From 977638d9d66bed382d911d24f184c13043357dea Mon Sep 17 00:00:00 2001 From: f4exb Date: Thu, 22 Oct 2020 08:38:43 +0200 Subject: [PATCH] AFC: implemented full functionality --- plugins/feature/afc/afc.cpp | 131 ++++++-- plugins/feature/afc/afc.h | 30 +- plugins/feature/afc/afcgui.ui | 2 +- plugins/feature/afc/afcworker.cpp | 363 +++++++++++++++++++++- plugins/feature/afc/afcworker.h | 62 +++- sdrbase/channel/channelapi.cpp | 13 +- sdrbase/channel/channelapi.h | 9 + sdrbase/feature/feature.cpp | 2 + sdrbase/feature/feature.h | 40 +++ sdrbase/webapi/webapirequestmapper.cpp | 256 ++-------------- sdrbase/webapi/webapiutils.cpp | 408 +++++++++++++++++++++++++ sdrbase/webapi/webapiutils.h | 21 ++ 12 files changed, 1047 insertions(+), 290 deletions(-) diff --git a/plugins/feature/afc/afc.cpp b/plugins/feature/afc/afc.cpp index 54aaba6a9..21801de97 100644 --- a/plugins/feature/afc/afc.cpp +++ b/plugins/feature/afc/afc.cpp @@ -25,14 +25,17 @@ #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::MsgPTT, Message) MESSAGE_CLASS_DEFINITION(AFC::MsgStartStop, Message) const QString AFC::m_featureIdURI = "sdrangel.feature.afc"; @@ -40,7 +43,8 @@ const QString AFC::m_featureId = "AFC"; AFC::AFC(WebAPIAdapterInterface *webAPIAdapterInterface) : Feature(m_featureIdURI, webAPIAdapterInterface), - m_ptt(false) + m_trackerDeviceSet(nullptr), + m_trackedDeviceSet(nullptr) { setObjectName(m_featureId); m_worker = new AFCWorker(webAPIAdapterInterface); @@ -55,6 +59,7 @@ AFC::~AFC() } delete m_worker; + removeFeatureReferences(); } void AFC::start() @@ -90,17 +95,6 @@ bool AFC::handleMessage(const Message& cmd) return true; } - else if (MsgPTT::match(cmd)) - { - MsgPTT& cfg = (MsgPTT&) cmd; - m_ptt = cfg.getTx(); - qDebug() << "AFC::handleMessage: MsgPTT: tx:" << m_ptt; - - AFCWorker::MsgPTT *msg = AFCWorker::MsgPTT::create(m_ptt); - m_worker->getInputMessageQueue()->push(msg); - - return true; - } else if (MsgStartStop::match(cmd)) { MsgStartStop& cfg = (MsgStartStop&) cmd; @@ -114,10 +108,25 @@ bool AFC::handleMessage(const Message& cmd) return true; } - else - { - return false; - } + 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; + } + } + + return false; } QByteArray AFC::serialize() const @@ -182,6 +191,14 @@ void AFC::applySettings(const AFCSettings& settings, bool force) reverseAPIKeys.append("freqTolerance"); } + if ((m_settings.m_trackerDeviceSetIndex != settings.m_trackerDeviceSetIndex) || force) { + trackerDeviceChange(settings.m_trackerDeviceSetIndex); + } + + if ((m_settings.m_trackedDeviceSetIndex != settings.m_trackedDeviceSetIndex) || force) { + trackedDeviceChange(settings.m_trackedDeviceSetIndex); + } + AFCWorker::MsgConfigureAFCWorker *msg = AFCWorker::MsgConfigureAFCWorker::create( settings, force ); @@ -266,20 +283,6 @@ int AFC::webapiActionsPost( if (swgAFCActions) { - if (featureActionsKeys.contains("ptt")) - { - bool ptt = swgAFCActions->getPtt() != 0; - - MsgPTT *msg = MsgPTT::create(ptt); - getInputMessageQueue()->push(msg); - - if (getMessageQueueToGUI()) - { - MsgPTT *msgToGUI = MsgPTT::create(ptt); - getMessageQueueToGUI()->push(msgToGUI); - } - } - return 202; } else @@ -368,7 +371,6 @@ void AFC::webapiUpdateFeatureSettings( void AFC::webapiFormatFeatureReport(SWGSDRangel::SWGFeatureReport& response) { - response.getAfcReport()->setPtt(m_ptt ? 1 : 0); } void AFC::webapiReverseSendSettings(QList& channelSettingsKeys, const AFCSettings& settings, bool force) @@ -447,3 +449,68 @@ void AFC::networkManagerFinished(QNetworkReply *reply) 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); + 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); + } + } +} + +void AFC::removeFeatureReferences() +{ + MainCore *mainCore = MainCore::instance(); + + if ((m_settings.m_trackerDeviceSetIndex >= 0) && (m_settings.m_trackerDeviceSetIndex < mainCore->getDeviceSets().size())) + { + DeviceSet *trackerDeviceSet = mainCore->getDeviceSets()[m_settings.m_trackerDeviceSetIndex]; + + if (trackerDeviceSet == m_trackerDeviceSet) + { + for (int i = 0; i < m_trackerDeviceSet->getNumberOfChannels(); i++) + { + ChannelAPI *channel = m_trackerDeviceSet->getChannelAt(i); + channel->removeFeatureSettingsFeedback(this); + } + } + } + + if ((m_settings.m_trackedDeviceSetIndex >= 0) && (m_settings.m_trackedDeviceSetIndex < mainCore->getDeviceSets().size())) + { + DeviceSet *trackerDeviceSet = mainCore->getDeviceSets()[m_settings.m_trackedDeviceSetIndex]; + + if (trackerDeviceSet == m_trackedDeviceSet) + { + for (int i = 0; i < m_trackedDeviceSet->getNumberOfChannels(); i++) + { + ChannelAPI *channel = m_trackedDeviceSet->getChannelAt(i); + channel->removeFeatureSettingsFeedback(this); + } + } + } +} diff --git a/plugins/feature/afc/afc.h b/plugins/feature/afc/afc.h index 9cdb1afb4..9ac4c1850 100644 --- a/plugins/feature/afc/afc.h +++ b/plugins/feature/afc/afc.h @@ -26,10 +26,11 @@ #include "afcsettings.h" -class WebAPIAdapterInterface; -class AFCWorker; class QNetworkAccessManager; class QNetworkReply; +class WebAPIAdapterInterface; +class DeviceSet; +class AFCWorker; namespace SWGSDRangel { class SWGDeviceState; @@ -61,25 +62,6 @@ public: { } }; - class MsgPTT : public Message { - MESSAGE_CLASS_DECLARATION - - public: - bool getTx() const { return m_tx; } - - static MsgPTT* create(bool tx) { - return new MsgPTT(tx); - } - - private: - bool m_tx; - - MsgPTT(bool tx) : - Message(), - m_tx(tx) - { } - }; - class MsgStartStop : public Message { MESSAGE_CLASS_DECLARATION @@ -150,7 +132,8 @@ private: QThread m_thread; AFCWorker *m_worker; AFCSettings m_settings; - bool m_ptt; + DeviceSet *m_trackerDeviceSet; + DeviceSet *m_trackedDeviceSet; QNetworkAccessManager *m_networkManager; QNetworkRequest m_networkRequest; @@ -160,6 +143,9 @@ private: 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 removeFeatureReferences(); private slots: void networkManagerFinished(QNetworkReply *reply); diff --git a/plugins/feature/afc/afcgui.ui b/plugins/feature/afc/afcgui.ui index bfbef1f4c..cef53c7ce 100644 --- a/plugins/feature/afc/afcgui.ui +++ b/plugins/feature/afc/afcgui.ui @@ -127,7 +127,7 @@ - Use transverter or device frequency for tracker frequency adjustment + Use transverter frequency for tracker frequency adjustment X diff --git a/plugins/feature/afc/afcworker.cpp b/plugins/feature/afc/afcworker.cpp index dfd7fb339..c4471181c 100644 --- a/plugins/feature/afc/afcworker.cpp +++ b/plugins/feature/afc/afcworker.cpp @@ -19,21 +19,31 @@ #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::MsgPTT, Message) +MESSAGE_CLASS_DEFINITION(AFCWorker::MsgTrackedDeviceChange, Message) AFCWorker::AFCWorker(WebAPIAdapterInterface *webAPIAdapterInterface) : m_webAPIAdapterInterface(webAPIAdapterInterface), m_msgQueueToGUI(nullptr), m_running(false), - m_tx(false), + m_freqTracker(nullptr), + m_trackerDeviceFrequency(0), + m_trackerChannelOffset(0), m_mutex(QMutex::Recursive) { qDebug("AFCWorker::AFCWorker"); @@ -81,14 +91,25 @@ bool AFCWorker::handleMessage(const Message& cmd) { if (MsgConfigureAFCWorker::match(cmd)) { + qDebug() << "AFCWorker::handleMessage: MsgConfigureAFCWorker"; QMutexLocker mutexLocker(&m_mutex); MsgConfigureAFCWorker& cfg = (MsgConfigureAFCWorker&) cmd; - qDebug() << "AFCWorker::handleMessage: MsgConfigureAFCWorker"; applySettings(cfg.getSettings(), cfg.getForce()); return true; } + else if (Feature::MsgChannelSettings::match(cmd)) + { + qDebug() << "AFCWorker::handleMessage: Feature::MsgChannelSettings"; + QMutexLocker mutexLocker(&m_mutex); + Feature::MsgChannelSettings& cfg = (Feature::MsgChannelSettings&) cmd; + SWGSDRangel::SWGChannelSettings *swgChannelSettings = cfg.getSWGSettings(); + processChannelSettings(cfg.getChannelAPI(), cfg.getChannelSettingsKeys(), swgChannelSettings); + + delete swgChannelSettings; + return true; + } else { return false; @@ -107,5 +128,341 @@ void AFCWorker::applySettings(const AFCSettings& settings, bool force) << " 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); + } + 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(); + + if (*swgChannelSettings->getChannelType() == "FreqTracker") + { + m_trackerChannelOffset = swgChannelSettings->getFreqTrackerSettings()->getInputFrequencyOffset(); + QMap::iterator it = m_channelsMap.begin(); + + for (; it != m_channelsMap.end(); ++it) + { + if (mainCore->existsChannel(it.key())) + { + int channelOffset = it.value().m_channelOffset + m_trackerChannelOffset - it.value().m_trackerOffset; + updateChannelOffset(it.key(),it.value().m_channelDirection, channelOffset); + } + else + { + m_channelsMap.erase(it); + } + } + + if (m_settings.m_hasTargetFrequency) { + updateTarget(); + } + } + else if (m_channelsMap.contains(const_cast(channelAPI))) + { + QJsonObject *jsonObj = swgChannelSettings->asJsonObject(); + QJsonValue channelOffsetValue; + + if (WebAPIUtils::extractValue(*jsonObj, "inputFrequencyOffset", channelOffsetValue)) + { + int channelOffset = channelOffsetValue.toInt(); + m_channelsMap[const_cast(channelAPI)].m_channelOffset = channelOffset; + m_channelsMap[const_cast(channelAPI)].m_trackerOffset = m_trackerChannelOffset; + } + } +} + +void AFCWorker::updateChannelOffset(ChannelAPI *channelAPI, int direction, int offset) +{ + 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); + + 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(); + } +} + +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::initTrackerDeviceSet: cannot find device frequency"; + return; + } + } + else + { + qDebug() << "AFCWorker::initTrackerDeviceSet: 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; + qDebug() << "AFCWorker::initTrackerDeviceSet: correction:" << correction << "tolerance:" << tolerance; + + if ((correction > -tolerance) && (correction < tolerance)) { + return; + } + + if (m_settings.m_transverterTarget) // act on transverter + { + QJsonObject *jsonObj = resDevice.asJsonObject(); + QJsonValue xverterFrequencyValue; + + if (WebAPIUtils::extractValue(*jsonObj, "transverterDeltaFrequency", xverterFrequencyValue)) + { + double xverterFrequency = xverterFrequencyValue.toDouble(); + updateDeviceFrequency(m_trackerDeviceSet, "transverterDeltaFrequency", xverterFrequency + correction); + } + else + { + qDebug() << "AFCWorker::initTrackerDeviceSet: cannot find device transverter frequency"; + return; + } + } + 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::initTrackerDeviceSet: cannot find device transverter frequency"; + return; + } + } +} + +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); + + QString jsonStr = tr("{ \"deviceHwType\": \"%1\", \"direction\": \"%2\", \"%3\": {%4}}") + .arg(deviceAPI->getHardwareId()) + .arg(getDeviceDirection(deviceAPI)) + .arg(deviceSettingsKey) + .arg(jsonSettingsStr); + swgDeviceSettings.fromJson(jsonStr); + qDebug() << "AFCWorker::updateDeviceFrequency:" << 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]; + } + } +} diff --git a/plugins/feature/afc/afcworker.h b/plugins/feature/afc/afcworker.h index bc074bfd4..744523bc0 100644 --- a/plugins/feature/afc/afcworker.h +++ b/plugins/feature/afc/afcworker.h @@ -19,6 +19,7 @@ #define INCLUDE_FEATURE_AFCWORKER_H_ #include +#include #include #include "util/message.h" @@ -27,6 +28,8 @@ #include "afcsettings.h" class WebAPIAdapterInterface; +class DeviceSet; +class ChannelAPI; class AFCWorker : public QObject { @@ -55,22 +58,23 @@ public: { } }; - class MsgPTT : public Message { + class MsgTrackedDeviceChange : public Message { MESSAGE_CLASS_DECLARATION public: - bool getTx() const { return m_tx; } + int getDeviceIndex() const { return m_deviceIndex; } - static MsgPTT* create(bool tx) { - return new MsgPTT(tx); + static MsgTrackedDeviceChange* create(int deviceIndex) + { + return new MsgTrackedDeviceChange(deviceIndex); } private: - bool m_tx; + int m_deviceIndex; - MsgPTT(bool tx) : + MsgTrackedDeviceChange(int deviceIndex) : Message(), - m_tx(tx) + m_deviceIndex(deviceIndex) { } }; @@ -84,17 +88,59 @@ public: void setMessageQueueToGUI(MessageQueue *messageQueue) { m_msgQueueToGUI = messageQueue; } 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; - bool m_tx; + 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 + ); + void updateChannelOffset(ChannelAPI *channelAPI, int direction, int offset); + void updateTarget(); + bool updateDeviceFrequency(DeviceSet *deviceSet, const QString& key, int64_t frequency); + int getDeviceDirection(DeviceAPI *deviceAPI); + void getDeviceSettingsKey(DeviceAPI *deviceAPI, QString& settingsKey); private slots: void handleInputMessages(); diff --git a/sdrbase/channel/channelapi.cpp b/sdrbase/channel/channelapi.cpp index fa8ecb183..54cddb6b9 100644 --- a/sdrbase/channel/channelapi.cpp +++ b/sdrbase/channel/channelapi.cpp @@ -27,4 +27,15 @@ ChannelAPI::ChannelAPI(const QString& name, StreamType streamType) : 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..f0bde4a02 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,18 @@ 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); + // 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 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/webapi/webapirequestmapper.cpp b/sdrbase/webapi/webapirequestmapper.cpp index 376da9135..f17fd8983 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,205 +57,6 @@ #include "SWGFeatureReport.h" #include "SWGFeatureActions.h" -const QMap WebAPIRequestMapper::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.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 = { - {"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 = { - {"SimplePTT", "SimplePTTSettings"}, - {"RigCtlServer", "RigCtlServerSettings"} -}; - -const QMap WebAPIRequestMapper::m_featureTypeToActionsKey = { - {"SimplePTT", "SimplePTTActions"} -}; - -const QMap WebAPIRequestMapper::m_featureURIToSettingsKey = { - {"sdrangel.feature.simpleptt", "SimplePTTSettings"}, - {"sdrangel.feature.rigctlserver", "RigCtlServerSettings"} -}; - WebAPIRequestMapper::WebAPIRequestMapper(QObject* parent) : HttpRequestHandler(parent), m_adapter(0) @@ -3025,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; } @@ -3069,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; } @@ -3118,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; } @@ -3144,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; } @@ -3164,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; } @@ -3184,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; } @@ -3643,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 @@ -3677,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 { @@ -3933,11 +3743,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