From 802c5fe53b9a58869c4529ddd33f893cf4d2e5ce Mon Sep 17 00:00:00 2001 From: f4exb Date: Wed, 26 Dec 2018 11:29:20 +0100 Subject: [PATCH] Reverse API: HackRF input --- .../samplesource/hackrfinput/hackrfinput.cpp | 219 ++++++++++++++---- .../samplesource/hackrfinput/hackrfinput.h | 26 ++- .../hackrfinput/hackrfinputgui.cpp | 24 ++ .../samplesource/hackrfinput/hackrfinputgui.h | 1 + .../hackrfinput/hackrfinputplugin.cpp | 2 +- .../hackrfinput/hackrfinputsettings.cpp | 23 +- .../hackrfinput/hackrfinputsettings.h | 4 + 7 files changed, 243 insertions(+), 56 deletions(-) diff --git a/plugins/samplesource/hackrfinput/hackrfinput.cpp b/plugins/samplesource/hackrfinput/hackrfinput.cpp index 2e0dc8dc9..614e86dd3 100644 --- a/plugins/samplesource/hackrfinput/hackrfinput.cpp +++ b/plugins/samplesource/hackrfinput/hackrfinput.cpp @@ -14,11 +14,12 @@ // along with this program. If not, see . // /////////////////////////////////////////////////////////////////////////////////// -#include "hackrfinput.h" - #include #include + #include +#include +#include #include "SWGDeviceSettings.h" #include "SWGDeviceState.h" @@ -32,6 +33,7 @@ #include "hackrf/devicehackrfvalues.h" #include "hackrf/devicehackrfshared.h" +#include "hackrfinput.h" #include "hackrfinputthread.h" MESSAGE_CLASS_DEFINITION(HackRFInput::MsgConfigureHackRF, Message) @@ -53,11 +55,20 @@ HackRFInput::HackRFInput(DeviceSourceAPI *deviceAPI) : m_deviceAPI->addSink(m_fileSink); m_deviceAPI->setBuddySharedPtr(&m_sharedParams); + + m_networkManager = new QNetworkAccessManager(); + connect(m_networkManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(networkManagerFinished(QNetworkReply*))); } HackRFInput::~HackRFInput() { - if (m_running) stop(); + disconnect(m_networkManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(networkManagerFinished(QNetworkReply*))); + delete m_networkManager; + + if (m_running) { + stop(); + } + m_deviceAPI->removeSink(m_fileSink); delete m_fileSink; closeDevice(); @@ -292,6 +303,10 @@ bool HackRFInput::handleMessage(const Message& message) m_deviceAPI->stopAcquisition(); } + if (m_settings.m_useReverseAPI) { + webapiReverseSendStartStop(cmd.getStartStop()); + } + return true; } else @@ -323,9 +338,20 @@ bool HackRFInput::applySettings(const HackRFInputSettings& settings, bool force) bool forwardChange = false; hackrf_error rc; + QList reverseAPIKeys; qDebug() << "HackRFInput::applySettings"; + if ((m_settings.m_dcBlock != settings.m_dcBlock) || force) { + reverseAPIKeys.append("dcBlock"); + } + if ((m_settings.m_iqCorrection != settings.m_iqCorrection) || force) { + reverseAPIKeys.append("iqCorrection"); + } + if ((m_settings.m_linkTxFrequency != settings.m_linkTxFrequency) || force) { + reverseAPIKeys.append("linkTxFrequency"); + } + if ((m_settings.m_dcBlock != settings.m_dcBlock) || (m_settings.m_iqCorrection != settings.m_iqCorrection) || force) { @@ -334,6 +360,7 @@ bool HackRFInput::applySettings(const HackRFInputSettings& settings, bool force) if ((m_settings.m_devSampleRate != settings.m_devSampleRate) || force) { + reverseAPIKeys.append("devSampleRate"); forwardChange = true; if (m_dev != 0) @@ -357,6 +384,7 @@ bool HackRFInput::applySettings(const HackRFInputSettings& settings, bool force) if ((m_settings.m_log2Decim != settings.m_log2Decim) || force) { + reverseAPIKeys.append("log2Decim"); forwardChange = true; if (m_hackRFThread != 0) @@ -368,7 +396,9 @@ bool HackRFInput::applySettings(const HackRFInputSettings& settings, bool force) if (force || (m_settings.m_centerFrequency != settings.m_centerFrequency)) // forward delta to buddy if necessary { - if (m_settings.m_linkTxFrequency && (m_deviceAPI->getSinkBuddies().size() > 0)) + reverseAPIKeys.append("centerFrequency"); + + if (m_settings.m_linkTxFrequency && (m_deviceAPI->getSinkBuddies().size() > 0)) { DeviceSinkAPI *buddy = m_deviceAPI->getSinkBuddies()[0]; DeviceHackRFShared::MsgConfigureFrequencyDelta *deltaMsg = DeviceHackRFShared::MsgConfigureFrequencyDelta::create( @@ -384,6 +414,13 @@ bool HackRFInput::applySettings(const HackRFInputSettings& settings, bool force) } } + if ((m_settings.m_LOppmTenths != settings.m_LOppmTenths) || force) { + reverseAPIKeys.append("LOppmTenths"); + } + if ((m_settings.m_fcPos != settings.m_fcPos) || force) { + reverseAPIKeys.append("fcPos"); + } + if ((m_settings.m_centerFrequency != settings.m_centerFrequency) || (m_settings.m_devSampleRate != settings.m_devSampleRate) || (m_settings.m_LOppmTenths != settings.m_LOppmTenths) || @@ -415,16 +452,15 @@ bool HackRFInput::applySettings(const HackRFInputSettings& settings, bool force) if ((m_settings.m_lnaGain != settings.m_lnaGain) || force) { + reverseAPIKeys.append("lnaGain"); + if (m_dev != 0) { rc = (hackrf_error) hackrf_set_lna_gain(m_dev, settings.m_lnaGain); - if(rc != HACKRF_SUCCESS) - { + if (rc != HACKRF_SUCCESS) { qDebug("HackRFInput::applySettings: airspy_set_lna_gain failed: %s", hackrf_error_name(rc)); - } - else - { + } else { qDebug() << "HackRFInput:applySettings: LNA gain set to " << settings.m_lnaGain; } } @@ -432,16 +468,15 @@ bool HackRFInput::applySettings(const HackRFInputSettings& settings, bool force) if ((m_settings.m_vgaGain != settings.m_vgaGain) || force) { + reverseAPIKeys.append("vgaGain"); + if (m_dev != 0) { rc = (hackrf_error) hackrf_set_vga_gain(m_dev, settings.m_vgaGain); - if (rc != HACKRF_SUCCESS) - { + if (rc != HACKRF_SUCCESS) { qDebug("HackRFInput::applySettings: hackrf_set_vga_gain failed: %s", hackrf_error_name(rc)); - } - else - { + } else { qDebug() << "HackRFInput:applySettings: VGA gain set to " << settings.m_vgaGain; } } @@ -449,17 +484,16 @@ bool HackRFInput::applySettings(const HackRFInputSettings& settings, bool force) if ((m_settings.m_bandwidth != settings.m_bandwidth) || force) { + reverseAPIKeys.append("bandwidth"); + if (m_dev != 0) { uint32_t bw_index = hackrf_compute_baseband_filter_bw_round_down_lt(settings.m_bandwidth + 1); // +1 so the round down to lower than yields desired bandwidth rc = (hackrf_error) hackrf_set_baseband_filter_bandwidth(m_dev, bw_index); - if (rc != HACKRF_SUCCESS) - { + if (rc != HACKRF_SUCCESS) { qDebug("HackRFInput::applySettings: hackrf_set_baseband_filter_bandwidth failed: %s", hackrf_error_name(rc)); - } - else - { + } else { qDebug() << "HackRFInput:applySettings: Baseband BW filter set to " << settings.m_bandwidth << " Hz"; } } @@ -467,16 +501,15 @@ bool HackRFInput::applySettings(const HackRFInputSettings& settings, bool force) if ((m_settings.m_biasT != settings.m_biasT) || force) { + reverseAPIKeys.append("biasT"); + if (m_dev != 0) { rc = (hackrf_error) hackrf_set_antenna_enable(m_dev, (settings.m_biasT ? 1 : 0)); - if(rc != HACKRF_SUCCESS) - { + if (rc != HACKRF_SUCCESS) { qDebug("HackRFInput::applySettings: hackrf_set_antenna_enable failed: %s", hackrf_error_name(rc)); - } - else - { + } else { qDebug() << "HackRFInput:applySettings: bias tee set to " << settings.m_biasT; } } @@ -484,16 +517,15 @@ bool HackRFInput::applySettings(const HackRFInputSettings& settings, bool force) if ((m_settings.m_lnaExt != settings.m_lnaExt) || force) { + reverseAPIKeys.append("lnaExt"); + if (m_dev != 0) { rc = (hackrf_error) hackrf_set_amp_enable(m_dev, (settings.m_lnaExt ? 1 : 0)); - if(rc != HACKRF_SUCCESS) - { + if (rc != HACKRF_SUCCESS) { qDebug("HackRFInput::applySettings: hackrf_set_amp_enable failed: %s", hackrf_error_name(rc)); - } - else - { + } else { qDebug() << "HackRFInput:applySettings: extra LNA set to " << settings.m_lnaExt; } } @@ -507,6 +539,15 @@ bool HackRFInput::applySettings(const HackRFInputSettings& settings, bool force) 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; qDebug() << "HackRFInput::applySettings: " @@ -656,20 +697,106 @@ int HackRFInput::webapiRun( return 200; } -//hackrf_device *HackRFInput::open_hackrf_from_sequence(int sequence) -//{ -// hackrf_device_list_t *hackrf_devices = hackrf_device_list(); -// hackrf_device *hackrf_ptr; -// hackrf_error rc; -// -// rc = (hackrf_error) hackrf_device_list_open(hackrf_devices, sequence, &hackrf_ptr); -// -// if (rc == HACKRF_SUCCESS) -// { -// return hackrf_ptr; -// } -// else -// { -// return 0; -// } -//} +void HackRFInput::webapiReverseSendSettings(QList& deviceSettingsKeys, const HackRFInputSettings& settings, bool force) +{ + SWGSDRangel::SWGDeviceSettings *swgDeviceSettings = new SWGSDRangel::SWGDeviceSettings(); + swgDeviceSettings->setTx(0); + swgDeviceSettings->setDeviceHwType(new QString("HackRF")); + swgDeviceSettings->setHackRfInputSettings(new SWGSDRangel::SWGHackRFInputSettings()); + SWGSDRangel::SWGHackRFInputSettings *swgHackRFInputSettings = swgDeviceSettings->getHackRfInputSettings(); + + // transfer data that has been modified. When force is on transfer all data except reverse API data + + if (deviceSettingsKeys.contains("centerFrequency") || force) { + swgHackRFInputSettings->setCenterFrequency(settings.m_centerFrequency); + } + if (deviceSettingsKeys.contains("LOppmTenths") || force) { + swgHackRFInputSettings->setLOppmTenths(settings.m_LOppmTenths); + } + if (deviceSettingsKeys.contains("bandwidth") || force) { + swgHackRFInputSettings->setBandwidth(settings.m_bandwidth); + } + if (deviceSettingsKeys.contains("lnaGain") || force) { + swgHackRFInputSettings->setLnaGain(settings.m_lnaGain); + } + if (deviceSettingsKeys.contains("vgaGain") || force) { + swgHackRFInputSettings->setVgaGain(settings.m_vgaGain); + } + if (deviceSettingsKeys.contains("log2Decim") || force) { + swgHackRFInputSettings->setLog2Decim(settings.m_log2Decim); + } + if (deviceSettingsKeys.contains("fcPos") || force) { + swgHackRFInputSettings->setFcPos((int) settings.m_fcPos); + } + if (deviceSettingsKeys.contains("devSampleRate") || force) { + swgHackRFInputSettings->setDevSampleRate(settings.m_devSampleRate); + } + if (deviceSettingsKeys.contains("biasT") || force) { + swgHackRFInputSettings->setBiasT(settings.m_biasT ? 1 : 0); + } + if (deviceSettingsKeys.contains("lnaExt") || force) { + swgHackRFInputSettings->setLnaExt(settings.m_lnaExt ? 1 : 0); + } + if (deviceSettingsKeys.contains("dcBlock") || force) { + swgHackRFInputSettings->setDcBlock(settings.m_dcBlock ? 1 : 0); + } + if (deviceSettingsKeys.contains("iqCorrection") || force) { + swgHackRFInputSettings->setIqCorrection(settings.m_iqCorrection ? 1 : 0); + } + if (deviceSettingsKeys.contains("linkTxFrequency") || force) { + swgHackRFInputSettings->setLinkTxFrequency(settings.m_linkTxFrequency ? 1 : 0); + } + if (deviceSettingsKeys.contains("fileRecordName") || force) { + swgHackRFInputSettings->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 HackRFInput::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 HackRFInput::networkManagerFinished(QNetworkReply *reply) +{ + QNetworkReply::NetworkError replyError = reply->error(); + + if (replyError) + { + qWarning() << "HackRFInput::networkManagerFinished:" + << " error(" << (int) replyError + << "): " << replyError + << ": " << reply->errorString(); + return; + } + + QString answer = reply->readAll(); + answer.chop(1); // remove last \n + qDebug("HackRFInput::networkManagerFinished: reply:\n%s", answer.toStdString().c_str()); +} diff --git a/plugins/samplesource/hackrfinput/hackrfinput.h b/plugins/samplesource/hackrfinput/hackrfinput.h index 890e6d616..4204d4d9a 100644 --- a/plugins/samplesource/hackrfinput/hackrfinput.h +++ b/plugins/samplesource/hackrfinput/hackrfinput.h @@ -19,18 +19,22 @@ #include #include +#include #include "libhackrf/hackrf.h" -#include +#include "dsp/devicesamplesource.h" #include "hackrf/devicehackrf.h" #include "hackrf/devicehackrfparam.h" #include "hackrfinputsettings.h" +class QNetworkAccessManager; +class QNetworkReply; class DeviceSourceAPI; class HackRFInputThread; class FileRecord; class HackRFInput : public DeviceSampleSource { + Q_OBJECT public: class MsgConfigureHackRF : public Message { @@ -151,13 +155,6 @@ public: private: - bool openDevice(); - void closeDevice(); - bool applySettings(const HackRFInputSettings& settings, bool force); -// hackrf_device *open_hackrf_from_sequence(int sequence); - void setDeviceCenterFrequency(quint64 freq); - void webapiFormatDeviceSettings(SWGSDRangel::SWGDeviceSettings& response, const HackRFInputSettings& settings); - DeviceSourceAPI *m_deviceAPI; QMutex m_mutex; HackRFInputSettings m_settings; @@ -167,6 +164,19 @@ private: DeviceHackRFParams m_sharedParams; 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 applySettings(const HackRFInputSettings& settings, bool force); + void setDeviceCenterFrequency(quint64 freq); + void webapiFormatDeviceSettings(SWGSDRangel::SWGDeviceSettings& response, const HackRFInputSettings& settings); + void webapiReverseSendSettings(QList& deviceSettingsKeys, const HackRFInputSettings& settings, bool force); + void webapiReverseSendStartStop(bool start); + +private slots: + void networkManagerFinished(QNetworkReply *reply); }; #endif // INCLUDE_HACKRFINPUT_H diff --git a/plugins/samplesource/hackrfinput/hackrfinputgui.cpp b/plugins/samplesource/hackrfinput/hackrfinputgui.cpp index 6de6ca1b0..6ef9b54ed 100644 --- a/plugins/samplesource/hackrfinput/hackrfinputgui.cpp +++ b/plugins/samplesource/hackrfinput/hackrfinputgui.cpp @@ -23,6 +23,8 @@ #include "gui/colormapper.h" #include "gui/glspectrum.h" +#include "gui/crightclickenabler.h" +#include "gui/basicdevicesettingsdialog.h" #include "dsp/dspengine.h" #include "dsp/dspcommands.h" #include "device/devicesourceapi.h" @@ -55,6 +57,9 @@ HackRFInputGui::HackRFInputGui(DeviceUISet *deviceUISet, QWidget* parent) : connect(&m_statusTimer, SIGNAL(timeout()), this, SLOT(updateStatus())); m_statusTimer.start(500); + CRightClickEnabler *startStopRightClickEnabler = new CRightClickEnabler(ui->startStop); + connect(startStopRightClickEnabler, SIGNAL(rightClick(const QPoint &)), this, SLOT(openDeviceSettingsDialog(const QPoint &))); + displaySettings(); displayBandwidths(); @@ -417,3 +422,22 @@ void HackRFInputGui::updateStatus() m_lastEngineState = state; } } + +void HackRFInputGui::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/hackrfinput/hackrfinputgui.h b/plugins/samplesource/hackrfinput/hackrfinputgui.h index 0f714af56..5e28a879d 100644 --- a/plugins/samplesource/hackrfinput/hackrfinputgui.h +++ b/plugins/samplesource/hackrfinput/hackrfinputgui.h @@ -100,6 +100,7 @@ private slots: void on_record_toggled(bool checked); void updateHardware(); void updateStatus(); + void openDeviceSettingsDialog(const QPoint& p); }; #endif // INCLUDE_HACKRFINPUTGUI_H diff --git a/plugins/samplesource/hackrfinput/hackrfinputplugin.cpp b/plugins/samplesource/hackrfinput/hackrfinputplugin.cpp index 3ac127c62..d7da12789 100644 --- a/plugins/samplesource/hackrfinput/hackrfinputplugin.cpp +++ b/plugins/samplesource/hackrfinput/hackrfinputplugin.cpp @@ -32,7 +32,7 @@ const PluginDescriptor HackRFInputPlugin::m_pluginDescriptor = { QString("HackRF Input"), - QString("3.14.6"), + QString("4.3.2"), QString("(c) Edouard Griffiths, F4EXB"), QString("https://github.com/f4exb/sdrangel"), true, diff --git a/plugins/samplesource/hackrfinput/hackrfinputsettings.cpp b/plugins/samplesource/hackrfinput/hackrfinputsettings.cpp index d2831bcc1..0809b776d 100644 --- a/plugins/samplesource/hackrfinput/hackrfinputsettings.cpp +++ b/plugins/samplesource/hackrfinput/hackrfinputsettings.cpp @@ -41,6 +41,10 @@ void HackRFInputSettings::resetToDefaults() m_devSampleRate = 2400000; m_linkTxFrequency = false; m_fileRecordName = ""; + m_useReverseAPI = false; + m_reverseAPIAddress = "127.0.0.1"; + m_reverseAPIPort = 8888; + m_reverseAPIDeviceIndex = 0; } QByteArray HackRFInputSettings::serialize() const @@ -59,6 +63,10 @@ QByteArray HackRFInputSettings::serialize() const s.writeBool(11, m_iqCorrection); s.writeU64(12, m_devSampleRate); s.writeBool(13, m_linkTxFrequency); + s.writeBool(14, m_useReverseAPI); + s.writeString(15, m_reverseAPIAddress); + s.writeU32(16, m_reverseAPIPort); + s.writeU32(17, m_reverseAPIDeviceIndex); return s.final(); } @@ -76,6 +84,7 @@ bool HackRFInputSettings::deserialize(const QByteArray& data) if (d.getVersion() == 1) { int intval; + uint32_t uintval; d.readS32(1, &m_LOppmTenths, 0); d.readBool(3, &m_biasT, false); @@ -89,7 +98,19 @@ bool HackRFInputSettings::deserialize(const QByteArray& data) d.readBool(10, &m_dcBlock, false); d.readBool(11, &m_iqCorrection, false); d.readU64(12, &m_devSampleRate, 2400000U); - d.readBool(11, &m_linkTxFrequency, false); + d.readBool(13, &m_linkTxFrequency, false); + d.readBool(14, &m_useReverseAPI, false); + d.readString(15, &m_reverseAPIAddress, "127.0.0.1"); + d.readU32(16, &uintval, 0); + + if ((uintval > 1023) && (uintval < 65535)) { + m_reverseAPIPort = uintval; + } else { + m_reverseAPIPort = 8888; + } + + d.readU32(17, &uintval, 0); + m_reverseAPIDeviceIndex = uintval > 99 ? 99 : uintval; return true; } diff --git a/plugins/samplesource/hackrfinput/hackrfinputsettings.h b/plugins/samplesource/hackrfinput/hackrfinputsettings.h index b2f0b3056..b1042ce07 100644 --- a/plugins/samplesource/hackrfinput/hackrfinputsettings.h +++ b/plugins/samplesource/hackrfinput/hackrfinputsettings.h @@ -41,6 +41,10 @@ struct HackRFInputSettings { bool m_iqCorrection; bool m_linkTxFrequency; QString m_fileRecordName; + bool m_useReverseAPI; + QString m_reverseAPIAddress; + uint16_t m_reverseAPIPort; + uint16_t m_reverseAPIDeviceIndex; HackRFInputSettings(); void resetToDefaults();