From 42d69204c69ba8308901b81fecdff6824caf781e Mon Sep 17 00:00:00 2001 From: f4exb Date: Wed, 26 Dec 2018 22:30:35 +0100 Subject: [PATCH] Reverse API: SDR daemon sink --- .../plutosdroutput/plutosdroutputplugin.cpp | 2 +- .../sdrdaemonsink/sdrdaemonsinkgui.cpp | 25 +++- .../sdrdaemonsink/sdrdaemonsinkgui.h | 1 + .../sdrdaemonsink/sdrdaemonsinkoutput.cpp | 112 +++++++++++++++++- .../sdrdaemonsink/sdrdaemonsinkoutput.h | 4 +- .../sdrdaemonsink/sdrdaemonsinkplugin.cpp | 2 +- .../sdrdaemonsink/sdrdaemonsinksettings.cpp | 20 ++++ .../sdrdaemonsink/sdrdaemonsinksettings.h | 4 + 8 files changed, 164 insertions(+), 6 deletions(-) diff --git a/plugins/samplesink/plutosdroutput/plutosdroutputplugin.cpp b/plugins/samplesink/plutosdroutput/plutosdroutputplugin.cpp index 99d3b4259..e1fc9d661 100644 --- a/plugins/samplesink/plutosdroutput/plutosdroutputplugin.cpp +++ b/plugins/samplesink/plutosdroutput/plutosdroutputplugin.cpp @@ -30,7 +30,7 @@ class DeviceSourceAPI; const PluginDescriptor PlutoSDROutputPlugin::m_pluginDescriptor = { QString("PlutoSDR Output"), - QString("4.3.1"), + QString("4.3.2"), QString("(c) Edouard Griffiths, F4EXB"), QString("https://github.com/f4exb/sdrangel"), true, diff --git a/plugins/samplesink/sdrdaemonsink/sdrdaemonsinkgui.cpp b/plugins/samplesink/sdrdaemonsink/sdrdaemonsinkgui.cpp index b7eb7e9ff..a37743009 100644 --- a/plugins/samplesink/sdrdaemonsink/sdrdaemonsinkgui.cpp +++ b/plugins/samplesink/sdrdaemonsink/sdrdaemonsinkgui.cpp @@ -15,7 +15,6 @@ /////////////////////////////////////////////////////////////////////////////////// #include - #include #include #include @@ -31,6 +30,8 @@ #include "plugin/pluginapi.h" #include "gui/colormapper.h" #include "gui/glspectrum.h" +#include "gui/crightclickenabler.h" +#include "gui/basicdevicesettingsdialog.h" #include "dsp/dspengine.h" #include "dsp/dspcommands.h" @@ -95,6 +96,9 @@ SDRdaemonSinkGui::SDRdaemonSinkGui(DeviceUISet *deviceUISet, QWidget* parent) : displayEventCounts(); displayEventTimer(); + CRightClickEnabler *startStopRightClickEnabler = new CRightClickEnabler(ui->startStop); + connect(startStopRightClickEnabler, SIGNAL(rightClick(const QPoint &)), this, SLOT(openDeviceSettingsDialog(const QPoint &))); + displaySettings(); sendSettings(); } @@ -624,3 +628,22 @@ void SDRdaemonSinkGui::analyzeApiReply(const QJsonObject& jsonObject) ui->infoText->setText(infoLine); } } + +void SDRdaemonSinkGui::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/sdrdaemonsink/sdrdaemonsinkgui.h b/plugins/samplesink/sdrdaemonsink/sdrdaemonsinkgui.h index 4204dfc16..772f137fe 100644 --- a/plugins/samplesink/sdrdaemonsink/sdrdaemonsinkgui.h +++ b/plugins/samplesink/sdrdaemonsink/sdrdaemonsinkgui.h @@ -154,6 +154,7 @@ private slots: void updateStatus(); void tick(); void networkManagerFinished(QNetworkReply *reply); + void openDeviceSettingsDialog(const QPoint& p); }; #endif // INCLUDE_FILESINKGUI_H diff --git a/plugins/samplesink/sdrdaemonsink/sdrdaemonsinkoutput.cpp b/plugins/samplesink/sdrdaemonsink/sdrdaemonsinkoutput.cpp index 7f9c9ab62..7ff09249d 100644 --- a/plugins/samplesink/sdrdaemonsink/sdrdaemonsinkoutput.cpp +++ b/plugins/samplesink/sdrdaemonsink/sdrdaemonsinkoutput.cpp @@ -20,6 +20,7 @@ #include #include #include +#include #include "SWGDeviceSettings.h" #include "SWGDeviceState.h" @@ -217,6 +218,10 @@ bool SDRdaemonSinkOutput::handleMessage(const Message& message) m_deviceAPI->stopGeneration(); } + if (m_settings.m_useReverseAPI) { + webapiReverseSendStartStop(cmd.getStartStop()); + } + return true; } else if (MsgConfigureSDRdaemonSinkChunkCorrection::match(message)) @@ -241,6 +246,20 @@ void SDRdaemonSinkOutput::applySettings(const SDRdaemonSinkSettings& settings, b QMutexLocker mutexLocker(&m_mutex); bool forwardChange = false; bool changeTxDelay = false; + QList reverseAPIKeys; + + if ((m_settings.m_dataAddress != settings.m_dataAddress) || force) { + reverseAPIKeys.append("dataAddress"); + } + if ((m_settings.m_dataPort != settings.m_dataPort) || force) { + reverseAPIKeys.append("dataPort"); + } + if ((m_settings.m_apiAddress != settings.m_apiAddress) || force) { + reverseAPIKeys.append("apiAddress"); + } + if ((m_settings.m_apiPort != settings.m_apiPort) || force) { + reverseAPIKeys.append("apiPort"); + } if (force || (m_settings.m_dataAddress != settings.m_dataAddress) || (m_settings.m_dataPort != settings.m_dataPort)) { @@ -251,6 +270,8 @@ void SDRdaemonSinkOutput::applySettings(const SDRdaemonSinkSettings& settings, b if (force || (m_settings.m_sampleRate != settings.m_sampleRate)) { + reverseAPIKeys.append("sampleRate"); + if (m_sdrDaemonSinkThread != 0) { m_sdrDaemonSinkThread->setSamplerate(settings.m_sampleRate); } @@ -264,6 +285,8 @@ void SDRdaemonSinkOutput::applySettings(const SDRdaemonSinkSettings& settings, b if (force || (m_settings.m_nbFECBlocks != settings.m_nbFECBlocks)) { + reverseAPIKeys.append("nbFECBlocks"); + if (m_sdrDaemonSinkThread != 0) { m_sdrDaemonSinkThread->setNbBlocksFEC(settings.m_nbFECBlocks); } @@ -273,6 +296,7 @@ void SDRdaemonSinkOutput::applySettings(const SDRdaemonSinkSettings& settings, b if (force || (m_settings.m_txDelay != settings.m_txDelay)) { + reverseAPIKeys.append("txDelay"); changeTxDelay = true; } @@ -300,6 +324,15 @@ void SDRdaemonSinkOutput::applySettings(const SDRdaemonSinkSettings& settings, b m_deviceAPI->getDeviceEngineInputMessageQueue()->push(notif); } + 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; } @@ -461,7 +494,7 @@ void SDRdaemonSinkOutput::networkManagerFinished(QNetworkReply *reply) if (error.error == QJsonParseError::NoError) { - analyzeApiReply(doc.object()); + analyzeApiReply(doc.object(), answer); } else { @@ -476,7 +509,7 @@ void SDRdaemonSinkOutput::networkManagerFinished(QNetworkReply *reply) } } -void SDRdaemonSinkOutput::analyzeApiReply(const QJsonObject& jsonObject) +void SDRdaemonSinkOutput::analyzeApiReply(const QJsonObject& jsonObject, const QString& answer) { if (jsonObject.contains("DaemonSourceReport")) { @@ -546,6 +579,10 @@ void SDRdaemonSinkOutput::analyzeApiReply(const QJsonObject& jsonObject) m_lastSampleCount = sampleCount; m_lastQueueLength = queueLength; } + else if (jsonObject.contains("sdrDaemonSinkSettings")) + { + qDebug("SDRdaemonSinkOutput::analyzeApiReply: reply:\n%s", answer.toStdString().c_str()); + } } void SDRdaemonSinkOutput::sampleRateCorrection(double remoteTimeDeltaUs, double timeDeltaUs, uint32_t remoteSampleCount, uint32_t sampleCount) @@ -559,3 +596,74 @@ void SDRdaemonSinkOutput::sampleRateCorrection(double remoteTimeDeltaUs, double MsgConfigureSDRdaemonSinkChunkCorrection* message = MsgConfigureSDRdaemonSinkChunkCorrection::create(m_chunkSizeCorrection); getInputMessageQueue()->push(message); } + +void SDRdaemonSinkOutput::webapiReverseSendSettings(QList& deviceSettingsKeys, const SDRdaemonSinkSettings& settings, bool force) +{ + SWGSDRangel::SWGDeviceSettings *swgDeviceSettings = new SWGSDRangel::SWGDeviceSettings(); + swgDeviceSettings->setTx(1); + swgDeviceSettings->setDeviceHwType(new QString("SDRdaemonSink")); + swgDeviceSettings->setSdrDaemonSinkSettings(new SWGSDRangel::SWGSDRdaemonSinkSettings()); + SWGSDRangel::SWGSDRdaemonSinkSettings *swgSdrDaemonSinkSettings = swgDeviceSettings->getSdrDaemonSinkSettings(); + + // transfer data that has been modified. When force is on transfer all data except reverse API data + + if (deviceSettingsKeys.contains("sampleRate") || force) { + swgSdrDaemonSinkSettings->setSampleRate(settings.m_sampleRate); + } + if (deviceSettingsKeys.contains("txDelay") || force) { + swgSdrDaemonSinkSettings->setTxDelay(settings.m_txDelay); + } + if (deviceSettingsKeys.contains("nbFECBlocks") || force) { + swgSdrDaemonSinkSettings->setNbFecBlocks(settings.m_nbFECBlocks); + } + if (deviceSettingsKeys.contains("apiAddress") || force) { + swgSdrDaemonSinkSettings->setApiAddress(new QString(settings.m_apiAddress)); + } + if (deviceSettingsKeys.contains("apiPort") || force) { + swgSdrDaemonSinkSettings->setApiPort(settings.m_apiPort); + } + if (deviceSettingsKeys.contains("dataAddress") || force) { + swgSdrDaemonSinkSettings->setDataAddress(new QString(settings.m_dataAddress)); + } + if (deviceSettingsKeys.contains("dataPort") || force) { + swgSdrDaemonSinkSettings->setDataPort(settings.m_dataPort); + } + if (deviceSettingsKeys.contains("deviceIndex") || force) { + swgSdrDaemonSinkSettings->setDeviceIndex(settings.m_deviceIndex); + } + if (deviceSettingsKeys.contains("channelIndex") || force) { + swgSdrDaemonSinkSettings->setChannelIndex(settings.m_channelIndex); + } + + 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 SDRdaemonSinkOutput::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"); + } +} diff --git a/plugins/samplesink/sdrdaemonsink/sdrdaemonsinkoutput.h b/plugins/samplesink/sdrdaemonsink/sdrdaemonsinkoutput.h index 93ce45d5e..f0940324a 100644 --- a/plugins/samplesink/sdrdaemonsink/sdrdaemonsinkoutput.h +++ b/plugins/samplesink/sdrdaemonsink/sdrdaemonsinkoutput.h @@ -193,8 +193,10 @@ private: void webapiFormatDeviceSettings(SWGSDRangel::SWGDeviceSettings& response, const SDRdaemonSinkSettings& settings); void webapiFormatDeviceReport(SWGSDRangel::SWGDeviceReport& response); - void analyzeApiReply(const QJsonObject& jsonObject); + void analyzeApiReply(const QJsonObject& jsonObject, const QString& answer); void sampleRateCorrection(double remoteTimeDeltaUs, double timeDeltaUs, uint32_t remoteSampleCount, uint32_t sampleCount); + void webapiReverseSendSettings(QList& deviceSettingsKeys, const SDRdaemonSinkSettings& settings, bool force); + void webapiReverseSendStartStop(bool start); private slots: void tick(); diff --git a/plugins/samplesink/sdrdaemonsink/sdrdaemonsinkplugin.cpp b/plugins/samplesink/sdrdaemonsink/sdrdaemonsinkplugin.cpp index 33c7f05c8..05e294324 100644 --- a/plugins/samplesink/sdrdaemonsink/sdrdaemonsinkplugin.cpp +++ b/plugins/samplesink/sdrdaemonsink/sdrdaemonsinkplugin.cpp @@ -29,7 +29,7 @@ const PluginDescriptor SDRdaemonSinkPlugin::m_pluginDescriptor = { QString("SDRdaemon sink output"), - QString("4.1.0"), + QString("4.3.2"), QString("(c) Edouard Griffiths, F4EXB"), QString("https://github.com/f4exb/sdrangel"), true, diff --git a/plugins/samplesink/sdrdaemonsink/sdrdaemonsinksettings.cpp b/plugins/samplesink/sdrdaemonsink/sdrdaemonsinksettings.cpp index 8467b259d..f81813dd6 100644 --- a/plugins/samplesink/sdrdaemonsink/sdrdaemonsinksettings.cpp +++ b/plugins/samplesink/sdrdaemonsink/sdrdaemonsinksettings.cpp @@ -34,6 +34,10 @@ void SDRdaemonSinkSettings::resetToDefaults() m_dataPort = 9090; m_deviceIndex = 0; m_channelIndex = 0; + m_useReverseAPI = false; + m_reverseAPIAddress = "127.0.0.1"; + m_reverseAPIPort = 8888; + m_reverseAPIDeviceIndex = 0; } QByteArray SDRdaemonSinkSettings::serialize() const @@ -50,6 +54,10 @@ QByteArray SDRdaemonSinkSettings::serialize() const s.writeU32(8, m_dataPort); s.writeU32(10, m_deviceIndex); s.writeU32(11, m_channelIndex); + s.writeBool(12, m_useReverseAPI); + s.writeString(13, m_reverseAPIAddress); + s.writeU32(14, m_reverseAPIPort); + s.writeU32(15, m_reverseAPIDeviceIndex); return s.final(); } @@ -80,6 +88,18 @@ bool SDRdaemonSinkSettings::deserialize(const QByteArray& data) m_dataPort = uintval % (1<<16); d.readU32(10, &m_deviceIndex, 0); d.readU32(11, &m_channelIndex, 0); + d.readBool(12, &m_useReverseAPI, false); + d.readString(13, &m_reverseAPIAddress, "127.0.0.1"); + d.readU32(14, &uintval, 0); + + if ((uintval > 1023) && (uintval < 65535)) { + m_reverseAPIPort = uintval; + } else { + m_reverseAPIPort = 8888; + } + + d.readU32(15, &uintval, 0); + m_reverseAPIDeviceIndex = uintval > 99 ? 99 : uintval; return true; } diff --git a/plugins/samplesink/sdrdaemonsink/sdrdaemonsinksettings.h b/plugins/samplesink/sdrdaemonsink/sdrdaemonsinksettings.h index 88176fdec..8ba59ddeb 100644 --- a/plugins/samplesink/sdrdaemonsink/sdrdaemonsinksettings.h +++ b/plugins/samplesink/sdrdaemonsink/sdrdaemonsinksettings.h @@ -30,6 +30,10 @@ struct SDRdaemonSinkSettings { quint16 m_dataPort; quint32 m_deviceIndex; quint32 m_channelIndex; + bool m_useReverseAPI; + QString m_reverseAPIAddress; + uint16_t m_reverseAPIPort; + uint16_t m_reverseAPIDeviceIndex; SDRdaemonSinkSettings(); void resetToDefaults();