diff --git a/plugins/channelrx/demodwfm/wfmdemod.cpp b/plugins/channelrx/demodwfm/wfmdemod.cpp index b9dbd0547..8db9a5889 100644 --- a/plugins/channelrx/demodwfm/wfmdemod.cpp +++ b/plugins/channelrx/demodwfm/wfmdemod.cpp @@ -16,11 +16,15 @@ /////////////////////////////////////////////////////////////////////////////////// -#include -#include #include #include +#include +#include +#include +#include +#include + #include "SWGChannelSettings.h" #include "SWGWFMDemodSettings.h" #include "SWGChannelReport.h" @@ -74,10 +78,15 @@ WFMDemod::WFMDemod(DeviceSourceAPI* deviceAPI) : 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*))); } WFMDemod::~WFMDemod() { + disconnect(m_networkManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(networkManagerFinished(QNetworkReply*))); + delete m_networkManager; DSPEngine::instance()->getAudioDeviceManager()->removeAudioSink(&m_audioFifo); m_deviceAPI->removeChannelAPI(this); @@ -317,8 +326,39 @@ void WFMDemod::applySettings(const WFMDemodSettings& settings, bool force) << " m_volume: " << settings.m_volume << " m_squelch: " << settings.m_squelch << " m_audioDeviceName: " << settings.m_audioDeviceName + << " m_audioMute: " << settings.m_audioMute << " force: " << force; + QList reverseAPIKeys; + + if((settings.m_inputFrequencyOffset != m_settings.m_inputFrequencyOffset) || force) { + reverseAPIKeys.append("inputFrequencyOffset"); + } + if((settings.m_rfBandwidth != m_settings.m_rfBandwidth) || force) { + reverseAPIKeys.append("rfBandwidth"); + } + if((settings.m_afBandwidth != m_settings.m_afBandwidth) || force) { + reverseAPIKeys.append("afBandwidth"); + } + if((settings.m_volume != m_settings.m_volume) || force) { + reverseAPIKeys.append("volume"); + } + if((settings.m_squelch != m_settings.m_squelch) || force) { + reverseAPIKeys.append("squelch"); + } + if((settings.m_audioMute != m_settings.m_audioMute) || force) { + reverseAPIKeys.append("audioMute"); + } + if((settings.m_audioDeviceName != m_settings.m_audioDeviceName) || force) { + reverseAPIKeys.append("audioDeviceName"); + } + if((settings.m_title != m_settings.m_title) || force) { + reverseAPIKeys.append("title"); + } + if((settings.m_rgbColor != m_settings.m_rgbColor) || force) { + reverseAPIKeys.append("rgbColor"); + } + if((settings.m_afBandwidth != m_settings.m_afBandwidth) || (settings.m_rfBandwidth != m_settings.m_rfBandwidth) || force) { @@ -356,6 +396,16 @@ void WFMDemod::applySettings(const WFMDemodSettings& 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; } @@ -500,3 +550,77 @@ void WFMDemod::webapiFormatChannelReport(SWGSDRangel::SWGChannelReport& response response.getWfmDemodReport()->setChannelSampleRate(m_inputSampleRate); } +void WFMDemod::webapiReverseSendSettings(QList& channelSettingsKeys, const WFMDemodSettings& settings, bool force) +{ + SWGSDRangel::SWGChannelSettings *swgChannelSettings = new SWGSDRangel::SWGChannelSettings(); + swgChannelSettings->setTx(0); + swgChannelSettings->setChannelType(new QString("WFMDemod")); + swgChannelSettings->setWfmDemodSettings(new SWGSDRangel::SWGWFMDemodSettings()); + SWGSDRangel::SWGWFMDemodSettings *swgWFMDemodSettings = swgChannelSettings->getWfmDemodSettings(); + + // transfer data that has been modified. When force is on transfer all data except reverse API data + + if (channelSettingsKeys.contains("inputFrequencyOffset") || force) { + swgWFMDemodSettings->setInputFrequencyOffset(settings.m_inputFrequencyOffset); + } + if (channelSettingsKeys.contains("rfBandwidth") || force) { + swgWFMDemodSettings->setRfBandwidth(settings.m_rfBandwidth); + } + if (channelSettingsKeys.contains("afBandwidth") || force) { + swgWFMDemodSettings->setAfBandwidth(settings.m_afBandwidth); + } + if (channelSettingsKeys.contains("volume") || force) { + swgWFMDemodSettings->setVolume(settings.m_volume); + } + if (channelSettingsKeys.contains("squelch") || force) { + swgWFMDemodSettings->setSquelch(settings.m_squelch); + } + if (channelSettingsKeys.contains("audioMute") || force) { + swgWFMDemodSettings->setAudioMute(settings.m_audioMute ? 1 : 0); + } + if (channelSettingsKeys.contains("rgbColor") || force) { + swgWFMDemodSettings->setRgbColor(settings.m_rgbColor); + } + if (channelSettingsKeys.contains("title") || force) { + swgWFMDemodSettings->setTitle(new QString(settings.m_title)); + } + if (channelSettingsKeys.contains("audioDeviceName") || force) { + swgWFMDemodSettings->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 WFMDemod::networkManagerFinished(QNetworkReply *reply) +{ + QNetworkReply::NetworkError replyError = reply->error(); + + if (replyError) + { + qWarning() << "WFMDemod::networkManagerFinished:" + << " error(" << (int) replyError + << "): " << replyError + << ": " << reply->errorString(); + return; + } + + QString answer = reply->readAll(); + answer.chop(1); // remove last \n + qDebug("WFMDemod::networkManagerFinished: reply:\n%s", answer.toStdString().c_str()); +} diff --git a/plugins/channelrx/demodwfm/wfmdemod.h b/plugins/channelrx/demodwfm/wfmdemod.h index fa707a600..d1edd3674 100644 --- a/plugins/channelrx/demodwfm/wfmdemod.h +++ b/plugins/channelrx/demodwfm/wfmdemod.h @@ -18,9 +18,11 @@ #ifndef INCLUDE_WFMDEMOD_H #define INCLUDE_WFMDEMOD_H -#include #include +#include +#include + #include "dsp/basebandsamplesink.h" #include "channel/channelsinkapi.h" #include "dsp/nco.h" @@ -36,11 +38,14 @@ #define rfFilterFftLength 1024 +class QNetworkAccessManager; +class QNetworkReply; class ThreadedBasebandSampleSink; class DownChannelizer; class DeviceSourceAPI; class WFMDemod : public BasebandSampleSink, public ChannelSinkAPI { + Q_OBJECT public: class MsgConfigureWFMDemod : public Message { MESSAGE_CLASS_DECLARATION @@ -203,6 +208,9 @@ private: PhaseDiscriminators m_phaseDiscri; + QNetworkAccessManager *m_networkManager; + QNetworkRequest m_networkRequest; + static const int m_udpBlockSize; void applyAudioSampleRate(int sampleRate); @@ -211,6 +219,10 @@ private: void webapiFormatChannelSettings(SWGSDRangel::SWGChannelSettings& response, const WFMDemodSettings& settings); void webapiFormatChannelReport(SWGSDRangel::SWGChannelReport& response); + void webapiReverseSendSettings(QList& channelSettingsKeys, const WFMDemodSettings& settings, bool force); + +private slots: + void networkManagerFinished(QNetworkReply *reply); }; #endif // INCLUDE_WFMDEMOD_H diff --git a/plugins/channelrx/demodwfm/wfmdemodgui.cpp b/plugins/channelrx/demodwfm/wfmdemodgui.cpp index 222ee4e00..32437cc51 100644 --- a/plugins/channelrx/demodwfm/wfmdemodgui.cpp +++ b/plugins/channelrx/demodwfm/wfmdemodgui.cpp @@ -169,12 +169,23 @@ void WFMDemodGUI::onWidgetRolled(QWidget* widget, bool rollDown) void WFMDemodGUI::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/demodwfm/wfmdemodsettings.cpp b/plugins/channelrx/demodwfm/wfmdemodsettings.cpp index ed50294d9..0b0625877 100644 --- a/plugins/channelrx/demodwfm/wfmdemodsettings.cpp +++ b/plugins/channelrx/demodwfm/wfmdemodsettings.cpp @@ -45,6 +45,11 @@ void WFMDemodSettings::resetToDefaults() m_rgbColor = QColor(0, 0, 255).rgb(); m_title = "WFM 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 WFMDemodSettings::serialize() const @@ -63,6 +68,11 @@ QByteArray WFMDemodSettings::serialize() const s.writeBlob(11, m_channelMarker->serialize()); } + s.writeBool(12, m_useReverseAPI); + s.writeString(13, m_reverseAPIAddress); + s.writeU32(14, m_reverseAPIPort); + s.writeU32(15, m_reverseAPIDeviceIndex); + s.writeU32(16, m_reverseAPIChannelIndex); return s.final(); } @@ -81,6 +91,7 @@ bool WFMDemodSettings::deserialize(const QByteArray& data) { QByteArray bytetmp; qint32 tmp; + uint32_t utmp; QString strtmp; d.readS32(1, &tmp, 0); @@ -103,6 +114,21 @@ bool WFMDemodSettings::deserialize(const QByteArray& data) m_channelMarker->deserialize(bytetmp); } + d.readBool(12, &m_useReverseAPI, false); + d.readString(13, &m_reverseAPIAddress, "127.0.0.1"); + d.readU32(14, &utmp, 0); + + if ((utmp > 1023) && (utmp < 65535)) { + m_reverseAPIPort = utmp; + } else { + m_reverseAPIPort = 8888; + } + + d.readU32(15, &utmp, 0); + m_reverseAPIDeviceIndex = utmp > 99 ? 99 : utmp; + d.readU32(16, &utmp, 0); + m_reverseAPIChannelIndex = utmp > 99 ? 99 : utmp; + return true; } else diff --git a/plugins/channelrx/demodwfm/wfmdemodsettings.h b/plugins/channelrx/demodwfm/wfmdemodsettings.h index 96e62c944..1afa1ee67 100644 --- a/plugins/channelrx/demodwfm/wfmdemodsettings.h +++ b/plugins/channelrx/demodwfm/wfmdemodsettings.h @@ -33,6 +33,11 @@ struct WFMDemodSettings 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;