From aad0046d03704af826f30c5826f56e7898a11eb1 Mon Sep 17 00:00:00 2001 From: f4exb Date: Wed, 26 Dec 2018 19:22:52 +0100 Subject: [PATCH] Reverse API: BladeRF output --- .../bladerf1output/bladerf1output.cpp | 217 +++++++++++++----- .../bladerf1output/bladerf1output.h | 29 ++- .../bladerf1output/bladerf1outputgui.cpp | 24 ++ .../bladerf1output/bladerf1outputgui.h | 1 + .../bladerf1output/bladerf1outputplugin.cpp | 2 +- .../bladerf1output/bladerf1outputsettings.cpp | 21 ++ .../bladerf1output/bladerf1outputsettings.h | 6 + .../bladerf2output/bladerf2output.cpp | 128 +++++++++++ .../bladerf2output/bladerf2output.h | 28 ++- .../bladerf2output/bladerf2outputgui.cpp | 23 ++ .../bladerf2output/bladerf2outputgui.h | 1 + .../bladerf2output/bladerf2outputplugin.cpp | 2 +- .../bladerf2output/bladerf2outputsettings.cpp | 22 ++ .../bladerf2output/bladerf2outputsettings.h | 5 + .../samplesink/limesdroutput/limesdroutput.h | 4 +- .../limesdroutput/limesdroutputsettings.h | 4 +- 16 files changed, 436 insertions(+), 81 deletions(-) diff --git a/plugins/samplesink/bladerf1output/bladerf1output.cpp b/plugins/samplesink/bladerf1output/bladerf1output.cpp index 9255cf3c3..0c4eb5693 100644 --- a/plugins/samplesink/bladerf1output/bladerf1output.cpp +++ b/plugins/samplesink/bladerf1output/bladerf1output.cpp @@ -14,11 +14,12 @@ // along with this program. If not, see . // /////////////////////////////////////////////////////////////////////////////////// -#include "bladerf1output.h" - #include #include + #include +#include +#include #include "SWGDeviceSettings.h" #include "SWGDeviceState.h" @@ -29,6 +30,7 @@ #include "device/devicesourceapi.h" #include "bladerf1/devicebladerf1shared.h" #include "bladerf1outputthread.h" +#include "bladerf1output.h" MESSAGE_CLASS_DEFINITION(Bladerf1Output::MsgConfigureBladerf1, Message) MESSAGE_CLASS_DEFINITION(Bladerf1Output::MsgStartStop, Message) @@ -45,11 +47,19 @@ Bladerf1Output::Bladerf1Output(DeviceSinkAPI *deviceAPI) : m_sampleSourceFifo.resize(16*BLADERFOUTPUT_BLOCKSIZE); openDevice(); m_deviceAPI->setBuddySharedPtr(&m_sharedParams); + m_networkManager = new QNetworkAccessManager(); + connect(m_networkManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(networkManagerFinished(QNetworkReply*))); } Bladerf1Output::~Bladerf1Output() { - 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); } @@ -276,6 +286,10 @@ bool Bladerf1Output::handleMessage(const Message& message) m_deviceAPI->stopGeneration(); } + if (m_settings.m_useReverseAPI) { + webapiReverseSendStartStop(cmd.getStartStop()); + } + return true; } else @@ -289,10 +303,21 @@ bool Bladerf1Output::applySettings(const BladeRF1OutputSettings& settings, bool bool forwardChange = false; bool suspendOwnThread = false; bool threadWasRunning = false; + QList reverseAPIKeys; // QMutexLocker mutexLocker(&m_mutex); qDebug() << "BladerfOutput::applySettings: m_dev: " << m_dev; + if ((m_settings.m_centerFrequency != settings.m_centerFrequency) || force) { + reverseAPIKeys.append("centerFrequency"); + } + if ((m_settings.m_devSampleRate != settings.m_devSampleRate) || force) { + reverseAPIKeys.append("devSampleRate"); + } + if ((m_settings.m_log2Interp != settings.m_log2Interp) || force) { + reverseAPIKeys.append("log2Interp"); + } + if ((m_settings.m_devSampleRate != settings.m_devSampleRate) || (m_settings.m_log2Interp != settings.m_log2Interp) || force) { @@ -337,12 +362,9 @@ bool Bladerf1Output::applySettings(const BladeRF1OutputSettings& settings, bool { unsigned int actualSamplerate; - if (bladerf_set_sample_rate(m_dev, BLADERF_MODULE_TX, settings.m_devSampleRate, &actualSamplerate) < 0) - { + if (bladerf_set_sample_rate(m_dev, BLADERF_MODULE_TX, settings.m_devSampleRate, &actualSamplerate) < 0) { qCritical("BladerfOutput::applySettings: could not set sample rate: %d", settings.m_devSampleRate); - } - else - { + } else { qDebug() << "BladerfOutput::applySettings: bladerf_set_sample_rate(BLADERF_MODULE_TX) actual sample rate is " << actualSamplerate; } } @@ -361,14 +383,13 @@ bool Bladerf1Output::applySettings(const BladeRF1OutputSettings& settings, bool if ((m_settings.m_vga1 != settings.m_vga1) || force) { + reverseAPIKeys.append("vga1"); + if (m_dev != 0) { - if(bladerf_set_txvga1(m_dev, settings.m_vga1) != 0) - { + if (bladerf_set_txvga1(m_dev, settings.m_vga1) != 0) { qDebug("BladerfOutput::applySettings: bladerf_set_txvga1() failed"); - } - else - { + } else { qDebug() << "BladerfOutput::applySettings: VGA1 gain set to " << settings.m_vga1; } } @@ -376,14 +397,13 @@ bool Bladerf1Output::applySettings(const BladeRF1OutputSettings& settings, bool if ((m_settings.m_vga2 != settings.m_vga2) || force) { + reverseAPIKeys.append("vga2"); + if(m_dev != 0) { - if(bladerf_set_txvga2(m_dev, settings.m_vga2) != 0) - { + if (bladerf_set_txvga2(m_dev, settings.m_vga2) != 0) { qDebug("BladerfOutput::applySettings:bladerf_set_rxvga2() failed"); - } - else - { + } else { qDebug() << "BladerfOutput::applySettings: VGA2 gain set to " << settings.m_vga2; } } @@ -391,6 +411,8 @@ bool Bladerf1Output::applySettings(const BladeRF1OutputSettings& settings, bool if ((m_settings.m_xb200 != settings.m_xb200) || force) { + reverseAPIKeys.append("xb200"); + if (m_dev != 0) { bool changeSettings; @@ -399,12 +421,9 @@ bool Bladerf1Output::applySettings(const BladeRF1OutputSettings& settings, bool { DeviceSourceAPI *buddy = m_deviceAPI->getSourceBuddies()[0]; - if (buddy->getDeviceSourceEngine()->state() == DSPDeviceSourceEngine::StRunning) // Tx side running - { + if (buddy->getDeviceSourceEngine()->state() == DSPDeviceSourceEngine::StRunning) { // Tx side running changeSettings = false; - } - else - { + } else { changeSettings = true; } } @@ -417,23 +436,17 @@ bool Bladerf1Output::applySettings(const BladeRF1OutputSettings& settings, bool { if (settings.m_xb200) { - if (bladerf_expansion_attach(m_dev, BLADERF_XB_200) != 0) - { + if (bladerf_expansion_attach(m_dev, BLADERF_XB_200) != 0) { qDebug("BladerfOutput::applySettings: bladerf_expansion_attach(xb200) failed"); - } - else - { + } else { qDebug() << "BladerfOutput::applySettings: Attach XB200"; } } else { - if (bladerf_expansion_attach(m_dev, BLADERF_XB_NONE) != 0) - { + if (bladerf_expansion_attach(m_dev, BLADERF_XB_NONE) != 0) { qDebug("BladerfOutput::applySettings: bladerf_expansion_attach(none) failed"); - } - else - { + } else { qDebug() << "BladerfOutput::applySettings: Detach XB200"; } } @@ -445,14 +458,13 @@ bool Bladerf1Output::applySettings(const BladeRF1OutputSettings& settings, bool if ((m_settings.m_xb200Path != settings.m_xb200Path) || force) { + reverseAPIKeys.append("xb200Path"); + if (m_dev != 0) { - if(bladerf_xb200_set_path(m_dev, BLADERF_MODULE_TX, settings.m_xb200Path) != 0) - { + if (bladerf_xb200_set_path(m_dev, BLADERF_MODULE_TX, settings.m_xb200Path) != 0) { qDebug("BladerfOutput::applySettings: bladerf_xb200_set_path(BLADERF_MODULE_TX) failed"); - } - else - { + } else { qDebug() << "BladerfOutput::applySettings: set xb200 path to " << settings.m_xb200Path; } } @@ -460,14 +472,13 @@ bool Bladerf1Output::applySettings(const BladeRF1OutputSettings& settings, bool if ((m_settings.m_xb200Filter != settings.m_xb200Filter) || force) { + reverseAPIKeys.append("xb200Filter"); + if (m_dev != 0) { - if(bladerf_xb200_set_filterbank(m_dev, BLADERF_MODULE_TX, settings.m_xb200Filter) != 0) - { + if (bladerf_xb200_set_filterbank(m_dev, BLADERF_MODULE_TX, settings.m_xb200Filter) != 0) { qDebug("BladerfOutput::applySettings: bladerf_xb200_set_filterbank(BLADERF_MODULE_TX) failed"); - } - else - { + } else { qDebug() << "BladerfOutput::applySettings: set xb200 filter to " << settings.m_xb200Filter; } } @@ -475,16 +486,15 @@ bool Bladerf1Output::applySettings(const BladeRF1OutputSettings& settings, bool if ((m_settings.m_bandwidth != settings.m_bandwidth) || force) { - if(m_dev != 0) + reverseAPIKeys.append("bandwidth"); + + if (m_dev != 0) { unsigned int actualBandwidth; - if( bladerf_set_bandwidth(m_dev, BLADERF_MODULE_TX, settings.m_bandwidth, &actualBandwidth) < 0) - { + if (bladerf_set_bandwidth(m_dev, BLADERF_MODULE_TX, settings.m_bandwidth, &actualBandwidth) < 0) { qCritical("BladerfOutput::applySettings: could not set bandwidth: %d", settings.m_bandwidth); - } - else - { + } else { qDebug() << "BladerfOutput::applySettings: bladerf_set_bandwidth(BLADERF_MODULE_TX) actual bandwidth is " << actualBandwidth; } } @@ -495,7 +505,7 @@ bool Bladerf1Output::applySettings(const BladeRF1OutputSettings& settings, bool forwardChange = true; } - if (m_dev != NULL) + if (m_dev != 0) { if (bladerf_set_frequency( m_dev, BLADERF_MODULE_TX, settings.m_centerFrequency ) != 0) { @@ -508,15 +518,16 @@ bool Bladerf1Output::applySettings(const BladeRF1OutputSettings& settings, bool m_bladerfThread->startWork(); } - m_settings.m_centerFrequency = settings.m_centerFrequency; - m_settings.m_bandwidth = settings.m_bandwidth; - m_settings.m_xb200Filter = settings.m_xb200Filter; - m_settings.m_xb200 = settings.m_xb200; - m_settings.m_xb200Path = settings.m_xb200Path; - m_settings.m_vga2 = settings.m_vga2; - m_settings.m_vga1 = settings.m_vga1; - m_settings.m_devSampleRate = settings.m_devSampleRate; - m_settings.m_log2Interp = settings.m_log2Interp; + 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) { @@ -635,3 +646,91 @@ int Bladerf1Output::webapiRun( return 200; } +void Bladerf1Output::webapiReverseSendSettings(QList& deviceSettingsKeys, const BladeRF1OutputSettings& settings, bool force) +{ + SWGSDRangel::SWGDeviceSettings *swgDeviceSettings = new SWGSDRangel::SWGDeviceSettings(); + swgDeviceSettings->setTx(1); + swgDeviceSettings->setDeviceHwType(new QString("BladeRF1")); + swgDeviceSettings->setBladeRf1OutputSettings(new SWGSDRangel::SWGBladeRF1OutputSettings()); + SWGSDRangel::SWGBladeRF1OutputSettings *swgBladeRF1OutputSettings = swgDeviceSettings->getBladeRf1OutputSettings(); + + // transfer data that has been modified. When force is on transfer all data except reverse API data + + if (deviceSettingsKeys.contains("centerFrequency") || force) { + swgBladeRF1OutputSettings->setCenterFrequency(settings.m_centerFrequency); + } + if (deviceSettingsKeys.contains("devSampleRate") || force) { + swgBladeRF1OutputSettings->setDevSampleRate(settings.m_devSampleRate); + } + if (deviceSettingsKeys.contains("vga1") || force) { + swgBladeRF1OutputSettings->setVga1(settings.m_vga1); + } + if (deviceSettingsKeys.contains("vga2") || force) { + swgBladeRF1OutputSettings->setVga2(settings.m_vga2); + } + if (deviceSettingsKeys.contains("bandwidth") || force) { + swgBladeRF1OutputSettings->setBandwidth(settings.m_bandwidth); + } + if (deviceSettingsKeys.contains("log2Interp") || force) { + swgBladeRF1OutputSettings->setLog2Interp(settings.m_log2Interp); + } + if (deviceSettingsKeys.contains("xb200") || force) { + swgBladeRF1OutputSettings->setXb200(settings.m_xb200 ? 1 : 0); + } + if (deviceSettingsKeys.contains("xb200Path") || force) { + swgBladeRF1OutputSettings->setXb200Path((int) settings.m_xb200Path); + } + if (deviceSettingsKeys.contains("xb200Filter") || force) { + swgBladeRF1OutputSettings->setXb200Filter((int) settings.m_xb200Filter); + } + + 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 Bladerf1Output::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 Bladerf1Output::networkManagerFinished(QNetworkReply *reply) +{ + QNetworkReply::NetworkError replyError = reply->error(); + + if (replyError) + { + qWarning() << "Bladerf1Output::networkManagerFinished:" + << " error(" << (int) replyError + << "): " << replyError + << ": " << reply->errorString(); + return; + } + + QString answer = reply->readAll(); + answer.chop(1); // remove last \n + qDebug("Bladerf1Output::networkManagerFinished: reply:\n%s", answer.toStdString().c_str()); +} diff --git a/plugins/samplesink/bladerf1output/bladerf1output.h b/plugins/samplesink/bladerf1output/bladerf1output.h index 2a71e825d..834030e3e 100644 --- a/plugins/samplesink/bladerf1output/bladerf1output.h +++ b/plugins/samplesink/bladerf1output/bladerf1output.h @@ -17,18 +17,22 @@ #ifndef INCLUDE_BLADERFOUTPUT_H #define INCLUDE_BLADERFOUTPUT_H -#include -#include #include +#include -#include "../../../devices/bladerf1/devicebladerf1.h" -#include "../../../devices/bladerf1/devicebladerf1param.h" +#include "libbladeRF.h" +#include "dsp/devicesamplesink.h" +#include "bladerf1/devicebladerf1.h" +#include "bladerf1/devicebladerf1param.h" #include "bladerf1outputsettings.h" +class QNetworkAccessManager; +class QNetworkReply; class DeviceSinkAPI; class Bladerf1OutputThread; class Bladerf1Output : public DeviceSampleSink { + Q_OBJECT public: class MsgConfigureBladerf1 : public Message { MESSAGE_CLASS_DECLARATION @@ -128,11 +132,6 @@ public: QString& errorMessage); private: - bool openDevice(); - void closeDevice(); - bool applySettings(const BladeRF1OutputSettings& settings, bool force); - void webapiFormatDeviceSettings(SWGSDRangel::SWGDeviceSettings& response, const BladeRF1OutputSettings& settings); - DeviceSinkAPI *m_deviceAPI; QMutex m_mutex; BladeRF1OutputSettings m_settings; @@ -141,6 +140,18 @@ private: QString m_deviceDescription; DeviceBladeRF1Params m_sharedParams; bool m_running; + QNetworkAccessManager *m_networkManager; + QNetworkRequest m_networkRequest; + + bool openDevice(); + void closeDevice(); + bool applySettings(const BladeRF1OutputSettings& settings, bool force); + void webapiFormatDeviceSettings(SWGSDRangel::SWGDeviceSettings& response, const BladeRF1OutputSettings& settings); + void webapiReverseSendSettings(QList& deviceSettingsKeys, const BladeRF1OutputSettings& settings, bool force); + void webapiReverseSendStartStop(bool start); + +private slots: + void networkManagerFinished(QNetworkReply *reply); }; #endif // INCLUDE_BLADERFOUTPUT_H diff --git a/plugins/samplesink/bladerf1output/bladerf1outputgui.cpp b/plugins/samplesink/bladerf1output/bladerf1outputgui.cpp index d94afe77d..538fe8529 100644 --- a/plugins/samplesink/bladerf1output/bladerf1outputgui.cpp +++ b/plugins/samplesink/bladerf1output/bladerf1outputgui.cpp @@ -22,6 +22,8 @@ #include "ui_bladerf1outputgui.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" #include "device/devicesinkapi.h" @@ -59,6 +61,9 @@ Bladerf1OutputGui::Bladerf1OutputGui(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(); connect(&m_inputMessageQueue, SIGNAL(messageEnqueued()), this, SLOT(handleInputMessages()), Qt::QueuedConnection); @@ -406,3 +411,22 @@ unsigned int Bladerf1OutputGui::getXb200Index(bool xb_200, bladerf_xb200_path xb return 0; } } + +void Bladerf1OutputGui::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/bladerf1output/bladerf1outputgui.h b/plugins/samplesink/bladerf1output/bladerf1outputgui.h index a3dc5988a..a8ced210c 100644 --- a/plugins/samplesink/bladerf1output/bladerf1outputgui.h +++ b/plugins/samplesink/bladerf1output/bladerf1outputgui.h @@ -84,6 +84,7 @@ private slots: void on_startStop_toggled(bool checked); void updateHardware(); void updateStatus(); + void openDeviceSettingsDialog(const QPoint& p); }; #endif // INCLUDE_BLADERFOUTPUTGUI_H diff --git a/plugins/samplesink/bladerf1output/bladerf1outputplugin.cpp b/plugins/samplesink/bladerf1output/bladerf1outputplugin.cpp index cfcbc4a92..b21619603 100644 --- a/plugins/samplesink/bladerf1output/bladerf1outputplugin.cpp +++ b/plugins/samplesink/bladerf1output/bladerf1outputplugin.cpp @@ -30,7 +30,7 @@ const PluginDescriptor Bladerf1OutputPlugin::m_pluginDescriptor = { QString("BladeRF1 Output"), - QString("4.2.0"), + QString("4.3.2"), QString("(c) Edouard Griffiths, F4EXB"), QString("https://github.com/f4exb/sdrangel"), true, diff --git a/plugins/samplesink/bladerf1output/bladerf1outputsettings.cpp b/plugins/samplesink/bladerf1output/bladerf1outputsettings.cpp index 1ff12929c..fcf544597 100644 --- a/plugins/samplesink/bladerf1output/bladerf1outputsettings.cpp +++ b/plugins/samplesink/bladerf1output/bladerf1outputsettings.cpp @@ -36,6 +36,10 @@ void BladeRF1OutputSettings::resetToDefaults() m_xb200 = false; m_xb200Path = BLADERF_XB200_MIX; m_xb200Filter = BLADERF_XB200_AUTO_1DB; + m_useReverseAPI = false; + m_reverseAPIAddress = "127.0.0.1"; + m_reverseAPIPort = 8888; + m_reverseAPIDeviceIndex = 0; } QByteArray BladeRF1OutputSettings::serialize() const @@ -50,6 +54,10 @@ QByteArray BladeRF1OutputSettings::serialize() const s.writeBool(6, m_xb200); s.writeS32(7, (int) m_xb200Path); s.writeS32(8, (int) m_xb200Filter); + s.writeBool(9, m_useReverseAPI); + s.writeString(10, m_reverseAPIAddress); + s.writeU32(11, m_reverseAPIPort); + s.writeU32(12, m_reverseAPIDeviceIndex); return s.final(); } @@ -67,6 +75,7 @@ bool BladeRF1OutputSettings::deserialize(const QByteArray& data) if (d.getVersion() == 1) { int intval; + uint32_t uintval; d.readS32(1, &m_devSampleRate); d.readS32(2, &m_vga1); @@ -78,6 +87,18 @@ bool BladeRF1OutputSettings::deserialize(const QByteArray& data) m_xb200Path = (bladerf_xb200_path) intval; d.readS32(8, &intval); m_xb200Filter = (bladerf_xb200_filter) intval; + 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/bladerf1output/bladerf1outputsettings.h b/plugins/samplesink/bladerf1output/bladerf1outputsettings.h index 07b1115ed..30ad7f5d0 100644 --- a/plugins/samplesink/bladerf1output/bladerf1outputsettings.h +++ b/plugins/samplesink/bladerf1output/bladerf1outputsettings.h @@ -18,6 +18,8 @@ #define _BLADERF_BLADERFOUTPUTSETTINGS_H_ #include +#include + #include struct BladeRF1OutputSettings { @@ -30,6 +32,10 @@ struct BladeRF1OutputSettings { bool m_xb200; bladerf_xb200_path m_xb200Path; bladerf_xb200_filter m_xb200Filter; + bool m_useReverseAPI; + QString m_reverseAPIAddress; + uint16_t m_reverseAPIPort; + uint16_t m_reverseAPIDeviceIndex; BladeRF1OutputSettings(); void resetToDefaults(); diff --git a/plugins/samplesink/bladerf2output/bladerf2output.cpp b/plugins/samplesink/bladerf2output/bladerf2output.cpp index caea1d0a5..abc8cdcb0 100644 --- a/plugins/samplesink/bladerf2output/bladerf2output.cpp +++ b/plugins/samplesink/bladerf2output/bladerf2output.cpp @@ -17,7 +17,10 @@ #include #include + #include +#include +#include #include "SWGDeviceState.h" #include "SWGDeviceSettings.h" @@ -48,10 +51,15 @@ BladeRF2Output::BladeRF2Output(DeviceSinkAPI *deviceAPI) : m_running(false) { openDevice(); + m_networkManager = new QNetworkAccessManager(); + connect(m_networkManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(networkManagerFinished(QNetworkReply*))); } BladeRF2Output::~BladeRF2Output() { + disconnect(m_networkManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(networkManagerFinished(QNetworkReply*))); + delete m_networkManager; + if (m_running) { stop(); } @@ -675,6 +683,10 @@ bool BladeRF2Output::handleMessage(const Message& message) m_deviceAPI->stopGeneration(); } + if (m_settings.m_useReverseAPI) { + webapiReverseSendStartStop(cmd.getStartStop()); + } + return true; } else @@ -688,6 +700,7 @@ bool BladeRF2Output::applySettings(const BladeRF2OutputSettings& settings, bool bool forwardChangeOwnDSP = false; bool forwardChangeRxBuddies = false; bool forwardChangeTxBuddies = false; + QList reverseAPIKeys; struct bladerf *dev = m_deviceShared.m_dev->getDev(); int requestedChannel = m_deviceAPI->getItemIndex(); @@ -698,6 +711,7 @@ bool BladeRF2Output::applySettings(const BladeRF2OutputSettings& settings, bool if ((m_settings.m_devSampleRate != settings.m_devSampleRate) || (m_settings.m_log2Interp != settings.m_log2Interp) || force) { + reverseAPIKeys.append("devSampleRate"); BladeRF2OutputThread *bladeRF2OutputThread = findThread(); SampleSourceFifo *fifo = 0; @@ -755,6 +769,7 @@ bool BladeRF2Output::applySettings(const BladeRF2OutputSettings& settings, bool if ((m_settings.m_bandwidth != settings.m_bandwidth) || force) { + reverseAPIKeys.append("bandwidth"); forwardChangeTxBuddies = true; if (dev != 0) @@ -776,6 +791,7 @@ bool BladeRF2Output::applySettings(const BladeRF2OutputSettings& settings, bool if ((m_settings.m_log2Interp != settings.m_log2Interp) || force) { + reverseAPIKeys.append("log2Interp"); forwardChangeOwnDSP = true; BladeRF2OutputThread *outputThread = findThread(); @@ -786,6 +802,19 @@ bool BladeRF2Output::applySettings(const BladeRF2OutputSettings& settings, bool } } + 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 ((m_settings.m_LOppmTenths != settings.m_LOppmTenths) || force) { + reverseAPIKeys.append("LOppmTenths"); + } + if ((m_settings.m_centerFrequency != settings.m_centerFrequency) || (m_settings.m_transverterMode != settings.m_transverterMode) || (m_settings.m_transverterDeltaFrequency != settings.m_transverterDeltaFrequency) @@ -812,12 +841,14 @@ bool BladeRF2Output::applySettings(const BladeRF2OutputSettings& settings, bool if ((m_settings.m_biasTee != settings.m_biasTee) || force) { + reverseAPIKeys.append("biasTee"); forwardChangeTxBuddies = true; m_deviceShared.m_dev->setBiasTeeTx(settings.m_biasTee); } if ((m_settings.m_globalGain != settings.m_globalGain) || force) { + reverseAPIKeys.append("globalGain"); forwardChangeTxBuddies = true; if (dev) @@ -877,6 +908,15 @@ bool BladeRF2Output::applySettings(const BladeRF2OutputSettings& settings, bool } } + 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; qDebug() << "BladeRF2Output::applySettings: " @@ -1056,3 +1096,91 @@ int BladeRF2Output::webapiRun( return 200; } +void BladeRF2Output::webapiReverseSendSettings(QList& deviceSettingsKeys, const BladeRF2OutputSettings& settings, bool force) +{ + SWGSDRangel::SWGDeviceSettings *swgDeviceSettings = new SWGSDRangel::SWGDeviceSettings(); + swgDeviceSettings->setTx(1); + swgDeviceSettings->setDeviceHwType(new QString("BladeRF2")); + swgDeviceSettings->setBladeRf2OutputSettings(new SWGSDRangel::SWGBladeRF2OutputSettings()); + SWGSDRangel::SWGBladeRF2OutputSettings *swgBladeRF2OutputSettings = swgDeviceSettings->getBladeRf2OutputSettings(); + + // transfer data that has been modified. When force is on transfer all data except reverse API data + + if (deviceSettingsKeys.contains("centerFrequency") || force) { + swgBladeRF2OutputSettings->setCenterFrequency(settings.m_centerFrequency); + } + if (deviceSettingsKeys.contains("LOppmTenths") || force) { + swgBladeRF2OutputSettings->setLOppmTenths(settings.m_LOppmTenths); + } + if (deviceSettingsKeys.contains("devSampleRate") || force) { + swgBladeRF2OutputSettings->setDevSampleRate(settings.m_devSampleRate); + } + if (deviceSettingsKeys.contains("bandwidth") || force) { + swgBladeRF2OutputSettings->setBandwidth(settings.m_bandwidth); + } + if (deviceSettingsKeys.contains("log2Interp") || force) { + swgBladeRF2OutputSettings->setLog2Interp(settings.m_log2Interp); + } + if (deviceSettingsKeys.contains("biasTee") || force) { + swgBladeRF2OutputSettings->setBiasTee(settings.m_biasTee ? 1 : 0); + } + if (deviceSettingsKeys.contains("globalGain") || force) { + swgBladeRF2OutputSettings->setGlobalGain(settings.m_globalGain); + } + if (deviceSettingsKeys.contains("transverterDeltaFrequency") || force) { + swgBladeRF2OutputSettings->setTransverterDeltaFrequency(settings.m_transverterDeltaFrequency); + } + if (deviceSettingsKeys.contains("transverterMode") || force) { + swgBladeRF2OutputSettings->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 BladeRF2Output::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 BladeRF2Output::networkManagerFinished(QNetworkReply *reply) +{ + QNetworkReply::NetworkError replyError = reply->error(); + + if (replyError) + { + qWarning() << "BladeRF2Output::networkManagerFinished:" + << " error(" << (int) replyError + << "): " << replyError + << ": " << reply->errorString(); + return; + } + + QString answer = reply->readAll(); + answer.chop(1); // remove last \n + qDebug("BladeRF2Output::networkManagerFinished: reply:\n%s", answer.toStdString().c_str()); +} diff --git a/plugins/samplesink/bladerf2output/bladerf2output.h b/plugins/samplesink/bladerf2output/bladerf2output.h index 9b501aeaa..7d5f4c7ce 100644 --- a/plugins/samplesink/bladerf2output/bladerf2output.h +++ b/plugins/samplesink/bladerf2output/bladerf2output.h @@ -18,17 +18,22 @@ #define PLUGINS_SAMPLESINK_BLADERF2OUTPUT_BLADERF2OUTPUT_H_ #include +#include + #include #include "dsp/devicesamplesink.h" #include "bladerf2/devicebladerf2shared.h" #include "bladerf2outputsettings.h" +class QNetworkAccessManager; +class QNetworkReply; class DeviceSinkAPI; class BladeRF2OutputThread; struct bladerf_gain_modes; class BladeRF2Output : public DeviceSampleSink { + Q_OBJECT public: class MsgConfigureBladeRF2 : public Message { MESSAGE_CLASS_DECLARATION @@ -147,6 +152,17 @@ public: QString& errorMessage); private: + DeviceSinkAPI *m_deviceAPI; + QMutex m_mutex; + BladeRF2OutputSettings m_settings; + struct bladerf* m_dev; + BladeRF2OutputThread* m_thread; + QString m_deviceDescription; + DeviceBladeRF2Shared m_deviceShared; + bool m_running; + QNetworkAccessManager *m_networkManager; + QNetworkRequest m_networkRequest; + bool openDevice(); void closeDevice(); BladeRF2OutputThread *findThread(); @@ -156,15 +172,11 @@ private: bool setDeviceCenterFrequency(struct bladerf *dev, int requestedChannel, quint64 freq_hz, int loPpmTenths); void webapiFormatDeviceSettings(SWGSDRangel::SWGDeviceSettings& response, const BladeRF2OutputSettings& settings); void webapiFormatDeviceReport(SWGSDRangel::SWGDeviceReport& response); + void webapiReverseSendSettings(QList& deviceSettingsKeys, const BladeRF2OutputSettings& settings, bool force); + void webapiReverseSendStartStop(bool start); - DeviceSinkAPI *m_deviceAPI; - QMutex m_mutex; - BladeRF2OutputSettings m_settings; - struct bladerf* m_dev; - BladeRF2OutputThread* m_thread; - QString m_deviceDescription; - DeviceBladeRF2Shared m_deviceShared; - bool m_running; +private slots: + void networkManagerFinished(QNetworkReply *reply); }; #endif /* PLUGINS_SAMPLESINK_BLADERF2OUTPUT_BLADERF2OUTPUT_H_ */ diff --git a/plugins/samplesink/bladerf2output/bladerf2outputgui.cpp b/plugins/samplesink/bladerf2output/bladerf2outputgui.cpp index 283a68cb0..06a77316d 100644 --- a/plugins/samplesink/bladerf2output/bladerf2outputgui.cpp +++ b/plugins/samplesink/bladerf2output/bladerf2outputgui.cpp @@ -22,6 +22,8 @@ #include "ui_bladerf2outputgui.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" #include "device/devicesinkapi.h" @@ -71,6 +73,9 @@ BladeRF2OutputGui::BladeRF2OutputGui(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(); connect(&m_inputMessageQueue, SIGNAL(messageEnqueued()), this, SLOT(handleInputMessages()), Qt::QueuedConnection); @@ -368,3 +373,21 @@ void BladeRF2OutputGui::updateStatus() } } +void BladeRF2OutputGui::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/bladerf2output/bladerf2outputgui.h b/plugins/samplesink/bladerf2output/bladerf2outputgui.h index 7c3b9be78..1655194a0 100644 --- a/plugins/samplesink/bladerf2output/bladerf2outputgui.h +++ b/plugins/samplesink/bladerf2output/bladerf2outputgui.h @@ -86,6 +86,7 @@ private slots: void on_transverter_clicked(); void updateHardware(); void updateStatus(); + void openDeviceSettingsDialog(const QPoint& p); }; diff --git a/plugins/samplesink/bladerf2output/bladerf2outputplugin.cpp b/plugins/samplesink/bladerf2output/bladerf2outputplugin.cpp index 32c222514..8307b331f 100644 --- a/plugins/samplesink/bladerf2output/bladerf2outputplugin.cpp +++ b/plugins/samplesink/bladerf2output/bladerf2outputplugin.cpp @@ -30,7 +30,7 @@ const PluginDescriptor BladeRF2OutputPlugin::m_pluginDescriptor = { QString("BladeRF2 Output"), - QString("4.3.0"), + QString("4.3.2"), QString("(c) Edouard Griffiths, F4EXB"), QString("https://github.com/f4exb/sdrangel"), true, diff --git a/plugins/samplesink/bladerf2output/bladerf2outputsettings.cpp b/plugins/samplesink/bladerf2output/bladerf2outputsettings.cpp index 2ea428ef5..27f8cd29f 100644 --- a/plugins/samplesink/bladerf2output/bladerf2outputsettings.cpp +++ b/plugins/samplesink/bladerf2output/bladerf2outputsettings.cpp @@ -36,6 +36,10 @@ void BladeRF2OutputSettings::resetToDefaults() m_log2Interp = 0; m_transverterMode = false; m_transverterDeltaFrequency = 0; + m_useReverseAPI = false; + m_reverseAPIAddress = "127.0.0.1"; + m_reverseAPIPort = 8888; + m_reverseAPIDeviceIndex = 0; } QByteArray BladeRF2OutputSettings::serialize() const @@ -50,6 +54,10 @@ QByteArray BladeRF2OutputSettings::serialize() const s.writeU32(6, m_log2Interp); s.writeBool(7, m_transverterMode); s.writeS64(8, m_transverterDeltaFrequency); + s.writeBool(9, m_useReverseAPI); + s.writeString(10, m_reverseAPIAddress); + s.writeU32(11, m_reverseAPIPort); + s.writeU32(12, m_reverseAPIDeviceIndex); return s.final(); } @@ -66,6 +74,8 @@ bool BladeRF2OutputSettings::deserialize(const QByteArray& data) if (d.getVersion() == 1) { + uint32_t uintval; + d.readS32(1, &m_devSampleRate); d.readS32(2, &m_bandwidth); d.readS32(3, &m_LOppmTenths); @@ -74,6 +84,18 @@ bool BladeRF2OutputSettings::deserialize(const QByteArray& data) d.readU32(6, &m_log2Interp); d.readBool(7, &m_transverterMode, false); d.readS64(8, &m_transverterDeltaFrequency, 0); + 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/bladerf2output/bladerf2outputsettings.h b/plugins/samplesink/bladerf2output/bladerf2outputsettings.h index b83cc380e..a2bca08dd 100644 --- a/plugins/samplesink/bladerf2output/bladerf2outputsettings.h +++ b/plugins/samplesink/bladerf2output/bladerf2outputsettings.h @@ -18,6 +18,7 @@ #define PLUGINS_SAMPLESINK_BLADERF2OUTPUT_BLADERF2OUTPUTSETTINGS_H_ #include +#include struct BladeRF2OutputSettings { quint64 m_centerFrequency; @@ -29,6 +30,10 @@ struct BladeRF2OutputSettings { quint32 m_log2Interp; bool m_transverterMode; qint64 m_transverterDeltaFrequency; + bool m_useReverseAPI; + QString m_reverseAPIAddress; + uint16_t m_reverseAPIPort; + uint16_t m_reverseAPIDeviceIndex; BladeRF2OutputSettings(); void resetToDefaults(); diff --git a/plugins/samplesink/limesdroutput/limesdroutput.h b/plugins/samplesink/limesdroutput/limesdroutput.h index e324c6af3..f94b7f6a5 100644 --- a/plugins/samplesink/limesdroutput/limesdroutput.h +++ b/plugins/samplesink/limesdroutput/limesdroutput.h @@ -26,11 +26,11 @@ #include "limesdr/devicelimesdrshared.h" #include "limesdroutputsettings.h" +class QNetworkAccessManager; +class QNetworkReply; class DeviceSinkAPI; class LimeSDROutputThread; struct DeviceLimeSDRParams; -class QNetworkAccessManager; -class QNetworkReply; class LimeSDROutput : public DeviceSampleSink { diff --git a/plugins/samplesink/limesdroutput/limesdroutputsettings.h b/plugins/samplesink/limesdroutput/limesdroutputsettings.h index c0b84ea11..501adc1da 100644 --- a/plugins/samplesink/limesdroutput/limesdroutputsettings.h +++ b/plugins/samplesink/limesdroutput/limesdroutputsettings.h @@ -17,9 +17,11 @@ #ifndef PLUGINS_SAMPLESOURCE_LIMESDROUTPUT_LIMESDROUTPUTSETTINGS_H_ #define PLUGINS_SAMPLESOURCE_LIMESDROUTPUT_LIMESDROUTPUTSETTINGS_H_ -#include #include +#include +#include + /** * These are the settings individual to each hardware channel or software Tx chain * Plus the settings to be saved in the presets