diff --git a/fcdlib/fcdtraits.cpp b/fcdlib/fcdtraits.cpp index ac008da78..7317531e7 100644 --- a/fcdlib/fcdtraits.cpp +++ b/fcdlib/fcdtraits.cpp @@ -34,8 +34,8 @@ const char *fcd_traits::displayedName = "FunCube Dongle Pro+"; const char *fcd_traits::pluginDisplayedName = "FunCube Pro Input"; const char *fcd_traits::pluginDisplayedName = "FunCube Pro+ Input"; -const char *fcd_traits::pluginVersion = "4.3.0"; -const char *fcd_traits::pluginVersion = "4.3.0"; +const char *fcd_traits::pluginVersion = "4.3.2"; +const char *fcd_traits::pluginVersion = "4.3.2"; const int64_t fcd_traits::loLowLimitFreq = 64000000L; const int64_t fcd_traits::loLowLimitFreq = 150000L; diff --git a/plugins/samplesource/fcdpro/fcdprogui.cpp b/plugins/samplesource/fcdpro/fcdprogui.cpp index 6928742b1..ffb6ae1af 100644 --- a/plugins/samplesource/fcdpro/fcdprogui.cpp +++ b/plugins/samplesource/fcdpro/fcdprogui.cpp @@ -19,6 +19,8 @@ #include "ui_fcdprogui.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 "fcdprogui.h" @@ -143,6 +145,9 @@ FCDProGui::FCDProGui(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); @@ -524,3 +529,21 @@ void FCDProGui::updateHardware() m_updateTimer.stop(); } +void FCDProGui::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/samplesource/fcdpro/fcdprogui.h b/plugins/samplesource/fcdpro/fcdprogui.h index de38ae1de..4b807f1ab 100644 --- a/plugins/samplesource/fcdpro/fcdprogui.h +++ b/plugins/samplesource/fcdpro/fcdprogui.h @@ -102,6 +102,7 @@ private slots: void on_transverter_clicked(); void updateHardware(); void updateStatus(); + void openDeviceSettingsDialog(const QPoint& p); }; #endif // INCLUDE_FCDPROGUI_H diff --git a/plugins/samplesource/fcdpro/fcdproinput.cpp b/plugins/samplesource/fcdpro/fcdproinput.cpp index 2ba8b52c0..59cba5817 100644 --- a/plugins/samplesource/fcdpro/fcdproinput.cpp +++ b/plugins/samplesource/fcdpro/fcdproinput.cpp @@ -14,10 +14,13 @@ // along with this program. If not, see . // /////////////////////////////////////////////////////////////////////////////////// -#include #include #include +#include +#include +#include + #include "SWGDeviceSettings.h" #include "SWGDeviceState.h" @@ -47,10 +50,15 @@ FCDProInput::FCDProInput(DeviceSourceAPI *deviceAPI) : openDevice(); m_fileSink = new FileRecord(QString("test_%1.sdriq").arg(m_deviceAPI->getDeviceUID())); m_deviceAPI->addSink(m_fileSink); + m_networkManager = new QNetworkAccessManager(); + connect(m_networkManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(networkManagerFinished(QNetworkReply*))); } FCDProInput::~FCDProInput() { + disconnect(m_networkManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(networkManagerFinished(QNetworkReply*))); + delete m_networkManager; + if (m_running) { stop(); } @@ -275,6 +283,10 @@ bool FCDProInput::handleMessage(const Message& message) m_deviceAPI->stopAcquisition(); } + if (m_settings.m_useReverseAPI) { + webapiReverseSendStartStop(cmd.getStartStop()); + } + return true; } else if (MsgFileRecord::match(message)) @@ -308,6 +320,17 @@ bool FCDProInput::handleMessage(const Message& message) void FCDProInput::applySettings(const FCDProSettings& settings, bool force) { bool forwardChange = false; + QList reverseAPIKeys; + + if (force || (m_settings.m_centerFrequency != settings.m_centerFrequency)) { + reverseAPIKeys.append("centerFrequency"); + } + if (force || (m_settings.m_transverterMode != settings.m_transverterMode)) { + reverseAPIKeys.append("transverterMode"); + } + if (force || (m_settings.m_transverterDeltaFrequency != settings.m_transverterDeltaFrequency)) { + reverseAPIKeys.append("transverterDeltaFrequency"); + } if (force || (m_settings.m_centerFrequency != settings.m_centerFrequency) || (m_settings.m_transverterMode != settings.m_transverterMode) @@ -332,186 +355,181 @@ void FCDProInput::applySettings(const FCDProSettings& settings, bool force) if ((m_settings.m_lnaGainIndex != settings.m_lnaGainIndex) || force) { - m_settings.m_lnaGainIndex = settings.m_lnaGainIndex; + reverseAPIKeys.append("lnaGainIndex"); - if (m_dev != 0) - { + if (m_dev != 0) { set_lnaGain(settings.m_lnaGainIndex); } } if ((m_settings.m_rfFilterIndex != settings.m_rfFilterIndex) || force) { - m_settings.m_rfFilterIndex = settings.m_rfFilterIndex; + reverseAPIKeys.append("rfFilterIndex"); - if (m_dev != 0) - { + if (m_dev != 0) { set_rfFilter(settings.m_rfFilterIndex); } } if ((m_settings.m_lnaEnhanceIndex != settings.m_lnaEnhanceIndex) || force) { - m_settings.m_lnaEnhanceIndex = settings.m_lnaEnhanceIndex; + reverseAPIKeys.append("lnaEnhanceIndex"); - if (m_dev != 0) - { + if (m_dev != 0) { set_lnaEnhance(settings.m_lnaEnhanceIndex); } } if ((m_settings.m_bandIndex != settings.m_bandIndex) || force) { - m_settings.m_bandIndex = settings.m_bandIndex; + reverseAPIKeys.append("bandIndex"); - if (m_dev != 0) - { + if (m_dev != 0) { set_band(settings.m_bandIndex); } } if ((m_settings.m_mixerGainIndex != settings.m_mixerGainIndex) || force) { - m_settings.m_mixerGainIndex = settings.m_mixerGainIndex; + reverseAPIKeys.append("mixerGainIndex"); - if (m_dev != 0) - { + if (m_dev != 0) { set_mixerGain(settings.m_mixerGainIndex); } } if ((m_settings.m_mixerFilterIndex != settings.m_mixerFilterIndex) || force) { - m_settings.m_mixerFilterIndex = settings.m_mixerFilterIndex; + reverseAPIKeys.append("mixerFilterIndex"); - if (m_dev != 0) - { + if (m_dev != 0) { set_mixerFilter(settings.m_mixerFilterIndex); } } if ((m_settings.m_biasCurrentIndex != settings.m_biasCurrentIndex) || force) { - m_settings.m_biasCurrentIndex = settings.m_biasCurrentIndex; + reverseAPIKeys.append("biasCurrentIndex"); - if (m_dev != 0) - { + if (m_dev != 0) { set_biasCurrent(settings.m_biasCurrentIndex); } } if ((m_settings.m_modeIndex != settings.m_modeIndex) || force) { - m_settings.m_modeIndex = settings.m_modeIndex; + reverseAPIKeys.append("modeIndex"); - if (m_dev != 0) - { + if (m_dev != 0) { set_mode(settings.m_modeIndex); } } if ((m_settings.m_gain1Index != settings.m_gain1Index) || force) { - m_settings.m_gain1Index = settings.m_gain1Index; + reverseAPIKeys.append("gain1Index"); - if (m_dev != 0) - { + if (m_dev != 0) { set_gain1(settings.m_gain1Index); } } if ((m_settings.m_rcFilterIndex != settings.m_rcFilterIndex) || force) { - m_settings.m_rcFilterIndex = settings.m_rcFilterIndex; + reverseAPIKeys.append("rcFilterIndex"); - if (m_dev != 0) - { + if (m_dev != 0) { set_rcFilter(settings.m_rcFilterIndex); } } if ((m_settings.m_gain2Index != settings.m_gain2Index) || force) { - m_settings.m_gain2Index = settings.m_gain2Index; + reverseAPIKeys.append("gain2Index"); - if (m_dev != 0) - { + if (m_dev != 0) { set_gain2(settings.m_gain2Index); } } if ((m_settings.m_gain3Index != settings.m_gain3Index) || force) { - m_settings.m_gain3Index = settings.m_gain3Index; + reverseAPIKeys.append("gain3Index"); - if (m_dev != 0) - { + if (m_dev != 0) { set_gain3(settings.m_gain3Index); } } if ((m_settings.m_gain4Index != settings.m_gain4Index) || force) { - m_settings.m_gain4Index = settings.m_gain4Index; + reverseAPIKeys.append("gain4Index"); - if (m_dev != 0) - { + if (m_dev != 0) { set_gain4(settings.m_gain4Index); } } if ((m_settings.m_ifFilterIndex != settings.m_ifFilterIndex) || force) { - m_settings.m_ifFilterIndex = settings.m_ifFilterIndex; + reverseAPIKeys.append("ifFilterIndex"); - if (m_dev != 0) - { + if (m_dev != 0) { set_ifFilter(settings.m_ifFilterIndex); } } if ((m_settings.m_gain5Index != settings.m_gain5Index) || force) { - m_settings.m_gain5Index = settings.m_gain5Index; + reverseAPIKeys.append("gain5Index"); - if (m_dev != 0) - { + if (m_dev != 0) { set_gain5(settings.m_gain5Index); } } if ((m_settings.m_gain6Index != settings.m_gain6Index) || force) { - m_settings.m_gain6Index = settings.m_gain6Index; + reverseAPIKeys.append("gain6Index"); - if (m_dev != 0) - { + if (m_dev != 0) { set_gain6(settings.m_gain6Index); } } if ((m_settings.m_LOppmTenths != settings.m_LOppmTenths) || force) { - m_settings.m_LOppmTenths = settings.m_LOppmTenths; + reverseAPIKeys.append("LOppmTenths"); + m_settings.m_LOppmTenths = settings.m_LOppmTenths; - if (m_dev != 0) - { + if (m_dev != 0) { set_lo_ppm(); } } if ((m_settings.m_dcBlock != settings.m_dcBlock) || force) { - m_settings.m_dcBlock = settings.m_dcBlock; - m_deviceAPI->configureCorrections(m_settings.m_dcBlock, m_settings.m_iqCorrection); + reverseAPIKeys.append("dcBlock"); + m_deviceAPI->configureCorrections(settings.m_dcBlock, settings.m_iqCorrection); } if ((m_settings.m_iqCorrection != settings.m_iqCorrection) || force) { - m_settings.m_iqCorrection = settings.m_iqCorrection; - m_deviceAPI->configureCorrections(m_settings.m_dcBlock, m_settings.m_iqCorrection); + reverseAPIKeys.append("iqCorrection"); + m_deviceAPI->configureCorrections(settings.m_dcBlock, settings.m_iqCorrection); } + 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) { DSPSignalNotification *notif = new DSPSignalNotification(fcd_traits::sampleRate, m_settings.m_centerFrequency); @@ -948,3 +966,134 @@ void FCDProInput::webapiFormatDeviceSettings(SWGSDRangel::SWGDeviceSettings& res response.getFcdProSettings()->setFileRecordName(new QString(settings.m_fileRecordName)); } } + +void FCDProInput::webapiReverseSendSettings(QList& deviceSettingsKeys, const FCDProSettings& settings, bool force) +{ + SWGSDRangel::SWGDeviceSettings *swgDeviceSettings = new SWGSDRangel::SWGDeviceSettings(); + swgDeviceSettings->setTx(0); + swgDeviceSettings->setDeviceHwType(new QString("FCDPro")); + swgDeviceSettings->setFcdProSettings(new SWGSDRangel::SWGFCDProSettings()); + SWGSDRangel::SWGFCDProSettings *swgFCDProSettings = swgDeviceSettings->getFcdProSettings(); + + // transfer data that has been modified. When force is on transfer all data except reverse API data + + if (deviceSettingsKeys.contains("centerFrequency") || force) { + swgFCDProSettings->setCenterFrequency(settings.m_centerFrequency); + } + if (deviceSettingsKeys.contains("LOppmTenths") || force) { + swgFCDProSettings->setLOppmTenths(settings.m_LOppmTenths); + } + if (deviceSettingsKeys.contains("lnaGainIndex") || force) { + swgFCDProSettings->setLnaGainIndex(settings.m_lnaGainIndex); + } + if (deviceSettingsKeys.contains("rfFilterIndex") || force) { + swgFCDProSettings->setRfFilterIndex(settings.m_rfFilterIndex); + } + if (deviceSettingsKeys.contains("lnaEnhanceIndex") || force) { + swgFCDProSettings->setLnaEnhanceIndex(settings.m_lnaEnhanceIndex); + } + if (deviceSettingsKeys.contains("bandIndex") || force) { + swgFCDProSettings->setBandIndex(settings.m_bandIndex); + } + if (deviceSettingsKeys.contains("mixerGainIndex") || force) { + swgFCDProSettings->setMixerGainIndex(settings.m_mixerGainIndex); + } + if (deviceSettingsKeys.contains("mixerFilterIndex") || force) { + swgFCDProSettings->setMixerFilterIndex(settings.m_mixerFilterIndex); + } + if (deviceSettingsKeys.contains("biasCurrentIndex") || force) { + swgFCDProSettings->setBiasCurrentIndex(settings.m_biasCurrentIndex); + } + if (deviceSettingsKeys.contains("modeIndex") || force) { + swgFCDProSettings->setModeIndex(settings.m_modeIndex); + } + if (deviceSettingsKeys.contains("gain1Index") || force) { + swgFCDProSettings->setGain1Index(settings.m_gain1Index); + } + if (deviceSettingsKeys.contains("gain2Index") || force) { + swgFCDProSettings->setGain2Index(settings.m_gain2Index); + } + if (deviceSettingsKeys.contains("gain3Index") || force) { + swgFCDProSettings->setGain3Index(settings.m_gain3Index); + } + if (deviceSettingsKeys.contains("gain4Index") || force) { + swgFCDProSettings->setGain4Index(settings.m_gain4Index); + } + if (deviceSettingsKeys.contains("gain5Index") || force) { + swgFCDProSettings->setGain5Index(settings.m_gain5Index); + } + if (deviceSettingsKeys.contains("gain6Index") || force) { + swgFCDProSettings->setGain6Index(settings.m_gain6Index); + } + if (deviceSettingsKeys.contains("rcFilterIndex") || force) { + swgFCDProSettings->setRcFilterIndex(settings.m_rcFilterIndex); + } + if (deviceSettingsKeys.contains("ifFilterIndex") || force) { + swgFCDProSettings->setIfFilterIndex(settings.m_ifFilterIndex); + } + if (deviceSettingsKeys.contains("dcBlock") || force) { + swgFCDProSettings->setDcBlock(settings.m_dcBlock ? 1 : 0); + } + if (deviceSettingsKeys.contains("iqCorrection") || force) { + swgFCDProSettings->setIqCorrection(settings.m_iqCorrection ? 1 : 0); + } + if (deviceSettingsKeys.contains("transverterDeltaFrequency") || force) { + swgFCDProSettings->setTransverterDeltaFrequency(settings.m_transverterDeltaFrequency); + } + if (deviceSettingsKeys.contains("transverterMode") || force) { + swgFCDProSettings->setTransverterMode(settings.m_transverterMode ? 1 : 0); + } + if (deviceSettingsKeys.contains("fileRecordName") || force) { + swgFCDProSettings->setFileRecordName(new QString(settings.m_fileRecordName)); + } + + 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 FCDProInput::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 FCDProInput::networkManagerFinished(QNetworkReply *reply) +{ + QNetworkReply::NetworkError replyError = reply->error(); + + if (replyError) + { + qWarning() << "FCDProInput::networkManagerFinished:" + << " error(" << (int) replyError + << "): " << replyError + << ": " << reply->errorString(); + return; + } + + QString answer = reply->readAll(); + answer.chop(1); // remove last \n + qDebug("FCDProInput::networkManagerFinished: reply:\n%s", answer.toStdString().c_str()); +} diff --git a/plugins/samplesource/fcdpro/fcdproinput.h b/plugins/samplesource/fcdpro/fcdproinput.h index aa0c7240f..06df9e25e 100644 --- a/plugins/samplesource/fcdpro/fcdproinput.h +++ b/plugins/samplesource/fcdpro/fcdproinput.h @@ -17,9 +17,11 @@ #ifndef INCLUDE_FCDPROINPUT_H #define INCLUDE_FCDPROINPUT_H +#include + #include #include -#include +#include #include "dsp/devicesamplesource.h" #include "audio/audioinput.h" @@ -33,11 +35,14 @@ struct fcd_buffer { std::size_t length; }; +class QNetworkAccessManager; +class QNetworkReply; class DeviceSourceAPI; class FCDProThread; class FileRecord; class FCDProInput : public DeviceSampleSource { + Q_OBJECT public: class MsgConfigureFCDPro : public Message { MESSAGE_CLASS_DECLARATION @@ -158,15 +163,6 @@ public: void set_gain6(int index); private: - bool openDevice(); - void closeDevice(); - bool openFCDAudio(const char *filename); - void closeFCDAudio(); - void applySettings(const FCDProSettings& settings, bool force); - void set_lo_ppm(); - - void webapiFormatDeviceSettings(SWGSDRangel::SWGDeviceSettings& response, const FCDProSettings& settings); - DeviceSourceAPI *m_deviceAPI; hid_device *m_dev; AudioInput m_fcdAudioInput; @@ -177,6 +173,22 @@ private: QString m_deviceDescription; bool m_running; FileRecord *m_fileSink; //!< File sink to record device I/Q output + QNetworkAccessManager *m_networkManager; + QNetworkRequest m_networkRequest; + + bool openDevice(); + void closeDevice(); + bool openFCDAudio(const char *filename); + void closeFCDAudio(); + void applySettings(const FCDProSettings& settings, bool force); + void set_lo_ppm(); + + void webapiFormatDeviceSettings(SWGSDRangel::SWGDeviceSettings& response, const FCDProSettings& settings); + void webapiReverseSendSettings(QList& deviceSettingsKeys, const FCDProSettings& settings, bool force); + void webapiReverseSendStartStop(bool start); + +private slots: + void networkManagerFinished(QNetworkReply *reply); }; #endif // INCLUDE_FCDPROINPUT_H diff --git a/plugins/samplesource/fcdpro/fcdprosettings.cpp b/plugins/samplesource/fcdpro/fcdprosettings.cpp index 65c92133a..18e809f4b 100644 --- a/plugins/samplesource/fcdpro/fcdprosettings.cpp +++ b/plugins/samplesource/fcdpro/fcdprosettings.cpp @@ -48,6 +48,10 @@ void FCDProSettings::resetToDefaults() m_transverterMode = false; m_transverterDeltaFrequency = 0; m_fileRecordName = ""; + m_useReverseAPI = false; + m_reverseAPIAddress = "127.0.0.1"; + m_reverseAPIPort = 8888; + m_reverseAPIDeviceIndex = 0; } QByteArray FCDProSettings::serialize() const @@ -75,6 +79,10 @@ QByteArray FCDProSettings::serialize() const s.writeS32(19, m_gain6Index); s.writeBool(20, m_transverterMode); s.writeS64(21, m_transverterDeltaFrequency); + s.writeBool(22, m_useReverseAPI); + s.writeString(23, m_reverseAPIAddress); + s.writeU32(24, m_reverseAPIPort); + s.writeU32(25, m_reverseAPIDeviceIndex); return s.final(); } @@ -91,6 +99,8 @@ bool FCDProSettings::deserialize(const QByteArray& data) if (d.getVersion() == 1) { + uint32_t uintval; + d.readBool(1, &m_dcBlock, false); d.readBool(2, &m_iqCorrection, false); d.readS32(3, &m_LOppmTenths, 0); @@ -112,6 +122,18 @@ bool FCDProSettings::deserialize(const QByteArray& data) d.readS32(19, &m_gain6Index, 0); d.readBool(20, &m_transverterMode, false); d.readS64(21, &m_transverterDeltaFrequency, 0); + d.readBool(22, &m_useReverseAPI, false); + d.readString(23, &m_reverseAPIAddress, "127.0.0.1"); + d.readU32(24, &uintval, 0); + + if ((uintval > 1023) && (uintval < 65535)) { + m_reverseAPIPort = uintval; + } else { + m_reverseAPIPort = 8888; + } + + d.readU32(25, &uintval, 0); + m_reverseAPIDeviceIndex = uintval > 99 ? 99 : uintval; return true; } diff --git a/plugins/samplesource/fcdpro/fcdprosettings.h b/plugins/samplesource/fcdpro/fcdprosettings.h index f4972717d..4ef9d1d8e 100644 --- a/plugins/samplesource/fcdpro/fcdprosettings.h +++ b/plugins/samplesource/fcdpro/fcdprosettings.h @@ -43,6 +43,10 @@ struct FCDProSettings { bool m_transverterMode; qint64 m_transverterDeltaFrequency; QString m_fileRecordName; + bool m_useReverseAPI; + QString m_reverseAPIAddress; + uint16_t m_reverseAPIPort; + uint16_t m_reverseAPIDeviceIndex; FCDProSettings(); void resetToDefaults(); diff --git a/plugins/samplesource/fcdproplus/fcdproplusgui.cpp b/plugins/samplesource/fcdproplus/fcdproplusgui.cpp index 7b261a9ca..5f2c92d77 100644 --- a/plugins/samplesource/fcdproplus/fcdproplusgui.cpp +++ b/plugins/samplesource/fcdproplus/fcdproplusgui.cpp @@ -20,6 +20,8 @@ #include "ui_fcdproplusgui.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 "fcdproplusgui.h" @@ -61,6 +63,9 @@ FCDProPlusGui::FCDProPlusGui(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); @@ -349,3 +354,22 @@ void FCDProPlusGui::on_transverter_clicked() m_settings.m_centerFrequency = ui->centerFrequency->getValueNew()*1000; sendSettings(); } + +void FCDProPlusGui::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/samplesource/fcdproplus/fcdproplusgui.h b/plugins/samplesource/fcdproplus/fcdproplusgui.h index 56be9dacd..81649fb11 100644 --- a/plugins/samplesource/fcdproplus/fcdproplusgui.h +++ b/plugins/samplesource/fcdproplus/fcdproplusgui.h @@ -89,6 +89,7 @@ private slots: void on_transverter_clicked(); void updateHardware(); void updateStatus(); + void openDeviceSettingsDialog(const QPoint& p); }; #endif // INCLUDE_FCDGUI_H diff --git a/plugins/samplesource/fcdproplus/fcdproplusinput.cpp b/plugins/samplesource/fcdproplus/fcdproplusinput.cpp index 4c9776e13..940ad9d83 100644 --- a/plugins/samplesource/fcdproplus/fcdproplusinput.cpp +++ b/plugins/samplesource/fcdproplus/fcdproplusinput.cpp @@ -14,10 +14,13 @@ // along with this program. If not, see . // /////////////////////////////////////////////////////////////////////////////////// -#include #include #include +#include +#include +#include + #include "SWGDeviceSettings.h" #include "SWGDeviceState.h" @@ -47,10 +50,15 @@ FCDProPlusInput::FCDProPlusInput(DeviceSourceAPI *deviceAPI) : openDevice(); m_fileSink = new FileRecord(QString("test_%1.sdriq").arg(m_deviceAPI->getDeviceUID())); m_deviceAPI->addSink(m_fileSink); + m_networkManager = new QNetworkAccessManager(); + connect(m_networkManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(networkManagerFinished(QNetworkReply*))); } FCDProPlusInput::~FCDProPlusInput() { + disconnect(m_networkManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(networkManagerFinished(QNetworkReply*))); + delete m_networkManager; + if (m_running) { stop(); } @@ -277,6 +285,10 @@ bool FCDProPlusInput::handleMessage(const Message& message) m_deviceAPI->stopAcquisition(); } + if (m_settings.m_useReverseAPI) { + webapiReverseSendStartStop(cmd.getStartStop()); + } + return true; } else if (MsgFileRecord::match(message)) @@ -310,6 +322,17 @@ bool FCDProPlusInput::handleMessage(const Message& message) void FCDProPlusInput::applySettings(const FCDProPlusSettings& settings, bool force) { bool forwardChange = false; + QList reverseAPIKeys; + + if (force || (m_settings.m_centerFrequency != settings.m_centerFrequency)) { + reverseAPIKeys.append("centerFrequency"); + } + if (force || (m_settings.m_transverterMode != settings.m_transverterMode)) { + reverseAPIKeys.append("transverterMode"); + } + if (force || (m_settings.m_transverterDeltaFrequency != settings.m_transverterDeltaFrequency)) { + reverseAPIKeys.append("transverterDeltaFrequency"); + } if (force || (m_settings.m_centerFrequency != settings.m_centerFrequency) || (m_settings.m_transverterMode != settings.m_transverterMode) @@ -319,8 +342,7 @@ void FCDProPlusInput::applySettings(const FCDProPlusSettings& settings, bool for deviceCenterFrequency -= settings.m_transverterMode ? settings.m_transverterDeltaFrequency : 0; deviceCenterFrequency = deviceCenterFrequency < 0 ? 0 : deviceCenterFrequency; - if (m_dev != 0) - { + if (m_dev != 0) { set_center_freq((double) deviceCenterFrequency); } @@ -334,86 +356,89 @@ void FCDProPlusInput::applySettings(const FCDProPlusSettings& settings, bool for if ((m_settings.m_lnaGain != settings.m_lnaGain) || force) { - m_settings.m_lnaGain = settings.m_lnaGain; + reverseAPIKeys.append("lnaGain"); - if (m_dev != 0) - { + if (m_dev != 0) { set_lna_gain(settings.m_lnaGain); } } if ((m_settings.m_biasT != settings.m_biasT) || force) { - m_settings.m_biasT = settings.m_biasT; + reverseAPIKeys.append("biasT"); - if (m_dev != 0) - { + if (m_dev != 0) { set_bias_t(settings.m_biasT); } } if ((m_settings.m_mixGain != settings.m_mixGain) || force) { - m_settings.m_mixGain = settings.m_mixGain; + reverseAPIKeys.append("mixGain"); - if (m_dev != 0) - { + if (m_dev != 0) { set_mixer_gain(settings.m_mixGain); } } if ((m_settings.m_ifGain != settings.m_ifGain) || force) { - m_settings.m_ifGain = settings.m_ifGain; + reverseAPIKeys.append("ifGain"); - if (m_dev != 0) - { + if (m_dev != 0) { set_if_gain(settings.m_ifGain); } } if ((m_settings.m_ifFilterIndex != settings.m_ifFilterIndex) || force) { - m_settings.m_ifFilterIndex = settings.m_ifFilterIndex; + reverseAPIKeys.append("ifFilterIndex"); - if (m_dev != 0) - { + if (m_dev != 0) { set_if_filter(settings.m_ifFilterIndex); } } if ((m_settings.m_rfFilterIndex != settings.m_rfFilterIndex) || force) { - m_settings.m_rfFilterIndex = settings.m_rfFilterIndex; - - if (m_dev != 0) - { + if (m_dev != 0) { set_rf_filter(settings.m_rfFilterIndex); } } if ((m_settings.m_LOppmTenths != settings.m_LOppmTenths) || force) { + reverseAPIKeys.append("LOppmTenths"); m_settings.m_LOppmTenths = settings.m_LOppmTenths; - if (m_dev != 0) - { + if (m_dev != 0) { set_lo_ppm(); } } if ((m_settings.m_dcBlock != settings.m_dcBlock) || force) { - m_settings.m_dcBlock = settings.m_dcBlock; - m_deviceAPI->configureCorrections(m_settings.m_dcBlock, m_settings.m_iqImbalance); + reverseAPIKeys.append("dcBlock"); + m_deviceAPI->configureCorrections(settings.m_dcBlock, settings.m_iqImbalance); } if ((m_settings.m_iqImbalance != settings.m_iqImbalance) || force) { - m_settings.m_iqImbalance = settings.m_iqImbalance; - m_deviceAPI->configureCorrections(m_settings.m_dcBlock, m_settings.m_iqImbalance); + reverseAPIKeys.append("iqImbalance"); + m_deviceAPI->configureCorrections(settings.m_dcBlock, settings.m_iqImbalance); } + 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) { DSPSignalNotification *notif = new DSPSignalNotification(fcd_traits::sampleRate, m_settings.m_centerFrequency); @@ -631,4 +656,103 @@ void FCDProPlusInput::webapiFormatDeviceSettings(SWGSDRangel::SWGDeviceSettings& } } +void FCDProPlusInput::webapiReverseSendSettings(QList& deviceSettingsKeys, const FCDProPlusSettings& settings, bool force) +{ + SWGSDRangel::SWGDeviceSettings *swgDeviceSettings = new SWGSDRangel::SWGDeviceSettings(); + swgDeviceSettings->setTx(0); + swgDeviceSettings->setDeviceHwType(new QString("FCDPro+")); + swgDeviceSettings->setFcdProPlusSettings(new SWGSDRangel::SWGFCDProPlusSettings()); + SWGSDRangel::SWGFCDProPlusSettings *swgFCDProPlusSettings = swgDeviceSettings->getFcdProPlusSettings(); + // transfer data that has been modified. When force is on transfer all data except reverse API data + + if (deviceSettingsKeys.contains("centerFrequency") || force) { + swgFCDProPlusSettings->setCenterFrequency(settings.m_centerFrequency); + } + if (deviceSettingsKeys.contains("rangeLow") || force) { + swgFCDProPlusSettings->setRangeLow(settings.m_rangeLow ? 1 : 0); + } + if (deviceSettingsKeys.contains("lnaGain") || force) { + swgFCDProPlusSettings->setLnaGain(settings.m_lnaGain ? 1 : 0); + } + if (deviceSettingsKeys.contains("mixGain") || force) { + swgFCDProPlusSettings->setMixGain(settings.m_mixGain ? 1 : 0); + } + if (deviceSettingsKeys.contains("biasT") || force) { + swgFCDProPlusSettings->setBiasT(settings.m_biasT ? 1 : 0); + } + if (deviceSettingsKeys.contains("ifGain") || force) { + swgFCDProPlusSettings->setIfGain(settings.m_ifGain); + } + if (deviceSettingsKeys.contains("ifFilterIndex") || force) { + swgFCDProPlusSettings->setIfFilterIndex(settings.m_ifFilterIndex); + } + if (deviceSettingsKeys.contains("LOppmTenths") || force) { + swgFCDProPlusSettings->setLOppmTenths(settings.m_LOppmTenths); + } + if (deviceSettingsKeys.contains("dcBlock") || force) { + swgFCDProPlusSettings->setDcBlock(settings.m_dcBlock ? 1 : 0); + } + if (deviceSettingsKeys.contains("iqImbalance") || force) { + swgFCDProPlusSettings->setIqImbalance(settings.m_iqImbalance ? 1 : 0); + } + if (deviceSettingsKeys.contains("transverterDeltaFrequency") || force) { + swgFCDProPlusSettings->setTransverterDeltaFrequency(settings.m_transverterDeltaFrequency); + } + if (deviceSettingsKeys.contains("transverterMode") || force) { + swgFCDProPlusSettings->setTransverterMode(settings.m_transverterMode ? 1 : 0); + } + if (deviceSettingsKeys.contains("fileRecordName") || force) { + swgFCDProPlusSettings->setFileRecordName(new QString(settings.m_fileRecordName)); + } + + 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 FCDProPlusInput::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 FCDProPlusInput::networkManagerFinished(QNetworkReply *reply) +{ + QNetworkReply::NetworkError replyError = reply->error(); + + if (replyError) + { + qWarning() << "FCDProPlusInput::networkManagerFinished:" + << " error(" << (int) replyError + << "): " << replyError + << ": " << reply->errorString(); + return; + } + + QString answer = reply->readAll(); + answer.chop(1); // remove last \n + qDebug("FCDProPlusInput::networkManagerFinished: reply:\n%s", answer.toStdString().c_str()); +} diff --git a/plugins/samplesource/fcdproplus/fcdproplusinput.h b/plugins/samplesource/fcdproplus/fcdproplusinput.h index 94206cd61..be5af4a71 100644 --- a/plugins/samplesource/fcdproplus/fcdproplusinput.h +++ b/plugins/samplesource/fcdproplus/fcdproplusinput.h @@ -17,9 +17,11 @@ #ifndef INCLUDE_FCDINPUT_H #define INCLUDE_FCDINPUT_H +#include + #include #include -#include +#include #include "dsp/devicesamplesource.h" #include "audio/audioinput.h" @@ -33,11 +35,14 @@ struct fcd_buffer { std::size_t length; }; +class QNetworkAccessManager; +class QNetworkReply; class DeviceSourceAPI; class FCDProPlusThread; class FileRecord; class FCDProPlusInput : public DeviceSampleSource { + Q_OBJECT public: class MsgConfigureFCDProPlus : public Message { MESSAGE_CLASS_DECLARATION @@ -148,13 +153,6 @@ public: void set_lo_ppm(); private: - bool openDevice(); - void closeDevice(); - bool openFCDAudio(const char *filename); - void closeFCDAudio(); - void applySettings(const FCDProPlusSettings& settings, bool force); - void webapiFormatDeviceSettings(SWGSDRangel::SWGDeviceSettings& response, const FCDProPlusSettings& settings); - DeviceSourceAPI *m_deviceAPI; hid_device *m_dev; AudioInput m_fcdAudioInput; @@ -165,6 +163,20 @@ private: QString m_deviceDescription; bool m_running; FileRecord *m_fileSink; //!< File sink to record device I/Q output + QNetworkAccessManager *m_networkManager; + QNetworkRequest m_networkRequest; + + bool openDevice(); + void closeDevice(); + bool openFCDAudio(const char *filename); + void closeFCDAudio(); + void applySettings(const FCDProPlusSettings& settings, bool force); + void webapiFormatDeviceSettings(SWGSDRangel::SWGDeviceSettings& response, const FCDProPlusSettings& settings); + void webapiReverseSendSettings(QList& deviceSettingsKeys, const FCDProPlusSettings& settings, bool force); + void webapiReverseSendStartStop(bool start); + +private slots: + void networkManagerFinished(QNetworkReply *reply); }; #endif // INCLUDE_FCD_H diff --git a/plugins/samplesource/fcdproplus/fcdproplussettings.cpp b/plugins/samplesource/fcdproplus/fcdproplussettings.cpp index 59d10c2d1..ba6d46367 100644 --- a/plugins/samplesource/fcdproplus/fcdproplussettings.cpp +++ b/plugins/samplesource/fcdproplus/fcdproplussettings.cpp @@ -39,6 +39,10 @@ void FCDProPlusSettings::resetToDefaults() m_transverterMode = false; m_transverterDeltaFrequency = 0; m_fileRecordName = ""; + m_useReverseAPI = false; + m_reverseAPIAddress = "127.0.0.1"; + m_reverseAPIPort = 8888; + m_reverseAPIDeviceIndex = 0; } QByteArray FCDProPlusSettings::serialize() const @@ -56,6 +60,10 @@ QByteArray FCDProPlusSettings::serialize() const s.writeU32(9, m_ifGain); s.writeBool(10, m_transverterMode); s.writeS64(11, m_transverterDeltaFrequency); + s.writeBool(12, m_useReverseAPI); + s.writeString(13, m_reverseAPIAddress); + s.writeU32(14, m_reverseAPIPort); + s.writeU32(15, m_reverseAPIDeviceIndex); return s.final(); } @@ -72,6 +80,8 @@ bool FCDProPlusSettings::deserialize(const QByteArray& data) if (d.getVersion() == 1) { + uint32_t uintval; + d.readBool(1, &m_biasT, false); d.readBool(2, &m_rangeLow, false); d.readBool(3, &m_mixGain, true); @@ -83,7 +93,18 @@ bool FCDProPlusSettings::deserialize(const QByteArray& data) d.readU32(9, &m_ifGain, 0); d.readBool(10, &m_transverterMode, false); d.readS64(11, &m_transverterDeltaFrequency, 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; } else diff --git a/plugins/samplesource/fcdproplus/fcdproplussettings.h b/plugins/samplesource/fcdproplus/fcdproplussettings.h index f4fe21c3d..7d505dcb4 100644 --- a/plugins/samplesource/fcdproplus/fcdproplussettings.h +++ b/plugins/samplesource/fcdproplus/fcdproplussettings.h @@ -34,6 +34,10 @@ struct FCDProPlusSettings { bool m_transverterMode; qint64 m_transverterDeltaFrequency; QString m_fileRecordName; + bool m_useReverseAPI; + QString m_reverseAPIAddress; + uint16_t m_reverseAPIPort; + uint16_t m_reverseAPIDeviceIndex; FCDProPlusSettings(); void resetToDefaults();