From 5a2e62aaeaca856a7dab2b664e2a626c72eac992 Mon Sep 17 00:00:00 2001 From: f4exb Date: Wed, 26 Dec 2018 21:40:46 +0100 Subject: [PATCH] Reverse API: PlutoSDR output --- .../plutosdroutput/plutosdroutput.cpp | 156 ++++++++++++++++++ .../plutosdroutput/plutosdroutput.h | 13 +- .../plutosdroutput/plutosdroutputgui.cpp | 24 +++ .../plutosdroutput/plutosdroutputgui.h | 1 + .../plutosdroutput/plutosdroutputsettings.cpp | 20 +++ .../plutosdroutput/plutosdroutputsettings.h | 9 +- 6 files changed, 220 insertions(+), 3 deletions(-) diff --git a/plugins/samplesink/plutosdroutput/plutosdroutput.cpp b/plugins/samplesink/plutosdroutput/plutosdroutput.cpp index 54157a930..ec727f0a3 100644 --- a/plugins/samplesink/plutosdroutput/plutosdroutput.cpp +++ b/plugins/samplesink/plutosdroutput/plutosdroutput.cpp @@ -15,6 +15,8 @@ /////////////////////////////////////////////////////////////////////////////////// #include +#include +#include #include "SWGDeviceSettings.h" #include "SWGDeviceState.h" @@ -54,10 +56,16 @@ PlutoSDROutput::PlutoSDROutput(DeviceSinkAPI *deviceAPI) : suspendBuddies(); openDevice(); resumeBuddies(); + + m_networkManager = new QNetworkAccessManager(); + connect(m_networkManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(networkManagerFinished(QNetworkReply*))); } PlutoSDROutput::~PlutoSDROutput() { + disconnect(m_networkManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(networkManagerFinished(QNetworkReply*))); + delete m_networkManager; + suspendBuddies(); closeDevice(); resumeBuddies(); @@ -210,6 +218,10 @@ bool PlutoSDROutput::handleMessage(const Message& message) m_deviceAPI->stopGeneration(); } + if (m_settings.m_useReverseAPI) { + webapiReverseSendStartStop(cmd.getStartStop()); + } + return true; } else @@ -315,6 +327,7 @@ bool PlutoSDROutput::applySettings(const PlutoSDROutputSettings& settings, bool bool suspendAllOtherThreads = false; // All others means Rx in fact DevicePlutoSDRBox *plutoBox = m_deviceShared.m_deviceParams->getBox(); QLocale loc; + QList reverseAPIKeys; qDebug().noquote() << "PlutoSDROutput::applySettings: center freq: " << m_settings.m_centerFrequency << " Hz" << " m_devSampleRate: " << loc.toString(m_settings.m_devSampleRate) << "S/s" @@ -331,6 +344,25 @@ bool PlutoSDROutput::applySettings(const PlutoSDROutputSettings& settings, bool << " m_transverterDeltaFrequency: " << m_settings.m_transverterDeltaFrequency << " force: " << force; + if ((m_settings.m_devSampleRate != settings.m_devSampleRate) || force) { + reverseAPIKeys.append("devSampleRate"); + } + if ((m_settings.m_lpfFIREnable != settings.m_lpfFIREnable) || force) { + reverseAPIKeys.append("lpfFIREnable"); + } + if ((m_settings.m_lpfFIRlog2Interp != settings.m_lpfFIRlog2Interp) || force) { + reverseAPIKeys.append("lpfFIRlog2Interp"); + } + if ((m_settings.m_lpfFIRBW != settings.m_lpfFIRBW) || force) { + reverseAPIKeys.append("lpfFIRBW"); + } + if ((m_settings.m_lpfFIRGain != settings.m_lpfFIRGain) || force) { + reverseAPIKeys.append("lpfFIRGain"); + } + if ((m_settings.m_LOppmTenths != settings.m_LOppmTenths) || force) { + reverseAPIKeys.append("LOppmTenths"); + } + // determine if buddies threads or own thread need to be suspended // changes affecting all buddies can occur if @@ -401,6 +433,7 @@ bool PlutoSDROutput::applySettings(const PlutoSDROutputSettings& settings, bool if ((m_settings.m_log2Interp != settings.m_log2Interp) || force) { + reverseAPIKeys.append("log2Interp"); m_sampleSourceFifo.resize((32*PLUTOSDR_BLOCKSIZE_SAMPLES)/(1< params; bool paramsToSet = false; + if ((m_settings.m_centerFrequency != settings.m_centerFrequency) || force) { + reverseAPIKeys.append("centerFrequency"); + } + if ((m_settings.m_transverterMode != settings.m_transverterMode) || force) { + reverseAPIKeys.append("transverterMode"); + } + if ((m_settings.m_transverterDeltaFrequency != settings.m_transverterDeltaFrequency) || force) { + reverseAPIKeys.append("transverterDeltaFrequency"); + } + if (force || (m_settings.m_centerFrequency != settings.m_centerFrequency) || (m_settings.m_transverterMode != settings.m_transverterMode) || (m_settings.m_transverterDeltaFrequency != settings.m_transverterDeltaFrequency)) @@ -442,12 +485,14 @@ bool PlutoSDROutput::applySettings(const PlutoSDROutputSettings& settings, bool if ((m_settings.m_lpfBW != settings.m_lpfBW) || force) { + reverseAPIKeys.append("lpfBW"); params.push_back(QString(tr("out_voltage_rf_bandwidth=%1").arg(settings.m_lpfBW)).toStdString()); paramsToSet = true; } if ((m_settings.m_antennaPath != settings.m_antennaPath) || force) { + reverseAPIKeys.append("antennaPath"); QString rfPortStr; PlutoSDROutputSettings::translateRFPath(settings.m_antennaPath, rfPortStr); params.push_back(QString(tr("out_voltage0_rf_port_select=%1").arg(rfPortStr)).toStdString()); @@ -456,6 +501,7 @@ bool PlutoSDROutput::applySettings(const PlutoSDROutputSettings& settings, bool if ((m_settings.m_att != settings.m_att) || force) { + reverseAPIKeys.append("att"); float attF = settings.m_att * 0.25f; params.push_back(QString(tr("out_voltage0_hardwaregain=%1").arg(attF)).toStdString()); paramsToSet = true; @@ -466,6 +512,15 @@ bool PlutoSDROutput::applySettings(const PlutoSDROutputSettings& settings, bool plutoBox->set_params(DevicePlutoSDRBox::DEVICE_PHY, params); } + 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 (suspendAllOtherThreads) @@ -687,3 +742,104 @@ void PlutoSDROutput::webapiFormatDeviceReport(SWGSDRangel::SWGDeviceReport& resp fetchTemperature(); response.getPlutoSdrOutputReport()->setTemperature(getTemperature()); } + +void PlutoSDROutput::webapiReverseSendSettings(QList& deviceSettingsKeys, const PlutoSDROutputSettings& settings, bool force) +{ + SWGSDRangel::SWGDeviceSettings *swgDeviceSettings = new SWGSDRangel::SWGDeviceSettings(); + swgDeviceSettings->setTx(1); + swgDeviceSettings->setDeviceHwType(new QString("PlutoSDR")); + swgDeviceSettings->setPlutoSdrOutputSettings(new SWGSDRangel::SWGPlutoSdrOutputSettings()); + SWGSDRangel::SWGPlutoSdrOutputSettings *swgPlutoSdrOutputSettings = swgDeviceSettings->getPlutoSdrOutputSettings(); + + // transfer data that has been modified. When force is on transfer all data except reverse API data + + if (deviceSettingsKeys.contains("centerFrequency") || force) { + swgPlutoSdrOutputSettings->setCenterFrequency(settings.m_centerFrequency); + } + if (deviceSettingsKeys.contains("devSampleRate") || force) { + swgPlutoSdrOutputSettings->setDevSampleRate(settings.m_devSampleRate); + } + if (deviceSettingsKeys.contains("LOppmTenths") || force) { + swgPlutoSdrOutputSettings->setLOppmTenths(settings.m_LOppmTenths); + } + if (deviceSettingsKeys.contains("lpfFIREnable") || force) { + swgPlutoSdrOutputSettings->setLpfFirEnable(settings.m_lpfFIREnable ? 1 : 0); + } + if (deviceSettingsKeys.contains("lpfFIRBW") || force) { + swgPlutoSdrOutputSettings->setLpfFirbw(settings.m_lpfFIRBW); + } + if (deviceSettingsKeys.contains("lpfFIRlog2Interp") || force) { + swgPlutoSdrOutputSettings->setLpfFiRlog2Interp(settings.m_lpfFIRlog2Interp); + } + if (deviceSettingsKeys.contains("lpfFIRGain") || force) { + swgPlutoSdrOutputSettings->setLpfFirGain(settings.m_lpfFIRGain); + } + if (deviceSettingsKeys.contains("log2Interp") || force) { + swgPlutoSdrOutputSettings->setLog2Interp(settings.m_log2Interp); + } + if (deviceSettingsKeys.contains("lpfBW") || force) { + swgPlutoSdrOutputSettings->setLpfBw(settings.m_lpfBW); + } + if (deviceSettingsKeys.contains("att") || force) { + swgPlutoSdrOutputSettings->setAtt(settings.m_att); + } + if (deviceSettingsKeys.contains("antennaPath") || force) { + swgPlutoSdrOutputSettings->setAntennaPath((int) settings.m_antennaPath); + } + if (deviceSettingsKeys.contains("transverterDeltaFrequency") || force) { + swgPlutoSdrOutputSettings->setTransverterDeltaFrequency(settings.m_transverterDeltaFrequency); + } + if (deviceSettingsKeys.contains("transverterMode") || force) { + swgPlutoSdrOutputSettings->setTransverterMode(settings.m_transverterMode ? 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 PlutoSDROutput::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 PlutoSDROutput::networkManagerFinished(QNetworkReply *reply) +{ + QNetworkReply::NetworkError replyError = reply->error(); + + if (replyError) + { + qWarning() << "PlutoSDROutput::networkManagerFinished:" + << " error(" << (int) replyError + << "): " << replyError + << ": " << reply->errorString(); + return; + } + + QString answer = reply->readAll(); + answer.chop(1); // remove last \n + qDebug("PlutoSDROutput::networkManagerFinished: reply:\n%s", answer.toStdString().c_str()); +} diff --git a/plugins/samplesink/plutosdroutput/plutosdroutput.h b/plugins/samplesink/plutosdroutput/plutosdroutput.h index b5512edc8..abc20902d 100644 --- a/plugins/samplesink/plutosdroutput/plutosdroutput.h +++ b/plugins/samplesink/plutosdroutput/plutosdroutput.h @@ -18,18 +18,22 @@ #define PLUGINS_SAMPLESOURCE_PLUTOSDROUTPUT_PLUTOSDRINPUT_H_ #include +#include #include "iio.h" -#include +#include "dsp/devicesamplesink.h" #include "util/message.h" #include "plutosdr/deviceplutosdrshared.h" #include "plutosdr/deviceplutosdrbox.h" #include "plutosdroutputsettings.h" +class QNetworkAccessManager; +class QNetworkReply; class DeviceSinkAPI; class PlutoSDROutputThread; class PlutoSDROutput : public DeviceSampleSink { + Q_OBJECT public: class MsgConfigurePlutoSDR : public Message { MESSAGE_CLASS_DECLARATION @@ -131,6 +135,8 @@ public: PlutoSDROutputThread *m_plutoSDROutputThread; DevicePlutoSDRBox::SampleRates m_deviceSampleRates; QMutex m_mutex; + QNetworkAccessManager *m_networkManager; + QNetworkRequest m_networkRequest; bool openDevice(); void closeDevice(); @@ -139,6 +145,11 @@ public: bool applySettings(const PlutoSDROutputSettings& settings, bool force = false); void webapiFormatDeviceSettings(SWGSDRangel::SWGDeviceSettings& response, const PlutoSDROutputSettings& settings); void webapiFormatDeviceReport(SWGSDRangel::SWGDeviceReport& response); + void webapiReverseSendSettings(QList& deviceSettingsKeys, const PlutoSDROutputSettings& settings, bool force); + void webapiReverseSendStartStop(bool start); + +private slots: + void networkManagerFinished(QNetworkReply *reply); }; diff --git a/plugins/samplesink/plutosdroutput/plutosdroutputgui.cpp b/plugins/samplesink/plutosdroutput/plutosdroutputgui.cpp index 4d96665e6..68fd31011 100644 --- a/plugins/samplesink/plutosdroutput/plutosdroutputgui.cpp +++ b/plugins/samplesink/plutosdroutput/plutosdroutputgui.cpp @@ -21,6 +21,8 @@ #include "dsp/dspengine.h" #include "dsp/dspcommands.h" #include "gui/glspectrum.h" +#include "gui/crightclickenabler.h" +#include "gui/basicdevicesettingsdialog.h" #include "device/devicesinkapi.h" #include "device/deviceuiset.h" #include "plutosdr/deviceplutosdr.h" @@ -59,6 +61,9 @@ PlutoSDROutputGUI::PlutoSDROutputGUI(DeviceUISet *deviceUISet, QWidget* parent) ui->swInterpLabel->setText(QString::fromUtf8("S\u2191")); ui->lpFIRInterpolationLabel->setText(QString::fromUtf8("\u2191")); + CRightClickEnabler *startStopRightClickEnabler = new CRightClickEnabler(ui->startStop); + connect(startStopRightClickEnabler, SIGNAL(rightClick(const QPoint &)), this, SLOT(openDeviceSettingsDialog(const QPoint &))); + blockApplySettings(true); displaySettings(); blockApplySettings(false); @@ -436,3 +441,22 @@ void PlutoSDROutputGUI::updateSampleRateAndFrequency() m_deviceUISet->getSpectrum()->setCenterFrequency(m_deviceCenterFrequency); ui->deviceRateLabel->setText(tr("%1k").arg(QString::number(m_sampleRate / 1000.0f, 'g', 5))); } + +void PlutoSDROutputGUI::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/plutosdroutput/plutosdroutputgui.h b/plugins/samplesink/plutosdroutput/plutosdroutputgui.h index 6ca6f2d20..cd037466b 100644 --- a/plugins/samplesink/plutosdroutput/plutosdroutputgui.h +++ b/plugins/samplesink/plutosdroutput/plutosdroutputgui.h @@ -92,6 +92,7 @@ private slots: void updateHardware(); void updateStatus(); void handleInputMessages(); + void openDeviceSettingsDialog(const QPoint& p); }; #endif /* PLUGINS_SAMPLESOURCE_PLUTOSDROUTPUT_PLUTOSDROUTPUTGUI_H_ */ diff --git a/plugins/samplesink/plutosdroutput/plutosdroutputsettings.cpp b/plugins/samplesink/plutosdroutput/plutosdroutputsettings.cpp index 90e1652e8..158a8b713 100644 --- a/plugins/samplesink/plutosdroutput/plutosdroutputsettings.cpp +++ b/plugins/samplesink/plutosdroutput/plutosdroutputsettings.cpp @@ -39,6 +39,10 @@ void PlutoSDROutputSettings::resetToDefaults() m_antennaPath = RFPATH_A; m_transverterMode = false; m_transverterDeltaFrequency = 0; + m_useReverseAPI = false; + m_reverseAPIAddress = "127.0.0.1"; + m_reverseAPIPort = 8888; + m_reverseAPIDeviceIndex = 0; } QByteArray PlutoSDROutputSettings::serialize() const @@ -57,6 +61,10 @@ QByteArray PlutoSDROutputSettings::serialize() const s.writeS32(14, (int) m_antennaPath); s.writeBool(15, m_transverterMode); s.writeS64(16, m_transverterDeltaFrequency); + s.writeBool(17, m_useReverseAPI); + s.writeString(18, m_reverseAPIAddress); + s.writeU32(19, m_reverseAPIPort); + s.writeU32(20, m_reverseAPIDeviceIndex); return s.final(); } @@ -98,6 +106,18 @@ bool PlutoSDROutputSettings::deserialize(const QByteArray& data) } d.readBool(15, &m_transverterMode, false); d.readS64(16, &m_transverterDeltaFrequency, 0); + d.readBool(17, &m_useReverseAPI, false); + d.readString(18, &m_reverseAPIAddress, "127.0.0.1"); + d.readU32(19, &uintval, 0); + + if ((uintval > 1023) && (uintval < 65535)) { + m_reverseAPIPort = uintval; + } else { + m_reverseAPIPort = 8888; + } + + d.readU32(20, &uintval, 0); + m_reverseAPIDeviceIndex = uintval > 99 ? 99 : uintval; return true; } diff --git a/plugins/samplesink/plutosdroutput/plutosdroutputsettings.h b/plugins/samplesink/plutosdroutput/plutosdroutputsettings.h index 672dbd4fd..39125bde3 100644 --- a/plugins/samplesink/plutosdroutput/plutosdroutputsettings.h +++ b/plugins/samplesink/plutosdroutput/plutosdroutputsettings.h @@ -17,9 +17,11 @@ #ifndef _PLUTOSDR_PLUTOSDROUTPUTSETTINGS_H_ #define _PLUTOSDR_PLUTOSDROUTPUTSETTINGS_H_ -#include #include +#include +#include + struct PlutoSDROutputSettings { enum RFPath { @@ -44,7 +46,10 @@ struct PlutoSDROutputSettings { RFPath m_antennaPath; bool m_transverterMode; qint64 m_transverterDeltaFrequency; - + bool m_useReverseAPI; + QString m_reverseAPIAddress; + uint16_t m_reverseAPIPort; + uint16_t m_reverseAPIDeviceIndex; PlutoSDROutputSettings(); void resetToDefaults();