diff --git a/plugins/samplesink/hackrfoutput/hackrfoutput.cpp b/plugins/samplesink/hackrfoutput/hackrfoutput.cpp index 00f0137cd..238f57213 100644 --- a/plugins/samplesink/hackrfoutput/hackrfoutput.cpp +++ b/plugins/samplesink/hackrfoutput/hackrfoutput.cpp @@ -14,11 +14,12 @@ // along with this program. If not, see . // /////////////////////////////////////////////////////////////////////////////////// -#include "hackrfoutput.h" - #include #include + #include +#include +#include #include "SWGDeviceSettings.h" #include "SWGDeviceState.h" @@ -29,8 +30,8 @@ #include "device/devicesourceapi.h" #include "device/devicesinkapi.h" #include "hackrf/devicehackrfshared.h" - #include "hackrfoutputthread.h" +#include "hackrfoutput.h" MESSAGE_CLASS_DEFINITION(HackRFOutput::MsgConfigureHackRF, Message) MESSAGE_CLASS_DEFINITION(HackRFOutput::MsgStartStop, Message) @@ -46,11 +47,19 @@ HackRFOutput::HackRFOutput(DeviceSinkAPI *deviceAPI) : { openDevice(); m_deviceAPI->setBuddySharedPtr(&m_sharedParams); + m_networkManager = new QNetworkAccessManager(); + connect(m_networkManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(networkManagerFinished(QNetworkReply*))); } HackRFOutput::~HackRFOutput() { - if (m_running) stop(); + disconnect(m_networkManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(networkManagerFinished(QNetworkReply*))); + delete m_networkManager; + + if (m_running) { + stop(); + } + closeDevice(); m_deviceAPI->setBuddySharedPtr(0); } @@ -264,6 +273,10 @@ bool HackRFOutput::handleMessage(const Message& message) m_deviceAPI->stopGeneration(); } + if (m_settings.m_useReverseAPI) { + webapiReverseSendStartStop(cmd.getStartStop()); + } + return true; } else @@ -297,8 +310,26 @@ bool HackRFOutput::applySettings(const HackRFOutputSettings& settings, bool forc bool suspendThread = false; bool threadWasRunning = false; hackrf_error rc; + QList reverseAPIKeys; - qDebug() << "HackRFOutput::applySettings"; + qDebug() << "HackRFOutput::applySettings" + << " m_centerFrequency: " << m_settings.m_centerFrequency + << " m_LOppmTenths: " << m_settings.m_LOppmTenths + << " m_bandwidth: " << m_settings.m_bandwidth + << " m_devSampleRate: " << m_settings.m_devSampleRate + << " m_log2Interp: " << m_settings.m_log2Interp + << " m_biasT: " << m_settings.m_biasT + << " m_lnaExt: " << m_settings.m_lnaExt + << " m_vgaGain: " << m_settings.m_vgaGain + << " m_useReverseAPI: " << m_settings.m_useReverseAPI + << " m_reverseAPIAddress: " << m_settings.m_reverseAPIAddress + << " m_reverseAPIPort: " << m_settings.m_reverseAPIPort + << " m_reverseAPIDeviceIndex: " << m_settings.m_reverseAPIDeviceIndex + << " force: " << force; + + if ((m_settings.m_devSampleRate != settings.m_devSampleRate) || force) { + reverseAPIKeys.append("devSampleRate"); + } if ((m_settings.m_devSampleRate != settings.m_devSampleRate) || (m_settings.m_log2Interp != settings.m_log2Interp) || force) @@ -349,6 +380,8 @@ bool HackRFOutput::applySettings(const HackRFOutputSettings& settings, bool forc if ((m_settings.m_log2Interp != settings.m_log2Interp) || force) { + reverseAPIKeys.append("log2Interp"); + if (m_hackRFThread != 0) { m_hackRFThread->setLog2Interpolation(settings.m_log2Interp); @@ -356,6 +389,13 @@ bool HackRFOutput::applySettings(const HackRFOutputSettings& settings, bool forc } } + if ((m_settings.m_centerFrequency != settings.m_centerFrequency) || force) { + reverseAPIKeys.append("centerFrequency"); + } + if ((m_settings.m_LOppmTenths != settings.m_LOppmTenths) || force) { + reverseAPIKeys.append("LOppmTenths"); + } + if (force || (m_settings.m_centerFrequency != settings.m_centerFrequency) || (m_settings.m_LOppmTenths != settings.m_LOppmTenths)) { @@ -370,16 +410,15 @@ bool HackRFOutput::applySettings(const HackRFOutputSettings& settings, bool forc if ((m_settings.m_vgaGain != settings.m_vgaGain) || force) { + reverseAPIKeys.append("vgaGain"); + if (m_dev != 0) { rc = (hackrf_error) hackrf_set_txvga_gain(m_dev, settings.m_vgaGain); - if(rc != HACKRF_SUCCESS) - { + if (rc != HACKRF_SUCCESS) { qDebug("HackRFOutput::applySettings: hackrf_set_txvga_gain failed: %s", hackrf_error_name(rc)); - } - else - { + } else { qDebug() << "HackRFOutput:applySettings: TxVGA gain set to " << settings.m_vgaGain; } } @@ -387,17 +426,16 @@ bool HackRFOutput::applySettings(const HackRFOutputSettings& settings, bool forc if ((m_settings.m_bandwidth != settings.m_bandwidth) || force) { + reverseAPIKeys.append("bandwidth"); + if (m_dev != 0) { uint32_t bw_index = hackrf_compute_baseband_filter_bw_round_down_lt(settings.m_bandwidth + 1); // +1 so the round down to lower than yields desired bandwidth rc = (hackrf_error) hackrf_set_baseband_filter_bandwidth(m_dev, bw_index); - if (rc != HACKRF_SUCCESS) - { + if (rc != HACKRF_SUCCESS) { qDebug("HackRFInput::applySettings: hackrf_set_baseband_filter_bandwidth failed: %s", hackrf_error_name(rc)); - } - else - { + } else { qDebug() << "HackRFInput:applySettings: Baseband BW filter set to " << settings.m_bandwidth << " Hz"; } } @@ -405,16 +443,15 @@ bool HackRFOutput::applySettings(const HackRFOutputSettings& settings, bool forc if ((m_settings.m_biasT != settings.m_biasT) || force) { + reverseAPIKeys.append("biasT"); + if (m_dev != 0) { rc = (hackrf_error) hackrf_set_antenna_enable(m_dev, (settings.m_biasT ? 1 : 0)); - if(rc != HACKRF_SUCCESS) - { + if (rc != HACKRF_SUCCESS) { qDebug("HackRFInput::applySettings: hackrf_set_antenna_enable failed: %s", hackrf_error_name(rc)); - } - else - { + } else { qDebug() << "HackRFInput:applySettings: bias tee set to " << settings.m_biasT; } } @@ -422,16 +459,15 @@ bool HackRFOutput::applySettings(const HackRFOutputSettings& settings, bool forc if ((m_settings.m_lnaExt != settings.m_lnaExt) || force) { + reverseAPIKeys.append("lnaExt"); + if (m_dev != 0) { rc = (hackrf_error) hackrf_set_amp_enable(m_dev, (settings.m_lnaExt ? 1 : 0)); - if(rc != HACKRF_SUCCESS) - { + if (rc != HACKRF_SUCCESS) { qDebug("HackRFInput::applySettings: hackrf_set_amp_enable failed: %s", hackrf_error_name(rc)); - } - else - { + } else { qDebug() << "HackRFInput:applySettings: extra LNA set to " << settings.m_lnaExt; } } @@ -442,14 +478,16 @@ bool HackRFOutput::applySettings(const HackRFOutputSettings& settings, bool forc m_hackRFThread->startWork(); } - m_settings.m_devSampleRate = settings.m_devSampleRate; - m_settings.m_log2Interp = settings.m_log2Interp; - m_settings.m_centerFrequency = settings.m_centerFrequency; - m_settings.m_LOppmTenths = settings.m_LOppmTenths; - m_settings.m_vgaGain = settings.m_vgaGain; - m_settings.m_bandwidth = settings.m_bandwidth; - m_settings.m_biasT = settings.m_biasT; - m_settings.m_lnaExt = settings.m_lnaExt; + if (settings.m_useReverseAPI) + { + bool fullUpdate = ((m_settings.m_useReverseAPI != settings.m_useReverseAPI) && settings.m_useReverseAPI) || + (m_settings.m_reverseAPIAddress != settings.m_reverseAPIAddress) || + (m_settings.m_reverseAPIPort != settings.m_reverseAPIPort) || + (m_settings.m_reverseAPIDeviceIndex != settings.m_reverseAPIDeviceIndex); + webapiReverseSendSettings(reverseAPIKeys, settings, fullUpdate || force); + } + + m_settings = settings; if (forwardChange) { @@ -559,3 +597,88 @@ int HackRFOutput::webapiRun( return 200; } +void HackRFOutput::webapiReverseSendSettings(QList& deviceSettingsKeys, const HackRFOutputSettings& settings, bool force) +{ + SWGSDRangel::SWGDeviceSettings *swgDeviceSettings = new SWGSDRangel::SWGDeviceSettings(); + swgDeviceSettings->setTx(1); + swgDeviceSettings->setDeviceHwType(new QString("HackRF")); + swgDeviceSettings->setHackRfOutputSettings(new SWGSDRangel::SWGHackRFOutputSettings()); + SWGSDRangel::SWGHackRFOutputSettings *swgHackRFOutputSettings = swgDeviceSettings->getHackRfOutputSettings(); + + // transfer data that has been modified. When force is on transfer all data except reverse API data + + if (deviceSettingsKeys.contains("centerFrequency") || force) { + swgHackRFOutputSettings->setCenterFrequency(settings.m_centerFrequency); + } + if (deviceSettingsKeys.contains("LOppmTenths") || force) { + swgHackRFOutputSettings->setLOppmTenths(settings.m_LOppmTenths); + } + if (deviceSettingsKeys.contains("bandwidth") || force) { + swgHackRFOutputSettings->setBandwidth(settings.m_bandwidth); + } + if (deviceSettingsKeys.contains("vgaGain") || force) { + swgHackRFOutputSettings->setVgaGain(settings.m_vgaGain); + } + if (deviceSettingsKeys.contains("log2Interp") || force) { + swgHackRFOutputSettings->setLog2Interp(settings.m_log2Interp); + } + if (deviceSettingsKeys.contains("devSampleRate") || force) { + swgHackRFOutputSettings->setDevSampleRate(settings.m_devSampleRate); + } + if (deviceSettingsKeys.contains("biasT") || force) { + swgHackRFOutputSettings->setBiasT(settings.m_biasT ? 1 : 0); + } + if (deviceSettingsKeys.contains("lnaExt") || force) { + swgHackRFOutputSettings->setLnaExt(settings.m_lnaExt ? 1 : 0); + } + + QString deviceSettingsURL = QString("http://%1:%2/sdrangel/deviceset/%3/device/settings") + .arg(settings.m_reverseAPIAddress) + .arg(settings.m_reverseAPIPort) + .arg(settings.m_reverseAPIDeviceIndex); + m_networkRequest.setUrl(QUrl(deviceSettingsURL)); + m_networkRequest.setHeader(QNetworkRequest::ContentTypeHeader, "application/json"); + + QBuffer *buffer=new QBuffer(); + buffer->open((QBuffer::ReadWrite)); + buffer->write(swgDeviceSettings->asJson().toUtf8()); + buffer->seek(0); + + // Always use PATCH to avoid passing reverse API settings + m_networkManager->sendCustomRequest(m_networkRequest, "PATCH", buffer); + + delete swgDeviceSettings; +} + +void HackRFOutput::webapiReverseSendStartStop(bool start) +{ + QString deviceSettingsURL = QString("http://%1:%2/sdrangel/deviceset/%3/device/run") + .arg(m_settings.m_reverseAPIAddress) + .arg(m_settings.m_reverseAPIPort) + .arg(m_settings.m_reverseAPIDeviceIndex); + m_networkRequest.setUrl(QUrl(deviceSettingsURL)); + + if (start) { + m_networkManager->sendCustomRequest(m_networkRequest, "POST"); + } else { + m_networkManager->sendCustomRequest(m_networkRequest, "DELETE"); + } +} + +void HackRFOutput::networkManagerFinished(QNetworkReply *reply) +{ + QNetworkReply::NetworkError replyError = reply->error(); + + if (replyError) + { + qWarning() << "HackRFOutput::networkManagerFinished:" + << " error(" << (int) replyError + << "): " << replyError + << ": " << reply->errorString(); + return; + } + + QString answer = reply->readAll(); + answer.chop(1); // remove last \n + qDebug("HackRFOutput::networkManagerFinished: reply:\n%s", answer.toStdString().c_str()); +} diff --git a/plugins/samplesink/hackrfoutput/hackrfoutput.h b/plugins/samplesink/hackrfoutput/hackrfoutput.h index 73c6a430b..b234a08fd 100644 --- a/plugins/samplesink/hackrfoutput/hackrfoutput.h +++ b/plugins/samplesink/hackrfoutput/hackrfoutput.h @@ -17,18 +17,22 @@ #ifndef INCLUDE_HACKRFOUTPUT_H #define INCLUDE_HACKRFOUTPUT_H +#include +#include + #include "dsp/devicesamplesink.h" #include "libhackrf/hackrf.h" -#include - #include "hackrf/devicehackrf.h" #include "hackrf/devicehackrfparam.h" #include "hackrfoutputsettings.h" +class QNetworkAccessManager; +class QNetworkReply; class DeviceSinkAPI; class HackRFOutputThread; class HackRFOutput : public DeviceSampleSink { + Q_OBJECT public: class MsgConfigureHackRF : public Message { @@ -129,13 +133,6 @@ public: QString& errorMessage); private: - bool openDevice(); - void closeDevice(); - bool applySettings(const HackRFOutputSettings& settings, bool force); -// hackrf_device *open_hackrf_from_sequence(int sequence); - void setDeviceCenterFrequency(quint64 freq_hz, qint32 LOppmTenths); - void webapiFormatDeviceSettings(SWGSDRangel::SWGDeviceSettings& response, const HackRFOutputSettings& settings); - DeviceSinkAPI *m_deviceAPI; QMutex m_mutex; HackRFOutputSettings m_settings; @@ -143,7 +140,21 @@ private: HackRFOutputThread* m_hackRFThread; QString m_deviceDescription; DeviceHackRFParams m_sharedParams; + QNetworkAccessManager *m_networkManager; + QNetworkRequest m_networkRequest; + bool m_running; + bool openDevice(); + void closeDevice(); + bool applySettings(const HackRFOutputSettings& settings, bool force); +// hackrf_device *open_hackrf_from_sequence(int sequence); + void setDeviceCenterFrequency(quint64 freq_hz, qint32 LOppmTenths); + void webapiFormatDeviceSettings(SWGSDRangel::SWGDeviceSettings& response, const HackRFOutputSettings& settings); + void webapiReverseSendSettings(QList& deviceSettingsKeys, const HackRFOutputSettings& settings, bool force); + void webapiReverseSendStartStop(bool start); + +private slots: + void networkManagerFinished(QNetworkReply *reply); }; #endif // INCLUDE_HACKRFINPUT_H diff --git a/plugins/samplesink/hackrfoutput/hackrfoutputgui.cpp b/plugins/samplesink/hackrfoutput/hackrfoutputgui.cpp index 153df00d9..28189e187 100644 --- a/plugins/samplesink/hackrfoutput/hackrfoutputgui.cpp +++ b/plugins/samplesink/hackrfoutput/hackrfoutputgui.cpp @@ -14,8 +14,6 @@ // along with this program. If not, see . // /////////////////////////////////////////////////////////////////////////////////// -#include "hackrfoutputgui.h" - #include #include @@ -23,6 +21,8 @@ #include "gui/colormapper.h" #include "gui/glspectrum.h" +#include "gui/crightclickenabler.h" +#include "gui/basicdevicesettingsdialog.h" #include "dsp/dspengine.h" #include "dsp/dspcommands.h" #include "device/devicesinkapi.h" @@ -31,6 +31,7 @@ #include "hackrf/devicehackrfvalues.h" #include "hackrf/devicehackrfshared.h" +#include "hackrfoutputgui.h" #include "ui_hackrfoutputgui.h" HackRFOutputGui::HackRFOutputGui(DeviceUISet *deviceUISet, QWidget* parent) : @@ -56,6 +57,9 @@ HackRFOutputGui::HackRFOutputGui(DeviceUISet *deviceUISet, QWidget* parent) : connect(&m_statusTimer, SIGNAL(timeout()), this, SLOT(updateStatus())); m_statusTimer.start(500); + CRightClickEnabler *startStopRightClickEnabler = new CRightClickEnabler(ui->startStop); + connect(startStopRightClickEnabler, SIGNAL(rightClick(const QPoint &)), this, SLOT(openDeviceSettingsDialog(const QPoint &))); + displaySettings(); displayBandwidths(); sendSettings(); @@ -329,7 +333,7 @@ void HackRFOutputGui::updateHardware() qDebug() << "HackRFOutputGui::updateHardware"; HackRFOutput::MsgConfigureHackRF* message = HackRFOutput::MsgConfigureHackRF::create(m_settings, m_forceSettings); m_deviceSampleSink->getInputMessageQueue()->push(message); - m_forceSettings = true; + m_forceSettings = false; m_updateTimer.stop(); } } @@ -363,3 +367,22 @@ void HackRFOutputGui::updateStatus() m_lastEngineState = state; } } + +void HackRFOutputGui::openDeviceSettingsDialog(const QPoint& p) +{ + BasicDeviceSettingsDialog dialog(this); + dialog.setUseReverseAPI(m_settings.m_useReverseAPI); + dialog.setReverseAPIAddress(m_settings.m_reverseAPIAddress); + dialog.setReverseAPIPort(m_settings.m_reverseAPIPort); + dialog.setReverseAPIDeviceIndex(m_settings.m_reverseAPIDeviceIndex); + + dialog.move(p); + dialog.exec(); + + m_settings.m_useReverseAPI = dialog.useReverseAPI(); + m_settings.m_reverseAPIAddress = dialog.getReverseAPIAddress(); + m_settings.m_reverseAPIPort = dialog.getReverseAPIPort(); + m_settings.m_reverseAPIDeviceIndex = dialog.getReverseAPIDeviceIndex(); + + sendSettings(); +} diff --git a/plugins/samplesink/hackrfoutput/hackrfoutputgui.h b/plugins/samplesink/hackrfoutput/hackrfoutputgui.h index fdcba768e..921efc1c2 100644 --- a/plugins/samplesink/hackrfoutput/hackrfoutputgui.h +++ b/plugins/samplesink/hackrfoutput/hackrfoutputgui.h @@ -17,10 +17,10 @@ #ifndef INCLUDE_HACKRFOUTPUTGUI_H #define INCLUDE_HACKRFOUTPUTGUI_H -#include #include #include +#include "plugin/plugininstancegui.h" #include "util/messagequeue.h" #include "hackrfoutput.h" @@ -95,6 +95,7 @@ private slots: void on_startStop_toggled(bool checked); void updateHardware(); void updateStatus(); + void openDeviceSettingsDialog(const QPoint& p); }; #endif // INCLUDE_HACKRFOUTPUTGUI_H diff --git a/plugins/samplesink/hackrfoutput/hackrfoutputsettings.cpp b/plugins/samplesink/hackrfoutput/hackrfoutputsettings.cpp index d15ae3580..427b1075e 100644 --- a/plugins/samplesink/hackrfoutput/hackrfoutputsettings.cpp +++ b/plugins/samplesink/hackrfoutput/hackrfoutputsettings.cpp @@ -35,6 +35,10 @@ void HackRFOutputSettings::resetToDefaults() m_vgaGain = 22; m_bandwidth = 1750000; m_devSampleRate = 2400000; + m_useReverseAPI = false; + m_reverseAPIAddress = "127.0.0.1"; + m_reverseAPIPort = 8888; + m_reverseAPIDeviceIndex = 0; } QByteArray HackRFOutputSettings::serialize() const @@ -48,6 +52,10 @@ QByteArray HackRFOutputSettings::serialize() const s.writeU32(6, m_vgaGain); s.writeU32(7, m_bandwidth); s.writeU64(8, m_devSampleRate); + s.writeBool(9, m_useReverseAPI); + s.writeString(10, m_reverseAPIAddress); + s.writeU32(11, m_reverseAPIPort); + s.writeU32(12, m_reverseAPIDeviceIndex); return s.final(); } @@ -64,6 +72,8 @@ bool HackRFOutputSettings::deserialize(const QByteArray& data) if (d.getVersion() == 1) { + uint32_t uintval; + d.readS32(1, &m_LOppmTenths, 0); d.readBool(3, &m_biasT, false); d.readU32(4, &m_log2Interp, 0); @@ -71,6 +81,18 @@ bool HackRFOutputSettings::deserialize(const QByteArray& data) d.readU32(6, &m_vgaGain, 30); d.readU32(7, &m_bandwidth, 1750000); d.readU64(8, &m_devSampleRate, 2400000); + d.readBool(9, &m_useReverseAPI, false); + d.readString(10, &m_reverseAPIAddress, "127.0.0.1"); + d.readU32(11, &uintval, 0); + + if ((uintval > 1023) && (uintval < 65535)) { + m_reverseAPIPort = uintval; + } else { + m_reverseAPIPort = 8888; + } + + d.readU32(12, &uintval, 0); + m_reverseAPIDeviceIndex = uintval > 99 ? 99 : uintval; return true; } diff --git a/plugins/samplesink/hackrfoutput/hackrfoutputsettings.h b/plugins/samplesink/hackrfoutput/hackrfoutputsettings.h index 610e9f4e4..29d32368b 100644 --- a/plugins/samplesink/hackrfoutput/hackrfoutputsettings.h +++ b/plugins/samplesink/hackrfoutput/hackrfoutputsettings.h @@ -18,6 +18,7 @@ #define _HACKRF_HACKRFOUTPUTSETTINGS_H_ #include +#include struct HackRFOutputSettings { quint64 m_centerFrequency; @@ -28,6 +29,10 @@ struct HackRFOutputSettings { quint64 m_devSampleRate; bool m_biasT; bool m_lnaExt; + bool m_useReverseAPI; + QString m_reverseAPIAddress; + uint16_t m_reverseAPIPort; + uint16_t m_reverseAPIDeviceIndex; HackRFOutputSettings(); void resetToDefaults();