diff --git a/doc/img/AFC_plugin.png b/doc/img/AFC_plugin.png new file mode 100644 index 000000000..3180605df Binary files /dev/null and b/doc/img/AFC_plugin.png differ diff --git a/doc/img/AFC_plugin.xcf b/doc/img/AFC_plugin.xcf new file mode 100644 index 000000000..92c019b8d Binary files /dev/null and b/doc/img/AFC_plugin.xcf differ diff --git a/doc/img/FreqTracker_plugin.png b/doc/img/FreqTracker_plugin.png index a3304a78a..cabc97428 100644 Binary files a/doc/img/FreqTracker_plugin.png and b/doc/img/FreqTracker_plugin.png differ diff --git a/doc/img/FreqTracker_plugin.xcf b/doc/img/FreqTracker_plugin.xcf index b84be5bfe..0c1217585 100644 Binary files a/doc/img/FreqTracker_plugin.xcf and b/doc/img/FreqTracker_plugin.xcf differ diff --git a/plugins/channelrx/demodam/amdemod.cpp b/plugins/channelrx/demodam/amdemod.cpp index 3599d0843..b52e0fbf6 100644 --- a/plugins/channelrx/demodam/amdemod.cpp +++ b/plugins/channelrx/demodam/amdemod.cpp @@ -35,7 +35,9 @@ #include "dsp/dspengine.h" #include "dsp/dspcommands.h" #include "device/deviceapi.h" +#include "feature/feature.h" #include "util/db.h" +#include "maincore.h" MESSAGE_CLASS_DEFINITION(AMDemod::MsgConfigureAMDemod, Message) @@ -224,6 +226,10 @@ void AMDemod::applySettings(const AMDemodSettings& settings, bool force) webapiReverseSendSettings(reverseAPIKeys, settings, fullUpdate || force); } + if (m_featuresSettingsFeedback.size() > 0) { + featuresSendSettings(reverseAPIKeys, settings, force); + } + m_settings = settings; } @@ -413,6 +419,63 @@ void AMDemod::webapiFormatChannelReport(SWGSDRangel::SWGChannelReport& response) void AMDemod::webapiReverseSendSettings(QList& channelSettingsKeys, const AMDemodSettings& settings, bool force) { SWGSDRangel::SWGChannelSettings *swgChannelSettings = new SWGSDRangel::SWGChannelSettings(); + webapiFormatChannelSettings(channelSettingsKeys, swgChannelSettings, settings, force); + + 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 + QNetworkReply *reply = m_networkManager->sendCustomRequest(m_networkRequest, "PATCH", buffer); + buffer->setParent(reply); + + delete swgChannelSettings; +} + +void AMDemod::featuresSendSettings(QList& channelSettingsKeys, const AMDemodSettings& settings, bool force) +{ + QList::iterator it = m_featuresSettingsFeedback.begin(); + MainCore *mainCore = MainCore::instance(); + + for (; it != m_featuresSettingsFeedback.end(); ++it) + { + if (mainCore->existsFeature(*it)) + { + SWGSDRangel::SWGChannelSettings *swgChannelSettings = new SWGSDRangel::SWGChannelSettings(); + webapiFormatChannelSettings(channelSettingsKeys, swgChannelSettings, settings, force); + + Feature::MsgChannelSettings *msg = Feature::MsgChannelSettings::create( + this, + channelSettingsKeys, + swgChannelSettings, + force + ); + + (*it)->getInputMessageQueue()->push(msg); + } + else + { + m_featuresSettingsFeedback.removeOne(*it); + } + } +} + +void AMDemod::webapiFormatChannelSettings( + QList& channelSettingsKeys, + SWGSDRangel::SWGChannelSettings *swgChannelSettings, + const AMDemodSettings& settings, + bool force +) +{ swgChannelSettings->setDirection(0); // Single sink (Rx) swgChannelSettings->setOriginatorChannelIndex(getIndexInDeviceSet()); swgChannelSettings->setOriginatorDeviceSetIndex(getDeviceSetIndex()); @@ -458,25 +521,6 @@ void AMDemod::webapiReverseSendSettings(QList& channelSettingsKeys, con if (channelSettingsKeys.contains("streamIndex") || force) { swgAMDemodSettings->setStreamIndex(settings.m_streamIndex); } - - 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 - QNetworkReply *reply = m_networkManager->sendCustomRequest(m_networkRequest, "PATCH", buffer); - buffer->setParent(reply); - - delete swgChannelSettings; } void AMDemod::networkManagerFinished(QNetworkReply *reply) diff --git a/plugins/channelrx/demodam/amdemod.h b/plugins/channelrx/demodam/amdemod.h index 00ccf7e1c..280f24aa0 100644 --- a/plugins/channelrx/demodam/amdemod.h +++ b/plugins/channelrx/demodam/amdemod.h @@ -142,6 +142,13 @@ private: void applySettings(const AMDemodSettings& settings, bool force = false); void webapiFormatChannelReport(SWGSDRangel::SWGChannelReport& response); void webapiReverseSendSettings(QList& channelSettingsKeys, const AMDemodSettings& settings, bool force); + void featuresSendSettings(QList& channelSettingsKeys, const AMDemodSettings& settings, bool force); + void webapiFormatChannelSettings( + QList& channelSettingsKeys, + SWGSDRangel::SWGChannelSettings *swgChannelSettings, + const AMDemodSettings& settings, + bool force + ); private slots: void networkManagerFinished(QNetworkReply *reply); diff --git a/plugins/channelrx/demodbfm/bfmdemod.cpp b/plugins/channelrx/demodbfm/bfmdemod.cpp index cd2a5050f..284695cf3 100644 --- a/plugins/channelrx/demodbfm/bfmdemod.cpp +++ b/plugins/channelrx/demodbfm/bfmdemod.cpp @@ -35,7 +35,9 @@ #include "dsp/dspcommands.h" #include "dsp/devicesamplemimo.h" #include "device/deviceapi.h" +#include "feature/feature.h" #include "util/db.h" +#include "maincore.h" #include "bfmdemod.h" @@ -212,6 +214,10 @@ void BFMDemod::applySettings(const BFMDemodSettings& settings, bool force) webapiReverseSendSettings(reverseAPIKeys, settings, fullUpdate || force); } + if (m_featuresSettingsFeedback.size() > 0) { + featuresSendSettings(reverseAPIKeys, settings, force); + } + m_settings = settings; } @@ -439,10 +445,67 @@ void BFMDemod::webapiFormatRDSReport(SWGSDRangel::SWGRDSReport *report) void BFMDemod::webapiReverseSendSettings(QList& channelSettingsKeys, const BFMDemodSettings& settings, bool force) { SWGSDRangel::SWGChannelSettings *swgChannelSettings = new SWGSDRangel::SWGChannelSettings(); - swgChannelSettings->setDirection(0); // single sink (Rx) + webapiFormatChannelSettings(channelSettingsKeys, swgChannelSettings, settings, force); + + 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 + QNetworkReply *reply = m_networkManager->sendCustomRequest(m_networkRequest, "PATCH", buffer); + buffer->setParent(reply); + + delete swgChannelSettings; +} + +void BFMDemod::featuresSendSettings(QList& channelSettingsKeys, const BFMDemodSettings& settings, bool force) +{ + QList::iterator it = m_featuresSettingsFeedback.begin(); + MainCore *mainCore = MainCore::instance(); + + for (; it != m_featuresSettingsFeedback.end(); ++it) + { + if (mainCore->existsFeature(*it)) + { + SWGSDRangel::SWGChannelSettings *swgChannelSettings = new SWGSDRangel::SWGChannelSettings(); + webapiFormatChannelSettings(channelSettingsKeys, swgChannelSettings, settings, force); + + Feature::MsgChannelSettings *msg = Feature::MsgChannelSettings::create( + this, + channelSettingsKeys, + swgChannelSettings, + force + ); + + (*it)->getInputMessageQueue()->push(msg); + } + else + { + m_featuresSettingsFeedback.removeOne(*it); + } + } +} + +void BFMDemod::webapiFormatChannelSettings( + QList& channelSettingsKeys, + SWGSDRangel::SWGChannelSettings *swgChannelSettings, + const BFMDemodSettings& settings, + bool force +) +{ + swgChannelSettings->setDirection(0); // Single sink (Rx) swgChannelSettings->setOriginatorChannelIndex(getIndexInDeviceSet()); swgChannelSettings->setOriginatorDeviceSetIndex(getDeviceSetIndex()); - swgChannelSettings->setChannelType(new QString("BFMDemod")); + swgChannelSettings->setChannelType(new QString(m_channelId)); swgChannelSettings->setBfmDemodSettings(new SWGSDRangel::SWGBFMDemodSettings()); SWGSDRangel::SWGBFMDemodSettings *swgBFMDemodSettings = swgChannelSettings->getBfmDemodSettings(); @@ -487,25 +550,6 @@ void BFMDemod::webapiReverseSendSettings(QList& channelSettingsKeys, co if (channelSettingsKeys.contains("streamIndex") || force) { swgBFMDemodSettings->setStreamIndex(settings.m_streamIndex); } - - 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 - QNetworkReply *reply = m_networkManager->sendCustomRequest(m_networkRequest, "PATCH", buffer); - buffer->setParent(reply); - - delete swgChannelSettings; } void BFMDemod::networkManagerFinished(QNetworkReply *reply) diff --git a/plugins/channelrx/demodbfm/bfmdemod.h b/plugins/channelrx/demodbfm/bfmdemod.h index 7764226da..f0428a022 100644 --- a/plugins/channelrx/demodbfm/bfmdemod.h +++ b/plugins/channelrx/demodbfm/bfmdemod.h @@ -158,6 +158,13 @@ private: void webapiFormatChannelReport(SWGSDRangel::SWGChannelReport& response); void webapiFormatRDSReport(SWGSDRangel::SWGRDSReport *report); void webapiReverseSendSettings(QList& channelSettingsKeys, const BFMDemodSettings& settings, bool force); + void featuresSendSettings(QList& channelSettingsKeys, const BFMDemodSettings& settings, bool force); + void webapiFormatChannelSettings( + QList& channelSettingsKeys, + SWGSDRangel::SWGChannelSettings *swgChannelSettings, + const BFMDemodSettings& settings, + bool force + ); private slots: void networkManagerFinished(QNetworkReply *reply); diff --git a/plugins/channelrx/demoddsd/dsddemod.cpp b/plugins/channelrx/demoddsd/dsddemod.cpp index 60196861a..be9eaea32 100644 --- a/plugins/channelrx/demoddsd/dsddemod.cpp +++ b/plugins/channelrx/demoddsd/dsddemod.cpp @@ -37,7 +37,9 @@ #include "dsp/dspengine.h" #include "dsp/dspcommands.h" #include "device/deviceapi.h" +#include "feature/feature.h" #include "util/db.h" +#include "maincore.h" #include "dsddemod.h" @@ -250,6 +252,10 @@ void DSDDemod::applySettings(const DSDDemodSettings& settings, bool force) webapiReverseSendSettings(reverseAPIKeys, settings, fullUpdate || force); } + if (m_featuresSettingsFeedback.size() > 0) { + featuresSendSettings(reverseAPIKeys, settings, force); + } + m_settings = settings; } @@ -487,10 +493,67 @@ void DSDDemod::webapiFormatChannelReport(SWGSDRangel::SWGChannelReport& response void DSDDemod::webapiReverseSendSettings(QList& channelSettingsKeys, const DSDDemodSettings& settings, bool force) { SWGSDRangel::SWGChannelSettings *swgChannelSettings = new SWGSDRangel::SWGChannelSettings(); - swgChannelSettings->setDirection(0); // single sink (Rx) + webapiFormatChannelSettings(channelSettingsKeys, swgChannelSettings, settings, force); + + 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 + QNetworkReply *reply = m_networkManager->sendCustomRequest(m_networkRequest, "PATCH", buffer); + buffer->setParent(reply); + + delete swgChannelSettings; +} + +void DSDDemod::featuresSendSettings(QList& channelSettingsKeys, const DSDDemodSettings& settings, bool force) +{ + QList::iterator it = m_featuresSettingsFeedback.begin(); + MainCore *mainCore = MainCore::instance(); + + for (; it != m_featuresSettingsFeedback.end(); ++it) + { + if (mainCore->existsFeature(*it)) + { + SWGSDRangel::SWGChannelSettings *swgChannelSettings = new SWGSDRangel::SWGChannelSettings(); + webapiFormatChannelSettings(channelSettingsKeys, swgChannelSettings, settings, force); + + Feature::MsgChannelSettings *msg = Feature::MsgChannelSettings::create( + this, + channelSettingsKeys, + swgChannelSettings, + force + ); + + (*it)->getInputMessageQueue()->push(msg); + } + else + { + m_featuresSettingsFeedback.removeOne(*it); + } + } +} + +void DSDDemod::webapiFormatChannelSettings( + QList& channelSettingsKeys, + SWGSDRangel::SWGChannelSettings *swgChannelSettings, + const DSDDemodSettings& settings, + bool force +) +{ + swgChannelSettings->setDirection(0); // Single sink (Rx) swgChannelSettings->setOriginatorChannelIndex(getIndexInDeviceSet()); swgChannelSettings->setOriginatorDeviceSetIndex(getDeviceSetIndex()); - swgChannelSettings->setChannelType(new QString("DSDDemod")); + swgChannelSettings->setChannelType(new QString(m_channelId)); swgChannelSettings->setDsdDemodSettings(new SWGSDRangel::SWGDSDDemodSettings()); SWGSDRangel::SWGDSDDemodSettings *swgDSDDemodSettings = swgChannelSettings->getDsdDemodSettings(); @@ -565,25 +628,6 @@ void DSDDemod::webapiReverseSendSettings(QList& channelSettingsKeys, co if (channelSettingsKeys.contains("streamIndex") || force) { swgDSDDemodSettings->setStreamIndex(settings.m_streamIndex); } - - 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 - QNetworkReply *reply = m_networkManager->sendCustomRequest(m_networkRequest, "PATCH", buffer); - buffer->setParent(reply); - - delete swgChannelSettings; } void DSDDemod::networkManagerFinished(QNetworkReply *reply) diff --git a/plugins/channelrx/demoddsd/dsddemod.h b/plugins/channelrx/demoddsd/dsddemod.h index 0d554bfcd..2a99ffa7c 100644 --- a/plugins/channelrx/demoddsd/dsddemod.h +++ b/plugins/channelrx/demoddsd/dsddemod.h @@ -140,6 +140,13 @@ private: void applySettings(const DSDDemodSettings& settings, bool force = false); void webapiFormatChannelReport(SWGSDRangel::SWGChannelReport& response); void webapiReverseSendSettings(QList& channelSettingsKeys, const DSDDemodSettings& settings, bool force); + void featuresSendSettings(QList& channelSettingsKeys, const DSDDemodSettings& settings, bool force); + void webapiFormatChannelSettings( + QList& channelSettingsKeys, + SWGSDRangel::SWGChannelSettings *swgChannelSettings, + const DSDDemodSettings& settings, + bool force + ); private slots: void networkManagerFinished(QNetworkReply *reply); diff --git a/plugins/channelrx/demodfreedv/freedvdemod.cpp b/plugins/channelrx/demodfreedv/freedvdemod.cpp index 0e08e5f38..68d5e3fea 100644 --- a/plugins/channelrx/demodfreedv/freedvdemod.cpp +++ b/plugins/channelrx/demodfreedv/freedvdemod.cpp @@ -30,7 +30,9 @@ #include "dsp/dspcommands.h" #include "dsp/devicesamplemimo.h" #include "device/deviceapi.h" +#include "feature/feature.h" #include "util/db.h" +#include "maincore.h" #include "freedvdemod.h" @@ -206,6 +208,10 @@ void FreeDVDemod::applySettings(const FreeDVDemodSettings& settings, bool force) webapiReverseSendSettings(reverseAPIKeys, settings, fullUpdate || force); } + if (m_featuresSettingsFeedback.size() > 0) { + featuresSendSettings(reverseAPIKeys, settings, force); + } + m_settings = settings; } @@ -386,10 +392,67 @@ void FreeDVDemod::webapiFormatChannelReport(SWGSDRangel::SWGChannelReport& respo void FreeDVDemod::webapiReverseSendSettings(QList& channelSettingsKeys, const FreeDVDemodSettings& settings, bool force) { SWGSDRangel::SWGChannelSettings *swgChannelSettings = new SWGSDRangel::SWGChannelSettings(); - swgChannelSettings->setDirection(0); // single sink (Rx) + webapiFormatChannelSettings(channelSettingsKeys, swgChannelSettings, settings, force); + + 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 + QNetworkReply *reply = m_networkManager->sendCustomRequest(m_networkRequest, "PATCH", buffer); + buffer->setParent(reply); + + delete swgChannelSettings; +} + +void FreeDVDemod::featuresSendSettings(QList& channelSettingsKeys, const FreeDVDemodSettings& settings, bool force) +{ + QList::iterator it = m_featuresSettingsFeedback.begin(); + MainCore *mainCore = MainCore::instance(); + + for (; it != m_featuresSettingsFeedback.end(); ++it) + { + if (mainCore->existsFeature(*it)) + { + SWGSDRangel::SWGChannelSettings *swgChannelSettings = new SWGSDRangel::SWGChannelSettings(); + webapiFormatChannelSettings(channelSettingsKeys, swgChannelSettings, settings, force); + + Feature::MsgChannelSettings *msg = Feature::MsgChannelSettings::create( + this, + channelSettingsKeys, + swgChannelSettings, + force + ); + + (*it)->getInputMessageQueue()->push(msg); + } + else + { + m_featuresSettingsFeedback.removeOne(*it); + } + } +} + +void FreeDVDemod::webapiFormatChannelSettings( + QList& channelSettingsKeys, + SWGSDRangel::SWGChannelSettings *swgChannelSettings, + const FreeDVDemodSettings& settings, + bool force +) +{ + swgChannelSettings->setDirection(0); // Single sink (Rx) swgChannelSettings->setOriginatorChannelIndex(getIndexInDeviceSet()); swgChannelSettings->setOriginatorDeviceSetIndex(getDeviceSetIndex()); - swgChannelSettings->setChannelType(new QString("FreeDVDemod")); + swgChannelSettings->setChannelType(new QString(m_channelId)); swgChannelSettings->setFreeDvDemodSettings(new SWGSDRangel::SWGFreeDVDemodSettings()); SWGSDRangel::SWGFreeDVDemodSettings *swgFreeDVDemodSettings = swgChannelSettings->getFreeDvDemodSettings(); @@ -428,25 +491,6 @@ void FreeDVDemod::webapiReverseSendSettings(QList& channelSettingsKeys, if (channelSettingsKeys.contains("streamIndex") || force) { swgFreeDVDemodSettings->setStreamIndex(settings.m_streamIndex); } - - 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 - QNetworkReply *reply = m_networkManager->sendCustomRequest(m_networkRequest, "PATCH", buffer); - buffer->setParent(reply); - - delete swgChannelSettings; } void FreeDVDemod::networkManagerFinished(QNetworkReply *reply) @@ -473,4 +517,4 @@ void FreeDVDemod::networkManagerFinished(QNetworkReply *reply) void FreeDVDemod::setLevelMeter(QObject *levelMeter) { connect(m_basebandSink, SIGNAL(levelChanged(qreal, qreal, int)), levelMeter, SLOT(levelChanged(qreal, qreal, int))); -} \ No newline at end of file +} diff --git a/plugins/channelrx/demodfreedv/freedvdemod.h b/plugins/channelrx/demodfreedv/freedvdemod.h index 532da4b2a..15bcd8eba 100644 --- a/plugins/channelrx/demodfreedv/freedvdemod.h +++ b/plugins/channelrx/demodfreedv/freedvdemod.h @@ -156,6 +156,13 @@ private: void applySettings(const FreeDVDemodSettings& settings, bool force = false); void webapiFormatChannelReport(SWGSDRangel::SWGChannelReport& response); void webapiReverseSendSettings(QList& channelSettingsKeys, const FreeDVDemodSettings& settings, bool force); + void featuresSendSettings(QList& channelSettingsKeys, const FreeDVDemodSettings& settings, bool force); + void webapiFormatChannelSettings( + QList& channelSettingsKeys, + SWGSDRangel::SWGChannelSettings *swgChannelSettings, + const FreeDVDemodSettings& settings, + bool force + ); private slots: void networkManagerFinished(QNetworkReply *reply); diff --git a/plugins/channelrx/demodnfm/nfmdemod.cpp b/plugins/channelrx/demodnfm/nfmdemod.cpp index a5a5760fb..0b746ad83 100644 --- a/plugins/channelrx/demodnfm/nfmdemod.cpp +++ b/plugins/channelrx/demodnfm/nfmdemod.cpp @@ -35,7 +35,9 @@ #include "dsp/dspcommands.h" #include "dsp/devicesamplemimo.h" #include "device/deviceapi.h" +#include "feature/feature.h" #include "util/db.h" +#include "maincore.h" #include "nfmdemod.h" @@ -441,10 +443,67 @@ void NFMDemod::webapiFormatChannelReport(SWGSDRangel::SWGChannelReport& response void NFMDemod::webapiReverseSendSettings(QList& channelSettingsKeys, const NFMDemodSettings& settings, bool force) { SWGSDRangel::SWGChannelSettings *swgChannelSettings = new SWGSDRangel::SWGChannelSettings(); - swgChannelSettings->setDirection(0); // single sink (Rx) + webapiFormatChannelSettings(channelSettingsKeys, swgChannelSettings, settings, force); + + 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 + QNetworkReply *reply = m_networkManager->sendCustomRequest(m_networkRequest, "PATCH", buffer); + buffer->setParent(reply); + + delete swgChannelSettings; +} + +void NFMDemod::featuresSendSettings(QList& channelSettingsKeys, const NFMDemodSettings& settings, bool force) +{ + QList::iterator it = m_featuresSettingsFeedback.begin(); + MainCore *mainCore = MainCore::instance(); + + for (; it != m_featuresSettingsFeedback.end(); ++it) + { + if (mainCore->existsFeature(*it)) + { + SWGSDRangel::SWGChannelSettings *swgChannelSettings = new SWGSDRangel::SWGChannelSettings(); + webapiFormatChannelSettings(channelSettingsKeys, swgChannelSettings, settings, force); + + Feature::MsgChannelSettings *msg = Feature::MsgChannelSettings::create( + this, + channelSettingsKeys, + swgChannelSettings, + force + ); + + (*it)->getInputMessageQueue()->push(msg); + } + else + { + m_featuresSettingsFeedback.removeOne(*it); + } + } +} + +void NFMDemod::webapiFormatChannelSettings( + QList& channelSettingsKeys, + SWGSDRangel::SWGChannelSettings *swgChannelSettings, + const NFMDemodSettings& settings, + bool force +) +{ + swgChannelSettings->setDirection(0); // Single sink (Rx) swgChannelSettings->setOriginatorChannelIndex(getIndexInDeviceSet()); swgChannelSettings->setOriginatorDeviceSetIndex(getDeviceSetIndex()); - swgChannelSettings->setChannelType(new QString("NFMDemod")); + swgChannelSettings->setChannelType(new QString(m_channelId)); swgChannelSettings->setNfmDemodSettings(new SWGSDRangel::SWGNFMDemodSettings()); SWGSDRangel::SWGNFMDemodSettings *swgNFMDemodSettings = swgChannelSettings->getNfmDemodSettings(); @@ -498,25 +557,6 @@ void NFMDemod::webapiReverseSendSettings(QList& channelSettingsKeys, co if (channelSettingsKeys.contains("streamIndex") || force) { swgNFMDemodSettings->setStreamIndex(settings.m_streamIndex); } - - 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 - QNetworkReply *reply = m_networkManager->sendCustomRequest(m_networkRequest, "PATCH", buffer); - buffer->setParent(reply); - - delete swgChannelSettings; } void NFMDemod::networkManagerFinished(QNetworkReply *reply) diff --git a/plugins/channelrx/demodnfm/nfmdemod.h b/plugins/channelrx/demodnfm/nfmdemod.h index b17250c6f..b3386eb61 100644 --- a/plugins/channelrx/demodnfm/nfmdemod.h +++ b/plugins/channelrx/demodnfm/nfmdemod.h @@ -138,6 +138,13 @@ private: void applySettings(const NFMDemodSettings& settings, bool force = false); void webapiFormatChannelReport(SWGSDRangel::SWGChannelReport& response); void webapiReverseSendSettings(QList& channelSettingsKeys, const NFMDemodSettings& settings, bool force); + void featuresSendSettings(QList& channelSettingsKeys, const NFMDemodSettings& settings, bool force); + void webapiFormatChannelSettings( + QList& channelSettingsKeys, + SWGSDRangel::SWGChannelSettings *swgChannelSettings, + const NFMDemodSettings& settings, + bool force + ); private slots: void networkManagerFinished(QNetworkReply *reply); diff --git a/plugins/channelrx/demodssb/ssbdemod.cpp b/plugins/channelrx/demodssb/ssbdemod.cpp index 5b370c8e5..49930de1a 100644 --- a/plugins/channelrx/demodssb/ssbdemod.cpp +++ b/plugins/channelrx/demodssb/ssbdemod.cpp @@ -36,7 +36,9 @@ #include "dsp/dspcommands.h" #include "dsp/devicesamplemimo.h" #include "device/deviceapi.h" +#include "feature/feature.h" #include "util/db.h" +#include "maincore.h" #include "ssbdemod.h" @@ -235,6 +237,10 @@ void SSBDemod::applySettings(const SSBDemodSettings& settings, bool force) webapiReverseSendSettings(reverseAPIKeys, settings, fullUpdate || force); } + if (m_featuresSettingsFeedback.size() > 0) { + featuresSendSettings(reverseAPIKeys, settings, force); + } + m_settings = settings; } @@ -443,10 +449,67 @@ void SSBDemod::webapiFormatChannelReport(SWGSDRangel::SWGChannelReport& response void SSBDemod::webapiReverseSendSettings(QList& channelSettingsKeys, const SSBDemodSettings& settings, bool force) { SWGSDRangel::SWGChannelSettings *swgChannelSettings = new SWGSDRangel::SWGChannelSettings(); - swgChannelSettings->setDirection(0); // single sink (Rx) + webapiFormatChannelSettings(channelSettingsKeys, swgChannelSettings, settings, force); + + 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 + QNetworkReply *reply = m_networkManager->sendCustomRequest(m_networkRequest, "PATCH", buffer); + buffer->setParent(reply); + + delete swgChannelSettings; +} + +void SSBDemod::featuresSendSettings(QList& channelSettingsKeys, const SSBDemodSettings& settings, bool force) +{ + QList::iterator it = m_featuresSettingsFeedback.begin(); + MainCore *mainCore = MainCore::instance(); + + for (; it != m_featuresSettingsFeedback.end(); ++it) + { + if (mainCore->existsFeature(*it)) + { + SWGSDRangel::SWGChannelSettings *swgChannelSettings = new SWGSDRangel::SWGChannelSettings(); + webapiFormatChannelSettings(channelSettingsKeys, swgChannelSettings, settings, force); + + Feature::MsgChannelSettings *msg = Feature::MsgChannelSettings::create( + this, + channelSettingsKeys, + swgChannelSettings, + force + ); + + (*it)->getInputMessageQueue()->push(msg); + } + else + { + m_featuresSettingsFeedback.removeOne(*it); + } + } +} + +void SSBDemod::webapiFormatChannelSettings( + QList& channelSettingsKeys, + SWGSDRangel::SWGChannelSettings *swgChannelSettings, + const SSBDemodSettings& settings, + bool force +) +{ + swgChannelSettings->setDirection(0); // Single sink (Rx) swgChannelSettings->setOriginatorChannelIndex(getIndexInDeviceSet()); swgChannelSettings->setOriginatorDeviceSetIndex(getDeviceSetIndex()); - swgChannelSettings->setChannelType(new QString("SSBDemod")); + swgChannelSettings->setChannelType(new QString(m_channelId)); swgChannelSettings->setSsbDemodSettings(new SWGSDRangel::SWGSSBDemodSettings()); SWGSDRangel::SWGSSBDemodSettings *swgSSBDemodSettings = swgChannelSettings->getSsbDemodSettings(); @@ -506,25 +569,6 @@ void SSBDemod::webapiReverseSendSettings(QList& channelSettingsKeys, co if (channelSettingsKeys.contains("streamIndex") || force) { swgSSBDemodSettings->setStreamIndex(settings.m_streamIndex); } - - 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 - QNetworkReply *reply = m_networkManager->sendCustomRequest(m_networkRequest, "PATCH", buffer); - buffer->setParent(reply); - - delete swgChannelSettings; } void SSBDemod::networkManagerFinished(QNetworkReply *reply) diff --git a/plugins/channelrx/demodssb/ssbdemod.h b/plugins/channelrx/demodssb/ssbdemod.h index 05df4728b..51c21647a 100644 --- a/plugins/channelrx/demodssb/ssbdemod.h +++ b/plugins/channelrx/demodssb/ssbdemod.h @@ -141,6 +141,13 @@ private: void applySettings(const SSBDemodSettings& settings, bool force = false); void webapiFormatChannelReport(SWGSDRangel::SWGChannelReport& response); void webapiReverseSendSettings(QList& channelSettingsKeys, const SSBDemodSettings& settings, bool force); + void featuresSendSettings(QList& channelSettingsKeys, const SSBDemodSettings& settings, bool force); + void webapiFormatChannelSettings( + QList& channelSettingsKeys, + SWGSDRangel::SWGChannelSettings *swgChannelSettings, + const SSBDemodSettings& settings, + bool force + ); private slots: void networkManagerFinished(QNetworkReply *reply); diff --git a/plugins/channelrx/demodwfm/wfmdemod.cpp b/plugins/channelrx/demodwfm/wfmdemod.cpp index 5aaed7a18..371594600 100644 --- a/plugins/channelrx/demodwfm/wfmdemod.cpp +++ b/plugins/channelrx/demodwfm/wfmdemod.cpp @@ -38,7 +38,9 @@ #include "dsp/dspcommands.h" #include "dsp/devicesamplemimo.h" #include "device/deviceapi.h" +#include "feature/feature.h" #include "util/db.h" +#include "maincore.h" #include "wfmdemod.h" @@ -211,6 +213,10 @@ void WFMDemod::applySettings(const WFMDemodSettings& settings, bool force) webapiReverseSendSettings(reverseAPIKeys, settings, fullUpdate || force); } + if (m_featuresSettingsFeedback.size() > 0) { + featuresSendSettings(reverseAPIKeys, settings, force); + } + m_settings = settings; } @@ -386,10 +392,67 @@ void WFMDemod::webapiFormatChannelReport(SWGSDRangel::SWGChannelReport& response void WFMDemod::webapiReverseSendSettings(QList& channelSettingsKeys, const WFMDemodSettings& settings, bool force) { SWGSDRangel::SWGChannelSettings *swgChannelSettings = new SWGSDRangel::SWGChannelSettings(); - swgChannelSettings->setDirection(0); // single sink (Rx) + webapiFormatChannelSettings(channelSettingsKeys, swgChannelSettings, settings, force); + + 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 + QNetworkReply *reply = m_networkManager->sendCustomRequest(m_networkRequest, "PATCH", buffer); + buffer->setParent(reply); + + delete swgChannelSettings; +} + +void WFMDemod::featuresSendSettings(QList& channelSettingsKeys, const WFMDemodSettings& settings, bool force) +{ + QList::iterator it = m_featuresSettingsFeedback.begin(); + MainCore *mainCore = MainCore::instance(); + + for (; it != m_featuresSettingsFeedback.end(); ++it) + { + if (mainCore->existsFeature(*it)) + { + SWGSDRangel::SWGChannelSettings *swgChannelSettings = new SWGSDRangel::SWGChannelSettings(); + webapiFormatChannelSettings(channelSettingsKeys, swgChannelSettings, settings, force); + + Feature::MsgChannelSettings *msg = Feature::MsgChannelSettings::create( + this, + channelSettingsKeys, + swgChannelSettings, + force + ); + + (*it)->getInputMessageQueue()->push(msg); + } + else + { + m_featuresSettingsFeedback.removeOne(*it); + } + } +} + +void WFMDemod::webapiFormatChannelSettings( + QList& channelSettingsKeys, + SWGSDRangel::SWGChannelSettings *swgChannelSettings, + const WFMDemodSettings& settings, + bool force +) +{ + swgChannelSettings->setDirection(0); // Single sink (Rx) swgChannelSettings->setOriginatorChannelIndex(getIndexInDeviceSet()); swgChannelSettings->setOriginatorDeviceSetIndex(getDeviceSetIndex()); - swgChannelSettings->setChannelType(new QString("WFMDemod")); + swgChannelSettings->setChannelType(new QString(m_channelId)); swgChannelSettings->setWfmDemodSettings(new SWGSDRangel::SWGWFMDemodSettings()); SWGSDRangel::SWGWFMDemodSettings *swgWFMDemodSettings = swgChannelSettings->getWfmDemodSettings(); @@ -425,25 +488,6 @@ void WFMDemod::webapiReverseSendSettings(QList& channelSettingsKeys, co if (channelSettingsKeys.contains("streamIndex") || force) { swgWFMDemodSettings->setStreamIndex(settings.m_streamIndex); } - - 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 - QNetworkReply *reply = m_networkManager->sendCustomRequest(m_networkRequest, "PATCH", buffer); - buffer->setParent(reply); - - delete swgChannelSettings; } void WFMDemod::networkManagerFinished(QNetworkReply *reply) diff --git a/plugins/channelrx/demodwfm/wfmdemod.h b/plugins/channelrx/demodwfm/wfmdemod.h index b0ba2f628..71ac9f15c 100644 --- a/plugins/channelrx/demodwfm/wfmdemod.h +++ b/plugins/channelrx/demodwfm/wfmdemod.h @@ -137,6 +137,13 @@ private: void webapiFormatChannelReport(SWGSDRangel::SWGChannelReport& response); void webapiReverseSendSettings(QList& channelSettingsKeys, const WFMDemodSettings& settings, bool force); + void featuresSendSettings(QList& channelSettingsKeys, const WFMDemodSettings& settings, bool force); + void webapiFormatChannelSettings( + QList& channelSettingsKeys, + SWGSDRangel::SWGChannelSettings *swgChannelSettings, + const WFMDemodSettings& settings, + bool force + ); private slots: void networkManagerFinished(QNetworkReply *reply); diff --git a/plugins/channelrx/filesink/filesink.cpp b/plugins/channelrx/filesink/filesink.cpp index 288d0e989..52a91193a 100644 --- a/plugins/channelrx/filesink/filesink.cpp +++ b/plugins/channelrx/filesink/filesink.cpp @@ -35,6 +35,8 @@ #include "dsp/hbfilterchainconverter.h" #include "dsp/devicesamplemimo.h" #include "device/deviceapi.h" +#include "feature/feature.h" +#include "maincore.h" #include "filesinkmessages.h" #include "filesinkbaseband.h" @@ -293,6 +295,10 @@ void FileSink::applySettings(const FileSinkSettings& settings, bool force) webapiReverseSendSettings(reverseAPIKeys, settings, fullUpdate || force); } + if (m_featuresSettingsFeedback.size() > 0) { + featuresSendSettings(reverseAPIKeys, settings, force); + } + m_settings = settings; } @@ -522,10 +528,67 @@ void FileSink::webapiFormatChannelReport(SWGSDRangel::SWGChannelReport& response void FileSink::webapiReverseSendSettings(QList& channelSettingsKeys, const FileSinkSettings& settings, bool force) { SWGSDRangel::SWGChannelSettings *swgChannelSettings = new SWGSDRangel::SWGChannelSettings(); - swgChannelSettings->setDirection(0); // single sink (Rx) + webapiFormatChannelSettings(channelSettingsKeys, swgChannelSettings, settings, force); + + 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 + QNetworkReply *reply = m_networkManager->sendCustomRequest(m_networkRequest, "PATCH", buffer); + buffer->setParent(reply); + + delete swgChannelSettings; +} + +void FileSink::featuresSendSettings(QList& channelSettingsKeys, const FileSinkSettings& settings, bool force) +{ + QList::iterator it = m_featuresSettingsFeedback.begin(); + MainCore *mainCore = MainCore::instance(); + + for (; it != m_featuresSettingsFeedback.end(); ++it) + { + if (mainCore->existsFeature(*it)) + { + SWGSDRangel::SWGChannelSettings *swgChannelSettings = new SWGSDRangel::SWGChannelSettings(); + webapiFormatChannelSettings(channelSettingsKeys, swgChannelSettings, settings, force); + + Feature::MsgChannelSettings *msg = Feature::MsgChannelSettings::create( + this, + channelSettingsKeys, + swgChannelSettings, + force + ); + + (*it)->getInputMessageQueue()->push(msg); + } + else + { + m_featuresSettingsFeedback.removeOne(*it); + } + } +} + +void FileSink::webapiFormatChannelSettings( + QList& channelSettingsKeys, + SWGSDRangel::SWGChannelSettings *swgChannelSettings, + const FileSinkSettings& settings, + bool force +) +{ + swgChannelSettings->setDirection(0); // Single sink (Rx) swgChannelSettings->setOriginatorChannelIndex(getIndexInDeviceSet()); swgChannelSettings->setOriginatorDeviceSetIndex(getDeviceSetIndex()); - swgChannelSettings->setChannelType(new QString("FileSink")); + swgChannelSettings->setChannelType(new QString(m_channelId)); swgChannelSettings->setFileSinkSettings(new SWGSDRangel::SWGFileSinkSettings()); SWGSDRangel::SWGFileSinkSettings *swgFileSinkSettings = swgChannelSettings->getFileSinkSettings(); @@ -564,25 +627,6 @@ void FileSink::webapiReverseSendSettings(QList& channelSettingsKeys, co if (channelSettingsKeys.contains("streamIndex")) { swgFileSinkSettings->setStreamIndex(settings.m_streamIndex); } - - 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 - QNetworkReply *reply = m_networkManager->sendCustomRequest(m_networkRequest, "PATCH", buffer); - buffer->setParent(reply); - - delete swgChannelSettings; } void FileSink::networkManagerFinished(QNetworkReply *reply) diff --git a/plugins/channelrx/filesink/filesink.h b/plugins/channelrx/filesink/filesink.h index 238742616..e60107e96 100644 --- a/plugins/channelrx/filesink/filesink.h +++ b/plugins/channelrx/filesink/filesink.h @@ -148,6 +148,13 @@ private: void webapiFormatChannelReport(SWGSDRangel::SWGChannelReport& response); void webapiReverseSendSettings(QList& channelSettingsKeys, const FileSinkSettings& settings, bool force); + void featuresSendSettings(QList& channelSettingsKeys, const FileSinkSettings& settings, bool force); + void webapiFormatChannelSettings( + QList& channelSettingsKeys, + SWGSDRangel::SWGChannelSettings *swgChannelSettings, + const FileSinkSettings& settings, + bool force + ); private slots: void networkManagerFinished(QNetworkReply *reply); diff --git a/plugins/channelrx/freqtracker/freqtracker.cpp b/plugins/channelrx/freqtracker/freqtracker.cpp index 497a59ebb..1b5f1ff75 100644 --- a/plugins/channelrx/freqtracker/freqtracker.cpp +++ b/plugins/channelrx/freqtracker/freqtracker.cpp @@ -41,6 +41,8 @@ #include "device/deviceapi.h" #include "util/db.h" #include "util/stepfunctions.h" +#include "feature/feature.h" +#include "maincore.h" #include "freqtrackerreport.h" @@ -53,12 +55,14 @@ const int FreqTracker::m_udpBlockSize = 512; FreqTracker::FreqTracker(DeviceAPI *deviceAPI) : ChannelAPI(m_channelIdURI, ChannelAPI::StreamSingleSink), m_deviceAPI(deviceAPI), + m_spectrumVis(SDR_RX_SCALEF), m_basebandSampleRate(0) { setObjectName(m_channelId); m_thread = new QThread(this); m_basebandSink = new FreqTrackerBaseband(); + m_basebandSink->setSpectrumSink(&m_spectrumVis); propagateMessageQueue(getInputMessageQueue()); m_basebandSink->moveToThread(m_thread); @@ -178,6 +182,7 @@ void FreqTracker::applySettings(const FreqTrackerSettings& settings, bool force) << " m_rrc: " << settings.m_rrc << " m_rrcRolloff: " << settings.m_rrcRolloff << " m_streamIndex: " << settings.m_streamIndex + << " m_spanLog2: " << settings.m_spanLog2 << " m_useReverseAPI: " << settings.m_useReverseAPI << " m_reverseAPIAddress: " << settings.m_reverseAPIAddress << " m_reverseAPIPort: " << settings.m_reverseAPIPort @@ -211,6 +216,9 @@ void FreqTracker::applySettings(const FreqTrackerSettings& settings, bool force) if ((m_settings.m_alphaEMA != settings.m_alphaEMA) || force) { reverseAPIKeys.append("alphaEMA"); } + if ((m_settings.m_spanLog2 != settings.m_spanLog2) || force) { + reverseAPIKeys.append("spanLog2"); + } if ((m_settings.m_tracking != settings.m_tracking) || force) { reverseAPIKeys.append("tracking"); } @@ -256,6 +264,15 @@ void FreqTracker::applySettings(const FreqTrackerSettings& settings, bool force) webapiReverseSendSettings(reverseAPIKeys, settings, fullUpdate || force); } + if (m_featuresSettingsFeedback.size() > 0) + { + if (m_featuresSettingsFeedbackBlockCount == 0) { + featuresSendSettings(reverseAPIKeys, settings, force); + } else { + m_featuresSettingsFeedbackBlockCount--; + } + } + m_settings = settings; } @@ -341,6 +358,9 @@ void FreqTracker::webapiUpdateChannelSettings( if (channelSettingsKeys.contains("title")) { settings.m_title = *response.getFreqTrackerSettings()->getTitle(); } + if (channelSettingsKeys.contains("spanLog2")) { + settings.m_spanLog2 = response.getFreqTrackerSettings()->getSpanLog2(); + } if (channelSettingsKeys.contains("alphaEMA")) { float alphaEMA = response.getFreqTrackerSettings()->getAlphaEma(); settings.m_alphaEMA = alphaEMA < 0.01 ? 0.01 : alphaEMA > 1.0 ? 1.0 : alphaEMA; @@ -412,6 +432,7 @@ void FreqTracker::webapiFormatChannelSettings(SWGSDRangel::SWGChannelSettings& r response.getFreqTrackerSettings()->setTitle(new QString(settings.m_title)); } + response.getFreqTrackerSettings()->setSpanLog2(settings.m_spanLog2); response.getFreqTrackerSettings()->setAlphaEma(settings.m_alphaEMA); response.getFreqTrackerSettings()->setTracking(settings.m_tracking ? 1 : 0); response.getFreqTrackerSettings()->setTrackerType((int) settings.m_trackerType); @@ -449,36 +470,7 @@ void FreqTracker::webapiFormatChannelReport(SWGSDRangel::SWGChannelReport& respo void FreqTracker::webapiReverseSendSettings(QList& channelSettingsKeys, const FreqTrackerSettings& settings, bool force) { SWGSDRangel::SWGChannelSettings *swgChannelSettings = new SWGSDRangel::SWGChannelSettings(); - swgChannelSettings->setDirection(0); // single sink (Rx) - swgChannelSettings->setOriginatorChannelIndex(getIndexInDeviceSet()); - swgChannelSettings->setOriginatorDeviceSetIndex(getDeviceSetIndex()); - swgChannelSettings->setChannelType(new QString("FreqTracker")); - swgChannelSettings->setFreqTrackerSettings(new SWGSDRangel::SWGFreqTrackerSettings()); - SWGSDRangel::SWGFreqTrackerSettings *swgFreqTrackerSettings = swgChannelSettings->getFreqTrackerSettings(); - - // transfer data that has been modified. When force is on transfer all data except reverse API data - - if (channelSettingsKeys.contains("inputFrequencyOffset") || force) { - swgFreqTrackerSettings->setInputFrequencyOffset(settings.m_inputFrequencyOffset); - } - if (channelSettingsKeys.contains("rfBandwidth") || force) { - swgFreqTrackerSettings->setRfBandwidth(settings.m_rfBandwidth); - } - if (channelSettingsKeys.contains("rgbColor") || force) { - swgFreqTrackerSettings->setRgbColor(settings.m_rgbColor); - } - if (channelSettingsKeys.contains("squelch") || force) { - swgFreqTrackerSettings->setSquelch(settings.m_squelch); - } - if (channelSettingsKeys.contains("title") || force) { - swgFreqTrackerSettings->setTitle(new QString(settings.m_title)); - } - if (channelSettingsKeys.contains("trackerType") || force) { - swgFreqTrackerSettings->setTrackerType((int) settings.m_trackerType); - } - if (channelSettingsKeys.contains("streamIndex") || force) { - swgFreqTrackerSettings->setStreamIndex(settings.m_streamIndex); - } + webapiFormatChannelSettings(channelSettingsKeys, swgChannelSettings, settings, force); QString channelSettingsURL = QString("http://%1:%2/sdrangel/deviceset/%3/channel/%4/settings") .arg(settings.m_reverseAPIAddress) @@ -500,6 +492,96 @@ void FreqTracker::webapiReverseSendSettings(QList& channelSettingsKeys, delete swgChannelSettings; } +void FreqTracker::featuresSendSettings(QList& channelSettingsKeys, const FreqTrackerSettings& settings, bool force) +{ + QList::iterator it = m_featuresSettingsFeedback.begin(); + MainCore *mainCore = MainCore::instance(); + + for (; it != m_featuresSettingsFeedback.end(); ++it) + { + if (mainCore->existsFeature(*it)) + { + SWGSDRangel::SWGChannelSettings *swgChannelSettings = new SWGSDRangel::SWGChannelSettings(); + webapiFormatChannelSettings(channelSettingsKeys, swgChannelSettings, settings, force); + + Feature::MsgChannelSettings *msg = Feature::MsgChannelSettings::create( + this, + channelSettingsKeys, + swgChannelSettings, + force + ); + + (*it)->getInputMessageQueue()->push(msg); + } + else + { + m_featuresSettingsFeedback.removeOne(*it); + } + } +} + +void FreqTracker::webapiFormatChannelSettings( + QList& channelSettingsKeys, + SWGSDRangel::SWGChannelSettings *swgChannelSettings, + const FreqTrackerSettings& settings, + bool force) +{ + swgChannelSettings->setDirection(0); // single sink (Rx) + swgChannelSettings->setOriginatorChannelIndex(getIndexInDeviceSet()); + swgChannelSettings->setOriginatorDeviceSetIndex(getDeviceSetIndex()); + swgChannelSettings->setChannelType(new QString("FreqTracker")); + swgChannelSettings->setFreqTrackerSettings(new SWGSDRangel::SWGFreqTrackerSettings()); + SWGSDRangel::SWGFreqTrackerSettings *swgFreqTrackerSettings = swgChannelSettings->getFreqTrackerSettings(); + + // transfer data that has been modified. When force is on transfer all data except reverse API data + + if (channelSettingsKeys.contains("inputFrequencyOffset") || force) { + swgFreqTrackerSettings->setInputFrequencyOffset(settings.m_inputFrequencyOffset); + } + if (channelSettingsKeys.contains("rfBandwidth") || force) { + swgFreqTrackerSettings->setRfBandwidth(settings.m_rfBandwidth); + } + if (channelSettingsKeys.contains("log2Decim") || force) { + swgFreqTrackerSettings->setLog2Decim(settings.m_log2Decim); + } + if (channelSettingsKeys.contains("squelch") || force) { + swgFreqTrackerSettings->setSquelch(settings.m_squelch); + } + if (channelSettingsKeys.contains("rgbColor") || force) { + swgFreqTrackerSettings->setRgbColor(settings.m_rgbColor); + } + if (channelSettingsKeys.contains("title") || force) { + swgFreqTrackerSettings->setTitle(new QString(settings.m_title)); + } + if (channelSettingsKeys.contains("spanLog2") || force) { + swgFreqTrackerSettings->setSpanLog2(settings.m_spanLog2); + } + if (channelSettingsKeys.contains("alphaEMA") || force) { + swgFreqTrackerSettings->setAlphaEma(settings.m_alphaEMA); + } + if (channelSettingsKeys.contains("tracking") || force) { + swgFreqTrackerSettings->setTracking(settings.m_tracking ? 1 : 0); + } + if (channelSettingsKeys.contains("trackerType") || force) { + swgFreqTrackerSettings->setTrackerType((int) settings.m_trackerType); + } + if (channelSettingsKeys.contains("pllPskOrder") || force) { + swgFreqTrackerSettings->setPllPskOrder(settings.m_pllPskOrder); + } + if (channelSettingsKeys.contains("rrc") || force) { + swgFreqTrackerSettings->setRrc(settings.m_rrc ? 1 : 0); + } + if (channelSettingsKeys.contains("rrcRolloff") || force) { + swgFreqTrackerSettings->setRrcRolloff(settings.m_rrcRolloff); + } + if (channelSettingsKeys.contains("squelchGate") || force) { + swgFreqTrackerSettings->setSquelchGate(settings.m_squelchGate); + } + if (channelSettingsKeys.contains("streamIndex") || force) { + swgFreqTrackerSettings->setStreamIndex(settings.m_streamIndex); + } +} + void FreqTracker::networkManagerFinished(QNetworkReply *reply) { QNetworkReply::NetworkError replyError = reply->error(); diff --git a/plugins/channelrx/freqtracker/freqtracker.h b/plugins/channelrx/freqtracker/freqtracker.h index 224059e3b..c374384ae 100644 --- a/plugins/channelrx/freqtracker/freqtracker.h +++ b/plugins/channelrx/freqtracker/freqtracker.h @@ -24,6 +24,7 @@ #include #include "dsp/basebandsamplesink.h" +#include "dsp/spectrumvis.h" #include "channel/channelapi.h" #include "util/message.h" @@ -109,6 +110,7 @@ public: const QStringList& channelSettingsKeys, SWGSDRangel::SWGChannelSettings& response); + SpectrumVis *getSpectrumVis() { return &m_spectrumVis; } uint32_t getSampleRate() const { return m_basebandSink->getSampleRate(); } double getMagSq() const { return m_basebandSink->getMagSq(); } bool getSquelchOpen() const { return m_basebandSink->getSquelchOpen(); } @@ -131,6 +133,7 @@ private: QThread *m_thread; FreqTrackerBaseband* m_basebandSink; FreqTrackerSettings m_settings; + SpectrumVis m_spectrumVis; int m_basebandSampleRate; //!< stored from device message used when starting baseband sink static const int m_udpBlockSize; QNetworkAccessManager *m_networkManager; @@ -139,6 +142,13 @@ private: void applySettings(const FreqTrackerSettings& settings, bool force = false); void webapiFormatChannelReport(SWGSDRangel::SWGChannelReport& response); void webapiReverseSendSettings(QList& channelSettingsKeys, const FreqTrackerSettings& settings, bool force); + void featuresSendSettings(QList& channelSettingsKeys, const FreqTrackerSettings& settings, bool force); + void webapiFormatChannelSettings( + QList& channelSettingsKeys, + SWGSDRangel::SWGChannelSettings *swgChannelSettings, + const FreqTrackerSettings& settings, + bool force + ); private slots: void networkManagerFinished(QNetworkReply *reply); diff --git a/plugins/channelrx/freqtracker/freqtrackerbaseband.h b/plugins/channelrx/freqtracker/freqtrackerbaseband.h index ae3ac94ea..716b9ac7a 100644 --- a/plugins/channelrx/freqtracker/freqtrackerbaseband.h +++ b/plugins/channelrx/freqtracker/freqtrackerbaseband.h @@ -28,6 +28,7 @@ #include "freqtrackersink.h" class DownChannelizer; +class SpectrumVis; class FreqTrackerBaseband : public QObject { @@ -61,6 +62,7 @@ public: void reset(); void feed(const SampleVector::const_iterator& begin, const SampleVector::const_iterator& end); MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; } //!< Get the queue for asynchronous inbound communication + void setSpectrumSink(SpectrumVis* spectrumSink) { m_spectrumVis = spectrumSink; m_sink.setSpectrumSink(spectrumSink); } int getChannelSampleRate() const; void setBasebandSampleRate(int sampleRate); void setMessageQueueToInput(MessageQueue *messageQueue) { m_sink.setMessageQueueToInput(messageQueue); } @@ -80,6 +82,7 @@ private: MessageQueue m_inputMessageQueue; //!< Queue for asynchronous inbound communication FreqTrackerSettings m_settings; unsigned int m_basebandSampleRate; + SpectrumVis *m_spectrumVis; QMutex m_mutex; bool handleMessage(const Message& cmd); diff --git a/plugins/channelrx/freqtracker/freqtrackergui.cpp b/plugins/channelrx/freqtracker/freqtrackergui.cpp index 91d143a5e..8df525b23 100644 --- a/plugins/channelrx/freqtracker/freqtrackergui.cpp +++ b/plugins/channelrx/freqtracker/freqtrackergui.cpp @@ -91,6 +91,8 @@ bool FreqTrackerGUI::handleMessage(const Message& message) m_basebandSampleRate = cfg.getSampleRate(); int sinkSampleRate = m_basebandSampleRate / (1<channelSampleRateText->setText(tr("%1k").arg(QString::number(sinkSampleRate / 1000.0f, 'g', 5))); + displaySpectrumBandwidth(m_settings.m_spanLog2); + m_pllChannelMarker.setBandwidth(sinkSampleRate/500); if (sinkSampleRate > 1000) { ui->rfBW->setMaximum(sinkSampleRate/100); @@ -151,6 +153,8 @@ void FreqTrackerGUI::on_log2Decim_currentIndexChanged(int index) m_settings.m_log2Decim = index < 0 ? 0 : index > 6 ? 6 : index; int sinkSampleRate = m_basebandSampleRate / (1<channelSampleRateText->setText(tr("%1k").arg(QString::number(sinkSampleRate / 1000.0f, 'g', 5))); + displaySpectrumBandwidth(m_settings.m_spanLog2); + m_pllChannelMarker.setBandwidth(sinkSampleRate/500); if (sinkSampleRate > 1000) { ui->rfBW->setMaximum(sinkSampleRate/100); @@ -231,6 +235,15 @@ void FreqTrackerGUI::on_squelchGate_valueChanged(int value) applySettings(); } +void FreqTrackerGUI::on_spanLog2_valueChanged(int value) +{ + if ((value < 0) || (value > 6)) { + return; + } + + applySpectrumBandwidth(ui->spanLog2->value()); +} + void FreqTrackerGUI::onWidgetRolled(QWidget* widget, bool rollDown) { (void) widget; @@ -288,6 +301,7 @@ FreqTrackerGUI::FreqTrackerGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, B m_pluginAPI(pluginAPI), m_deviceUISet(deviceUISet), m_channelMarker(this), + m_pllChannelMarker(this), m_basebandSampleRate(0), m_doApplySettings(true), m_squelchOpen(false), @@ -300,6 +314,8 @@ FreqTrackerGUI::FreqTrackerGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, B m_freqTracker = reinterpret_cast(rxChannel); m_freqTracker->setMessageQueueToGUI(getInputMessageQueue()); + m_spectrumVis = m_freqTracker->getSpectrumVis(); + m_spectrumVis->setGLSpectrum(ui->glSpectrum); connect(&MainCore::instance()->getMasterTimer(), SIGNAL(timeout()), this, SLOT(tick())); // 50 ms @@ -318,10 +334,23 @@ FreqTrackerGUI::FreqTrackerGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, B setTitleColor(m_channelMarker.getColor()); m_settings.setChannelMarker(&m_channelMarker); + m_settings.setSpectrumGUI(ui->spectrumGUI); m_deviceUISet->addChannelMarker(&m_channelMarker); m_deviceUISet->addRollupWidget(this); + ui->glSpectrum->setCenterFrequency(0); + m_pllChannelMarker.blockSignals(true); + m_pllChannelMarker.setColor(Qt::white); + m_pllChannelMarker.setCenterFrequency(0); + m_pllChannelMarker.setBandwidth(70); + m_pllChannelMarker.setTitle("Tracker"); + m_pllChannelMarker.setMovable(false); + m_pllChannelMarker.blockSignals(false); + m_pllChannelMarker.setVisible(true); + ui->glSpectrum->addChannelMarker(&m_pllChannelMarker); + ui->spectrumGUI->setBuddies(m_spectrumVis, ui->glSpectrum); + connect(&m_channelMarker, SIGNAL(changedByCursor()), this, SLOT(channelMarkerChangedByCursor())); connect(&m_channelMarker, SIGNAL(highlightedByCursor()), this, SLOT(channelMarkerHighlightedByCursor())); connect(getInputMessageQueue(), SIGNAL(messageEnqueued()), this, SLOT(handleInputMessages())); @@ -349,6 +378,13 @@ void FreqTrackerGUI::applySettings(bool force) } } +void FreqTrackerGUI::applySpectrumBandwidth(int spanLog2, bool force) +{ + displaySpectrumBandwidth(spanLog2); + m_settings.m_spanLog2 = spanLog2; + applySettings(force); +} + void FreqTrackerGUI::displaySettings() { m_channelMarker.blockSignals(true); @@ -387,11 +423,29 @@ void FreqTrackerGUI::displaySettings() ui->squelchGateText->setText(QString("%1").arg(m_settings.m_squelchGate * 10.0f, 0, 'f', 0)); ui->squelchGate->setValue(m_settings.m_squelchGate); + displaySpectrumBandwidth(m_settings.m_spanLog2); displayStreamIndex(); blockApplySettings(false); } +void FreqTrackerGUI::displaySpectrumBandwidth(int spanLog2) +{ + int spectrumRate = (m_basebandSampleRate / (1<spanLog2->blockSignals(true); + ui->spanLog2->setValue(spanLog2); + ui->spanLog2->blockSignals(false); + ui->spanText->setText(tr("%1k").arg(spanStr)); + ui->glSpectrum->setSampleRate(spectrumRate); +} + void FreqTrackerGUI::displayStreamIndex() { if (m_deviceUISet->m_deviceMIMOEngine) { @@ -445,6 +499,7 @@ void FreqTrackerGUI::tick() int freq = m_freqTracker->getAvgDeltaFreq(); QLocale loc; ui->trackingFrequencyText->setText(tr("%1 Hz").arg(loc.toString(freq))); + m_pllChannelMarker.setCenterFrequency(freq); if (m_settings.m_tracking) { ui->tracking->setToolTip("Tracking on"); diff --git a/plugins/channelrx/freqtracker/freqtrackergui.h b/plugins/channelrx/freqtracker/freqtrackergui.h index a0fa5b636..4c7943bef 100644 --- a/plugins/channelrx/freqtracker/freqtrackergui.h +++ b/plugins/channelrx/freqtracker/freqtrackergui.h @@ -28,9 +28,9 @@ class PluginAPI; class DeviceUISet; - class FreqTracker; class BasebandSampleSink; +class SpectrumVis; namespace Ui { class FreqTrackerGUI; @@ -57,11 +57,13 @@ private: PluginAPI* m_pluginAPI; DeviceUISet* m_deviceUISet; ChannelMarker m_channelMarker; + ChannelMarker m_pllChannelMarker; FreqTrackerSettings m_settings; int m_basebandSampleRate; bool m_doApplySettings; FreqTracker* m_freqTracker; + SpectrumVis* m_spectrumVis; bool m_squelchOpen; uint32_t m_tickCount; MessageQueue m_inputMessageQueue; @@ -71,7 +73,9 @@ private: void blockApplySettings(bool block); void applySettings(bool force = false); + void applySpectrumBandwidth(int spanLog2, bool force = false); void displaySettings(); + void displaySpectrumBandwidth(int spanLog2); void displayStreamIndex(); bool handleMessage(const Message& message); @@ -90,6 +94,7 @@ private slots: void on_rrcRolloff_valueChanged(int value); void on_squelch_valueChanged(int value); void on_squelchGate_valueChanged(int value); + void on_spanLog2_valueChanged(int value); void onWidgetRolled(QWidget* widget, bool rollDown); void onMenuDialogCalled(const QPoint& p); void handleInputMessages(); diff --git a/plugins/channelrx/freqtracker/freqtrackergui.ui b/plugins/channelrx/freqtracker/freqtrackergui.ui index 6238f9883..4e88d0d5b 100644 --- a/plugins/channelrx/freqtracker/freqtrackergui.ui +++ b/plugins/channelrx/freqtracker/freqtrackergui.ui @@ -6,8 +6,8 @@ 0 0 - 360 - 145 + 400 + 327 @@ -18,16 +18,10 @@ - 360 + 400 100 - - - 360 - 16777215 - - Liberation Sans @@ -45,8 +39,8 @@ 0 0 - 358 - 140 + 401 + 151 @@ -679,6 +673,122 @@ + + + + + + + 50 + 0 + + + + + 50 + 16777215 + + + + Span + + + + + + + Spectrum display frequency span + + + 0 + + + 6 + + + 1 + + + 0 + + + 0 + + + Qt::Horizontal + + + + + + + + 50 + 0 + + + + + 50 + 16777215 + + + + Spectrum display frequency span (kHz) + + + 6.0k + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + + + + 0 + 160 + 401 + 161 + + + + Channel Spectrum + + + + 2 + + + 3 + + + 3 + + + 3 + + + 3 + + + + + + Liberation Mono + 8 + + + + + + + @@ -689,23 +799,35 @@
gui/rollupwidget.h
1 + + ButtonSwitch + QToolButton +
gui/buttonswitch.h
+
LevelMeterSignalDB QWidget
gui/levelmeter.h
1
- - ButtonSwitch - QToolButton -
gui/buttonswitch.h
-
ValueDialZ QWidget
gui/valuedialz.h
1
+ + GLSpectrum + QWidget +
gui/glspectrum.h
+ 1 +
+ + GLSpectrumGUI + QWidget +
gui/glspectrumgui.h
+ 1 +
diff --git a/plugins/channelrx/freqtracker/freqtrackersettings.cpp b/plugins/channelrx/freqtracker/freqtrackersettings.cpp index 65f2c4f53..96a831e01 100644 --- a/plugins/channelrx/freqtracker/freqtrackersettings.cpp +++ b/plugins/channelrx/freqtracker/freqtrackersettings.cpp @@ -23,7 +23,8 @@ #include "freqtrackersettings.h" FreqTrackerSettings::FreqTrackerSettings() : - m_channelMarker(0) + m_channelMarker(0), + m_spectrumGUI(0) { resetToDefaults(); } @@ -36,6 +37,7 @@ void FreqTrackerSettings::resetToDefaults() m_squelch = -40.0; m_rgbColor = QColor(200, 244, 66).rgb(); m_title = "Frequency Tracker"; + m_spanLog2 = 0; m_alphaEMA = 0.1; m_tracking = false; m_trackerType = TrackerFLL; @@ -57,6 +59,10 @@ QByteArray FreqTrackerSettings::serialize() const s.writeS32(1, m_inputFrequencyOffset); s.writeS32(2, m_rfBandwidth/100); s.writeU32(3, m_log2Decim); + + if (m_spectrumGUI) { + s.writeBlob(4, m_spectrumGUI->serialize()); + } s.writeS32(5, m_squelch); if (m_channelMarker) { @@ -67,6 +73,7 @@ QByteArray FreqTrackerSettings::serialize() const s.writeFloat(8, m_alphaEMA); s.writeString(9, m_title); s.writeBool(10, m_tracking); + s.writeS32(11, m_spanLog2); s.writeS32(12, (int) m_trackerType); s.writeU32(13, m_pllPskOrder); s.writeBool(14, m_rrc); @@ -105,7 +112,13 @@ bool FreqTrackerSettings::deserialize(const QByteArray& data) m_rfBandwidth = 100 * tmp; d.readU32(3, &utmp, 0); m_log2Decim = utmp > 6 ? 6 : utmp; - d.readS32(4, &tmp, 20); + + if (m_spectrumGUI) + { + d.readBlob(4, &bytetmp); + m_spectrumGUI->deserialize(bytetmp); + } + d.readS32(5, &tmp, -40); m_squelch = tmp; d.readBlob(6, &bytetmp); @@ -119,6 +132,7 @@ bool FreqTrackerSettings::deserialize(const QByteArray& data) m_alphaEMA = ftmp < 0.01 ? 0.01 : ftmp > 1.0 ? 1.0 : ftmp; d.readString(9, &m_title, "Frequency Tracker"); d.readBool(10, &m_tracking, false); + d.readS32(11, &m_spanLog2, 0); d.readS32(12, &tmp, 0); m_trackerType = tmp < 0 ? TrackerFLL : tmp > 2 ? TrackerPLL : (TrackerType) tmp; d.readU32(13, &utmp, 2); diff --git a/plugins/channelrx/freqtracker/freqtrackersettings.h b/plugins/channelrx/freqtracker/freqtrackersettings.h index aabd85f7e..c3ba9ef85 100644 --- a/plugins/channelrx/freqtracker/freqtrackersettings.h +++ b/plugins/channelrx/freqtracker/freqtrackersettings.h @@ -41,6 +41,8 @@ struct FreqTrackerSettings quint32 m_rgbColor; QString m_title; Serializable *m_channelMarker; + Serializable *m_spectrumGUI; + int m_spanLog2; float m_alphaEMA; //!< alpha factor for delta frequency EMA bool m_tracking; TrackerType m_trackerType; @@ -58,6 +60,7 @@ struct FreqTrackerSettings FreqTrackerSettings(); void resetToDefaults(); void setChannelMarker(Serializable *channelMarker) { m_channelMarker = channelMarker; } + void setSpectrumGUI(Serializable *spectrumGUI) { m_spectrumGUI = spectrumGUI; } QByteArray serialize() const; bool deserialize(const QByteArray& data); }; diff --git a/plugins/channelrx/freqtracker/freqtrackersink.cpp b/plugins/channelrx/freqtracker/freqtrackersink.cpp index 390ae77ce..4b8ee1c78 100644 --- a/plugins/channelrx/freqtracker/freqtrackersink.cpp +++ b/plugins/channelrx/freqtracker/freqtrackersink.cpp @@ -22,6 +22,7 @@ #include "dsp/dspengine.h" #include "dsp/dspcommands.h" #include "dsp/fftfilt.h" +#include "dsp/spectrumvis.h" #include "util/db.h" #include "util/stepfunctions.h" #include "util/messagequeue.h" @@ -33,6 +34,9 @@ FreqTrackerSink::FreqTrackerSink() : m_channelSampleRate(48000), m_inputFrequencyOffset(0), m_sinkSampleRate(48000), + m_spectrumSink(nullptr), + m_sampleBufferCount(0), + m_undersampleCount(0), m_squelchOpen(false), m_squelchGate(0), m_magsqSum(0.0f), @@ -52,6 +56,9 @@ FreqTrackerSink::FreqTrackerSink() : m_timer = &DSPEngine::instance()->getMasterTimer(); #endif m_magsq = 0.0; + m_sampleBufferSize = m_sinkSampleRate / 20; // 50 ms + m_sampleBuffer.resize(m_sampleBufferSize); + m_sum = Complex{0.0, 0.0}; m_rrcFilter = new fftfilt(m_settings.m_rfBandwidth / m_sinkSampleRate, 2*1024); m_pll.computeCoefficients(0.002f, 0.5f, 10.0f); // bandwidth, damping factor, loop gain @@ -102,6 +109,18 @@ void FreqTrackerSink::processOneSample(Complex &ci) { fftfilt::cmplx *sideband; int n_out; + int decim = 1<feed(m_sampleBuffer.begin(), m_sampleBuffer.end(), false); + m_sampleBufferCount = 0; + } + } Real FreqTrackerSink::getFrequency() const @@ -215,6 +242,11 @@ void FreqTrackerSink::applyChannelSettings(int sinkSampleRate, int channelSample if (useInterpolator) { setInterpolator(); } + + m_sampleBufferSize = (m_sinkSampleRate/(1<10: Squelch time gate +

10: Squelch time gate

-Number of milliseconds following squelch gate opening after which the signal is declared open. 0 means squelch is declared open with no delay and is suitable for burst signals. The value can be varied in steps of 10 ms from 0 to 990 ms. \ No newline at end of file +Number of milliseconds following squelch gate opening after which the signal is declared open. 0 means squelch is declared open with no delay and is suitable for burst signals. The value can be varied in steps of 10 ms from 0 to 990 ms. + +

11: Spectrum display frequency span

+ +The channel signal is decimated by a power of two before being applied to the channel spectrum display. It is a kind of zoom on the center of the spectrum. + +

12: Channel spectrum

+ +This is the spectrum display of the tracker channel. When the tracker is locked to the signal the center of the channel should fall almost in the middle of the signal spectrum (ideally in the middle when the tracker error is zero). Thus the locking can be followed dynamically and it can be more reliable than the lock indicator. A channel marker shows the tracker offset from the channel center frequency (tracker error). Its width is the tracker error tolerance and is ±1/1000th of the channel width. Controls on the bottom of the panel are identical to the ones of the main spectrum display. diff --git a/plugins/channelrx/localsink/localsink.cpp b/plugins/channelrx/localsink/localsink.cpp index b1f62c4fe..a33a80997 100644 --- a/plugins/channelrx/localsink/localsink.cpp +++ b/plugins/channelrx/localsink/localsink.cpp @@ -33,6 +33,8 @@ #include "dsp/hbfilterchainconverter.h" #include "dsp/devicesamplemimo.h" #include "device/deviceapi.h" +#include "feature/feature.h" +#include "maincore.h" #include "localsinkbaseband.h" #include "localsink.h" @@ -302,6 +304,10 @@ void LocalSink::applySettings(const LocalSinkSettings& settings, bool force) webapiReverseSendSettings(reverseAPIKeys, settings, fullUpdate || force); } + if (m_featuresSettingsFeedback.size() > 0) { + featuresSendSettings(reverseAPIKeys, settings, force); + } + m_settings = settings; } @@ -436,10 +442,67 @@ void LocalSink::webapiFormatChannelSettings(SWGSDRangel::SWGChannelSettings& res void LocalSink::webapiReverseSendSettings(QList& channelSettingsKeys, const LocalSinkSettings& settings, bool force) { SWGSDRangel::SWGChannelSettings *swgChannelSettings = new SWGSDRangel::SWGChannelSettings(); - swgChannelSettings->setDirection(0); // single sink (Rx) + webapiFormatChannelSettings(channelSettingsKeys, swgChannelSettings, settings, force); + + 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 + QNetworkReply *reply = m_networkManager->sendCustomRequest(m_networkRequest, "PATCH", buffer); + buffer->setParent(reply); + + delete swgChannelSettings; +} + +void LocalSink::featuresSendSettings(QList& channelSettingsKeys, const LocalSinkSettings& settings, bool force) +{ + QList::iterator it = m_featuresSettingsFeedback.begin(); + MainCore *mainCore = MainCore::instance(); + + for (; it != m_featuresSettingsFeedback.end(); ++it) + { + if (mainCore->existsFeature(*it)) + { + SWGSDRangel::SWGChannelSettings *swgChannelSettings = new SWGSDRangel::SWGChannelSettings(); + webapiFormatChannelSettings(channelSettingsKeys, swgChannelSettings, settings, force); + + Feature::MsgChannelSettings *msg = Feature::MsgChannelSettings::create( + this, + channelSettingsKeys, + swgChannelSettings, + force + ); + + (*it)->getInputMessageQueue()->push(msg); + } + else + { + m_featuresSettingsFeedback.removeOne(*it); + } + } +} + +void LocalSink::webapiFormatChannelSettings( + QList& channelSettingsKeys, + SWGSDRangel::SWGChannelSettings *swgChannelSettings, + const LocalSinkSettings& settings, + bool force +) +{ + swgChannelSettings->setDirection(0); // Single sink (Rx) swgChannelSettings->setOriginatorChannelIndex(getIndexInDeviceSet()); swgChannelSettings->setOriginatorDeviceSetIndex(getDeviceSetIndex()); - swgChannelSettings->setChannelType(new QString("LocalSink")); + swgChannelSettings->setChannelType(new QString(m_channelId)); swgChannelSettings->setLocalSinkSettings(new SWGSDRangel::SWGLocalSinkSettings()); SWGSDRangel::SWGLocalSinkSettings *swgLocalSinkSettings = swgChannelSettings->getLocalSinkSettings(); @@ -466,25 +529,6 @@ void LocalSink::webapiReverseSendSettings(QList& channelSettingsKeys, c if (channelSettingsKeys.contains("streamIndex") || force) { swgLocalSinkSettings->setStreamIndex(settings.m_streamIndex); } - - 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 - QNetworkReply *reply = m_networkManager->sendCustomRequest(m_networkRequest, "PATCH", buffer); - buffer->setParent(reply); - - delete swgChannelSettings; } void LocalSink::networkManagerFinished(QNetworkReply *reply) diff --git a/plugins/channelrx/localsink/localsink.h b/plugins/channelrx/localsink/localsink.h index 7da9107c0..d2eca5839 100644 --- a/plugins/channelrx/localsink/localsink.h +++ b/plugins/channelrx/localsink/localsink.h @@ -154,6 +154,13 @@ private: DeviceSampleSource *getLocalDevice(uint32_t index); void webapiReverseSendSettings(QList& channelSettingsKeys, const LocalSinkSettings& settings, bool force); + void featuresSendSettings(QList& channelSettingsKeys, const LocalSinkSettings& settings, bool force); + void webapiFormatChannelSettings( + QList& channelSettingsKeys, + SWGSDRangel::SWGChannelSettings *swgChannelSettings, + const LocalSinkSettings& settings, + bool force + ); private slots: void networkManagerFinished(QNetworkReply *reply); diff --git a/plugins/channelrx/remotesink/remotesink.cpp b/plugins/channelrx/remotesink/remotesink.cpp index 34bdcf5ce..548e0a912 100644 --- a/plugins/channelrx/remotesink/remotesink.cpp +++ b/plugins/channelrx/remotesink/remotesink.cpp @@ -36,6 +36,8 @@ #include "dsp/devicesamplemimo.h" #include "dsp/dspdevicesourceengine.h" #include "device/deviceapi.h" +#include "feature/feature.h" +#include "maincore.h" #include "remotesinkbaseband.h" @@ -236,6 +238,10 @@ void RemoteSink::applySettings(const RemoteSinkSettings& settings, bool force) webapiReverseSendSettings(reverseAPIKeys, settings, fullUpdate || force); } + if (m_featuresSettingsFeedback.size() > 0) { + featuresSendSettings(reverseAPIKeys, settings, force); + } + m_settings = settings; if (frequencyOffsetChange) { @@ -415,10 +421,67 @@ void RemoteSink::webapiFormatChannelSettings(SWGSDRangel::SWGChannelSettings& re void RemoteSink::webapiReverseSendSettings(QList& channelSettingsKeys, const RemoteSinkSettings& settings, bool force) { SWGSDRangel::SWGChannelSettings *swgChannelSettings = new SWGSDRangel::SWGChannelSettings(); - swgChannelSettings->setDirection(0); // single sink (Rx) + webapiFormatChannelSettings(channelSettingsKeys, swgChannelSettings, settings, force); + + 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 + QNetworkReply *reply = m_networkManager->sendCustomRequest(m_networkRequest, "PATCH", buffer); + buffer->setParent(reply); + + delete swgChannelSettings; +} + +void RemoteSink::featuresSendSettings(QList& channelSettingsKeys, const RemoteSinkSettings& settings, bool force) +{ + QList::iterator it = m_featuresSettingsFeedback.begin(); + MainCore *mainCore = MainCore::instance(); + + for (; it != m_featuresSettingsFeedback.end(); ++it) + { + if (mainCore->existsFeature(*it)) + { + SWGSDRangel::SWGChannelSettings *swgChannelSettings = new SWGSDRangel::SWGChannelSettings(); + webapiFormatChannelSettings(channelSettingsKeys, swgChannelSettings, settings, force); + + Feature::MsgChannelSettings *msg = Feature::MsgChannelSettings::create( + this, + channelSettingsKeys, + swgChannelSettings, + force + ); + + (*it)->getInputMessageQueue()->push(msg); + } + else + { + m_featuresSettingsFeedback.removeOne(*it); + } + } +} + +void RemoteSink::webapiFormatChannelSettings( + QList& channelSettingsKeys, + SWGSDRangel::SWGChannelSettings *swgChannelSettings, + const RemoteSinkSettings& settings, + bool force +) +{ + swgChannelSettings->setDirection(0); // Single sink (Rx) swgChannelSettings->setOriginatorChannelIndex(getIndexInDeviceSet()); swgChannelSettings->setOriginatorDeviceSetIndex(getDeviceSetIndex()); - swgChannelSettings->setChannelType(new QString("RemoteSink")); + swgChannelSettings->setChannelType(new QString(m_channelId)); swgChannelSettings->setRemoteSinkSettings(new SWGSDRangel::SWGRemoteSinkSettings()); SWGSDRangel::SWGRemoteSinkSettings *swgRemoteSinkSettings = swgChannelSettings->getRemoteSinkSettings(); @@ -452,25 +515,6 @@ void RemoteSink::webapiReverseSendSettings(QList& channelSettingsKeys, if (channelSettingsKeys.contains("streamIndex") || force) { swgRemoteSinkSettings->setStreamIndex(settings.m_streamIndex); } - - 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 - QNetworkReply *reply = m_networkManager->sendCustomRequest(m_networkRequest, "PATCH", buffer); - buffer->setParent(reply); - - delete swgChannelSettings; } void RemoteSink::networkManagerFinished(QNetworkReply *reply) diff --git a/plugins/channelrx/remotesink/remotesink.h b/plugins/channelrx/remotesink/remotesink.h index 61a02f8b6..424a00860 100644 --- a/plugins/channelrx/remotesink/remotesink.h +++ b/plugins/channelrx/remotesink/remotesink.h @@ -133,6 +133,13 @@ private: static void validateFilterChainHash(RemoteSinkSettings& settings); void calculateFrequencyOffset(); void webapiReverseSendSettings(QList& channelSettingsKeys, const RemoteSinkSettings& settings, bool force); + void featuresSendSettings(QList& channelSettingsKeys, const RemoteSinkSettings& settings, bool force); + void webapiFormatChannelSettings( + QList& channelSettingsKeys, + SWGSDRangel::SWGChannelSettings *swgChannelSettings, + const RemoteSinkSettings& settings, + bool force + ); private slots: void networkManagerFinished(QNetworkReply *reply); diff --git a/plugins/channelrx/udpsink/udpsink.cpp b/plugins/channelrx/udpsink/udpsink.cpp index a596005ea..7a0882f0f 100644 --- a/plugins/channelrx/udpsink/udpsink.cpp +++ b/plugins/channelrx/udpsink/udpsink.cpp @@ -33,6 +33,8 @@ #include "dsp/dspcommands.h" #include "dsp/devicesamplemimo.h" #include "device/deviceapi.h" +#include "feature/feature.h" +#include "maincore.h" #include "udpsink.h" @@ -236,6 +238,10 @@ void UDPSink::applySettings(const UDPSinkSettings& settings, bool force) webapiReverseSendSettings(reverseAPIKeys, settings, fullUpdate || force); } + if (m_featuresSettingsFeedback.size() > 0) { + featuresSendSettings(reverseAPIKeys, settings, force); + } + m_settings = settings; } @@ -448,10 +454,67 @@ void UDPSink::webapiFormatChannelReport(SWGSDRangel::SWGChannelReport& response) void UDPSink::webapiReverseSendSettings(QList& channelSettingsKeys, const UDPSinkSettings& settings, bool force) { SWGSDRangel::SWGChannelSettings *swgChannelSettings = new SWGSDRangel::SWGChannelSettings(); - swgChannelSettings->setDirection(0); // single sink (Rx) + webapiFormatChannelSettings(channelSettingsKeys, swgChannelSettings, settings, force); + + 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 + QNetworkReply *reply = m_networkManager->sendCustomRequest(m_networkRequest, "PATCH", buffer); + buffer->setParent(reply); + + delete swgChannelSettings; +} + +void UDPSink::featuresSendSettings(QList& channelSettingsKeys, const UDPSinkSettings& settings, bool force) +{ + QList::iterator it = m_featuresSettingsFeedback.begin(); + MainCore *mainCore = MainCore::instance(); + + for (; it != m_featuresSettingsFeedback.end(); ++it) + { + if (mainCore->existsFeature(*it)) + { + SWGSDRangel::SWGChannelSettings *swgChannelSettings = new SWGSDRangel::SWGChannelSettings(); + webapiFormatChannelSettings(channelSettingsKeys, swgChannelSettings, settings, force); + + Feature::MsgChannelSettings *msg = Feature::MsgChannelSettings::create( + this, + channelSettingsKeys, + swgChannelSettings, + force + ); + + (*it)->getInputMessageQueue()->push(msg); + } + else + { + m_featuresSettingsFeedback.removeOne(*it); + } + } +} + +void UDPSink::webapiFormatChannelSettings( + QList& channelSettingsKeys, + SWGSDRangel::SWGChannelSettings *swgChannelSettings, + const UDPSinkSettings& settings, + bool force +) +{ + swgChannelSettings->setDirection(0); // Single sink (Rx) swgChannelSettings->setOriginatorChannelIndex(getIndexInDeviceSet()); swgChannelSettings->setOriginatorDeviceSetIndex(getDeviceSetIndex()); - swgChannelSettings->setChannelType(new QString("UDPSink")); + swgChannelSettings->setChannelType(new QString(m_channelId)); swgChannelSettings->setUdpSinkSettings(new SWGSDRangel::SWGUDPSinkSettings()); SWGSDRangel::SWGUDPSinkSettings *swgUDPSinkSettings = swgChannelSettings->getUdpSinkSettings(); @@ -517,25 +580,6 @@ void UDPSink::webapiReverseSendSettings(QList& channelSettingsKeys, con if (channelSettingsKeys.contains("streamIndex") || force) { swgUDPSinkSettings->setStreamIndex(settings.m_streamIndex); } - - 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 - QNetworkReply *reply = m_networkManager->sendCustomRequest(m_networkRequest, "PATCH", buffer); - buffer->setParent(reply); - - delete swgChannelSettings; } void UDPSink::networkManagerFinished(QNetworkReply *reply) @@ -563,4 +607,4 @@ void UDPSink::enableSpectrum(bool enable) { UDPSinkBaseband::MsgEnableSpectrum *msg = UDPSinkBaseband::MsgEnableSpectrum::create(enable); m_basebandSink->getInputMessageQueue()->push(msg); -} \ No newline at end of file +} diff --git a/plugins/channelrx/udpsink/udpsink.h b/plugins/channelrx/udpsink/udpsink.h index b98f16c75..b52472835 100644 --- a/plugins/channelrx/udpsink/udpsink.h +++ b/plugins/channelrx/udpsink/udpsink.h @@ -145,6 +145,13 @@ protected: void webapiFormatChannelReport(SWGSDRangel::SWGChannelReport& response); void webapiReverseSendSettings(QList& channelSettingsKeys, const UDPSinkSettings& settings, bool force); + void featuresSendSettings(QList& channelSettingsKeys, const UDPSinkSettings& settings, bool force); + void webapiFormatChannelSettings( + QList& channelSettingsKeys, + SWGSDRangel::SWGChannelSettings *swgChannelSettings, + const UDPSinkSettings& settings, + bool force + ); }; #endif // INCLUDE_UDPSINK_H diff --git a/plugins/channeltx/filesource/filesource.cpp b/plugins/channeltx/filesource/filesource.cpp index 5e9a3e453..d4f995319 100644 --- a/plugins/channeltx/filesource/filesource.cpp +++ b/plugins/channeltx/filesource/filesource.cpp @@ -33,7 +33,9 @@ #include "dsp/devicesamplesink.h" #include "dsp/hbfilterchainconverter.h" #include "dsp/filerecord.h" +#include "feature/feature.h" #include "util/db.h" +#include "maincore.h" #include "filesourcebaseband.h" @@ -261,6 +263,10 @@ void FileSource::applySettings(const FileSourceSettings& settings, bool force) webapiReverseSendSettings(reverseAPIKeys, settings, fullUpdate || force); } + if (m_featuresSettingsFeedback.size() > 0) { + featuresSendSettings(reverseAPIKeys, settings, force); + } + m_settings = settings; } @@ -498,10 +504,67 @@ void FileSource::webapiFormatChannelReport(SWGSDRangel::SWGChannelReport& respon void FileSource::webapiReverseSendSettings(QList& channelSettingsKeys, const FileSourceSettings& settings, bool force) { SWGSDRangel::SWGChannelSettings *swgChannelSettings = new SWGSDRangel::SWGChannelSettings(); + webapiFormatChannelSettings(channelSettingsKeys, swgChannelSettings, settings, force); + + 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 + QNetworkReply *reply = m_networkManager->sendCustomRequest(m_networkRequest, "PATCH", buffer); + buffer->setParent(reply); + + delete swgChannelSettings; +} + +void FileSource::featuresSendSettings(QList& channelSettingsKeys, const FileSourceSettings& settings, bool force) +{ + QList::iterator it = m_featuresSettingsFeedback.begin(); + MainCore *mainCore = MainCore::instance(); + + for (; it != m_featuresSettingsFeedback.end(); ++it) + { + if (mainCore->existsFeature(*it)) + { + SWGSDRangel::SWGChannelSettings *swgChannelSettings = new SWGSDRangel::SWGChannelSettings(); + webapiFormatChannelSettings(channelSettingsKeys, swgChannelSettings, settings, force); + + Feature::MsgChannelSettings *msg = Feature::MsgChannelSettings::create( + this, + channelSettingsKeys, + swgChannelSettings, + force + ); + + (*it)->getInputMessageQueue()->push(msg); + } + else + { + m_featuresSettingsFeedback.removeOne(*it); + } + } +} + +void FileSource::webapiFormatChannelSettings( + QList& channelSettingsKeys, + SWGSDRangel::SWGChannelSettings *swgChannelSettings, + const FileSourceSettings& settings, + bool force +) +{ swgChannelSettings->setDirection(1); // single source (Tx) swgChannelSettings->setOriginatorChannelIndex(getIndexInDeviceSet()); swgChannelSettings->setOriginatorDeviceSetIndex(getDeviceSetIndex()); - swgChannelSettings->setChannelType(new QString("FileSource")); + swgChannelSettings->setChannelType(new QString(m_channelId)); swgChannelSettings->setFileSourceSettings(new SWGSDRangel::SWGFileSourceSettings()); SWGSDRangel::SWGFileSourceSettings *swgFileSourceSettings = swgChannelSettings->getFileSourceSettings(); @@ -525,25 +588,6 @@ void FileSource::webapiReverseSendSettings(QList& channelSettingsKeys, if (channelSettingsKeys.contains("streamIndex") || force) { swgFileSourceSettings->setStreamIndex(settings.m_streamIndex); } - - 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 - QNetworkReply *reply = m_networkManager->sendCustomRequest(m_networkRequest, "PATCH", buffer); - buffer->setParent(reply); - - delete swgChannelSettings; } void FileSource::networkManagerFinished(QNetworkReply *reply) @@ -585,4 +629,4 @@ double FileSource::getMagSq() const uint32_t FileSource::getNumberOfDeviceStreams() const { return m_deviceAPI->getNbSinkStreams(); -} \ No newline at end of file +} diff --git a/plugins/channeltx/filesource/filesource.h b/plugins/channeltx/filesource/filesource.h index a1ae86a8e..a217ac87d 100644 --- a/plugins/channeltx/filesource/filesource.h +++ b/plugins/channeltx/filesource/filesource.h @@ -254,6 +254,13 @@ private: void calculateFrequencyOffset(); void webapiFormatChannelReport(SWGSDRangel::SWGChannelReport& response); void webapiReverseSendSettings(QList& channelSettingsKeys, const FileSourceSettings& settings, bool force); + void featuresSendSettings(QList& channelSettingsKeys, const FileSourceSettings& settings, bool force); + void webapiFormatChannelSettings( + QList& channelSettingsKeys, + SWGSDRangel::SWGChannelSettings *swgChannelSettings, + const FileSourceSettings& settings, + bool force + ); private slots: void networkManagerFinished(QNetworkReply *reply); diff --git a/plugins/channeltx/localsource/localsource.cpp b/plugins/channeltx/localsource/localsource.cpp index 8ef035656..889c38ce1 100644 --- a/plugins/channeltx/localsource/localsource.cpp +++ b/plugins/channeltx/localsource/localsource.cpp @@ -31,6 +31,8 @@ #include "dsp/devicesamplesink.h" #include "dsp/hbfilterchainconverter.h" #include "device/deviceapi.h" +#include "feature/feature.h" +#include "maincore.h" #include "localsourcebaseband.h" @@ -305,6 +307,10 @@ void LocalSource::applySettings(const LocalSourceSettings& settings, bool force) webapiReverseSendSettings(reverseAPIKeys, settings, fullUpdate || force); } + if (m_featuresSettingsFeedback.size() > 0) { + featuresSendSettings(reverseAPIKeys, settings, force); + } + m_settings = settings; } @@ -438,10 +444,67 @@ void LocalSource::webapiFormatChannelSettings(SWGSDRangel::SWGChannelSettings& r void LocalSource::webapiReverseSendSettings(QList& channelSettingsKeys, const LocalSourceSettings& settings, bool force) { SWGSDRangel::SWGChannelSettings *swgChannelSettings = new SWGSDRangel::SWGChannelSettings(); + webapiFormatChannelSettings(channelSettingsKeys, swgChannelSettings, settings, force); + + 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 + QNetworkReply *reply = m_networkManager->sendCustomRequest(m_networkRequest, "PATCH", buffer); + buffer->setParent(reply); + + delete swgChannelSettings; +} + +void LocalSource::featuresSendSettings(QList& channelSettingsKeys, const LocalSourceSettings& settings, bool force) +{ + QList::iterator it = m_featuresSettingsFeedback.begin(); + MainCore *mainCore = MainCore::instance(); + + for (; it != m_featuresSettingsFeedback.end(); ++it) + { + if (mainCore->existsFeature(*it)) + { + SWGSDRangel::SWGChannelSettings *swgChannelSettings = new SWGSDRangel::SWGChannelSettings(); + webapiFormatChannelSettings(channelSettingsKeys, swgChannelSettings, settings, force); + + Feature::MsgChannelSettings *msg = Feature::MsgChannelSettings::create( + this, + channelSettingsKeys, + swgChannelSettings, + force + ); + + (*it)->getInputMessageQueue()->push(msg); + } + else + { + m_featuresSettingsFeedback.removeOne(*it); + } + } +} + +void LocalSource::webapiFormatChannelSettings( + QList& channelSettingsKeys, + SWGSDRangel::SWGChannelSettings *swgChannelSettings, + const LocalSourceSettings& settings, + bool force +) +{ swgChannelSettings->setDirection(1); // single source (Tx) swgChannelSettings->setOriginatorChannelIndex(getIndexInDeviceSet()); swgChannelSettings->setOriginatorDeviceSetIndex(getDeviceSetIndex()); - swgChannelSettings->setChannelType(new QString("LocalSource")); + swgChannelSettings->setChannelType(new QString(m_channelId)); swgChannelSettings->setLocalSourceSettings(new SWGSDRangel::SWGLocalSourceSettings()); SWGSDRangel::SWGLocalSourceSettings *swgLocalSourceSettings = swgChannelSettings->getLocalSourceSettings(); @@ -468,25 +531,6 @@ void LocalSource::webapiReverseSendSettings(QList& channelSettingsKeys, if (channelSettingsKeys.contains("streamIndex") || force) { swgLocalSourceSettings->setRgbColor(settings.m_streamIndex); } - - 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 - QNetworkReply *reply = m_networkManager->sendCustomRequest(m_networkRequest, "PATCH", buffer); - buffer->setParent(reply); - - delete swgChannelSettings; } void LocalSource::networkManagerFinished(QNetworkReply *reply) diff --git a/plugins/channeltx/localsource/localsource.h b/plugins/channeltx/localsource/localsource.h index 38cafc5e1..d53436c65 100644 --- a/plugins/channeltx/localsource/localsource.h +++ b/plugins/channeltx/localsource/localsource.h @@ -152,6 +152,13 @@ private: DeviceSampleSink *getLocalDevice(uint32_t index); void webapiReverseSendSettings(QList& channelSettingsKeys, const LocalSourceSettings& settings, bool force); + void featuresSendSettings(QList& channelSettingsKeys, const LocalSourceSettings& settings, bool force); + void webapiFormatChannelSettings( + QList& channelSettingsKeys, + SWGSDRangel::SWGChannelSettings *swgChannelSettings, + const LocalSourceSettings& settings, + bool force + ); private slots: void networkManagerFinished(QNetworkReply *reply); diff --git a/plugins/channeltx/mod802.15.4/ieee_802_15_4_mod.cpp b/plugins/channeltx/mod802.15.4/ieee_802_15_4_mod.cpp index 1003fb800..af9dcb8c6 100644 --- a/plugins/channeltx/mod802.15.4/ieee_802_15_4_mod.cpp +++ b/plugins/channeltx/mod802.15.4/ieee_802_15_4_mod.cpp @@ -38,8 +38,10 @@ #include "dsp/dspengine.h" #include "dsp/dspcommands.h" #include "device/deviceapi.h" +#include "feature/feature.h" #include "util/db.h" #include "util/crc.h" +#include "maincore.h" #include "ieee_802_15_4_modbaseband.h" #include "ieee_802_15_4_mod.h" @@ -217,6 +219,10 @@ void IEEE_802_15_4_Mod::applySettings(const IEEE_802_15_4_ModSettings& settings, webapiReverseSendSettings(reverseAPIKeys, settings, fullUpdate || force); } + if (m_featuresSettingsFeedback.size() > 0) { + featuresSendSettings(reverseAPIKeys, settings, force); + } + m_settings = settings; } @@ -423,10 +429,67 @@ void IEEE_802_15_4_Mod::webapiFormatChannelReport(SWGSDRangel::SWGChannelReport& void IEEE_802_15_4_Mod::webapiReverseSendSettings(QList& channelSettingsKeys, const IEEE_802_15_4_ModSettings& settings, bool force) { SWGSDRangel::SWGChannelSettings *swgChannelSettings = new SWGSDRangel::SWGChannelSettings(); + webapiFormatChannelSettings(channelSettingsKeys, swgChannelSettings, settings, force); + + 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 + QNetworkReply *reply = m_networkManager->sendCustomRequest(m_networkRequest, "PATCH", buffer); + buffer->setParent(reply); + + delete swgChannelSettings; +} + +void IEEE_802_15_4_Mod::featuresSendSettings(QList& channelSettingsKeys, const IEEE_802_15_4_ModSettings& settings, bool force) +{ + QList::iterator it = m_featuresSettingsFeedback.begin(); + MainCore *mainCore = MainCore::instance(); + + for (; it != m_featuresSettingsFeedback.end(); ++it) + { + if (mainCore->existsFeature(*it)) + { + SWGSDRangel::SWGChannelSettings *swgChannelSettings = new SWGSDRangel::SWGChannelSettings(); + webapiFormatChannelSettings(channelSettingsKeys, swgChannelSettings, settings, force); + + Feature::MsgChannelSettings *msg = Feature::MsgChannelSettings::create( + this, + channelSettingsKeys, + swgChannelSettings, + force + ); + + (*it)->getInputMessageQueue()->push(msg); + } + else + { + m_featuresSettingsFeedback.removeOne(*it); + } + } +} + +void IEEE_802_15_4_Mod::webapiFormatChannelSettings( + QList& channelSettingsKeys, + SWGSDRangel::SWGChannelSettings *swgChannelSettings, + const IEEE_802_15_4_ModSettings& settings, + bool force +) +{ swgChannelSettings->setDirection(1); // single source (Tx) swgChannelSettings->setOriginatorChannelIndex(getIndexInDeviceSet()); swgChannelSettings->setOriginatorDeviceSetIndex(getDeviceSetIndex()); - swgChannelSettings->setChannelType(new QString("IEEE_802_15_4_Mod")); + swgChannelSettings->setChannelType(new QString(m_channelId)); swgChannelSettings->setIeee802154ModSettings(new SWGSDRangel::SWGIEEE_802_15_4_ModSettings()); SWGSDRangel::SWGIEEE_802_15_4_ModSettings *swgIEEE_802_15_4_ModSettings = swgChannelSettings->getIeee802154ModSettings(); @@ -462,25 +525,6 @@ void IEEE_802_15_4_Mod::webapiReverseSendSettings(QList& channelSetting if (channelSettingsKeys.contains("streamIndex") || force) { swgIEEE_802_15_4_ModSettings->setStreamIndex(settings.m_streamIndex); } - - 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 - QNetworkReply *reply = m_networkManager->sendCustomRequest(m_networkRequest, "PATCH", buffer); - buffer->setParent(reply); - - delete swgChannelSettings; } void IEEE_802_15_4_Mod::networkManagerFinished(QNetworkReply *reply) diff --git a/plugins/channeltx/mod802.15.4/ieee_802_15_4_mod.h b/plugins/channeltx/mod802.15.4/ieee_802_15_4_mod.h index 3e3c82dcc..3937bb79f 100644 --- a/plugins/channeltx/mod802.15.4/ieee_802_15_4_mod.h +++ b/plugins/channeltx/mod802.15.4/ieee_802_15_4_mod.h @@ -168,6 +168,13 @@ private: void applySettings(const IEEE_802_15_4_ModSettings& settings, bool force = false); void webapiFormatChannelReport(SWGSDRangel::SWGChannelReport& response); void webapiReverseSendSettings(QList& channelSettingsKeys, const IEEE_802_15_4_ModSettings& settings, bool force); + void featuresSendSettings(QList& channelSettingsKeys, const IEEE_802_15_4_ModSettings& settings, bool force); + void webapiFormatChannelSettings( + QList& channelSettingsKeys, + SWGSDRangel::SWGChannelSettings *swgChannelSettings, + const IEEE_802_15_4_ModSettings& settings, + bool force + ); private slots: void networkManagerFinished(QNetworkReply *reply); diff --git a/plugins/channeltx/modam/ammod.cpp b/plugins/channeltx/modam/ammod.cpp index 9684a16de..577469b86 100644 --- a/plugins/channeltx/modam/ammod.cpp +++ b/plugins/channeltx/modam/ammod.cpp @@ -35,7 +35,9 @@ #include "dsp/devicesamplemimo.h" #include "dsp/cwkeyer.h" #include "device/deviceapi.h" +#include "feature/feature.h" #include "util/db.h" +#include "maincore.h" #include "ammodbaseband.h" #include "ammod.h" @@ -300,6 +302,10 @@ void AMMod::applySettings(const AMModSettings& settings, bool force) webapiReverseSendSettings(reverseAPIKeys, settings, fullUpdate || force); } + if (m_featuresSettingsFeedback.size() > 0) { + featuresSendSettings(reverseAPIKeys, settings, force); + } + m_settings = settings; } @@ -502,59 +508,7 @@ void AMMod::webapiFormatChannelReport(SWGSDRangel::SWGChannelReport& response) void AMMod::webapiReverseSendSettings(QList& channelSettingsKeys, const AMModSettings& settings, bool force) { SWGSDRangel::SWGChannelSettings *swgChannelSettings = new SWGSDRangel::SWGChannelSettings(); - swgChannelSettings->setDirection(1); // single source (Tx) - swgChannelSettings->setOriginatorChannelIndex(getIndexInDeviceSet()); - swgChannelSettings->setOriginatorDeviceSetIndex(getDeviceSetIndex()); - swgChannelSettings->setChannelType(new QString("AMMod")); - swgChannelSettings->setAmModSettings(new SWGSDRangel::SWGAMModSettings()); - SWGSDRangel::SWGAMModSettings *swgAMModSettings = swgChannelSettings->getAmModSettings(); - - // transfer data that has been modified. When force is on transfer all data except reverse API data - - if (channelSettingsKeys.contains("channelMute") || force) { - swgAMModSettings->setChannelMute(settings.m_channelMute ? 1 : 0); - } - if (channelSettingsKeys.contains("inputFrequencyOffset") || force) { - swgAMModSettings->setInputFrequencyOffset(settings.m_inputFrequencyOffset); - } - if (channelSettingsKeys.contains("modAFInput") || force) { - swgAMModSettings->setModAfInput((int) settings.m_modAFInput); - } - if (channelSettingsKeys.contains("audioDeviceName") || force) { - swgAMModSettings->setAudioDeviceName(new QString(settings.m_audioDeviceName)); - } - if (channelSettingsKeys.contains("playLoop") || force) { - swgAMModSettings->setPlayLoop(settings.m_playLoop ? 1 : 0); - } - if (channelSettingsKeys.contains("rfBandwidth") || force) { - swgAMModSettings->setRfBandwidth(settings.m_rfBandwidth); - } - if (channelSettingsKeys.contains("rgbColor") || force) { - swgAMModSettings->setRgbColor(settings.m_rgbColor); - } - if (channelSettingsKeys.contains("title") || force) { - swgAMModSettings->setTitle(new QString(settings.m_title)); - } - if (channelSettingsKeys.contains("toneFrequency") || force) { - swgAMModSettings->setToneFrequency(settings.m_toneFrequency); - } - if (channelSettingsKeys.contains("volumeFactor") || force) { - swgAMModSettings->setVolumeFactor(settings.m_volumeFactor); - } - if (channelSettingsKeys.contains("modFactor") || force) { - swgAMModSettings->setModFactor(settings.m_modFactor); - } - if (channelSettingsKeys.contains("streamIndex") || force) { - swgAMModSettings->setStreamIndex(settings.m_streamIndex); - } - - if (force) - { - const CWKeyerSettings& cwKeyerSettings = m_basebandSource->getCWKeyer().getSettings(); - swgAMModSettings->setCwKeyer(new SWGSDRangel::SWGCWKeyerSettings()); - SWGSDRangel::SWGCWKeyerSettings *apiCwKeyerSettings = swgAMModSettings->getCwKeyer(); - m_basebandSource->getCWKeyer().webapiFormatChannelSettings(apiCwKeyerSettings, cwKeyerSettings); - } + webapiFormatChannelSettings(channelSettingsKeys, swgChannelSettings, settings, force); QString channelSettingsURL = QString("http://%1:%2/sdrangel/deviceset/%3/channel/%4/settings") .arg(settings.m_reverseAPIAddress) @@ -608,6 +562,96 @@ void AMMod::webapiReverseSendCWSettings(const CWKeyerSettings& cwKeyerSettings) delete swgChannelSettings; } +void AMMod::featuresSendSettings(QList& channelSettingsKeys, const AMModSettings& settings, bool force) +{ + QList::iterator it = m_featuresSettingsFeedback.begin(); + MainCore *mainCore = MainCore::instance(); + + for (; it != m_featuresSettingsFeedback.end(); ++it) + { + if (mainCore->existsFeature(*it)) + { + SWGSDRangel::SWGChannelSettings *swgChannelSettings = new SWGSDRangel::SWGChannelSettings(); + webapiFormatChannelSettings(channelSettingsKeys, swgChannelSettings, settings, force); + + Feature::MsgChannelSettings *msg = Feature::MsgChannelSettings::create( + this, + channelSettingsKeys, + swgChannelSettings, + force + ); + + (*it)->getInputMessageQueue()->push(msg); + } + else + { + m_featuresSettingsFeedback.removeOne(*it); + } + } +} + +void AMMod::webapiFormatChannelSettings( + QList& channelSettingsKeys, + SWGSDRangel::SWGChannelSettings *swgChannelSettings, + const AMModSettings& settings, + bool force +) +{ + swgChannelSettings->setDirection(1); // single source (Tx) + swgChannelSettings->setOriginatorChannelIndex(getIndexInDeviceSet()); + swgChannelSettings->setOriginatorDeviceSetIndex(getDeviceSetIndex()); + swgChannelSettings->setChannelType(new QString(m_channelId)); + swgChannelSettings->setAmModSettings(new SWGSDRangel::SWGAMModSettings()); + SWGSDRangel::SWGAMModSettings *swgAMModSettings = swgChannelSettings->getAmModSettings(); + + // transfer data that has been modified. When force is on transfer all data except reverse API data + + if (channelSettingsKeys.contains("channelMute") || force) { + swgAMModSettings->setChannelMute(settings.m_channelMute ? 1 : 0); + } + if (channelSettingsKeys.contains("inputFrequencyOffset") || force) { + swgAMModSettings->setInputFrequencyOffset(settings.m_inputFrequencyOffset); + } + if (channelSettingsKeys.contains("modAFInput") || force) { + swgAMModSettings->setModAfInput((int) settings.m_modAFInput); + } + if (channelSettingsKeys.contains("audioDeviceName") || force) { + swgAMModSettings->setAudioDeviceName(new QString(settings.m_audioDeviceName)); + } + if (channelSettingsKeys.contains("playLoop") || force) { + swgAMModSettings->setPlayLoop(settings.m_playLoop ? 1 : 0); + } + if (channelSettingsKeys.contains("rfBandwidth") || force) { + swgAMModSettings->setRfBandwidth(settings.m_rfBandwidth); + } + if (channelSettingsKeys.contains("rgbColor") || force) { + swgAMModSettings->setRgbColor(settings.m_rgbColor); + } + if (channelSettingsKeys.contains("title") || force) { + swgAMModSettings->setTitle(new QString(settings.m_title)); + } + if (channelSettingsKeys.contains("toneFrequency") || force) { + swgAMModSettings->setToneFrequency(settings.m_toneFrequency); + } + if (channelSettingsKeys.contains("volumeFactor") || force) { + swgAMModSettings->setVolumeFactor(settings.m_volumeFactor); + } + if (channelSettingsKeys.contains("modFactor") || force) { + swgAMModSettings->setModFactor(settings.m_modFactor); + } + if (channelSettingsKeys.contains("streamIndex") || force) { + swgAMModSettings->setStreamIndex(settings.m_streamIndex); + } + + if (force) + { + const CWKeyerSettings& cwKeyerSettings = m_basebandSource->getCWKeyer().getSettings(); + swgAMModSettings->setCwKeyer(new SWGSDRangel::SWGCWKeyerSettings()); + SWGSDRangel::SWGCWKeyerSettings *apiCwKeyerSettings = swgAMModSettings->getCwKeyer(); + m_basebandSource->getCWKeyer().webapiFormatChannelSettings(apiCwKeyerSettings, cwKeyerSettings); + } +} + void AMMod::networkManagerFinished(QNetworkReply *reply) { QNetworkReply::NetworkError replyError = reply->error(); diff --git a/plugins/channeltx/modam/ammod.h b/plugins/channeltx/modam/ammod.h index edf4558a5..25a4c019e 100644 --- a/plugins/channeltx/modam/ammod.h +++ b/plugins/channeltx/modam/ammod.h @@ -261,6 +261,13 @@ private: void webapiFormatChannelReport(SWGSDRangel::SWGChannelReport& response); void webapiReverseSendSettings(QList& channelSettingsKeys, const AMModSettings& settings, bool force); void webapiReverseSendCWSettings(const CWKeyerSettings& settings); + void featuresSendSettings(QList& channelSettingsKeys, const AMModSettings& settings, bool force); + void webapiFormatChannelSettings( + QList& channelSettingsKeys, + SWGSDRangel::SWGChannelSettings *swgChannelSettings, + const AMModSettings& settings, + bool force + ); private slots: void networkManagerFinished(QNetworkReply *reply); diff --git a/plugins/channeltx/modatv/atvmod.cpp b/plugins/channeltx/modatv/atvmod.cpp index 467843cd9..fdf157bbf 100644 --- a/plugins/channeltx/modatv/atvmod.cpp +++ b/plugins/channeltx/modatv/atvmod.cpp @@ -34,7 +34,9 @@ #include "dsp/dspcommands.h" #include "dsp/devicesamplemimo.h" #include "device/deviceapi.h" +#include "feature/feature.h" #include "util/db.h" +#include "maincore.h" #include "atvmodbaseband.h" #include "atvmod.h" @@ -320,6 +322,10 @@ void ATVMod::applySettings(const ATVModSettings& settings, bool force) webapiReverseSendSettings(reverseAPIKeys, settings, fullUpdate || force); } + if (m_featuresSettingsFeedback.size() > 0) { + featuresSendSettings(reverseAPIKeys, settings, force); + } + m_settings = settings; } @@ -583,10 +589,67 @@ void ATVMod::webapiFormatChannelReport(SWGSDRangel::SWGChannelReport& response) void ATVMod::webapiReverseSendSettings(QList& channelSettingsKeys, const ATVModSettings& settings, bool force) { SWGSDRangel::SWGChannelSettings *swgChannelSettings = new SWGSDRangel::SWGChannelSettings(); + webapiFormatChannelSettings(channelSettingsKeys, swgChannelSettings, settings, force); + + 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 + QNetworkReply *reply = m_networkManager->sendCustomRequest(m_networkRequest, "PATCH", buffer); + buffer->setParent(reply); + + delete swgChannelSettings; +} + +void ATVMod::featuresSendSettings(QList& channelSettingsKeys, const ATVModSettings& settings, bool force) +{ + QList::iterator it = m_featuresSettingsFeedback.begin(); + MainCore *mainCore = MainCore::instance(); + + for (; it != m_featuresSettingsFeedback.end(); ++it) + { + if (mainCore->existsFeature(*it)) + { + SWGSDRangel::SWGChannelSettings *swgChannelSettings = new SWGSDRangel::SWGChannelSettings(); + webapiFormatChannelSettings(channelSettingsKeys, swgChannelSettings, settings, force); + + Feature::MsgChannelSettings *msg = Feature::MsgChannelSettings::create( + this, + channelSettingsKeys, + swgChannelSettings, + force + ); + + (*it)->getInputMessageQueue()->push(msg); + } + else + { + m_featuresSettingsFeedback.removeOne(*it); + } + } +} + +void ATVMod::webapiFormatChannelSettings( + QList& channelSettingsKeys, + SWGSDRangel::SWGChannelSettings *swgChannelSettings, + const ATVModSettings& settings, + bool force +) +{ swgChannelSettings->setDirection(1); // single source (Tx) swgChannelSettings->setOriginatorChannelIndex(getIndexInDeviceSet()); swgChannelSettings->setOriginatorDeviceSetIndex(getDeviceSetIndex()); - swgChannelSettings->setChannelType(new QString("ATVMod")); + swgChannelSettings->setChannelType(new QString(m_channelId)); swgChannelSettings->setAtvModSettings(new SWGSDRangel::SWGATVModSettings()); SWGSDRangel::SWGATVModSettings *swgATVModSettings = swgChannelSettings->getAtvModSettings(); @@ -658,25 +721,6 @@ void ATVMod::webapiReverseSendSettings(QList& channelSettingsKeys, cons if (channelSettingsKeys.contains("streamIndex") || force) { swgATVModSettings->setStreamIndex(settings.m_streamIndex); } - - 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 - QNetworkReply *reply = m_networkManager->sendCustomRequest(m_networkRequest, "PATCH", buffer); - buffer->setParent(reply); - - delete swgChannelSettings; } void ATVMod::networkManagerFinished(QNetworkReply *reply) @@ -723,4 +767,4 @@ void ATVMod::getCameraNumbers(std::vector& numbers) void ATVMod::propagateMessageQueueToGUI() { m_basebandSource->setMessageQueueToGUI(getMessageQueueToGUI()); -} \ No newline at end of file +} diff --git a/plugins/channeltx/modatv/atvmod.h b/plugins/channeltx/modatv/atvmod.h index 5556dde4a..a6caa8136 100644 --- a/plugins/channeltx/modatv/atvmod.h +++ b/plugins/channeltx/modatv/atvmod.h @@ -317,6 +317,13 @@ private: void applySettings(const ATVModSettings& settings, bool force = false); void webapiFormatChannelReport(SWGSDRangel::SWGChannelReport& response); void webapiReverseSendSettings(QList& channelSettingsKeys, const ATVModSettings& settings, bool force); + void featuresSendSettings(QList& channelSettingsKeys, const ATVModSettings& settings, bool force); + void webapiFormatChannelSettings( + QList& channelSettingsKeys, + SWGSDRangel::SWGChannelSettings *swgChannelSettings, + const ATVModSettings& settings, + bool force + ); private slots: void networkManagerFinished(QNetworkReply *reply); diff --git a/plugins/channeltx/modfreedv/freedvmod.cpp b/plugins/channeltx/modfreedv/freedvmod.cpp index 06f3c4944..98fe967a7 100644 --- a/plugins/channeltx/modfreedv/freedvmod.cpp +++ b/plugins/channeltx/modfreedv/freedvmod.cpp @@ -34,7 +34,9 @@ #include "dsp/dspengine.h" #include "dsp/dspcommands.h" #include "device/deviceapi.h" +#include "feature/feature.h" #include "util/db.h" +#include "maincore.h" #include "freedvmodbaseband.h" #include "freedvmod.h" @@ -288,6 +290,10 @@ void FreeDVMod::applySettings(const FreeDVModSettings& settings, bool force) webapiReverseSendSettings(reverseAPIKeys, settings, fullUpdate || force); } + if (m_featuresSettingsFeedback.size() > 0) { + featuresSendSettings(reverseAPIKeys, settings, force); + } + m_settings = settings; } @@ -494,10 +500,99 @@ void FreeDVMod::webapiFormatChannelReport(SWGSDRangel::SWGChannelReport& respons void FreeDVMod::webapiReverseSendSettings(QList& channelSettingsKeys, const FreeDVModSettings& settings, bool force) { SWGSDRangel::SWGChannelSettings *swgChannelSettings = new SWGSDRangel::SWGChannelSettings(); + webapiFormatChannelSettings(channelSettingsKeys, swgChannelSettings, settings, force); + + 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 + QNetworkReply *reply = m_networkManager->sendCustomRequest(m_networkRequest, "PATCH", buffer); + buffer->setParent(reply); + + delete swgChannelSettings; +} + +void FreeDVMod::webapiReverseSendCWSettings(const CWKeyerSettings& cwKeyerSettings) +{ + SWGSDRangel::SWGChannelSettings *swgChannelSettings = new SWGSDRangel::SWGChannelSettings(); + swgChannelSettings->setDirection(1); // single source (Tx) + swgChannelSettings->setChannelType(new QString("FreeDVMod")); + swgChannelSettings->setFreeDvModSettings(new SWGSDRangel::SWGFreeDVModSettings()); + SWGSDRangel::SWGFreeDVModSettings *swgFreeDVModSettings = swgChannelSettings->getFreeDvModSettings(); + + swgFreeDVModSettings->setCwKeyer(new SWGSDRangel::SWGCWKeyerSettings()); + SWGSDRangel::SWGCWKeyerSettings *apiCwKeyerSettings = swgFreeDVModSettings->getCwKeyer(); + m_basebandSource->getCWKeyer().webapiFormatChannelSettings(apiCwKeyerSettings, cwKeyerSettings); + + QString channelSettingsURL = QString("http://%1:%2/sdrangel/deviceset/%3/channel/%4/settings") + .arg(m_settings.m_reverseAPIAddress) + .arg(m_settings.m_reverseAPIPort) + .arg(m_settings.m_reverseAPIDeviceIndex) + .arg(m_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 + QNetworkReply *reply = m_networkManager->sendCustomRequest(m_networkRequest, "PATCH", buffer); + buffer->setParent(reply); + + delete swgChannelSettings; +} + +void FreeDVMod::featuresSendSettings(QList& channelSettingsKeys, const FreeDVModSettings& settings, bool force) +{ + QList::iterator it = m_featuresSettingsFeedback.begin(); + MainCore *mainCore = MainCore::instance(); + + for (; it != m_featuresSettingsFeedback.end(); ++it) + { + if (mainCore->existsFeature(*it)) + { + SWGSDRangel::SWGChannelSettings *swgChannelSettings = new SWGSDRangel::SWGChannelSettings(); + webapiFormatChannelSettings(channelSettingsKeys, swgChannelSettings, settings, force); + + Feature::MsgChannelSettings *msg = Feature::MsgChannelSettings::create( + this, + channelSettingsKeys, + swgChannelSettings, + force + ); + + (*it)->getInputMessageQueue()->push(msg); + } + else + { + m_featuresSettingsFeedback.removeOne(*it); + } + } +} + +void FreeDVMod::webapiFormatChannelSettings( + QList& channelSettingsKeys, + SWGSDRangel::SWGChannelSettings *swgChannelSettings, + const FreeDVModSettings& settings, + bool force +) +{ swgChannelSettings->setDirection(1); // single source (Tx) swgChannelSettings->setOriginatorChannelIndex(getIndexInDeviceSet()); swgChannelSettings->setOriginatorDeviceSetIndex(getDeviceSetIndex()); - swgChannelSettings->setChannelType(new QString("FreeDVMod")); + swgChannelSettings->setChannelType(new QString(m_channelId)); swgChannelSettings->setFreeDvModSettings(new SWGSDRangel::SWGFreeDVModSettings()); SWGSDRangel::SWGFreeDVModSettings *swgFreeDVModSettings = swgChannelSettings->getFreeDvModSettings(); @@ -550,57 +645,6 @@ void FreeDVMod::webapiReverseSendSettings(QList& channelSettingsKeys, c SWGSDRangel::SWGCWKeyerSettings *apiCwKeyerSettings = swgFreeDVModSettings->getCwKeyer(); m_basebandSource->getCWKeyer().webapiFormatChannelSettings(apiCwKeyerSettings, cwKeyerSettings); } - - 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 - QNetworkReply *reply = m_networkManager->sendCustomRequest(m_networkRequest, "PATCH", buffer); - buffer->setParent(reply); - - delete swgChannelSettings; -} - -void FreeDVMod::webapiReverseSendCWSettings(const CWKeyerSettings& cwKeyerSettings) -{ - SWGSDRangel::SWGChannelSettings *swgChannelSettings = new SWGSDRangel::SWGChannelSettings(); - swgChannelSettings->setDirection(1); // single source (Tx) - swgChannelSettings->setChannelType(new QString("FreeDVMod")); - swgChannelSettings->setFreeDvModSettings(new SWGSDRangel::SWGFreeDVModSettings()); - SWGSDRangel::SWGFreeDVModSettings *swgFreeDVModSettings = swgChannelSettings->getFreeDvModSettings(); - - swgFreeDVModSettings->setCwKeyer(new SWGSDRangel::SWGCWKeyerSettings()); - SWGSDRangel::SWGCWKeyerSettings *apiCwKeyerSettings = swgFreeDVModSettings->getCwKeyer(); - m_basebandSource->getCWKeyer().webapiFormatChannelSettings(apiCwKeyerSettings, cwKeyerSettings); - - QString channelSettingsURL = QString("http://%1:%2/sdrangel/deviceset/%3/channel/%4/settings") - .arg(m_settings.m_reverseAPIAddress) - .arg(m_settings.m_reverseAPIPort) - .arg(m_settings.m_reverseAPIDeviceIndex) - .arg(m_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 - QNetworkReply *reply = m_networkManager->sendCustomRequest(m_networkRequest, "PATCH", buffer); - buffer->setParent(reply); - - delete swgChannelSettings; } void FreeDVMod::networkManagerFinished(QNetworkReply *reply) @@ -662,4 +706,4 @@ void FreeDVMod::setLevelMeter(QObject *levelMeter) uint32_t FreeDVMod::getNumberOfDeviceStreams() const { return m_deviceAPI->getNbSinkStreams(); -} \ No newline at end of file +} diff --git a/plugins/channeltx/modfreedv/freedvmod.h b/plugins/channeltx/modfreedv/freedvmod.h index f1601b872..758547d6e 100644 --- a/plugins/channeltx/modfreedv/freedvmod.h +++ b/plugins/channeltx/modfreedv/freedvmod.h @@ -269,6 +269,13 @@ private: void webapiFormatChannelReport(SWGSDRangel::SWGChannelReport& response); void webapiReverseSendSettings(QList& channelSettingsKeys, const FreeDVModSettings& settings, bool force); void webapiReverseSendCWSettings(const CWKeyerSettings& settings); + void featuresSendSettings(QList& channelSettingsKeys, const FreeDVModSettings& settings, bool force); + void webapiFormatChannelSettings( + QList& channelSettingsKeys, + SWGSDRangel::SWGChannelSettings *swgChannelSettings, + const FreeDVModSettings& settings, + bool force + ); private slots: void networkManagerFinished(QNetworkReply *reply); diff --git a/plugins/channeltx/modnfm/nfmmod.cpp b/plugins/channeltx/modnfm/nfmmod.cpp index 2047fd222..5227ccf98 100644 --- a/plugins/channeltx/modnfm/nfmmod.cpp +++ b/plugins/channeltx/modnfm/nfmmod.cpp @@ -36,7 +36,9 @@ #include "dsp/dspcommands.h" #include "dsp/cwkeyer.h" #include "device/deviceapi.h" +#include "feature/feature.h" #include "util/db.h" +#include "maincore.h" #include "nfmmodbaseband.h" #include "nfmmod.h" @@ -346,6 +348,10 @@ void NFMMod::applySettings(const NFMModSettings& settings, bool force) webapiReverseSendSettings(reverseAPIKeys, settings, fullUpdate || force); } + if (m_featuresSettingsFeedback.size() > 0) { + featuresSendSettings(reverseAPIKeys, settings, force); + } + m_settings = settings; } @@ -556,10 +562,99 @@ void NFMMod::webapiFormatChannelReport(SWGSDRangel::SWGChannelReport& response) void NFMMod::webapiReverseSendSettings(QList& channelSettingsKeys, const NFMModSettings& settings, bool force) { SWGSDRangel::SWGChannelSettings *swgChannelSettings = new SWGSDRangel::SWGChannelSettings(); + webapiFormatChannelSettings(channelSettingsKeys, swgChannelSettings, settings, force); + + 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 + QNetworkReply *reply = m_networkManager->sendCustomRequest(m_networkRequest, "PATCH", buffer); + buffer->setParent(reply); + + delete swgChannelSettings; +} + +void NFMMod::webapiReverseSendCWSettings(const CWKeyerSettings& cwKeyerSettings) +{ + SWGSDRangel::SWGChannelSettings *swgChannelSettings = new SWGSDRangel::SWGChannelSettings(); + swgChannelSettings->setDirection(1); // single source (Tx) + swgChannelSettings->setChannelType(new QString("NFMMod")); + swgChannelSettings->setNfmModSettings(new SWGSDRangel::SWGNFMModSettings()); + SWGSDRangel::SWGNFMModSettings *swgNFModSettings = swgChannelSettings->getNfmModSettings(); + + swgNFModSettings->setCwKeyer(new SWGSDRangel::SWGCWKeyerSettings()); + SWGSDRangel::SWGCWKeyerSettings *apiCwKeyerSettings = swgNFModSettings->getCwKeyer(); + m_basebandSource->getCWKeyer().webapiFormatChannelSettings(apiCwKeyerSettings, cwKeyerSettings); + + QString channelSettingsURL = QString("http://%1:%2/sdrangel/deviceset/%3/channel/%4/settings") + .arg(m_settings.m_reverseAPIAddress) + .arg(m_settings.m_reverseAPIPort) + .arg(m_settings.m_reverseAPIDeviceIndex) + .arg(m_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 + QNetworkReply *reply = m_networkManager->sendCustomRequest(m_networkRequest, "PATCH", buffer); + buffer->setParent(reply); + + delete swgChannelSettings; +} + +void NFMMod::featuresSendSettings(QList& channelSettingsKeys, const NFMModSettings& settings, bool force) +{ + QList::iterator it = m_featuresSettingsFeedback.begin(); + MainCore *mainCore = MainCore::instance(); + + for (; it != m_featuresSettingsFeedback.end(); ++it) + { + if (mainCore->existsFeature(*it)) + { + SWGSDRangel::SWGChannelSettings *swgChannelSettings = new SWGSDRangel::SWGChannelSettings(); + webapiFormatChannelSettings(channelSettingsKeys, swgChannelSettings, settings, force); + + Feature::MsgChannelSettings *msg = Feature::MsgChannelSettings::create( + this, + channelSettingsKeys, + swgChannelSettings, + force + ); + + (*it)->getInputMessageQueue()->push(msg); + } + else + { + m_featuresSettingsFeedback.removeOne(*it); + } + } +} + +void NFMMod::webapiFormatChannelSettings( + QList& channelSettingsKeys, + SWGSDRangel::SWGChannelSettings *swgChannelSettings, + const NFMModSettings& settings, + bool force +) +{ swgChannelSettings->setDirection(1); // single source (Tx) swgChannelSettings->setOriginatorChannelIndex(getIndexInDeviceSet()); swgChannelSettings->setOriginatorDeviceSetIndex(getDeviceSetIndex()); - swgChannelSettings->setChannelType(new QString("NFMMod")); + swgChannelSettings->setChannelType(new QString(m_channelId)); swgChannelSettings->setNfmModSettings(new SWGSDRangel::SWGNFMModSettings()); SWGSDRangel::SWGNFMModSettings *swgNFMModSettings = swgChannelSettings->getNfmModSettings(); @@ -618,57 +713,6 @@ void NFMMod::webapiReverseSendSettings(QList& channelSettingsKeys, cons SWGSDRangel::SWGCWKeyerSettings *apiCwKeyerSettings = swgNFMModSettings->getCwKeyer(); m_basebandSource->getCWKeyer().webapiFormatChannelSettings(apiCwKeyerSettings, cwKeyerSettings); } - - 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 - QNetworkReply *reply = m_networkManager->sendCustomRequest(m_networkRequest, "PATCH", buffer); - buffer->setParent(reply); - - delete swgChannelSettings; -} - -void NFMMod::webapiReverseSendCWSettings(const CWKeyerSettings& cwKeyerSettings) -{ - SWGSDRangel::SWGChannelSettings *swgChannelSettings = new SWGSDRangel::SWGChannelSettings(); - swgChannelSettings->setDirection(1); // single source (Tx) - swgChannelSettings->setChannelType(new QString("NFMMod")); - swgChannelSettings->setNfmModSettings(new SWGSDRangel::SWGNFMModSettings()); - SWGSDRangel::SWGNFMModSettings *swgNFModSettings = swgChannelSettings->getNfmModSettings(); - - swgNFModSettings->setCwKeyer(new SWGSDRangel::SWGCWKeyerSettings()); - SWGSDRangel::SWGCWKeyerSettings *apiCwKeyerSettings = swgNFModSettings->getCwKeyer(); - m_basebandSource->getCWKeyer().webapiFormatChannelSettings(apiCwKeyerSettings, cwKeyerSettings); - - QString channelSettingsURL = QString("http://%1:%2/sdrangel/deviceset/%3/channel/%4/settings") - .arg(m_settings.m_reverseAPIAddress) - .arg(m_settings.m_reverseAPIPort) - .arg(m_settings.m_reverseAPIDeviceIndex) - .arg(m_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 - QNetworkReply *reply = m_networkManager->sendCustomRequest(m_networkRequest, "PATCH", buffer); - buffer->setParent(reply); - - delete swgChannelSettings; } void NFMMod::networkManagerFinished(QNetworkReply *reply) diff --git a/plugins/channeltx/modnfm/nfmmod.h b/plugins/channeltx/modnfm/nfmmod.h index 875af3328..ff3abb104 100644 --- a/plugins/channeltx/modnfm/nfmmod.h +++ b/plugins/channeltx/modnfm/nfmmod.h @@ -261,6 +261,13 @@ private: void webapiFormatChannelReport(SWGSDRangel::SWGChannelReport& response); void webapiReverseSendSettings(QList& channelSettingsKeys, const NFMModSettings& settings, bool force); void webapiReverseSendCWSettings(const CWKeyerSettings& settings); + void featuresSendSettings(QList& channelSettingsKeys, const NFMModSettings& settings, bool force); + void webapiFormatChannelSettings( + QList& channelSettingsKeys, + SWGSDRangel::SWGChannelSettings *swgChannelSettings, + const NFMModSettings& settings, + bool force + ); private slots: void networkManagerFinished(QNetworkReply *reply); diff --git a/plugins/channeltx/modpacket/packetmod.cpp b/plugins/channeltx/modpacket/packetmod.cpp index 141c1214e..4a14c0d10 100644 --- a/plugins/channeltx/modpacket/packetmod.cpp +++ b/plugins/channeltx/modpacket/packetmod.cpp @@ -38,8 +38,10 @@ #include "dsp/dspengine.h" #include "dsp/dspcommands.h" #include "device/deviceapi.h" +#include "feature/feature.h" #include "util/db.h" #include "util/crc.h" +#include "maincore.h" #include "packetmodbaseband.h" #include "packetmod.h" @@ -344,6 +346,10 @@ void PacketMod::applySettings(const PacketModSettings& settings, bool force) webapiReverseSendSettings(reverseAPIKeys, settings, fullUpdate || force); } + if (m_featuresSettingsFeedback.size() > 0) { + featuresSendSettings(reverseAPIKeys, settings, force); + } + m_settings = settings; } @@ -703,10 +709,67 @@ void PacketMod::webapiFormatChannelReport(SWGSDRangel::SWGChannelReport& respons void PacketMod::webapiReverseSendSettings(QList& channelSettingsKeys, const PacketModSettings& settings, bool force) { SWGSDRangel::SWGChannelSettings *swgChannelSettings = new SWGSDRangel::SWGChannelSettings(); + webapiFormatChannelSettings(channelSettingsKeys, swgChannelSettings, settings, force); + + 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 + QNetworkReply *reply = m_networkManager->sendCustomRequest(m_networkRequest, "PATCH", buffer); + buffer->setParent(reply); + + delete swgChannelSettings; +} + +void PacketMod::featuresSendSettings(QList& channelSettingsKeys, const PacketModSettings& settings, bool force) +{ + QList::iterator it = m_featuresSettingsFeedback.begin(); + MainCore *mainCore = MainCore::instance(); + + for (; it != m_featuresSettingsFeedback.end(); ++it) + { + if (mainCore->existsFeature(*it)) + { + SWGSDRangel::SWGChannelSettings *swgChannelSettings = new SWGSDRangel::SWGChannelSettings(); + webapiFormatChannelSettings(channelSettingsKeys, swgChannelSettings, settings, force); + + Feature::MsgChannelSettings *msg = Feature::MsgChannelSettings::create( + this, + channelSettingsKeys, + swgChannelSettings, + force + ); + + (*it)->getInputMessageQueue()->push(msg); + } + else + { + m_featuresSettingsFeedback.removeOne(*it); + } + } +} + +void PacketMod::webapiFormatChannelSettings( + QList& channelSettingsKeys, + SWGSDRangel::SWGChannelSettings *swgChannelSettings, + const PacketModSettings& settings, + bool force +) +{ swgChannelSettings->setDirection(1); // single source (Tx) swgChannelSettings->setOriginatorChannelIndex(getIndexInDeviceSet()); swgChannelSettings->setOriginatorDeviceSetIndex(getDeviceSetIndex()); - swgChannelSettings->setChannelType(new QString("PacketMod")); + swgChannelSettings->setChannelType(new QString(m_channelId)); swgChannelSettings->setPacketModSettings(new SWGSDRangel::SWGPacketModSettings()); SWGSDRangel::SWGPacketModSettings *swgPacketModSettings = swgChannelSettings->getPacketModSettings(); @@ -835,25 +898,6 @@ void PacketMod::webapiReverseSendSettings(QList& channelSettingsKeys, c if (channelSettingsKeys.contains("streamIndex") || force) { swgPacketModSettings->setStreamIndex(settings.m_streamIndex); } - - 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 - QNetworkReply *reply = m_networkManager->sendCustomRequest(m_networkRequest, "PATCH", buffer); - buffer->setParent(reply); - - delete swgChannelSettings; } void PacketMod::networkManagerFinished(QNetworkReply *reply) diff --git a/plugins/channeltx/modpacket/packetmod.h b/plugins/channeltx/modpacket/packetmod.h index 972b080f1..c28276a25 100644 --- a/plugins/channeltx/modpacket/packetmod.h +++ b/plugins/channeltx/modpacket/packetmod.h @@ -179,6 +179,13 @@ private: void applySettings(const PacketModSettings& settings, bool force = false); void webapiFormatChannelReport(SWGSDRangel::SWGChannelReport& response); void webapiReverseSendSettings(QList& channelSettingsKeys, const PacketModSettings& settings, bool force); + void featuresSendSettings(QList& channelSettingsKeys, const PacketModSettings& settings, bool force); + void webapiFormatChannelSettings( + QList& channelSettingsKeys, + SWGSDRangel::SWGChannelSettings *swgChannelSettings, + const PacketModSettings& settings, + bool force + ); private slots: void networkManagerFinished(QNetworkReply *reply); diff --git a/plugins/channeltx/modssb/ssbmod.cpp b/plugins/channeltx/modssb/ssbmod.cpp index 8bdcc32a0..898570dc1 100644 --- a/plugins/channeltx/modssb/ssbmod.cpp +++ b/plugins/channeltx/modssb/ssbmod.cpp @@ -35,7 +35,9 @@ #include "dsp/dspcommands.h" #include "dsp/cwkeyer.h" #include "device/deviceapi.h" +#include "feature/feature.h" #include "util/db.h" +#include "maincore.h" #include "ssbmodbaseband.h" #include "ssbmod.h" @@ -305,6 +307,10 @@ void SSBMod::applySettings(const SSBModSettings& settings, bool force) webapiReverseSendSettings(reverseAPIKeys, settings, fullUpdate || force); } + if (m_featuresSettingsFeedback.size() > 0) { + featuresSendSettings(reverseAPIKeys, settings, force); + } + m_settings = settings; m_settings.m_bandwidth = band; m_settings.m_lowCutoff = lowCutoff; @@ -534,10 +540,99 @@ void SSBMod::webapiFormatChannelReport(SWGSDRangel::SWGChannelReport& response) void SSBMod::webapiReverseSendSettings(QList& channelSettingsKeys, const SSBModSettings& settings, bool force) { SWGSDRangel::SWGChannelSettings *swgChannelSettings = new SWGSDRangel::SWGChannelSettings(); + webapiFormatChannelSettings(channelSettingsKeys, swgChannelSettings, settings, force); + + 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 + QNetworkReply *reply = m_networkManager->sendCustomRequest(m_networkRequest, "PATCH", buffer); + buffer->setParent(reply); + + delete swgChannelSettings; +} + +void SSBMod::webapiReverseSendCWSettings(const CWKeyerSettings& cwKeyerSettings) +{ + SWGSDRangel::SWGChannelSettings *swgChannelSettings = new SWGSDRangel::SWGChannelSettings(); + swgChannelSettings->setDirection(1); // single source (Tx) + swgChannelSettings->setChannelType(new QString("SSBMod")); + swgChannelSettings->setSsbModSettings(new SWGSDRangel::SWGSSBModSettings()); + SWGSDRangel::SWGSSBModSettings *swgSSBModSettings = swgChannelSettings->getSsbModSettings(); + + swgSSBModSettings->setCwKeyer(new SWGSDRangel::SWGCWKeyerSettings()); + SWGSDRangel::SWGCWKeyerSettings *apiCwKeyerSettings = swgSSBModSettings->getCwKeyer(); + m_basebandSource->getCWKeyer().webapiFormatChannelSettings(apiCwKeyerSettings, cwKeyerSettings); + + QString channelSettingsURL = QString("http://%1:%2/sdrangel/deviceset/%3/channel/%4/settings") + .arg(m_settings.m_reverseAPIAddress) + .arg(m_settings.m_reverseAPIPort) + .arg(m_settings.m_reverseAPIDeviceIndex) + .arg(m_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 + QNetworkReply *reply = m_networkManager->sendCustomRequest(m_networkRequest, "PATCH", buffer); + buffer->setParent(reply); + + delete swgChannelSettings; +} + +void SSBMod::featuresSendSettings(QList& channelSettingsKeys, const SSBModSettings& settings, bool force) +{ + QList::iterator it = m_featuresSettingsFeedback.begin(); + MainCore *mainCore = MainCore::instance(); + + for (; it != m_featuresSettingsFeedback.end(); ++it) + { + if (mainCore->existsFeature(*it)) + { + SWGSDRangel::SWGChannelSettings *swgChannelSettings = new SWGSDRangel::SWGChannelSettings(); + webapiFormatChannelSettings(channelSettingsKeys, swgChannelSettings, settings, force); + + Feature::MsgChannelSettings *msg = Feature::MsgChannelSettings::create( + this, + channelSettingsKeys, + swgChannelSettings, + force + ); + + (*it)->getInputMessageQueue()->push(msg); + } + else + { + m_featuresSettingsFeedback.removeOne(*it); + } + } +} + +void SSBMod::webapiFormatChannelSettings( + QList& channelSettingsKeys, + SWGSDRangel::SWGChannelSettings *swgChannelSettings, + const SSBModSettings& settings, + bool force +) +{ swgChannelSettings->setDirection(1); // single source (Tx) swgChannelSettings->setOriginatorChannelIndex(getIndexInDeviceSet()); swgChannelSettings->setOriginatorDeviceSetIndex(getDeviceSetIndex()); - swgChannelSettings->setChannelType(new QString("SSBMod")); + swgChannelSettings->setChannelType(new QString(m_channelId)); swgChannelSettings->setSsbModSettings(new SWGSDRangel::SWGSSBModSettings()); SWGSDRangel::SWGSSBModSettings *swgSSBModSettings = swgChannelSettings->getSsbModSettings(); @@ -605,57 +700,6 @@ void SSBMod::webapiReverseSendSettings(QList& channelSettingsKeys, cons SWGSDRangel::SWGCWKeyerSettings *apiCwKeyerSettings = swgSSBModSettings->getCwKeyer(); m_basebandSource->getCWKeyer().webapiFormatChannelSettings(apiCwKeyerSettings, cwKeyerSettings); } - - 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 - QNetworkReply *reply = m_networkManager->sendCustomRequest(m_networkRequest, "PATCH", buffer); - buffer->setParent(reply); - - delete swgChannelSettings; -} - -void SSBMod::webapiReverseSendCWSettings(const CWKeyerSettings& cwKeyerSettings) -{ - SWGSDRangel::SWGChannelSettings *swgChannelSettings = new SWGSDRangel::SWGChannelSettings(); - swgChannelSettings->setDirection(1); // single source (Tx) - swgChannelSettings->setChannelType(new QString("SSBMod")); - swgChannelSettings->setSsbModSettings(new SWGSDRangel::SWGSSBModSettings()); - SWGSDRangel::SWGSSBModSettings *swgSSBModSettings = swgChannelSettings->getSsbModSettings(); - - swgSSBModSettings->setCwKeyer(new SWGSDRangel::SWGCWKeyerSettings()); - SWGSDRangel::SWGCWKeyerSettings *apiCwKeyerSettings = swgSSBModSettings->getCwKeyer(); - m_basebandSource->getCWKeyer().webapiFormatChannelSettings(apiCwKeyerSettings, cwKeyerSettings); - - QString channelSettingsURL = QString("http://%1:%2/sdrangel/deviceset/%3/channel/%4/settings") - .arg(m_settings.m_reverseAPIAddress) - .arg(m_settings.m_reverseAPIPort) - .arg(m_settings.m_reverseAPIDeviceIndex) - .arg(m_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 - QNetworkReply *reply = m_networkManager->sendCustomRequest(m_networkRequest, "PATCH", buffer); - buffer->setParent(reply); - - delete swgChannelSettings; } void SSBMod::networkManagerFinished(QNetworkReply *reply) @@ -707,4 +751,4 @@ int SSBMod::getFeedbackAudioSampleRate() const uint32_t SSBMod::getNumberOfDeviceStreams() const { return m_deviceAPI->getNbSinkStreams(); -} \ No newline at end of file +} diff --git a/plugins/channeltx/modssb/ssbmod.h b/plugins/channeltx/modssb/ssbmod.h index 8f3913989..16088a26e 100644 --- a/plugins/channeltx/modssb/ssbmod.h +++ b/plugins/channeltx/modssb/ssbmod.h @@ -265,6 +265,13 @@ private: void webapiFormatChannelReport(SWGSDRangel::SWGChannelReport& response); void webapiReverseSendSettings(QList& channelSettingsKeys, const SSBModSettings& settings, bool force); void webapiReverseSendCWSettings(const CWKeyerSettings& settings); + void featuresSendSettings(QList& channelSettingsKeys, const SSBModSettings& settings, bool force); + void webapiFormatChannelSettings( + QList& channelSettingsKeys, + SWGSDRangel::SWGChannelSettings *swgChannelSettings, + const SSBModSettings& settings, + bool force + ); private slots: void networkManagerFinished(QNetworkReply *reply); diff --git a/plugins/channeltx/modwfm/wfmmod.cpp b/plugins/channeltx/modwfm/wfmmod.cpp index ca65ae8bd..1bac328b9 100644 --- a/plugins/channeltx/modwfm/wfmmod.cpp +++ b/plugins/channeltx/modwfm/wfmmod.cpp @@ -34,7 +34,9 @@ #include "dsp/dspengine.h" #include "dsp/dspcommands.h" #include "device/deviceapi.h" +#include "feature/feature.h" #include "util/db.h" +#include "maincore.h" #include "wfmmodbaseband.h" #include "wfmmod.h" @@ -286,6 +288,10 @@ void WFMMod::applySettings(const WFMModSettings& settings, bool force) webapiReverseSendSettings(reverseAPIKeys, settings, fullUpdate || force); } + if (m_featuresSettingsFeedback.size() > 0) { + featuresSendSettings(reverseAPIKeys, settings, force); + } + m_settings = settings; } @@ -489,62 +495,7 @@ void WFMMod::webapiFormatChannelReport(SWGSDRangel::SWGChannelReport& response) void WFMMod::webapiReverseSendSettings(QList& channelSettingsKeys, const WFMModSettings& settings, bool force) { SWGSDRangel::SWGChannelSettings *swgChannelSettings = new SWGSDRangel::SWGChannelSettings(); - swgChannelSettings->setDirection(1); // single source (Tx) - swgChannelSettings->setOriginatorChannelIndex(getIndexInDeviceSet()); - swgChannelSettings->setOriginatorDeviceSetIndex(getDeviceSetIndex()); - swgChannelSettings->setChannelType(new QString("WFMMod")); - swgChannelSettings->setWfmModSettings(new SWGSDRangel::SWGWFMModSettings()); - SWGSDRangel::SWGWFMModSettings *swgWFMModSettings = swgChannelSettings->getWfmModSettings(); - - // transfer data that has been modified. When force is on transfer all data except reverse API data - - if (channelSettingsKeys.contains("channelMute") || force) { - swgWFMModSettings->setChannelMute(settings.m_channelMute ? 1 : 0); - } - if (channelSettingsKeys.contains("inputFrequencyOffset") || force) { - swgWFMModSettings->setInputFrequencyOffset(settings.m_inputFrequencyOffset); - } - if (channelSettingsKeys.contains("modAFInput") || force) { - swgWFMModSettings->setModAfInput((int) settings.m_modAFInput); - } - if (channelSettingsKeys.contains("playLoop") || force) { - swgWFMModSettings->setPlayLoop(settings.m_playLoop ? 1 : 0); - } - if (channelSettingsKeys.contains("rfBandwidth") || force) { - swgWFMModSettings->setRfBandwidth(settings.m_rfBandwidth); - } - if (channelSettingsKeys.contains("afBandwidth") || force) { - swgWFMModSettings->setAfBandwidth(settings.m_afBandwidth); - } - if (channelSettingsKeys.contains("rgbColor") || force) { - swgWFMModSettings->setRgbColor(settings.m_rgbColor); - } - if (channelSettingsKeys.contains("title") || force) { - swgWFMModSettings->setTitle(new QString(settings.m_title)); - } - if (channelSettingsKeys.contains("toneFrequency") || force) { - swgWFMModSettings->setToneFrequency(settings.m_toneFrequency); - } - if (channelSettingsKeys.contains("volumeFactor") || force) { - swgWFMModSettings->setVolumeFactor(settings.m_volumeFactor); - } - if (channelSettingsKeys.contains("fmDeviation")) { - swgWFMModSettings->setFmDeviation(settings.m_fmDeviation); - } - if (channelSettingsKeys.contains("streamIndex")) { - swgWFMModSettings->setStreamIndex(settings.m_streamIndex); - } - if (channelSettingsKeys.contains("audioDeviceName") || force) { - swgWFMModSettings->setAudioDeviceName(new QString(settings.m_audioDeviceName)); - } - - if (force) - { - const CWKeyerSettings& cwKeyerSettings = m_basebandSource->getCWKeyer().getSettings(); - swgWFMModSettings->setCwKeyer(new SWGSDRangel::SWGCWKeyerSettings()); - SWGSDRangel::SWGCWKeyerSettings *apiCwKeyerSettings = swgWFMModSettings->getCwKeyer(); - m_basebandSource->getCWKeyer().webapiFormatChannelSettings(apiCwKeyerSettings, cwKeyerSettings); - } + webapiFormatChannelSettings(channelSettingsKeys, swgChannelSettings, settings, force); QString channelSettingsURL = QString("http://%1:%2/sdrangel/deviceset/%3/channel/%4/settings") .arg(settings.m_reverseAPIAddress) @@ -598,6 +549,99 @@ void WFMMod::webapiReverseSendCWSettings(const CWKeyerSettings& cwKeyerSettings) delete swgChannelSettings; } +void WFMMod::featuresSendSettings(QList& channelSettingsKeys, const WFMModSettings& settings, bool force) +{ + QList::iterator it = m_featuresSettingsFeedback.begin(); + MainCore *mainCore = MainCore::instance(); + + for (; it != m_featuresSettingsFeedback.end(); ++it) + { + if (mainCore->existsFeature(*it)) + { + SWGSDRangel::SWGChannelSettings *swgChannelSettings = new SWGSDRangel::SWGChannelSettings(); + webapiFormatChannelSettings(channelSettingsKeys, swgChannelSettings, settings, force); + + Feature::MsgChannelSettings *msg = Feature::MsgChannelSettings::create( + this, + channelSettingsKeys, + swgChannelSettings, + force + ); + + (*it)->getInputMessageQueue()->push(msg); + } + else + { + m_featuresSettingsFeedback.removeOne(*it); + } + } +} + +void WFMMod::webapiFormatChannelSettings( + QList& channelSettingsKeys, + SWGSDRangel::SWGChannelSettings *swgChannelSettings, + const WFMModSettings& settings, + bool force +) +{ + swgChannelSettings->setDirection(1); // single source (Tx) + swgChannelSettings->setOriginatorChannelIndex(getIndexInDeviceSet()); + swgChannelSettings->setOriginatorDeviceSetIndex(getDeviceSetIndex()); + swgChannelSettings->setChannelType(new QString(m_channelId)); + swgChannelSettings->setWfmModSettings(new SWGSDRangel::SWGWFMModSettings()); + SWGSDRangel::SWGWFMModSettings *swgWFMModSettings = swgChannelSettings->getWfmModSettings(); + + // transfer data that has been modified. When force is on transfer all data except reverse API data + + if (channelSettingsKeys.contains("channelMute") || force) { + swgWFMModSettings->setChannelMute(settings.m_channelMute ? 1 : 0); + } + if (channelSettingsKeys.contains("inputFrequencyOffset") || force) { + swgWFMModSettings->setInputFrequencyOffset(settings.m_inputFrequencyOffset); + } + if (channelSettingsKeys.contains("modAFInput") || force) { + swgWFMModSettings->setModAfInput((int) settings.m_modAFInput); + } + if (channelSettingsKeys.contains("playLoop") || force) { + swgWFMModSettings->setPlayLoop(settings.m_playLoop ? 1 : 0); + } + if (channelSettingsKeys.contains("rfBandwidth") || force) { + swgWFMModSettings->setRfBandwidth(settings.m_rfBandwidth); + } + if (channelSettingsKeys.contains("afBandwidth") || force) { + swgWFMModSettings->setAfBandwidth(settings.m_afBandwidth); + } + if (channelSettingsKeys.contains("rgbColor") || force) { + swgWFMModSettings->setRgbColor(settings.m_rgbColor); + } + if (channelSettingsKeys.contains("title") || force) { + swgWFMModSettings->setTitle(new QString(settings.m_title)); + } + if (channelSettingsKeys.contains("toneFrequency") || force) { + swgWFMModSettings->setToneFrequency(settings.m_toneFrequency); + } + if (channelSettingsKeys.contains("volumeFactor") || force) { + swgWFMModSettings->setVolumeFactor(settings.m_volumeFactor); + } + if (channelSettingsKeys.contains("fmDeviation")) { + swgWFMModSettings->setFmDeviation(settings.m_fmDeviation); + } + if (channelSettingsKeys.contains("streamIndex")) { + swgWFMModSettings->setStreamIndex(settings.m_streamIndex); + } + if (channelSettingsKeys.contains("audioDeviceName") || force) { + swgWFMModSettings->setAudioDeviceName(new QString(settings.m_audioDeviceName)); + } + + if (force) + { + const CWKeyerSettings& cwKeyerSettings = m_basebandSource->getCWKeyer().getSettings(); + swgWFMModSettings->setCwKeyer(new SWGSDRangel::SWGCWKeyerSettings()); + SWGSDRangel::SWGCWKeyerSettings *apiCwKeyerSettings = swgWFMModSettings->getCwKeyer(); + m_basebandSource->getCWKeyer().webapiFormatChannelSettings(apiCwKeyerSettings, cwKeyerSettings); + } +} + void WFMMod::networkManagerFinished(QNetworkReply *reply) { QNetworkReply::NetworkError replyError = reply->error(); diff --git a/plugins/channeltx/modwfm/wfmmod.h b/plugins/channeltx/modwfm/wfmmod.h index 4b6e0696f..fee868cae 100644 --- a/plugins/channeltx/modwfm/wfmmod.h +++ b/plugins/channeltx/modwfm/wfmmod.h @@ -273,6 +273,13 @@ private: void webapiFormatChannelReport(SWGSDRangel::SWGChannelReport& response); void webapiReverseSendSettings(QList& channelSettingsKeys, const WFMModSettings& settings, bool force); void webapiReverseSendCWSettings(const CWKeyerSettings& settings); + void featuresSendSettings(QList& channelSettingsKeys, const WFMModSettings& settings, bool force); + void webapiFormatChannelSettings( + QList& channelSettingsKeys, + SWGSDRangel::SWGChannelSettings *swgChannelSettings, + const WFMModSettings& settings, + bool force + ); private slots: void networkManagerFinished(QNetworkReply *reply); diff --git a/plugins/channeltx/remotesource/remotesource.cpp b/plugins/channeltx/remotesource/remotesource.cpp index 180f90cdb..2a81cb6b1 100644 --- a/plugins/channeltx/remotesource/remotesource.cpp +++ b/plugins/channeltx/remotesource/remotesource.cpp @@ -29,7 +29,10 @@ #include "dsp/devicesamplesink.h" #include "device/deviceapi.h" +#include "feature/feature.h" #include "util/timeutil.h" +#include "util/db.h" +#include "maincore.h" #include "remotesourcebaseband.h" @@ -202,6 +205,10 @@ void RemoteSource::applySettings(const RemoteSourceSettings& settings, bool forc webapiReverseSendSettings(reverseAPIKeys, settings, fullUpdate || force); } + if (m_featuresSettingsFeedback.size() > 0) { + featuresSendSettings(reverseAPIKeys, settings, force); + } + m_settings = settings; } @@ -350,10 +357,67 @@ void RemoteSource::webapiFormatChannelReport(SWGSDRangel::SWGChannelReport& resp void RemoteSource::webapiReverseSendSettings(QList& channelSettingsKeys, const RemoteSourceSettings& settings, bool force) { SWGSDRangel::SWGChannelSettings *swgChannelSettings = new SWGSDRangel::SWGChannelSettings(); + webapiFormatChannelSettings(channelSettingsKeys, swgChannelSettings, settings, force); + + 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 + QNetworkReply *reply = m_networkManager->sendCustomRequest(m_networkRequest, "PATCH", buffer); + buffer->setParent(reply); + + delete swgChannelSettings; +} + +void RemoteSource::featuresSendSettings(QList& channelSettingsKeys, const RemoteSourceSettings& settings, bool force) +{ + QList::iterator it = m_featuresSettingsFeedback.begin(); + MainCore *mainCore = MainCore::instance(); + + for (; it != m_featuresSettingsFeedback.end(); ++it) + { + if (mainCore->existsFeature(*it)) + { + SWGSDRangel::SWGChannelSettings *swgChannelSettings = new SWGSDRangel::SWGChannelSettings(); + webapiFormatChannelSettings(channelSettingsKeys, swgChannelSettings, settings, force); + + Feature::MsgChannelSettings *msg = Feature::MsgChannelSettings::create( + this, + channelSettingsKeys, + swgChannelSettings, + force + ); + + (*it)->getInputMessageQueue()->push(msg); + } + else + { + m_featuresSettingsFeedback.removeOne(*it); + } + } +} + +void RemoteSource::webapiFormatChannelSettings( + QList& channelSettingsKeys, + SWGSDRangel::SWGChannelSettings *swgChannelSettings, + const RemoteSourceSettings& settings, + bool force +) +{ swgChannelSettings->setDirection(1); // single source (Tx) swgChannelSettings->setOriginatorChannelIndex(getIndexInDeviceSet()); swgChannelSettings->setOriginatorDeviceSetIndex(getDeviceSetIndex()); - swgChannelSettings->setChannelType(new QString("RemoteSource")); + swgChannelSettings->setChannelType(new QString(m_channelId)); swgChannelSettings->setRemoteSourceSettings(new SWGSDRangel::SWGRemoteSourceSettings()); SWGSDRangel::SWGRemoteSourceSettings *swgRemoteSourceSettings = swgChannelSettings->getRemoteSourceSettings(); @@ -374,25 +438,6 @@ void RemoteSource::webapiReverseSendSettings(QList& channelSettingsKeys if (channelSettingsKeys.contains("streamIndex") || force) { swgRemoteSourceSettings->setStreamIndex(settings.m_streamIndex); } - - 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 - QNetworkReply *reply = m_networkManager->sendCustomRequest(m_networkRequest, "PATCH", buffer); - buffer->setParent(reply); - - delete swgChannelSettings; } void RemoteSource::networkManagerFinished(QNetworkReply *reply) @@ -419,4 +464,4 @@ void RemoteSource::networkManagerFinished(QNetworkReply *reply) uint32_t RemoteSource::getNumberOfDeviceStreams() const { return m_deviceAPI->getNbSinkStreams(); -} \ No newline at end of file +} diff --git a/plugins/channeltx/remotesource/remotesource.h b/plugins/channeltx/remotesource/remotesource.h index 41b9519cc..5ecce8b91 100644 --- a/plugins/channeltx/remotesource/remotesource.h +++ b/plugins/channeltx/remotesource/remotesource.h @@ -222,6 +222,13 @@ private: void applySettings(const RemoteSourceSettings& settings, bool force = false); void webapiFormatChannelReport(SWGSDRangel::SWGChannelReport& response); void webapiReverseSendSettings(QList& channelSettingsKeys, const RemoteSourceSettings& settings, bool force); + void featuresSendSettings(QList& channelSettingsKeys, const RemoteSourceSettings& settings, bool force); + void webapiFormatChannelSettings( + QList& channelSettingsKeys, + SWGSDRangel::SWGChannelSettings *swgChannelSettings, + const RemoteSourceSettings& settings, + bool force + ); private slots: void networkManagerFinished(QNetworkReply *reply); diff --git a/plugins/channeltx/udpsource/udpsource.cpp b/plugins/channeltx/udpsource/udpsource.cpp index 8165c5b15..c2f5dc437 100644 --- a/plugins/channeltx/udpsource/udpsource.cpp +++ b/plugins/channeltx/udpsource/udpsource.cpp @@ -27,7 +27,9 @@ #include "device/deviceapi.h" #include "dsp/dspcommands.h" +#include "feature/feature.h" #include "util/db.h" +#include "maincore.h" #include "udpsourcebaseband.h" #include "udpsource.h" @@ -251,6 +253,10 @@ void UDPSource::applySettings(const UDPSourceSettings& settings, bool force) webapiReverseSendSettings(reverseAPIKeys, settings, fullUpdate || force); } + if (m_featuresSettingsFeedback.size() > 0) { + featuresSendSettings(reverseAPIKeys, settings, force); + } + m_settings = settings; } @@ -484,10 +490,67 @@ void UDPSource::webapiFormatChannelReport(SWGSDRangel::SWGChannelReport& respons void UDPSource::webapiReverseSendSettings(QList& channelSettingsKeys, const UDPSourceSettings& settings, bool force) { SWGSDRangel::SWGChannelSettings *swgChannelSettings = new SWGSDRangel::SWGChannelSettings(); + webapiFormatChannelSettings(channelSettingsKeys, swgChannelSettings, settings, force); + + 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 + QNetworkReply *reply = m_networkManager->sendCustomRequest(m_networkRequest, "PATCH", buffer); + buffer->setParent(reply); + + delete swgChannelSettings; +} + +void UDPSource::featuresSendSettings(QList& channelSettingsKeys, const UDPSourceSettings& settings, bool force) +{ + QList::iterator it = m_featuresSettingsFeedback.begin(); + MainCore *mainCore = MainCore::instance(); + + for (; it != m_featuresSettingsFeedback.end(); ++it) + { + if (mainCore->existsFeature(*it)) + { + SWGSDRangel::SWGChannelSettings *swgChannelSettings = new SWGSDRangel::SWGChannelSettings(); + webapiFormatChannelSettings(channelSettingsKeys, swgChannelSettings, settings, force); + + Feature::MsgChannelSettings *msg = Feature::MsgChannelSettings::create( + this, + channelSettingsKeys, + swgChannelSettings, + force + ); + + (*it)->getInputMessageQueue()->push(msg); + } + else + { + m_featuresSettingsFeedback.removeOne(*it); + } + } +} + +void UDPSource::webapiFormatChannelSettings( + QList& channelSettingsKeys, + SWGSDRangel::SWGChannelSettings *swgChannelSettings, + const UDPSourceSettings& settings, + bool force +) +{ swgChannelSettings->setDirection(1); // single source (Tx) swgChannelSettings->setOriginatorChannelIndex(getIndexInDeviceSet()); swgChannelSettings->setOriginatorDeviceSetIndex(getDeviceSetIndex()); - swgChannelSettings->setChannelType(new QString("UDPSource")); + swgChannelSettings->setChannelType(new QString(m_channelId)); swgChannelSettings->setUdpSourceSettings(new SWGSDRangel::SWGUDPSourceSettings()); SWGSDRangel::SWGUDPSourceSettings *swgUDPSourceSettings = swgChannelSettings->getUdpSourceSettings(); @@ -559,25 +622,6 @@ void UDPSource::webapiReverseSendSettings(QList& channelSettingsKeys, c if (channelSettingsKeys.contains("streamIndex") || force) { swgUDPSourceSettings->setStreamIndex(settings.m_streamIndex); } - - 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 - QNetworkReply *reply = m_networkManager->sendCustomRequest(m_networkRequest, "PATCH", buffer); - buffer->setParent(reply); - - delete swgChannelSettings; } void UDPSource::networkManagerFinished(QNetworkReply *reply) @@ -628,4 +672,4 @@ bool UDPSource::getSquelchOpen() const uint32_t UDPSource::getNumberOfDeviceStreams() const { return m_deviceAPI->getNbSinkStreams(); -} \ No newline at end of file +} diff --git a/plugins/channeltx/udpsource/udpsource.h b/plugins/channeltx/udpsource/udpsource.h index 72db40759..16d95dec1 100644 --- a/plugins/channeltx/udpsource/udpsource.h +++ b/plugins/channeltx/udpsource/udpsource.h @@ -176,6 +176,13 @@ private: void webapiFormatChannelReport(SWGSDRangel::SWGChannelReport& response); void webapiReverseSendSettings(QList& channelSettingsKeys, const UDPSourceSettings& settings, bool force); + void featuresSendSettings(QList& channelSettingsKeys, const UDPSourceSettings& settings, bool force); + void webapiFormatChannelSettings( + QList& channelSettingsKeys, + SWGSDRangel::SWGChannelSettings *swgChannelSettings, + const UDPSourceSettings& settings, + bool force + ); }; diff --git a/plugins/feature/CMakeLists.txt b/plugins/feature/CMakeLists.txt index 6d80a3cd6..e6cf4b815 100644 --- a/plugins/feature/CMakeLists.txt +++ b/plugins/feature/CMakeLists.txt @@ -3,5 +3,6 @@ project(feature) if (Qt5SerialPort_FOUND) add_subdirectory(gs232controller) endif() +add_subdirectory(afc) add_subdirectory(rigctlserver) add_subdirectory(simpleptt) diff --git a/plugins/feature/afc/CMakeLists.txt b/plugins/feature/afc/CMakeLists.txt new file mode 100644 index 000000000..2f240e401 --- /dev/null +++ b/plugins/feature/afc/CMakeLists.txt @@ -0,0 +1,58 @@ +project(afc) + +set(afc_SOURCES + afc.cpp + afcsettings.cpp + afcplugin.cpp + afcworker.cpp + afcreport.cpp + afcwebapiadapter.cpp +) + +set(afc_HEADERS + afc.h + afcsettings.h + afcplugin.h + afcworker.h + afcreport.h + afcwebapiadapter.h +) + +include_directories( + ${CMAKE_SOURCE_DIR}/swagger/sdrangel/code/qt5/client +) + +if(NOT SERVER_MODE) + set(afc_SOURCES + ${afc_SOURCES} + afcgui.cpp + afcgui.ui + ) + set(afc_HEADERS + ${afc_HEADERS} + afcgui.h + ) + + set(TARGET_NAME featureafc) + set(TARGET_LIB "Qt5::Widgets") + set(TARGET_LIB_GUI "sdrgui") + set(INSTALL_FOLDER ${INSTALL_PLUGINS_DIR}) +else() + set(TARGET_NAME featureafcsrv) + set(TARGET_LIB "") + set(TARGET_LIB_GUI "") + set(INSTALL_FOLDER ${INSTALL_PLUGINSSRV_DIR}) +endif() + +add_library(${TARGET_NAME} SHARED + ${afc_SOURCES} +) + +target_link_libraries(${TARGET_NAME} + Qt5::Core + ${TARGET_LIB} + sdrbase + ${TARGET_LIB_GUI} +) + +install(TARGETS ${TARGET_NAME} DESTINATION ${INSTALL_FOLDER}) diff --git a/plugins/feature/afc/afc.cpp b/plugins/feature/afc/afc.cpp new file mode 100644 index 000000000..48f2ecdd0 --- /dev/null +++ b/plugins/feature/afc/afc.cpp @@ -0,0 +1,580 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2020 Edouard Griffiths, F4EXB // +// // +// This program is free software; you can redistribute it and/or modify // +// it under the terms of the GNU General Public License as published by // +// the Free Software Foundation as version 3 of the License, or // +// (at your option) any later version. // +// // +// This program is distributed in the hope that it will be useful, // +// but WITHOUT ANY WARRANTY; without even the implied warranty of // +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // +// GNU General Public License V3 for more details. // +// // +// You should have received a copy of the GNU General Public License // +// along with this program. If not, see . // +/////////////////////////////////////////////////////////////////////////////////// + +#include +#include +#include +#include + +#include "SWGFeatureSettings.h" +#include "SWGFeatureReport.h" +#include "SWGFeatureActions.h" +#include "SWGAFCReport.h" +#include "SWGDeviceState.h" +#include "SWGChannelSettings.h" + +#include "dsp/dspengine.h" +#include "device/deviceset.h" +#include "channel/channelapi.h" +#include "maincore.h" + +#include "afcworker.h" +#include "afc.h" + +MESSAGE_CLASS_DEFINITION(AFC::MsgConfigureAFC, Message) +MESSAGE_CLASS_DEFINITION(AFC::MsgStartStop, Message) +MESSAGE_CLASS_DEFINITION(AFC::MsgDeviceTrack, Message) +MESSAGE_CLASS_DEFINITION(AFC::MsgDevicesApply, Message) + +const QString AFC::m_featureIdURI = "sdrangel.feature.afc"; +const QString AFC::m_featureId = "AFC"; + +AFC::AFC(WebAPIAdapterInterface *webAPIAdapterInterface) : + Feature(m_featureIdURI, webAPIAdapterInterface), + m_trackerDeviceSet(nullptr), + m_trackedDeviceSet(nullptr), + m_trackerIndexInDeviceSet(-1), + m_trackerChannelAPI(nullptr) +{ + setObjectName(m_featureId); + m_worker = new AFCWorker(webAPIAdapterInterface); + m_state = StIdle; + m_errorMessage = "AFC error"; +} + +AFC::~AFC() +{ + if (m_worker->isRunning()) { + stop(); + } + + delete m_worker; + removeTrackerFeatureReference(); + removeTrackedFeatureReferences(); +} + +void AFC::start() +{ + qDebug("AFC::start"); + + m_worker->reset(); + m_worker->setMessageQueueToGUI(getMessageQueueToGUI()); + bool ok = m_worker->startWork(); + m_state = ok ? StRunning : StError; + m_thread.start(); + + AFCWorker::MsgConfigureAFCWorker *msg = AFCWorker::MsgConfigureAFCWorker::create(m_settings, true); + m_worker->getInputMessageQueue()->push(msg); +} + +void AFC::stop() +{ + qDebug("AFC::stop"); + m_worker->stopWork(); + m_state = StIdle; + m_thread.quit(); + m_thread.wait(); +} + +bool AFC::handleMessage(const Message& cmd) +{ + if (MsgConfigureAFC::match(cmd)) + { + MsgConfigureAFC& cfg = (MsgConfigureAFC&) cmd; + qDebug() << "AFC::handleMessage: MsgConfigureAFC"; + applySettings(cfg.getSettings(), cfg.getForce()); + + return true; + } + else if (MsgStartStop::match(cmd)) + { + MsgStartStop& cfg = (MsgStartStop&) cmd; + qDebug() << "AFC::handleMessage: MsgStartStop: start:" << cfg.getStartStop(); + + if (cfg.getStartStop()) { + start(); + } else { + stop(); + } + + return true; + } + else if (Feature::MsgChannelSettings::match(cmd)) + { + Feature::MsgChannelSettings& cfg = (Feature::MsgChannelSettings&) cmd; + SWGSDRangel::SWGChannelSettings *swgChannelSettings = cfg.getSWGSettings(); + QString *channelType = swgChannelSettings->getChannelType(); + qDebug() << "AFC::handleMessage: Feature::MsgChannelSettings: " << *channelType; + + if (m_worker->isRunning()) + { + m_worker->getInputMessageQueue()->push(&cfg); + } + else + { + delete swgChannelSettings; + return true; + } + } + else if (MsgDeviceTrack::match(cmd)) + { + if (m_worker->isRunning()) + { + AFCWorker::MsgDeviceTrack *msg = AFCWorker::MsgDeviceTrack::create(); + m_worker->getInputMessageQueue()->push(msg); + } + + return true; + } + else if (MsgDevicesApply::match(cmd)) + { + removeTrackerFeatureReference(); + trackerDeviceChange(m_settings.m_trackerDeviceSetIndex); + removeTrackedFeatureReferences(); + trackedDeviceChange(m_settings.m_trackedDeviceSetIndex); + + if (m_worker->isRunning()) + { + AFCWorker::MsgDevicesApply *msg = AFCWorker::MsgDevicesApply::create(); + m_worker->getInputMessageQueue()->push(msg); + } + + return true; + } + + return false; +} + +QByteArray AFC::serialize() const +{ + return m_settings.serialize(); +} + +bool AFC::deserialize(const QByteArray& data) +{ + if (m_settings.deserialize(data)) + { + MsgConfigureAFC *msg = MsgConfigureAFC::create(m_settings, true); + m_inputMessageQueue.push(msg); + return true; + } + else + { + m_settings.resetToDefaults(); + MsgConfigureAFC *msg = MsgConfigureAFC::create(m_settings, true); + m_inputMessageQueue.push(msg); + return false; + } +} + +void AFC::applySettings(const AFCSettings& settings, bool force) +{ + qDebug() << "AFC::applySettings:" + << " m_title: " << settings.m_title + << " m_rgbColor: " << settings.m_rgbColor + << " m_trackerDeviceSetIndex: " << settings.m_trackerDeviceSetIndex + << " m_trackedDeviceSetIndex: " << settings.m_trackedDeviceSetIndex + << " m_hasTargetFrequency: " << settings.m_hasTargetFrequency + << " m_transverterTarget: " << settings.m_transverterTarget + << " m_targetFrequency: " << settings.m_targetFrequency + << " m_freqTolerance: " << settings.m_freqTolerance + << " m_trackerAdjustPeriod:" << settings.m_trackerAdjustPeriod + << " force: " << force; + + QList reverseAPIKeys; + + if ((m_settings.m_title != settings.m_title) || force) { + reverseAPIKeys.append("title"); + } + if ((m_settings.m_rgbColor != settings.m_rgbColor) || force) { + reverseAPIKeys.append("rgbColor"); + } + if ((m_settings.m_trackerDeviceSetIndex != settings.m_trackerDeviceSetIndex) || force) { + reverseAPIKeys.append("trackerDeviceSetIndex"); + } + if ((m_settings.m_trackedDeviceSetIndex != settings.m_trackedDeviceSetIndex) || force) { + reverseAPIKeys.append("trackedDeviceSetIndex"); + } + if ((m_settings.m_hasTargetFrequency != settings.m_hasTargetFrequency) || force) { + reverseAPIKeys.append("hasTargetFrequency"); + } + if ((m_settings.m_transverterTarget != settings.m_transverterTarget) || force) { + reverseAPIKeys.append("transverterTarget"); + } + if ((m_settings.m_targetFrequency != settings.m_targetFrequency) || force) { + reverseAPIKeys.append("targetFrequency"); + } + if ((m_settings.m_freqTolerance != settings.m_freqTolerance) || force) { + reverseAPIKeys.append("freqTolerance"); + } + if ((m_settings.m_trackerAdjustPeriod != settings.m_trackerAdjustPeriod) || force) { + reverseAPIKeys.append("trackerAdjustPeriod"); + } + + if ((m_settings.m_trackerDeviceSetIndex != settings.m_trackerDeviceSetIndex) || force) + { + removeTrackerFeatureReference(); + trackerDeviceChange(settings.m_trackerDeviceSetIndex); + } + + if ((m_settings.m_trackedDeviceSetIndex != settings.m_trackedDeviceSetIndex) || force) + { + removeTrackedFeatureReferences(); + trackedDeviceChange(settings.m_trackedDeviceSetIndex); + } + + AFCWorker::MsgConfigureAFCWorker *msg = AFCWorker::MsgConfigureAFCWorker::create( + settings, force + ); + m_worker->getInputMessageQueue()->push(msg); + + 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_reverseAPIFeatureSetIndex != settings.m_reverseAPIFeatureSetIndex) || + (m_settings.m_reverseAPIFeatureIndex != settings.m_reverseAPIFeatureIndex); + webapiReverseSendSettings(reverseAPIKeys, settings, fullUpdate || force); + } + + m_settings = settings; +} + +int AFC::webapiRun(bool run, + SWGSDRangel::SWGDeviceState& response, + QString& errorMessage) +{ + getFeatureStateStr(*response.getState()); + MsgStartStop *msg = MsgStartStop::create(run); + getInputMessageQueue()->push(msg); + return 202; +} + +int AFC::webapiSettingsGet( + SWGSDRangel::SWGFeatureSettings& response, + QString& errorMessage) +{ + (void) errorMessage; + response.setAfcSettings(new SWGSDRangel::SWGAFCSettings()); + response.getAfcSettings()->init(); + webapiFormatFeatureSettings(response, m_settings); + return 200; +} + +int AFC::webapiSettingsPutPatch( + bool force, + const QStringList& featureSettingsKeys, + SWGSDRangel::SWGFeatureSettings& response, + QString& errorMessage) +{ + (void) errorMessage; + AFCSettings settings = m_settings; + webapiUpdateFeatureSettings(settings, featureSettingsKeys, response); + + MsgConfigureAFC *msg = MsgConfigureAFC::create(settings, force); + m_inputMessageQueue.push(msg); + + qDebug("AFC::webapiSettingsPutPatch: forward to GUI: %p", m_guiMessageQueue); + if (m_guiMessageQueue) // forward to GUI if any + { + MsgConfigureAFC *msgToGUI = MsgConfigureAFC::create(settings, force); + m_guiMessageQueue->push(msgToGUI); + } + + webapiFormatFeatureSettings(response, settings); + + return 200; +} + +int AFC::webapiReportGet( + SWGSDRangel::SWGFeatureReport& response, + QString& errorMessage) +{ + (void) errorMessage; + response.setAfcReport(new SWGSDRangel::SWGAFCReport()); + response.getAfcReport()->init(); + webapiFormatFeatureReport(response); + return 200; +} + +int AFC::webapiActionsPost( + const QStringList& featureActionsKeys, + SWGSDRangel::SWGFeatureActions& query, + QString& errorMessage) +{ + SWGSDRangel::SWGAFCActions *swgAFCActions = query.getAfcActions(); + + if (swgAFCActions) + { + if (featureActionsKeys.contains("deviceTrack")) + { + bool deviceTrack = swgAFCActions->getDeviceTrack() != 0; + + if (deviceTrack) + { + MsgDeviceTrack *msg = MsgDeviceTrack::create(); + getInputMessageQueue()->push(msg); + } + } + + if (featureActionsKeys.contains("devicesApply")) + { + bool devicesApply = swgAFCActions->getDevicesApply() != 0; + + if (devicesApply) + { + MsgDevicesApply *msg = MsgDevicesApply::create(); + getInputMessageQueue()->push(msg); + } + } + + return 202; + } + else + { + errorMessage = "Missing AFCActions in query"; + return 400; + } +} + +void AFC::webapiFormatFeatureSettings( + SWGSDRangel::SWGFeatureSettings& response, + const AFCSettings& settings) +{ + if (response.getAfcSettings()->getTitle()) { + *response.getAfcSettings()->getTitle() = settings.m_title; + } else { + response.getAfcSettings()->setTitle(new QString(settings.m_title)); + } + + response.getAfcSettings()->setRgbColor(settings.m_rgbColor); + response.getAfcSettings()->setTrackerDeviceSetIndex(settings.m_trackerDeviceSetIndex); + response.getAfcSettings()->setTrackedDeviceSetIndex(settings.m_trackedDeviceSetIndex); + response.getAfcSettings()->setHasTargetFrequency(settings.m_hasTargetFrequency); + response.getAfcSettings()->setTransverterTarget(settings.m_transverterTarget); + response.getAfcSettings()->setTargetFrequency(settings.m_targetFrequency); + response.getAfcSettings()->setFreqTolerance(settings.m_freqTolerance); + response.getAfcSettings()->setTrackerAdjustPeriod(settings.m_trackerAdjustPeriod); + + response.getAfcSettings()->setUseReverseApi(settings.m_useReverseAPI ? 1 : 0); + + if (response.getAfcSettings()->getReverseApiAddress()) { + *response.getAfcSettings()->getReverseApiAddress() = settings.m_reverseAPIAddress; + } else { + response.getAfcSettings()->setReverseApiAddress(new QString(settings.m_reverseAPIAddress)); + } + + response.getAfcSettings()->setReverseApiPort(settings.m_reverseAPIPort); + response.getAfcSettings()->setReverseApiDeviceIndex(settings.m_reverseAPIFeatureSetIndex); + response.getAfcSettings()->setReverseApiChannelIndex(settings.m_reverseAPIFeatureIndex); +} + +void AFC::webapiUpdateFeatureSettings( + AFCSettings& settings, + const QStringList& featureSettingsKeys, + SWGSDRangel::SWGFeatureSettings& response) +{ + if (featureSettingsKeys.contains("title")) { + settings.m_title = *response.getAfcSettings()->getTitle(); + } + if (featureSettingsKeys.contains("rgbColor")) { + settings.m_rgbColor = response.getAfcSettings()->getRgbColor(); + } + if (featureSettingsKeys.contains("trackerDeviceSetIndex")) { + settings.m_trackerDeviceSetIndex = response.getAfcSettings()->getTrackerDeviceSetIndex(); + } + if (featureSettingsKeys.contains("trackedDeviceSetIndex")) { + settings.m_trackedDeviceSetIndex = response.getAfcSettings()->getTrackedDeviceSetIndex(); + } + if (featureSettingsKeys.contains("hasTargetFrequency")) { + settings.m_hasTargetFrequency = response.getAfcSettings()->getHasTargetFrequency() != 0; + } + if (featureSettingsKeys.contains("hasTargetFrequency")) { + settings.m_hasTargetFrequency = response.getAfcSettings()->getHasTargetFrequency() != 0; + } + if (featureSettingsKeys.contains("targetFrequency")) { + settings.m_targetFrequency = response.getAfcSettings()->getTargetFrequency(); + } + if (featureSettingsKeys.contains("freqTolerance")) { + settings.m_freqTolerance = response.getAfcSettings()->getFreqTolerance(); + } + if (featureSettingsKeys.contains("trackerAdjustPeriod")) { + settings.m_trackerAdjustPeriod = response.getAfcSettings()->getTrackerAdjustPeriod(); + } + if (featureSettingsKeys.contains("useReverseAPI")) { + settings.m_useReverseAPI = response.getAfcSettings()->getUseReverseApi() != 0; + } + if (featureSettingsKeys.contains("reverseAPIAddress")) { + settings.m_reverseAPIAddress = *response.getAfcSettings()->getReverseApiAddress(); + } + if (featureSettingsKeys.contains("reverseAPIPort")) { + settings.m_reverseAPIPort = response.getAfcSettings()->getReverseApiPort(); + } + if (featureSettingsKeys.contains("reverseAPIDeviceIndex")) { + settings.m_reverseAPIFeatureSetIndex = response.getAfcSettings()->getReverseApiDeviceIndex(); + } + if (featureSettingsKeys.contains("reverseAPIChannelIndex")) { + settings.m_reverseAPIFeatureIndex = response.getAfcSettings()->getReverseApiChannelIndex(); + } +} + +void AFC::webapiFormatFeatureReport(SWGSDRangel::SWGFeatureReport& response) +{ + response.getAfcReport()->setTrackerChannelIndex(m_trackerIndexInDeviceSet); + response.getAfcReport()->setTrackerDeviceFrequency(m_worker->getTrackerDeviceFrequency()); + response.getAfcReport()->setTrackerChannelOffset(m_worker->getTrackerChannelOffset()); +} + +void AFC::webapiReverseSendSettings(QList& channelSettingsKeys, const AFCSettings& settings, bool force) +{ + SWGSDRangel::SWGFeatureSettings *swgFeatureSettings = new SWGSDRangel::SWGFeatureSettings(); + // swgFeatureSettings->setOriginatorFeatureIndex(getIndexInDeviceSet()); + // swgFeatureSettings->setOriginatorFeatureSetIndex(getDeviceSetIndex()); + swgFeatureSettings->setFeatureType(new QString("AFC")); + swgFeatureSettings->setAfcSettings(new SWGSDRangel::SWGAFCSettings()); + SWGSDRangel::SWGAFCSettings *swgAFCSettings = swgFeatureSettings->getAfcSettings(); + + // transfer data that has been modified. When force is on transfer all data except reverse API data + + if (channelSettingsKeys.contains("title") || force) { + swgAFCSettings->setTitle(new QString(settings.m_title)); + } + if (channelSettingsKeys.contains("rgbColor") || force) { + swgAFCSettings->setRgbColor(settings.m_rgbColor); + } + if (channelSettingsKeys.contains("trackerDeviceSetIndex") || force) { + swgAFCSettings->setTrackerDeviceSetIndex(settings.m_trackerDeviceSetIndex); + } + if (channelSettingsKeys.contains("trackedDeviceSetIndex") || force) { + swgAFCSettings->setTrackedDeviceSetIndex(settings.m_trackedDeviceSetIndex); + } + if (channelSettingsKeys.contains("hasTargetFrequency") || force) { + swgAFCSettings->setHasTargetFrequency(settings.m_hasTargetFrequency ? 1 : 0); + } + if (channelSettingsKeys.contains("targetFrequency") || force) { + swgAFCSettings->setTargetFrequency(settings.m_targetFrequency ? 1 : 0); + } + if (channelSettingsKeys.contains("targetFrequency") || force) { + swgAFCSettings->setTargetFrequency(settings.m_targetFrequency); + } + if (channelSettingsKeys.contains("freqTolerance") || force) { + swgAFCSettings->setFreqTolerance(settings.m_freqTolerance); + } + if (channelSettingsKeys.contains("trackerAdjustPeriod") || force) { + swgAFCSettings->setTrackerAdjustPeriod(settings.m_trackerAdjustPeriod); + } + + QString channelSettingsURL = QString("http://%1:%2/sdrangel/featureset/%3/feature/%4/settings") + .arg(settings.m_reverseAPIAddress) + .arg(settings.m_reverseAPIPort) + .arg(settings.m_reverseAPIFeatureSetIndex) + .arg(settings.m_reverseAPIFeatureIndex); + m_networkRequest.setUrl(QUrl(channelSettingsURL)); + m_networkRequest.setHeader(QNetworkRequest::ContentTypeHeader, "application/json"); + + QBuffer *buffer = new QBuffer(); + buffer->open((QBuffer::ReadWrite)); + buffer->write(swgFeatureSettings->asJson().toUtf8()); + buffer->seek(0); + + // Always use PATCH to avoid passing reverse API settings + QNetworkReply *reply = m_networkManager->sendCustomRequest(m_networkRequest, "PATCH", buffer); + buffer->setParent(reply); + + delete swgFeatureSettings; +} + +void AFC::networkManagerFinished(QNetworkReply *reply) +{ + QNetworkReply::NetworkError replyError = reply->error(); + + if (replyError) + { + qWarning() << "AFC::networkManagerFinished:" + << " error(" << (int) replyError + << "): " << replyError + << ": " << reply->errorString(); + } + else + { + QString answer = reply->readAll(); + answer.chop(1); // remove last \n + qDebug("AFC::networkManagerFinished: reply:\n%s", answer.toStdString().c_str()); + } + + reply->deleteLater(); +} + +void AFC::trackerDeviceChange(int deviceIndex) +{ + MainCore *mainCore = MainCore::instance(); + m_trackerDeviceSet = mainCore->getDeviceSets()[deviceIndex]; + + for (int i = 0; i < m_trackerDeviceSet->getNumberOfChannels(); i++) + { + ChannelAPI *channel = m_trackerDeviceSet->getChannelAt(i); + + if (channel->getURI() == "sdrangel.channel.freqtracker") + { + channel->addFeatureSettingsFeedback(this); + m_trackerChannelAPI = channel; + break; + } + } +} + +void AFC::trackedDeviceChange(int deviceIndex) +{ + MainCore *mainCore = MainCore::instance(); + m_trackedDeviceSet = mainCore->getDeviceSets()[deviceIndex]; + + for (int i = 0; i < m_trackedDeviceSet->getNumberOfChannels(); i++) + { + ChannelAPI *channel = m_trackedDeviceSet->getChannelAt(i); + + if (channel->getURI() != "sdrangel.channel.freqtracker") + { + channel->addFeatureSettingsFeedback(this); + m_trackerIndexInDeviceSet = i; + } + } +} + +void AFC::removeTrackerFeatureReference() +{ + if (m_trackerChannelAPI) + { + if (MainCore::instance()->existsChannel(m_trackerChannelAPI)) { + m_trackerChannelAPI->removeFeatureSettingsFeedback(this); + } + } +} + +void AFC::removeTrackedFeatureReferences() +{ + for (QList::iterator it = m_trackedChannelAPIs.begin(); it != m_trackedChannelAPIs.end(); ++it) + { + ChannelAPI *channel = *it; + + if (MainCore::instance()->existsChannel(channel)) { + channel->removeFeatureSettingsFeedback(this); + } + } + + m_trackedChannelAPIs.clear(); +} diff --git a/plugins/feature/afc/afc.h b/plugins/feature/afc/afc.h new file mode 100644 index 000000000..a735f42db --- /dev/null +++ b/plugins/feature/afc/afc.h @@ -0,0 +1,184 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2020 Edouard Griffiths, F4EXB // +// // +// This program is free software; you can redistribute it and/or modify // +// it under the terms of the GNU General Public License as published by // +// the Free Software Foundation as version 3 of the License, or // +// (at your option) any later version. // +// // +// This program is distributed in the hope that it will be useful, // +// but WITHOUT ANY WARRANTY; without even the implied warranty of // +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // +// GNU General Public License V3 for more details. // +// // +// You should have received a copy of the GNU General Public License // +// along with this program. If not, see . // +/////////////////////////////////////////////////////////////////////////////////// + +#ifndef INCLUDE_FEATURE_AFC_H_ +#define INCLUDE_FEATURE_AFC_H_ + +#include +#include + +#include "feature/feature.h" +#include "util/message.h" + +#include "afcsettings.h" + +class QNetworkAccessManager; +class QNetworkReply; +class WebAPIAdapterInterface; +class DeviceSet; +class AFCWorker; + +namespace SWGSDRangel { + class SWGDeviceState; +} + +class AFC : public Feature +{ + Q_OBJECT +public: + class MsgConfigureAFC : public Message { + MESSAGE_CLASS_DECLARATION + + public: + const AFCSettings& getSettings() const { return m_settings; } + bool getForce() const { return m_force; } + + static MsgConfigureAFC* create(const AFCSettings& settings, bool force) { + return new MsgConfigureAFC(settings, force); + } + + private: + AFCSettings m_settings; + bool m_force; + + MsgConfigureAFC(const AFCSettings& settings, bool force) : + Message(), + m_settings(settings), + m_force(force) + { } + }; + + class MsgStartStop : public Message { + MESSAGE_CLASS_DECLARATION + + public: + bool getStartStop() const { return m_startStop; } + + static MsgStartStop* create(bool startStop) { + return new MsgStartStop(startStop); + } + + protected: + bool m_startStop; + + MsgStartStop(bool startStop) : + Message(), + m_startStop(startStop) + { } + }; + + class MsgDeviceTrack : public Message { + MESSAGE_CLASS_DECLARATION + + public: + static MsgDeviceTrack* create() { + return new MsgDeviceTrack(); + } + protected: + MsgDeviceTrack() : + Message() + { } + }; + + class MsgDevicesApply : public Message { + MESSAGE_CLASS_DECLARATION + + public: + static MsgDevicesApply* create() { + return new MsgDevicesApply(); + } + protected: + MsgDevicesApply() : + Message() + { } + }; + + AFC(WebAPIAdapterInterface *webAPIAdapterInterface); + virtual ~AFC(); + virtual void destroy() { delete this; } + virtual bool handleMessage(const Message& cmd); + + virtual const QString& getURI() const { return m_featureIdURI; } + virtual void getIdentifier(QString& id) const { id = m_featureId; } + virtual void getTitle(QString& title) const { title = m_settings.m_title; } + + virtual QByteArray serialize() const; + virtual bool deserialize(const QByteArray& data); + + virtual int webapiRun(bool run, + SWGSDRangel::SWGDeviceState& response, + QString& errorMessage); + + virtual int webapiSettingsGet( + SWGSDRangel::SWGFeatureSettings& response, + QString& errorMessage); + + virtual int webapiSettingsPutPatch( + bool force, + const QStringList& featureSettingsKeys, + SWGSDRangel::SWGFeatureSettings& response, + QString& errorMessage); + + virtual int webapiReportGet( + SWGSDRangel::SWGFeatureReport& response, + QString& errorMessage); + + virtual int webapiActionsPost( + const QStringList& featureActionsKeys, + SWGSDRangel::SWGFeatureActions& query, + QString& errorMessage); + + static void webapiFormatFeatureSettings( + SWGSDRangel::SWGFeatureSettings& response, + const AFCSettings& settings); + + static void webapiUpdateFeatureSettings( + AFCSettings& settings, + const QStringList& featureSettingsKeys, + SWGSDRangel::SWGFeatureSettings& response); + + static const QString m_featureIdURI; + static const QString m_featureId; + +private: + QThread m_thread; + AFCWorker *m_worker; + AFCSettings m_settings; + DeviceSet *m_trackerDeviceSet; + DeviceSet *m_trackedDeviceSet; + int m_trackerIndexInDeviceSet; + ChannelAPI *m_trackerChannelAPI; + QList m_trackedChannelAPIs; + + QNetworkAccessManager *m_networkManager; + QNetworkRequest m_networkRequest; + + void start(); + void stop(); + void applySettings(const AFCSettings& settings, bool force = false); + void webapiFormatFeatureReport(SWGSDRangel::SWGFeatureReport& response); + void webapiReverseSendSettings(QList& featureSettingsKeys, const AFCSettings& settings, bool force); + void trackerDeviceChange(int deviceIndex); + void trackedDeviceChange(int deviceIndex); + void removeTrackerFeatureReference(); + void removeTrackedFeatureReferences(); + +private slots: + void networkManagerFinished(QNetworkReply *reply); +}; + +#endif // INCLUDE_FEATURE_AFC_H_ diff --git a/plugins/feature/afc/afcgui.cpp b/plugins/feature/afc/afcgui.cpp new file mode 100644 index 000000000..c33552469 --- /dev/null +++ b/plugins/feature/afc/afcgui.cpp @@ -0,0 +1,417 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2020 Edouard Griffiths, F4EXB // +// // +// This program is free software; you can redistribute it and/or modify // +// it under the terms of the GNU General Public License as published by // +// the Free Software Foundation as version 3 of the License, or // +// (at your option) any later version. // +// // +// This program is distributed in the hope that it will be useful, // +// but WITHOUT ANY WARRANTY; without even the implied warranty of // +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // +// GNU General Public License V3 for more details. // +// // +// You should have received a copy of the GNU General Public License // +// along with this program. If not, see . // +/////////////////////////////////////////////////////////////////////////////////// + +#include + +#include "feature/featureuiset.h" +#include "device/deviceset.h" +#include "channel/channelapi.h" +#include "gui/basicfeaturesettingsdialog.h" +#include "maincore.h" + +#include "ui_afcgui.h" +#include "afcreport.h" +#include "afc.h" +#include "afcgui.h" + +AFCGUI* AFCGUI::create(PluginAPI* pluginAPI, FeatureUISet *featureUISet, Feature *feature) +{ + AFCGUI* gui = new AFCGUI(pluginAPI, featureUISet, feature); + return gui; +} + +void AFCGUI::destroy() +{ + delete this; +} + +void AFCGUI::resetToDefaults() +{ + m_settings.resetToDefaults(); + displaySettings(); + applySettings(true); +} + +QByteArray AFCGUI::serialize() const +{ + return m_settings.serialize(); +} + +bool AFCGUI::deserialize(const QByteArray& data) +{ + if (m_settings.deserialize(data)) + { + displaySettings(); + applySettings(true); + return true; + } + else + { + resetToDefaults(); + return false; + } +} + +bool AFCGUI::handleMessage(const Message& message) +{ + if (AFC::MsgConfigureAFC::match(message)) + { + qDebug("AFCGUI::handleMessage: AFC::MsgConfigureAFC"); + const AFC::MsgConfigureAFC& cfg = (AFC::MsgConfigureAFC&) message; + m_settings = cfg.getSettings(); + blockApplySettings(true); + displaySettings(); + blockApplySettings(false); + + return true; + } + else if (AFCReport::MsgUpdateTarget::match(message)) + { + const AFCReport::MsgUpdateTarget& cfg = (AFCReport::MsgUpdateTarget&) message; + bool frequencyChanged = cfg.getFrequencyChanged(); + + if (cfg.getFrequencyChanged()) { + ui->statusIndicator->setStyleSheet("QLabel { background-color: rgb(232, 85, 85); border-radius: 8px; }"); // red + } else { + ui->statusIndicator->setStyleSheet("QLabel { background-color: rgb(85, 232, 85); border-radius: 8px; }"); // green + } + + ui->statusIndicator->setToolTip(tr("%1 Hz").arg(cfg.getFrequencyAdjustment())); + m_autoTargetStatusTimer.start(500); + return true; + } + + return false; +} + +void AFCGUI::handleInputMessages() +{ + Message* message; + + while ((message = getInputMessageQueue()->pop())) + { + if (handleMessage(*message)) { + delete message; + } + } +} + +void AFCGUI::onWidgetRolled(QWidget* widget, bool rollDown) +{ + (void) widget; + (void) rollDown; +} + +AFCGUI::AFCGUI(PluginAPI* pluginAPI, FeatureUISet *featureUISet, Feature *feature, QWidget* parent) : + FeatureGUI(parent), + ui(new Ui::AFCGUI), + m_pluginAPI(pluginAPI), + m_featureUISet(featureUISet), + m_doApplySettings(true), + m_lastFeatureState(0) +{ + ui->setupUi(this); + setAttribute(Qt::WA_DeleteOnClose, true); + + ui->targetFrequency->setColorMapper(ColorMapper(ColorMapper::GrayGold)); + ui->targetFrequency->setValueRange(10, 0, 9999999999L); + + ui->toleranceFrequency->setColorMapper(ColorMapper(ColorMapper::GrayYellow)); + ui->toleranceFrequency->setValueRange(5, 0, 99999L); + + setChannelWidget(false); + connect(this, SIGNAL(widgetRolled(QWidget*,bool)), this, SLOT(onWidgetRolled(QWidget*,bool))); + m_afc = reinterpret_cast(feature); + m_afc->setMessageQueueToGUI(&m_inputMessageQueue); + + m_featureUISet->addRollupWidget(this); + + connect(this, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(onMenuDialogCalled(const QPoint &))); + connect(getInputMessageQueue(), SIGNAL(messageEnqueued()), this, SLOT(handleInputMessages())); + + connect(&m_statusTimer, SIGNAL(timeout()), this, SLOT(updateStatus())); + m_statusTimer.start(1000); + + connect(&m_autoTargetStatusTimer, SIGNAL(timeout()), this, SLOT(resetAutoTargetStatus())); + m_autoTargetStatusTimer.setSingleShot(true); + ui->statusIndicator->setStyleSheet("QLabel { background-color: gray; border-radius: 8px; }"); + + updateDeviceSetLists(); + displaySettings(); + applySettings(true); +} + +AFCGUI::~AFCGUI() +{ + delete ui; +} + +void AFCGUI::blockApplySettings(bool block) +{ + m_doApplySettings = !block; +} + +void AFCGUI::displaySettings() +{ + setTitleColor(m_settings.m_rgbColor); + setWindowTitle(m_settings.m_title); + blockApplySettings(true); + ui->hasTargetFrequency->setChecked(m_settings.m_hasTargetFrequency); + ui->transverterTarget->setChecked(m_settings.m_transverterTarget); + ui->targetFrequency->setValue(m_settings.m_targetFrequency); + ui->toleranceFrequency->setValue(m_settings.m_freqTolerance); + ui->targetPeriod->setValue(m_settings.m_trackerAdjustPeriod); + ui->targetPeriodText->setText(tr("%1").arg(m_settings.m_trackerAdjustPeriod)); + blockApplySettings(false); +} + +void AFCGUI::updateDeviceSetLists() +{ + MainCore *mainCore = MainCore::instance(); + std::vector& deviceSets = mainCore->getDeviceSets(); + std::vector::const_iterator it = deviceSets.begin(); + + ui->trackerDevice->blockSignals(true); + ui->trackedDevice->blockSignals(true); + + ui->trackerDevice->clear(); + ui->trackedDevice->clear(); + + unsigned int deviceIndex = 0; + + for (; it != deviceSets.end(); ++it, deviceIndex++) + { + DSPDeviceSourceEngine *deviceSourceEngine = (*it)->m_deviceSourceEngine; + DSPDeviceSinkEngine *deviceSinkEngine = (*it)->m_deviceSinkEngine; + + if (deviceSourceEngine) { + ui->trackedDevice->addItem(QString("R%1").arg(deviceIndex), deviceIndex); + } else if (deviceSinkEngine) { + ui->trackedDevice->addItem(QString("T%1").arg(deviceIndex), deviceIndex); + } + + for (int chi = 0; chi < (*it)->getNumberOfChannels(); chi++) + { + ChannelAPI *channel = (*it)->getChannelAt(chi); + + if (channel->getURI() == "sdrangel.channel.freqtracker") + { + ui->trackerDevice->addItem(QString("R%1").arg(deviceIndex), deviceIndex); + break; + } + } + } + + int trackedDeviceIndex; + int trackerDeviceIndex; + + if (deviceIndex > 0) + { + if (m_settings.m_trackedDeviceSetIndex < 0) { + ui->trackedDevice->setCurrentIndex(0); + } else { + ui->trackedDevice->setCurrentIndex(m_settings.m_trackedDeviceSetIndex); + } + + if (m_settings.m_trackerDeviceSetIndex < 0) { + ui->trackerDevice->setCurrentIndex(0); + } else { + ui->trackerDevice->setCurrentIndex(m_settings.m_trackerDeviceSetIndex); + } + + trackedDeviceIndex = ui->trackedDevice->currentData().toInt(); + trackerDeviceIndex = ui->trackerDevice->currentData().toInt(); + } + else + { + trackedDeviceIndex = -1; + trackerDeviceIndex = -1; + } + + if ((trackedDeviceIndex != m_settings.m_trackedDeviceSetIndex) || + (trackerDeviceIndex != m_settings.m_trackerDeviceSetIndex)) + { + qDebug("AFCGUI::updateDeviceSetLists: device index changed: %d:%d", trackerDeviceIndex, trackedDeviceIndex); + m_settings.m_trackerDeviceSetIndex = trackerDeviceIndex; + m_settings.m_trackedDeviceSetIndex = trackedDeviceIndex; + applySettings(); + } + + ui->trackerDevice->blockSignals(false); + ui->trackedDevice->blockSignals(false); +} + +void AFCGUI::leaveEvent(QEvent*) +{ +} + +void AFCGUI::enterEvent(QEvent*) +{ +} + +void AFCGUI::onMenuDialogCalled(const QPoint &p) +{ + if (m_contextMenuType == ContextMenuChannelSettings) + { + BasicFeatureSettingsDialog dialog(this); + dialog.setTitle(m_settings.m_title); + dialog.setColor(m_settings.m_rgbColor); + dialog.setUseReverseAPI(m_settings.m_useReverseAPI); + dialog.setReverseAPIAddress(m_settings.m_reverseAPIAddress); + dialog.setReverseAPIPort(m_settings.m_reverseAPIPort); + dialog.setReverseAPIFeatureSetIndex(m_settings.m_reverseAPIFeatureSetIndex); + dialog.setReverseAPIFeatureIndex(m_settings.m_reverseAPIFeatureIndex); + + dialog.move(p); + dialog.exec(); + + m_settings.m_rgbColor = dialog.getColor().rgb(); + m_settings.m_title = dialog.getTitle(); + m_settings.m_useReverseAPI = dialog.useReverseAPI(); + m_settings.m_reverseAPIAddress = dialog.getReverseAPIAddress(); + m_settings.m_reverseAPIPort = dialog.getReverseAPIPort(); + m_settings.m_reverseAPIFeatureSetIndex = dialog.getReverseAPIFeatureSetIndex(); + m_settings.m_reverseAPIFeatureIndex = dialog.getReverseAPIFeatureIndex(); + + setWindowTitle(m_settings.m_title); + setTitleColor(m_settings.m_rgbColor); + + applySettings(); + } + + resetContextMenuType(); +} + +void AFCGUI::on_startStop_toggled(bool checked) +{ + if (m_doApplySettings) + { + AFC::MsgStartStop *message = AFC::MsgStartStop::create(checked); + m_afc->getInputMessageQueue()->push(message); + } +} + +void AFCGUI::on_hasTargetFrequency_toggled(bool checked) +{ + m_settings.m_hasTargetFrequency = checked; + applySettings(); +} + +void AFCGUI::on_targetFrequency_changed(quint64 value) +{ + m_settings.m_targetFrequency = value; + applySettings(); +} + +void AFCGUI::on_transverterTarget_toggled(bool checked) +{ + m_settings.m_transverterTarget = checked; + applySettings(); +} + + +void AFCGUI::on_toleranceFrequency_changed(quint64 value) +{ + m_settings.m_freqTolerance = value; + applySettings(); +} + +void AFCGUI::on_deviceTrack_clicked() +{ + AFC::MsgDeviceTrack *msg = AFC::MsgDeviceTrack::create(); + m_afc->getInputMessageQueue()->push(msg); +} + +void AFCGUI::on_devicesRefresh_clicked() +{ + updateDeviceSetLists(); + displaySettings(); +} + +void AFCGUI::on_trackerDevice_currentIndexChanged(int index) +{ + if (index >= 0) + { + m_settings.m_trackerDeviceSetIndex = index; + applySettings(); + } +} + +void AFCGUI::on_trackedDevice_currentIndexChanged(int index) +{ + if (index >= 0) + { + m_settings.m_trackedDeviceSetIndex = index; + applySettings(); + } +} + +void AFCGUI::on_devicesApply_clicked() +{ + AFC::MsgDevicesApply *msg = AFC::MsgDevicesApply::create(); + m_afc->getInputMessageQueue()->push(msg); +} + +void AFCGUI::on_targetPeriod_valueChanged(int value) +{ + m_settings.m_trackerAdjustPeriod = value; + ui->targetPeriodText->setText(tr("%1").arg(m_settings.m_trackerAdjustPeriod)); + applySettings(); +} + +void AFCGUI::updateStatus() +{ + int state = m_afc->getState(); + + if (m_lastFeatureState != state) + { + switch (state) + { + case Feature::StNotStarted: + ui->startStop->setStyleSheet("QToolButton { background:rgb(79,79,79); }"); + break; + case Feature::StIdle: + ui->startStop->setStyleSheet("QToolButton { background-color : blue; }"); + break; + case Feature::StRunning: + ui->startStop->setStyleSheet("QToolButton { background-color : green; }"); + break; + case Feature::StError: + ui->startStop->setStyleSheet("QToolButton { background-color : red; }"); + QMessageBox::information(this, tr("Message"), m_afc->getErrorMessage()); + break; + default: + break; + } + + m_lastFeatureState = state; + } +} + +void AFCGUI::resetAutoTargetStatus() +{ + ui->statusIndicator->setStyleSheet("QLabel { background-color: gray; border-radius: 8px; }"); +} + +void AFCGUI::applySettings(bool force) +{ + if (m_doApplySettings) + { + AFC::MsgConfigureAFC* message = AFC::MsgConfigureAFC::create( m_settings, force); + m_afc->getInputMessageQueue()->push(message); + } +} diff --git a/plugins/feature/afc/afcgui.h b/plugins/feature/afc/afcgui.h new file mode 100644 index 000000000..b9adbe79b --- /dev/null +++ b/plugins/feature/afc/afcgui.h @@ -0,0 +1,91 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2020 Edouard Griffiths, F4EXB // +// // +// This program is free software; you can redistribute it and/or modify // +// it under the terms of the GNU General Public License as published by // +// the Free Software Foundation as version 3 of the License, or // +// (at your option) any later version. // +// // +// This program is distributed in the hope that it will be useful, // +// but WITHOUT ANY WARRANTY; without even the implied warranty of // +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // +// GNU General Public License V3 for more details. // +// // +// You should have received a copy of the GNU General Public License // +// along with this program. If not, see . // +/////////////////////////////////////////////////////////////////////////////////// + +#ifndef INCLUDE_FEATURE_AFCGUI_H_ +#define INCLUDE_FEATURE_AFCGUI_H_ + +#include + +#include "feature/featuregui.h" +#include "util/messagequeue.h" +#include "afcsettings.h" + +class PluginAPI; +class FeatureUISet; +class AFC; + +namespace Ui { + class AFCGUI; +} + +class AFCGUI : public FeatureGUI { + Q_OBJECT +public: + static AFCGUI* create(PluginAPI* pluginAPI, FeatureUISet *featureUISet, Feature *feature); + virtual void destroy(); + + void resetToDefaults(); + QByteArray serialize() const; + bool deserialize(const QByteArray& data); + virtual MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; } + +private: + Ui::AFCGUI* ui; + PluginAPI* m_pluginAPI; + FeatureUISet* m_featureUISet; + AFCSettings m_settings; + bool m_doApplySettings; + + AFC* m_afc; + MessageQueue m_inputMessageQueue; + QTimer m_statusTimer; + QTimer m_autoTargetStatusTimer; + int m_lastFeatureState; + + explicit AFCGUI(PluginAPI* pluginAPI, FeatureUISet *featureUISet, Feature *feature, QWidget* parent = nullptr); + virtual ~AFCGUI(); + + void blockApplySettings(bool block); + void applySettings(bool force = false); + void displaySettings(); + void updateDeviceSetLists(); + bool handleMessage(const Message& message); + + void leaveEvent(QEvent*); + void enterEvent(QEvent*); + +private slots: + void onMenuDialogCalled(const QPoint &p); + void onWidgetRolled(QWidget* widget, bool rollDown); + void handleInputMessages(); + void on_startStop_toggled(bool checked); + void on_hasTargetFrequency_toggled(bool checked); + void on_targetFrequency_changed(quint64 value); + void on_transverterTarget_toggled(bool checked); + void on_toleranceFrequency_changed(quint64 value); + void on_deviceTrack_clicked(); + void on_devicesRefresh_clicked(); + void on_trackerDevice_currentIndexChanged(int index); + void on_trackedDevice_currentIndexChanged(int index); + void on_devicesApply_clicked(); + void on_targetPeriod_valueChanged(int value); + void updateStatus(); + void resetAutoTargetStatus(); +}; + + +#endif // INCLUDE_FEATURE_AFCGUI_H_ diff --git a/plugins/feature/afc/afcgui.ui b/plugins/feature/afc/afcgui.ui new file mode 100644 index 000000000..bb6c85553 --- /dev/null +++ b/plugins/feature/afc/afcgui.ui @@ -0,0 +1,431 @@ + + + AFCGUI + + + + 0 + 0 + 340 + 160 + + + + + 0 + 0 + + + + + 340 + 100 + + + + + Liberation Sans + 9 + + + + AFC + + + + + 0 + 0 + 340 + 151 + + + + Settings + + + + 3 + + + 2 + + + 2 + + + 2 + + + 2 + + + + + + + start/stop acquisition + + + + + + + :/play.png + :/stop.png:/play.png + + + + + + + + 24 + 16777215 + + + + Refresh indexes of available device sets + + + + + + + :/recycle.png:/recycle.png + + + + + + + Tracker + + + + + + + + 55 + 0 + + + + + 50 + 16777215 + + + + Tracker deviceset index + + + + + + + Tracked + + + + + + + + 55 + 0 + + + + + 50 + 16777215 + + + + Tracked deviceset index + + + + + + + + 24 + 24 + + + + Reinitialization of device data + + + + + + + :/arrow_left.png:/arrow_left.png + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + Tracker target frequency auto adjust + + + T + + + + + + + + 0 + 0 + + + + + 32 + 16 + + + + + Liberation Mono + 12 + + + + PointingHandCursor + + + Qt::StrongFocus + + + Tracker target tracker frequency in Hz + + + + + + + Hz + + + + + + + Use transverter frequency for tracker target frequency adjustment + + + X + + + + + + + + + + + + + + &plusmn; + + + Qt::RichText + + + + + + + + 0 + 0 + + + + + 32 + 16 + + + + + Liberation Mono + 12 + + + + PointingHandCursor + + + Qt::StrongFocus + + + Tracker target frequency error tolerance (Hz) + + + + + + + Hz + + + + + + + + 24 + 24 + + + + Tracker target frequency adjustment period (seconds) + + + 1 + + + 120 + + + 1 + + + 20 + + + + + + + + 24 + 0 + + + + Tracker target frequency adjustment period (seconds) + + + 000 + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + 24 + 24 + + + + Force tracker target frequency adjustment + + + + + + + :/arrow_left.png:/arrow_left.png + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 0 + 0 + + + + + 16 + 16 + + + + Idle + + + QLabel { background-color: gray; border-radius: 8px; } + + + + + + + + + + + + + + RollupWidget + QWidget +
gui/rollupwidget.h
+ 1 +
+ + ButtonSwitch + QToolButton +
gui/buttonswitch.h
+
+ + ValueDial + QWidget +
gui/valuedial.h
+ 1 +
+
+ + + + +
diff --git a/plugins/feature/afc/afcplugin.cpp b/plugins/feature/afc/afcplugin.cpp new file mode 100644 index 000000000..89bb77f3c --- /dev/null +++ b/plugins/feature/afc/afcplugin.cpp @@ -0,0 +1,80 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2020 Edouard Griffiths, F4EXB // +// // +// This program is free software; you can redistribute it and/or modify // +// it under the terms of the GNU General Public License as published by // +// the Free Software Foundation as version 3 of the License, or // +// (at your option) any later version. // +// // +// This program is distributed in the hope that it will be useful, // +// but WITHOUT ANY WARRANTY; without even the implied warranty of // +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // +// GNU General Public License V3 for more details. // +// // +// You should have received a copy of the GNU General Public License // +// along with this program. If not, see . // +/////////////////////////////////////////////////////////////////////////////////// + + +#include +#include "plugin/pluginapi.h" + +#ifndef SERVER_MODE +#include "afcgui.h" +#endif +#include "afc.h" +#include "afcplugin.h" +#include "afcwebapiadapter.h" + +const PluginDescriptor AFCPlugin::m_pluginDescriptor = { + AFC::m_featureId, + QString("AFC"), + QString("4.21.0"), + QString("(c) Edouard Griffiths, F4EXB"), + QString("https://github.com/f4exb/sdrangel"), + true, + QString("https://github.com/f4exb/sdrangel") +}; + +AFCPlugin::AFCPlugin(QObject* parent) : + QObject(parent), + m_pluginAPI(nullptr) +{ +} + +const PluginDescriptor& AFCPlugin::getPluginDescriptor() const +{ + return m_pluginDescriptor; +} + +void AFCPlugin::initPlugin(PluginAPI* pluginAPI) +{ + m_pluginAPI = pluginAPI; + + // register AFC feature + m_pluginAPI->registerFeature(AFC::m_featureIdURI, AFC::m_featureId, this); +} + +#ifdef SERVER_MODE +FeatureGUI* AFCPlugin::createFeatureGUI(FeatureUISet *featureUISet, Feature *feature) const +{ + (void) featureUISet; + (void) feature; + return nullptr; +} +#else +FeatureGUI* AFCPlugin::createFeatureGUI(FeatureUISet *featureUISet, Feature *feature) const +{ + return AFCGUI::create(m_pluginAPI, featureUISet, feature); +} +#endif + +Feature* AFCPlugin::createFeature(WebAPIAdapterInterface* webAPIAdapterInterface) const +{ + return new AFC(webAPIAdapterInterface); +} + +FeatureWebAPIAdapter* AFCPlugin::createFeatureWebAPIAdapter() const +{ + return new AFCWebAPIAdapter(); +} diff --git a/plugins/feature/afc/afcplugin.h b/plugins/feature/afc/afcplugin.h new file mode 100644 index 000000000..eea88635a --- /dev/null +++ b/plugins/feature/afc/afcplugin.h @@ -0,0 +1,48 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2020 Edouard Griffiths, F4EXB // +// // +// This program is free software; you can redistribute it and/or modify // +// it under the terms of the GNU General Public License as published by // +// the Free Software Foundation as version 3 of the License, or // +// (at your option) any later version. // +// // +// This program is distributed in the hope that it will be useful, // +// but WITHOUT ANY WARRANTY; without even the implied warranty of // +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // +// GNU General Public License V3 for more details. // +// // +// You should have received a copy of the GNU General Public License // +// along with this program. If not, see . // +/////////////////////////////////////////////////////////////////////////////////// + +#ifndef INCLUDE_FEATURE_AFCPLUGIN_H +#define INCLUDE_FEATURE_AFCPLUGIN_H + +#include +#include "plugin/plugininterface.h" + +class FeatureGUI; +class WebAPIAdapterInterface; + +class AFCPlugin : public QObject, PluginInterface { + Q_OBJECT + Q_INTERFACES(PluginInterface) + Q_PLUGIN_METADATA(IID "sdrangel.feature.afc") + +public: + explicit AFCPlugin(QObject* parent = nullptr); + + const PluginDescriptor& getPluginDescriptor() const; + void initPlugin(PluginAPI* pluginAPI); + + virtual FeatureGUI* createFeatureGUI(FeatureUISet *featureUISet, Feature *feature) const; + virtual Feature* createFeature(WebAPIAdapterInterface *webAPIAdapterInterface) const; + virtual FeatureWebAPIAdapter* createFeatureWebAPIAdapter() const; + +private: + static const PluginDescriptor m_pluginDescriptor; + + PluginAPI* m_pluginAPI; +}; + +#endif // INCLUDE_FEATURE_AFCPLUGIN_H diff --git a/plugins/feature/afc/afcreport.cpp b/plugins/feature/afc/afcreport.cpp new file mode 100644 index 000000000..a9ced7006 --- /dev/null +++ b/plugins/feature/afc/afcreport.cpp @@ -0,0 +1,26 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2020 Edouard Griffiths, F4EXB // +// // +// This program is free software; you can redistribute it and/or modify // +// it under the terms of the GNU General Public License as published by // +// the Free Software Foundation as version 3 of the License, or // +// (at your option) any later version. // +// // +// This program is distributed in the hope that it will be useful, // +// but WITHOUT ANY WARRANTY; without even the implied warranty of // +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // +// GNU General Public License V3 for more details. // +// // +// You should have received a copy of the GNU General Public License // +// along with this program. If not, see . // +/////////////////////////////////////////////////////////////////////////////////// + +#include "afcreport.h" + +MESSAGE_CLASS_DEFINITION(AFCReport::MsgUpdateTarget, Message) + +AFCReport::AFCReport() +{} + +AFCReport::~AFCReport() +{} diff --git a/plugins/feature/afc/afcreport.h b/plugins/feature/afc/afcreport.h new file mode 100644 index 000000000..47b6bf8ef --- /dev/null +++ b/plugins/feature/afc/afcreport.h @@ -0,0 +1,58 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2020 Edouard Griffiths, F4EXB // +// // +// This program is free software; you can redistribute it and/or modify // +// it under the terms of the GNU General Public License as published by // +// the Free Software Foundation as version 3 of the License, or // +// (at your option) any later version. // +// // +// This program is distributed in the hope that it will be useful, // +// but WITHOUT ANY WARRANTY; without even the implied warranty of // +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // +// GNU General Public License V3 for more details. // +// // +// You should have received a copy of the GNU General Public License // +// along with this program. If not, see . // +/////////////////////////////////////////////////////////////////////////////////// + +#ifndef INCLUDE_FEATURE_AFCREPORT_H_ +#define INCLUDE_FEATURE_AFCREPORT_H_ + +#include "util/message.h" + +class AFCReport +{ +public: + enum RadioState { + RadioIdle, + RadioRx, + RadioTx + }; + class MsgUpdateTarget : public Message { + MESSAGE_CLASS_DECLARATION + + public: + int getFrequencyAdjustment() const { return m_frequencyAdjustment; } + bool getFrequencyChanged() const { return m_frequencyChanged; } + + static MsgUpdateTarget* create(int frequencyAdjustment, bool frequencyChanged) + { + return new MsgUpdateTarget(frequencyAdjustment, frequencyChanged); + } + + private: + int m_frequencyAdjustment; + bool m_frequencyChanged; + + MsgUpdateTarget(int frequencyAdjustment, bool frequencyChanged) : + Message(), + m_frequencyAdjustment(frequencyAdjustment), + m_frequencyChanged(frequencyChanged) + { } + }; + + AFCReport(); + ~AFCReport(); +}; + +#endif // INCLUDE_FEATURE_AFCREPORT_H_ diff --git a/plugins/feature/afc/afcsettings.cpp b/plugins/feature/afc/afcsettings.cpp new file mode 100644 index 000000000..0b4b1fa7c --- /dev/null +++ b/plugins/feature/afc/afcsettings.cpp @@ -0,0 +1,118 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2020 Edouard Griffiths, F4EXB // +// // +// This program is free software; you can redistribute it and/or modify // +// it under the terms of the GNU General Public License as published by // +// the Free Software Foundation as version 3 of the License, or // +// (at your option) any later version. // +// // +// This program is distributed in the hope that it will be useful, // +// but WITHOUT ANY WARRANTY; without even the implied warranty of // +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // +// GNU General Public License V3 for more details. // +// // +// You should have received a copy of the GNU General Public License // +// along with this program. If not, see . // +/////////////////////////////////////////////////////////////////////////////////// + +#include + +#include "util/simpleserializer.h" +#include "settings/serializable.h" + +#include "afcsettings.h" + +AFCSettings::AFCSettings() +{ + resetToDefaults(); +} + +void AFCSettings::resetToDefaults() +{ + m_title = "AFC"; + m_rgbColor = QColor(255, 255, 0).rgb(); + m_trackerDeviceSetIndex = -1; + m_trackedDeviceSetIndex = -1; + m_hasTargetFrequency = false; + m_transverterTarget = false; + m_targetFrequency = 0; + m_freqTolerance = 1000; + m_trackerAdjustPeriod = 20; + m_useReverseAPI = false; + m_reverseAPIAddress = "127.0.0.1"; + m_reverseAPIPort = 8888; + m_reverseAPIFeatureSetIndex = 0; + m_reverseAPIFeatureIndex = 0; +} + +QByteArray AFCSettings::serialize() const +{ + SimpleSerializer s(1); + + s.writeString(1, m_title); + s.writeU32(2, m_rgbColor); + s.writeS32(3, m_trackerDeviceSetIndex); + s.writeU32(4, m_trackerAdjustPeriod); + s.writeS32(5, m_trackedDeviceSetIndex); + s.writeBool(6, m_hasTargetFrequency); + s.writeBool(7, m_transverterTarget); + s.writeU64(8, m_targetFrequency); + s.writeU64(9, m_freqTolerance); + s.writeBool(10, m_useReverseAPI); + s.writeString(11, m_reverseAPIAddress); + s.writeU32(12, m_reverseAPIPort); + s.writeU32(13, m_reverseAPIFeatureSetIndex); + s.writeU32(14, m_reverseAPIFeatureIndex); + + return s.final(); +} + +bool AFCSettings::deserialize(const QByteArray& data) +{ + SimpleDeserializer d(data); + + if(!d.isValid()) + { + resetToDefaults(); + return false; + } + + if(d.getVersion() == 1) + { + QByteArray bytetmp; + qint32 tmp; + uint32_t utmp; + QString strtmp; + + d.readString(1, &m_title, "AFC"); + d.readU32(2, &m_rgbColor, QColor(255, 255, 0).rgb()); + d.readS32(3, &m_trackerDeviceSetIndex, -1); + d.readU32(4, &m_trackerAdjustPeriod, 20); + d.readS32(5, &m_trackedDeviceSetIndex, -1); + d.readBool(6, &m_hasTargetFrequency, false); + d.readBool(7, &m_transverterTarget, false); + d.readU64(8, &m_targetFrequency, 0); + d.readU64(9, &m_freqTolerance, 1000); + d.readBool(10, &m_useReverseAPI, false); + d.readString(11, &m_reverseAPIAddress, "127.0.0.1"); + d.readU32(12, &utmp, 0); + + if ((utmp > 1023) && (utmp < 65535)) { + m_reverseAPIPort = utmp; + } else { + m_reverseAPIPort = 8888; + } + + d.readU32(13, &utmp, 0); + m_reverseAPIFeatureSetIndex = utmp > 99 ? 99 : utmp; + d.readU32(14, &utmp, 0); + m_reverseAPIFeatureIndex = utmp > 99 ? 99 : utmp; + + return true; + } + else + { + resetToDefaults(); + return false; + } +} diff --git a/plugins/feature/afc/afcsettings.h b/plugins/feature/afc/afcsettings.h new file mode 100644 index 000000000..a60022a64 --- /dev/null +++ b/plugins/feature/afc/afcsettings.h @@ -0,0 +1,49 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2020 Edouard Griffiths, F4EXB // +// // +// This program is free software; you can redistribute it and/or modify // +// it under the terms of the GNU General Public License as published by // +// the Free Software Foundation as version 3 of the License, or // +// (at your option) any later version. // +// // +// This program is distributed in the hope that it will be useful, // +// but WITHOUT ANY WARRANTY; without even the implied warranty of // +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // +// GNU General Public License V3 for more details. // +// // +// You should have received a copy of the GNU General Public License // +// along with this program. If not, see . // +/////////////////////////////////////////////////////////////////////////////////// + +#ifndef INCLUDE_FEATURE_AFCSETTINGS_H_ +#define INCLUDE_FEATURE_AFCSETTINGS_H_ + +#include +#include + +class Serializable; + +struct AFCSettings +{ + QString m_title; + quint32 m_rgbColor; + int m_trackerDeviceSetIndex; //!< will take the first instance of freq tracker in the list of channels + int m_trackedDeviceSetIndex; + bool m_hasTargetFrequency; + bool m_transverterTarget; + quint64 m_targetFrequency; + quint64 m_freqTolerance; + unsigned int m_trackerAdjustPeriod; //!< tracker channel frequency adjustment period in seconds + bool m_useReverseAPI; + QString m_reverseAPIAddress; + uint16_t m_reverseAPIPort; + uint16_t m_reverseAPIFeatureSetIndex; + uint16_t m_reverseAPIFeatureIndex; + + AFCSettings(); + void resetToDefaults(); + QByteArray serialize() const; + bool deserialize(const QByteArray& data); +}; + +#endif // INCLUDE_FEATURE_AFCSETTINGS_H_ diff --git a/plugins/feature/afc/afcwebapiadapter.cpp b/plugins/feature/afc/afcwebapiadapter.cpp new file mode 100644 index 000000000..a34c36ed1 --- /dev/null +++ b/plugins/feature/afc/afcwebapiadapter.cpp @@ -0,0 +1,50 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2020 Edouard Griffiths, F4EXB. // +// // +// This program is free software; you can redistribute it and/or modify // +// it under the terms of the GNU General Public License as published by // +// the Free Software Foundation as version 3 of the License, or // +// (at your option) any later version. // +// // +// This program is distributed in the hope that it will be useful, // +// but WITHOUT ANY WARRANTY; without even the implied warranty of // +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // +// GNU General Public License V3 for more details. // +// // +// You should have received a copy of the GNU General Public License // +// along with this program. If not, see . // +/////////////////////////////////////////////////////////////////////////////////// + +#include "SWGFeatureSettings.h" +#include "afc.h" +#include "afcwebapiadapter.h" + +AFCWebAPIAdapter::AFCWebAPIAdapter() +{} + +AFCWebAPIAdapter::~AFCWebAPIAdapter() +{} + +int AFCWebAPIAdapter::webapiSettingsGet( + SWGSDRangel::SWGFeatureSettings& response, + QString& errorMessage) +{ + (void) errorMessage; + response.setAfcSettings(new SWGSDRangel::SWGAFCSettings()); + response.getAfcSettings()->init(); + AFC::webapiFormatFeatureSettings(response, m_settings); + + return 200; +} + +int AFCWebAPIAdapter::webapiSettingsPutPatch( + bool force, + const QStringList& featureSettingsKeys, + SWGSDRangel::SWGFeatureSettings& response, + QString& errorMessage) +{ + (void) errorMessage; + AFC::webapiUpdateFeatureSettings(m_settings, featureSettingsKeys, response); + + return 200; +} diff --git a/plugins/feature/afc/afcwebapiadapter.h b/plugins/feature/afc/afcwebapiadapter.h new file mode 100644 index 000000000..f53cc6c42 --- /dev/null +++ b/plugins/feature/afc/afcwebapiadapter.h @@ -0,0 +1,49 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2020 Edouard Griffiths, F4EXB. // +// // +// This program is free software; you can redistribute it and/or modify // +// it under the terms of the GNU General Public License as published by // +// the Free Software Foundation as version 3 of the License, or // +// (at your option) any later version. // +// // +// This program is distributed in the hope that it will be useful, // +// but WITHOUT ANY WARRANTY; without even the implied warranty of // +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // +// GNU General Public License V3 for more details. // +// // +// You should have received a copy of the GNU General Public License // +// along with this program. If not, see . // +/////////////////////////////////////////////////////////////////////////////////// + +#ifndef INCLUDE_AFC_WEBAPIADAPTER_H +#define INCLUDE_AFC_WEBAPIADAPTER_H + +#include "feature/featurewebapiadapter.h" +#include "afcsettings.h" + +/** + * Standalone API adapter only for the settings + */ +class AFCWebAPIAdapter : public FeatureWebAPIAdapter { +public: + AFCWebAPIAdapter(); + virtual ~AFCWebAPIAdapter(); + + virtual QByteArray serialize() const { return m_settings.serialize(); } + virtual bool deserialize(const QByteArray& data) { return m_settings.deserialize(data); } + + virtual int webapiSettingsGet( + SWGSDRangel::SWGFeatureSettings& response, + QString& errorMessage); + + virtual int webapiSettingsPutPatch( + bool force, + const QStringList& featureSettingsKeys, + SWGSDRangel::SWGFeatureSettings& response, + QString& errorMessage); + +private: + AFCSettings m_settings; +}; + +#endif // INCLUDE_AFC_WEBAPIADAPTER_H diff --git a/plugins/feature/afc/afcworker.cpp b/plugins/feature/afc/afcworker.cpp new file mode 100644 index 000000000..6d6c2aec4 --- /dev/null +++ b/plugins/feature/afc/afcworker.cpp @@ -0,0 +1,532 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2020 Edouard Griffiths, F4EXB // +// // +// This program is free software; you can redistribute it and/or modify // +// it under the terms of the GNU General Public License as published by // +// the Free Software Foundation as version 3 of the License, or // +// (at your option) any later version. // +// // +// This program is distributed in the hope that it will be useful, // +// but WITHOUT ANY WARRANTY; without even the implied warranty of // +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // +// GNU General Public License V3 for more details. // +// // +// You should have received a copy of the GNU General Public License // +// along with this program. If not, see . // +/////////////////////////////////////////////////////////////////////////////////// + +#include + +#include "SWGDeviceState.h" +#include "SWGSuccessResponse.h" +#include "SWGDeviceSettings.h" +#include "SWGChannelSettings.h" +#include "SWGErrorResponse.h" + +#include "webapi/webapiadapterinterface.h" +#include "webapi/webapiutils.h" +#include "device/deviceset.h" +#include "device/deviceapi.h" +#include "channel/channelapi.h" +#include "feature/feature.h" +#include "maincore.h" + +#include "afcreport.h" +#include "afcworker.h" + +MESSAGE_CLASS_DEFINITION(AFCWorker::MsgConfigureAFCWorker, Message) +MESSAGE_CLASS_DEFINITION(AFCWorker::MsgTrackedDeviceChange, Message) +MESSAGE_CLASS_DEFINITION(AFCWorker::MsgDeviceTrack, Message) +MESSAGE_CLASS_DEFINITION(AFCWorker::MsgDevicesApply, Message) + +AFCWorker::AFCWorker(WebAPIAdapterInterface *webAPIAdapterInterface) : + m_webAPIAdapterInterface(webAPIAdapterInterface), + m_msgQueueToGUI(nullptr), + m_running(false), + m_freqTracker(nullptr), + m_trackerDeviceFrequency(0), + m_trackerChannelOffset(0), + m_mutex(QMutex::Recursive) +{ + qDebug("AFCWorker::AFCWorker"); + connect(&m_updateTimer, SIGNAL(timeout()), this, SLOT(updateTarget())); + + if (m_settings.m_hasTargetFrequency) { + m_updateTimer.start(m_settings.m_trackerAdjustPeriod * 1000); + } +} + +AFCWorker::~AFCWorker() +{ + m_inputMessageQueue.clear(); +} + +void AFCWorker::reset() +{ + QMutexLocker mutexLocker(&m_mutex); + m_inputMessageQueue.clear(); +} + +bool AFCWorker::startWork() +{ + QMutexLocker mutexLocker(&m_mutex); + connect(&m_inputMessageQueue, SIGNAL(messageEnqueued()), this, SLOT(handleInputMessages())); + m_running = true; + return m_running; +} + +void AFCWorker::stopWork() +{ + QMutexLocker mutexLocker(&m_mutex); + disconnect(&m_inputMessageQueue, SIGNAL(messageEnqueued()), this, SLOT(handleInputMessages())); + m_running = false; +} + +void AFCWorker::handleInputMessages() +{ + Message* message; + + while ((message = m_inputMessageQueue.pop()) != nullptr) + { + if (handleMessage(*message)) { + delete message; + } + } +} + +bool AFCWorker::handleMessage(const Message& cmd) +{ + if (MsgConfigureAFCWorker::match(cmd)) + { + qDebug() << "AFCWorker::handleMessage: MsgConfigureAFCWorker"; + QMutexLocker mutexLocker(&m_mutex); + MsgConfigureAFCWorker& cfg = (MsgConfigureAFCWorker&) cmd; + + applySettings(cfg.getSettings(), cfg.getForce()); + + return true; + } + else if (Feature::MsgChannelSettings::match(cmd)) + { + QMutexLocker mutexLocker(&m_mutex); + Feature::MsgChannelSettings& cfg = (Feature::MsgChannelSettings&) cmd; + SWGSDRangel::SWGChannelSettings *swgChannelSettings = cfg.getSWGSettings(); + qDebug() << "AFCWorker::handleMessage: Feature::MsgChannelSettings:" << *swgChannelSettings->getChannelType(); + processChannelSettings(cfg.getChannelAPI(), cfg.getChannelSettingsKeys(), swgChannelSettings); + + delete swgChannelSettings; + return true; + } + else if (MsgDeviceTrack::match(cmd)) + { + qDebug() << "AFCWorker::handleMessage: MsgDeviceTrack"; + QMutexLocker mutexLocker(&m_mutex); + updateTarget(); + return true; + } + else if (MsgDevicesApply::match(cmd)) + { + qDebug() << "AFCWorker::handleMessage: MsgDevicesApply"; + QMutexLocker mutexLocker(&m_mutex); + initTrackerDeviceSet(m_settings.m_trackerDeviceSetIndex); + initTrackedDeviceSet(m_settings.m_trackedDeviceSetIndex); + return true; + } + else + { + return false; + } +} + +void AFCWorker::applySettings(const AFCSettings& settings, bool force) +{ + qDebug() << "AFCWorker::applySettings:" + << " m_title: " << settings.m_title + << " m_rgbColor: " << settings.m_rgbColor + << " m_trackerDeviceSetIndex: " << settings.m_trackerDeviceSetIndex + << " m_trackedDeviceSetIndex: " << settings.m_trackedDeviceSetIndex + << " m_hasTargetFrequency: " << settings.m_hasTargetFrequency + << " m_transverterTarget: " << settings.m_transverterTarget + << " m_targetFrequency: " << settings.m_targetFrequency + << " m_freqTolerance: " << settings.m_freqTolerance + << " force: " << force; + + if ((settings.m_trackerDeviceSetIndex != m_settings.m_trackerDeviceSetIndex) || force) { + initTrackerDeviceSet(settings.m_trackerDeviceSetIndex); + } + + if ((settings.m_trackedDeviceSetIndex != m_settings.m_trackedDeviceSetIndex) || force) { + initTrackedDeviceSet(settings.m_trackedDeviceSetIndex); + } + + if ((settings.m_trackerAdjustPeriod != m_settings.m_trackerAdjustPeriod) || force) { + m_updateTimer.setInterval(settings.m_trackerAdjustPeriod * 1000); + } + + if ((settings.m_hasTargetFrequency != m_settings.m_hasTargetFrequency) || force) + { + if (settings.m_hasTargetFrequency) { + m_updateTimer.start(m_settings.m_trackerAdjustPeriod * 1000); + } else { + m_updateTimer.stop(); + } + } + + m_settings = settings; +} + + +void AFCWorker::initTrackerDeviceSet(int deviceSetIndex) +{ + MainCore *mainCore = MainCore::instance(); + m_trackerDeviceSet = mainCore->getDeviceSets()[deviceSetIndex]; + + for (int i = 0; i < m_trackerDeviceSet->getNumberOfChannels(); i++) + { + ChannelAPI *channel = m_trackerDeviceSet->getChannelAt(i); + + if (channel->getURI() == "sdrangel.channel.freqtracker") + { + m_freqTracker = channel; + SWGSDRangel::SWGDeviceSettings resDevice; + SWGSDRangel::SWGChannelSettings resChannel; + SWGSDRangel::SWGErrorResponse error; + + int rc = m_webAPIAdapterInterface->devicesetDeviceSettingsGet(deviceSetIndex, resDevice, error); + + if (rc / 100 == 2) + { + QJsonObject *jsonObj = resDevice.asJsonObject(); + QJsonValue freqValue; + + if (WebAPIUtils::extractValue(*jsonObj, "centerFrequency", freqValue)) + { + double freq = freqValue.toDouble(); + m_trackerDeviceFrequency = freq; + } + else + { + qDebug() << "AFCWorker::initTrackerDeviceSet: cannot find device frequency"; + } + } + else + { + qDebug() << "AFCWorker::initTrackerDeviceSet: devicesetDeviceSettingsGet error" << rc << ":" << *error.getMessage(); + } + + + rc = m_webAPIAdapterInterface->devicesetChannelSettingsGet(deviceSetIndex, i, resChannel, error); + + if (rc / 100 == 2) { + m_trackerChannelOffset = resChannel.getFreqTrackerSettings()->getInputFrequencyOffset(); + } else { + qDebug() << "AFCWorker::initTrackerDeviceSet: devicesetChannelSettingsGet error" << rc << ":" << *error.getMessage(); + } + + break; + } + } +} + +void AFCWorker::initTrackedDeviceSet(int deviceSetIndex) +{ + MainCore *mainCore = MainCore::instance(); + m_trackedDeviceSet = mainCore->getDeviceSets()[deviceSetIndex]; + m_channelsMap.clear(); + + for (int i = 0; i < m_trackedDeviceSet->getNumberOfChannels(); i++) + { + ChannelAPI *channel = m_trackedDeviceSet->getChannelAt(i); + + if (channel->getURI() != "sdrangel.channel.freqtracker") + { + SWGSDRangel::SWGChannelSettings resChannel; + SWGSDRangel::SWGErrorResponse error; + + int rc = m_webAPIAdapterInterface->devicesetChannelSettingsGet(deviceSetIndex, i, resChannel, error); + + if (rc / 100 == 2) + { + QJsonObject *jsonObj = resChannel.asJsonObject(); + QJsonValue directionValue; + QJsonValue channelOffsetValue; + + if (WebAPIUtils::extractValue(*jsonObj, "direction", directionValue)) + { + int direction = directionValue.toInt(); + + if (WebAPIUtils::extractValue(*jsonObj, "inputFrequencyOffset", channelOffsetValue)) + { + int channelOffset = channelOffsetValue.toInt(); + m_channelsMap.insert(channel, ChannelTracking{channelOffset, m_trackerChannelOffset, direction}); + } + else + { + qDebug() << "AFCWorker::initTrackedDeviceSet: cannot find channel offset frequency"; + } + } + else + { + qDebug() << "AFCWorker::initTrackedDeviceSet: cannot find channel direction"; + } + } + else + { + qDebug() << "AFCWorker::initTrackedDeviceSet: devicesetChannelSettingsGet error" << rc << ":" << *error.getMessage(); + } + } + } +} + +void AFCWorker::processChannelSettings( + const ChannelAPI *channelAPI, + const QList &channelSettingsKeys, + SWGSDRangel::SWGChannelSettings *swgChannelSettings) +{ + MainCore *mainCore = MainCore::instance(); + QJsonObject *jsonObj = swgChannelSettings->asJsonObject(); + QJsonValue channelOffsetValue; + + if (WebAPIUtils::extractValue(*jsonObj, "inputFrequencyOffset", channelOffsetValue)) + { + if (*swgChannelSettings->getChannelType() == "FreqTracker") + { + int trackerChannelOffset = channelOffsetValue.toInt(); + + if (trackerChannelOffset != m_trackerChannelOffset) + { + qDebug("AFCWorker::processChannelSettings: FreqTracker offset change: %d", trackerChannelOffset); + m_trackerChannelOffset = trackerChannelOffset; + QMap::iterator it = m_channelsMap.begin(); + + for (; it != m_channelsMap.end(); ++it) + { + if (mainCore->existsChannel(it.key())) + { + int channelOffset = it.value().m_channelOffset + trackerChannelOffset - it.value().m_trackerOffset; + updateChannelOffset(it.key(), it.value().m_channelDirection, channelOffset); + } + else + { + m_channelsMap.erase(it); + } + } + } + } + else if (m_channelsMap.contains(const_cast(channelAPI))) + { + int channelOffset = channelOffsetValue.toInt(); + m_channelsMap[const_cast(channelAPI)].m_channelOffset = channelOffset; + m_channelsMap[const_cast(channelAPI)].m_trackerOffset = m_trackerChannelOffset; + } + } +} + +bool AFCWorker::updateChannelOffset(ChannelAPI *channelAPI, int direction, int offset, unsigned int blockCount) +{ + SWGSDRangel::SWGChannelSettings swgChannelSettings; + SWGSDRangel::SWGErrorResponse errorResponse; + QString channelId; + channelAPI->getIdentifier(channelId); + swgChannelSettings.init(); + qDebug() << "AFCWorker::updateChannelOffset:" << channelId << ":" << offset; + + QStringList channelSettingsKeys; + channelSettingsKeys.append("inputFrequencyOffset"); + QString jsonSettingsStr = tr("\"inputFrequencyOffset\":%1").arg(offset); + + QString jsonStr = tr("{ \"channelType\": \"%1\", \"direction\": \"%2\", \"%3Settings\": {%4}}") + .arg(QString(channelId)) + .arg(direction) + .arg(QString(channelId)) + .arg(jsonSettingsStr); + swgChannelSettings.fromJson(jsonStr); + + channelAPI->setFeatureSettingsFeedbackBlockCount(1); + int httpRC = m_webAPIAdapterInterface->devicesetChannelSettingsPutPatch( + m_trackedDeviceSet->getIndex(), + channelAPI->getIndexInDeviceSet(), + false, // PATCH + channelSettingsKeys, + swgChannelSettings, + errorResponse + ); + + if (httpRC / 100 != 2) + { + qDebug() << "AFCWorker::updateChannelOffset: error code" << httpRC << ":" << *errorResponse.getMessage(); + return false; + } + + return true; +} + +void AFCWorker::updateTarget() +{ + SWGSDRangel::SWGDeviceSettings resDevice; + SWGSDRangel::SWGChannelSettings resChannel; + SWGSDRangel::SWGErrorResponse error; + + int rc = m_webAPIAdapterInterface->devicesetDeviceSettingsGet(m_settings.m_trackerDeviceSetIndex, resDevice, error); + + if (rc / 100 == 2) + { + QJsonObject *jsonObj = resDevice.asJsonObject(); + QJsonValue freqValue; + + if (WebAPIUtils::extractValue(*jsonObj, "centerFrequency", freqValue)) + { + double freq = freqValue.toDouble(); + m_trackerDeviceFrequency = freq; + } + else + { + qDebug() << "AFCWorker::updateTarget: cannot find device frequency"; + return; + } + } + else + { + qDebug() << "AFCWorker::updateTarget: devicesetDeviceSettingsGet error" << rc << ":" << *error.getMessage(); + return; + } + + int64_t trackerFrequency = m_trackerDeviceFrequency + m_trackerChannelOffset; + int64_t correction = m_settings.m_targetFrequency - trackerFrequency; + int64_t tolerance = m_settings.m_freqTolerance; + + if ((correction > -tolerance) && (correction < tolerance)) + { + reportUpdateTarget(correction, false); + return; + } + + if (m_settings.m_transverterTarget) // act on transverter + { + QJsonObject *jsonObj = resDevice.asJsonObject(); + QJsonValue xverterFrequencyValue; + + // adjust transverter + if (WebAPIUtils::extractValue(*jsonObj, "transverterDeltaFrequency", xverterFrequencyValue)) + { + double xverterFrequency = xverterFrequencyValue.toDouble(); + updateDeviceFrequency(m_trackerDeviceSet, "transverterDeltaFrequency", xverterFrequency + correction); + } + else + { + qDebug() << "AFCWorker::updateTarget: cannot find device transverter frequency"; + return; + } + + // adjust tracker offset + if (updateChannelOffset(m_freqTracker, 0, m_trackerChannelOffset + correction, 1)) { + m_trackerChannelOffset += correction; + } + + reportUpdateTarget(correction, true); + } + else // act on device + { + QJsonObject *jsonObj = resDevice.asJsonObject(); + QJsonValue deviceFrequencyValue; + + if (WebAPIUtils::extractValue(*jsonObj, "centerFrequency", deviceFrequencyValue)) + { + double deviceFrequency = deviceFrequencyValue.toDouble(); + updateDeviceFrequency(m_trackerDeviceSet, "centerFrequency", deviceFrequency + correction); + } + else + { + qDebug() << "AFCWorker::updateTarget: cannot find device transverter frequency"; + return; + } + + reportUpdateTarget(correction, true); + } +} + +bool AFCWorker::updateDeviceFrequency(DeviceSet *deviceSet, const QString& key, int64_t frequency) +{ + SWGSDRangel::SWGDeviceSettings swgDeviceSettings; + SWGSDRangel::SWGErrorResponse errorResponse; + QStringList deviceSettingsKeys; + deviceSettingsKeys.append(key); + int deviceIndex = deviceSet->getIndex(); + DeviceAPI *deviceAPI = deviceSet->m_deviceAPI; + swgDeviceSettings.init(); + QString jsonSettingsStr = tr("\"%1\":%2").arg(key).arg(frequency); + QString deviceSettingsKey; + getDeviceSettingsKey(deviceAPI, deviceSettingsKey); + qDebug() << "AFCWorker::updateDeviceFrequency:" + << deviceAPI->getHardwareId() + << ":" << key + << ":" << frequency; + + QString jsonStr = tr("{ \"deviceHwType\": \"%1\", \"direction\": \"%2\", \"%3\": {%4}}") + .arg(deviceAPI->getHardwareId()) + .arg(getDeviceDirection(deviceAPI)) + .arg(deviceSettingsKey) + .arg(jsonSettingsStr); + swgDeviceSettings.fromJson(jsonStr); + + int httpRC = m_webAPIAdapterInterface->devicesetDeviceSettingsPutPatch + ( + deviceIndex, + false, // PATCH + deviceSettingsKeys, + swgDeviceSettings, + errorResponse + ); + + if (httpRC / 100 != 2) + { + qDebug("AFCWorker::updateDeviceFrequency: error %d: %s", httpRC, qPrintable(*errorResponse.getMessage())); + return false; + } + + return true; +} + +int AFCWorker::getDeviceDirection(DeviceAPI *deviceAPI) +{ + if (deviceAPI->getSampleSink()) { + return 1; + } else if (deviceAPI->getSampleMIMO()) { + return 2; + } + + return 0; +} + +void AFCWorker::getDeviceSettingsKey(DeviceAPI *deviceAPI, QString& settingsKey) +{ + const QString& deviceHwId = deviceAPI->getHardwareId(); + + if (deviceAPI->getSampleSink()) + { + if (WebAPIUtils::m_sinkDeviceHwIdToSettingsKey.contains(deviceHwId)) { + settingsKey = WebAPIUtils::m_sinkDeviceHwIdToSettingsKey[deviceHwId]; + } + } + else if (deviceAPI->getSampleMIMO()) + { + if (WebAPIUtils::m_mimoDeviceHwIdToSettingsKey.contains(deviceHwId)) { + settingsKey = WebAPIUtils::m_mimoDeviceHwIdToSettingsKey[deviceHwId]; + } + } + else + { + if (WebAPIUtils::m_sourceDeviceHwIdToSettingsKey.contains(deviceHwId)) { + settingsKey = WebAPIUtils::m_sourceDeviceHwIdToSettingsKey[deviceHwId]; + } + } +} + +void AFCWorker::reportUpdateTarget(int correction, bool done) +{ + if (m_msgQueueToGUI) + { + AFCReport::MsgUpdateTarget *msg = AFCReport::MsgUpdateTarget::create(correction, done); + m_msgQueueToGUI->push(msg); + } +} diff --git a/plugins/feature/afc/afcworker.h b/plugins/feature/afc/afcworker.h new file mode 100644 index 000000000..862e22607 --- /dev/null +++ b/plugins/feature/afc/afcworker.h @@ -0,0 +1,178 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2020 Edouard Griffiths, F4EXB // +// // +// This program is free software; you can redistribute it and/or modify // +// it under the terms of the GNU General Public License as published by // +// the Free Software Foundation as version 3 of the License, or // +// (at your option) any later version. // +// // +// This program is distributed in the hope that it will be useful, // +// but WITHOUT ANY WARRANTY; without even the implied warranty of // +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // +// GNU General Public License V3 for more details. // +// // +// You should have received a copy of the GNU General Public License // +// along with this program. If not, see . // +/////////////////////////////////////////////////////////////////////////////////// + +#ifndef INCLUDE_FEATURE_AFCWORKER_H_ +#define INCLUDE_FEATURE_AFCWORKER_H_ + +#include +#include +#include + +#include "util/message.h" +#include "util/messagequeue.h" + +#include "afcsettings.h" + +class WebAPIAdapterInterface; +class DeviceSet; +class ChannelAPI; + +class AFCWorker : public QObject +{ + Q_OBJECT +public: + class MsgConfigureAFCWorker : public Message { + MESSAGE_CLASS_DECLARATION + + public: + const AFCSettings& getSettings() const { return m_settings; } + bool getForce() const { return m_force; } + + static MsgConfigureAFCWorker* create(const AFCSettings& settings, bool force) + { + return new MsgConfigureAFCWorker(settings, force); + } + + private: + AFCSettings m_settings; + bool m_force; + + MsgConfigureAFCWorker(const AFCSettings& settings, bool force) : + Message(), + m_settings(settings), + m_force(force) + { } + }; + + class MsgTrackedDeviceChange : public Message { + MESSAGE_CLASS_DECLARATION + + public: + int getDeviceIndex() const { return m_deviceIndex; } + + static MsgTrackedDeviceChange* create(int deviceIndex) + { + return new MsgTrackedDeviceChange(deviceIndex); + } + + private: + int m_deviceIndex; + + MsgTrackedDeviceChange(int deviceIndex) : + Message(), + m_deviceIndex(deviceIndex) + { } + }; + + class MsgDeviceTrack : public Message { + MESSAGE_CLASS_DECLARATION + + public: + static MsgDeviceTrack* create() { + return new MsgDeviceTrack(); + } + protected: + MsgDeviceTrack() : + Message() + { } + }; + + class MsgDevicesApply : public Message { + MESSAGE_CLASS_DECLARATION + + public: + static MsgDevicesApply* create() { + return new MsgDevicesApply(); + } + protected: + MsgDevicesApply() : + Message() + { } + }; + + AFCWorker(WebAPIAdapterInterface *webAPIAdapterInterface); + ~AFCWorker(); + void reset(); + bool startWork(); + void stopWork(); + bool isRunning() const { return m_running; } + MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; } + void setMessageQueueToGUI(MessageQueue *messageQueue) { m_msgQueueToGUI = messageQueue; } + uint64_t getTrackerDeviceFrequency() const { return m_trackerDeviceFrequency; } + int getTrackerChannelOffset() const { return m_trackerChannelOffset; } + +private: + struct ChannelTracking + { + int m_channelOffset; + int m_trackerOffset; + int m_channelDirection; + + ChannelTracking() : + m_channelOffset(0), + m_trackerOffset(0), + m_channelDirection(0) + {} + + ChannelTracking(int channelOffset, int trackerOffset, int channelDirection) : + m_channelOffset(channelOffset), + m_trackerOffset(trackerOffset), + m_channelDirection(m_channelDirection) + {} + + ChannelTracking(const ChannelTracking& other) : + m_channelOffset(other.m_channelOffset), + m_trackerOffset(other.m_trackerOffset), + m_channelDirection(other.m_channelDirection) + {} + }; + + WebAPIAdapterInterface *m_webAPIAdapterInterface; + MessageQueue m_inputMessageQueue; //!< Queue for asynchronous inbound communication + MessageQueue *m_msgQueueToGUI; //!< Queue to report state to GUI + AFCSettings m_settings; + bool m_running; + DeviceSet *m_trackerDeviceSet; + DeviceSet *m_trackedDeviceSet; + ChannelAPI *m_freqTracker; + uint64_t m_trackerDeviceFrequency; + int m_trackerChannelOffset; + QMap m_channelsMap; + QTimer m_updateTimer; + QMutex m_mutex; + + bool handleMessage(const Message& cmd); + void applySettings(const AFCSettings& settings, bool force = false); + void initTrackerDeviceSet(int deviceSetIndex); + void initTrackedDeviceSet(int deviceSetIndex); + void processChannelSettings( + const ChannelAPI *channelAPI, + const QList &channelSettingsKeys, + SWGSDRangel::SWGChannelSettings *swgChannelSettings + ); + bool updateChannelOffset(ChannelAPI *channelAPI, int direction, int offset, unsigned int blockCount = 0); + bool updateDeviceFrequency(DeviceSet *deviceSet, const QString& key, int64_t frequency); + int getDeviceDirection(DeviceAPI *deviceAPI); + void getDeviceSettingsKey(DeviceAPI *deviceAPI, QString& settingsKey); + void reportUpdateTarget(int correction, bool done); + +private slots: + void updateTarget(); + void handleInputMessages(); +}; + +#endif // INCLUDE_FEATURE_SIMPLEPTTWORKER_H_ diff --git a/plugins/feature/afc/readme.md b/plugins/feature/afc/readme.md new file mode 100644 index 000000000..573280371 --- /dev/null +++ b/plugins/feature/afc/readme.md @@ -0,0 +1,67 @@ +

Automatic Frequency Control plugin

+ +

Introduction

+ +This plugin makes the link between a [frequency tracker](../../channelrx/freqtracker/readme.md) and other channels in order to have them controlled by the frequency tracker. Thus it closes the loop to effectively make an automatic frequency control system. + +

Interface

+ +![File source channel plugin GUI](../../../doc/img/AFC_plugin.png) + +

1: Start/Stop plugin

+ +This button starts or stops the plugin + +

2: Update device sets lists

+ +It updates the tracker device set and tracked device set combo boxes (3) and (4) respectively with the available device sets. + +

3: Tracker device set selection

+ +The first frequency tracker in this device set will be used to control frequency. Thus only Rx device sets can be selected. + +

4: Tracked device set selection

+ +All channels but frequency tracker(s) in this device set will have their offset frequency controlled by the frequency tracker selected with (3). + +

5: (Re)apply device sets selection

+ +Use this button to force evaluation of selected device sets i.e. the first frequency tracker used for tracking and the tracked channels. + +

6: Automatic target frequency readjustment

+ +When the frequency tracker drifts following the signal it is tracking its effective frequency will move accordingly. To avoid it going too far from a nominal frequency set by (7) the device or transverter frequency can be used to re-adjust the frequency tracker center frequency periodically. + +

7: Tracker target frequency

+ +This is the nominal frequency of the signal being tracked. For example (as in the picture) when tracking the QO-100 center beacon this is 10489.750 MHz thus with the transverter shift set at -250 kHz this is 489.750 MHz (The actual downconverted Rx frequency is 739.750 MHz). + +

8: Use transverter shift to adjust target frequency

+ +When unset the device center frequency is used and when set the device center frequency setting is unchanged and the transverter shift is adjusted. + +You would use the transverter adjustment for QO-100 tracking for example thus the resulting IF frequency is unchanged maintaining the center beacon around 489.750 MHz. + +The transverter shift can be adjusted down to the Hz but depending on the device actual steps such granularity may not be effectively achievable. + +

9: Target frequency tolerance

+ +Frequency readjustment will actually take place only if the frequency tracker frequency moves further away than ± this value from the nominal frequency (7). + +You should not choose a value that is too tight else the frequency tracker frequency will keep moving around the target frequency without stabilizing. In practice you may set a low value and trigger a single shot adjustment with the (11) button and once stabilized choose a value significantly higher than the offset from nominal that is obtained. + +Please note that if the device frequency adjustment is used the steps are in kHz so multiples of the kHz should be used. + +

10. Target frequency readjustment period (seconds)

+ +The target frequency readjustment is periodically activated and frequency change is effectively activated if the tracker frequency offset from nominal is larger than the tolerance (9). + +Depending on how fast the frequency drift occurs you should set a value in combination with the frequency tolerance (9) so that the frequency is not readjusted too frequently. + +

11. Activate target frequency readjustment immediately

+ +This forces target readjustment process described above immediately. + +

12. Target readjustement indicator

+ +This indicator will flash briefly when the readjustment process takes place. Its color is green if the frequency is not changed and is red if frequency changes. The tooltip shows the last frequency difference that was calculated. diff --git a/sdrbase/channel/channelapi.cpp b/sdrbase/channel/channelapi.cpp index fa8ecb183..8df494a05 100644 --- a/sdrbase/channel/channelapi.cpp +++ b/sdrbase/channel/channelapi.cpp @@ -21,10 +21,22 @@ #include "channelapi.h" ChannelAPI::ChannelAPI(const QString& name, StreamType streamType) : + m_featuresSettingsFeedbackBlockCount(0), m_streamType(streamType), m_name(name), m_indexInDeviceSet(-1), m_deviceSetIndex(0), m_deviceAPI(0), m_uid(UidCalculator::getNewObjectId()) -{ } \ No newline at end of file +{ } + +void ChannelAPI::addFeatureSettingsFeedback(Feature *feature) +{ + m_featuresSettingsFeedback.removeOne(feature); + m_featuresSettingsFeedback.append(feature); +} + +void ChannelAPI::removeFeatureSettingsFeedback(Feature *feature) +{ + m_featuresSettingsFeedback.removeOne(feature); +} diff --git a/sdrbase/channel/channelapi.h b/sdrbase/channel/channelapi.h index f1b5479fc..5d18a557e 100644 --- a/sdrbase/channel/channelapi.h +++ b/sdrbase/channel/channelapi.h @@ -22,11 +22,14 @@ #include #include +#include + #include #include "export.h" class DeviceAPI; +class Feature; namespace SWGSDRangel { @@ -116,12 +119,20 @@ public: void setDeviceAPI(DeviceAPI *deviceAPI) { m_deviceAPI = deviceAPI; } uint64_t getUID() const { return m_uid; } + // Features support + void addFeatureSettingsFeedback(Feature *feature); + void removeFeatureSettingsFeedback(Feature *feature); + void setFeatureSettingsFeedbackBlockCount(unsigned int count) { m_featuresSettingsFeedbackBlockCount = count; } + // MIMO support StreamType getStreamType() const { return m_streamType; } virtual int getNbSinkStreams() const = 0; virtual int getNbSourceStreams() const = 0; virtual qint64 getStreamCenterFrequency(int streamIndex, bool sinkElseSource) const = 0; +protected: + QList m_featuresSettingsFeedback; //!< list of features to report back settings changes in swagger API format + unsigned int m_featuresSettingsFeedbackBlockCount; //!< actually send feedback if 0. Decremented at each potential feedback private: StreamType m_streamType; diff --git a/sdrbase/feature/feature.cpp b/sdrbase/feature/feature.cpp index 75ce9f970..2af1a49c1 100644 --- a/sdrbase/feature/feature.cpp +++ b/sdrbase/feature/feature.cpp @@ -24,6 +24,8 @@ #include "feature.h" +MESSAGE_CLASS_DEFINITION(Feature::MsgChannelSettings, Message) + Feature::Feature(const QString& name, WebAPIAdapterInterface *webAPIAdapterInterface) : m_name(name), m_uid(UidCalculator::getNewObjectId()), diff --git a/sdrbase/feature/feature.h b/sdrbase/feature/feature.h index f41b79e21..06e8a08f2 100644 --- a/sdrbase/feature/feature.h +++ b/sdrbase/feature/feature.h @@ -29,6 +29,7 @@ #include "util/messagequeue.h" class WebAPIAdapterInterface; +class ChannelAPI; namespace SWGSDRangel { @@ -36,11 +37,50 @@ namespace SWGSDRangel class SWGFeatureReport; class SWGFeatureActions; class SWGDeviceState; + class SWGChannelSettings; } class SDRBASE_API Feature : public QObject { Q_OBJECT public: + class MsgChannelSettings : public Message { + MESSAGE_CLASS_DECLARATION + + public: + const ChannelAPI *getChannelAPI() const { return m_channelAPI; } + const QList& getChannelSettingsKeys() const { return m_channelSettingsKeys; } + SWGSDRangel::SWGChannelSettings *getSWGSettings() const { return m_swgSettings; } + bool getForce() const { return m_force; } + + static MsgChannelSettings* create( + const ChannelAPI *channelAPI, + const QList& channelSettingsKey, + SWGSDRangel::SWGChannelSettings *swgSettings, + bool force) + { + return new MsgChannelSettings(channelAPI, channelSettingsKey, swgSettings, force); + } + + private: + const ChannelAPI *m_channelAPI; + QList m_channelSettingsKeys; + SWGSDRangel::SWGChannelSettings *m_swgSettings; + bool m_force; + + MsgChannelSettings( + const ChannelAPI *channelAPI, + const QList& channelSettingsKeys, + SWGSDRangel::SWGChannelSettings *swgSettings, + bool force + ) : + Message(), + m_channelAPI(channelAPI), + m_channelSettingsKeys(channelSettingsKeys), + m_swgSettings(swgSettings), + m_force(force) + { } + }; + enum FeatureState { StNotStarted, //!< feature is before initialization StIdle, //!< feature is idle diff --git a/sdrbase/resources/webapi/doc/html2/index.html b/sdrbase/resources/webapi/doc/html2/index.html index aaffc30d4..3fb307511 100644 --- a/sdrbase/resources/webapi/doc/html2/index.html +++ b/sdrbase/resources/webapi/doc/html2/index.html @@ -776,6 +776,91 @@ margin-bottom: 20px; } }, "description" : "ADSBDemod" +}; + defs.AFCActions = { + "properties" : { + "deviceTrack" : { + "type" : "integer", + "description" : "(Re)initialize tracker target frequency adjustment\n * 0 - release\n * 1 - engage\n" + }, + "devicesApply" : { + "type" : "integer", + "description" : "(Re)initialize device sets tracking\n * 0 - release\n * 1 - engage\n" + } + }, + "description" : "AFC actions" +}; + defs.AFCReport = { + "properties" : { + "trackerChannelIndex" : { + "type" : "integer", + "description" : "Tracker index in device set" + }, + "trackerDeviceFrequency" : { + "type" : "integer", + "format" : "int64" + }, + "trackerChannelOffset" : { + "type" : "integer", + "description" : "Tracker channel offset from device center frequency" + } + }, + "description" : "AFC report" +}; + defs.AFCSettings = { + "properties" : { + "title" : { + "type" : "string" + }, + "rgbColor" : { + "type" : "integer" + }, + "trackerDeviceSetIndex" : { + "type" : "integer", + "description" : "index of the device set of frequency tracker being used" + }, + "trackedDeviceSetIndex" : { + "type" : "integer", + "description" : "index of the device set being tracked (channels and possibly device)" + }, + "hasTargetFrequency" : { + "type" : "integer", + "description" : "Adjust device frequency to match tracker frequency\n * 0 - disabled\n * 1 - enabled\n" + }, + "transverterTarget" : { + "type" : "integer", + "description" : "Use transverter or device frequency for tracker frequency adjustment\n * 0 - device\n * 1 - transverter\n" + }, + "targetFrequency" : { + "type" : "integer", + "format" : "int64", + "description" : "Target frequency for the tracker" + }, + "freqTolerance" : { + "type" : "integer" + }, + "trackerAdjustPeriod" : { + "type" : "integer", + "description" : "Tracker channel frequency adjustment period in seconds" + }, + "useReverseAPI" : { + "type" : "integer", + "description" : "Synchronize with reverse API (1 for yes, 0 for no)" + }, + "reverseAPIAddress" : { + "type" : "string" + }, + "reverseAPIPort" : { + "type" : "integer" + }, + "reverseAPIDeviceIndex" : { + "type" : "integer" + }, + "reverseAPIChannelIndex" : { + "type" : "integer" + } + }, + "description" : "AFC settings" }; defs.AMBEDevice = { "properties" : { @@ -3289,6 +3374,9 @@ margin-bottom: 20px; "type" : "integer", "description" : "Optional for reverse API. This is the feature index from where the message comes from." }, + "AFCActions" : { + "$ref" : "#/definitions/AFCActions" + }, "SimplePTTActions" : { "$ref" : "#/definitions/SimplePTTActions" } @@ -3315,6 +3403,9 @@ margin-bottom: 20px; "type" : "string", "description" : "Feature type code" }, + "AFCReport" : { + "$ref" : "#/definitions/AFCReport" + }, "SimplePTTReport" : { "$ref" : "#/definitions/SimplePTTReport" } @@ -3390,6 +3481,9 @@ margin-bottom: 20px; "GS232ControllerSettings" : { "$ref" : "#/definitions/GS232ControllerSettings" }, + "AFCSettings" : { + "$ref" : "#/definitions/AFCSettings" + }, "SimplePTTSettings" : { "$ref" : "#/definitions/SimplePTTSettings" }, @@ -3878,6 +3972,9 @@ margin-bottom: 20px; "title" : { "type" : "string" }, + "spanLog2" : { + "type" : "integer" + }, "alphaEMA" : { "type" : "number", "format" : "float", @@ -40117,7 +40214,7 @@ except ApiException as e:
- Generated 2020-10-27T19:23:34.436+01:00 + Generated 2020-10-27T23:03:34.026+01:00
diff --git a/sdrbase/resources/webapi/doc/swagger/include/ADSBDemod.yaml b/sdrbase/resources/webapi/doc/swagger/include/ADSBDemod.yaml new file mode 100644 index 000000000..4476535cd --- /dev/null +++ b/sdrbase/resources/webapi/doc/swagger/include/ADSBDemod.yaml @@ -0,0 +1,58 @@ +ADSBDemodSettings: + description: ADSBDemod + properties: + inputFrequencyOffset: + description: channel center frequency shift from baseband center in Hz + type: integer + format: int64 + rfBandwidth: + description: channel RF bandwidth in Hz + type: number + format: float + correlationThreshold: + type: number + format: float + samplesPerBit: + type: integer + removeTimeout: + type: integer + beastEnabled: + type: integer + beastHost: + type: string + beastPort: + type: integer + rgbColor: + type: integer + title: + type: string + streamIndex: + description: MIMO channel. Not relevant when connected to SI (single Rx). + type: integer + useReverseAPI: + description: Synchronize with reverse API (1 for yes, 0 for no) + type: integer + reverseAPIAddress: + type: string + reverseAPIPort: + type: integer + reverseAPIDeviceIndex: + type: integer + reverseAPIChannelIndex: + type: integer + +ADSBDemodReport: + description: ADSBDemod + properties: + channelPowerDB: + description: power received in channel (dB) + type: number + format: float + channelSampleRate: + type: integer + targetAzimuth: + type: number + format: float + targetElevation: + type: number + format: float diff --git a/sdrbase/resources/webapi/doc/swagger/include/AFC.yaml b/sdrbase/resources/webapi/doc/swagger/include/AFC.yaml new file mode 100644 index 000000000..ebd836e63 --- /dev/null +++ b/sdrbase/resources/webapi/doc/swagger/include/AFC.yaml @@ -0,0 +1,76 @@ +AFCSettings: + description: "AFC settings" + properties: + title: + type: string + rgbColor: + type: integer + trackerDeviceSetIndex: + description: index of the device set of frequency tracker being used + type: integer + trackedDeviceSetIndex: + description: index of the device set being tracked (channels and possibly device) + type: integer + hasTargetFrequency: + type: integer + description: > + Adjust device frequency to match tracker frequency + * 0 - disabled + * 1 - enabled + transverterTarget: + type: integer + description: > + Use transverter or device frequency for tracker frequency adjustment + * 0 - device + * 1 - transverter + targetFrequency: + description: Target frequency for the tracker + type: integer + format: int64 + freqTolerance: + descritpion: Frequency shift tolerance before tracker frequency is (re)adjusted + type: integer + trackerAdjustPeriod: + description: Tracker channel frequency adjustment period in seconds + type: integer + useReverseAPI: + description: Synchronize with reverse API (1 for yes, 0 for no) + type: integer + reverseAPIAddress: + type: string + reverseAPIPort: + type: integer + reverseAPIDeviceIndex: + type: integer + reverseAPIChannelIndex: + type: integer + +AFCReport: + description: "AFC report" + properties: + trackerChannelIndex: + description: Tracker index in device set + type: integer + trackerDeviceFrequency: + descritpion: Center frequency of tracker device + type: integer + format: int64 + trackerChannelOffset: + description: Tracker channel offset from device center frequency + type: integer + +AFCActions: + description: "AFC actions" + properties: + deviceTrack: + type: integer + description: > + (Re)initialize tracker target frequency adjustment + * 0 - release + * 1 - engage + devicesApply: + type: integer + description: > + (Re)initialize device sets tracking + * 0 - release + * 1 - engage diff --git a/sdrbase/resources/webapi/doc/swagger/include/ChannelReport.yaml b/sdrbase/resources/webapi/doc/swagger/include/ChannelReport.yaml index 8b5435992..bb26735fc 100644 --- a/sdrbase/resources/webapi/doc/swagger/include/ChannelReport.yaml +++ b/sdrbase/resources/webapi/doc/swagger/include/ChannelReport.yaml @@ -11,6 +11,8 @@ ChannelReport: direction: description: 0 for Rx only, 1 for Tx only or 2 for any number and direction (default 0) type: integer + ADSBDemodReport: + $ref: "/doc/swagger/include/ADSBDemod.yaml#/ADSBDemodReport" AMDemodReport: $ref: "/doc/swagger/include/AMDemod.yaml#/AMDemodReport" AMModReport: diff --git a/sdrbase/resources/webapi/doc/swagger/include/ChannelSettings.yaml b/sdrbase/resources/webapi/doc/swagger/include/ChannelSettings.yaml index 59dc14035..9eb4e65a9 100644 --- a/sdrbase/resources/webapi/doc/swagger/include/ChannelSettings.yaml +++ b/sdrbase/resources/webapi/doc/swagger/include/ChannelSettings.yaml @@ -17,6 +17,8 @@ ChannelSettings: originatorChannelIndex: description: Optional for reverse API. This is the channel index from where the message comes from. type: integer + ADSBDemodSettings: + $ref: "/doc/swagger/include/ADSBDemod.yaml#/ADSBDemodSettings" AMDemodSettings: $ref: "/doc/swagger/include/AMDemod.yaml#/AMDemodSettings" AMModSettings: diff --git a/sdrbase/resources/webapi/doc/swagger/include/FeatureActions.yaml b/sdrbase/resources/webapi/doc/swagger/include/FeatureActions.yaml index dbdea0da6..1dd79cbbf 100644 --- a/sdrbase/resources/webapi/doc/swagger/include/FeatureActions.yaml +++ b/sdrbase/resources/webapi/doc/swagger/include/FeatureActions.yaml @@ -13,5 +13,7 @@ FeatureActions: originatorFeatureIndex: description: Optional for reverse API. This is the feature index from where the message comes from. type: integer + AFCActions: + $ref: "/doc/swagger/include/AFC.yaml#/AFCActions" SimplePTTActions: $ref: "/doc/swagger/include/SimplePTT.yaml#/SimplePTTActions" diff --git a/sdrbase/resources/webapi/doc/swagger/include/FeatureReport.yaml b/sdrbase/resources/webapi/doc/swagger/include/FeatureReport.yaml index 52ad07b14..9fd5a1f0d 100644 --- a/sdrbase/resources/webapi/doc/swagger/include/FeatureReport.yaml +++ b/sdrbase/resources/webapi/doc/swagger/include/FeatureReport.yaml @@ -7,5 +7,7 @@ FeatureReport: featureType: description: Feature type code type: string + AFCReport: + $ref: "/doc/swagger/include/AFC.yaml#/AFCReport" SimplePTTReport: $ref: "/doc/swagger/include/SimplePTT.yaml#/SimplePTTReport" diff --git a/sdrbase/resources/webapi/doc/swagger/include/FeatureSettings.yaml b/sdrbase/resources/webapi/doc/swagger/include/FeatureSettings.yaml index 4f5b69c83..36ba21d2f 100644 --- a/sdrbase/resources/webapi/doc/swagger/include/FeatureSettings.yaml +++ b/sdrbase/resources/webapi/doc/swagger/include/FeatureSettings.yaml @@ -13,6 +13,10 @@ FeatureSettings: originatorFeatureIndex: description: Optional for reverse API. This is the feature index from where the message comes from. type: integer + GS232ControllerSettings: + $ref: "/doc/swagger/include/GS232Controller.yaml#/GS232ControllerSettings" + AFCSettings: + $ref: "/doc/swagger/include/AFC.yaml#/AFCSettings" SimplePTTSettings: $ref: "/doc/swagger/include/SimplePTT.yaml#/SimplePTTSettings" RigCtlServerSettings: diff --git a/sdrbase/resources/webapi/doc/swagger/include/FreqTracker.yaml b/sdrbase/resources/webapi/doc/swagger/include/FreqTracker.yaml index 68a029cd5..5d507b162 100644 --- a/sdrbase/resources/webapi/doc/swagger/include/FreqTracker.yaml +++ b/sdrbase/resources/webapi/doc/swagger/include/FreqTracker.yaml @@ -19,6 +19,8 @@ FreqTrackerSettings: type: integer title: type: string + spanLog2: + type: integer alphaEMA: description: Alpha factor for delta frequency EMA type: number diff --git a/sdrbase/resources/webapi/doc/swagger/include/GS232Controller.yaml b/sdrbase/resources/webapi/doc/swagger/include/GS232Controller.yaml new file mode 100644 index 000000000..7c8b2ed12 --- /dev/null +++ b/sdrbase/resources/webapi/doc/swagger/include/GS232Controller.yaml @@ -0,0 +1,36 @@ +GS232ControllerSettings: + description: "GS-232 Controller settings" + properties: + azimuth: + description: Target azimuth in degrees (0-450) + type: integer + elevation: + description: Target elevation in degrees (0-180) + type: integer + serialPort: + description: The serial port the GS-232 controller is connected to + type: string + baudRate: + description: The baud rate to use for the serial connection to the GS-232 controller + type: integer + track: + type: integer + title: + type: string + rgbColor: + type: integer + deviceIndex: + type: integer + channelIndex: + type: integer + useReverseAPI: + description: Synchronize with reverse API (1 for yes, 0 for no) + type: integer + reverseAPIAddress: + type: string + reverseAPIPort: + type: integer + reverseAPIDeviceIndex: + type: integer + reverseAPIChannelIndex: + type: integer diff --git a/sdrbase/resources/webapi/doc/swagger/include/USRP.yaml b/sdrbase/resources/webapi/doc/swagger/include/USRP.yaml index 05d22351c..e388f288f 100644 --- a/sdrbase/resources/webapi/doc/swagger/include/USRP.yaml +++ b/sdrbase/resources/webapi/doc/swagger/include/USRP.yaml @@ -6,6 +6,8 @@ USRPInputSettings: format: int64 devSampleRate: type: integer + loOffset: + type: integer dcBlock: type: integer iqCorrection: @@ -46,6 +48,8 @@ USRPOutputSettings: format: int64 devSampleRate: type: integer + loOffset: + type: integer log2SoftInterp: type: integer lpfBW: diff --git a/sdrbase/webapi/webapirequestmapper.cpp b/sdrbase/webapi/webapirequestmapper.cpp index 651fab751..a204e23cf 100644 --- a/sdrbase/webapi/webapirequestmapper.cpp +++ b/sdrbase/webapi/webapirequestmapper.cpp @@ -25,6 +25,7 @@ #include "httpdocrootsettings.h" #include "webapirequestmapper.h" +#include "webapiutils.h" #include "SWGInstanceSummaryResponse.h" #include "SWGInstanceConfigResponse.h" #include "SWGInstanceDevicesResponse.h" @@ -56,209 +57,6 @@ #include "SWGFeatureReport.h" #include "SWGFeatureActions.h" -const QMap WebAPIRequestMapper::m_channelURIToSettingsKey = { - {"sdrangel.channel.adsbdemod", "ADSBDemodSettings"}, - {"sdrangel.channel.amdemod", "AMDemodSettings"}, - {"de.maintech.sdrangelove.channel.am", "AMDemodSettings"}, // remap - {"sdrangel.channeltx.modam", "AMModSettings"}, - {"sdrangel.channeltx.modatv", "ATVModSettings"}, - {"sdrangel.channel.bfm", "BFMDemodSettings"}, - {"sdrangel.channel.chanalyzer", "ChannelAnalyzerSettings"}, - {"sdrangel.channel.chanalyzerng", "ChannelAnalyzerSettings"}, // remap - {"org.f4exb.sdrangelove.channel.chanalyzer", "ChannelAnalyzerSettings"}, // remap - {"sdrangel.channel.demodatv", "ATVDemodSettings"}, - {"sdrangel.channel.demoddatv", "DATVDemodSettings"}, - {"sdrangel.channel.dsddemod", "DSDDemodSettings"}, - {"sdrangel.channel.filesink", "FileSinkSettings"}, - {"sdrangel.channeltx.filesource", "FileSourceSettings"}, - {"sdrangel.channel.freedvdemod", "FreeDVDemodSettings"}, - {"sdrangel.channeltx.freedvmod", "FreeDVModSettings"}, - {"sdrangel.channel.freqtracker", "FreqTrackerSettings"}, - {"sdrangel.channel.nfmdemod", "NFMDemodSettings"}, - {"de.maintech.sdrangelove.channel.nfm", "NFMDemodSettings"}, // remap - {"sdrangel.channeltx.modnfm", "NFMModSettings"}, - {"sdrangel.demod.localsink", "LocalSinkSettings"}, - {"sdrangel.channel.localsink", "LocalSinkSettings"}, // remap - {"sdrangel.channel.localsource", "LocalSourceSettings"}, - {"sdrangel.channeltx.modpacket", "PacketModSettings"}, - {"sdrangel.channeltx.mod802.15.4", "IEEE_802_15_4_ModSettings"}, - {"sdrangel.demod.remotesink", "RemoteSinkSettings"}, - {"sdrangel.channeltx.remotesource", "RemoteSourceSettings"}, - {"sdrangel.channeltx.modssb", "SSBModSettings"}, - {"sdrangel.channel.ssbdemod", "SSBDemodSettings"}, - {"de.maintech.sdrangelove.channel.ssb", "SSBDemodSettings"}, // remap - {"sdrangel.channeltx.udpsource", "UDPSourceSettings"}, - {"sdrangel.channeltx.udpsink", "UDPSourceSettings"}, // remap - {"sdrangel.channel.udpsink", "UDPSinkSettings"}, - {"sdrangel.channel.udpsrc", "UDPSinkSettings"}, // remap - {"sdrangel.channel.wfmdemod", "WFMDemodSettings"}, - {"de.maintech.sdrangelove.channel.wfm", "WFMDemodSettings"}, // remap - {"sdrangel.channeltx.modwfm", "WFMModSettings"} -}; - -const QMap WebAPIRequestMapper::m_deviceIdToSettingsKey = { - {"sdrangel.samplesource.airspy", "airspySettings"}, - {"sdrangel.samplesource.airspyhf", "airspyHFSettings"}, - {"sdrangel.samplesource.bladerf1input", "bladeRF1InputSettings"}, - {"sdrangel.samplesource.bladerf", "bladeRF1InputSettings"}, // remap - {"sdrangel.samplesink.bladerf1output", "bladeRF1OutputSettings"}, - {"sdrangel.samplesource.bladerf1output", "bladeRF1OutputSettings"}, // remap - {"sdrangel.samplesource.bladerfoutput", "bladeRF1OutputSettings"}, // remap - {"sdrangel.samplesource.bladerf2input", "bladeRF2InputSettings"}, - {"sdrangel.samplesink.bladerf2output", "bladeRF2OutputSettings"}, - {"sdrangel.samplesource.bladerf2output", "bladeRF2OutputSettings"}, // remap - {"sdrangel.samplesource.fcdpro", "fcdProSettings"}, - {"sdrangel.samplesource.fcdproplus", "fcdProPlusSettings"}, - {"sdrangel.samplesource.fileinput", "fileInputSettings"}, - {"sdrangel.samplesource.filesource", "fileInputSettings"}, // remap - {"sdrangel.samplesource.hackrf", "hackRFInputSettings"}, - {"sdrangel.samplesink.hackrf", "hackRFOutputSettings"}, - {"sdrangel.samplesource.hackrfoutput", "hackRFOutputSettings"}, // remap - {"sdrangel.samplesource.kiwisdrsource", "kiwiSDRSettings"}, - {"sdrangel.samplesource.limesdr", "limeSdrInputSettings"}, - {"sdrangel.samplesink.limesdr", "limeSdrOutputSettings"}, - {"sdrangel.samplesource.localinput", "localInputSettings"}, - {"sdrangel.samplesink.localoutput", "localOutputSettings"}, - {"sdrangel.samplesource.localoutput", "localOutputSettings"}, // remap - {"sdrangel.samplesource.perseus", "perseusSettings"}, - {"sdrangel.samplesource.plutosdr", "plutoSdrInputSettings"}, - {"sdrangel.samplesink.plutosdr", "plutoSdrOutputSettings"}, - {"sdrangel.samplesource.rtlsdr", "rtlSdrSettings"}, - {"sdrangel.samplesource.remoteinput", "remoteInputSettings"}, - {"sdrangel.samplesink.remoteoutput", "remoteOutputSettings"}, - {"sdrangel.samplesource.sdrplay", "sdrPlaySettings"}, - {"sdrangel.samplesource.soapysdrinput", "soapySDRInputSettings"}, - {"sdrangel.samplesink.soapysdroutput", "soapySDROutputSettings"}, - {"sdrangel.samplesource.testsource", "testSourceSettings"}, - {"sdrangel.samplesource.usrp", "usrpInputSettings"}, - {"sdrangel.samplesink.usrp", "usrpOutputSettings"}, - {"sdrangel.samplesource.xtrx", "XtrxInputSettings"}, - {"sdrangel.samplesink.xtrx", "XtrxOutputSettings"} -}; - -const QMap WebAPIRequestMapper::m_channelTypeToSettingsKey = { - {"ADSBDemod", "ADSBDemodSettings"}, - {"AMDemod", "AMDemodSettings"}, - {"AMMod", "AMModSettings"}, - {"ATVDemod", "ATVDemodSettings"}, - {"ATVMod", "ATVModSettings"}, - {"BFMDemod", "BFMDemodSettings"}, - {"ChannelAnalyzer", "ChannelAnalyzerSettings"}, - {"DATVDemod", "DATVDemodSettings"}, - {"DSDDemod", "DSDDemodSettings"}, - {"FileSink", "FileSinkSettings"}, - {"FileSource", "FileSourceSettings"}, - {"FreeDVDemod", "FreeDVDemodSettings"}, - {"FreeDVMod", "FreeDVModSettings"}, - {"FreqTracker", "FreqTrackerSettings"}, - {"IEEE_802_15_4_Mod", "IEEE_802_15_4_ModSettings"}, - {"NFMDemod", "NFMDemodSettings"}, - {"NFMMod", "NFMModSettings"}, - {"PacketMod", "PacketModSettings"}, - {"LocalSink", "LocalSinkSettings"}, - {"LocalSource", "LocalSourceSettings"}, - {"RemoteSink", "RemoteSinkSettings"}, - {"RemoteSource", "RemoteSourceSettings"}, - {"SSBMod", "SSBModSettings"}, - {"SSBDemod", "SSBDemodSettings"}, - {"UDPSink", "UDPSourceSettings"}, - {"UDPSource", "UDPSinkSettings"}, - {"WFMDemod", "WFMDemodSettings"}, - {"WFMMod", "WFMModSettings"} -}; - -const QMap WebAPIRequestMapper::m_channelTypeToActionsKey = { - {"FileSink", "FileSinkActions"}, - {"FileSource", "FileSourceActions"}, - {"IEEE_802_15_4_Mod", "IEEE_802_15_4_ModActions"}, - {"PacketMod", "PacketModActions"} -}; - -const QMap WebAPIRequestMapper::m_sourceDeviceHwIdToSettingsKey = { - {"Airspy", "airspySettings"}, - {"AirspyHF", "airspyHFSettings"}, - {"BladeRF1", "bladeRF1InputSettings"}, - {"BladeRF2", "bladeRF2InputSettings"}, - {"FCDPro", "fcdProSettings"}, - {"FCDPro+", "fcdProPlusSettings"}, - {"FileInput", "fileInputSettings"}, - {"HackRF", "hackRFInputSettings"}, - {"KiwiSDR", "kiwiSDRSettings"}, - {"LimeSDR", "limeSdrInputSettings"}, - {"LocalInput", "localInputSettings"}, - {"Perseus", "perseusSettings"}, - {"PlutoSDR", "plutoSdrInputSettings"}, - {"RTLSDR", "rtlSdrSettings"}, - {"RemoteInput", "remoteInputSettings"}, - {"SDRplay1", "sdrPlaySettings"}, - {"SoapySDR", "soapySDRInputSettings"}, - {"TestSource", "testSourceSettings"}, - {"USRP", "usrpInputSettings"}, - {"XTRX", "XtrxInputSettings"} -}; - -const QMap WebAPIRequestMapper::m_sourceDeviceHwIdToActionsKey = { - {"Airspy", "airspyActions"}, - {"AirspyHF", "airspyHFActions"}, - {"BladeRF1", "bladeRF1InputActions"}, - {"FCDPro", "fcdProActions"}, - {"FCDPro+", "fcdProPlusActions"}, - {"HackRF", "hackRFInputActions"}, - {"KiwiSDR", "kiwiSDRActions"}, - {"LimeSDR", "limeSdrInputActions"}, - {"LocalInput", "localInputActions"}, - {"Perseus", "perseusActions"}, - {"PlutoSDR", "plutoSdrInputActions"}, - {"RemoteInput", "remoteInputActions"}, - {"RTLSDR", "rtlSdrActions"}, - {"SDRplay1", "sdrPlayActions"}, - {"SoapySDR", "soapySDRInputActions"}, - {"TestSource", "testSourceActions"}, - {"USRP", "usrpSourceActions"}, - {"XTRX", "xtrxInputActions"} -}; - -const QMap WebAPIRequestMapper::m_sinkDeviceHwIdToSettingsKey = { - {"BladeRF1", "bladeRF1OutputSettings"}, - {"BladeRF2", "bladeRF2OutputSettings"}, - {"HackRF", "hackRFOutputSettings"}, - {"LimeSDR", "limeSdrOutputSettings"}, - {"LocalOutput", "localOutputSettings"}, - {"PlutoSDR", "plutoSdrOutputSettings"}, - {"RemoteOutput", "remoteOutputSettings"}, - {"SoapySDR", "soapySDROutputSettings"}, - {"USRP", "usrpOutputSettings"}, - {"XTRX", "xtrxOutputSettings"} -}; - -const QMap WebAPIRequestMapper::m_sinkDeviceHwIdToActionsKey = { -}; - -const QMap WebAPIRequestMapper::m_mimoDeviceHwIdToSettingsKey= { - {"BladeRF2", "bladeRF2MIMOSettings"}, - {"TestMI", "testMISettings"}, - {"TestMOSync", "testMOSyncSettings"} -}; - -const QMap WebAPIRequestMapper::m_mimoDeviceHwIdToActionsKey= { -}; - -const QMap WebAPIRequestMapper::m_featureTypeToSettingsKey = { - {"GS232Controller", "GS232ControllerSettings"}, - {"SimplePTT", "SimplePTTSettings"}, - {"RigCtlServer", "RigCtlServerSettings"} -}; - -const QMap WebAPIRequestMapper::m_featureTypeToActionsKey = { - {"SimplePTT", "SimplePTTActions"} -}; - -const QMap WebAPIRequestMapper::m_featureURIToSettingsKey = { - {"sdrangel.feature.gs232controller", "GS232ControllerSettings"}, - {"sdrangel.feature.simpleptt", "SimplePTTSettings"}, - {"sdrangel.feature.rigctlserver", "RigCtlServerSettings"} -}; - WebAPIRequestMapper::WebAPIRequestMapper(QObject* parent) : HttpRequestHandler(parent), m_adapter(0) @@ -3029,16 +2827,24 @@ bool WebAPIRequestMapper::validateDeviceSettings( if (deviceSettings.getDirection() == 0) // source { - if (m_sourceDeviceHwIdToSettingsKey.contains(*deviceHwType)) { - deviceSettingsKey = m_sourceDeviceHwIdToSettingsKey[*deviceHwType]; + if (WebAPIUtils::m_sourceDeviceHwIdToSettingsKey.contains(*deviceHwType)) { + deviceSettingsKey = WebAPIUtils::m_sourceDeviceHwIdToSettingsKey[*deviceHwType]; } else { return false; } } else if (deviceSettings.getDirection() == 1) // sink { - if (m_sinkDeviceHwIdToSettingsKey.contains(*deviceHwType)) { - deviceSettingsKey = m_sinkDeviceHwIdToSettingsKey[*deviceHwType]; + if (WebAPIUtils::m_sinkDeviceHwIdToSettingsKey.contains(*deviceHwType)) { + deviceSettingsKey = WebAPIUtils::m_sinkDeviceHwIdToSettingsKey[*deviceHwType]; + } else { + return false; + } + } + else if (deviceSettings.getDirection() == 2) // MIMO + { + if (WebAPIUtils::m_mimoDeviceHwIdToSettingsKey.contains(*deviceHwType)) { + deviceSettingsKey = WebAPIUtils::m_mimoDeviceHwIdToSettingsKey[*deviceHwType]; } else { return false; } @@ -3073,24 +2879,24 @@ bool WebAPIRequestMapper::validateDeviceActions( if (deviceActions.getDirection() == 0) // source { - if (m_sourceDeviceHwIdToSettingsKey.contains(*deviceHwType)) { - deviceActionsKey = m_sourceDeviceHwIdToActionsKey[*deviceHwType]; + if (WebAPIUtils::m_sourceDeviceHwIdToSettingsKey.contains(*deviceHwType)) { + deviceActionsKey = WebAPIUtils::m_sourceDeviceHwIdToActionsKey[*deviceHwType]; } else { return false; } } else if (deviceActions.getDirection() == 1) // sink { - if (m_sinkDeviceHwIdToSettingsKey.contains(*deviceHwType)) { - deviceActionsKey = m_sinkDeviceHwIdToActionsKey[*deviceHwType]; + if (WebAPIUtils::m_sinkDeviceHwIdToSettingsKey.contains(*deviceHwType)) { + deviceActionsKey = WebAPIUtils::m_sinkDeviceHwIdToActionsKey[*deviceHwType]; } else { return false; } } else if (deviceActions.getDirection() == 2) // MIMO { - if (m_mimoDeviceHwIdToSettingsKey.contains(*deviceHwType)) { - deviceActionsKey = m_mimoDeviceHwIdToActionsKey[*deviceHwType]; + if (WebAPIUtils::m_mimoDeviceHwIdToSettingsKey.contains(*deviceHwType)) { + deviceActionsKey = WebAPIUtils::m_mimoDeviceHwIdToActionsKey[*deviceHwType]; } else { return false; } @@ -3122,8 +2928,8 @@ bool WebAPIRequestMapper::validateChannelSettings( QString *channelType = channelSettings.getChannelType(); - if (m_channelTypeToSettingsKey.contains(*channelType)) { - return getChannelSettings(m_channelTypeToSettingsKey[*channelType], &channelSettings, jsonObject, channelSettingsKeys); + if (WebAPIUtils::m_channelTypeToSettingsKey.contains(*channelType)) { + return getChannelSettings(WebAPIUtils::m_channelTypeToSettingsKey[*channelType], &channelSettings, jsonObject, channelSettingsKeys); } else { return false; } @@ -3148,8 +2954,8 @@ bool WebAPIRequestMapper::validateChannelActions( QString *channelType = channelActions.getChannelType(); - if (m_channelTypeToActionsKey.contains(*channelType)) { - return getChannelActions(m_channelTypeToActionsKey[*channelType], &channelActions, jsonObject, channelActionsKeys); + if (WebAPIUtils::m_channelTypeToActionsKey.contains(*channelType)) { + return getChannelActions(WebAPIUtils::m_channelTypeToActionsKey[*channelType], &channelActions, jsonObject, channelActionsKeys); } else { return false; } @@ -3168,8 +2974,8 @@ bool WebAPIRequestMapper::validateFeatureSettings( QString *featureType = featureSettings.getFeatureType(); - if (m_featureTypeToSettingsKey.contains(*featureType)) { - return getFeatureSettings(m_featureTypeToSettingsKey[*featureType], &featureSettings, jsonObject, featureSettingsKeys); + if (WebAPIUtils::m_featureTypeToSettingsKey.contains(*featureType)) { + return getFeatureSettings(WebAPIUtils::m_featureTypeToSettingsKey[*featureType], &featureSettings, jsonObject, featureSettingsKeys); } else { return false; } @@ -3188,8 +2994,8 @@ bool WebAPIRequestMapper::validateFeatureActions( QString *featureType = featureActions.getFeatureType(); - if (m_featureTypeToActionsKey.contains(*featureType)) { - return getFeatureActions(m_featureTypeToActionsKey[*featureType], &featureActions, jsonObject, featureActionsKeys); + if (WebAPIUtils::m_featureTypeToActionsKey.contains(*featureType)) { + return getFeatureActions(WebAPIUtils::m_featureTypeToActionsKey[*featureType], &featureActions, jsonObject, featureActionsKeys); } else { return false; } @@ -3647,12 +3453,12 @@ bool WebAPIRequestMapper::appendPresetFeatureKeys( feature->setFeatureIdUri(featureURI); featureKeys.m_keys.append("featureIdURI"); - if (featureSettingsJson.contains("config") && m_featureURIToSettingsKey.contains(*featureURI)) + if (featureSettingsJson.contains("config") && WebAPIUtils::m_featureURIToSettingsKey.contains(*featureURI)) { SWGSDRangel::SWGFeatureSettings *featureSettings = new SWGSDRangel::SWGFeatureSettings(); feature->setConfig(featureSettings); return getFeatureSettings( - m_channelURIToSettingsKey[*featureURI], + WebAPIUtils::m_channelURIToSettingsKey[*featureURI], featureSettings, featureSettingsJson["config"].toObject(), featureKeys.m_featureKeys @@ -3681,11 +3487,11 @@ bool WebAPIRequestMapper::appendPresetChannelKeys( channel->setChannelIdUri(channelURI); channelKeys.m_keys.append("channelIdURI"); - if (channelSettingsJson.contains("config") && m_channelURIToSettingsKey.contains(*channelURI)) + if (channelSettingsJson.contains("config") && WebAPIUtils::m_channelURIToSettingsKey.contains(*channelURI)) { SWGSDRangel::SWGChannelSettings *channelSettings = new SWGSDRangel::SWGChannelSettings(); channel->setConfig(channelSettings); - return getChannelSettings(m_channelURIToSettingsKey[*channelURI], channelSettings, channelSettingsJson["config"].toObject(), channelKeys.m_channelKeys); + return getChannelSettings(WebAPIUtils::m_channelURIToSettingsKey[*channelURI], channelSettings, channelSettingsJson["config"].toObject(), channelKeys.m_channelKeys); } else { @@ -3942,11 +3748,11 @@ bool WebAPIRequestMapper::appendPresetDeviceKeys( devicelKeys.m_keys.append("deviceSequence"); } - if (deviceSettngsJson.contains("config") && m_deviceIdToSettingsKey.contains(*deviceId)) + if (deviceSettngsJson.contains("config") && WebAPIUtils::m_deviceIdToSettingsKey.contains(*deviceId)) { SWGSDRangel::SWGDeviceSettings *deviceSettings = new SWGSDRangel::SWGDeviceSettings(); device->setConfig(deviceSettings); - return getDeviceSettings(m_deviceIdToSettingsKey[*deviceId], deviceSettings, deviceSettngsJson["config"].toObject(), devicelKeys.m_deviceKeys); + return getDeviceSettings(WebAPIUtils::m_deviceIdToSettingsKey[*deviceId], deviceSettings, deviceSettngsJson["config"].toObject(), devicelKeys.m_deviceKeys); } else { diff --git a/sdrbase/webapi/webapiutils.cpp b/sdrbase/webapi/webapiutils.cpp index 86df2e98d..f392c639f 100644 --- a/sdrbase/webapi/webapiutils.cpp +++ b/sdrbase/webapi/webapiutils.cpp @@ -21,6 +21,224 @@ #include "webapiutils.h" +const QMap WebAPIUtils::m_channelURIToSettingsKey = { + {"sdrangel.channel.amdemod", "AMDemodSettings"}, + {"de.maintech.sdrangelove.channel.am", "AMDemodSettings"}, // remap + {"sdrangel.channeltx.modam", "AMModSettings"}, + {"sdrangel.channeltx.modatv", "ATVModSettings"}, + {"sdrangel.channel.bfm", "BFMDemodSettings"}, + {"sdrangel.channel.chanalyzer", "ChannelAnalyzerSettings"}, + {"sdrangel.channel.chanalyzerng", "ChannelAnalyzerSettings"}, // remap + {"org.f4exb.sdrangelove.channel.chanalyzer", "ChannelAnalyzerSettings"}, // remap + {"sdrangel.channel.chirpchatdemod", "ChirpChatDemodSettings"}, + {"sdrangel.channel.modchirpchat", "ChirpChatModSettings"}, + {"sdrangel.channel.demodatv", "ATVDemodSettings"}, + {"sdrangel.channel.demoddatv", "DATVDemodSettings"}, + {"sdrangel.channel.dsddemod", "DSDDemodSettings"}, + {"sdrangel.channel.filesink", "FileSinkSettings"}, + {"sdrangel.channeltx.filesource", "FileSourceSettings"}, + {"sdrangel.channel.freedvdemod", "FreeDVDemodSettings"}, + {"sdrangel.channeltx.freedvmod", "FreeDVModSettings"}, + {"sdrangel.channel.freqtracker", "FreqTrackerSettings"}, + {"sdrangel.channel.nfmdemod", "NFMDemodSettings"}, + {"de.maintech.sdrangelove.channel.nfm", "NFMDemodSettings"}, // remap + {"sdrangel.channeltx.modnfm", "NFMModSettings"}, + {"sdrangel.demod.localsink", "LocalSinkSettings"}, + {"sdrangel.channel.localsink", "LocalSinkSettings"}, // remap + {"sdrangel.channel.localsource", "LocalSourceSettings"}, + {"sdrangel.channeltx.modpacket", "PacketModSettings"}, + {"sdrangel.channeltx.mod802.15.4", "IEEE_802_15_4_ModSettings"}, + {"sdrangel.demod.remotesink", "RemoteSinkSettings"}, + {"sdrangel.channeltx.remotesource", "RemoteSourceSettings"}, + {"sdrangel.channeltx.modssb", "SSBModSettings"}, + {"sdrangel.channel.ssbdemod", "SSBDemodSettings"}, + {"de.maintech.sdrangelove.channel.ssb", "SSBDemodSettings"}, // remap + {"sdrangel.channeltx.udpsource", "UDPSourceSettings"}, + {"sdrangel.channeltx.udpsink", "UDPSourceSettings"}, // remap + {"sdrangel.channel.udpsink", "UDPSinkSettings"}, + {"sdrangel.channel.udpsrc", "UDPSinkSettings"}, // remap + {"sdrangel.channel.wfmdemod", "WFMDemodSettings"}, + {"de.maintech.sdrangelove.channel.wfm", "WFMDemodSettings"}, // remap + {"sdrangel.channeltx.modwfm", "WFMModSettings"}, + {"sdrangel.channel.beamsteeringcwmod", "BeamSteeringCWModSettings"}, + {"sdrangel.channelmimo.interferometer", "InterferometerSettings"}, + {"sdrangel.channel.sigmffilesink", "SigMFFileSinkSettings"} +}; + +const QMap WebAPIUtils::m_deviceIdToSettingsKey = { + {"sdrangel.samplesource.airspy", "airspySettings"}, + {"sdrangel.samplesource.airspyhf", "airspyHFSettings"}, + {"sdrangel.samplesource.bladerf1input", "bladeRF1InputSettings"}, + {"sdrangel.samplesource.bladerf", "bladeRF1InputSettings"}, // remap + {"sdrangel.samplesink.bladerf1output", "bladeRF1OutputSettings"}, + {"sdrangel.samplesource.bladerf1output", "bladeRF1OutputSettings"}, // remap + {"sdrangel.samplesource.bladerfoutput", "bladeRF1OutputSettings"}, // remap + {"sdrangel.samplesource.bladerf2input", "bladeRF2InputSettings"}, + {"sdrangel.samplesink.bladerf2output", "bladeRF2OutputSettings"}, + {"sdrangel.samplesource.bladerf2output", "bladeRF2OutputSettings"}, // remap + {"sdrangel.samplemimo.bladerf2mimo", "bladeRF2MIMOSettings"}, + {"sdrangel.samplesource.fcdpro", "fcdProSettings"}, + {"sdrangel.samplesource.fcdproplus", "fcdProPlusSettings"}, + {"sdrangel.samplesource.fileinput", "fileInputSettings"}, + {"sdrangel.samplesource.filesource", "fileInputSettings"}, // remap + {"sdrangel.samplesource.hackrf", "hackRFInputSettings"}, + {"sdrangel.samplesink.hackrf", "hackRFOutputSettings"}, + {"sdrangel.samplesource.hackrfoutput", "hackRFOutputSettings"}, // remap + {"sdrangel.samplesource.kiwisdrsource", "kiwiSDRSettings"}, + {"sdrangel.samplesource.limesdr", "limeSdrInputSettings"}, + {"sdrangel.samplesink.limesdr", "limeSdrOutputSettings"}, + {"sdrangel.samplesource.localinput", "localInputSettings"}, + {"sdrangel.samplesink.localoutput", "localOutputSettings"}, + {"sdrangel.samplesource.localoutput", "localOutputSettings"}, // remap + {"sdrangel.samplemimo.metismiso", "metisMISOSettings"}, + {"sdrangel.samplesource.perseus", "perseusSettings"}, + {"sdrangel.samplesource.plutosdr", "plutoSdrInputSettings"}, + {"sdrangel.samplesink.plutosdr", "plutoSdrOutputSettings"}, + {"sdrangel.samplesource.rtlsdr", "rtlSdrSettings"}, + {"sdrangel.samplesource.remoteinput", "remoteInputSettings"}, + {"sdrangel.samplesink.remoteoutput", "remoteOutputSettings"}, + {"sdrangel.samplesource.sdrplay", "sdrPlaySettings"}, + {"sdrangel.samplesource.sigmffileinput", "sigMFFileInputSettings"}, + {"sdrangel.samplesource.soapysdrinput", "soapySDRInputSettings"}, + {"sdrangel.samplesink.soapysdroutput", "soapySDROutputSettings"}, + {"sdrangel.samplesource.testsource", "testSourceSettings"}, + {"sdrangel.samplemimo.testmi", "testMISettings"}, + {"sdrangel.samplemimo.testmosync", "testMOSyncSettings"}, + {"sdrangel.samplesource.usrp", "usrpInputSettings"}, + {"sdrangel.samplesink.usrp", "usrpOutputSettings"}, + {"sdrangel.samplesource.xtrx", "xtrxInputSettings"}, + {"sdrangel.samplesink.xtrx", "xtrxOutputSettings"} +}; + +const QMap WebAPIUtils::m_channelTypeToSettingsKey = { + {"AMDemod", "AMDemodSettings"}, + {"AMMod", "AMModSettings"}, + {"ATVDemod", "ATVDemodSettings"}, + {"ATVMod", "ATVModSettings"}, + {"BFMDemod", "BFMDemodSettings"}, + {"ChannelAnalyzer", "ChannelAnalyzerSettings"}, + {"ChirpChatDemod", "ChirpChatDemodSettings"}, + {"ChirpChatMod", "ChirpChatModSettings"}, + {"DATVDemod", "DATVDemodSettings"}, + {"DSDDemod", "DSDDemodSettings"}, + {"FileSink", "FileSinkSettings"}, + {"FileSource", "FileSourceSettings"}, + {"FreeDVDemod", "FreeDVDemodSettings"}, + {"FreeDVMod", "FreeDVModSettings"}, + {"FreqTracker", "FreqTrackerSettings"}, + {"IEEE_802_15_4_Mod", "IEEE_802_15_4_ModSettings"}, + {"NFMDemod", "NFMDemodSettings"}, + {"NFMMod", "NFMModSettings"}, + {"PacketMod", "PacketModSettings"}, + {"LocalSink", "LocalSinkSettings"}, + {"LocalSource", "LocalSourceSettings"}, + {"RemoteSink", "RemoteSinkSettings"}, + {"RemoteSource", "RemoteSourceSettings"}, + {"SSBMod", "SSBModSettings"}, + {"SSBDemod", "SSBDemodSettings"}, + {"UDPSink", "UDPSourceSettings"}, + {"UDPSource", "UDPSinkSettings"}, + {"WFMDemod", "WFMDemodSettings"}, + {"WFMMod", "WFMModSettings"}, + {"BeamSteeringCWMod", "BeamSteeringCWModSettings"}, + {"Interferometer", "InterferometerSettings"}, + {"SigMFFileSink", "SigMFFileSinkSettings"} +}; + +const QMap WebAPIUtils::m_channelTypeToActionsKey = { + {"FileSink", "FileSinkActions"}, + {"FileSource", "FileSourceActions"}, + {"SigMFFileSink", "SigMFFileSinkActions"}, + {"IEEE_802_15_4_Mod", "IEEE_802_15_4_ModActions"}, + {"PacketMod", "PacketModActions"} +}; + +const QMap WebAPIUtils::m_sourceDeviceHwIdToSettingsKey = { + {"Airspy", "airspySettings"}, + {"AirspyHF", "airspyHFSettings"}, + {"BladeRF1", "bladeRF1InputSettings"}, + {"BladeRF2", "bladeRF2InputSettings"}, + {"FCDPro", "fcdProSettings"}, + {"FCDPro+", "fcdProPlusSettings"}, + {"FileInput", "fileInputSettings"}, + {"HackRF", "hackRFInputSettings"}, + {"KiwiSDR", "kiwiSDRSettings"}, + {"LimeSDR", "limeSdrInputSettings"}, + {"LocalInput", "localInputSettings"}, + {"Perseus", "perseusSettings"}, + {"PlutoSDR", "plutoSdrInputSettings"}, + {"RTLSDR", "rtlSdrSettings"}, + {"RemoteInput", "remoteInputSettings"}, + {"SDRplay1", "sdrPlaySettings"}, + {"SigMFFileInput", "sigMFFileInputSettings"}, + {"SoapySDR", "soapySDRInputSettings"}, + {"TestSource", "testSourceSettings"}, + {"USRP", "usrpInputSettings"}, + {"XTRX", "xtrxInputSettings"} +}; + +const QMap WebAPIUtils::m_sourceDeviceHwIdToActionsKey = { + {"Airspy", "airspyActions"}, + {"AirspyHF", "airspyHFActions"}, + {"BladeRF1", "bladeRF1InputActions"}, + {"FCDPro", "fcdProActions"}, + {"FCDPro+", "fcdProPlusActions"}, + {"HackRF", "hackRFInputActions"}, + {"KiwiSDR", "kiwiSDRActions"}, + {"LimeSDR", "limeSdrInputActions"}, + {"LocalInput", "localInputActions"}, + {"Perseus", "perseusActions"}, + {"PlutoSDR", "plutoSdrInputActions"}, + {"RemoteInput", "remoteInputActions"}, + {"RTLSDR", "rtlSdrActions"}, + {"SDRplay1", "sdrPlayActions"}, + {"SigMFFileInput", "sigMFFileActions"}, + {"SoapySDR", "soapySDRInputActions"}, + {"TestSource", "testSourceActions"}, + {"USRP", "usrpSourceActions"}, + {"XTRX", "xtrxInputActions"} +}; + +const QMap WebAPIUtils::m_sinkDeviceHwIdToSettingsKey = { + {"BladeRF1", "bladeRF1OutputSettings"}, + {"BladeRF2", "bladeRF2OutputSettings"}, + {"HackRF", "hackRFOutputSettings"}, + {"LimeSDR", "limeSdrOutputSettings"}, + {"LocalOutput", "localOutputSettings"}, + {"PlutoSDR", "plutoSdrOutputSettings"}, + {"RemoteOutput", "remoteOutputSettings"}, + {"SoapySDR", "soapySDROutputSettings"}, + {"USRP", "usrpOutputSettings"}, + {"XTRX", "xtrxOutputSettings"} +}; + +const QMap WebAPIUtils::m_sinkDeviceHwIdToActionsKey = { +}; + +const QMap WebAPIUtils::m_mimoDeviceHwIdToSettingsKey = { + {"BladeRF2", "bladeRF2MIMOSettings"}, + {"MetisMISO", "metisMISOSettings"}, + {"TestMI", "testMISettings"}, + {"TestMOSync", "testMOSyncSettings"} +}; + +const QMap WebAPIUtils::m_mimoDeviceHwIdToActionsKey = { +}; + +const QMap WebAPIUtils::m_featureTypeToSettingsKey = { + {"SimplePTT", "SimplePTTSettings"}, + {"RigCtlServer", "RigCtlServerSettings"} +}; + +const QMap WebAPIUtils::m_featureTypeToActionsKey = { + {"SimplePTT", "SimplePTTActions"} +}; + +const QMap WebAPIUtils::m_featureURIToSettingsKey = { + {"sdrangel.feature.simpleptt", "SimplePTTSettings"}, + {"sdrangel.feature.rigctlserver", "RigCtlServerSettings"} +}; + // Get integer value from within JSON object bool WebAPIUtils::getObjectInt(const QJsonObject &json, const QString &key, int &value) { @@ -114,3 +332,193 @@ bool WebAPIUtils::setSubObjectDouble(QJsonObject &json, const QString &key, doub return false; } + +// look for value in key=value +bool WebAPIUtils::extractValue(const QJsonObject &json, const QString &key, QJsonValue &value) +{ + // final + if (json.contains(key)) + { + value = json[key]; + return true; + } + else + { + for (QJsonObject::const_iterator it = json.begin(); it != json.end(); it++) + { + QJsonValue jsonValue = it.value(); + + if (jsonValue.isObject()) + { + if (extractValue(jsonValue.toObject(), key, value)) { + return true; + } + } + } + } + + return false; +} + +// look for [...] in key=[...] +bool WebAPIUtils::extractArray(const QJsonObject &json, const QString &key, QJsonArray &value) +{ + // final + if (json.contains(key)) + { + if (json[key].isArray()) + { + value = json[key].toArray(); + return true; + } + else + { + return false; + } + } + else + { + for (QJsonObject::const_iterator it = json.begin(); it != json.end(); it++) + { + QJsonValue jsonValue = it.value(); + + if (jsonValue.isObject()) + { + if (extractArray(jsonValue.toObject(), key, value)) { + return true; + } + } + } + } + + return false; +} + +// look for {...} in key={...} +bool WebAPIUtils::extractObject(const QJsonObject &json, const QString &key, QJsonObject &value) +{ + // final + if (json.contains(key)) + { + if (json[key].isObject()) + { + value = json[key].toObject(); + return true; + } + else + { + return false; + } + } + else + { + for (QJsonObject::const_iterator it = json.begin(); it != json.end(); it++) + { + QJsonValue jsonValue = it.value(); + + if (jsonValue.isObject()) + { + if (extractObject(jsonValue.toObject(), key, value)) { + return true; + } + } + } + } + + return false; +} + +// set value in key=value +bool WebAPIUtils::setValue(const QJsonObject &json, const QString &key, const QJsonValue &value) +{ + // final + if (json.contains(key)) + { + json[key] = value; + return true; + } + else + { + for (QJsonObject::const_iterator it = json.begin(); it != json.end(); it++) + { + QJsonValue jsonValue = it.value(); + + if (jsonValue.isObject()) + { + if (setValue(jsonValue.toObject(), key, value)) { + return true; + } + } + } + } + + return false; +} + +// set [...] in key=[...] +bool WebAPIUtils::setArray(const QJsonObject &json, const QString &key, const QJsonArray &value) +{ + // final + if (json.contains(key)) + { + if (json[key].isArray()) + { + json[key] = value; + return true; + } + else + { + return false; + } + } + else + { + for (QJsonObject::const_iterator it = json.begin(); it != json.end(); it++) + { + QJsonValue jsonValue = it.value(); + + if (jsonValue.isObject()) + { + if (setArray(jsonValue.toObject(), key, value)) { + return true; + } + } + } + } + + return false; +} + +// set {...} in key={...} +bool WebAPIUtils::setObject(const QJsonObject &json, const QString &key, const QJsonObject &value) +{ + // final + if (json.contains(key)) + { + if (json[key].isObject()) + { + json[key] = value; + return true; + } + else + { + return false; + } + } + else + { + for (QJsonObject::const_iterator it = json.begin(); it != json.end(); it++) + { + QJsonValue jsonValue = it.value(); + + if (jsonValue.isObject()) + { + if (setObject(jsonValue.toObject(), key, value)) { + return true; + } + } + } + } + + return false; +} diff --git a/sdrbase/webapi/webapiutils.h b/sdrbase/webapi/webapiutils.h index 3a99167f9..32ae7591e 100644 --- a/sdrbase/webapi/webapiutils.h +++ b/sdrbase/webapi/webapiutils.h @@ -21,17 +21,38 @@ #include #include +#include #include "export.h" class SDRBASE_API WebAPIUtils { public: + static const QMap m_channelURIToSettingsKey; + static const QMap m_deviceIdToSettingsKey; + static const QMap m_channelTypeToSettingsKey; + static const QMap m_sourceDeviceHwIdToSettingsKey; + static const QMap m_sinkDeviceHwIdToSettingsKey; + static const QMap m_mimoDeviceHwIdToSettingsKey; + static const QMap m_channelTypeToActionsKey; + static const QMap m_sourceDeviceHwIdToActionsKey; + static const QMap m_sinkDeviceHwIdToActionsKey; + static const QMap m_mimoDeviceHwIdToActionsKey; + static const QMap m_featureTypeToSettingsKey; + static const QMap m_featureTypeToActionsKey; + static const QMap m_featureURIToSettingsKey; + static bool getObjectInt(const QJsonObject &json, const QString &key, int &value); static bool getObjectString(const QJsonObject &json, const QString &key, QString &value); static bool getObjectObjects(const QJsonObject &json, const QString &key, QList &objects); static bool getSubObjectDouble(const QJsonObject &json, const QString &key, double &value); static bool setSubObjectDouble(QJsonObject &json, const QString &key, double value); + static bool extractValue(const QJsonObject &json, const QString &key, QJsonValue &value); + static bool extractArray(const QJsonObject &json, const QString &key, QJsonArray &value); + static bool extractObject(const QJsonObject &json, const QString &key, QJsonObject &value); + static bool setValue(const QJsonObject &json, const QString &key, const QJsonValue &value); + static bool setArray(const QJsonObject &json, const QString &key, const QJsonArray &value); + static bool setObject(const QJsonObject &json, const QString &key, const QJsonObject &value); }; #endif diff --git a/sdrgui/resources/arrow_left.png b/sdrgui/resources/arrow_left.png new file mode 100644 index 000000000..4445d0ac2 Binary files /dev/null and b/sdrgui/resources/arrow_left.png differ diff --git a/sdrgui/resources/res.qrc b/sdrgui/resources/res.qrc index 8480b58bf..33f47fa23 100644 --- a/sdrgui/resources/res.qrc +++ b/sdrgui/resources/res.qrc @@ -11,6 +11,7 @@ aircraft_drone.png map_antenna.png map_truck.png + arrow_left.png star.png swap.png gridpolar.png diff --git a/swagger/sdrangel/api/swagger/include/AFC.yaml b/swagger/sdrangel/api/swagger/include/AFC.yaml new file mode 100644 index 000000000..ebd836e63 --- /dev/null +++ b/swagger/sdrangel/api/swagger/include/AFC.yaml @@ -0,0 +1,76 @@ +AFCSettings: + description: "AFC settings" + properties: + title: + type: string + rgbColor: + type: integer + trackerDeviceSetIndex: + description: index of the device set of frequency tracker being used + type: integer + trackedDeviceSetIndex: + description: index of the device set being tracked (channels and possibly device) + type: integer + hasTargetFrequency: + type: integer + description: > + Adjust device frequency to match tracker frequency + * 0 - disabled + * 1 - enabled + transverterTarget: + type: integer + description: > + Use transverter or device frequency for tracker frequency adjustment + * 0 - device + * 1 - transverter + targetFrequency: + description: Target frequency for the tracker + type: integer + format: int64 + freqTolerance: + descritpion: Frequency shift tolerance before tracker frequency is (re)adjusted + type: integer + trackerAdjustPeriod: + description: Tracker channel frequency adjustment period in seconds + type: integer + useReverseAPI: + description: Synchronize with reverse API (1 for yes, 0 for no) + type: integer + reverseAPIAddress: + type: string + reverseAPIPort: + type: integer + reverseAPIDeviceIndex: + type: integer + reverseAPIChannelIndex: + type: integer + +AFCReport: + description: "AFC report" + properties: + trackerChannelIndex: + description: Tracker index in device set + type: integer + trackerDeviceFrequency: + descritpion: Center frequency of tracker device + type: integer + format: int64 + trackerChannelOffset: + description: Tracker channel offset from device center frequency + type: integer + +AFCActions: + description: "AFC actions" + properties: + deviceTrack: + type: integer + description: > + (Re)initialize tracker target frequency adjustment + * 0 - release + * 1 - engage + devicesApply: + type: integer + description: > + (Re)initialize device sets tracking + * 0 - release + * 1 - engage diff --git a/swagger/sdrangel/api/swagger/include/FeatureActions.yaml b/swagger/sdrangel/api/swagger/include/FeatureActions.yaml index 148f90b6d..5739ae33e 100644 --- a/swagger/sdrangel/api/swagger/include/FeatureActions.yaml +++ b/swagger/sdrangel/api/swagger/include/FeatureActions.yaml @@ -13,5 +13,7 @@ FeatureActions: originatorFeatureIndex: description: Optional for reverse API. This is the feature index from where the message comes from. type: integer + AFCActions: + $ref: "http://swgserver:8081/api/swagger/include/AFC.yaml#/AFCActions" SimplePTTActions: $ref: "http://swgserver:8081/api/swagger/include/SimplePTT.yaml#/SimplePTTActions" diff --git a/swagger/sdrangel/api/swagger/include/FeatureReport.yaml b/swagger/sdrangel/api/swagger/include/FeatureReport.yaml index 4cfc15ac5..de58bdda8 100644 --- a/swagger/sdrangel/api/swagger/include/FeatureReport.yaml +++ b/swagger/sdrangel/api/swagger/include/FeatureReport.yaml @@ -7,5 +7,7 @@ FeatureReport: featureType: description: Feature type code type: string + AFCReport: + $ref: "http://swgserver:8081/api/swagger/include/AFC.yaml#/AFCReport" SimplePTTReport: $ref: "http://swgserver:8081/api/swagger/include/SimplePTT.yaml#/SimplePTTReport" diff --git a/swagger/sdrangel/api/swagger/include/FeatureSettings.yaml b/swagger/sdrangel/api/swagger/include/FeatureSettings.yaml index 621cbfada..6efff8584 100644 --- a/swagger/sdrangel/api/swagger/include/FeatureSettings.yaml +++ b/swagger/sdrangel/api/swagger/include/FeatureSettings.yaml @@ -15,6 +15,8 @@ FeatureSettings: type: integer GS232ControllerSettings: $ref: "http://swgserver:8081/api/swagger/include/GS232Controller.yaml#/GS232ControllerSettings" + AFCSettings: + $ref: "http://swgserver:8081/api/swagger/include/AFC.yaml#/AFCSettings" SimplePTTSettings: $ref: "http://swgserver:8081/api/swagger/include/SimplePTT.yaml#/SimplePTTSettings" RigCtlServerSettings: diff --git a/swagger/sdrangel/api/swagger/include/FreqTracker.yaml b/swagger/sdrangel/api/swagger/include/FreqTracker.yaml index 68a029cd5..5d507b162 100644 --- a/swagger/sdrangel/api/swagger/include/FreqTracker.yaml +++ b/swagger/sdrangel/api/swagger/include/FreqTracker.yaml @@ -19,6 +19,8 @@ FreqTrackerSettings: type: integer title: type: string + spanLog2: + type: integer alphaEMA: description: Alpha factor for delta frequency EMA type: number diff --git a/swagger/sdrangel/code/html2/index.html b/swagger/sdrangel/code/html2/index.html index aaffc30d4..3fb307511 100644 --- a/swagger/sdrangel/code/html2/index.html +++ b/swagger/sdrangel/code/html2/index.html @@ -776,6 +776,91 @@ margin-bottom: 20px; } }, "description" : "ADSBDemod" +}; + defs.AFCActions = { + "properties" : { + "deviceTrack" : { + "type" : "integer", + "description" : "(Re)initialize tracker target frequency adjustment\n * 0 - release\n * 1 - engage\n" + }, + "devicesApply" : { + "type" : "integer", + "description" : "(Re)initialize device sets tracking\n * 0 - release\n * 1 - engage\n" + } + }, + "description" : "AFC actions" +}; + defs.AFCReport = { + "properties" : { + "trackerChannelIndex" : { + "type" : "integer", + "description" : "Tracker index in device set" + }, + "trackerDeviceFrequency" : { + "type" : "integer", + "format" : "int64" + }, + "trackerChannelOffset" : { + "type" : "integer", + "description" : "Tracker channel offset from device center frequency" + } + }, + "description" : "AFC report" +}; + defs.AFCSettings = { + "properties" : { + "title" : { + "type" : "string" + }, + "rgbColor" : { + "type" : "integer" + }, + "trackerDeviceSetIndex" : { + "type" : "integer", + "description" : "index of the device set of frequency tracker being used" + }, + "trackedDeviceSetIndex" : { + "type" : "integer", + "description" : "index of the device set being tracked (channels and possibly device)" + }, + "hasTargetFrequency" : { + "type" : "integer", + "description" : "Adjust device frequency to match tracker frequency\n * 0 - disabled\n * 1 - enabled\n" + }, + "transverterTarget" : { + "type" : "integer", + "description" : "Use transverter or device frequency for tracker frequency adjustment\n * 0 - device\n * 1 - transverter\n" + }, + "targetFrequency" : { + "type" : "integer", + "format" : "int64", + "description" : "Target frequency for the tracker" + }, + "freqTolerance" : { + "type" : "integer" + }, + "trackerAdjustPeriod" : { + "type" : "integer", + "description" : "Tracker channel frequency adjustment period in seconds" + }, + "useReverseAPI" : { + "type" : "integer", + "description" : "Synchronize with reverse API (1 for yes, 0 for no)" + }, + "reverseAPIAddress" : { + "type" : "string" + }, + "reverseAPIPort" : { + "type" : "integer" + }, + "reverseAPIDeviceIndex" : { + "type" : "integer" + }, + "reverseAPIChannelIndex" : { + "type" : "integer" + } + }, + "description" : "AFC settings" }; defs.AMBEDevice = { "properties" : { @@ -3289,6 +3374,9 @@ margin-bottom: 20px; "type" : "integer", "description" : "Optional for reverse API. This is the feature index from where the message comes from." }, + "AFCActions" : { + "$ref" : "#/definitions/AFCActions" + }, "SimplePTTActions" : { "$ref" : "#/definitions/SimplePTTActions" } @@ -3315,6 +3403,9 @@ margin-bottom: 20px; "type" : "string", "description" : "Feature type code" }, + "AFCReport" : { + "$ref" : "#/definitions/AFCReport" + }, "SimplePTTReport" : { "$ref" : "#/definitions/SimplePTTReport" } @@ -3390,6 +3481,9 @@ margin-bottom: 20px; "GS232ControllerSettings" : { "$ref" : "#/definitions/GS232ControllerSettings" }, + "AFCSettings" : { + "$ref" : "#/definitions/AFCSettings" + }, "SimplePTTSettings" : { "$ref" : "#/definitions/SimplePTTSettings" }, @@ -3878,6 +3972,9 @@ margin-bottom: 20px; "title" : { "type" : "string" }, + "spanLog2" : { + "type" : "integer" + }, "alphaEMA" : { "type" : "number", "format" : "float", @@ -40117,7 +40214,7 @@ except ApiException as e:
- Generated 2020-10-27T19:23:34.436+01:00 + Generated 2020-10-27T23:03:34.026+01:00
diff --git a/swagger/sdrangel/code/qt5/client/SWGAFCActions.cpp b/swagger/sdrangel/code/qt5/client/SWGAFCActions.cpp new file mode 100644 index 000000000..96adf1fd1 --- /dev/null +++ b/swagger/sdrangel/code/qt5/client/SWGAFCActions.cpp @@ -0,0 +1,131 @@ +/** + * SDRangel + * This is the web REST/JSON API of SDRangel SDR software. SDRangel is an Open Source Qt5/OpenGL 3.0+ (4.3+ in Windows) GUI and server Software Defined Radio and signal analyzer in software. It supports Airspy, BladeRF, HackRF, LimeSDR, PlutoSDR, RTL-SDR, SDRplay RSP1, USRP and FunCube --- Limitations and specifcities: * In SDRangel GUI the first Rx device set cannot be deleted. Conversely the server starts with no device sets and its number of device sets can be reduced to zero by as many calls as necessary to /sdrangel/deviceset with DELETE method. * Preset import and export from/to file is a server only feature. * Device set focus is a GUI only feature. * The following channels are not implemented (status 501 is returned): ATV and DATV demodulators, Channel Analyzer NG, LoRa demodulator * The device settings and report structures contains only the sub-structure corresponding to the device type. The DeviceSettings and DeviceReport structures documented here shows all of them but only one will be or should be present at a time * The channel settings and report structures contains only the sub-structure corresponding to the channel type. The ChannelSettings and ChannelReport structures documented here shows all of them but only one will be or should be present at a time --- + * + * OpenAPI spec version: 4.15.0 + * Contact: f4exb06@gmail.com + * + * NOTE: This class is auto generated by the swagger code generator program. + * https://github.com/swagger-api/swagger-codegen.git + * Do not edit the class manually. + */ + + +#include "SWGAFCActions.h" + +#include "SWGHelpers.h" + +#include +#include +#include +#include + +namespace SWGSDRangel { + +SWGAFCActions::SWGAFCActions(QString* json) { + init(); + this->fromJson(*json); +} + +SWGAFCActions::SWGAFCActions() { + device_track = 0; + m_device_track_isSet = false; + devices_apply = 0; + m_devices_apply_isSet = false; +} + +SWGAFCActions::~SWGAFCActions() { + this->cleanup(); +} + +void +SWGAFCActions::init() { + device_track = 0; + m_device_track_isSet = false; + devices_apply = 0; + m_devices_apply_isSet = false; +} + +void +SWGAFCActions::cleanup() { + + +} + +SWGAFCActions* +SWGAFCActions::fromJson(QString &json) { + QByteArray array (json.toStdString().c_str()); + QJsonDocument doc = QJsonDocument::fromJson(array); + QJsonObject jsonObject = doc.object(); + this->fromJsonObject(jsonObject); + return this; +} + +void +SWGAFCActions::fromJsonObject(QJsonObject &pJson) { + ::SWGSDRangel::setValue(&device_track, pJson["deviceTrack"], "qint32", ""); + + ::SWGSDRangel::setValue(&devices_apply, pJson["devicesApply"], "qint32", ""); + +} + +QString +SWGAFCActions::asJson () +{ + QJsonObject* obj = this->asJsonObject(); + + QJsonDocument doc(*obj); + QByteArray bytes = doc.toJson(); + delete obj; + return QString(bytes); +} + +QJsonObject* +SWGAFCActions::asJsonObject() { + QJsonObject* obj = new QJsonObject(); + if(m_device_track_isSet){ + obj->insert("deviceTrack", QJsonValue(device_track)); + } + if(m_devices_apply_isSet){ + obj->insert("devicesApply", QJsonValue(devices_apply)); + } + + return obj; +} + +qint32 +SWGAFCActions::getDeviceTrack() { + return device_track; +} +void +SWGAFCActions::setDeviceTrack(qint32 device_track) { + this->device_track = device_track; + this->m_device_track_isSet = true; +} + +qint32 +SWGAFCActions::getDevicesApply() { + return devices_apply; +} +void +SWGAFCActions::setDevicesApply(qint32 devices_apply) { + this->devices_apply = devices_apply; + this->m_devices_apply_isSet = true; +} + + +bool +SWGAFCActions::isSet(){ + bool isObjectUpdated = false; + do{ + if(m_device_track_isSet){ + isObjectUpdated = true; break; + } + if(m_devices_apply_isSet){ + isObjectUpdated = true; break; + } + }while(false); + return isObjectUpdated; +} +} + diff --git a/swagger/sdrangel/code/qt5/client/SWGAFCActions.h b/swagger/sdrangel/code/qt5/client/SWGAFCActions.h new file mode 100644 index 000000000..7afe7c4d6 --- /dev/null +++ b/swagger/sdrangel/code/qt5/client/SWGAFCActions.h @@ -0,0 +1,64 @@ +/** + * SDRangel + * This is the web REST/JSON API of SDRangel SDR software. SDRangel is an Open Source Qt5/OpenGL 3.0+ (4.3+ in Windows) GUI and server Software Defined Radio and signal analyzer in software. It supports Airspy, BladeRF, HackRF, LimeSDR, PlutoSDR, RTL-SDR, SDRplay RSP1, USRP and FunCube --- Limitations and specifcities: * In SDRangel GUI the first Rx device set cannot be deleted. Conversely the server starts with no device sets and its number of device sets can be reduced to zero by as many calls as necessary to /sdrangel/deviceset with DELETE method. * Preset import and export from/to file is a server only feature. * Device set focus is a GUI only feature. * The following channels are not implemented (status 501 is returned): ATV and DATV demodulators, Channel Analyzer NG, LoRa demodulator * The device settings and report structures contains only the sub-structure corresponding to the device type. The DeviceSettings and DeviceReport structures documented here shows all of them but only one will be or should be present at a time * The channel settings and report structures contains only the sub-structure corresponding to the channel type. The ChannelSettings and ChannelReport structures documented here shows all of them but only one will be or should be present at a time --- + * + * OpenAPI spec version: 4.15.0 + * Contact: f4exb06@gmail.com + * + * NOTE: This class is auto generated by the swagger code generator program. + * https://github.com/swagger-api/swagger-codegen.git + * Do not edit the class manually. + */ + +/* + * SWGAFCActions.h + * + * AFC actions + */ + +#ifndef SWGAFCActions_H_ +#define SWGAFCActions_H_ + +#include + + + +#include "SWGObject.h" +#include "export.h" + +namespace SWGSDRangel { + +class SWG_API SWGAFCActions: public SWGObject { +public: + SWGAFCActions(); + SWGAFCActions(QString* json); + virtual ~SWGAFCActions(); + void init(); + void cleanup(); + + virtual QString asJson () override; + virtual QJsonObject* asJsonObject() override; + virtual void fromJsonObject(QJsonObject &json) override; + virtual SWGAFCActions* fromJson(QString &jsonString) override; + + qint32 getDeviceTrack(); + void setDeviceTrack(qint32 device_track); + + qint32 getDevicesApply(); + void setDevicesApply(qint32 devices_apply); + + + virtual bool isSet() override; + +private: + qint32 device_track; + bool m_device_track_isSet; + + qint32 devices_apply; + bool m_devices_apply_isSet; + +}; + +} + +#endif /* SWGAFCActions_H_ */ diff --git a/swagger/sdrangel/code/qt5/client/SWGAFCReport.cpp b/swagger/sdrangel/code/qt5/client/SWGAFCReport.cpp new file mode 100644 index 000000000..f577686c2 --- /dev/null +++ b/swagger/sdrangel/code/qt5/client/SWGAFCReport.cpp @@ -0,0 +1,154 @@ +/** + * SDRangel + * This is the web REST/JSON API of SDRangel SDR software. SDRangel is an Open Source Qt5/OpenGL 3.0+ (4.3+ in Windows) GUI and server Software Defined Radio and signal analyzer in software. It supports Airspy, BladeRF, HackRF, LimeSDR, PlutoSDR, RTL-SDR, SDRplay RSP1, USRP and FunCube --- Limitations and specifcities: * In SDRangel GUI the first Rx device set cannot be deleted. Conversely the server starts with no device sets and its number of device sets can be reduced to zero by as many calls as necessary to /sdrangel/deviceset with DELETE method. * Preset import and export from/to file is a server only feature. * Device set focus is a GUI only feature. * The following channels are not implemented (status 501 is returned): ATV and DATV demodulators, Channel Analyzer NG, LoRa demodulator * The device settings and report structures contains only the sub-structure corresponding to the device type. The DeviceSettings and DeviceReport structures documented here shows all of them but only one will be or should be present at a time * The channel settings and report structures contains only the sub-structure corresponding to the channel type. The ChannelSettings and ChannelReport structures documented here shows all of them but only one will be or should be present at a time --- + * + * OpenAPI spec version: 4.15.0 + * Contact: f4exb06@gmail.com + * + * NOTE: This class is auto generated by the swagger code generator program. + * https://github.com/swagger-api/swagger-codegen.git + * Do not edit the class manually. + */ + + +#include "SWGAFCReport.h" + +#include "SWGHelpers.h" + +#include +#include +#include +#include + +namespace SWGSDRangel { + +SWGAFCReport::SWGAFCReport(QString* json) { + init(); + this->fromJson(*json); +} + +SWGAFCReport::SWGAFCReport() { + tracker_channel_index = 0; + m_tracker_channel_index_isSet = false; + tracker_device_frequency = 0L; + m_tracker_device_frequency_isSet = false; + tracker_channel_offset = 0; + m_tracker_channel_offset_isSet = false; +} + +SWGAFCReport::~SWGAFCReport() { + this->cleanup(); +} + +void +SWGAFCReport::init() { + tracker_channel_index = 0; + m_tracker_channel_index_isSet = false; + tracker_device_frequency = 0L; + m_tracker_device_frequency_isSet = false; + tracker_channel_offset = 0; + m_tracker_channel_offset_isSet = false; +} + +void +SWGAFCReport::cleanup() { + + + +} + +SWGAFCReport* +SWGAFCReport::fromJson(QString &json) { + QByteArray array (json.toStdString().c_str()); + QJsonDocument doc = QJsonDocument::fromJson(array); + QJsonObject jsonObject = doc.object(); + this->fromJsonObject(jsonObject); + return this; +} + +void +SWGAFCReport::fromJsonObject(QJsonObject &pJson) { + ::SWGSDRangel::setValue(&tracker_channel_index, pJson["trackerChannelIndex"], "qint32", ""); + + ::SWGSDRangel::setValue(&tracker_device_frequency, pJson["trackerDeviceFrequency"], "qint64", ""); + + ::SWGSDRangel::setValue(&tracker_channel_offset, pJson["trackerChannelOffset"], "qint32", ""); + +} + +QString +SWGAFCReport::asJson () +{ + QJsonObject* obj = this->asJsonObject(); + + QJsonDocument doc(*obj); + QByteArray bytes = doc.toJson(); + delete obj; + return QString(bytes); +} + +QJsonObject* +SWGAFCReport::asJsonObject() { + QJsonObject* obj = new QJsonObject(); + if(m_tracker_channel_index_isSet){ + obj->insert("trackerChannelIndex", QJsonValue(tracker_channel_index)); + } + if(m_tracker_device_frequency_isSet){ + obj->insert("trackerDeviceFrequency", QJsonValue(tracker_device_frequency)); + } + if(m_tracker_channel_offset_isSet){ + obj->insert("trackerChannelOffset", QJsonValue(tracker_channel_offset)); + } + + return obj; +} + +qint32 +SWGAFCReport::getTrackerChannelIndex() { + return tracker_channel_index; +} +void +SWGAFCReport::setTrackerChannelIndex(qint32 tracker_channel_index) { + this->tracker_channel_index = tracker_channel_index; + this->m_tracker_channel_index_isSet = true; +} + +qint64 +SWGAFCReport::getTrackerDeviceFrequency() { + return tracker_device_frequency; +} +void +SWGAFCReport::setTrackerDeviceFrequency(qint64 tracker_device_frequency) { + this->tracker_device_frequency = tracker_device_frequency; + this->m_tracker_device_frequency_isSet = true; +} + +qint32 +SWGAFCReport::getTrackerChannelOffset() { + return tracker_channel_offset; +} +void +SWGAFCReport::setTrackerChannelOffset(qint32 tracker_channel_offset) { + this->tracker_channel_offset = tracker_channel_offset; + this->m_tracker_channel_offset_isSet = true; +} + + +bool +SWGAFCReport::isSet(){ + bool isObjectUpdated = false; + do{ + if(m_tracker_channel_index_isSet){ + isObjectUpdated = true; break; + } + if(m_tracker_device_frequency_isSet){ + isObjectUpdated = true; break; + } + if(m_tracker_channel_offset_isSet){ + isObjectUpdated = true; break; + } + }while(false); + return isObjectUpdated; +} +} + diff --git a/swagger/sdrangel/code/qt5/client/SWGAFCReport.h b/swagger/sdrangel/code/qt5/client/SWGAFCReport.h new file mode 100644 index 000000000..81ba69f0c --- /dev/null +++ b/swagger/sdrangel/code/qt5/client/SWGAFCReport.h @@ -0,0 +1,70 @@ +/** + * SDRangel + * This is the web REST/JSON API of SDRangel SDR software. SDRangel is an Open Source Qt5/OpenGL 3.0+ (4.3+ in Windows) GUI and server Software Defined Radio and signal analyzer in software. It supports Airspy, BladeRF, HackRF, LimeSDR, PlutoSDR, RTL-SDR, SDRplay RSP1, USRP and FunCube --- Limitations and specifcities: * In SDRangel GUI the first Rx device set cannot be deleted. Conversely the server starts with no device sets and its number of device sets can be reduced to zero by as many calls as necessary to /sdrangel/deviceset with DELETE method. * Preset import and export from/to file is a server only feature. * Device set focus is a GUI only feature. * The following channels are not implemented (status 501 is returned): ATV and DATV demodulators, Channel Analyzer NG, LoRa demodulator * The device settings and report structures contains only the sub-structure corresponding to the device type. The DeviceSettings and DeviceReport structures documented here shows all of them but only one will be or should be present at a time * The channel settings and report structures contains only the sub-structure corresponding to the channel type. The ChannelSettings and ChannelReport structures documented here shows all of them but only one will be or should be present at a time --- + * + * OpenAPI spec version: 4.15.0 + * Contact: f4exb06@gmail.com + * + * NOTE: This class is auto generated by the swagger code generator program. + * https://github.com/swagger-api/swagger-codegen.git + * Do not edit the class manually. + */ + +/* + * SWGAFCReport.h + * + * AFC report + */ + +#ifndef SWGAFCReport_H_ +#define SWGAFCReport_H_ + +#include + + + +#include "SWGObject.h" +#include "export.h" + +namespace SWGSDRangel { + +class SWG_API SWGAFCReport: public SWGObject { +public: + SWGAFCReport(); + SWGAFCReport(QString* json); + virtual ~SWGAFCReport(); + void init(); + void cleanup(); + + virtual QString asJson () override; + virtual QJsonObject* asJsonObject() override; + virtual void fromJsonObject(QJsonObject &json) override; + virtual SWGAFCReport* fromJson(QString &jsonString) override; + + qint32 getTrackerChannelIndex(); + void setTrackerChannelIndex(qint32 tracker_channel_index); + + qint64 getTrackerDeviceFrequency(); + void setTrackerDeviceFrequency(qint64 tracker_device_frequency); + + qint32 getTrackerChannelOffset(); + void setTrackerChannelOffset(qint32 tracker_channel_offset); + + + virtual bool isSet() override; + +private: + qint32 tracker_channel_index; + bool m_tracker_channel_index_isSet; + + qint64 tracker_device_frequency; + bool m_tracker_device_frequency_isSet; + + qint32 tracker_channel_offset; + bool m_tracker_channel_offset_isSet; + +}; + +} + +#endif /* SWGAFCReport_H_ */ diff --git a/swagger/sdrangel/code/qt5/client/SWGAFCSettings.cpp b/swagger/sdrangel/code/qt5/client/SWGAFCSettings.cpp new file mode 100644 index 000000000..656f0b51b --- /dev/null +++ b/swagger/sdrangel/code/qt5/client/SWGAFCSettings.cpp @@ -0,0 +1,411 @@ +/** + * SDRangel + * This is the web REST/JSON API of SDRangel SDR software. SDRangel is an Open Source Qt5/OpenGL 3.0+ (4.3+ in Windows) GUI and server Software Defined Radio and signal analyzer in software. It supports Airspy, BladeRF, HackRF, LimeSDR, PlutoSDR, RTL-SDR, SDRplay RSP1, USRP and FunCube --- Limitations and specifcities: * In SDRangel GUI the first Rx device set cannot be deleted. Conversely the server starts with no device sets and its number of device sets can be reduced to zero by as many calls as necessary to /sdrangel/deviceset with DELETE method. * Preset import and export from/to file is a server only feature. * Device set focus is a GUI only feature. * The following channels are not implemented (status 501 is returned): ATV and DATV demodulators, Channel Analyzer NG, LoRa demodulator * The device settings and report structures contains only the sub-structure corresponding to the device type. The DeviceSettings and DeviceReport structures documented here shows all of them but only one will be or should be present at a time * The channel settings and report structures contains only the sub-structure corresponding to the channel type. The ChannelSettings and ChannelReport structures documented here shows all of them but only one will be or should be present at a time --- + * + * OpenAPI spec version: 4.15.0 + * Contact: f4exb06@gmail.com + * + * NOTE: This class is auto generated by the swagger code generator program. + * https://github.com/swagger-api/swagger-codegen.git + * Do not edit the class manually. + */ + + +#include "SWGAFCSettings.h" + +#include "SWGHelpers.h" + +#include +#include +#include +#include + +namespace SWGSDRangel { + +SWGAFCSettings::SWGAFCSettings(QString* json) { + init(); + this->fromJson(*json); +} + +SWGAFCSettings::SWGAFCSettings() { + title = nullptr; + m_title_isSet = false; + rgb_color = 0; + m_rgb_color_isSet = false; + tracker_device_set_index = 0; + m_tracker_device_set_index_isSet = false; + tracked_device_set_index = 0; + m_tracked_device_set_index_isSet = false; + has_target_frequency = 0; + m_has_target_frequency_isSet = false; + transverter_target = 0; + m_transverter_target_isSet = false; + target_frequency = 0L; + m_target_frequency_isSet = false; + freq_tolerance = 0; + m_freq_tolerance_isSet = false; + tracker_adjust_period = 0; + m_tracker_adjust_period_isSet = false; + use_reverse_api = 0; + m_use_reverse_api_isSet = false; + reverse_api_address = nullptr; + m_reverse_api_address_isSet = false; + reverse_api_port = 0; + m_reverse_api_port_isSet = false; + reverse_api_device_index = 0; + m_reverse_api_device_index_isSet = false; + reverse_api_channel_index = 0; + m_reverse_api_channel_index_isSet = false; +} + +SWGAFCSettings::~SWGAFCSettings() { + this->cleanup(); +} + +void +SWGAFCSettings::init() { + title = new QString(""); + m_title_isSet = false; + rgb_color = 0; + m_rgb_color_isSet = false; + tracker_device_set_index = 0; + m_tracker_device_set_index_isSet = false; + tracked_device_set_index = 0; + m_tracked_device_set_index_isSet = false; + has_target_frequency = 0; + m_has_target_frequency_isSet = false; + transverter_target = 0; + m_transverter_target_isSet = false; + target_frequency = 0L; + m_target_frequency_isSet = false; + freq_tolerance = 0; + m_freq_tolerance_isSet = false; + tracker_adjust_period = 0; + m_tracker_adjust_period_isSet = false; + use_reverse_api = 0; + m_use_reverse_api_isSet = false; + reverse_api_address = new QString(""); + m_reverse_api_address_isSet = false; + reverse_api_port = 0; + m_reverse_api_port_isSet = false; + reverse_api_device_index = 0; + m_reverse_api_device_index_isSet = false; + reverse_api_channel_index = 0; + m_reverse_api_channel_index_isSet = false; +} + +void +SWGAFCSettings::cleanup() { + if(title != nullptr) { + delete title; + } + + + + + + + + + + if(reverse_api_address != nullptr) { + delete reverse_api_address; + } + + + +} + +SWGAFCSettings* +SWGAFCSettings::fromJson(QString &json) { + QByteArray array (json.toStdString().c_str()); + QJsonDocument doc = QJsonDocument::fromJson(array); + QJsonObject jsonObject = doc.object(); + this->fromJsonObject(jsonObject); + return this; +} + +void +SWGAFCSettings::fromJsonObject(QJsonObject &pJson) { + ::SWGSDRangel::setValue(&title, pJson["title"], "QString", "QString"); + + ::SWGSDRangel::setValue(&rgb_color, pJson["rgbColor"], "qint32", ""); + + ::SWGSDRangel::setValue(&tracker_device_set_index, pJson["trackerDeviceSetIndex"], "qint32", ""); + + ::SWGSDRangel::setValue(&tracked_device_set_index, pJson["trackedDeviceSetIndex"], "qint32", ""); + + ::SWGSDRangel::setValue(&has_target_frequency, pJson["hasTargetFrequency"], "qint32", ""); + + ::SWGSDRangel::setValue(&transverter_target, pJson["transverterTarget"], "qint32", ""); + + ::SWGSDRangel::setValue(&target_frequency, pJson["targetFrequency"], "qint64", ""); + + ::SWGSDRangel::setValue(&freq_tolerance, pJson["freqTolerance"], "qint32", ""); + + ::SWGSDRangel::setValue(&tracker_adjust_period, pJson["trackerAdjustPeriod"], "qint32", ""); + + ::SWGSDRangel::setValue(&use_reverse_api, pJson["useReverseAPI"], "qint32", ""); + + ::SWGSDRangel::setValue(&reverse_api_address, pJson["reverseAPIAddress"], "QString", "QString"); + + ::SWGSDRangel::setValue(&reverse_api_port, pJson["reverseAPIPort"], "qint32", ""); + + ::SWGSDRangel::setValue(&reverse_api_device_index, pJson["reverseAPIDeviceIndex"], "qint32", ""); + + ::SWGSDRangel::setValue(&reverse_api_channel_index, pJson["reverseAPIChannelIndex"], "qint32", ""); + +} + +QString +SWGAFCSettings::asJson () +{ + QJsonObject* obj = this->asJsonObject(); + + QJsonDocument doc(*obj); + QByteArray bytes = doc.toJson(); + delete obj; + return QString(bytes); +} + +QJsonObject* +SWGAFCSettings::asJsonObject() { + QJsonObject* obj = new QJsonObject(); + if(title != nullptr && *title != QString("")){ + toJsonValue(QString("title"), title, obj, QString("QString")); + } + if(m_rgb_color_isSet){ + obj->insert("rgbColor", QJsonValue(rgb_color)); + } + if(m_tracker_device_set_index_isSet){ + obj->insert("trackerDeviceSetIndex", QJsonValue(tracker_device_set_index)); + } + if(m_tracked_device_set_index_isSet){ + obj->insert("trackedDeviceSetIndex", QJsonValue(tracked_device_set_index)); + } + if(m_has_target_frequency_isSet){ + obj->insert("hasTargetFrequency", QJsonValue(has_target_frequency)); + } + if(m_transverter_target_isSet){ + obj->insert("transverterTarget", QJsonValue(transverter_target)); + } + if(m_target_frequency_isSet){ + obj->insert("targetFrequency", QJsonValue(target_frequency)); + } + if(m_freq_tolerance_isSet){ + obj->insert("freqTolerance", QJsonValue(freq_tolerance)); + } + if(m_tracker_adjust_period_isSet){ + obj->insert("trackerAdjustPeriod", QJsonValue(tracker_adjust_period)); + } + if(m_use_reverse_api_isSet){ + obj->insert("useReverseAPI", QJsonValue(use_reverse_api)); + } + if(reverse_api_address != nullptr && *reverse_api_address != QString("")){ + toJsonValue(QString("reverseAPIAddress"), reverse_api_address, obj, QString("QString")); + } + if(m_reverse_api_port_isSet){ + obj->insert("reverseAPIPort", QJsonValue(reverse_api_port)); + } + if(m_reverse_api_device_index_isSet){ + obj->insert("reverseAPIDeviceIndex", QJsonValue(reverse_api_device_index)); + } + if(m_reverse_api_channel_index_isSet){ + obj->insert("reverseAPIChannelIndex", QJsonValue(reverse_api_channel_index)); + } + + return obj; +} + +QString* +SWGAFCSettings::getTitle() { + return title; +} +void +SWGAFCSettings::setTitle(QString* title) { + this->title = title; + this->m_title_isSet = true; +} + +qint32 +SWGAFCSettings::getRgbColor() { + return rgb_color; +} +void +SWGAFCSettings::setRgbColor(qint32 rgb_color) { + this->rgb_color = rgb_color; + this->m_rgb_color_isSet = true; +} + +qint32 +SWGAFCSettings::getTrackerDeviceSetIndex() { + return tracker_device_set_index; +} +void +SWGAFCSettings::setTrackerDeviceSetIndex(qint32 tracker_device_set_index) { + this->tracker_device_set_index = tracker_device_set_index; + this->m_tracker_device_set_index_isSet = true; +} + +qint32 +SWGAFCSettings::getTrackedDeviceSetIndex() { + return tracked_device_set_index; +} +void +SWGAFCSettings::setTrackedDeviceSetIndex(qint32 tracked_device_set_index) { + this->tracked_device_set_index = tracked_device_set_index; + this->m_tracked_device_set_index_isSet = true; +} + +qint32 +SWGAFCSettings::getHasTargetFrequency() { + return has_target_frequency; +} +void +SWGAFCSettings::setHasTargetFrequency(qint32 has_target_frequency) { + this->has_target_frequency = has_target_frequency; + this->m_has_target_frequency_isSet = true; +} + +qint32 +SWGAFCSettings::getTransverterTarget() { + return transverter_target; +} +void +SWGAFCSettings::setTransverterTarget(qint32 transverter_target) { + this->transverter_target = transverter_target; + this->m_transverter_target_isSet = true; +} + +qint64 +SWGAFCSettings::getTargetFrequency() { + return target_frequency; +} +void +SWGAFCSettings::setTargetFrequency(qint64 target_frequency) { + this->target_frequency = target_frequency; + this->m_target_frequency_isSet = true; +} + +qint32 +SWGAFCSettings::getFreqTolerance() { + return freq_tolerance; +} +void +SWGAFCSettings::setFreqTolerance(qint32 freq_tolerance) { + this->freq_tolerance = freq_tolerance; + this->m_freq_tolerance_isSet = true; +} + +qint32 +SWGAFCSettings::getTrackerAdjustPeriod() { + return tracker_adjust_period; +} +void +SWGAFCSettings::setTrackerAdjustPeriod(qint32 tracker_adjust_period) { + this->tracker_adjust_period = tracker_adjust_period; + this->m_tracker_adjust_period_isSet = true; +} + +qint32 +SWGAFCSettings::getUseReverseApi() { + return use_reverse_api; +} +void +SWGAFCSettings::setUseReverseApi(qint32 use_reverse_api) { + this->use_reverse_api = use_reverse_api; + this->m_use_reverse_api_isSet = true; +} + +QString* +SWGAFCSettings::getReverseApiAddress() { + return reverse_api_address; +} +void +SWGAFCSettings::setReverseApiAddress(QString* reverse_api_address) { + this->reverse_api_address = reverse_api_address; + this->m_reverse_api_address_isSet = true; +} + +qint32 +SWGAFCSettings::getReverseApiPort() { + return reverse_api_port; +} +void +SWGAFCSettings::setReverseApiPort(qint32 reverse_api_port) { + this->reverse_api_port = reverse_api_port; + this->m_reverse_api_port_isSet = true; +} + +qint32 +SWGAFCSettings::getReverseApiDeviceIndex() { + return reverse_api_device_index; +} +void +SWGAFCSettings::setReverseApiDeviceIndex(qint32 reverse_api_device_index) { + this->reverse_api_device_index = reverse_api_device_index; + this->m_reverse_api_device_index_isSet = true; +} + +qint32 +SWGAFCSettings::getReverseApiChannelIndex() { + return reverse_api_channel_index; +} +void +SWGAFCSettings::setReverseApiChannelIndex(qint32 reverse_api_channel_index) { + this->reverse_api_channel_index = reverse_api_channel_index; + this->m_reverse_api_channel_index_isSet = true; +} + + +bool +SWGAFCSettings::isSet(){ + bool isObjectUpdated = false; + do{ + if(title && *title != QString("")){ + isObjectUpdated = true; break; + } + if(m_rgb_color_isSet){ + isObjectUpdated = true; break; + } + if(m_tracker_device_set_index_isSet){ + isObjectUpdated = true; break; + } + if(m_tracked_device_set_index_isSet){ + isObjectUpdated = true; break; + } + if(m_has_target_frequency_isSet){ + isObjectUpdated = true; break; + } + if(m_transverter_target_isSet){ + isObjectUpdated = true; break; + } + if(m_target_frequency_isSet){ + isObjectUpdated = true; break; + } + if(m_freq_tolerance_isSet){ + isObjectUpdated = true; break; + } + if(m_tracker_adjust_period_isSet){ + isObjectUpdated = true; break; + } + if(m_use_reverse_api_isSet){ + isObjectUpdated = true; break; + } + if(reverse_api_address && *reverse_api_address != QString("")){ + isObjectUpdated = true; break; + } + if(m_reverse_api_port_isSet){ + isObjectUpdated = true; break; + } + if(m_reverse_api_device_index_isSet){ + isObjectUpdated = true; break; + } + if(m_reverse_api_channel_index_isSet){ + isObjectUpdated = true; break; + } + }while(false); + return isObjectUpdated; +} +} + diff --git a/swagger/sdrangel/code/qt5/client/SWGAFCSettings.h b/swagger/sdrangel/code/qt5/client/SWGAFCSettings.h new file mode 100644 index 000000000..02dfb2b5e --- /dev/null +++ b/swagger/sdrangel/code/qt5/client/SWGAFCSettings.h @@ -0,0 +1,137 @@ +/** + * SDRangel + * This is the web REST/JSON API of SDRangel SDR software. SDRangel is an Open Source Qt5/OpenGL 3.0+ (4.3+ in Windows) GUI and server Software Defined Radio and signal analyzer in software. It supports Airspy, BladeRF, HackRF, LimeSDR, PlutoSDR, RTL-SDR, SDRplay RSP1, USRP and FunCube --- Limitations and specifcities: * In SDRangel GUI the first Rx device set cannot be deleted. Conversely the server starts with no device sets and its number of device sets can be reduced to zero by as many calls as necessary to /sdrangel/deviceset with DELETE method. * Preset import and export from/to file is a server only feature. * Device set focus is a GUI only feature. * The following channels are not implemented (status 501 is returned): ATV and DATV demodulators, Channel Analyzer NG, LoRa demodulator * The device settings and report structures contains only the sub-structure corresponding to the device type. The DeviceSettings and DeviceReport structures documented here shows all of them but only one will be or should be present at a time * The channel settings and report structures contains only the sub-structure corresponding to the channel type. The ChannelSettings and ChannelReport structures documented here shows all of them but only one will be or should be present at a time --- + * + * OpenAPI spec version: 4.15.0 + * Contact: f4exb06@gmail.com + * + * NOTE: This class is auto generated by the swagger code generator program. + * https://github.com/swagger-api/swagger-codegen.git + * Do not edit the class manually. + */ + +/* + * SWGAFCSettings.h + * + * AFC settings + */ + +#ifndef SWGAFCSettings_H_ +#define SWGAFCSettings_H_ + +#include + + +#include + +#include "SWGObject.h" +#include "export.h" + +namespace SWGSDRangel { + +class SWG_API SWGAFCSettings: public SWGObject { +public: + SWGAFCSettings(); + SWGAFCSettings(QString* json); + virtual ~SWGAFCSettings(); + void init(); + void cleanup(); + + virtual QString asJson () override; + virtual QJsonObject* asJsonObject() override; + virtual void fromJsonObject(QJsonObject &json) override; + virtual SWGAFCSettings* fromJson(QString &jsonString) override; + + QString* getTitle(); + void setTitle(QString* title); + + qint32 getRgbColor(); + void setRgbColor(qint32 rgb_color); + + qint32 getTrackerDeviceSetIndex(); + void setTrackerDeviceSetIndex(qint32 tracker_device_set_index); + + qint32 getTrackedDeviceSetIndex(); + void setTrackedDeviceSetIndex(qint32 tracked_device_set_index); + + qint32 getHasTargetFrequency(); + void setHasTargetFrequency(qint32 has_target_frequency); + + qint32 getTransverterTarget(); + void setTransverterTarget(qint32 transverter_target); + + qint64 getTargetFrequency(); + void setTargetFrequency(qint64 target_frequency); + + qint32 getFreqTolerance(); + void setFreqTolerance(qint32 freq_tolerance); + + qint32 getTrackerAdjustPeriod(); + void setTrackerAdjustPeriod(qint32 tracker_adjust_period); + + qint32 getUseReverseApi(); + void setUseReverseApi(qint32 use_reverse_api); + + QString* getReverseApiAddress(); + void setReverseApiAddress(QString* reverse_api_address); + + qint32 getReverseApiPort(); + void setReverseApiPort(qint32 reverse_api_port); + + qint32 getReverseApiDeviceIndex(); + void setReverseApiDeviceIndex(qint32 reverse_api_device_index); + + qint32 getReverseApiChannelIndex(); + void setReverseApiChannelIndex(qint32 reverse_api_channel_index); + + + virtual bool isSet() override; + +private: + QString* title; + bool m_title_isSet; + + qint32 rgb_color; + bool m_rgb_color_isSet; + + qint32 tracker_device_set_index; + bool m_tracker_device_set_index_isSet; + + qint32 tracked_device_set_index; + bool m_tracked_device_set_index_isSet; + + qint32 has_target_frequency; + bool m_has_target_frequency_isSet; + + qint32 transverter_target; + bool m_transverter_target_isSet; + + qint64 target_frequency; + bool m_target_frequency_isSet; + + qint32 freq_tolerance; + bool m_freq_tolerance_isSet; + + qint32 tracker_adjust_period; + bool m_tracker_adjust_period_isSet; + + qint32 use_reverse_api; + bool m_use_reverse_api_isSet; + + QString* reverse_api_address; + bool m_reverse_api_address_isSet; + + qint32 reverse_api_port; + bool m_reverse_api_port_isSet; + + qint32 reverse_api_device_index; + bool m_reverse_api_device_index_isSet; + + qint32 reverse_api_channel_index; + bool m_reverse_api_channel_index_isSet; + +}; + +} + +#endif /* SWGAFCSettings_H_ */ diff --git a/swagger/sdrangel/code/qt5/client/SWGFeatureActions.cpp b/swagger/sdrangel/code/qt5/client/SWGFeatureActions.cpp index 8b7fec5ea..8d28c594b 100644 --- a/swagger/sdrangel/code/qt5/client/SWGFeatureActions.cpp +++ b/swagger/sdrangel/code/qt5/client/SWGFeatureActions.cpp @@ -34,6 +34,8 @@ SWGFeatureActions::SWGFeatureActions() { m_originator_feature_set_index_isSet = false; originator_feature_index = 0; m_originator_feature_index_isSet = false; + afc_actions = nullptr; + m_afc_actions_isSet = false; simple_ptt_actions = nullptr; m_simple_ptt_actions_isSet = false; } @@ -50,6 +52,8 @@ SWGFeatureActions::init() { m_originator_feature_set_index_isSet = false; originator_feature_index = 0; m_originator_feature_index_isSet = false; + afc_actions = new SWGAFCActions(); + m_afc_actions_isSet = false; simple_ptt_actions = new SWGSimplePTTActions(); m_simple_ptt_actions_isSet = false; } @@ -61,6 +65,9 @@ SWGFeatureActions::cleanup() { } + if(afc_actions != nullptr) { + delete afc_actions; + } if(simple_ptt_actions != nullptr) { delete simple_ptt_actions; } @@ -83,6 +90,8 @@ SWGFeatureActions::fromJsonObject(QJsonObject &pJson) { ::SWGSDRangel::setValue(&originator_feature_index, pJson["originatorFeatureIndex"], "qint32", ""); + ::SWGSDRangel::setValue(&afc_actions, pJson["AFCActions"], "SWGAFCActions", "SWGAFCActions"); + ::SWGSDRangel::setValue(&simple_ptt_actions, pJson["SimplePTTActions"], "SWGSimplePTTActions", "SWGSimplePTTActions"); } @@ -110,6 +119,9 @@ SWGFeatureActions::asJsonObject() { if(m_originator_feature_index_isSet){ obj->insert("originatorFeatureIndex", QJsonValue(originator_feature_index)); } + if((afc_actions != nullptr) && (afc_actions->isSet())){ + toJsonValue(QString("AFCActions"), afc_actions, obj, QString("SWGAFCActions")); + } if((simple_ptt_actions != nullptr) && (simple_ptt_actions->isSet())){ toJsonValue(QString("SimplePTTActions"), simple_ptt_actions, obj, QString("SWGSimplePTTActions")); } @@ -147,6 +159,16 @@ SWGFeatureActions::setOriginatorFeatureIndex(qint32 originator_feature_index) { this->m_originator_feature_index_isSet = true; } +SWGAFCActions* +SWGFeatureActions::getAfcActions() { + return afc_actions; +} +void +SWGFeatureActions::setAfcActions(SWGAFCActions* afc_actions) { + this->afc_actions = afc_actions; + this->m_afc_actions_isSet = true; +} + SWGSimplePTTActions* SWGFeatureActions::getSimplePttActions() { return simple_ptt_actions; @@ -171,6 +193,9 @@ SWGFeatureActions::isSet(){ if(m_originator_feature_index_isSet){ isObjectUpdated = true; break; } + if(afc_actions && afc_actions->isSet()){ + isObjectUpdated = true; break; + } if(simple_ptt_actions && simple_ptt_actions->isSet()){ isObjectUpdated = true; break; } diff --git a/swagger/sdrangel/code/qt5/client/SWGFeatureActions.h b/swagger/sdrangel/code/qt5/client/SWGFeatureActions.h index 93715663a..ee21bd369 100644 --- a/swagger/sdrangel/code/qt5/client/SWGFeatureActions.h +++ b/swagger/sdrangel/code/qt5/client/SWGFeatureActions.h @@ -22,6 +22,7 @@ #include +#include "SWGAFCActions.h" #include "SWGSimplePTTActions.h" #include @@ -52,6 +53,9 @@ public: qint32 getOriginatorFeatureIndex(); void setOriginatorFeatureIndex(qint32 originator_feature_index); + SWGAFCActions* getAfcActions(); + void setAfcActions(SWGAFCActions* afc_actions); + SWGSimplePTTActions* getSimplePttActions(); void setSimplePttActions(SWGSimplePTTActions* simple_ptt_actions); @@ -68,6 +72,9 @@ private: qint32 originator_feature_index; bool m_originator_feature_index_isSet; + SWGAFCActions* afc_actions; + bool m_afc_actions_isSet; + SWGSimplePTTActions* simple_ptt_actions; bool m_simple_ptt_actions_isSet; diff --git a/swagger/sdrangel/code/qt5/client/SWGFeatureReport.cpp b/swagger/sdrangel/code/qt5/client/SWGFeatureReport.cpp index 66b010f40..de5220891 100644 --- a/swagger/sdrangel/code/qt5/client/SWGFeatureReport.cpp +++ b/swagger/sdrangel/code/qt5/client/SWGFeatureReport.cpp @@ -30,6 +30,8 @@ SWGFeatureReport::SWGFeatureReport(QString* json) { SWGFeatureReport::SWGFeatureReport() { feature_type = nullptr; m_feature_type_isSet = false; + afc_report = nullptr; + m_afc_report_isSet = false; simple_ptt_report = nullptr; m_simple_ptt_report_isSet = false; } @@ -42,6 +44,8 @@ void SWGFeatureReport::init() { feature_type = new QString(""); m_feature_type_isSet = false; + afc_report = new SWGAFCReport(); + m_afc_report_isSet = false; simple_ptt_report = new SWGSimplePTTReport(); m_simple_ptt_report_isSet = false; } @@ -51,6 +55,9 @@ SWGFeatureReport::cleanup() { if(feature_type != nullptr) { delete feature_type; } + if(afc_report != nullptr) { + delete afc_report; + } if(simple_ptt_report != nullptr) { delete simple_ptt_report; } @@ -69,6 +76,8 @@ void SWGFeatureReport::fromJsonObject(QJsonObject &pJson) { ::SWGSDRangel::setValue(&feature_type, pJson["featureType"], "QString", "QString"); + ::SWGSDRangel::setValue(&afc_report, pJson["AFCReport"], "SWGAFCReport", "SWGAFCReport"); + ::SWGSDRangel::setValue(&simple_ptt_report, pJson["SimplePTTReport"], "SWGSimplePTTReport", "SWGSimplePTTReport"); } @@ -90,6 +99,9 @@ SWGFeatureReport::asJsonObject() { if(feature_type != nullptr && *feature_type != QString("")){ toJsonValue(QString("featureType"), feature_type, obj, QString("QString")); } + if((afc_report != nullptr) && (afc_report->isSet())){ + toJsonValue(QString("AFCReport"), afc_report, obj, QString("SWGAFCReport")); + } if((simple_ptt_report != nullptr) && (simple_ptt_report->isSet())){ toJsonValue(QString("SimplePTTReport"), simple_ptt_report, obj, QString("SWGSimplePTTReport")); } @@ -107,6 +119,16 @@ SWGFeatureReport::setFeatureType(QString* feature_type) { this->m_feature_type_isSet = true; } +SWGAFCReport* +SWGFeatureReport::getAfcReport() { + return afc_report; +} +void +SWGFeatureReport::setAfcReport(SWGAFCReport* afc_report) { + this->afc_report = afc_report; + this->m_afc_report_isSet = true; +} + SWGSimplePTTReport* SWGFeatureReport::getSimplePttReport() { return simple_ptt_report; @@ -125,6 +147,9 @@ SWGFeatureReport::isSet(){ if(feature_type && *feature_type != QString("")){ isObjectUpdated = true; break; } + if(afc_report && afc_report->isSet()){ + isObjectUpdated = true; break; + } if(simple_ptt_report && simple_ptt_report->isSet()){ isObjectUpdated = true; break; } diff --git a/swagger/sdrangel/code/qt5/client/SWGFeatureReport.h b/swagger/sdrangel/code/qt5/client/SWGFeatureReport.h index 14473da60..9fc74eb2b 100644 --- a/swagger/sdrangel/code/qt5/client/SWGFeatureReport.h +++ b/swagger/sdrangel/code/qt5/client/SWGFeatureReport.h @@ -22,6 +22,7 @@ #include +#include "SWGAFCReport.h" #include "SWGSimplePTTReport.h" #include @@ -46,6 +47,9 @@ public: QString* getFeatureType(); void setFeatureType(QString* feature_type); + SWGAFCReport* getAfcReport(); + void setAfcReport(SWGAFCReport* afc_report); + SWGSimplePTTReport* getSimplePttReport(); void setSimplePttReport(SWGSimplePTTReport* simple_ptt_report); @@ -56,6 +60,9 @@ private: QString* feature_type; bool m_feature_type_isSet; + SWGAFCReport* afc_report; + bool m_afc_report_isSet; + SWGSimplePTTReport* simple_ptt_report; bool m_simple_ptt_report_isSet; diff --git a/swagger/sdrangel/code/qt5/client/SWGFeatureSettings.cpp b/swagger/sdrangel/code/qt5/client/SWGFeatureSettings.cpp index 11580d15c..74e7bf725 100644 --- a/swagger/sdrangel/code/qt5/client/SWGFeatureSettings.cpp +++ b/swagger/sdrangel/code/qt5/client/SWGFeatureSettings.cpp @@ -36,6 +36,8 @@ SWGFeatureSettings::SWGFeatureSettings() { m_originator_feature_index_isSet = false; gs232_controller_settings = nullptr; m_gs232_controller_settings_isSet = false; + afc_settings = nullptr; + m_afc_settings_isSet = false; simple_ptt_settings = nullptr; m_simple_ptt_settings_isSet = false; rig_ctl_server_settings = nullptr; @@ -56,6 +58,8 @@ SWGFeatureSettings::init() { m_originator_feature_index_isSet = false; gs232_controller_settings = new SWGGS232ControllerSettings(); m_gs232_controller_settings_isSet = false; + afc_settings = new SWGAFCSettings(); + m_afc_settings_isSet = false; simple_ptt_settings = new SWGSimplePTTSettings(); m_simple_ptt_settings_isSet = false; rig_ctl_server_settings = new SWGRigCtlServerSettings(); @@ -72,6 +76,9 @@ SWGFeatureSettings::cleanup() { if(gs232_controller_settings != nullptr) { delete gs232_controller_settings; } + if(afc_settings != nullptr) { + delete afc_settings; + } if(simple_ptt_settings != nullptr) { delete simple_ptt_settings; } @@ -99,6 +106,8 @@ SWGFeatureSettings::fromJsonObject(QJsonObject &pJson) { ::SWGSDRangel::setValue(&gs232_controller_settings, pJson["GS232ControllerSettings"], "SWGGS232ControllerSettings", "SWGGS232ControllerSettings"); + ::SWGSDRangel::setValue(&afc_settings, pJson["AFCSettings"], "SWGAFCSettings", "SWGAFCSettings"); + ::SWGSDRangel::setValue(&simple_ptt_settings, pJson["SimplePTTSettings"], "SWGSimplePTTSettings", "SWGSimplePTTSettings"); ::SWGSDRangel::setValue(&rig_ctl_server_settings, pJson["RigCtlServerSettings"], "SWGRigCtlServerSettings", "SWGRigCtlServerSettings"); @@ -131,6 +140,9 @@ SWGFeatureSettings::asJsonObject() { if((gs232_controller_settings != nullptr) && (gs232_controller_settings->isSet())){ toJsonValue(QString("GS232ControllerSettings"), gs232_controller_settings, obj, QString("SWGGS232ControllerSettings")); } + if((afc_settings != nullptr) && (afc_settings->isSet())){ + toJsonValue(QString("AFCSettings"), afc_settings, obj, QString("SWGAFCSettings")); + } if((simple_ptt_settings != nullptr) && (simple_ptt_settings->isSet())){ toJsonValue(QString("SimplePTTSettings"), simple_ptt_settings, obj, QString("SWGSimplePTTSettings")); } @@ -181,6 +193,16 @@ SWGFeatureSettings::setGs232ControllerSettings(SWGGS232ControllerSettings* gs232 this->m_gs232_controller_settings_isSet = true; } +SWGAFCSettings* +SWGFeatureSettings::getAfcSettings() { + return afc_settings; +} +void +SWGFeatureSettings::setAfcSettings(SWGAFCSettings* afc_settings) { + this->afc_settings = afc_settings; + this->m_afc_settings_isSet = true; +} + SWGSimplePTTSettings* SWGFeatureSettings::getSimplePttSettings() { return simple_ptt_settings; @@ -218,6 +240,9 @@ SWGFeatureSettings::isSet(){ if(gs232_controller_settings && gs232_controller_settings->isSet()){ isObjectUpdated = true; break; } + if(afc_settings && afc_settings->isSet()){ + isObjectUpdated = true; break; + } if(simple_ptt_settings && simple_ptt_settings->isSet()){ isObjectUpdated = true; break; } diff --git a/swagger/sdrangel/code/qt5/client/SWGFeatureSettings.h b/swagger/sdrangel/code/qt5/client/SWGFeatureSettings.h index 9bc2b8cd5..e53b5db85 100644 --- a/swagger/sdrangel/code/qt5/client/SWGFeatureSettings.h +++ b/swagger/sdrangel/code/qt5/client/SWGFeatureSettings.h @@ -22,6 +22,7 @@ #include +#include "SWGAFCSettings.h" #include "SWGGS232ControllerSettings.h" #include "SWGRigCtlServerSettings.h" #include "SWGSimplePTTSettings.h" @@ -57,6 +58,9 @@ public: SWGGS232ControllerSettings* getGs232ControllerSettings(); void setGs232ControllerSettings(SWGGS232ControllerSettings* gs232_controller_settings); + SWGAFCSettings* getAfcSettings(); + void setAfcSettings(SWGAFCSettings* afc_settings); + SWGSimplePTTSettings* getSimplePttSettings(); void setSimplePttSettings(SWGSimplePTTSettings* simple_ptt_settings); @@ -79,6 +83,9 @@ private: SWGGS232ControllerSettings* gs232_controller_settings; bool m_gs232_controller_settings_isSet; + SWGAFCSettings* afc_settings; + bool m_afc_settings_isSet; + SWGSimplePTTSettings* simple_ptt_settings; bool m_simple_ptt_settings_isSet; diff --git a/swagger/sdrangel/code/qt5/client/SWGFreqTrackerSettings.cpp b/swagger/sdrangel/code/qt5/client/SWGFreqTrackerSettings.cpp index 1b4304d41..ecac0e393 100644 --- a/swagger/sdrangel/code/qt5/client/SWGFreqTrackerSettings.cpp +++ b/swagger/sdrangel/code/qt5/client/SWGFreqTrackerSettings.cpp @@ -40,6 +40,8 @@ SWGFreqTrackerSettings::SWGFreqTrackerSettings() { m_rgb_color_isSet = false; title = nullptr; m_title_isSet = false; + span_log2 = 0; + m_span_log2_isSet = false; alpha_ema = 0.0f; m_alpha_ema_isSet = false; tracking = 0; @@ -86,6 +88,8 @@ SWGFreqTrackerSettings::init() { m_rgb_color_isSet = false; title = new QString(""); m_title_isSet = false; + span_log2 = 0; + m_span_log2_isSet = false; alpha_ema = 0.0f; m_alpha_ema_isSet = false; tracking = 0; @@ -133,6 +137,7 @@ SWGFreqTrackerSettings::cleanup() { + if(reverse_api_address != nullptr) { delete reverse_api_address; } @@ -164,6 +169,8 @@ SWGFreqTrackerSettings::fromJsonObject(QJsonObject &pJson) { ::SWGSDRangel::setValue(&title, pJson["title"], "QString", "QString"); + ::SWGSDRangel::setValue(&span_log2, pJson["spanLog2"], "qint32", ""); + ::SWGSDRangel::setValue(&alpha_ema, pJson["alphaEMA"], "float", ""); ::SWGSDRangel::setValue(&tracking, pJson["tracking"], "qint32", ""); @@ -224,6 +231,9 @@ SWGFreqTrackerSettings::asJsonObject() { if(title != nullptr && *title != QString("")){ toJsonValue(QString("title"), title, obj, QString("QString")); } + if(m_span_log2_isSet){ + obj->insert("spanLog2", QJsonValue(span_log2)); + } if(m_alpha_ema_isSet){ obj->insert("alphaEMA", QJsonValue(alpha_ema)); } @@ -327,6 +337,16 @@ SWGFreqTrackerSettings::setTitle(QString* title) { this->m_title_isSet = true; } +qint32 +SWGFreqTrackerSettings::getSpanLog2() { + return span_log2; +} +void +SWGFreqTrackerSettings::setSpanLog2(qint32 span_log2) { + this->span_log2 = span_log2; + this->m_span_log2_isSet = true; +} + float SWGFreqTrackerSettings::getAlphaEma() { return alpha_ema; @@ -480,6 +500,9 @@ SWGFreqTrackerSettings::isSet(){ if(title && *title != QString("")){ isObjectUpdated = true; break; } + if(m_span_log2_isSet){ + isObjectUpdated = true; break; + } if(m_alpha_ema_isSet){ isObjectUpdated = true; break; } diff --git a/swagger/sdrangel/code/qt5/client/SWGFreqTrackerSettings.h b/swagger/sdrangel/code/qt5/client/SWGFreqTrackerSettings.h index a6855ff80..fee0e0247 100644 --- a/swagger/sdrangel/code/qt5/client/SWGFreqTrackerSettings.h +++ b/swagger/sdrangel/code/qt5/client/SWGFreqTrackerSettings.h @@ -60,6 +60,9 @@ public: QString* getTitle(); void setTitle(QString* title); + qint32 getSpanLog2(); + void setSpanLog2(qint32 span_log2); + float getAlphaEma(); void setAlphaEma(float alpha_ema); @@ -121,6 +124,9 @@ private: QString* title; bool m_title_isSet; + qint32 span_log2; + bool m_span_log2_isSet; + float alpha_ema; bool m_alpha_ema_isSet; diff --git a/swagger/sdrangel/code/qt5/client/SWGModelFactory.h b/swagger/sdrangel/code/qt5/client/SWGModelFactory.h index 420db2ec7..f54e54fb3 100644 --- a/swagger/sdrangel/code/qt5/client/SWGModelFactory.h +++ b/swagger/sdrangel/code/qt5/client/SWGModelFactory.h @@ -16,6 +16,9 @@ #include "SWGADSBDemodReport.h" #include "SWGADSBDemodSettings.h" +#include "SWGAFCActions.h" +#include "SWGAFCReport.h" +#include "SWGAFCSettings.h" #include "SWGAMBEDevice.h" #include "SWGAMBEDevices.h" #include "SWGAMDemodReport.h" @@ -212,6 +215,15 @@ namespace SWGSDRangel { if(QString("SWGADSBDemodSettings").compare(type) == 0) { return new SWGADSBDemodSettings(); } + if(QString("SWGAFCActions").compare(type) == 0) { + return new SWGAFCActions(); + } + if(QString("SWGAFCReport").compare(type) == 0) { + return new SWGAFCReport(); + } + if(QString("SWGAFCSettings").compare(type) == 0) { + return new SWGAFCSettings(); + } if(QString("SWGAMBEDevice").compare(type) == 0) { return new SWGAMBEDevice(); }