AFC: implemented full functionality

This commit is contained in:
f4exb 2020-10-22 08:38:43 +02:00
parent 1c1eade408
commit 977638d9d6
12 changed files with 1047 additions and 290 deletions

View File

@ -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<QString>& 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);
}
}
}
}

View File

@ -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<QString>& featureSettingsKeys, const AFCSettings& settings, bool force);
void trackerDeviceChange(int deviceIndex);
void trackedDeviceChange(int deviceIndex);
void removeFeatureReferences();
private slots:
void networkManagerFinished(QNetworkReply *reply);

View File

@ -127,7 +127,7 @@
<item>
<widget class="ButtonSwitch" name="transverterTarget">
<property name="toolTip">
<string>Use transverter or device frequency for tracker frequency adjustment</string>
<string>Use transverter frequency for tracker frequency adjustment</string>
</property>
<property name="text">
<string>X</string>

View File

@ -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<QString> &channelSettingsKeys,
SWGSDRangel::SWGChannelSettings *swgChannelSettings)
{
MainCore *mainCore = MainCore::instance();
if (*swgChannelSettings->getChannelType() == "FreqTracker")
{
m_trackerChannelOffset = swgChannelSettings->getFreqTrackerSettings()->getInputFrequencyOffset();
QMap<ChannelAPI*, ChannelTracking>::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*>(channelAPI)))
{
QJsonObject *jsonObj = swgChannelSettings->asJsonObject();
QJsonValue channelOffsetValue;
if (WebAPIUtils::extractValue(*jsonObj, "inputFrequencyOffset", channelOffsetValue))
{
int channelOffset = channelOffsetValue.toInt();
m_channelsMap[const_cast<ChannelAPI*>(channelAPI)].m_channelOffset = channelOffset;
m_channelsMap[const_cast<ChannelAPI*>(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];
}
}
}

View File

@ -19,6 +19,7 @@
#define INCLUDE_FEATURE_AFCWORKER_H_
#include <QObject>
#include <QMap>
#include <QTimer>
#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<ChannelAPI*, ChannelTracking> 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<QString> &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();

View File

@ -27,4 +27,15 @@ ChannelAPI::ChannelAPI(const QString& name, StreamType streamType) :
m_deviceSetIndex(0),
m_deviceAPI(0),
m_uid(UidCalculator::getNewObjectId())
{ }
{ }
void ChannelAPI::addFeatureSettingsFeedback(Feature *feature)
{
m_featuresSettingsFeedback.removeOne(feature);
m_featuresSettingsFeedback.append(feature);
}
void ChannelAPI::removeFeatureSettingsFeedback(Feature *feature)
{
m_featuresSettingsFeedback.removeOne(feature);
}

View File

@ -22,11 +22,14 @@
#include <QString>
#include <QByteArray>
#include <QList>
#include <stdint.h>
#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<Feature*> m_featuresSettingsFeedback; //!< list of features to report back settings changes in swagger API format
private:
StreamType m_streamType;

View File

@ -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()),

View File

@ -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<QString>& 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<QString>& channelSettingsKey,
SWGSDRangel::SWGChannelSettings *swgSettings,
bool force)
{
return new MsgChannelSettings(channelAPI, channelSettingsKey, swgSettings, force);
}
private:
const ChannelAPI *m_channelAPI;
QList<QString> m_channelSettingsKeys;
SWGSDRangel::SWGChannelSettings *m_swgSettings;
bool m_force;
MsgChannelSettings(
const ChannelAPI *channelAPI,
const QList<QString>& 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

View File

@ -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<QString, QString> 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<QString, QString> 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<QString, QString> 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<QString, QString> WebAPIRequestMapper::m_channelTypeToActionsKey = {
{"FileSink", "FileSinkActions"},
{"FileSource", "FileSourceActions"},
{"IEEE_802_15_4_Mod", "IEEE_802_15_4_ModActions"},
{"PacketMod", "PacketModActions"}
};
const QMap<QString, QString> 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<QString, QString> 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<QString, QString> 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<QString, QString> WebAPIRequestMapper::m_sinkDeviceHwIdToActionsKey = {
};
const QMap<QString, QString> WebAPIRequestMapper::m_mimoDeviceHwIdToSettingsKey= {
{"BladeRF2", "bladeRF2MIMOSettings"},
{"TestMI", "testMISettings"},
{"TestMOSync", "testMOSyncSettings"}
};
const QMap<QString, QString> WebAPIRequestMapper::m_mimoDeviceHwIdToActionsKey= {
};
const QMap<QString, QString> WebAPIRequestMapper::m_featureTypeToSettingsKey = {
{"SimplePTT", "SimplePTTSettings"},
{"RigCtlServer", "RigCtlServerSettings"}
};
const QMap<QString, QString> WebAPIRequestMapper::m_featureTypeToActionsKey = {
{"SimplePTT", "SimplePTTActions"}
};
const QMap<QString, QString> 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
{

View File

@ -21,6 +21,224 @@
#include "webapiutils.h"
const QMap<QString, QString> 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<QString, QString> 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<QString, QString> 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<QString, QString> WebAPIUtils::m_channelTypeToActionsKey = {
{"FileSink", "FileSinkActions"},
{"FileSource", "FileSourceActions"},
{"SigMFFileSink", "SigMFFileSinkActions"},
{"IEEE_802_15_4_Mod", "IEEE_802_15_4_ModActions"},
{"PacketMod", "PacketModActions"}
};
const QMap<QString, QString> 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<QString, QString> 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<QString, QString> 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<QString, QString> WebAPIUtils::m_sinkDeviceHwIdToActionsKey = {
};
const QMap<QString, QString> WebAPIUtils::m_mimoDeviceHwIdToSettingsKey = {
{"BladeRF2", "bladeRF2MIMOSettings"},
{"MetisMISO", "metisMISOSettings"},
{"TestMI", "testMISettings"},
{"TestMOSync", "testMOSyncSettings"}
};
const QMap<QString, QString> WebAPIUtils::m_mimoDeviceHwIdToActionsKey = {
};
const QMap<QString, QString> WebAPIUtils::m_featureTypeToSettingsKey = {
{"SimplePTT", "SimplePTTSettings"},
{"RigCtlServer", "RigCtlServerSettings"}
};
const QMap<QString, QString> WebAPIUtils::m_featureTypeToActionsKey = {
{"SimplePTT", "SimplePTTActions"}
};
const QMap<QString, QString> 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;
}

View File

@ -21,17 +21,38 @@
#include <QJsonObject>
#include <QString>
#include <QMap>
#include "export.h"
class SDRBASE_API WebAPIUtils
{
public:
static const QMap<QString, QString> m_channelURIToSettingsKey;
static const QMap<QString, QString> m_deviceIdToSettingsKey;
static const QMap<QString, QString> m_channelTypeToSettingsKey;
static const QMap<QString, QString> m_sourceDeviceHwIdToSettingsKey;
static const QMap<QString, QString> m_sinkDeviceHwIdToSettingsKey;
static const QMap<QString, QString> m_mimoDeviceHwIdToSettingsKey;
static const QMap<QString, QString> m_channelTypeToActionsKey;
static const QMap<QString, QString> m_sourceDeviceHwIdToActionsKey;
static const QMap<QString, QString> m_sinkDeviceHwIdToActionsKey;
static const QMap<QString, QString> m_mimoDeviceHwIdToActionsKey;
static const QMap<QString, QString> m_featureTypeToSettingsKey;
static const QMap<QString, QString> m_featureTypeToActionsKey;
static const QMap<QString, QString> 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<QJsonObject> &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