From f62b6d82c2465bc90dab62d7174d7f17401b0d59 Mon Sep 17 00:00:00 2001 From: f4exb Date: Sun, 23 Dec 2018 23:19:05 +0100 Subject: [PATCH] Reverse API: NFM demod --- plugins/channelrx/demodnfm/nfmdemod.cpp | 148 +++++++++++++++++- plugins/channelrx/demodnfm/nfmdemod.h | 14 +- plugins/channelrx/demodnfm/nfmdemodgui.cpp | 10 ++ .../channelrx/demodnfm/nfmdemodsettings.cpp | 25 +++ plugins/channelrx/demodnfm/nfmdemodsettings.h | 5 + 5 files changed, 199 insertions(+), 3 deletions(-) diff --git a/plugins/channelrx/demodnfm/nfmdemod.cpp b/plugins/channelrx/demodnfm/nfmdemod.cpp index 69d75bba4..fd195356c 100644 --- a/plugins/channelrx/demodnfm/nfmdemod.cpp +++ b/plugins/channelrx/demodnfm/nfmdemod.cpp @@ -15,11 +15,15 @@ // along with this program. If not, see . // /////////////////////////////////////////////////////////////////////////////////// -#include -#include #include #include +#include +#include +#include +#include +#include + #include "SWGChannelSettings.h" #include "SWGNFMDemodSettings.h" #include "SWGChannelReport.h" @@ -94,10 +98,15 @@ NFMDemod::NFMDemod(DeviceSourceAPI *devieAPI) : m_threadedChannelizer = new ThreadedBasebandSampleSink(m_channelizer, this); m_deviceAPI->addThreadedSink(m_threadedChannelizer); m_deviceAPI->addChannelAPI(this); + + m_networkManager = new QNetworkAccessManager(); + connect(m_networkManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(networkManagerFinished(QNetworkReply*))); } NFMDemod::~NFMDemod() { + disconnect(m_networkManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(networkManagerFinished(QNetworkReply*))); + delete m_networkManager; DSPEngine::instance()->getAudioDeviceManager()->removeAudioSink(&m_audioFifo); m_deviceAPI->removeChannelAPI(this); m_deviceAPI->removeThreadedSink(m_threadedChannelizer); @@ -491,10 +500,33 @@ void NFMDemod::applySettings(const NFMDemodSettings& settings, bool force) << " m_ctcssOn: " << settings.m_ctcssOn << " m_audioMute: " << settings.m_audioMute << " m_audioDeviceName: " << settings.m_audioDeviceName + << " m_useReverseAPI: " << settings.m_useReverseAPI << " force: " << force; + QList reverseAPIKeys; + + if ((settings.m_inputFrequencyOffset != m_settings.m_inputFrequencyOffset) || force) { + reverseAPIKeys.append("inputFrequencyOffset"); + } + if ((settings.m_volume != m_settings.m_volume) || force) { + reverseAPIKeys.append("volume"); + } + if ((settings.m_ctcssOn != m_settings.m_ctcssOn) || force) { + reverseAPIKeys.append("ctcssOn"); + } + if ((settings.m_audioMute != m_settings.m_audioMute) || force) { + reverseAPIKeys.append("audioMute"); + } + if ((settings.m_rgbColor != m_settings.m_rgbColor) || force) { + reverseAPIKeys.append("rgbColor"); + } + if ((settings.m_title != m_settings.m_title) || force) { + reverseAPIKeys.append("title"); + } + if ((settings.m_rfBandwidth != m_settings.m_rfBandwidth) || force) { + reverseAPIKeys.append("rfBandwidth"); m_settingsMutex.lock(); m_interpolator.create(16, m_inputSampleRate, settings.m_rfBandwidth / 2.2); m_interpolatorDistanceRemain = 0; @@ -504,11 +536,13 @@ void NFMDemod::applySettings(const NFMDemodSettings& settings, bool force) if ((settings.m_fmDeviation != m_settings.m_fmDeviation) || force) { + reverseAPIKeys.append("fmDeviation"); m_phaseDiscri.setFMScaling((8.0f*m_audioSampleRate) / static_cast(settings.m_fmDeviation)); // integrate 4x factor } if ((settings.m_afBandwidth != m_settings.m_afBandwidth) || force) { + reverseAPIKeys.append("afBandwidth"); m_settingsMutex.lock(); m_bandpass.create(301, m_audioSampleRate, 300.0, settings.m_afBandwidth); m_settingsMutex.unlock(); @@ -516,10 +550,18 @@ void NFMDemod::applySettings(const NFMDemodSettings& settings, bool force) if ((settings.m_squelchGate != m_settings.m_squelchGate) || force) { + reverseAPIKeys.append("squelchGate"); m_squelchGate = (m_audioSampleRate / 100) * settings.m_squelchGate; // gate is given in 10s of ms at 48000 Hz audio sample rate m_squelchCount = 0; // reset squelch open counter } + if ((settings.m_squelch != m_settings.m_squelch) || force) { + reverseAPIKeys.append("squelch"); + } + if ((settings.m_deltaSquelch != m_settings.m_deltaSquelch) || force) { + reverseAPIKeys.append("deltaSquelch"); + } + if ((settings.m_squelch != m_settings.m_squelch) || (settings.m_deltaSquelch != m_settings.m_deltaSquelch) || force) { @@ -540,11 +582,13 @@ void NFMDemod::applySettings(const NFMDemodSettings& settings, bool force) if ((settings.m_ctcssIndex != m_settings.m_ctcssIndex) || force) { + reverseAPIKeys.append("ctcssIndex"); setSelectedCtcssIndex(settings.m_ctcssIndex); } if ((settings.m_audioDeviceName != m_settings.m_audioDeviceName) || force) { + reverseAPIKeys.append("audioDeviceName"); AudioDeviceManager *audioDeviceManager = DSPEngine::instance()->getAudioDeviceManager(); int audioDeviceIndex = audioDeviceManager->getOutputDeviceIndex(settings.m_audioDeviceName); //qDebug("AMDemod::applySettings: audioDeviceName: %s audioDeviceIndex: %d", qPrintable(settings.m_audioDeviceName), audioDeviceIndex); @@ -556,6 +600,16 @@ void NFMDemod::applySettings(const NFMDemodSettings& settings, bool force) } } + 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) || + (m_settings.m_reverseAPIChannelIndex != settings.m_reverseAPIChannelIndex); + webapiReverseSendSettings(reverseAPIKeys, settings, fullUpdate || force); + } + m_settings = settings; } @@ -722,3 +776,93 @@ void NFMDemod::webapiFormatChannelReport(SWGSDRangel::SWGChannelReport& response response.getNfmDemodReport()->setAudioSampleRate(m_audioSampleRate); response.getNfmDemodReport()->setChannelSampleRate(m_inputSampleRate); } + +void NFMDemod::webapiReverseSendSettings(QList& channelSettingsKeys, const NFMDemodSettings& settings, bool force) +{ + SWGSDRangel::SWGChannelSettings *swgChannelSettings = new SWGSDRangel::SWGChannelSettings(); + swgChannelSettings->setTx(0); + swgChannelSettings->setChannelType(new QString("NFMDemod")); + swgChannelSettings->setNfmDemodSettings(new SWGSDRangel::SWGNFMDemodSettings()); + SWGSDRangel::SWGNFMDemodSettings *swgNFMDemodSettings = swgChannelSettings->getNfmDemodSettings(); + + // transfer data that has been modified. When force is on transfer all data except reverse API data + + if (channelSettingsKeys.contains("afBandwidth") || force) { + swgNFMDemodSettings->setAfBandwidth(settings.m_afBandwidth); + } + if (channelSettingsKeys.contains("audioMute") || force) { + swgNFMDemodSettings->setAudioMute(settings.m_audioMute ? 1 : 0); + } + if (channelSettingsKeys.contains("ctcssIndex") || force) { + swgNFMDemodSettings->setCtcssIndex(settings.m_ctcssIndex); + } + if (channelSettingsKeys.contains("ctcssOn") || force) { + swgNFMDemodSettings->setCtcssOn(settings.m_ctcssOn ? 1 : 0); + } + if (channelSettingsKeys.contains("deltaSquelch") || force) { + swgNFMDemodSettings->setDeltaSquelch(settings.m_deltaSquelch ? 1 : 0); + } + if (channelSettingsKeys.contains("fmDeviation") || force) { + swgNFMDemodSettings->setFmDeviation(settings.m_fmDeviation); + } + if (channelSettingsKeys.contains("inputFrequencyOffset") || force) { + swgNFMDemodSettings->setInputFrequencyOffset(settings.m_inputFrequencyOffset); + } + if (channelSettingsKeys.contains("rfBandwidth") || force) { + swgNFMDemodSettings->setRfBandwidth(settings.m_rfBandwidth); + } + if (channelSettingsKeys.contains("rgbColor") || force) { + swgNFMDemodSettings->setRgbColor(settings.m_rgbColor); + } + if (channelSettingsKeys.contains("squelch") || force) { + swgNFMDemodSettings->setSquelch(settings.m_squelch); + } + if (channelSettingsKeys.contains("squelchGate") || force) { + swgNFMDemodSettings->setSquelchGate(settings.m_squelchGate); + } + if (channelSettingsKeys.contains("title") || force) { + swgNFMDemodSettings->setTitle(new QString(settings.m_title)); + } + if (channelSettingsKeys.contains("volume") || force) { + swgNFMDemodSettings->setVolume(settings.m_volume); + } + if (channelSettingsKeys.contains("audioDeviceName") || force) { + swgNFMDemodSettings->setAudioDeviceName(new QString(settings.m_audioDeviceName)); + } + + QString channelSettingsURL = QString("http://%1:%2/sdrangel/deviceset/%3/channel/%4/settings") + .arg(settings.m_reverseAPIAddress) + .arg(settings.m_reverseAPIPort) + .arg(settings.m_reverseAPIDeviceIndex) + .arg(settings.m_reverseAPIChannelIndex); + m_networkRequest.setUrl(QUrl(channelSettingsURL)); + m_networkRequest.setHeader(QNetworkRequest::ContentTypeHeader, "application/json"); + + QBuffer *buffer=new QBuffer(); + buffer->open((QBuffer::ReadWrite)); + buffer->write(swgChannelSettings->asJson().toUtf8()); + buffer->seek(0); + + // Always use PATCH to avoid passing reverse API settings + m_networkManager->sendCustomRequest(m_networkRequest, "PATCH", buffer); + + delete swgChannelSettings; +} + +void NFMDemod::networkManagerFinished(QNetworkReply *reply) +{ + QNetworkReply::NetworkError replyError = reply->error(); + + if (replyError) + { + qWarning() << "NFMDemod::networkManagerFinished:" + << " error(" << (int) replyError + << "): " << replyError + << ": " << reply->errorString(); + return; + } + + QString answer = reply->readAll(); + answer.chop(1); // remove last \n + qDebug("NFMDemod::networkManagerFinished: reply:\n%s", answer.toStdString().c_str()); +} diff --git a/plugins/channelrx/demodnfm/nfmdemod.h b/plugins/channelrx/demodnfm/nfmdemod.h index ae1ec8c9b..cd24a8e07 100644 --- a/plugins/channelrx/demodnfm/nfmdemod.h +++ b/plugins/channelrx/demodnfm/nfmdemod.h @@ -18,9 +18,11 @@ #ifndef INCLUDE_NFMDEMOD_H #define INCLUDE_NFMDEMOD_H -#include #include +#include +#include + #include "dsp/basebandsamplesink.h" #include "channel/channelsinkapi.h" #include "dsp/phasediscri.h" @@ -38,11 +40,14 @@ #include "nfmdemodsettings.h" +class QNetworkAccessManager; +class QNetworkReply; class DeviceSourceAPI; class ThreadedBasebandSampleSink; class DownChannelizer; class NFMDemod : public BasebandSampleSink, public ChannelSinkAPI { + Q_OBJECT public: class MsgConfigureNFMDemod : public Message { MESSAGE_CLASS_DECLARATION @@ -235,6 +240,9 @@ private: PhaseDiscriminators m_phaseDiscri; + QNetworkAccessManager *m_networkManager; + QNetworkRequest m_networkRequest; + static const int m_udpBlockSize; // void apply(bool force = false); @@ -243,6 +251,10 @@ private: void applyAudioSampleRate(int sampleRate); void webapiFormatChannelSettings(SWGSDRangel::SWGChannelSettings& response, const NFMDemodSettings& settings); void webapiFormatChannelReport(SWGSDRangel::SWGChannelReport& response); + void webapiReverseSendSettings(QList& channelSettingsKeys, const NFMDemodSettings& settings, bool force); + +private slots: + void networkManagerFinished(QNetworkReply *reply); }; #endif // INCLUDE_NFMDEMOD_H diff --git a/plugins/channelrx/demodnfm/nfmdemodgui.cpp b/plugins/channelrx/demodnfm/nfmdemodgui.cpp index 904e6e64d..2b739cc99 100644 --- a/plugins/channelrx/demodnfm/nfmdemodgui.cpp +++ b/plugins/channelrx/demodnfm/nfmdemodgui.cpp @@ -227,12 +227,22 @@ void NFMDemodGUI::onWidgetRolled(QWidget* widget, bool rollDown) void NFMDemodGUI::onMenuDialogCalled(const QPoint &p) { BasicChannelSettingsDialog dialog(&m_channelMarker, 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.setReverseAPIChannelIndex(m_settings.m_reverseAPIChannelIndex); dialog.move(p); dialog.exec(); m_settings.m_inputFrequencyOffset = m_channelMarker.getCenterFrequency(); m_settings.m_rgbColor = m_channelMarker.getColor().rgb(); m_settings.m_title = m_channelMarker.getTitle(); + m_settings.m_useReverseAPI = dialog.useReverseAPI(); + m_settings.m_reverseAPIAddress = dialog.getReverseAPIAddress(); + m_settings.m_reverseAPIPort = dialog.getReverseAPIPort(); + m_settings.m_reverseAPIDeviceIndex = dialog.getReverseAPIDeviceIndex(); + m_settings.m_reverseAPIChannelIndex = dialog.getReverseAPIChannelIndex(); setWindowTitle(m_settings.m_title); setTitleColor(m_settings.m_rgbColor); diff --git a/plugins/channelrx/demodnfm/nfmdemodsettings.cpp b/plugins/channelrx/demodnfm/nfmdemodsettings.cpp index b23684402..a7f515598 100644 --- a/plugins/channelrx/demodnfm/nfmdemodsettings.cpp +++ b/plugins/channelrx/demodnfm/nfmdemodsettings.cpp @@ -52,6 +52,11 @@ void NFMDemodSettings::resetToDefaults() m_rgbColor = QColor(255, 0, 0).rgb(); m_title = "NFM Demodulator"; m_audioDeviceName = AudioDeviceManager::m_defaultDeviceName; + m_useReverseAPI = false; + m_reverseAPIAddress = "127.0.0.1"; + m_reverseAPIPort = 8888; + m_reverseAPIDeviceIndex = 0; + m_reverseAPIChannelIndex = 0; } QByteArray NFMDemodSettings::serialize() const @@ -75,6 +80,11 @@ QByteArray NFMDemodSettings::serialize() const s.writeString(14, m_title); s.writeString(15, m_audioDeviceName); + s.writeBool(16, m_useReverseAPI); + s.writeString(17, m_reverseAPIAddress); + s.writeU32(18, m_reverseAPIPort); + s.writeU32(19, m_reverseAPIDeviceIndex); + s.writeU32(20, m_reverseAPIChannelIndex); return s.final(); } @@ -93,6 +103,7 @@ bool NFMDemodSettings::deserialize(const QByteArray& data) { QByteArray bytetmp; qint32 tmp; + uint32_t utmp; if (m_channelMarker) { @@ -119,6 +130,20 @@ bool NFMDemodSettings::deserialize(const QByteArray& data) d.readBool(12, &m_deltaSquelch, false); d.readString(14, &m_title, "NFM Demodulator"); d.readString(15, &m_audioDeviceName, AudioDeviceManager::m_defaultDeviceName); + d.readBool(16, &m_useReverseAPI, false); + d.readString(17, &m_reverseAPIAddress, "127.0.0.1"); + d.readU32(18, &utmp, 0); + + if ((utmp > 1023) && (utmp < 65535)) { + m_reverseAPIPort = utmp; + } else { + m_reverseAPIPort = 8888; + } + + d.readU32(19, &utmp, 0); + m_reverseAPIDeviceIndex = utmp > 99 ? 99 : utmp; + d.readU32(20, &utmp, 0); + m_reverseAPIChannelIndex = utmp > 99 ? 99 : utmp; return true; } diff --git a/plugins/channelrx/demodnfm/nfmdemodsettings.h b/plugins/channelrx/demodnfm/nfmdemodsettings.h index 285735674..3f4098a43 100644 --- a/plugins/channelrx/demodnfm/nfmdemodsettings.h +++ b/plugins/channelrx/demodnfm/nfmdemodsettings.h @@ -41,6 +41,11 @@ struct NFMDemodSettings quint32 m_rgbColor; QString m_title; QString m_audioDeviceName; + bool m_useReverseAPI; + QString m_reverseAPIAddress; + uint16_t m_reverseAPIPort; + uint16_t m_reverseAPIDeviceIndex; + uint16_t m_reverseAPIChannelIndex; Serializable *m_channelMarker;