Merge AFC plugin and Frequency Tracker changes

This commit is contained in:
f4exb 2020-10-27 23:13:08 +01:00
commit 5e1be619dd
120 changed files with 7333 additions and 924 deletions

BIN
doc/img/AFC_plugin.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

BIN
doc/img/AFC_plugin.xcf Normal file

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

After

Width:  |  Height:  |  Size: 60 KiB

Binary file not shown.

View File

@ -35,7 +35,9 @@
#include "dsp/dspengine.h"
#include "dsp/dspcommands.h"
#include "device/deviceapi.h"
#include "feature/feature.h"
#include "util/db.h"
#include "maincore.h"
MESSAGE_CLASS_DEFINITION(AMDemod::MsgConfigureAMDemod, Message)
@ -224,6 +226,10 @@ void AMDemod::applySettings(const AMDemodSettings& settings, bool force)
webapiReverseSendSettings(reverseAPIKeys, settings, fullUpdate || force);
}
if (m_featuresSettingsFeedback.size() > 0) {
featuresSendSettings(reverseAPIKeys, settings, force);
}
m_settings = settings;
}
@ -413,6 +419,63 @@ void AMDemod::webapiFormatChannelReport(SWGSDRangel::SWGChannelReport& response)
void AMDemod::webapiReverseSendSettings(QList<QString>& channelSettingsKeys, const AMDemodSettings& settings, bool force)
{
SWGSDRangel::SWGChannelSettings *swgChannelSettings = new SWGSDRangel::SWGChannelSettings();
webapiFormatChannelSettings(channelSettingsKeys, swgChannelSettings, settings, force);
QString channelSettingsURL = QString("http://%1:%2/sdrangel/deviceset/%3/channel/%4/settings")
.arg(settings.m_reverseAPIAddress)
.arg(settings.m_reverseAPIPort)
.arg(settings.m_reverseAPIDeviceIndex)
.arg(settings.m_reverseAPIChannelIndex);
m_networkRequest.setUrl(QUrl(channelSettingsURL));
m_networkRequest.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
QBuffer *buffer = new QBuffer();
buffer->open((QBuffer::ReadWrite));
buffer->write(swgChannelSettings->asJson().toUtf8());
buffer->seek(0);
// Always use PATCH to avoid passing reverse API settings
QNetworkReply *reply = m_networkManager->sendCustomRequest(m_networkRequest, "PATCH", buffer);
buffer->setParent(reply);
delete swgChannelSettings;
}
void AMDemod::featuresSendSettings(QList<QString>& channelSettingsKeys, const AMDemodSettings& settings, bool force)
{
QList<Feature*>::iterator it = m_featuresSettingsFeedback.begin();
MainCore *mainCore = MainCore::instance();
for (; it != m_featuresSettingsFeedback.end(); ++it)
{
if (mainCore->existsFeature(*it))
{
SWGSDRangel::SWGChannelSettings *swgChannelSettings = new SWGSDRangel::SWGChannelSettings();
webapiFormatChannelSettings(channelSettingsKeys, swgChannelSettings, settings, force);
Feature::MsgChannelSettings *msg = Feature::MsgChannelSettings::create(
this,
channelSettingsKeys,
swgChannelSettings,
force
);
(*it)->getInputMessageQueue()->push(msg);
}
else
{
m_featuresSettingsFeedback.removeOne(*it);
}
}
}
void AMDemod::webapiFormatChannelSettings(
QList<QString>& channelSettingsKeys,
SWGSDRangel::SWGChannelSettings *swgChannelSettings,
const AMDemodSettings& settings,
bool force
)
{
swgChannelSettings->setDirection(0); // Single sink (Rx)
swgChannelSettings->setOriginatorChannelIndex(getIndexInDeviceSet());
swgChannelSettings->setOriginatorDeviceSetIndex(getDeviceSetIndex());
@ -458,25 +521,6 @@ void AMDemod::webapiReverseSendSettings(QList<QString>& channelSettingsKeys, con
if (channelSettingsKeys.contains("streamIndex") || force) {
swgAMDemodSettings->setStreamIndex(settings.m_streamIndex);
}
QString channelSettingsURL = QString("http://%1:%2/sdrangel/deviceset/%3/channel/%4/settings")
.arg(settings.m_reverseAPIAddress)
.arg(settings.m_reverseAPIPort)
.arg(settings.m_reverseAPIDeviceIndex)
.arg(settings.m_reverseAPIChannelIndex);
m_networkRequest.setUrl(QUrl(channelSettingsURL));
m_networkRequest.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
QBuffer *buffer = new QBuffer();
buffer->open((QBuffer::ReadWrite));
buffer->write(swgChannelSettings->asJson().toUtf8());
buffer->seek(0);
// Always use PATCH to avoid passing reverse API settings
QNetworkReply *reply = m_networkManager->sendCustomRequest(m_networkRequest, "PATCH", buffer);
buffer->setParent(reply);
delete swgChannelSettings;
}
void AMDemod::networkManagerFinished(QNetworkReply *reply)

View File

@ -142,6 +142,13 @@ private:
void applySettings(const AMDemodSettings& settings, bool force = false);
void webapiFormatChannelReport(SWGSDRangel::SWGChannelReport& response);
void webapiReverseSendSettings(QList<QString>& channelSettingsKeys, const AMDemodSettings& settings, bool force);
void featuresSendSettings(QList<QString>& channelSettingsKeys, const AMDemodSettings& settings, bool force);
void webapiFormatChannelSettings(
QList<QString>& channelSettingsKeys,
SWGSDRangel::SWGChannelSettings *swgChannelSettings,
const AMDemodSettings& settings,
bool force
);
private slots:
void networkManagerFinished(QNetworkReply *reply);

View File

@ -35,7 +35,9 @@
#include "dsp/dspcommands.h"
#include "dsp/devicesamplemimo.h"
#include "device/deviceapi.h"
#include "feature/feature.h"
#include "util/db.h"
#include "maincore.h"
#include "bfmdemod.h"
@ -212,6 +214,10 @@ void BFMDemod::applySettings(const BFMDemodSettings& settings, bool force)
webapiReverseSendSettings(reverseAPIKeys, settings, fullUpdate || force);
}
if (m_featuresSettingsFeedback.size() > 0) {
featuresSendSettings(reverseAPIKeys, settings, force);
}
m_settings = settings;
}
@ -439,10 +445,67 @@ void BFMDemod::webapiFormatRDSReport(SWGSDRangel::SWGRDSReport *report)
void BFMDemod::webapiReverseSendSettings(QList<QString>& channelSettingsKeys, const BFMDemodSettings& settings, bool force)
{
SWGSDRangel::SWGChannelSettings *swgChannelSettings = new SWGSDRangel::SWGChannelSettings();
swgChannelSettings->setDirection(0); // single sink (Rx)
webapiFormatChannelSettings(channelSettingsKeys, swgChannelSettings, settings, force);
QString channelSettingsURL = QString("http://%1:%2/sdrangel/deviceset/%3/channel/%4/settings")
.arg(settings.m_reverseAPIAddress)
.arg(settings.m_reverseAPIPort)
.arg(settings.m_reverseAPIDeviceIndex)
.arg(settings.m_reverseAPIChannelIndex);
m_networkRequest.setUrl(QUrl(channelSettingsURL));
m_networkRequest.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
QBuffer *buffer = new QBuffer();
buffer->open((QBuffer::ReadWrite));
buffer->write(swgChannelSettings->asJson().toUtf8());
buffer->seek(0);
// Always use PATCH to avoid passing reverse API settings
QNetworkReply *reply = m_networkManager->sendCustomRequest(m_networkRequest, "PATCH", buffer);
buffer->setParent(reply);
delete swgChannelSettings;
}
void BFMDemod::featuresSendSettings(QList<QString>& channelSettingsKeys, const BFMDemodSettings& settings, bool force)
{
QList<Feature*>::iterator it = m_featuresSettingsFeedback.begin();
MainCore *mainCore = MainCore::instance();
for (; it != m_featuresSettingsFeedback.end(); ++it)
{
if (mainCore->existsFeature(*it))
{
SWGSDRangel::SWGChannelSettings *swgChannelSettings = new SWGSDRangel::SWGChannelSettings();
webapiFormatChannelSettings(channelSettingsKeys, swgChannelSettings, settings, force);
Feature::MsgChannelSettings *msg = Feature::MsgChannelSettings::create(
this,
channelSettingsKeys,
swgChannelSettings,
force
);
(*it)->getInputMessageQueue()->push(msg);
}
else
{
m_featuresSettingsFeedback.removeOne(*it);
}
}
}
void BFMDemod::webapiFormatChannelSettings(
QList<QString>& channelSettingsKeys,
SWGSDRangel::SWGChannelSettings *swgChannelSettings,
const BFMDemodSettings& settings,
bool force
)
{
swgChannelSettings->setDirection(0); // Single sink (Rx)
swgChannelSettings->setOriginatorChannelIndex(getIndexInDeviceSet());
swgChannelSettings->setOriginatorDeviceSetIndex(getDeviceSetIndex());
swgChannelSettings->setChannelType(new QString("BFMDemod"));
swgChannelSettings->setChannelType(new QString(m_channelId));
swgChannelSettings->setBfmDemodSettings(new SWGSDRangel::SWGBFMDemodSettings());
SWGSDRangel::SWGBFMDemodSettings *swgBFMDemodSettings = swgChannelSettings->getBfmDemodSettings();
@ -487,25 +550,6 @@ void BFMDemod::webapiReverseSendSettings(QList<QString>& channelSettingsKeys, co
if (channelSettingsKeys.contains("streamIndex") || force) {
swgBFMDemodSettings->setStreamIndex(settings.m_streamIndex);
}
QString channelSettingsURL = QString("http://%1:%2/sdrangel/deviceset/%3/channel/%4/settings")
.arg(settings.m_reverseAPIAddress)
.arg(settings.m_reverseAPIPort)
.arg(settings.m_reverseAPIDeviceIndex)
.arg(settings.m_reverseAPIChannelIndex);
m_networkRequest.setUrl(QUrl(channelSettingsURL));
m_networkRequest.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
QBuffer *buffer = new QBuffer();
buffer->open((QBuffer::ReadWrite));
buffer->write(swgChannelSettings->asJson().toUtf8());
buffer->seek(0);
// Always use PATCH to avoid passing reverse API settings
QNetworkReply *reply = m_networkManager->sendCustomRequest(m_networkRequest, "PATCH", buffer);
buffer->setParent(reply);
delete swgChannelSettings;
}
void BFMDemod::networkManagerFinished(QNetworkReply *reply)

View File

@ -158,6 +158,13 @@ private:
void webapiFormatChannelReport(SWGSDRangel::SWGChannelReport& response);
void webapiFormatRDSReport(SWGSDRangel::SWGRDSReport *report);
void webapiReverseSendSettings(QList<QString>& channelSettingsKeys, const BFMDemodSettings& settings, bool force);
void featuresSendSettings(QList<QString>& channelSettingsKeys, const BFMDemodSettings& settings, bool force);
void webapiFormatChannelSettings(
QList<QString>& channelSettingsKeys,
SWGSDRangel::SWGChannelSettings *swgChannelSettings,
const BFMDemodSettings& settings,
bool force
);
private slots:
void networkManagerFinished(QNetworkReply *reply);

View File

@ -37,7 +37,9 @@
#include "dsp/dspengine.h"
#include "dsp/dspcommands.h"
#include "device/deviceapi.h"
#include "feature/feature.h"
#include "util/db.h"
#include "maincore.h"
#include "dsddemod.h"
@ -250,6 +252,10 @@ void DSDDemod::applySettings(const DSDDemodSettings& settings, bool force)
webapiReverseSendSettings(reverseAPIKeys, settings, fullUpdate || force);
}
if (m_featuresSettingsFeedback.size() > 0) {
featuresSendSettings(reverseAPIKeys, settings, force);
}
m_settings = settings;
}
@ -487,10 +493,67 @@ void DSDDemod::webapiFormatChannelReport(SWGSDRangel::SWGChannelReport& response
void DSDDemod::webapiReverseSendSettings(QList<QString>& channelSettingsKeys, const DSDDemodSettings& settings, bool force)
{
SWGSDRangel::SWGChannelSettings *swgChannelSettings = new SWGSDRangel::SWGChannelSettings();
swgChannelSettings->setDirection(0); // single sink (Rx)
webapiFormatChannelSettings(channelSettingsKeys, swgChannelSettings, settings, force);
QString channelSettingsURL = QString("http://%1:%2/sdrangel/deviceset/%3/channel/%4/settings")
.arg(settings.m_reverseAPIAddress)
.arg(settings.m_reverseAPIPort)
.arg(settings.m_reverseAPIDeviceIndex)
.arg(settings.m_reverseAPIChannelIndex);
m_networkRequest.setUrl(QUrl(channelSettingsURL));
m_networkRequest.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
QBuffer *buffer = new QBuffer();
buffer->open((QBuffer::ReadWrite));
buffer->write(swgChannelSettings->asJson().toUtf8());
buffer->seek(0);
// Always use PATCH to avoid passing reverse API settings
QNetworkReply *reply = m_networkManager->sendCustomRequest(m_networkRequest, "PATCH", buffer);
buffer->setParent(reply);
delete swgChannelSettings;
}
void DSDDemod::featuresSendSettings(QList<QString>& channelSettingsKeys, const DSDDemodSettings& settings, bool force)
{
QList<Feature*>::iterator it = m_featuresSettingsFeedback.begin();
MainCore *mainCore = MainCore::instance();
for (; it != m_featuresSettingsFeedback.end(); ++it)
{
if (mainCore->existsFeature(*it))
{
SWGSDRangel::SWGChannelSettings *swgChannelSettings = new SWGSDRangel::SWGChannelSettings();
webapiFormatChannelSettings(channelSettingsKeys, swgChannelSettings, settings, force);
Feature::MsgChannelSettings *msg = Feature::MsgChannelSettings::create(
this,
channelSettingsKeys,
swgChannelSettings,
force
);
(*it)->getInputMessageQueue()->push(msg);
}
else
{
m_featuresSettingsFeedback.removeOne(*it);
}
}
}
void DSDDemod::webapiFormatChannelSettings(
QList<QString>& channelSettingsKeys,
SWGSDRangel::SWGChannelSettings *swgChannelSettings,
const DSDDemodSettings& settings,
bool force
)
{
swgChannelSettings->setDirection(0); // Single sink (Rx)
swgChannelSettings->setOriginatorChannelIndex(getIndexInDeviceSet());
swgChannelSettings->setOriginatorDeviceSetIndex(getDeviceSetIndex());
swgChannelSettings->setChannelType(new QString("DSDDemod"));
swgChannelSettings->setChannelType(new QString(m_channelId));
swgChannelSettings->setDsdDemodSettings(new SWGSDRangel::SWGDSDDemodSettings());
SWGSDRangel::SWGDSDDemodSettings *swgDSDDemodSettings = swgChannelSettings->getDsdDemodSettings();
@ -565,25 +628,6 @@ void DSDDemod::webapiReverseSendSettings(QList<QString>& channelSettingsKeys, co
if (channelSettingsKeys.contains("streamIndex") || force) {
swgDSDDemodSettings->setStreamIndex(settings.m_streamIndex);
}
QString channelSettingsURL = QString("http://%1:%2/sdrangel/deviceset/%3/channel/%4/settings")
.arg(settings.m_reverseAPIAddress)
.arg(settings.m_reverseAPIPort)
.arg(settings.m_reverseAPIDeviceIndex)
.arg(settings.m_reverseAPIChannelIndex);
m_networkRequest.setUrl(QUrl(channelSettingsURL));
m_networkRequest.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
QBuffer *buffer = new QBuffer();
buffer->open((QBuffer::ReadWrite));
buffer->write(swgChannelSettings->asJson().toUtf8());
buffer->seek(0);
// Always use PATCH to avoid passing reverse API settings
QNetworkReply *reply = m_networkManager->sendCustomRequest(m_networkRequest, "PATCH", buffer);
buffer->setParent(reply);
delete swgChannelSettings;
}
void DSDDemod::networkManagerFinished(QNetworkReply *reply)

View File

@ -140,6 +140,13 @@ private:
void applySettings(const DSDDemodSettings& settings, bool force = false);
void webapiFormatChannelReport(SWGSDRangel::SWGChannelReport& response);
void webapiReverseSendSettings(QList<QString>& channelSettingsKeys, const DSDDemodSettings& settings, bool force);
void featuresSendSettings(QList<QString>& channelSettingsKeys, const DSDDemodSettings& settings, bool force);
void webapiFormatChannelSettings(
QList<QString>& channelSettingsKeys,
SWGSDRangel::SWGChannelSettings *swgChannelSettings,
const DSDDemodSettings& settings,
bool force
);
private slots:
void networkManagerFinished(QNetworkReply *reply);

View File

@ -30,7 +30,9 @@
#include "dsp/dspcommands.h"
#include "dsp/devicesamplemimo.h"
#include "device/deviceapi.h"
#include "feature/feature.h"
#include "util/db.h"
#include "maincore.h"
#include "freedvdemod.h"
@ -206,6 +208,10 @@ void FreeDVDemod::applySettings(const FreeDVDemodSettings& settings, bool force)
webapiReverseSendSettings(reverseAPIKeys, settings, fullUpdate || force);
}
if (m_featuresSettingsFeedback.size() > 0) {
featuresSendSettings(reverseAPIKeys, settings, force);
}
m_settings = settings;
}
@ -386,10 +392,67 @@ void FreeDVDemod::webapiFormatChannelReport(SWGSDRangel::SWGChannelReport& respo
void FreeDVDemod::webapiReverseSendSettings(QList<QString>& channelSettingsKeys, const FreeDVDemodSettings& settings, bool force)
{
SWGSDRangel::SWGChannelSettings *swgChannelSettings = new SWGSDRangel::SWGChannelSettings();
swgChannelSettings->setDirection(0); // single sink (Rx)
webapiFormatChannelSettings(channelSettingsKeys, swgChannelSettings, settings, force);
QString channelSettingsURL = QString("http://%1:%2/sdrangel/deviceset/%3/channel/%4/settings")
.arg(settings.m_reverseAPIAddress)
.arg(settings.m_reverseAPIPort)
.arg(settings.m_reverseAPIDeviceIndex)
.arg(settings.m_reverseAPIChannelIndex);
m_networkRequest.setUrl(QUrl(channelSettingsURL));
m_networkRequest.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
QBuffer *buffer = new QBuffer();
buffer->open((QBuffer::ReadWrite));
buffer->write(swgChannelSettings->asJson().toUtf8());
buffer->seek(0);
// Always use PATCH to avoid passing reverse API settings
QNetworkReply *reply = m_networkManager->sendCustomRequest(m_networkRequest, "PATCH", buffer);
buffer->setParent(reply);
delete swgChannelSettings;
}
void FreeDVDemod::featuresSendSettings(QList<QString>& channelSettingsKeys, const FreeDVDemodSettings& settings, bool force)
{
QList<Feature*>::iterator it = m_featuresSettingsFeedback.begin();
MainCore *mainCore = MainCore::instance();
for (; it != m_featuresSettingsFeedback.end(); ++it)
{
if (mainCore->existsFeature(*it))
{
SWGSDRangel::SWGChannelSettings *swgChannelSettings = new SWGSDRangel::SWGChannelSettings();
webapiFormatChannelSettings(channelSettingsKeys, swgChannelSettings, settings, force);
Feature::MsgChannelSettings *msg = Feature::MsgChannelSettings::create(
this,
channelSettingsKeys,
swgChannelSettings,
force
);
(*it)->getInputMessageQueue()->push(msg);
}
else
{
m_featuresSettingsFeedback.removeOne(*it);
}
}
}
void FreeDVDemod::webapiFormatChannelSettings(
QList<QString>& channelSettingsKeys,
SWGSDRangel::SWGChannelSettings *swgChannelSettings,
const FreeDVDemodSettings& settings,
bool force
)
{
swgChannelSettings->setDirection(0); // Single sink (Rx)
swgChannelSettings->setOriginatorChannelIndex(getIndexInDeviceSet());
swgChannelSettings->setOriginatorDeviceSetIndex(getDeviceSetIndex());
swgChannelSettings->setChannelType(new QString("FreeDVDemod"));
swgChannelSettings->setChannelType(new QString(m_channelId));
swgChannelSettings->setFreeDvDemodSettings(new SWGSDRangel::SWGFreeDVDemodSettings());
SWGSDRangel::SWGFreeDVDemodSettings *swgFreeDVDemodSettings = swgChannelSettings->getFreeDvDemodSettings();
@ -428,25 +491,6 @@ void FreeDVDemod::webapiReverseSendSettings(QList<QString>& channelSettingsKeys,
if (channelSettingsKeys.contains("streamIndex") || force) {
swgFreeDVDemodSettings->setStreamIndex(settings.m_streamIndex);
}
QString channelSettingsURL = QString("http://%1:%2/sdrangel/deviceset/%3/channel/%4/settings")
.arg(settings.m_reverseAPIAddress)
.arg(settings.m_reverseAPIPort)
.arg(settings.m_reverseAPIDeviceIndex)
.arg(settings.m_reverseAPIChannelIndex);
m_networkRequest.setUrl(QUrl(channelSettingsURL));
m_networkRequest.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
QBuffer *buffer = new QBuffer();
buffer->open((QBuffer::ReadWrite));
buffer->write(swgChannelSettings->asJson().toUtf8());
buffer->seek(0);
// Always use PATCH to avoid passing reverse API settings
QNetworkReply *reply = m_networkManager->sendCustomRequest(m_networkRequest, "PATCH", buffer);
buffer->setParent(reply);
delete swgChannelSettings;
}
void FreeDVDemod::networkManagerFinished(QNetworkReply *reply)
@ -473,4 +517,4 @@ void FreeDVDemod::networkManagerFinished(QNetworkReply *reply)
void FreeDVDemod::setLevelMeter(QObject *levelMeter)
{
connect(m_basebandSink, SIGNAL(levelChanged(qreal, qreal, int)), levelMeter, SLOT(levelChanged(qreal, qreal, int)));
}
}

View File

@ -156,6 +156,13 @@ private:
void applySettings(const FreeDVDemodSettings& settings, bool force = false);
void webapiFormatChannelReport(SWGSDRangel::SWGChannelReport& response);
void webapiReverseSendSettings(QList<QString>& channelSettingsKeys, const FreeDVDemodSettings& settings, bool force);
void featuresSendSettings(QList<QString>& channelSettingsKeys, const FreeDVDemodSettings& settings, bool force);
void webapiFormatChannelSettings(
QList<QString>& channelSettingsKeys,
SWGSDRangel::SWGChannelSettings *swgChannelSettings,
const FreeDVDemodSettings& settings,
bool force
);
private slots:
void networkManagerFinished(QNetworkReply *reply);

View File

@ -35,7 +35,9 @@
#include "dsp/dspcommands.h"
#include "dsp/devicesamplemimo.h"
#include "device/deviceapi.h"
#include "feature/feature.h"
#include "util/db.h"
#include "maincore.h"
#include "nfmdemod.h"
@ -441,10 +443,67 @@ void NFMDemod::webapiFormatChannelReport(SWGSDRangel::SWGChannelReport& response
void NFMDemod::webapiReverseSendSettings(QList<QString>& channelSettingsKeys, const NFMDemodSettings& settings, bool force)
{
SWGSDRangel::SWGChannelSettings *swgChannelSettings = new SWGSDRangel::SWGChannelSettings();
swgChannelSettings->setDirection(0); // single sink (Rx)
webapiFormatChannelSettings(channelSettingsKeys, swgChannelSettings, settings, force);
QString channelSettingsURL = QString("http://%1:%2/sdrangel/deviceset/%3/channel/%4/settings")
.arg(settings.m_reverseAPIAddress)
.arg(settings.m_reverseAPIPort)
.arg(settings.m_reverseAPIDeviceIndex)
.arg(settings.m_reverseAPIChannelIndex);
m_networkRequest.setUrl(QUrl(channelSettingsURL));
m_networkRequest.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
QBuffer *buffer = new QBuffer();
buffer->open((QBuffer::ReadWrite));
buffer->write(swgChannelSettings->asJson().toUtf8());
buffer->seek(0);
// Always use PATCH to avoid passing reverse API settings
QNetworkReply *reply = m_networkManager->sendCustomRequest(m_networkRequest, "PATCH", buffer);
buffer->setParent(reply);
delete swgChannelSettings;
}
void NFMDemod::featuresSendSettings(QList<QString>& channelSettingsKeys, const NFMDemodSettings& settings, bool force)
{
QList<Feature*>::iterator it = m_featuresSettingsFeedback.begin();
MainCore *mainCore = MainCore::instance();
for (; it != m_featuresSettingsFeedback.end(); ++it)
{
if (mainCore->existsFeature(*it))
{
SWGSDRangel::SWGChannelSettings *swgChannelSettings = new SWGSDRangel::SWGChannelSettings();
webapiFormatChannelSettings(channelSettingsKeys, swgChannelSettings, settings, force);
Feature::MsgChannelSettings *msg = Feature::MsgChannelSettings::create(
this,
channelSettingsKeys,
swgChannelSettings,
force
);
(*it)->getInputMessageQueue()->push(msg);
}
else
{
m_featuresSettingsFeedback.removeOne(*it);
}
}
}
void NFMDemod::webapiFormatChannelSettings(
QList<QString>& channelSettingsKeys,
SWGSDRangel::SWGChannelSettings *swgChannelSettings,
const NFMDemodSettings& settings,
bool force
)
{
swgChannelSettings->setDirection(0); // Single sink (Rx)
swgChannelSettings->setOriginatorChannelIndex(getIndexInDeviceSet());
swgChannelSettings->setOriginatorDeviceSetIndex(getDeviceSetIndex());
swgChannelSettings->setChannelType(new QString("NFMDemod"));
swgChannelSettings->setChannelType(new QString(m_channelId));
swgChannelSettings->setNfmDemodSettings(new SWGSDRangel::SWGNFMDemodSettings());
SWGSDRangel::SWGNFMDemodSettings *swgNFMDemodSettings = swgChannelSettings->getNfmDemodSettings();
@ -498,25 +557,6 @@ void NFMDemod::webapiReverseSendSettings(QList<QString>& channelSettingsKeys, co
if (channelSettingsKeys.contains("streamIndex") || force) {
swgNFMDemodSettings->setStreamIndex(settings.m_streamIndex);
}
QString channelSettingsURL = QString("http://%1:%2/sdrangel/deviceset/%3/channel/%4/settings")
.arg(settings.m_reverseAPIAddress)
.arg(settings.m_reverseAPIPort)
.arg(settings.m_reverseAPIDeviceIndex)
.arg(settings.m_reverseAPIChannelIndex);
m_networkRequest.setUrl(QUrl(channelSettingsURL));
m_networkRequest.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
QBuffer *buffer = new QBuffer();
buffer->open((QBuffer::ReadWrite));
buffer->write(swgChannelSettings->asJson().toUtf8());
buffer->seek(0);
// Always use PATCH to avoid passing reverse API settings
QNetworkReply *reply = m_networkManager->sendCustomRequest(m_networkRequest, "PATCH", buffer);
buffer->setParent(reply);
delete swgChannelSettings;
}
void NFMDemod::networkManagerFinished(QNetworkReply *reply)

View File

@ -138,6 +138,13 @@ private:
void applySettings(const NFMDemodSettings& settings, bool force = false);
void webapiFormatChannelReport(SWGSDRangel::SWGChannelReport& response);
void webapiReverseSendSettings(QList<QString>& channelSettingsKeys, const NFMDemodSettings& settings, bool force);
void featuresSendSettings(QList<QString>& channelSettingsKeys, const NFMDemodSettings& settings, bool force);
void webapiFormatChannelSettings(
QList<QString>& channelSettingsKeys,
SWGSDRangel::SWGChannelSettings *swgChannelSettings,
const NFMDemodSettings& settings,
bool force
);
private slots:
void networkManagerFinished(QNetworkReply *reply);

View File

@ -36,7 +36,9 @@
#include "dsp/dspcommands.h"
#include "dsp/devicesamplemimo.h"
#include "device/deviceapi.h"
#include "feature/feature.h"
#include "util/db.h"
#include "maincore.h"
#include "ssbdemod.h"
@ -235,6 +237,10 @@ void SSBDemod::applySettings(const SSBDemodSettings& settings, bool force)
webapiReverseSendSettings(reverseAPIKeys, settings, fullUpdate || force);
}
if (m_featuresSettingsFeedback.size() > 0) {
featuresSendSettings(reverseAPIKeys, settings, force);
}
m_settings = settings;
}
@ -443,10 +449,67 @@ void SSBDemod::webapiFormatChannelReport(SWGSDRangel::SWGChannelReport& response
void SSBDemod::webapiReverseSendSettings(QList<QString>& channelSettingsKeys, const SSBDemodSettings& settings, bool force)
{
SWGSDRangel::SWGChannelSettings *swgChannelSettings = new SWGSDRangel::SWGChannelSettings();
swgChannelSettings->setDirection(0); // single sink (Rx)
webapiFormatChannelSettings(channelSettingsKeys, swgChannelSettings, settings, force);
QString channelSettingsURL = QString("http://%1:%2/sdrangel/deviceset/%3/channel/%4/settings")
.arg(settings.m_reverseAPIAddress)
.arg(settings.m_reverseAPIPort)
.arg(settings.m_reverseAPIDeviceIndex)
.arg(settings.m_reverseAPIChannelIndex);
m_networkRequest.setUrl(QUrl(channelSettingsURL));
m_networkRequest.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
QBuffer *buffer = new QBuffer();
buffer->open((QBuffer::ReadWrite));
buffer->write(swgChannelSettings->asJson().toUtf8());
buffer->seek(0);
// Always use PATCH to avoid passing reverse API settings
QNetworkReply *reply = m_networkManager->sendCustomRequest(m_networkRequest, "PATCH", buffer);
buffer->setParent(reply);
delete swgChannelSettings;
}
void SSBDemod::featuresSendSettings(QList<QString>& channelSettingsKeys, const SSBDemodSettings& settings, bool force)
{
QList<Feature*>::iterator it = m_featuresSettingsFeedback.begin();
MainCore *mainCore = MainCore::instance();
for (; it != m_featuresSettingsFeedback.end(); ++it)
{
if (mainCore->existsFeature(*it))
{
SWGSDRangel::SWGChannelSettings *swgChannelSettings = new SWGSDRangel::SWGChannelSettings();
webapiFormatChannelSettings(channelSettingsKeys, swgChannelSettings, settings, force);
Feature::MsgChannelSettings *msg = Feature::MsgChannelSettings::create(
this,
channelSettingsKeys,
swgChannelSettings,
force
);
(*it)->getInputMessageQueue()->push(msg);
}
else
{
m_featuresSettingsFeedback.removeOne(*it);
}
}
}
void SSBDemod::webapiFormatChannelSettings(
QList<QString>& channelSettingsKeys,
SWGSDRangel::SWGChannelSettings *swgChannelSettings,
const SSBDemodSettings& settings,
bool force
)
{
swgChannelSettings->setDirection(0); // Single sink (Rx)
swgChannelSettings->setOriginatorChannelIndex(getIndexInDeviceSet());
swgChannelSettings->setOriginatorDeviceSetIndex(getDeviceSetIndex());
swgChannelSettings->setChannelType(new QString("SSBDemod"));
swgChannelSettings->setChannelType(new QString(m_channelId));
swgChannelSettings->setSsbDemodSettings(new SWGSDRangel::SWGSSBDemodSettings());
SWGSDRangel::SWGSSBDemodSettings *swgSSBDemodSettings = swgChannelSettings->getSsbDemodSettings();
@ -506,25 +569,6 @@ void SSBDemod::webapiReverseSendSettings(QList<QString>& channelSettingsKeys, co
if (channelSettingsKeys.contains("streamIndex") || force) {
swgSSBDemodSettings->setStreamIndex(settings.m_streamIndex);
}
QString channelSettingsURL = QString("http://%1:%2/sdrangel/deviceset/%3/channel/%4/settings")
.arg(settings.m_reverseAPIAddress)
.arg(settings.m_reverseAPIPort)
.arg(settings.m_reverseAPIDeviceIndex)
.arg(settings.m_reverseAPIChannelIndex);
m_networkRequest.setUrl(QUrl(channelSettingsURL));
m_networkRequest.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
QBuffer *buffer = new QBuffer();
buffer->open((QBuffer::ReadWrite));
buffer->write(swgChannelSettings->asJson().toUtf8());
buffer->seek(0);
// Always use PATCH to avoid passing reverse API settings
QNetworkReply *reply = m_networkManager->sendCustomRequest(m_networkRequest, "PATCH", buffer);
buffer->setParent(reply);
delete swgChannelSettings;
}
void SSBDemod::networkManagerFinished(QNetworkReply *reply)

View File

@ -141,6 +141,13 @@ private:
void applySettings(const SSBDemodSettings& settings, bool force = false);
void webapiFormatChannelReport(SWGSDRangel::SWGChannelReport& response);
void webapiReverseSendSettings(QList<QString>& channelSettingsKeys, const SSBDemodSettings& settings, bool force);
void featuresSendSettings(QList<QString>& channelSettingsKeys, const SSBDemodSettings& settings, bool force);
void webapiFormatChannelSettings(
QList<QString>& channelSettingsKeys,
SWGSDRangel::SWGChannelSettings *swgChannelSettings,
const SSBDemodSettings& settings,
bool force
);
private slots:
void networkManagerFinished(QNetworkReply *reply);

View File

@ -38,7 +38,9 @@
#include "dsp/dspcommands.h"
#include "dsp/devicesamplemimo.h"
#include "device/deviceapi.h"
#include "feature/feature.h"
#include "util/db.h"
#include "maincore.h"
#include "wfmdemod.h"
@ -211,6 +213,10 @@ void WFMDemod::applySettings(const WFMDemodSettings& settings, bool force)
webapiReverseSendSettings(reverseAPIKeys, settings, fullUpdate || force);
}
if (m_featuresSettingsFeedback.size() > 0) {
featuresSendSettings(reverseAPIKeys, settings, force);
}
m_settings = settings;
}
@ -386,10 +392,67 @@ void WFMDemod::webapiFormatChannelReport(SWGSDRangel::SWGChannelReport& response
void WFMDemod::webapiReverseSendSettings(QList<QString>& channelSettingsKeys, const WFMDemodSettings& settings, bool force)
{
SWGSDRangel::SWGChannelSettings *swgChannelSettings = new SWGSDRangel::SWGChannelSettings();
swgChannelSettings->setDirection(0); // single sink (Rx)
webapiFormatChannelSettings(channelSettingsKeys, swgChannelSettings, settings, force);
QString channelSettingsURL = QString("http://%1:%2/sdrangel/deviceset/%3/channel/%4/settings")
.arg(settings.m_reverseAPIAddress)
.arg(settings.m_reverseAPIPort)
.arg(settings.m_reverseAPIDeviceIndex)
.arg(settings.m_reverseAPIChannelIndex);
m_networkRequest.setUrl(QUrl(channelSettingsURL));
m_networkRequest.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
QBuffer *buffer = new QBuffer();
buffer->open((QBuffer::ReadWrite));
buffer->write(swgChannelSettings->asJson().toUtf8());
buffer->seek(0);
// Always use PATCH to avoid passing reverse API settings
QNetworkReply *reply = m_networkManager->sendCustomRequest(m_networkRequest, "PATCH", buffer);
buffer->setParent(reply);
delete swgChannelSettings;
}
void WFMDemod::featuresSendSettings(QList<QString>& channelSettingsKeys, const WFMDemodSettings& settings, bool force)
{
QList<Feature*>::iterator it = m_featuresSettingsFeedback.begin();
MainCore *mainCore = MainCore::instance();
for (; it != m_featuresSettingsFeedback.end(); ++it)
{
if (mainCore->existsFeature(*it))
{
SWGSDRangel::SWGChannelSettings *swgChannelSettings = new SWGSDRangel::SWGChannelSettings();
webapiFormatChannelSettings(channelSettingsKeys, swgChannelSettings, settings, force);
Feature::MsgChannelSettings *msg = Feature::MsgChannelSettings::create(
this,
channelSettingsKeys,
swgChannelSettings,
force
);
(*it)->getInputMessageQueue()->push(msg);
}
else
{
m_featuresSettingsFeedback.removeOne(*it);
}
}
}
void WFMDemod::webapiFormatChannelSettings(
QList<QString>& channelSettingsKeys,
SWGSDRangel::SWGChannelSettings *swgChannelSettings,
const WFMDemodSettings& settings,
bool force
)
{
swgChannelSettings->setDirection(0); // Single sink (Rx)
swgChannelSettings->setOriginatorChannelIndex(getIndexInDeviceSet());
swgChannelSettings->setOriginatorDeviceSetIndex(getDeviceSetIndex());
swgChannelSettings->setChannelType(new QString("WFMDemod"));
swgChannelSettings->setChannelType(new QString(m_channelId));
swgChannelSettings->setWfmDemodSettings(new SWGSDRangel::SWGWFMDemodSettings());
SWGSDRangel::SWGWFMDemodSettings *swgWFMDemodSettings = swgChannelSettings->getWfmDemodSettings();
@ -425,25 +488,6 @@ void WFMDemod::webapiReverseSendSettings(QList<QString>& channelSettingsKeys, co
if (channelSettingsKeys.contains("streamIndex") || force) {
swgWFMDemodSettings->setStreamIndex(settings.m_streamIndex);
}
QString channelSettingsURL = QString("http://%1:%2/sdrangel/deviceset/%3/channel/%4/settings")
.arg(settings.m_reverseAPIAddress)
.arg(settings.m_reverseAPIPort)
.arg(settings.m_reverseAPIDeviceIndex)
.arg(settings.m_reverseAPIChannelIndex);
m_networkRequest.setUrl(QUrl(channelSettingsURL));
m_networkRequest.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
QBuffer *buffer = new QBuffer();
buffer->open((QBuffer::ReadWrite));
buffer->write(swgChannelSettings->asJson().toUtf8());
buffer->seek(0);
// Always use PATCH to avoid passing reverse API settings
QNetworkReply *reply = m_networkManager->sendCustomRequest(m_networkRequest, "PATCH", buffer);
buffer->setParent(reply);
delete swgChannelSettings;
}
void WFMDemod::networkManagerFinished(QNetworkReply *reply)

View File

@ -137,6 +137,13 @@ private:
void webapiFormatChannelReport(SWGSDRangel::SWGChannelReport& response);
void webapiReverseSendSettings(QList<QString>& channelSettingsKeys, const WFMDemodSettings& settings, bool force);
void featuresSendSettings(QList<QString>& channelSettingsKeys, const WFMDemodSettings& settings, bool force);
void webapiFormatChannelSettings(
QList<QString>& channelSettingsKeys,
SWGSDRangel::SWGChannelSettings *swgChannelSettings,
const WFMDemodSettings& settings,
bool force
);
private slots:
void networkManagerFinished(QNetworkReply *reply);

View File

@ -35,6 +35,8 @@
#include "dsp/hbfilterchainconverter.h"
#include "dsp/devicesamplemimo.h"
#include "device/deviceapi.h"
#include "feature/feature.h"
#include "maincore.h"
#include "filesinkmessages.h"
#include "filesinkbaseband.h"
@ -293,6 +295,10 @@ void FileSink::applySettings(const FileSinkSettings& settings, bool force)
webapiReverseSendSettings(reverseAPIKeys, settings, fullUpdate || force);
}
if (m_featuresSettingsFeedback.size() > 0) {
featuresSendSettings(reverseAPIKeys, settings, force);
}
m_settings = settings;
}
@ -522,10 +528,67 @@ void FileSink::webapiFormatChannelReport(SWGSDRangel::SWGChannelReport& response
void FileSink::webapiReverseSendSettings(QList<QString>& channelSettingsKeys, const FileSinkSettings& settings, bool force)
{
SWGSDRangel::SWGChannelSettings *swgChannelSettings = new SWGSDRangel::SWGChannelSettings();
swgChannelSettings->setDirection(0); // single sink (Rx)
webapiFormatChannelSettings(channelSettingsKeys, swgChannelSettings, settings, force);
QString channelSettingsURL = QString("http://%1:%2/sdrangel/deviceset/%3/channel/%4/settings")
.arg(settings.m_reverseAPIAddress)
.arg(settings.m_reverseAPIPort)
.arg(settings.m_reverseAPIDeviceIndex)
.arg(settings.m_reverseAPIChannelIndex);
m_networkRequest.setUrl(QUrl(channelSettingsURL));
m_networkRequest.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
QBuffer *buffer = new QBuffer();
buffer->open((QBuffer::ReadWrite));
buffer->write(swgChannelSettings->asJson().toUtf8());
buffer->seek(0);
// Always use PATCH to avoid passing reverse API settings
QNetworkReply *reply = m_networkManager->sendCustomRequest(m_networkRequest, "PATCH", buffer);
buffer->setParent(reply);
delete swgChannelSettings;
}
void FileSink::featuresSendSettings(QList<QString>& channelSettingsKeys, const FileSinkSettings& settings, bool force)
{
QList<Feature*>::iterator it = m_featuresSettingsFeedback.begin();
MainCore *mainCore = MainCore::instance();
for (; it != m_featuresSettingsFeedback.end(); ++it)
{
if (mainCore->existsFeature(*it))
{
SWGSDRangel::SWGChannelSettings *swgChannelSettings = new SWGSDRangel::SWGChannelSettings();
webapiFormatChannelSettings(channelSettingsKeys, swgChannelSettings, settings, force);
Feature::MsgChannelSettings *msg = Feature::MsgChannelSettings::create(
this,
channelSettingsKeys,
swgChannelSettings,
force
);
(*it)->getInputMessageQueue()->push(msg);
}
else
{
m_featuresSettingsFeedback.removeOne(*it);
}
}
}
void FileSink::webapiFormatChannelSettings(
QList<QString>& channelSettingsKeys,
SWGSDRangel::SWGChannelSettings *swgChannelSettings,
const FileSinkSettings& settings,
bool force
)
{
swgChannelSettings->setDirection(0); // Single sink (Rx)
swgChannelSettings->setOriginatorChannelIndex(getIndexInDeviceSet());
swgChannelSettings->setOriginatorDeviceSetIndex(getDeviceSetIndex());
swgChannelSettings->setChannelType(new QString("FileSink"));
swgChannelSettings->setChannelType(new QString(m_channelId));
swgChannelSettings->setFileSinkSettings(new SWGSDRangel::SWGFileSinkSettings());
SWGSDRangel::SWGFileSinkSettings *swgFileSinkSettings = swgChannelSettings->getFileSinkSettings();
@ -564,25 +627,6 @@ void FileSink::webapiReverseSendSettings(QList<QString>& channelSettingsKeys, co
if (channelSettingsKeys.contains("streamIndex")) {
swgFileSinkSettings->setStreamIndex(settings.m_streamIndex);
}
QString channelSettingsURL = QString("http://%1:%2/sdrangel/deviceset/%3/channel/%4/settings")
.arg(settings.m_reverseAPIAddress)
.arg(settings.m_reverseAPIPort)
.arg(settings.m_reverseAPIDeviceIndex)
.arg(settings.m_reverseAPIChannelIndex);
m_networkRequest.setUrl(QUrl(channelSettingsURL));
m_networkRequest.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
QBuffer *buffer = new QBuffer();
buffer->open((QBuffer::ReadWrite));
buffer->write(swgChannelSettings->asJson().toUtf8());
buffer->seek(0);
// Always use PATCH to avoid passing reverse API settings
QNetworkReply *reply = m_networkManager->sendCustomRequest(m_networkRequest, "PATCH", buffer);
buffer->setParent(reply);
delete swgChannelSettings;
}
void FileSink::networkManagerFinished(QNetworkReply *reply)

View File

@ -148,6 +148,13 @@ private:
void webapiFormatChannelReport(SWGSDRangel::SWGChannelReport& response);
void webapiReverseSendSettings(QList<QString>& channelSettingsKeys, const FileSinkSettings& settings, bool force);
void featuresSendSettings(QList<QString>& channelSettingsKeys, const FileSinkSettings& settings, bool force);
void webapiFormatChannelSettings(
QList<QString>& channelSettingsKeys,
SWGSDRangel::SWGChannelSettings *swgChannelSettings,
const FileSinkSettings& settings,
bool force
);
private slots:
void networkManagerFinished(QNetworkReply *reply);

View File

@ -41,6 +41,8 @@
#include "device/deviceapi.h"
#include "util/db.h"
#include "util/stepfunctions.h"
#include "feature/feature.h"
#include "maincore.h"
#include "freqtrackerreport.h"
@ -53,12 +55,14 @@ const int FreqTracker::m_udpBlockSize = 512;
FreqTracker::FreqTracker(DeviceAPI *deviceAPI) :
ChannelAPI(m_channelIdURI, ChannelAPI::StreamSingleSink),
m_deviceAPI(deviceAPI),
m_spectrumVis(SDR_RX_SCALEF),
m_basebandSampleRate(0)
{
setObjectName(m_channelId);
m_thread = new QThread(this);
m_basebandSink = new FreqTrackerBaseband();
m_basebandSink->setSpectrumSink(&m_spectrumVis);
propagateMessageQueue(getInputMessageQueue());
m_basebandSink->moveToThread(m_thread);
@ -178,6 +182,7 @@ void FreqTracker::applySettings(const FreqTrackerSettings& settings, bool force)
<< " m_rrc: " << settings.m_rrc
<< " m_rrcRolloff: " << settings.m_rrcRolloff
<< " m_streamIndex: " << settings.m_streamIndex
<< " m_spanLog2: " << settings.m_spanLog2
<< " m_useReverseAPI: " << settings.m_useReverseAPI
<< " m_reverseAPIAddress: " << settings.m_reverseAPIAddress
<< " m_reverseAPIPort: " << settings.m_reverseAPIPort
@ -211,6 +216,9 @@ void FreqTracker::applySettings(const FreqTrackerSettings& settings, bool force)
if ((m_settings.m_alphaEMA != settings.m_alphaEMA) || force) {
reverseAPIKeys.append("alphaEMA");
}
if ((m_settings.m_spanLog2 != settings.m_spanLog2) || force) {
reverseAPIKeys.append("spanLog2");
}
if ((m_settings.m_tracking != settings.m_tracking) || force) {
reverseAPIKeys.append("tracking");
}
@ -256,6 +264,15 @@ void FreqTracker::applySettings(const FreqTrackerSettings& settings, bool force)
webapiReverseSendSettings(reverseAPIKeys, settings, fullUpdate || force);
}
if (m_featuresSettingsFeedback.size() > 0)
{
if (m_featuresSettingsFeedbackBlockCount == 0) {
featuresSendSettings(reverseAPIKeys, settings, force);
} else {
m_featuresSettingsFeedbackBlockCount--;
}
}
m_settings = settings;
}
@ -341,6 +358,9 @@ void FreqTracker::webapiUpdateChannelSettings(
if (channelSettingsKeys.contains("title")) {
settings.m_title = *response.getFreqTrackerSettings()->getTitle();
}
if (channelSettingsKeys.contains("spanLog2")) {
settings.m_spanLog2 = response.getFreqTrackerSettings()->getSpanLog2();
}
if (channelSettingsKeys.contains("alphaEMA")) {
float alphaEMA = response.getFreqTrackerSettings()->getAlphaEma();
settings.m_alphaEMA = alphaEMA < 0.01 ? 0.01 : alphaEMA > 1.0 ? 1.0 : alphaEMA;
@ -412,6 +432,7 @@ void FreqTracker::webapiFormatChannelSettings(SWGSDRangel::SWGChannelSettings& r
response.getFreqTrackerSettings()->setTitle(new QString(settings.m_title));
}
response.getFreqTrackerSettings()->setSpanLog2(settings.m_spanLog2);
response.getFreqTrackerSettings()->setAlphaEma(settings.m_alphaEMA);
response.getFreqTrackerSettings()->setTracking(settings.m_tracking ? 1 : 0);
response.getFreqTrackerSettings()->setTrackerType((int) settings.m_trackerType);
@ -449,36 +470,7 @@ void FreqTracker::webapiFormatChannelReport(SWGSDRangel::SWGChannelReport& respo
void FreqTracker::webapiReverseSendSettings(QList<QString>& channelSettingsKeys, const FreqTrackerSettings& settings, bool force)
{
SWGSDRangel::SWGChannelSettings *swgChannelSettings = new SWGSDRangel::SWGChannelSettings();
swgChannelSettings->setDirection(0); // single sink (Rx)
swgChannelSettings->setOriginatorChannelIndex(getIndexInDeviceSet());
swgChannelSettings->setOriginatorDeviceSetIndex(getDeviceSetIndex());
swgChannelSettings->setChannelType(new QString("FreqTracker"));
swgChannelSettings->setFreqTrackerSettings(new SWGSDRangel::SWGFreqTrackerSettings());
SWGSDRangel::SWGFreqTrackerSettings *swgFreqTrackerSettings = swgChannelSettings->getFreqTrackerSettings();
// transfer data that has been modified. When force is on transfer all data except reverse API data
if (channelSettingsKeys.contains("inputFrequencyOffset") || force) {
swgFreqTrackerSettings->setInputFrequencyOffset(settings.m_inputFrequencyOffset);
}
if (channelSettingsKeys.contains("rfBandwidth") || force) {
swgFreqTrackerSettings->setRfBandwidth(settings.m_rfBandwidth);
}
if (channelSettingsKeys.contains("rgbColor") || force) {
swgFreqTrackerSettings->setRgbColor(settings.m_rgbColor);
}
if (channelSettingsKeys.contains("squelch") || force) {
swgFreqTrackerSettings->setSquelch(settings.m_squelch);
}
if (channelSettingsKeys.contains("title") || force) {
swgFreqTrackerSettings->setTitle(new QString(settings.m_title));
}
if (channelSettingsKeys.contains("trackerType") || force) {
swgFreqTrackerSettings->setTrackerType((int) settings.m_trackerType);
}
if (channelSettingsKeys.contains("streamIndex") || force) {
swgFreqTrackerSettings->setStreamIndex(settings.m_streamIndex);
}
webapiFormatChannelSettings(channelSettingsKeys, swgChannelSettings, settings, force);
QString channelSettingsURL = QString("http://%1:%2/sdrangel/deviceset/%3/channel/%4/settings")
.arg(settings.m_reverseAPIAddress)
@ -500,6 +492,96 @@ void FreqTracker::webapiReverseSendSettings(QList<QString>& channelSettingsKeys,
delete swgChannelSettings;
}
void FreqTracker::featuresSendSettings(QList<QString>& channelSettingsKeys, const FreqTrackerSettings& settings, bool force)
{
QList<Feature*>::iterator it = m_featuresSettingsFeedback.begin();
MainCore *mainCore = MainCore::instance();
for (; it != m_featuresSettingsFeedback.end(); ++it)
{
if (mainCore->existsFeature(*it))
{
SWGSDRangel::SWGChannelSettings *swgChannelSettings = new SWGSDRangel::SWGChannelSettings();
webapiFormatChannelSettings(channelSettingsKeys, swgChannelSettings, settings, force);
Feature::MsgChannelSettings *msg = Feature::MsgChannelSettings::create(
this,
channelSettingsKeys,
swgChannelSettings,
force
);
(*it)->getInputMessageQueue()->push(msg);
}
else
{
m_featuresSettingsFeedback.removeOne(*it);
}
}
}
void FreqTracker::webapiFormatChannelSettings(
QList<QString>& channelSettingsKeys,
SWGSDRangel::SWGChannelSettings *swgChannelSettings,
const FreqTrackerSettings& settings,
bool force)
{
swgChannelSettings->setDirection(0); // single sink (Rx)
swgChannelSettings->setOriginatorChannelIndex(getIndexInDeviceSet());
swgChannelSettings->setOriginatorDeviceSetIndex(getDeviceSetIndex());
swgChannelSettings->setChannelType(new QString("FreqTracker"));
swgChannelSettings->setFreqTrackerSettings(new SWGSDRangel::SWGFreqTrackerSettings());
SWGSDRangel::SWGFreqTrackerSettings *swgFreqTrackerSettings = swgChannelSettings->getFreqTrackerSettings();
// transfer data that has been modified. When force is on transfer all data except reverse API data
if (channelSettingsKeys.contains("inputFrequencyOffset") || force) {
swgFreqTrackerSettings->setInputFrequencyOffset(settings.m_inputFrequencyOffset);
}
if (channelSettingsKeys.contains("rfBandwidth") || force) {
swgFreqTrackerSettings->setRfBandwidth(settings.m_rfBandwidth);
}
if (channelSettingsKeys.contains("log2Decim") || force) {
swgFreqTrackerSettings->setLog2Decim(settings.m_log2Decim);
}
if (channelSettingsKeys.contains("squelch") || force) {
swgFreqTrackerSettings->setSquelch(settings.m_squelch);
}
if (channelSettingsKeys.contains("rgbColor") || force) {
swgFreqTrackerSettings->setRgbColor(settings.m_rgbColor);
}
if (channelSettingsKeys.contains("title") || force) {
swgFreqTrackerSettings->setTitle(new QString(settings.m_title));
}
if (channelSettingsKeys.contains("spanLog2") || force) {
swgFreqTrackerSettings->setSpanLog2(settings.m_spanLog2);
}
if (channelSettingsKeys.contains("alphaEMA") || force) {
swgFreqTrackerSettings->setAlphaEma(settings.m_alphaEMA);
}
if (channelSettingsKeys.contains("tracking") || force) {
swgFreqTrackerSettings->setTracking(settings.m_tracking ? 1 : 0);
}
if (channelSettingsKeys.contains("trackerType") || force) {
swgFreqTrackerSettings->setTrackerType((int) settings.m_trackerType);
}
if (channelSettingsKeys.contains("pllPskOrder") || force) {
swgFreqTrackerSettings->setPllPskOrder(settings.m_pllPskOrder);
}
if (channelSettingsKeys.contains("rrc") || force) {
swgFreqTrackerSettings->setRrc(settings.m_rrc ? 1 : 0);
}
if (channelSettingsKeys.contains("rrcRolloff") || force) {
swgFreqTrackerSettings->setRrcRolloff(settings.m_rrcRolloff);
}
if (channelSettingsKeys.contains("squelchGate") || force) {
swgFreqTrackerSettings->setSquelchGate(settings.m_squelchGate);
}
if (channelSettingsKeys.contains("streamIndex") || force) {
swgFreqTrackerSettings->setStreamIndex(settings.m_streamIndex);
}
}
void FreqTracker::networkManagerFinished(QNetworkReply *reply)
{
QNetworkReply::NetworkError replyError = reply->error();

View File

@ -24,6 +24,7 @@
#include <QMutex>
#include "dsp/basebandsamplesink.h"
#include "dsp/spectrumvis.h"
#include "channel/channelapi.h"
#include "util/message.h"
@ -109,6 +110,7 @@ public:
const QStringList& channelSettingsKeys,
SWGSDRangel::SWGChannelSettings& response);
SpectrumVis *getSpectrumVis() { return &m_spectrumVis; }
uint32_t getSampleRate() const { return m_basebandSink->getSampleRate(); }
double getMagSq() const { return m_basebandSink->getMagSq(); }
bool getSquelchOpen() const { return m_basebandSink->getSquelchOpen(); }
@ -131,6 +133,7 @@ private:
QThread *m_thread;
FreqTrackerBaseband* m_basebandSink;
FreqTrackerSettings m_settings;
SpectrumVis m_spectrumVis;
int m_basebandSampleRate; //!< stored from device message used when starting baseband sink
static const int m_udpBlockSize;
QNetworkAccessManager *m_networkManager;
@ -139,6 +142,13 @@ private:
void applySettings(const FreqTrackerSettings& settings, bool force = false);
void webapiFormatChannelReport(SWGSDRangel::SWGChannelReport& response);
void webapiReverseSendSettings(QList<QString>& channelSettingsKeys, const FreqTrackerSettings& settings, bool force);
void featuresSendSettings(QList<QString>& channelSettingsKeys, const FreqTrackerSettings& settings, bool force);
void webapiFormatChannelSettings(
QList<QString>& channelSettingsKeys,
SWGSDRangel::SWGChannelSettings *swgChannelSettings,
const FreqTrackerSettings& settings,
bool force
);
private slots:
void networkManagerFinished(QNetworkReply *reply);

View File

@ -28,6 +28,7 @@
#include "freqtrackersink.h"
class DownChannelizer;
class SpectrumVis;
class FreqTrackerBaseband : public QObject
{
@ -61,6 +62,7 @@ public:
void reset();
void feed(const SampleVector::const_iterator& begin, const SampleVector::const_iterator& end);
MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; } //!< Get the queue for asynchronous inbound communication
void setSpectrumSink(SpectrumVis* spectrumSink) { m_spectrumVis = spectrumSink; m_sink.setSpectrumSink(spectrumSink); }
int getChannelSampleRate() const;
void setBasebandSampleRate(int sampleRate);
void setMessageQueueToInput(MessageQueue *messageQueue) { m_sink.setMessageQueueToInput(messageQueue); }
@ -80,6 +82,7 @@ private:
MessageQueue m_inputMessageQueue; //!< Queue for asynchronous inbound communication
FreqTrackerSettings m_settings;
unsigned int m_basebandSampleRate;
SpectrumVis *m_spectrumVis;
QMutex m_mutex;
bool handleMessage(const Message& cmd);

View File

@ -91,6 +91,8 @@ bool FreqTrackerGUI::handleMessage(const Message& message)
m_basebandSampleRate = cfg.getSampleRate();
int sinkSampleRate = m_basebandSampleRate / (1<<m_settings.m_log2Decim);
ui->channelSampleRateText->setText(tr("%1k").arg(QString::number(sinkSampleRate / 1000.0f, 'g', 5)));
displaySpectrumBandwidth(m_settings.m_spanLog2);
m_pllChannelMarker.setBandwidth(sinkSampleRate/500);
if (sinkSampleRate > 1000) {
ui->rfBW->setMaximum(sinkSampleRate/100);
@ -151,6 +153,8 @@ void FreqTrackerGUI::on_log2Decim_currentIndexChanged(int index)
m_settings.m_log2Decim = index < 0 ? 0 : index > 6 ? 6 : index;
int sinkSampleRate = m_basebandSampleRate / (1<<m_settings.m_log2Decim);
ui->channelSampleRateText->setText(tr("%1k").arg(QString::number(sinkSampleRate / 1000.0f, 'g', 5)));
displaySpectrumBandwidth(m_settings.m_spanLog2);
m_pllChannelMarker.setBandwidth(sinkSampleRate/500);
if (sinkSampleRate > 1000) {
ui->rfBW->setMaximum(sinkSampleRate/100);
@ -231,6 +235,15 @@ void FreqTrackerGUI::on_squelchGate_valueChanged(int value)
applySettings();
}
void FreqTrackerGUI::on_spanLog2_valueChanged(int value)
{
if ((value < 0) || (value > 6)) {
return;
}
applySpectrumBandwidth(ui->spanLog2->value());
}
void FreqTrackerGUI::onWidgetRolled(QWidget* widget, bool rollDown)
{
(void) widget;
@ -288,6 +301,7 @@ FreqTrackerGUI::FreqTrackerGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, B
m_pluginAPI(pluginAPI),
m_deviceUISet(deviceUISet),
m_channelMarker(this),
m_pllChannelMarker(this),
m_basebandSampleRate(0),
m_doApplySettings(true),
m_squelchOpen(false),
@ -300,6 +314,8 @@ FreqTrackerGUI::FreqTrackerGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, B
m_freqTracker = reinterpret_cast<FreqTracker*>(rxChannel);
m_freqTracker->setMessageQueueToGUI(getInputMessageQueue());
m_spectrumVis = m_freqTracker->getSpectrumVis();
m_spectrumVis->setGLSpectrum(ui->glSpectrum);
connect(&MainCore::instance()->getMasterTimer(), SIGNAL(timeout()), this, SLOT(tick())); // 50 ms
@ -318,10 +334,23 @@ FreqTrackerGUI::FreqTrackerGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, B
setTitleColor(m_channelMarker.getColor());
m_settings.setChannelMarker(&m_channelMarker);
m_settings.setSpectrumGUI(ui->spectrumGUI);
m_deviceUISet->addChannelMarker(&m_channelMarker);
m_deviceUISet->addRollupWidget(this);
ui->glSpectrum->setCenterFrequency(0);
m_pllChannelMarker.blockSignals(true);
m_pllChannelMarker.setColor(Qt::white);
m_pllChannelMarker.setCenterFrequency(0);
m_pllChannelMarker.setBandwidth(70);
m_pllChannelMarker.setTitle("Tracker");
m_pllChannelMarker.setMovable(false);
m_pllChannelMarker.blockSignals(false);
m_pllChannelMarker.setVisible(true);
ui->glSpectrum->addChannelMarker(&m_pllChannelMarker);
ui->spectrumGUI->setBuddies(m_spectrumVis, ui->glSpectrum);
connect(&m_channelMarker, SIGNAL(changedByCursor()), this, SLOT(channelMarkerChangedByCursor()));
connect(&m_channelMarker, SIGNAL(highlightedByCursor()), this, SLOT(channelMarkerHighlightedByCursor()));
connect(getInputMessageQueue(), SIGNAL(messageEnqueued()), this, SLOT(handleInputMessages()));
@ -349,6 +378,13 @@ void FreqTrackerGUI::applySettings(bool force)
}
}
void FreqTrackerGUI::applySpectrumBandwidth(int spanLog2, bool force)
{
displaySpectrumBandwidth(spanLog2);
m_settings.m_spanLog2 = spanLog2;
applySettings(force);
}
void FreqTrackerGUI::displaySettings()
{
m_channelMarker.blockSignals(true);
@ -387,11 +423,29 @@ void FreqTrackerGUI::displaySettings()
ui->squelchGateText->setText(QString("%1").arg(m_settings.m_squelchGate * 10.0f, 0, 'f', 0));
ui->squelchGate->setValue(m_settings.m_squelchGate);
displaySpectrumBandwidth(m_settings.m_spanLog2);
displayStreamIndex();
blockApplySettings(false);
}
void FreqTrackerGUI::displaySpectrumBandwidth(int spanLog2)
{
int spectrumRate = (m_basebandSampleRate / (1<<m_settings.m_log2Decim)) / (1<<spanLog2);
qDebug() << "FreqTrackerGUI::displaySpectrumBandwidth:"
<< " spanLog2: " << spanLog2
<< " spectrumRate: " << spectrumRate;
QString spanStr = QString::number(spectrumRate/1000.0, 'f', 1);
ui->spanLog2->blockSignals(true);
ui->spanLog2->setValue(spanLog2);
ui->spanLog2->blockSignals(false);
ui->spanText->setText(tr("%1k").arg(spanStr));
ui->glSpectrum->setSampleRate(spectrumRate);
}
void FreqTrackerGUI::displayStreamIndex()
{
if (m_deviceUISet->m_deviceMIMOEngine) {
@ -445,6 +499,7 @@ void FreqTrackerGUI::tick()
int freq = m_freqTracker->getAvgDeltaFreq();
QLocale loc;
ui->trackingFrequencyText->setText(tr("%1 Hz").arg(loc.toString(freq)));
m_pllChannelMarker.setCenterFrequency(freq);
if (m_settings.m_tracking) {
ui->tracking->setToolTip("Tracking on");

View File

@ -28,9 +28,9 @@
class PluginAPI;
class DeviceUISet;
class FreqTracker;
class BasebandSampleSink;
class SpectrumVis;
namespace Ui {
class FreqTrackerGUI;
@ -57,11 +57,13 @@ private:
PluginAPI* m_pluginAPI;
DeviceUISet* m_deviceUISet;
ChannelMarker m_channelMarker;
ChannelMarker m_pllChannelMarker;
FreqTrackerSettings m_settings;
int m_basebandSampleRate;
bool m_doApplySettings;
FreqTracker* m_freqTracker;
SpectrumVis* m_spectrumVis;
bool m_squelchOpen;
uint32_t m_tickCount;
MessageQueue m_inputMessageQueue;
@ -71,7 +73,9 @@ private:
void blockApplySettings(bool block);
void applySettings(bool force = false);
void applySpectrumBandwidth(int spanLog2, bool force = false);
void displaySettings();
void displaySpectrumBandwidth(int spanLog2);
void displayStreamIndex();
bool handleMessage(const Message& message);
@ -90,6 +94,7 @@ private slots:
void on_rrcRolloff_valueChanged(int value);
void on_squelch_valueChanged(int value);
void on_squelchGate_valueChanged(int value);
void on_spanLog2_valueChanged(int value);
void onWidgetRolled(QWidget* widget, bool rollDown);
void onMenuDialogCalled(const QPoint& p);
void handleInputMessages();

View File

@ -6,8 +6,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>360</width>
<height>145</height>
<width>400</width>
<height>327</height>
</rect>
</property>
<property name="sizePolicy">
@ -18,16 +18,10 @@
</property>
<property name="minimumSize">
<size>
<width>360</width>
<width>400</width>
<height>100</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>360</width>
<height>16777215</height>
</size>
</property>
<property name="font">
<font>
<family>Liberation Sans</family>
@ -45,8 +39,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>358</width>
<height>140</height>
<width>401</width>
<height>151</height>
</rect>
</property>
<property name="windowTitle">
@ -679,6 +673,122 @@
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="spanLayout">
<item>
<widget class="QLabel" name="spanLabel">
<property name="minimumSize">
<size>
<width>50</width>
<height>0</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>50</width>
<height>16777215</height>
</size>
</property>
<property name="text">
<string>Span</string>
</property>
</widget>
</item>
<item>
<widget class="QSlider" name="spanLog2">
<property name="toolTip">
<string>Spectrum display frequency span</string>
</property>
<property name="minimum">
<number>0</number>
</property>
<property name="maximum">
<number>6</number>
</property>
<property name="pageStep">
<number>1</number>
</property>
<property name="value">
<number>0</number>
</property>
<property name="sliderPosition">
<number>0</number>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="spanText">
<property name="minimumSize">
<size>
<width>50</width>
<height>0</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>50</width>
<height>16777215</height>
</size>
</property>
<property name="toolTip">
<string>Spectrum display frequency span (kHz)</string>
</property>
<property name="text">
<string>6.0k</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<widget class="QWidget" name="spectrumContainer" native="true">
<property name="geometry">
<rect>
<x>0</x>
<y>160</y>
<width>401</width>
<height>161</height>
</rect>
</property>
<property name="windowTitle">
<string>Channel Spectrum</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2">
<property name="spacing">
<number>2</number>
</property>
<property name="leftMargin">
<number>3</number>
</property>
<property name="topMargin">
<number>3</number>
</property>
<property name="rightMargin">
<number>3</number>
</property>
<property name="bottomMargin">
<number>3</number>
</property>
<item>
<widget class="GLSpectrum" name="glSpectrum" native="true">
<property name="font">
<font>
<family>Liberation Mono</family>
<pointsize>8</pointsize>
</font>
</property>
</widget>
</item>
<item>
<widget class="GLSpectrumGUI" name="spectrumGUI" native="true"/>
</item>
</layout>
</widget>
</widget>
@ -689,23 +799,35 @@
<header>gui/rollupwidget.h</header>
<container>1</container>
</customwidget>
<customwidget>
<class>ButtonSwitch</class>
<extends>QToolButton</extends>
<header>gui/buttonswitch.h</header>
</customwidget>
<customwidget>
<class>LevelMeterSignalDB</class>
<extends>QWidget</extends>
<header>gui/levelmeter.h</header>
<container>1</container>
</customwidget>
<customwidget>
<class>ButtonSwitch</class>
<extends>QToolButton</extends>
<header>gui/buttonswitch.h</header>
</customwidget>
<customwidget>
<class>ValueDialZ</class>
<extends>QWidget</extends>
<header>gui/valuedialz.h</header>
<container>1</container>
</customwidget>
<customwidget>
<class>GLSpectrum</class>
<extends>QWidget</extends>
<header>gui/glspectrum.h</header>
<container>1</container>
</customwidget>
<customwidget>
<class>GLSpectrumGUI</class>
<extends>QWidget</extends>
<header>gui/glspectrumgui.h</header>
<container>1</container>
</customwidget>
</customwidgets>
<resources>
<include location="../../../sdrgui/resources/res.qrc"/>

View File

@ -23,7 +23,8 @@
#include "freqtrackersettings.h"
FreqTrackerSettings::FreqTrackerSettings() :
m_channelMarker(0)
m_channelMarker(0),
m_spectrumGUI(0)
{
resetToDefaults();
}
@ -36,6 +37,7 @@ void FreqTrackerSettings::resetToDefaults()
m_squelch = -40.0;
m_rgbColor = QColor(200, 244, 66).rgb();
m_title = "Frequency Tracker";
m_spanLog2 = 0;
m_alphaEMA = 0.1;
m_tracking = false;
m_trackerType = TrackerFLL;
@ -57,6 +59,10 @@ QByteArray FreqTrackerSettings::serialize() const
s.writeS32(1, m_inputFrequencyOffset);
s.writeS32(2, m_rfBandwidth/100);
s.writeU32(3, m_log2Decim);
if (m_spectrumGUI) {
s.writeBlob(4, m_spectrumGUI->serialize());
}
s.writeS32(5, m_squelch);
if (m_channelMarker) {
@ -67,6 +73,7 @@ QByteArray FreqTrackerSettings::serialize() const
s.writeFloat(8, m_alphaEMA);
s.writeString(9, m_title);
s.writeBool(10, m_tracking);
s.writeS32(11, m_spanLog2);
s.writeS32(12, (int) m_trackerType);
s.writeU32(13, m_pllPskOrder);
s.writeBool(14, m_rrc);
@ -105,7 +112,13 @@ bool FreqTrackerSettings::deserialize(const QByteArray& data)
m_rfBandwidth = 100 * tmp;
d.readU32(3, &utmp, 0);
m_log2Decim = utmp > 6 ? 6 : utmp;
d.readS32(4, &tmp, 20);
if (m_spectrumGUI)
{
d.readBlob(4, &bytetmp);
m_spectrumGUI->deserialize(bytetmp);
}
d.readS32(5, &tmp, -40);
m_squelch = tmp;
d.readBlob(6, &bytetmp);
@ -119,6 +132,7 @@ bool FreqTrackerSettings::deserialize(const QByteArray& data)
m_alphaEMA = ftmp < 0.01 ? 0.01 : ftmp > 1.0 ? 1.0 : ftmp;
d.readString(9, &m_title, "Frequency Tracker");
d.readBool(10, &m_tracking, false);
d.readS32(11, &m_spanLog2, 0);
d.readS32(12, &tmp, 0);
m_trackerType = tmp < 0 ? TrackerFLL : tmp > 2 ? TrackerPLL : (TrackerType) tmp;
d.readU32(13, &utmp, 2);

View File

@ -41,6 +41,8 @@ struct FreqTrackerSettings
quint32 m_rgbColor;
QString m_title;
Serializable *m_channelMarker;
Serializable *m_spectrumGUI;
int m_spanLog2;
float m_alphaEMA; //!< alpha factor for delta frequency EMA
bool m_tracking;
TrackerType m_trackerType;
@ -58,6 +60,7 @@ struct FreqTrackerSettings
FreqTrackerSettings();
void resetToDefaults();
void setChannelMarker(Serializable *channelMarker) { m_channelMarker = channelMarker; }
void setSpectrumGUI(Serializable *spectrumGUI) { m_spectrumGUI = spectrumGUI; }
QByteArray serialize() const;
bool deserialize(const QByteArray& data);
};

View File

@ -22,6 +22,7 @@
#include "dsp/dspengine.h"
#include "dsp/dspcommands.h"
#include "dsp/fftfilt.h"
#include "dsp/spectrumvis.h"
#include "util/db.h"
#include "util/stepfunctions.h"
#include "util/messagequeue.h"
@ -33,6 +34,9 @@ FreqTrackerSink::FreqTrackerSink() :
m_channelSampleRate(48000),
m_inputFrequencyOffset(0),
m_sinkSampleRate(48000),
m_spectrumSink(nullptr),
m_sampleBufferCount(0),
m_undersampleCount(0),
m_squelchOpen(false),
m_squelchGate(0),
m_magsqSum(0.0f),
@ -52,6 +56,9 @@ FreqTrackerSink::FreqTrackerSink() :
m_timer = &DSPEngine::instance()->getMasterTimer();
#endif
m_magsq = 0.0;
m_sampleBufferSize = m_sinkSampleRate / 20; // 50 ms
m_sampleBuffer.resize(m_sampleBufferSize);
m_sum = Complex{0.0, 0.0};
m_rrcFilter = new fftfilt(m_settings.m_rfBandwidth / m_sinkSampleRate, 2*1024);
m_pll.computeCoefficients(0.002f, 0.5f, 10.0f); // bandwidth, damping factor, loop gain
@ -102,6 +109,18 @@ void FreqTrackerSink::processOneSample(Complex &ci)
{
fftfilt::cmplx *sideband;
int n_out;
int decim = 1<<m_settings.m_spanLog2;
m_sum += ci;
if (m_undersampleCount++ == decim)
{
Real avgr = m_sum.real() / decim;
Real avgi = m_sum.imag() / decim;
m_sampleBuffer[m_sampleBufferCount++] = Sample(avgr, avgi);
m_sum.real(0.0);
m_sum.imag(0.0);
m_undersampleCount = 0;
}
if (m_settings.m_rrc)
{
@ -168,7 +187,15 @@ void FreqTrackerSink::processOneSample(Complex &ci)
m_pll.feed(re, im);
}
}
}
if (m_spectrumSink && (m_sampleBufferCount == m_sampleBufferSize))
{
m_spectrumSink->feed(m_sampleBuffer.begin(), m_sampleBuffer.end(), false);
m_sampleBufferCount = 0;
}
}
Real FreqTrackerSink::getFrequency() const
@ -215,6 +242,11 @@ void FreqTrackerSink::applyChannelSettings(int sinkSampleRate, int channelSample
if (useInterpolator) {
setInterpolator();
}
m_sampleBufferSize = (m_sinkSampleRate/(1<<m_settings.m_spanLog2)) / 20; // 50 ms
m_sampleBuffer.resize(m_sampleBufferSize);
m_sampleBufferCount = 0;
m_undersampleCount = 0;
}
void FreqTrackerSink::applySettings(const FreqTrackerSettings& settings, bool force)
@ -293,6 +325,14 @@ void FreqTrackerSink::applySettings(const FreqTrackerSettings& settings, bool fo
useInterpolator = true;
}
if ((settings.m_spanLog2 != m_settings.m_spanLog2) || force)
{
m_sampleBufferSize = (m_sinkSampleRate/(1<<settings.m_spanLog2)) / 20; // 50 ms
m_sampleBuffer.resize(m_sampleBufferSize);
m_sampleBufferCount = 0;
m_undersampleCount = 0;
}
m_settings = settings;
if (useInterpolator) {

View File

@ -36,6 +36,7 @@
#include "freqtrackersettings.h"
class SpectrumVis;
class fftfilt;
class MessageQueue;
class QTimer;
@ -48,6 +49,7 @@ public:
virtual void feed(const SampleVector::const_iterator& begin, const SampleVector::const_iterator& end);
void setSpectrumSink(SpectrumVis* spectrumSink) { m_spectrumSink = spectrumSink; }
void applySettings(const FreqTrackerSettings& settings, bool force = false);
void applyChannelSettings(int sinkSampleRate, int channelSampleRate, int channelFrequencyOffset, bool force = false);
void setMessageQueueToInput(MessageQueue *messageQueue) { m_messageQueueToInput = messageQueue;}
@ -99,6 +101,13 @@ private:
int m_inputFrequencyOffset;
uint32_t m_sinkSampleRate;
SpectrumVis* m_spectrumSink;
SampleVector m_sampleBuffer;
unsigned int m_sampleBufferCount;
unsigned int m_sampleBufferSize;
Complex m_sum;
int m_undersampleCount;
NCOF m_nco;
PhaseLockComplex m_pll;
FreqLockComplex m_fll;
@ -138,4 +147,4 @@ private slots:
void tick();
};
#endif // INCLUDE_FREQTRACKERSINK_H
#endif // INCLUDE_FREQTRACKERSINK_H

View File

@ -96,6 +96,14 @@ This indicator lights in green when the squelch is open. When the squelch is clo
This is the squelch threshold in dB. The average total power received in the signal bandwidth before demodulation is compared to this value and the squelch input is open above this value. It can be varied continuously in 0.1 dB steps from 0.0 to -100.0 dB using the dial button.
<h4>10: Squelch time gate</h4>
<h3>10: Squelch time gate</h3>
Number of milliseconds following squelch gate opening after which the signal is declared open. 0 means squelch is declared open with no delay and is suitable for burst signals. The value can be varied in steps of 10 ms from 0 to 990 ms.
Number of milliseconds following squelch gate opening after which the signal is declared open. 0 means squelch is declared open with no delay and is suitable for burst signals. The value can be varied in steps of 10 ms from 0 to 990 ms.
<h3>11: Spectrum display frequency span</h3>
The channel signal is decimated by a power of two before being applied to the channel spectrum display. It is a kind of zoom on the center of the spectrum.
<h3>12: Channel spectrum</h3>
This is the spectrum display of the tracker channel. When the tracker is locked to the signal the center of the channel should fall almost in the middle of the signal spectrum (ideally in the middle when the tracker error is zero). Thus the locking can be followed dynamically and it can be more reliable than the lock indicator. A channel marker shows the tracker offset from the channel center frequency (tracker error). Its width is the tracker error tolerance and is &plusmn;1/1000th of the channel width. Controls on the bottom of the panel are identical to the ones of the main spectrum display.

View File

@ -33,6 +33,8 @@
#include "dsp/hbfilterchainconverter.h"
#include "dsp/devicesamplemimo.h"
#include "device/deviceapi.h"
#include "feature/feature.h"
#include "maincore.h"
#include "localsinkbaseband.h"
#include "localsink.h"
@ -302,6 +304,10 @@ void LocalSink::applySettings(const LocalSinkSettings& settings, bool force)
webapiReverseSendSettings(reverseAPIKeys, settings, fullUpdate || force);
}
if (m_featuresSettingsFeedback.size() > 0) {
featuresSendSettings(reverseAPIKeys, settings, force);
}
m_settings = settings;
}
@ -436,10 +442,67 @@ void LocalSink::webapiFormatChannelSettings(SWGSDRangel::SWGChannelSettings& res
void LocalSink::webapiReverseSendSettings(QList<QString>& channelSettingsKeys, const LocalSinkSettings& settings, bool force)
{
SWGSDRangel::SWGChannelSettings *swgChannelSettings = new SWGSDRangel::SWGChannelSettings();
swgChannelSettings->setDirection(0); // single sink (Rx)
webapiFormatChannelSettings(channelSettingsKeys, swgChannelSettings, settings, force);
QString channelSettingsURL = QString("http://%1:%2/sdrangel/deviceset/%3/channel/%4/settings")
.arg(settings.m_reverseAPIAddress)
.arg(settings.m_reverseAPIPort)
.arg(settings.m_reverseAPIDeviceIndex)
.arg(settings.m_reverseAPIChannelIndex);
m_networkRequest.setUrl(QUrl(channelSettingsURL));
m_networkRequest.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
QBuffer *buffer = new QBuffer();
buffer->open((QBuffer::ReadWrite));
buffer->write(swgChannelSettings->asJson().toUtf8());
buffer->seek(0);
// Always use PATCH to avoid passing reverse API settings
QNetworkReply *reply = m_networkManager->sendCustomRequest(m_networkRequest, "PATCH", buffer);
buffer->setParent(reply);
delete swgChannelSettings;
}
void LocalSink::featuresSendSettings(QList<QString>& channelSettingsKeys, const LocalSinkSettings& settings, bool force)
{
QList<Feature*>::iterator it = m_featuresSettingsFeedback.begin();
MainCore *mainCore = MainCore::instance();
for (; it != m_featuresSettingsFeedback.end(); ++it)
{
if (mainCore->existsFeature(*it))
{
SWGSDRangel::SWGChannelSettings *swgChannelSettings = new SWGSDRangel::SWGChannelSettings();
webapiFormatChannelSettings(channelSettingsKeys, swgChannelSettings, settings, force);
Feature::MsgChannelSettings *msg = Feature::MsgChannelSettings::create(
this,
channelSettingsKeys,
swgChannelSettings,
force
);
(*it)->getInputMessageQueue()->push(msg);
}
else
{
m_featuresSettingsFeedback.removeOne(*it);
}
}
}
void LocalSink::webapiFormatChannelSettings(
QList<QString>& channelSettingsKeys,
SWGSDRangel::SWGChannelSettings *swgChannelSettings,
const LocalSinkSettings& settings,
bool force
)
{
swgChannelSettings->setDirection(0); // Single sink (Rx)
swgChannelSettings->setOriginatorChannelIndex(getIndexInDeviceSet());
swgChannelSettings->setOriginatorDeviceSetIndex(getDeviceSetIndex());
swgChannelSettings->setChannelType(new QString("LocalSink"));
swgChannelSettings->setChannelType(new QString(m_channelId));
swgChannelSettings->setLocalSinkSettings(new SWGSDRangel::SWGLocalSinkSettings());
SWGSDRangel::SWGLocalSinkSettings *swgLocalSinkSettings = swgChannelSettings->getLocalSinkSettings();
@ -466,25 +529,6 @@ void LocalSink::webapiReverseSendSettings(QList<QString>& channelSettingsKeys, c
if (channelSettingsKeys.contains("streamIndex") || force) {
swgLocalSinkSettings->setStreamIndex(settings.m_streamIndex);
}
QString channelSettingsURL = QString("http://%1:%2/sdrangel/deviceset/%3/channel/%4/settings")
.arg(settings.m_reverseAPIAddress)
.arg(settings.m_reverseAPIPort)
.arg(settings.m_reverseAPIDeviceIndex)
.arg(settings.m_reverseAPIChannelIndex);
m_networkRequest.setUrl(QUrl(channelSettingsURL));
m_networkRequest.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
QBuffer *buffer = new QBuffer();
buffer->open((QBuffer::ReadWrite));
buffer->write(swgChannelSettings->asJson().toUtf8());
buffer->seek(0);
// Always use PATCH to avoid passing reverse API settings
QNetworkReply *reply = m_networkManager->sendCustomRequest(m_networkRequest, "PATCH", buffer);
buffer->setParent(reply);
delete swgChannelSettings;
}
void LocalSink::networkManagerFinished(QNetworkReply *reply)

View File

@ -154,6 +154,13 @@ private:
DeviceSampleSource *getLocalDevice(uint32_t index);
void webapiReverseSendSettings(QList<QString>& channelSettingsKeys, const LocalSinkSettings& settings, bool force);
void featuresSendSettings(QList<QString>& channelSettingsKeys, const LocalSinkSettings& settings, bool force);
void webapiFormatChannelSettings(
QList<QString>& channelSettingsKeys,
SWGSDRangel::SWGChannelSettings *swgChannelSettings,
const LocalSinkSettings& settings,
bool force
);
private slots:
void networkManagerFinished(QNetworkReply *reply);

View File

@ -36,6 +36,8 @@
#include "dsp/devicesamplemimo.h"
#include "dsp/dspdevicesourceengine.h"
#include "device/deviceapi.h"
#include "feature/feature.h"
#include "maincore.h"
#include "remotesinkbaseband.h"
@ -236,6 +238,10 @@ void RemoteSink::applySettings(const RemoteSinkSettings& settings, bool force)
webapiReverseSendSettings(reverseAPIKeys, settings, fullUpdate || force);
}
if (m_featuresSettingsFeedback.size() > 0) {
featuresSendSettings(reverseAPIKeys, settings, force);
}
m_settings = settings;
if (frequencyOffsetChange) {
@ -415,10 +421,67 @@ void RemoteSink::webapiFormatChannelSettings(SWGSDRangel::SWGChannelSettings& re
void RemoteSink::webapiReverseSendSettings(QList<QString>& channelSettingsKeys, const RemoteSinkSettings& settings, bool force)
{
SWGSDRangel::SWGChannelSettings *swgChannelSettings = new SWGSDRangel::SWGChannelSettings();
swgChannelSettings->setDirection(0); // single sink (Rx)
webapiFormatChannelSettings(channelSettingsKeys, swgChannelSettings, settings, force);
QString channelSettingsURL = QString("http://%1:%2/sdrangel/deviceset/%3/channel/%4/settings")
.arg(settings.m_reverseAPIAddress)
.arg(settings.m_reverseAPIPort)
.arg(settings.m_reverseAPIDeviceIndex)
.arg(settings.m_reverseAPIChannelIndex);
m_networkRequest.setUrl(QUrl(channelSettingsURL));
m_networkRequest.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
QBuffer *buffer = new QBuffer();
buffer->open((QBuffer::ReadWrite));
buffer->write(swgChannelSettings->asJson().toUtf8());
buffer->seek(0);
// Always use PATCH to avoid passing reverse API settings
QNetworkReply *reply = m_networkManager->sendCustomRequest(m_networkRequest, "PATCH", buffer);
buffer->setParent(reply);
delete swgChannelSettings;
}
void RemoteSink::featuresSendSettings(QList<QString>& channelSettingsKeys, const RemoteSinkSettings& settings, bool force)
{
QList<Feature*>::iterator it = m_featuresSettingsFeedback.begin();
MainCore *mainCore = MainCore::instance();
for (; it != m_featuresSettingsFeedback.end(); ++it)
{
if (mainCore->existsFeature(*it))
{
SWGSDRangel::SWGChannelSettings *swgChannelSettings = new SWGSDRangel::SWGChannelSettings();
webapiFormatChannelSettings(channelSettingsKeys, swgChannelSettings, settings, force);
Feature::MsgChannelSettings *msg = Feature::MsgChannelSettings::create(
this,
channelSettingsKeys,
swgChannelSettings,
force
);
(*it)->getInputMessageQueue()->push(msg);
}
else
{
m_featuresSettingsFeedback.removeOne(*it);
}
}
}
void RemoteSink::webapiFormatChannelSettings(
QList<QString>& channelSettingsKeys,
SWGSDRangel::SWGChannelSettings *swgChannelSettings,
const RemoteSinkSettings& settings,
bool force
)
{
swgChannelSettings->setDirection(0); // Single sink (Rx)
swgChannelSettings->setOriginatorChannelIndex(getIndexInDeviceSet());
swgChannelSettings->setOriginatorDeviceSetIndex(getDeviceSetIndex());
swgChannelSettings->setChannelType(new QString("RemoteSink"));
swgChannelSettings->setChannelType(new QString(m_channelId));
swgChannelSettings->setRemoteSinkSettings(new SWGSDRangel::SWGRemoteSinkSettings());
SWGSDRangel::SWGRemoteSinkSettings *swgRemoteSinkSettings = swgChannelSettings->getRemoteSinkSettings();
@ -452,25 +515,6 @@ void RemoteSink::webapiReverseSendSettings(QList<QString>& channelSettingsKeys,
if (channelSettingsKeys.contains("streamIndex") || force) {
swgRemoteSinkSettings->setStreamIndex(settings.m_streamIndex);
}
QString channelSettingsURL = QString("http://%1:%2/sdrangel/deviceset/%3/channel/%4/settings")
.arg(settings.m_reverseAPIAddress)
.arg(settings.m_reverseAPIPort)
.arg(settings.m_reverseAPIDeviceIndex)
.arg(settings.m_reverseAPIChannelIndex);
m_networkRequest.setUrl(QUrl(channelSettingsURL));
m_networkRequest.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
QBuffer *buffer = new QBuffer();
buffer->open((QBuffer::ReadWrite));
buffer->write(swgChannelSettings->asJson().toUtf8());
buffer->seek(0);
// Always use PATCH to avoid passing reverse API settings
QNetworkReply *reply = m_networkManager->sendCustomRequest(m_networkRequest, "PATCH", buffer);
buffer->setParent(reply);
delete swgChannelSettings;
}
void RemoteSink::networkManagerFinished(QNetworkReply *reply)

View File

@ -133,6 +133,13 @@ private:
static void validateFilterChainHash(RemoteSinkSettings& settings);
void calculateFrequencyOffset();
void webapiReverseSendSettings(QList<QString>& channelSettingsKeys, const RemoteSinkSettings& settings, bool force);
void featuresSendSettings(QList<QString>& channelSettingsKeys, const RemoteSinkSettings& settings, bool force);
void webapiFormatChannelSettings(
QList<QString>& channelSettingsKeys,
SWGSDRangel::SWGChannelSettings *swgChannelSettings,
const RemoteSinkSettings& settings,
bool force
);
private slots:
void networkManagerFinished(QNetworkReply *reply);

View File

@ -33,6 +33,8 @@
#include "dsp/dspcommands.h"
#include "dsp/devicesamplemimo.h"
#include "device/deviceapi.h"
#include "feature/feature.h"
#include "maincore.h"
#include "udpsink.h"
@ -236,6 +238,10 @@ void UDPSink::applySettings(const UDPSinkSettings& settings, bool force)
webapiReverseSendSettings(reverseAPIKeys, settings, fullUpdate || force);
}
if (m_featuresSettingsFeedback.size() > 0) {
featuresSendSettings(reverseAPIKeys, settings, force);
}
m_settings = settings;
}
@ -448,10 +454,67 @@ void UDPSink::webapiFormatChannelReport(SWGSDRangel::SWGChannelReport& response)
void UDPSink::webapiReverseSendSettings(QList<QString>& channelSettingsKeys, const UDPSinkSettings& settings, bool force)
{
SWGSDRangel::SWGChannelSettings *swgChannelSettings = new SWGSDRangel::SWGChannelSettings();
swgChannelSettings->setDirection(0); // single sink (Rx)
webapiFormatChannelSettings(channelSettingsKeys, swgChannelSettings, settings, force);
QString channelSettingsURL = QString("http://%1:%2/sdrangel/deviceset/%3/channel/%4/settings")
.arg(settings.m_reverseAPIAddress)
.arg(settings.m_reverseAPIPort)
.arg(settings.m_reverseAPIDeviceIndex)
.arg(settings.m_reverseAPIChannelIndex);
m_networkRequest.setUrl(QUrl(channelSettingsURL));
m_networkRequest.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
QBuffer *buffer = new QBuffer();
buffer->open((QBuffer::ReadWrite));
buffer->write(swgChannelSettings->asJson().toUtf8());
buffer->seek(0);
// Always use PATCH to avoid passing reverse API settings
QNetworkReply *reply = m_networkManager->sendCustomRequest(m_networkRequest, "PATCH", buffer);
buffer->setParent(reply);
delete swgChannelSettings;
}
void UDPSink::featuresSendSettings(QList<QString>& channelSettingsKeys, const UDPSinkSettings& settings, bool force)
{
QList<Feature*>::iterator it = m_featuresSettingsFeedback.begin();
MainCore *mainCore = MainCore::instance();
for (; it != m_featuresSettingsFeedback.end(); ++it)
{
if (mainCore->existsFeature(*it))
{
SWGSDRangel::SWGChannelSettings *swgChannelSettings = new SWGSDRangel::SWGChannelSettings();
webapiFormatChannelSettings(channelSettingsKeys, swgChannelSettings, settings, force);
Feature::MsgChannelSettings *msg = Feature::MsgChannelSettings::create(
this,
channelSettingsKeys,
swgChannelSettings,
force
);
(*it)->getInputMessageQueue()->push(msg);
}
else
{
m_featuresSettingsFeedback.removeOne(*it);
}
}
}
void UDPSink::webapiFormatChannelSettings(
QList<QString>& channelSettingsKeys,
SWGSDRangel::SWGChannelSettings *swgChannelSettings,
const UDPSinkSettings& settings,
bool force
)
{
swgChannelSettings->setDirection(0); // Single sink (Rx)
swgChannelSettings->setOriginatorChannelIndex(getIndexInDeviceSet());
swgChannelSettings->setOriginatorDeviceSetIndex(getDeviceSetIndex());
swgChannelSettings->setChannelType(new QString("UDPSink"));
swgChannelSettings->setChannelType(new QString(m_channelId));
swgChannelSettings->setUdpSinkSettings(new SWGSDRangel::SWGUDPSinkSettings());
SWGSDRangel::SWGUDPSinkSettings *swgUDPSinkSettings = swgChannelSettings->getUdpSinkSettings();
@ -517,25 +580,6 @@ void UDPSink::webapiReverseSendSettings(QList<QString>& channelSettingsKeys, con
if (channelSettingsKeys.contains("streamIndex") || force) {
swgUDPSinkSettings->setStreamIndex(settings.m_streamIndex);
}
QString channelSettingsURL = QString("http://%1:%2/sdrangel/deviceset/%3/channel/%4/settings")
.arg(settings.m_reverseAPIAddress)
.arg(settings.m_reverseAPIPort)
.arg(settings.m_reverseAPIDeviceIndex)
.arg(settings.m_reverseAPIChannelIndex);
m_networkRequest.setUrl(QUrl(channelSettingsURL));
m_networkRequest.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
QBuffer *buffer = new QBuffer();
buffer->open((QBuffer::ReadWrite));
buffer->write(swgChannelSettings->asJson().toUtf8());
buffer->seek(0);
// Always use PATCH to avoid passing reverse API settings
QNetworkReply *reply = m_networkManager->sendCustomRequest(m_networkRequest, "PATCH", buffer);
buffer->setParent(reply);
delete swgChannelSettings;
}
void UDPSink::networkManagerFinished(QNetworkReply *reply)
@ -563,4 +607,4 @@ void UDPSink::enableSpectrum(bool enable)
{
UDPSinkBaseband::MsgEnableSpectrum *msg = UDPSinkBaseband::MsgEnableSpectrum::create(enable);
m_basebandSink->getInputMessageQueue()->push(msg);
}
}

View File

@ -145,6 +145,13 @@ protected:
void webapiFormatChannelReport(SWGSDRangel::SWGChannelReport& response);
void webapiReverseSendSettings(QList<QString>& channelSettingsKeys, const UDPSinkSettings& settings, bool force);
void featuresSendSettings(QList<QString>& channelSettingsKeys, const UDPSinkSettings& settings, bool force);
void webapiFormatChannelSettings(
QList<QString>& channelSettingsKeys,
SWGSDRangel::SWGChannelSettings *swgChannelSettings,
const UDPSinkSettings& settings,
bool force
);
};
#endif // INCLUDE_UDPSINK_H

View File

@ -33,7 +33,9 @@
#include "dsp/devicesamplesink.h"
#include "dsp/hbfilterchainconverter.h"
#include "dsp/filerecord.h"
#include "feature/feature.h"
#include "util/db.h"
#include "maincore.h"
#include "filesourcebaseband.h"
@ -261,6 +263,10 @@ void FileSource::applySettings(const FileSourceSettings& settings, bool force)
webapiReverseSendSettings(reverseAPIKeys, settings, fullUpdate || force);
}
if (m_featuresSettingsFeedback.size() > 0) {
featuresSendSettings(reverseAPIKeys, settings, force);
}
m_settings = settings;
}
@ -498,10 +504,67 @@ void FileSource::webapiFormatChannelReport(SWGSDRangel::SWGChannelReport& respon
void FileSource::webapiReverseSendSettings(QList<QString>& channelSettingsKeys, const FileSourceSettings& settings, bool force)
{
SWGSDRangel::SWGChannelSettings *swgChannelSettings = new SWGSDRangel::SWGChannelSettings();
webapiFormatChannelSettings(channelSettingsKeys, swgChannelSettings, settings, force);
QString channelSettingsURL = QString("http://%1:%2/sdrangel/deviceset/%3/channel/%4/settings")
.arg(settings.m_reverseAPIAddress)
.arg(settings.m_reverseAPIPort)
.arg(settings.m_reverseAPIDeviceIndex)
.arg(settings.m_reverseAPIChannelIndex);
m_networkRequest.setUrl(QUrl(channelSettingsURL));
m_networkRequest.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
QBuffer *buffer = new QBuffer();
buffer->open((QBuffer::ReadWrite));
buffer->write(swgChannelSettings->asJson().toUtf8());
buffer->seek(0);
// Always use PATCH to avoid passing reverse API settings
QNetworkReply *reply = m_networkManager->sendCustomRequest(m_networkRequest, "PATCH", buffer);
buffer->setParent(reply);
delete swgChannelSettings;
}
void FileSource::featuresSendSettings(QList<QString>& channelSettingsKeys, const FileSourceSettings& settings, bool force)
{
QList<Feature*>::iterator it = m_featuresSettingsFeedback.begin();
MainCore *mainCore = MainCore::instance();
for (; it != m_featuresSettingsFeedback.end(); ++it)
{
if (mainCore->existsFeature(*it))
{
SWGSDRangel::SWGChannelSettings *swgChannelSettings = new SWGSDRangel::SWGChannelSettings();
webapiFormatChannelSettings(channelSettingsKeys, swgChannelSettings, settings, force);
Feature::MsgChannelSettings *msg = Feature::MsgChannelSettings::create(
this,
channelSettingsKeys,
swgChannelSettings,
force
);
(*it)->getInputMessageQueue()->push(msg);
}
else
{
m_featuresSettingsFeedback.removeOne(*it);
}
}
}
void FileSource::webapiFormatChannelSettings(
QList<QString>& channelSettingsKeys,
SWGSDRangel::SWGChannelSettings *swgChannelSettings,
const FileSourceSettings& settings,
bool force
)
{
swgChannelSettings->setDirection(1); // single source (Tx)
swgChannelSettings->setOriginatorChannelIndex(getIndexInDeviceSet());
swgChannelSettings->setOriginatorDeviceSetIndex(getDeviceSetIndex());
swgChannelSettings->setChannelType(new QString("FileSource"));
swgChannelSettings->setChannelType(new QString(m_channelId));
swgChannelSettings->setFileSourceSettings(new SWGSDRangel::SWGFileSourceSettings());
SWGSDRangel::SWGFileSourceSettings *swgFileSourceSettings = swgChannelSettings->getFileSourceSettings();
@ -525,25 +588,6 @@ void FileSource::webapiReverseSendSettings(QList<QString>& channelSettingsKeys,
if (channelSettingsKeys.contains("streamIndex") || force) {
swgFileSourceSettings->setStreamIndex(settings.m_streamIndex);
}
QString channelSettingsURL = QString("http://%1:%2/sdrangel/deviceset/%3/channel/%4/settings")
.arg(settings.m_reverseAPIAddress)
.arg(settings.m_reverseAPIPort)
.arg(settings.m_reverseAPIDeviceIndex)
.arg(settings.m_reverseAPIChannelIndex);
m_networkRequest.setUrl(QUrl(channelSettingsURL));
m_networkRequest.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
QBuffer *buffer = new QBuffer();
buffer->open((QBuffer::ReadWrite));
buffer->write(swgChannelSettings->asJson().toUtf8());
buffer->seek(0);
// Always use PATCH to avoid passing reverse API settings
QNetworkReply *reply = m_networkManager->sendCustomRequest(m_networkRequest, "PATCH", buffer);
buffer->setParent(reply);
delete swgChannelSettings;
}
void FileSource::networkManagerFinished(QNetworkReply *reply)
@ -585,4 +629,4 @@ double FileSource::getMagSq() const
uint32_t FileSource::getNumberOfDeviceStreams() const
{
return m_deviceAPI->getNbSinkStreams();
}
}

View File

@ -254,6 +254,13 @@ private:
void calculateFrequencyOffset();
void webapiFormatChannelReport(SWGSDRangel::SWGChannelReport& response);
void webapiReverseSendSettings(QList<QString>& channelSettingsKeys, const FileSourceSettings& settings, bool force);
void featuresSendSettings(QList<QString>& channelSettingsKeys, const FileSourceSettings& settings, bool force);
void webapiFormatChannelSettings(
QList<QString>& channelSettingsKeys,
SWGSDRangel::SWGChannelSettings *swgChannelSettings,
const FileSourceSettings& settings,
bool force
);
private slots:
void networkManagerFinished(QNetworkReply *reply);

View File

@ -31,6 +31,8 @@
#include "dsp/devicesamplesink.h"
#include "dsp/hbfilterchainconverter.h"
#include "device/deviceapi.h"
#include "feature/feature.h"
#include "maincore.h"
#include "localsourcebaseband.h"
@ -305,6 +307,10 @@ void LocalSource::applySettings(const LocalSourceSettings& settings, bool force)
webapiReverseSendSettings(reverseAPIKeys, settings, fullUpdate || force);
}
if (m_featuresSettingsFeedback.size() > 0) {
featuresSendSettings(reverseAPIKeys, settings, force);
}
m_settings = settings;
}
@ -438,10 +444,67 @@ void LocalSource::webapiFormatChannelSettings(SWGSDRangel::SWGChannelSettings& r
void LocalSource::webapiReverseSendSettings(QList<QString>& channelSettingsKeys, const LocalSourceSettings& settings, bool force)
{
SWGSDRangel::SWGChannelSettings *swgChannelSettings = new SWGSDRangel::SWGChannelSettings();
webapiFormatChannelSettings(channelSettingsKeys, swgChannelSettings, settings, force);
QString channelSettingsURL = QString("http://%1:%2/sdrangel/deviceset/%3/channel/%4/settings")
.arg(settings.m_reverseAPIAddress)
.arg(settings.m_reverseAPIPort)
.arg(settings.m_reverseAPIDeviceIndex)
.arg(settings.m_reverseAPIChannelIndex);
m_networkRequest.setUrl(QUrl(channelSettingsURL));
m_networkRequest.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
QBuffer *buffer = new QBuffer();
buffer->open((QBuffer::ReadWrite));
buffer->write(swgChannelSettings->asJson().toUtf8());
buffer->seek(0);
// Always use PATCH to avoid passing reverse API settings
QNetworkReply *reply = m_networkManager->sendCustomRequest(m_networkRequest, "PATCH", buffer);
buffer->setParent(reply);
delete swgChannelSettings;
}
void LocalSource::featuresSendSettings(QList<QString>& channelSettingsKeys, const LocalSourceSettings& settings, bool force)
{
QList<Feature*>::iterator it = m_featuresSettingsFeedback.begin();
MainCore *mainCore = MainCore::instance();
for (; it != m_featuresSettingsFeedback.end(); ++it)
{
if (mainCore->existsFeature(*it))
{
SWGSDRangel::SWGChannelSettings *swgChannelSettings = new SWGSDRangel::SWGChannelSettings();
webapiFormatChannelSettings(channelSettingsKeys, swgChannelSettings, settings, force);
Feature::MsgChannelSettings *msg = Feature::MsgChannelSettings::create(
this,
channelSettingsKeys,
swgChannelSettings,
force
);
(*it)->getInputMessageQueue()->push(msg);
}
else
{
m_featuresSettingsFeedback.removeOne(*it);
}
}
}
void LocalSource::webapiFormatChannelSettings(
QList<QString>& channelSettingsKeys,
SWGSDRangel::SWGChannelSettings *swgChannelSettings,
const LocalSourceSettings& settings,
bool force
)
{
swgChannelSettings->setDirection(1); // single source (Tx)
swgChannelSettings->setOriginatorChannelIndex(getIndexInDeviceSet());
swgChannelSettings->setOriginatorDeviceSetIndex(getDeviceSetIndex());
swgChannelSettings->setChannelType(new QString("LocalSource"));
swgChannelSettings->setChannelType(new QString(m_channelId));
swgChannelSettings->setLocalSourceSettings(new SWGSDRangel::SWGLocalSourceSettings());
SWGSDRangel::SWGLocalSourceSettings *swgLocalSourceSettings = swgChannelSettings->getLocalSourceSettings();
@ -468,25 +531,6 @@ void LocalSource::webapiReverseSendSettings(QList<QString>& channelSettingsKeys,
if (channelSettingsKeys.contains("streamIndex") || force) {
swgLocalSourceSettings->setRgbColor(settings.m_streamIndex);
}
QString channelSettingsURL = QString("http://%1:%2/sdrangel/deviceset/%3/channel/%4/settings")
.arg(settings.m_reverseAPIAddress)
.arg(settings.m_reverseAPIPort)
.arg(settings.m_reverseAPIDeviceIndex)
.arg(settings.m_reverseAPIChannelIndex);
m_networkRequest.setUrl(QUrl(channelSettingsURL));
m_networkRequest.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
QBuffer *buffer = new QBuffer();
buffer->open((QBuffer::ReadWrite));
buffer->write(swgChannelSettings->asJson().toUtf8());
buffer->seek(0);
// Always use PATCH to avoid passing reverse API settings
QNetworkReply *reply = m_networkManager->sendCustomRequest(m_networkRequest, "PATCH", buffer);
buffer->setParent(reply);
delete swgChannelSettings;
}
void LocalSource::networkManagerFinished(QNetworkReply *reply)

View File

@ -152,6 +152,13 @@ private:
DeviceSampleSink *getLocalDevice(uint32_t index);
void webapiReverseSendSettings(QList<QString>& channelSettingsKeys, const LocalSourceSettings& settings, bool force);
void featuresSendSettings(QList<QString>& channelSettingsKeys, const LocalSourceSettings& settings, bool force);
void webapiFormatChannelSettings(
QList<QString>& channelSettingsKeys,
SWGSDRangel::SWGChannelSettings *swgChannelSettings,
const LocalSourceSettings& settings,
bool force
);
private slots:
void networkManagerFinished(QNetworkReply *reply);

View File

@ -38,8 +38,10 @@
#include "dsp/dspengine.h"
#include "dsp/dspcommands.h"
#include "device/deviceapi.h"
#include "feature/feature.h"
#include "util/db.h"
#include "util/crc.h"
#include "maincore.h"
#include "ieee_802_15_4_modbaseband.h"
#include "ieee_802_15_4_mod.h"
@ -217,6 +219,10 @@ void IEEE_802_15_4_Mod::applySettings(const IEEE_802_15_4_ModSettings& settings,
webapiReverseSendSettings(reverseAPIKeys, settings, fullUpdate || force);
}
if (m_featuresSettingsFeedback.size() > 0) {
featuresSendSettings(reverseAPIKeys, settings, force);
}
m_settings = settings;
}
@ -423,10 +429,67 @@ void IEEE_802_15_4_Mod::webapiFormatChannelReport(SWGSDRangel::SWGChannelReport&
void IEEE_802_15_4_Mod::webapiReverseSendSettings(QList<QString>& channelSettingsKeys, const IEEE_802_15_4_ModSettings& settings, bool force)
{
SWGSDRangel::SWGChannelSettings *swgChannelSettings = new SWGSDRangel::SWGChannelSettings();
webapiFormatChannelSettings(channelSettingsKeys, swgChannelSettings, settings, force);
QString channelSettingsURL = QString("http://%1:%2/sdrangel/deviceset/%3/channel/%4/settings")
.arg(settings.m_reverseAPIAddress)
.arg(settings.m_reverseAPIPort)
.arg(settings.m_reverseAPIDeviceIndex)
.arg(settings.m_reverseAPIChannelIndex);
m_networkRequest.setUrl(QUrl(channelSettingsURL));
m_networkRequest.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
QBuffer *buffer = new QBuffer();
buffer->open((QBuffer::ReadWrite));
buffer->write(swgChannelSettings->asJson().toUtf8());
buffer->seek(0);
// Always use PATCH to avoid passing reverse API settings
QNetworkReply *reply = m_networkManager->sendCustomRequest(m_networkRequest, "PATCH", buffer);
buffer->setParent(reply);
delete swgChannelSettings;
}
void IEEE_802_15_4_Mod::featuresSendSettings(QList<QString>& channelSettingsKeys, const IEEE_802_15_4_ModSettings& settings, bool force)
{
QList<Feature*>::iterator it = m_featuresSettingsFeedback.begin();
MainCore *mainCore = MainCore::instance();
for (; it != m_featuresSettingsFeedback.end(); ++it)
{
if (mainCore->existsFeature(*it))
{
SWGSDRangel::SWGChannelSettings *swgChannelSettings = new SWGSDRangel::SWGChannelSettings();
webapiFormatChannelSettings(channelSettingsKeys, swgChannelSettings, settings, force);
Feature::MsgChannelSettings *msg = Feature::MsgChannelSettings::create(
this,
channelSettingsKeys,
swgChannelSettings,
force
);
(*it)->getInputMessageQueue()->push(msg);
}
else
{
m_featuresSettingsFeedback.removeOne(*it);
}
}
}
void IEEE_802_15_4_Mod::webapiFormatChannelSettings(
QList<QString>& channelSettingsKeys,
SWGSDRangel::SWGChannelSettings *swgChannelSettings,
const IEEE_802_15_4_ModSettings& settings,
bool force
)
{
swgChannelSettings->setDirection(1); // single source (Tx)
swgChannelSettings->setOriginatorChannelIndex(getIndexInDeviceSet());
swgChannelSettings->setOriginatorDeviceSetIndex(getDeviceSetIndex());
swgChannelSettings->setChannelType(new QString("IEEE_802_15_4_Mod"));
swgChannelSettings->setChannelType(new QString(m_channelId));
swgChannelSettings->setIeee802154ModSettings(new SWGSDRangel::SWGIEEE_802_15_4_ModSettings());
SWGSDRangel::SWGIEEE_802_15_4_ModSettings *swgIEEE_802_15_4_ModSettings = swgChannelSettings->getIeee802154ModSettings();
@ -462,25 +525,6 @@ void IEEE_802_15_4_Mod::webapiReverseSendSettings(QList<QString>& channelSetting
if (channelSettingsKeys.contains("streamIndex") || force) {
swgIEEE_802_15_4_ModSettings->setStreamIndex(settings.m_streamIndex);
}
QString channelSettingsURL = QString("http://%1:%2/sdrangel/deviceset/%3/channel/%4/settings")
.arg(settings.m_reverseAPIAddress)
.arg(settings.m_reverseAPIPort)
.arg(settings.m_reverseAPIDeviceIndex)
.arg(settings.m_reverseAPIChannelIndex);
m_networkRequest.setUrl(QUrl(channelSettingsURL));
m_networkRequest.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
QBuffer *buffer = new QBuffer();
buffer->open((QBuffer::ReadWrite));
buffer->write(swgChannelSettings->asJson().toUtf8());
buffer->seek(0);
// Always use PATCH to avoid passing reverse API settings
QNetworkReply *reply = m_networkManager->sendCustomRequest(m_networkRequest, "PATCH", buffer);
buffer->setParent(reply);
delete swgChannelSettings;
}
void IEEE_802_15_4_Mod::networkManagerFinished(QNetworkReply *reply)

View File

@ -168,6 +168,13 @@ private:
void applySettings(const IEEE_802_15_4_ModSettings& settings, bool force = false);
void webapiFormatChannelReport(SWGSDRangel::SWGChannelReport& response);
void webapiReverseSendSettings(QList<QString>& channelSettingsKeys, const IEEE_802_15_4_ModSettings& settings, bool force);
void featuresSendSettings(QList<QString>& channelSettingsKeys, const IEEE_802_15_4_ModSettings& settings, bool force);
void webapiFormatChannelSettings(
QList<QString>& channelSettingsKeys,
SWGSDRangel::SWGChannelSettings *swgChannelSettings,
const IEEE_802_15_4_ModSettings& settings,
bool force
);
private slots:
void networkManagerFinished(QNetworkReply *reply);

View File

@ -35,7 +35,9 @@
#include "dsp/devicesamplemimo.h"
#include "dsp/cwkeyer.h"
#include "device/deviceapi.h"
#include "feature/feature.h"
#include "util/db.h"
#include "maincore.h"
#include "ammodbaseband.h"
#include "ammod.h"
@ -300,6 +302,10 @@ void AMMod::applySettings(const AMModSettings& settings, bool force)
webapiReverseSendSettings(reverseAPIKeys, settings, fullUpdate || force);
}
if (m_featuresSettingsFeedback.size() > 0) {
featuresSendSettings(reverseAPIKeys, settings, force);
}
m_settings = settings;
}
@ -502,59 +508,7 @@ void AMMod::webapiFormatChannelReport(SWGSDRangel::SWGChannelReport& response)
void AMMod::webapiReverseSendSettings(QList<QString>& channelSettingsKeys, const AMModSettings& settings, bool force)
{
SWGSDRangel::SWGChannelSettings *swgChannelSettings = new SWGSDRangel::SWGChannelSettings();
swgChannelSettings->setDirection(1); // single source (Tx)
swgChannelSettings->setOriginatorChannelIndex(getIndexInDeviceSet());
swgChannelSettings->setOriginatorDeviceSetIndex(getDeviceSetIndex());
swgChannelSettings->setChannelType(new QString("AMMod"));
swgChannelSettings->setAmModSettings(new SWGSDRangel::SWGAMModSettings());
SWGSDRangel::SWGAMModSettings *swgAMModSettings = swgChannelSettings->getAmModSettings();
// transfer data that has been modified. When force is on transfer all data except reverse API data
if (channelSettingsKeys.contains("channelMute") || force) {
swgAMModSettings->setChannelMute(settings.m_channelMute ? 1 : 0);
}
if (channelSettingsKeys.contains("inputFrequencyOffset") || force) {
swgAMModSettings->setInputFrequencyOffset(settings.m_inputFrequencyOffset);
}
if (channelSettingsKeys.contains("modAFInput") || force) {
swgAMModSettings->setModAfInput((int) settings.m_modAFInput);
}
if (channelSettingsKeys.contains("audioDeviceName") || force) {
swgAMModSettings->setAudioDeviceName(new QString(settings.m_audioDeviceName));
}
if (channelSettingsKeys.contains("playLoop") || force) {
swgAMModSettings->setPlayLoop(settings.m_playLoop ? 1 : 0);
}
if (channelSettingsKeys.contains("rfBandwidth") || force) {
swgAMModSettings->setRfBandwidth(settings.m_rfBandwidth);
}
if (channelSettingsKeys.contains("rgbColor") || force) {
swgAMModSettings->setRgbColor(settings.m_rgbColor);
}
if (channelSettingsKeys.contains("title") || force) {
swgAMModSettings->setTitle(new QString(settings.m_title));
}
if (channelSettingsKeys.contains("toneFrequency") || force) {
swgAMModSettings->setToneFrequency(settings.m_toneFrequency);
}
if (channelSettingsKeys.contains("volumeFactor") || force) {
swgAMModSettings->setVolumeFactor(settings.m_volumeFactor);
}
if (channelSettingsKeys.contains("modFactor") || force) {
swgAMModSettings->setModFactor(settings.m_modFactor);
}
if (channelSettingsKeys.contains("streamIndex") || force) {
swgAMModSettings->setStreamIndex(settings.m_streamIndex);
}
if (force)
{
const CWKeyerSettings& cwKeyerSettings = m_basebandSource->getCWKeyer().getSettings();
swgAMModSettings->setCwKeyer(new SWGSDRangel::SWGCWKeyerSettings());
SWGSDRangel::SWGCWKeyerSettings *apiCwKeyerSettings = swgAMModSettings->getCwKeyer();
m_basebandSource->getCWKeyer().webapiFormatChannelSettings(apiCwKeyerSettings, cwKeyerSettings);
}
webapiFormatChannelSettings(channelSettingsKeys, swgChannelSettings, settings, force);
QString channelSettingsURL = QString("http://%1:%2/sdrangel/deviceset/%3/channel/%4/settings")
.arg(settings.m_reverseAPIAddress)
@ -608,6 +562,96 @@ void AMMod::webapiReverseSendCWSettings(const CWKeyerSettings& cwKeyerSettings)
delete swgChannelSettings;
}
void AMMod::featuresSendSettings(QList<QString>& channelSettingsKeys, const AMModSettings& settings, bool force)
{
QList<Feature*>::iterator it = m_featuresSettingsFeedback.begin();
MainCore *mainCore = MainCore::instance();
for (; it != m_featuresSettingsFeedback.end(); ++it)
{
if (mainCore->existsFeature(*it))
{
SWGSDRangel::SWGChannelSettings *swgChannelSettings = new SWGSDRangel::SWGChannelSettings();
webapiFormatChannelSettings(channelSettingsKeys, swgChannelSettings, settings, force);
Feature::MsgChannelSettings *msg = Feature::MsgChannelSettings::create(
this,
channelSettingsKeys,
swgChannelSettings,
force
);
(*it)->getInputMessageQueue()->push(msg);
}
else
{
m_featuresSettingsFeedback.removeOne(*it);
}
}
}
void AMMod::webapiFormatChannelSettings(
QList<QString>& channelSettingsKeys,
SWGSDRangel::SWGChannelSettings *swgChannelSettings,
const AMModSettings& settings,
bool force
)
{
swgChannelSettings->setDirection(1); // single source (Tx)
swgChannelSettings->setOriginatorChannelIndex(getIndexInDeviceSet());
swgChannelSettings->setOriginatorDeviceSetIndex(getDeviceSetIndex());
swgChannelSettings->setChannelType(new QString(m_channelId));
swgChannelSettings->setAmModSettings(new SWGSDRangel::SWGAMModSettings());
SWGSDRangel::SWGAMModSettings *swgAMModSettings = swgChannelSettings->getAmModSettings();
// transfer data that has been modified. When force is on transfer all data except reverse API data
if (channelSettingsKeys.contains("channelMute") || force) {
swgAMModSettings->setChannelMute(settings.m_channelMute ? 1 : 0);
}
if (channelSettingsKeys.contains("inputFrequencyOffset") || force) {
swgAMModSettings->setInputFrequencyOffset(settings.m_inputFrequencyOffset);
}
if (channelSettingsKeys.contains("modAFInput") || force) {
swgAMModSettings->setModAfInput((int) settings.m_modAFInput);
}
if (channelSettingsKeys.contains("audioDeviceName") || force) {
swgAMModSettings->setAudioDeviceName(new QString(settings.m_audioDeviceName));
}
if (channelSettingsKeys.contains("playLoop") || force) {
swgAMModSettings->setPlayLoop(settings.m_playLoop ? 1 : 0);
}
if (channelSettingsKeys.contains("rfBandwidth") || force) {
swgAMModSettings->setRfBandwidth(settings.m_rfBandwidth);
}
if (channelSettingsKeys.contains("rgbColor") || force) {
swgAMModSettings->setRgbColor(settings.m_rgbColor);
}
if (channelSettingsKeys.contains("title") || force) {
swgAMModSettings->setTitle(new QString(settings.m_title));
}
if (channelSettingsKeys.contains("toneFrequency") || force) {
swgAMModSettings->setToneFrequency(settings.m_toneFrequency);
}
if (channelSettingsKeys.contains("volumeFactor") || force) {
swgAMModSettings->setVolumeFactor(settings.m_volumeFactor);
}
if (channelSettingsKeys.contains("modFactor") || force) {
swgAMModSettings->setModFactor(settings.m_modFactor);
}
if (channelSettingsKeys.contains("streamIndex") || force) {
swgAMModSettings->setStreamIndex(settings.m_streamIndex);
}
if (force)
{
const CWKeyerSettings& cwKeyerSettings = m_basebandSource->getCWKeyer().getSettings();
swgAMModSettings->setCwKeyer(new SWGSDRangel::SWGCWKeyerSettings());
SWGSDRangel::SWGCWKeyerSettings *apiCwKeyerSettings = swgAMModSettings->getCwKeyer();
m_basebandSource->getCWKeyer().webapiFormatChannelSettings(apiCwKeyerSettings, cwKeyerSettings);
}
}
void AMMod::networkManagerFinished(QNetworkReply *reply)
{
QNetworkReply::NetworkError replyError = reply->error();

View File

@ -261,6 +261,13 @@ private:
void webapiFormatChannelReport(SWGSDRangel::SWGChannelReport& response);
void webapiReverseSendSettings(QList<QString>& channelSettingsKeys, const AMModSettings& settings, bool force);
void webapiReverseSendCWSettings(const CWKeyerSettings& settings);
void featuresSendSettings(QList<QString>& channelSettingsKeys, const AMModSettings& settings, bool force);
void webapiFormatChannelSettings(
QList<QString>& channelSettingsKeys,
SWGSDRangel::SWGChannelSettings *swgChannelSettings,
const AMModSettings& settings,
bool force
);
private slots:
void networkManagerFinished(QNetworkReply *reply);

View File

@ -34,7 +34,9 @@
#include "dsp/dspcommands.h"
#include "dsp/devicesamplemimo.h"
#include "device/deviceapi.h"
#include "feature/feature.h"
#include "util/db.h"
#include "maincore.h"
#include "atvmodbaseband.h"
#include "atvmod.h"
@ -320,6 +322,10 @@ void ATVMod::applySettings(const ATVModSettings& settings, bool force)
webapiReverseSendSettings(reverseAPIKeys, settings, fullUpdate || force);
}
if (m_featuresSettingsFeedback.size() > 0) {
featuresSendSettings(reverseAPIKeys, settings, force);
}
m_settings = settings;
}
@ -583,10 +589,67 @@ void ATVMod::webapiFormatChannelReport(SWGSDRangel::SWGChannelReport& response)
void ATVMod::webapiReverseSendSettings(QList<QString>& channelSettingsKeys, const ATVModSettings& settings, bool force)
{
SWGSDRangel::SWGChannelSettings *swgChannelSettings = new SWGSDRangel::SWGChannelSettings();
webapiFormatChannelSettings(channelSettingsKeys, swgChannelSettings, settings, force);
QString channelSettingsURL = QString("http://%1:%2/sdrangel/deviceset/%3/channel/%4/settings")
.arg(settings.m_reverseAPIAddress)
.arg(settings.m_reverseAPIPort)
.arg(settings.m_reverseAPIDeviceIndex)
.arg(settings.m_reverseAPIChannelIndex);
m_networkRequest.setUrl(QUrl(channelSettingsURL));
m_networkRequest.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
QBuffer *buffer = new QBuffer();
buffer->open((QBuffer::ReadWrite));
buffer->write(swgChannelSettings->asJson().toUtf8());
buffer->seek(0);
// Always use PATCH to avoid passing reverse API settings
QNetworkReply *reply = m_networkManager->sendCustomRequest(m_networkRequest, "PATCH", buffer);
buffer->setParent(reply);
delete swgChannelSettings;
}
void ATVMod::featuresSendSettings(QList<QString>& channelSettingsKeys, const ATVModSettings& settings, bool force)
{
QList<Feature*>::iterator it = m_featuresSettingsFeedback.begin();
MainCore *mainCore = MainCore::instance();
for (; it != m_featuresSettingsFeedback.end(); ++it)
{
if (mainCore->existsFeature(*it))
{
SWGSDRangel::SWGChannelSettings *swgChannelSettings = new SWGSDRangel::SWGChannelSettings();
webapiFormatChannelSettings(channelSettingsKeys, swgChannelSettings, settings, force);
Feature::MsgChannelSettings *msg = Feature::MsgChannelSettings::create(
this,
channelSettingsKeys,
swgChannelSettings,
force
);
(*it)->getInputMessageQueue()->push(msg);
}
else
{
m_featuresSettingsFeedback.removeOne(*it);
}
}
}
void ATVMod::webapiFormatChannelSettings(
QList<QString>& channelSettingsKeys,
SWGSDRangel::SWGChannelSettings *swgChannelSettings,
const ATVModSettings& settings,
bool force
)
{
swgChannelSettings->setDirection(1); // single source (Tx)
swgChannelSettings->setOriginatorChannelIndex(getIndexInDeviceSet());
swgChannelSettings->setOriginatorDeviceSetIndex(getDeviceSetIndex());
swgChannelSettings->setChannelType(new QString("ATVMod"));
swgChannelSettings->setChannelType(new QString(m_channelId));
swgChannelSettings->setAtvModSettings(new SWGSDRangel::SWGATVModSettings());
SWGSDRangel::SWGATVModSettings *swgATVModSettings = swgChannelSettings->getAtvModSettings();
@ -658,25 +721,6 @@ void ATVMod::webapiReverseSendSettings(QList<QString>& channelSettingsKeys, cons
if (channelSettingsKeys.contains("streamIndex") || force) {
swgATVModSettings->setStreamIndex(settings.m_streamIndex);
}
QString channelSettingsURL = QString("http://%1:%2/sdrangel/deviceset/%3/channel/%4/settings")
.arg(settings.m_reverseAPIAddress)
.arg(settings.m_reverseAPIPort)
.arg(settings.m_reverseAPIDeviceIndex)
.arg(settings.m_reverseAPIChannelIndex);
m_networkRequest.setUrl(QUrl(channelSettingsURL));
m_networkRequest.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
QBuffer *buffer = new QBuffer();
buffer->open((QBuffer::ReadWrite));
buffer->write(swgChannelSettings->asJson().toUtf8());
buffer->seek(0);
// Always use PATCH to avoid passing reverse API settings
QNetworkReply *reply = m_networkManager->sendCustomRequest(m_networkRequest, "PATCH", buffer);
buffer->setParent(reply);
delete swgChannelSettings;
}
void ATVMod::networkManagerFinished(QNetworkReply *reply)
@ -723,4 +767,4 @@ void ATVMod::getCameraNumbers(std::vector<int>& numbers)
void ATVMod::propagateMessageQueueToGUI()
{
m_basebandSource->setMessageQueueToGUI(getMessageQueueToGUI());
}
}

View File

@ -317,6 +317,13 @@ private:
void applySettings(const ATVModSettings& settings, bool force = false);
void webapiFormatChannelReport(SWGSDRangel::SWGChannelReport& response);
void webapiReverseSendSettings(QList<QString>& channelSettingsKeys, const ATVModSettings& settings, bool force);
void featuresSendSettings(QList<QString>& channelSettingsKeys, const ATVModSettings& settings, bool force);
void webapiFormatChannelSettings(
QList<QString>& channelSettingsKeys,
SWGSDRangel::SWGChannelSettings *swgChannelSettings,
const ATVModSettings& settings,
bool force
);
private slots:
void networkManagerFinished(QNetworkReply *reply);

View File

@ -34,7 +34,9 @@
#include "dsp/dspengine.h"
#include "dsp/dspcommands.h"
#include "device/deviceapi.h"
#include "feature/feature.h"
#include "util/db.h"
#include "maincore.h"
#include "freedvmodbaseband.h"
#include "freedvmod.h"
@ -288,6 +290,10 @@ void FreeDVMod::applySettings(const FreeDVModSettings& settings, bool force)
webapiReverseSendSettings(reverseAPIKeys, settings, fullUpdate || force);
}
if (m_featuresSettingsFeedback.size() > 0) {
featuresSendSettings(reverseAPIKeys, settings, force);
}
m_settings = settings;
}
@ -494,10 +500,99 @@ void FreeDVMod::webapiFormatChannelReport(SWGSDRangel::SWGChannelReport& respons
void FreeDVMod::webapiReverseSendSettings(QList<QString>& channelSettingsKeys, const FreeDVModSettings& settings, bool force)
{
SWGSDRangel::SWGChannelSettings *swgChannelSettings = new SWGSDRangel::SWGChannelSettings();
webapiFormatChannelSettings(channelSettingsKeys, swgChannelSettings, settings, force);
QString channelSettingsURL = QString("http://%1:%2/sdrangel/deviceset/%3/channel/%4/settings")
.arg(settings.m_reverseAPIAddress)
.arg(settings.m_reverseAPIPort)
.arg(settings.m_reverseAPIDeviceIndex)
.arg(settings.m_reverseAPIChannelIndex);
m_networkRequest.setUrl(QUrl(channelSettingsURL));
m_networkRequest.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
QBuffer *buffer = new QBuffer();
buffer->open((QBuffer::ReadWrite));
buffer->write(swgChannelSettings->asJson().toUtf8());
buffer->seek(0);
// Always use PATCH to avoid passing reverse API settings
QNetworkReply *reply = m_networkManager->sendCustomRequest(m_networkRequest, "PATCH", buffer);
buffer->setParent(reply);
delete swgChannelSettings;
}
void FreeDVMod::webapiReverseSendCWSettings(const CWKeyerSettings& cwKeyerSettings)
{
SWGSDRangel::SWGChannelSettings *swgChannelSettings = new SWGSDRangel::SWGChannelSettings();
swgChannelSettings->setDirection(1); // single source (Tx)
swgChannelSettings->setChannelType(new QString("FreeDVMod"));
swgChannelSettings->setFreeDvModSettings(new SWGSDRangel::SWGFreeDVModSettings());
SWGSDRangel::SWGFreeDVModSettings *swgFreeDVModSettings = swgChannelSettings->getFreeDvModSettings();
swgFreeDVModSettings->setCwKeyer(new SWGSDRangel::SWGCWKeyerSettings());
SWGSDRangel::SWGCWKeyerSettings *apiCwKeyerSettings = swgFreeDVModSettings->getCwKeyer();
m_basebandSource->getCWKeyer().webapiFormatChannelSettings(apiCwKeyerSettings, cwKeyerSettings);
QString channelSettingsURL = QString("http://%1:%2/sdrangel/deviceset/%3/channel/%4/settings")
.arg(m_settings.m_reverseAPIAddress)
.arg(m_settings.m_reverseAPIPort)
.arg(m_settings.m_reverseAPIDeviceIndex)
.arg(m_settings.m_reverseAPIChannelIndex);
m_networkRequest.setUrl(QUrl(channelSettingsURL));
m_networkRequest.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
QBuffer *buffer = new QBuffer();
buffer->open((QBuffer::ReadWrite));
buffer->write(swgChannelSettings->asJson().toUtf8());
buffer->seek(0);
// Always use PATCH to avoid passing reverse API settings
QNetworkReply *reply = m_networkManager->sendCustomRequest(m_networkRequest, "PATCH", buffer);
buffer->setParent(reply);
delete swgChannelSettings;
}
void FreeDVMod::featuresSendSettings(QList<QString>& channelSettingsKeys, const FreeDVModSettings& settings, bool force)
{
QList<Feature*>::iterator it = m_featuresSettingsFeedback.begin();
MainCore *mainCore = MainCore::instance();
for (; it != m_featuresSettingsFeedback.end(); ++it)
{
if (mainCore->existsFeature(*it))
{
SWGSDRangel::SWGChannelSettings *swgChannelSettings = new SWGSDRangel::SWGChannelSettings();
webapiFormatChannelSettings(channelSettingsKeys, swgChannelSettings, settings, force);
Feature::MsgChannelSettings *msg = Feature::MsgChannelSettings::create(
this,
channelSettingsKeys,
swgChannelSettings,
force
);
(*it)->getInputMessageQueue()->push(msg);
}
else
{
m_featuresSettingsFeedback.removeOne(*it);
}
}
}
void FreeDVMod::webapiFormatChannelSettings(
QList<QString>& channelSettingsKeys,
SWGSDRangel::SWGChannelSettings *swgChannelSettings,
const FreeDVModSettings& settings,
bool force
)
{
swgChannelSettings->setDirection(1); // single source (Tx)
swgChannelSettings->setOriginatorChannelIndex(getIndexInDeviceSet());
swgChannelSettings->setOriginatorDeviceSetIndex(getDeviceSetIndex());
swgChannelSettings->setChannelType(new QString("FreeDVMod"));
swgChannelSettings->setChannelType(new QString(m_channelId));
swgChannelSettings->setFreeDvModSettings(new SWGSDRangel::SWGFreeDVModSettings());
SWGSDRangel::SWGFreeDVModSettings *swgFreeDVModSettings = swgChannelSettings->getFreeDvModSettings();
@ -550,57 +645,6 @@ void FreeDVMod::webapiReverseSendSettings(QList<QString>& channelSettingsKeys, c
SWGSDRangel::SWGCWKeyerSettings *apiCwKeyerSettings = swgFreeDVModSettings->getCwKeyer();
m_basebandSource->getCWKeyer().webapiFormatChannelSettings(apiCwKeyerSettings, cwKeyerSettings);
}
QString channelSettingsURL = QString("http://%1:%2/sdrangel/deviceset/%3/channel/%4/settings")
.arg(settings.m_reverseAPIAddress)
.arg(settings.m_reverseAPIPort)
.arg(settings.m_reverseAPIDeviceIndex)
.arg(settings.m_reverseAPIChannelIndex);
m_networkRequest.setUrl(QUrl(channelSettingsURL));
m_networkRequest.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
QBuffer *buffer = new QBuffer();
buffer->open((QBuffer::ReadWrite));
buffer->write(swgChannelSettings->asJson().toUtf8());
buffer->seek(0);
// Always use PATCH to avoid passing reverse API settings
QNetworkReply *reply = m_networkManager->sendCustomRequest(m_networkRequest, "PATCH", buffer);
buffer->setParent(reply);
delete swgChannelSettings;
}
void FreeDVMod::webapiReverseSendCWSettings(const CWKeyerSettings& cwKeyerSettings)
{
SWGSDRangel::SWGChannelSettings *swgChannelSettings = new SWGSDRangel::SWGChannelSettings();
swgChannelSettings->setDirection(1); // single source (Tx)
swgChannelSettings->setChannelType(new QString("FreeDVMod"));
swgChannelSettings->setFreeDvModSettings(new SWGSDRangel::SWGFreeDVModSettings());
SWGSDRangel::SWGFreeDVModSettings *swgFreeDVModSettings = swgChannelSettings->getFreeDvModSettings();
swgFreeDVModSettings->setCwKeyer(new SWGSDRangel::SWGCWKeyerSettings());
SWGSDRangel::SWGCWKeyerSettings *apiCwKeyerSettings = swgFreeDVModSettings->getCwKeyer();
m_basebandSource->getCWKeyer().webapiFormatChannelSettings(apiCwKeyerSettings, cwKeyerSettings);
QString channelSettingsURL = QString("http://%1:%2/sdrangel/deviceset/%3/channel/%4/settings")
.arg(m_settings.m_reverseAPIAddress)
.arg(m_settings.m_reverseAPIPort)
.arg(m_settings.m_reverseAPIDeviceIndex)
.arg(m_settings.m_reverseAPIChannelIndex);
m_networkRequest.setUrl(QUrl(channelSettingsURL));
m_networkRequest.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
QBuffer *buffer = new QBuffer();
buffer->open((QBuffer::ReadWrite));
buffer->write(swgChannelSettings->asJson().toUtf8());
buffer->seek(0);
// Always use PATCH to avoid passing reverse API settings
QNetworkReply *reply = m_networkManager->sendCustomRequest(m_networkRequest, "PATCH", buffer);
buffer->setParent(reply);
delete swgChannelSettings;
}
void FreeDVMod::networkManagerFinished(QNetworkReply *reply)
@ -662,4 +706,4 @@ void FreeDVMod::setLevelMeter(QObject *levelMeter)
uint32_t FreeDVMod::getNumberOfDeviceStreams() const
{
return m_deviceAPI->getNbSinkStreams();
}
}

View File

@ -269,6 +269,13 @@ private:
void webapiFormatChannelReport(SWGSDRangel::SWGChannelReport& response);
void webapiReverseSendSettings(QList<QString>& channelSettingsKeys, const FreeDVModSettings& settings, bool force);
void webapiReverseSendCWSettings(const CWKeyerSettings& settings);
void featuresSendSettings(QList<QString>& channelSettingsKeys, const FreeDVModSettings& settings, bool force);
void webapiFormatChannelSettings(
QList<QString>& channelSettingsKeys,
SWGSDRangel::SWGChannelSettings *swgChannelSettings,
const FreeDVModSettings& settings,
bool force
);
private slots:
void networkManagerFinished(QNetworkReply *reply);

View File

@ -36,7 +36,9 @@
#include "dsp/dspcommands.h"
#include "dsp/cwkeyer.h"
#include "device/deviceapi.h"
#include "feature/feature.h"
#include "util/db.h"
#include "maincore.h"
#include "nfmmodbaseband.h"
#include "nfmmod.h"
@ -346,6 +348,10 @@ void NFMMod::applySettings(const NFMModSettings& settings, bool force)
webapiReverseSendSettings(reverseAPIKeys, settings, fullUpdate || force);
}
if (m_featuresSettingsFeedback.size() > 0) {
featuresSendSettings(reverseAPIKeys, settings, force);
}
m_settings = settings;
}
@ -556,10 +562,99 @@ void NFMMod::webapiFormatChannelReport(SWGSDRangel::SWGChannelReport& response)
void NFMMod::webapiReverseSendSettings(QList<QString>& channelSettingsKeys, const NFMModSettings& settings, bool force)
{
SWGSDRangel::SWGChannelSettings *swgChannelSettings = new SWGSDRangel::SWGChannelSettings();
webapiFormatChannelSettings(channelSettingsKeys, swgChannelSettings, settings, force);
QString channelSettingsURL = QString("http://%1:%2/sdrangel/deviceset/%3/channel/%4/settings")
.arg(settings.m_reverseAPIAddress)
.arg(settings.m_reverseAPIPort)
.arg(settings.m_reverseAPIDeviceIndex)
.arg(settings.m_reverseAPIChannelIndex);
m_networkRequest.setUrl(QUrl(channelSettingsURL));
m_networkRequest.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
QBuffer *buffer = new QBuffer();
buffer->open((QBuffer::ReadWrite));
buffer->write(swgChannelSettings->asJson().toUtf8());
buffer->seek(0);
// Always use PATCH to avoid passing reverse API settings
QNetworkReply *reply = m_networkManager->sendCustomRequest(m_networkRequest, "PATCH", buffer);
buffer->setParent(reply);
delete swgChannelSettings;
}
void NFMMod::webapiReverseSendCWSettings(const CWKeyerSettings& cwKeyerSettings)
{
SWGSDRangel::SWGChannelSettings *swgChannelSettings = new SWGSDRangel::SWGChannelSettings();
swgChannelSettings->setDirection(1); // single source (Tx)
swgChannelSettings->setChannelType(new QString("NFMMod"));
swgChannelSettings->setNfmModSettings(new SWGSDRangel::SWGNFMModSettings());
SWGSDRangel::SWGNFMModSettings *swgNFModSettings = swgChannelSettings->getNfmModSettings();
swgNFModSettings->setCwKeyer(new SWGSDRangel::SWGCWKeyerSettings());
SWGSDRangel::SWGCWKeyerSettings *apiCwKeyerSettings = swgNFModSettings->getCwKeyer();
m_basebandSource->getCWKeyer().webapiFormatChannelSettings(apiCwKeyerSettings, cwKeyerSettings);
QString channelSettingsURL = QString("http://%1:%2/sdrangel/deviceset/%3/channel/%4/settings")
.arg(m_settings.m_reverseAPIAddress)
.arg(m_settings.m_reverseAPIPort)
.arg(m_settings.m_reverseAPIDeviceIndex)
.arg(m_settings.m_reverseAPIChannelIndex);
m_networkRequest.setUrl(QUrl(channelSettingsURL));
m_networkRequest.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
QBuffer *buffer = new QBuffer();
buffer->open((QBuffer::ReadWrite));
buffer->write(swgChannelSettings->asJson().toUtf8());
buffer->seek(0);
// Always use PATCH to avoid passing reverse API settings
QNetworkReply *reply = m_networkManager->sendCustomRequest(m_networkRequest, "PATCH", buffer);
buffer->setParent(reply);
delete swgChannelSettings;
}
void NFMMod::featuresSendSettings(QList<QString>& channelSettingsKeys, const NFMModSettings& settings, bool force)
{
QList<Feature*>::iterator it = m_featuresSettingsFeedback.begin();
MainCore *mainCore = MainCore::instance();
for (; it != m_featuresSettingsFeedback.end(); ++it)
{
if (mainCore->existsFeature(*it))
{
SWGSDRangel::SWGChannelSettings *swgChannelSettings = new SWGSDRangel::SWGChannelSettings();
webapiFormatChannelSettings(channelSettingsKeys, swgChannelSettings, settings, force);
Feature::MsgChannelSettings *msg = Feature::MsgChannelSettings::create(
this,
channelSettingsKeys,
swgChannelSettings,
force
);
(*it)->getInputMessageQueue()->push(msg);
}
else
{
m_featuresSettingsFeedback.removeOne(*it);
}
}
}
void NFMMod::webapiFormatChannelSettings(
QList<QString>& channelSettingsKeys,
SWGSDRangel::SWGChannelSettings *swgChannelSettings,
const NFMModSettings& settings,
bool force
)
{
swgChannelSettings->setDirection(1); // single source (Tx)
swgChannelSettings->setOriginatorChannelIndex(getIndexInDeviceSet());
swgChannelSettings->setOriginatorDeviceSetIndex(getDeviceSetIndex());
swgChannelSettings->setChannelType(new QString("NFMMod"));
swgChannelSettings->setChannelType(new QString(m_channelId));
swgChannelSettings->setNfmModSettings(new SWGSDRangel::SWGNFMModSettings());
SWGSDRangel::SWGNFMModSettings *swgNFMModSettings = swgChannelSettings->getNfmModSettings();
@ -618,57 +713,6 @@ void NFMMod::webapiReverseSendSettings(QList<QString>& channelSettingsKeys, cons
SWGSDRangel::SWGCWKeyerSettings *apiCwKeyerSettings = swgNFMModSettings->getCwKeyer();
m_basebandSource->getCWKeyer().webapiFormatChannelSettings(apiCwKeyerSettings, cwKeyerSettings);
}
QString channelSettingsURL = QString("http://%1:%2/sdrangel/deviceset/%3/channel/%4/settings")
.arg(settings.m_reverseAPIAddress)
.arg(settings.m_reverseAPIPort)
.arg(settings.m_reverseAPIDeviceIndex)
.arg(settings.m_reverseAPIChannelIndex);
m_networkRequest.setUrl(QUrl(channelSettingsURL));
m_networkRequest.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
QBuffer *buffer = new QBuffer();
buffer->open((QBuffer::ReadWrite));
buffer->write(swgChannelSettings->asJson().toUtf8());
buffer->seek(0);
// Always use PATCH to avoid passing reverse API settings
QNetworkReply *reply = m_networkManager->sendCustomRequest(m_networkRequest, "PATCH", buffer);
buffer->setParent(reply);
delete swgChannelSettings;
}
void NFMMod::webapiReverseSendCWSettings(const CWKeyerSettings& cwKeyerSettings)
{
SWGSDRangel::SWGChannelSettings *swgChannelSettings = new SWGSDRangel::SWGChannelSettings();
swgChannelSettings->setDirection(1); // single source (Tx)
swgChannelSettings->setChannelType(new QString("NFMMod"));
swgChannelSettings->setNfmModSettings(new SWGSDRangel::SWGNFMModSettings());
SWGSDRangel::SWGNFMModSettings *swgNFModSettings = swgChannelSettings->getNfmModSettings();
swgNFModSettings->setCwKeyer(new SWGSDRangel::SWGCWKeyerSettings());
SWGSDRangel::SWGCWKeyerSettings *apiCwKeyerSettings = swgNFModSettings->getCwKeyer();
m_basebandSource->getCWKeyer().webapiFormatChannelSettings(apiCwKeyerSettings, cwKeyerSettings);
QString channelSettingsURL = QString("http://%1:%2/sdrangel/deviceset/%3/channel/%4/settings")
.arg(m_settings.m_reverseAPIAddress)
.arg(m_settings.m_reverseAPIPort)
.arg(m_settings.m_reverseAPIDeviceIndex)
.arg(m_settings.m_reverseAPIChannelIndex);
m_networkRequest.setUrl(QUrl(channelSettingsURL));
m_networkRequest.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
QBuffer *buffer = new QBuffer();
buffer->open((QBuffer::ReadWrite));
buffer->write(swgChannelSettings->asJson().toUtf8());
buffer->seek(0);
// Always use PATCH to avoid passing reverse API settings
QNetworkReply *reply = m_networkManager->sendCustomRequest(m_networkRequest, "PATCH", buffer);
buffer->setParent(reply);
delete swgChannelSettings;
}
void NFMMod::networkManagerFinished(QNetworkReply *reply)

View File

@ -261,6 +261,13 @@ private:
void webapiFormatChannelReport(SWGSDRangel::SWGChannelReport& response);
void webapiReverseSendSettings(QList<QString>& channelSettingsKeys, const NFMModSettings& settings, bool force);
void webapiReverseSendCWSettings(const CWKeyerSettings& settings);
void featuresSendSettings(QList<QString>& channelSettingsKeys, const NFMModSettings& settings, bool force);
void webapiFormatChannelSettings(
QList<QString>& channelSettingsKeys,
SWGSDRangel::SWGChannelSettings *swgChannelSettings,
const NFMModSettings& settings,
bool force
);
private slots:
void networkManagerFinished(QNetworkReply *reply);

View File

@ -38,8 +38,10 @@
#include "dsp/dspengine.h"
#include "dsp/dspcommands.h"
#include "device/deviceapi.h"
#include "feature/feature.h"
#include "util/db.h"
#include "util/crc.h"
#include "maincore.h"
#include "packetmodbaseband.h"
#include "packetmod.h"
@ -344,6 +346,10 @@ void PacketMod::applySettings(const PacketModSettings& settings, bool force)
webapiReverseSendSettings(reverseAPIKeys, settings, fullUpdate || force);
}
if (m_featuresSettingsFeedback.size() > 0) {
featuresSendSettings(reverseAPIKeys, settings, force);
}
m_settings = settings;
}
@ -703,10 +709,67 @@ void PacketMod::webapiFormatChannelReport(SWGSDRangel::SWGChannelReport& respons
void PacketMod::webapiReverseSendSettings(QList<QString>& channelSettingsKeys, const PacketModSettings& settings, bool force)
{
SWGSDRangel::SWGChannelSettings *swgChannelSettings = new SWGSDRangel::SWGChannelSettings();
webapiFormatChannelSettings(channelSettingsKeys, swgChannelSettings, settings, force);
QString channelSettingsURL = QString("http://%1:%2/sdrangel/deviceset/%3/channel/%4/settings")
.arg(settings.m_reverseAPIAddress)
.arg(settings.m_reverseAPIPort)
.arg(settings.m_reverseAPIDeviceIndex)
.arg(settings.m_reverseAPIChannelIndex);
m_networkRequest.setUrl(QUrl(channelSettingsURL));
m_networkRequest.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
QBuffer *buffer = new QBuffer();
buffer->open((QBuffer::ReadWrite));
buffer->write(swgChannelSettings->asJson().toUtf8());
buffer->seek(0);
// Always use PATCH to avoid passing reverse API settings
QNetworkReply *reply = m_networkManager->sendCustomRequest(m_networkRequest, "PATCH", buffer);
buffer->setParent(reply);
delete swgChannelSettings;
}
void PacketMod::featuresSendSettings(QList<QString>& channelSettingsKeys, const PacketModSettings& settings, bool force)
{
QList<Feature*>::iterator it = m_featuresSettingsFeedback.begin();
MainCore *mainCore = MainCore::instance();
for (; it != m_featuresSettingsFeedback.end(); ++it)
{
if (mainCore->existsFeature(*it))
{
SWGSDRangel::SWGChannelSettings *swgChannelSettings = new SWGSDRangel::SWGChannelSettings();
webapiFormatChannelSettings(channelSettingsKeys, swgChannelSettings, settings, force);
Feature::MsgChannelSettings *msg = Feature::MsgChannelSettings::create(
this,
channelSettingsKeys,
swgChannelSettings,
force
);
(*it)->getInputMessageQueue()->push(msg);
}
else
{
m_featuresSettingsFeedback.removeOne(*it);
}
}
}
void PacketMod::webapiFormatChannelSettings(
QList<QString>& channelSettingsKeys,
SWGSDRangel::SWGChannelSettings *swgChannelSettings,
const PacketModSettings& settings,
bool force
)
{
swgChannelSettings->setDirection(1); // single source (Tx)
swgChannelSettings->setOriginatorChannelIndex(getIndexInDeviceSet());
swgChannelSettings->setOriginatorDeviceSetIndex(getDeviceSetIndex());
swgChannelSettings->setChannelType(new QString("PacketMod"));
swgChannelSettings->setChannelType(new QString(m_channelId));
swgChannelSettings->setPacketModSettings(new SWGSDRangel::SWGPacketModSettings());
SWGSDRangel::SWGPacketModSettings *swgPacketModSettings = swgChannelSettings->getPacketModSettings();
@ -835,25 +898,6 @@ void PacketMod::webapiReverseSendSettings(QList<QString>& channelSettingsKeys, c
if (channelSettingsKeys.contains("streamIndex") || force) {
swgPacketModSettings->setStreamIndex(settings.m_streamIndex);
}
QString channelSettingsURL = QString("http://%1:%2/sdrangel/deviceset/%3/channel/%4/settings")
.arg(settings.m_reverseAPIAddress)
.arg(settings.m_reverseAPIPort)
.arg(settings.m_reverseAPIDeviceIndex)
.arg(settings.m_reverseAPIChannelIndex);
m_networkRequest.setUrl(QUrl(channelSettingsURL));
m_networkRequest.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
QBuffer *buffer = new QBuffer();
buffer->open((QBuffer::ReadWrite));
buffer->write(swgChannelSettings->asJson().toUtf8());
buffer->seek(0);
// Always use PATCH to avoid passing reverse API settings
QNetworkReply *reply = m_networkManager->sendCustomRequest(m_networkRequest, "PATCH", buffer);
buffer->setParent(reply);
delete swgChannelSettings;
}
void PacketMod::networkManagerFinished(QNetworkReply *reply)

View File

@ -179,6 +179,13 @@ private:
void applySettings(const PacketModSettings& settings, bool force = false);
void webapiFormatChannelReport(SWGSDRangel::SWGChannelReport& response);
void webapiReverseSendSettings(QList<QString>& channelSettingsKeys, const PacketModSettings& settings, bool force);
void featuresSendSettings(QList<QString>& channelSettingsKeys, const PacketModSettings& settings, bool force);
void webapiFormatChannelSettings(
QList<QString>& channelSettingsKeys,
SWGSDRangel::SWGChannelSettings *swgChannelSettings,
const PacketModSettings& settings,
bool force
);
private slots:
void networkManagerFinished(QNetworkReply *reply);

View File

@ -35,7 +35,9 @@
#include "dsp/dspcommands.h"
#include "dsp/cwkeyer.h"
#include "device/deviceapi.h"
#include "feature/feature.h"
#include "util/db.h"
#include "maincore.h"
#include "ssbmodbaseband.h"
#include "ssbmod.h"
@ -305,6 +307,10 @@ void SSBMod::applySettings(const SSBModSettings& settings, bool force)
webapiReverseSendSettings(reverseAPIKeys, settings, fullUpdate || force);
}
if (m_featuresSettingsFeedback.size() > 0) {
featuresSendSettings(reverseAPIKeys, settings, force);
}
m_settings = settings;
m_settings.m_bandwidth = band;
m_settings.m_lowCutoff = lowCutoff;
@ -534,10 +540,99 @@ void SSBMod::webapiFormatChannelReport(SWGSDRangel::SWGChannelReport& response)
void SSBMod::webapiReverseSendSettings(QList<QString>& channelSettingsKeys, const SSBModSettings& settings, bool force)
{
SWGSDRangel::SWGChannelSettings *swgChannelSettings = new SWGSDRangel::SWGChannelSettings();
webapiFormatChannelSettings(channelSettingsKeys, swgChannelSettings, settings, force);
QString channelSettingsURL = QString("http://%1:%2/sdrangel/deviceset/%3/channel/%4/settings")
.arg(settings.m_reverseAPIAddress)
.arg(settings.m_reverseAPIPort)
.arg(settings.m_reverseAPIDeviceIndex)
.arg(settings.m_reverseAPIChannelIndex);
m_networkRequest.setUrl(QUrl(channelSettingsURL));
m_networkRequest.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
QBuffer *buffer = new QBuffer();
buffer->open((QBuffer::ReadWrite));
buffer->write(swgChannelSettings->asJson().toUtf8());
buffer->seek(0);
// Always use PATCH to avoid passing reverse API settings
QNetworkReply *reply = m_networkManager->sendCustomRequest(m_networkRequest, "PATCH", buffer);
buffer->setParent(reply);
delete swgChannelSettings;
}
void SSBMod::webapiReverseSendCWSettings(const CWKeyerSettings& cwKeyerSettings)
{
SWGSDRangel::SWGChannelSettings *swgChannelSettings = new SWGSDRangel::SWGChannelSettings();
swgChannelSettings->setDirection(1); // single source (Tx)
swgChannelSettings->setChannelType(new QString("SSBMod"));
swgChannelSettings->setSsbModSettings(new SWGSDRangel::SWGSSBModSettings());
SWGSDRangel::SWGSSBModSettings *swgSSBModSettings = swgChannelSettings->getSsbModSettings();
swgSSBModSettings->setCwKeyer(new SWGSDRangel::SWGCWKeyerSettings());
SWGSDRangel::SWGCWKeyerSettings *apiCwKeyerSettings = swgSSBModSettings->getCwKeyer();
m_basebandSource->getCWKeyer().webapiFormatChannelSettings(apiCwKeyerSettings, cwKeyerSettings);
QString channelSettingsURL = QString("http://%1:%2/sdrangel/deviceset/%3/channel/%4/settings")
.arg(m_settings.m_reverseAPIAddress)
.arg(m_settings.m_reverseAPIPort)
.arg(m_settings.m_reverseAPIDeviceIndex)
.arg(m_settings.m_reverseAPIChannelIndex);
m_networkRequest.setUrl(QUrl(channelSettingsURL));
m_networkRequest.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
QBuffer *buffer = new QBuffer();
buffer->open((QBuffer::ReadWrite));
buffer->write(swgChannelSettings->asJson().toUtf8());
buffer->seek(0);
// Always use PATCH to avoid passing reverse API settings
QNetworkReply *reply = m_networkManager->sendCustomRequest(m_networkRequest, "PATCH", buffer);
buffer->setParent(reply);
delete swgChannelSettings;
}
void SSBMod::featuresSendSettings(QList<QString>& channelSettingsKeys, const SSBModSettings& settings, bool force)
{
QList<Feature*>::iterator it = m_featuresSettingsFeedback.begin();
MainCore *mainCore = MainCore::instance();
for (; it != m_featuresSettingsFeedback.end(); ++it)
{
if (mainCore->existsFeature(*it))
{
SWGSDRangel::SWGChannelSettings *swgChannelSettings = new SWGSDRangel::SWGChannelSettings();
webapiFormatChannelSettings(channelSettingsKeys, swgChannelSettings, settings, force);
Feature::MsgChannelSettings *msg = Feature::MsgChannelSettings::create(
this,
channelSettingsKeys,
swgChannelSettings,
force
);
(*it)->getInputMessageQueue()->push(msg);
}
else
{
m_featuresSettingsFeedback.removeOne(*it);
}
}
}
void SSBMod::webapiFormatChannelSettings(
QList<QString>& channelSettingsKeys,
SWGSDRangel::SWGChannelSettings *swgChannelSettings,
const SSBModSettings& settings,
bool force
)
{
swgChannelSettings->setDirection(1); // single source (Tx)
swgChannelSettings->setOriginatorChannelIndex(getIndexInDeviceSet());
swgChannelSettings->setOriginatorDeviceSetIndex(getDeviceSetIndex());
swgChannelSettings->setChannelType(new QString("SSBMod"));
swgChannelSettings->setChannelType(new QString(m_channelId));
swgChannelSettings->setSsbModSettings(new SWGSDRangel::SWGSSBModSettings());
SWGSDRangel::SWGSSBModSettings *swgSSBModSettings = swgChannelSettings->getSsbModSettings();
@ -605,57 +700,6 @@ void SSBMod::webapiReverseSendSettings(QList<QString>& channelSettingsKeys, cons
SWGSDRangel::SWGCWKeyerSettings *apiCwKeyerSettings = swgSSBModSettings->getCwKeyer();
m_basebandSource->getCWKeyer().webapiFormatChannelSettings(apiCwKeyerSettings, cwKeyerSettings);
}
QString channelSettingsURL = QString("http://%1:%2/sdrangel/deviceset/%3/channel/%4/settings")
.arg(settings.m_reverseAPIAddress)
.arg(settings.m_reverseAPIPort)
.arg(settings.m_reverseAPIDeviceIndex)
.arg(settings.m_reverseAPIChannelIndex);
m_networkRequest.setUrl(QUrl(channelSettingsURL));
m_networkRequest.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
QBuffer *buffer = new QBuffer();
buffer->open((QBuffer::ReadWrite));
buffer->write(swgChannelSettings->asJson().toUtf8());
buffer->seek(0);
// Always use PATCH to avoid passing reverse API settings
QNetworkReply *reply = m_networkManager->sendCustomRequest(m_networkRequest, "PATCH", buffer);
buffer->setParent(reply);
delete swgChannelSettings;
}
void SSBMod::webapiReverseSendCWSettings(const CWKeyerSettings& cwKeyerSettings)
{
SWGSDRangel::SWGChannelSettings *swgChannelSettings = new SWGSDRangel::SWGChannelSettings();
swgChannelSettings->setDirection(1); // single source (Tx)
swgChannelSettings->setChannelType(new QString("SSBMod"));
swgChannelSettings->setSsbModSettings(new SWGSDRangel::SWGSSBModSettings());
SWGSDRangel::SWGSSBModSettings *swgSSBModSettings = swgChannelSettings->getSsbModSettings();
swgSSBModSettings->setCwKeyer(new SWGSDRangel::SWGCWKeyerSettings());
SWGSDRangel::SWGCWKeyerSettings *apiCwKeyerSettings = swgSSBModSettings->getCwKeyer();
m_basebandSource->getCWKeyer().webapiFormatChannelSettings(apiCwKeyerSettings, cwKeyerSettings);
QString channelSettingsURL = QString("http://%1:%2/sdrangel/deviceset/%3/channel/%4/settings")
.arg(m_settings.m_reverseAPIAddress)
.arg(m_settings.m_reverseAPIPort)
.arg(m_settings.m_reverseAPIDeviceIndex)
.arg(m_settings.m_reverseAPIChannelIndex);
m_networkRequest.setUrl(QUrl(channelSettingsURL));
m_networkRequest.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
QBuffer *buffer = new QBuffer();
buffer->open((QBuffer::ReadWrite));
buffer->write(swgChannelSettings->asJson().toUtf8());
buffer->seek(0);
// Always use PATCH to avoid passing reverse API settings
QNetworkReply *reply = m_networkManager->sendCustomRequest(m_networkRequest, "PATCH", buffer);
buffer->setParent(reply);
delete swgChannelSettings;
}
void SSBMod::networkManagerFinished(QNetworkReply *reply)
@ -707,4 +751,4 @@ int SSBMod::getFeedbackAudioSampleRate() const
uint32_t SSBMod::getNumberOfDeviceStreams() const
{
return m_deviceAPI->getNbSinkStreams();
}
}

View File

@ -265,6 +265,13 @@ private:
void webapiFormatChannelReport(SWGSDRangel::SWGChannelReport& response);
void webapiReverseSendSettings(QList<QString>& channelSettingsKeys, const SSBModSettings& settings, bool force);
void webapiReverseSendCWSettings(const CWKeyerSettings& settings);
void featuresSendSettings(QList<QString>& channelSettingsKeys, const SSBModSettings& settings, bool force);
void webapiFormatChannelSettings(
QList<QString>& channelSettingsKeys,
SWGSDRangel::SWGChannelSettings *swgChannelSettings,
const SSBModSettings& settings,
bool force
);
private slots:
void networkManagerFinished(QNetworkReply *reply);

View File

@ -34,7 +34,9 @@
#include "dsp/dspengine.h"
#include "dsp/dspcommands.h"
#include "device/deviceapi.h"
#include "feature/feature.h"
#include "util/db.h"
#include "maincore.h"
#include "wfmmodbaseband.h"
#include "wfmmod.h"
@ -286,6 +288,10 @@ void WFMMod::applySettings(const WFMModSettings& settings, bool force)
webapiReverseSendSettings(reverseAPIKeys, settings, fullUpdate || force);
}
if (m_featuresSettingsFeedback.size() > 0) {
featuresSendSettings(reverseAPIKeys, settings, force);
}
m_settings = settings;
}
@ -489,62 +495,7 @@ void WFMMod::webapiFormatChannelReport(SWGSDRangel::SWGChannelReport& response)
void WFMMod::webapiReverseSendSettings(QList<QString>& channelSettingsKeys, const WFMModSettings& settings, bool force)
{
SWGSDRangel::SWGChannelSettings *swgChannelSettings = new SWGSDRangel::SWGChannelSettings();
swgChannelSettings->setDirection(1); // single source (Tx)
swgChannelSettings->setOriginatorChannelIndex(getIndexInDeviceSet());
swgChannelSettings->setOriginatorDeviceSetIndex(getDeviceSetIndex());
swgChannelSettings->setChannelType(new QString("WFMMod"));
swgChannelSettings->setWfmModSettings(new SWGSDRangel::SWGWFMModSettings());
SWGSDRangel::SWGWFMModSettings *swgWFMModSettings = swgChannelSettings->getWfmModSettings();
// transfer data that has been modified. When force is on transfer all data except reverse API data
if (channelSettingsKeys.contains("channelMute") || force) {
swgWFMModSettings->setChannelMute(settings.m_channelMute ? 1 : 0);
}
if (channelSettingsKeys.contains("inputFrequencyOffset") || force) {
swgWFMModSettings->setInputFrequencyOffset(settings.m_inputFrequencyOffset);
}
if (channelSettingsKeys.contains("modAFInput") || force) {
swgWFMModSettings->setModAfInput((int) settings.m_modAFInput);
}
if (channelSettingsKeys.contains("playLoop") || force) {
swgWFMModSettings->setPlayLoop(settings.m_playLoop ? 1 : 0);
}
if (channelSettingsKeys.contains("rfBandwidth") || force) {
swgWFMModSettings->setRfBandwidth(settings.m_rfBandwidth);
}
if (channelSettingsKeys.contains("afBandwidth") || force) {
swgWFMModSettings->setAfBandwidth(settings.m_afBandwidth);
}
if (channelSettingsKeys.contains("rgbColor") || force) {
swgWFMModSettings->setRgbColor(settings.m_rgbColor);
}
if (channelSettingsKeys.contains("title") || force) {
swgWFMModSettings->setTitle(new QString(settings.m_title));
}
if (channelSettingsKeys.contains("toneFrequency") || force) {
swgWFMModSettings->setToneFrequency(settings.m_toneFrequency);
}
if (channelSettingsKeys.contains("volumeFactor") || force) {
swgWFMModSettings->setVolumeFactor(settings.m_volumeFactor);
}
if (channelSettingsKeys.contains("fmDeviation")) {
swgWFMModSettings->setFmDeviation(settings.m_fmDeviation);
}
if (channelSettingsKeys.contains("streamIndex")) {
swgWFMModSettings->setStreamIndex(settings.m_streamIndex);
}
if (channelSettingsKeys.contains("audioDeviceName") || force) {
swgWFMModSettings->setAudioDeviceName(new QString(settings.m_audioDeviceName));
}
if (force)
{
const CWKeyerSettings& cwKeyerSettings = m_basebandSource->getCWKeyer().getSettings();
swgWFMModSettings->setCwKeyer(new SWGSDRangel::SWGCWKeyerSettings());
SWGSDRangel::SWGCWKeyerSettings *apiCwKeyerSettings = swgWFMModSettings->getCwKeyer();
m_basebandSource->getCWKeyer().webapiFormatChannelSettings(apiCwKeyerSettings, cwKeyerSettings);
}
webapiFormatChannelSettings(channelSettingsKeys, swgChannelSettings, settings, force);
QString channelSettingsURL = QString("http://%1:%2/sdrangel/deviceset/%3/channel/%4/settings")
.arg(settings.m_reverseAPIAddress)
@ -598,6 +549,99 @@ void WFMMod::webapiReverseSendCWSettings(const CWKeyerSettings& cwKeyerSettings)
delete swgChannelSettings;
}
void WFMMod::featuresSendSettings(QList<QString>& channelSettingsKeys, const WFMModSettings& settings, bool force)
{
QList<Feature*>::iterator it = m_featuresSettingsFeedback.begin();
MainCore *mainCore = MainCore::instance();
for (; it != m_featuresSettingsFeedback.end(); ++it)
{
if (mainCore->existsFeature(*it))
{
SWGSDRangel::SWGChannelSettings *swgChannelSettings = new SWGSDRangel::SWGChannelSettings();
webapiFormatChannelSettings(channelSettingsKeys, swgChannelSettings, settings, force);
Feature::MsgChannelSettings *msg = Feature::MsgChannelSettings::create(
this,
channelSettingsKeys,
swgChannelSettings,
force
);
(*it)->getInputMessageQueue()->push(msg);
}
else
{
m_featuresSettingsFeedback.removeOne(*it);
}
}
}
void WFMMod::webapiFormatChannelSettings(
QList<QString>& channelSettingsKeys,
SWGSDRangel::SWGChannelSettings *swgChannelSettings,
const WFMModSettings& settings,
bool force
)
{
swgChannelSettings->setDirection(1); // single source (Tx)
swgChannelSettings->setOriginatorChannelIndex(getIndexInDeviceSet());
swgChannelSettings->setOriginatorDeviceSetIndex(getDeviceSetIndex());
swgChannelSettings->setChannelType(new QString(m_channelId));
swgChannelSettings->setWfmModSettings(new SWGSDRangel::SWGWFMModSettings());
SWGSDRangel::SWGWFMModSettings *swgWFMModSettings = swgChannelSettings->getWfmModSettings();
// transfer data that has been modified. When force is on transfer all data except reverse API data
if (channelSettingsKeys.contains("channelMute") || force) {
swgWFMModSettings->setChannelMute(settings.m_channelMute ? 1 : 0);
}
if (channelSettingsKeys.contains("inputFrequencyOffset") || force) {
swgWFMModSettings->setInputFrequencyOffset(settings.m_inputFrequencyOffset);
}
if (channelSettingsKeys.contains("modAFInput") || force) {
swgWFMModSettings->setModAfInput((int) settings.m_modAFInput);
}
if (channelSettingsKeys.contains("playLoop") || force) {
swgWFMModSettings->setPlayLoop(settings.m_playLoop ? 1 : 0);
}
if (channelSettingsKeys.contains("rfBandwidth") || force) {
swgWFMModSettings->setRfBandwidth(settings.m_rfBandwidth);
}
if (channelSettingsKeys.contains("afBandwidth") || force) {
swgWFMModSettings->setAfBandwidth(settings.m_afBandwidth);
}
if (channelSettingsKeys.contains("rgbColor") || force) {
swgWFMModSettings->setRgbColor(settings.m_rgbColor);
}
if (channelSettingsKeys.contains("title") || force) {
swgWFMModSettings->setTitle(new QString(settings.m_title));
}
if (channelSettingsKeys.contains("toneFrequency") || force) {
swgWFMModSettings->setToneFrequency(settings.m_toneFrequency);
}
if (channelSettingsKeys.contains("volumeFactor") || force) {
swgWFMModSettings->setVolumeFactor(settings.m_volumeFactor);
}
if (channelSettingsKeys.contains("fmDeviation")) {
swgWFMModSettings->setFmDeviation(settings.m_fmDeviation);
}
if (channelSettingsKeys.contains("streamIndex")) {
swgWFMModSettings->setStreamIndex(settings.m_streamIndex);
}
if (channelSettingsKeys.contains("audioDeviceName") || force) {
swgWFMModSettings->setAudioDeviceName(new QString(settings.m_audioDeviceName));
}
if (force)
{
const CWKeyerSettings& cwKeyerSettings = m_basebandSource->getCWKeyer().getSettings();
swgWFMModSettings->setCwKeyer(new SWGSDRangel::SWGCWKeyerSettings());
SWGSDRangel::SWGCWKeyerSettings *apiCwKeyerSettings = swgWFMModSettings->getCwKeyer();
m_basebandSource->getCWKeyer().webapiFormatChannelSettings(apiCwKeyerSettings, cwKeyerSettings);
}
}
void WFMMod::networkManagerFinished(QNetworkReply *reply)
{
QNetworkReply::NetworkError replyError = reply->error();

View File

@ -273,6 +273,13 @@ private:
void webapiFormatChannelReport(SWGSDRangel::SWGChannelReport& response);
void webapiReverseSendSettings(QList<QString>& channelSettingsKeys, const WFMModSettings& settings, bool force);
void webapiReverseSendCWSettings(const CWKeyerSettings& settings);
void featuresSendSettings(QList<QString>& channelSettingsKeys, const WFMModSettings& settings, bool force);
void webapiFormatChannelSettings(
QList<QString>& channelSettingsKeys,
SWGSDRangel::SWGChannelSettings *swgChannelSettings,
const WFMModSettings& settings,
bool force
);
private slots:
void networkManagerFinished(QNetworkReply *reply);

View File

@ -29,7 +29,10 @@
#include "dsp/devicesamplesink.h"
#include "device/deviceapi.h"
#include "feature/feature.h"
#include "util/timeutil.h"
#include "util/db.h"
#include "maincore.h"
#include "remotesourcebaseband.h"
@ -202,6 +205,10 @@ void RemoteSource::applySettings(const RemoteSourceSettings& settings, bool forc
webapiReverseSendSettings(reverseAPIKeys, settings, fullUpdate || force);
}
if (m_featuresSettingsFeedback.size() > 0) {
featuresSendSettings(reverseAPIKeys, settings, force);
}
m_settings = settings;
}
@ -350,10 +357,67 @@ void RemoteSource::webapiFormatChannelReport(SWGSDRangel::SWGChannelReport& resp
void RemoteSource::webapiReverseSendSettings(QList<QString>& channelSettingsKeys, const RemoteSourceSettings& settings, bool force)
{
SWGSDRangel::SWGChannelSettings *swgChannelSettings = new SWGSDRangel::SWGChannelSettings();
webapiFormatChannelSettings(channelSettingsKeys, swgChannelSettings, settings, force);
QString channelSettingsURL = QString("http://%1:%2/sdrangel/deviceset/%3/channel/%4/settings")
.arg(settings.m_reverseAPIAddress)
.arg(settings.m_reverseAPIPort)
.arg(settings.m_reverseAPIDeviceIndex)
.arg(settings.m_reverseAPIChannelIndex);
m_networkRequest.setUrl(QUrl(channelSettingsURL));
m_networkRequest.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
QBuffer *buffer = new QBuffer();
buffer->open((QBuffer::ReadWrite));
buffer->write(swgChannelSettings->asJson().toUtf8());
buffer->seek(0);
// Always use PATCH to avoid passing reverse API settings
QNetworkReply *reply = m_networkManager->sendCustomRequest(m_networkRequest, "PATCH", buffer);
buffer->setParent(reply);
delete swgChannelSettings;
}
void RemoteSource::featuresSendSettings(QList<QString>& channelSettingsKeys, const RemoteSourceSettings& settings, bool force)
{
QList<Feature*>::iterator it = m_featuresSettingsFeedback.begin();
MainCore *mainCore = MainCore::instance();
for (; it != m_featuresSettingsFeedback.end(); ++it)
{
if (mainCore->existsFeature(*it))
{
SWGSDRangel::SWGChannelSettings *swgChannelSettings = new SWGSDRangel::SWGChannelSettings();
webapiFormatChannelSettings(channelSettingsKeys, swgChannelSettings, settings, force);
Feature::MsgChannelSettings *msg = Feature::MsgChannelSettings::create(
this,
channelSettingsKeys,
swgChannelSettings,
force
);
(*it)->getInputMessageQueue()->push(msg);
}
else
{
m_featuresSettingsFeedback.removeOne(*it);
}
}
}
void RemoteSource::webapiFormatChannelSettings(
QList<QString>& channelSettingsKeys,
SWGSDRangel::SWGChannelSettings *swgChannelSettings,
const RemoteSourceSettings& settings,
bool force
)
{
swgChannelSettings->setDirection(1); // single source (Tx)
swgChannelSettings->setOriginatorChannelIndex(getIndexInDeviceSet());
swgChannelSettings->setOriginatorDeviceSetIndex(getDeviceSetIndex());
swgChannelSettings->setChannelType(new QString("RemoteSource"));
swgChannelSettings->setChannelType(new QString(m_channelId));
swgChannelSettings->setRemoteSourceSettings(new SWGSDRangel::SWGRemoteSourceSettings());
SWGSDRangel::SWGRemoteSourceSettings *swgRemoteSourceSettings = swgChannelSettings->getRemoteSourceSettings();
@ -374,25 +438,6 @@ void RemoteSource::webapiReverseSendSettings(QList<QString>& channelSettingsKeys
if (channelSettingsKeys.contains("streamIndex") || force) {
swgRemoteSourceSettings->setStreamIndex(settings.m_streamIndex);
}
QString channelSettingsURL = QString("http://%1:%2/sdrangel/deviceset/%3/channel/%4/settings")
.arg(settings.m_reverseAPIAddress)
.arg(settings.m_reverseAPIPort)
.arg(settings.m_reverseAPIDeviceIndex)
.arg(settings.m_reverseAPIChannelIndex);
m_networkRequest.setUrl(QUrl(channelSettingsURL));
m_networkRequest.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
QBuffer *buffer = new QBuffer();
buffer->open((QBuffer::ReadWrite));
buffer->write(swgChannelSettings->asJson().toUtf8());
buffer->seek(0);
// Always use PATCH to avoid passing reverse API settings
QNetworkReply *reply = m_networkManager->sendCustomRequest(m_networkRequest, "PATCH", buffer);
buffer->setParent(reply);
delete swgChannelSettings;
}
void RemoteSource::networkManagerFinished(QNetworkReply *reply)
@ -419,4 +464,4 @@ void RemoteSource::networkManagerFinished(QNetworkReply *reply)
uint32_t RemoteSource::getNumberOfDeviceStreams() const
{
return m_deviceAPI->getNbSinkStreams();
}
}

View File

@ -222,6 +222,13 @@ private:
void applySettings(const RemoteSourceSettings& settings, bool force = false);
void webapiFormatChannelReport(SWGSDRangel::SWGChannelReport& response);
void webapiReverseSendSettings(QList<QString>& channelSettingsKeys, const RemoteSourceSettings& settings, bool force);
void featuresSendSettings(QList<QString>& channelSettingsKeys, const RemoteSourceSettings& settings, bool force);
void webapiFormatChannelSettings(
QList<QString>& channelSettingsKeys,
SWGSDRangel::SWGChannelSettings *swgChannelSettings,
const RemoteSourceSettings& settings,
bool force
);
private slots:
void networkManagerFinished(QNetworkReply *reply);

View File

@ -27,7 +27,9 @@
#include "device/deviceapi.h"
#include "dsp/dspcommands.h"
#include "feature/feature.h"
#include "util/db.h"
#include "maincore.h"
#include "udpsourcebaseband.h"
#include "udpsource.h"
@ -251,6 +253,10 @@ void UDPSource::applySettings(const UDPSourceSettings& settings, bool force)
webapiReverseSendSettings(reverseAPIKeys, settings, fullUpdate || force);
}
if (m_featuresSettingsFeedback.size() > 0) {
featuresSendSettings(reverseAPIKeys, settings, force);
}
m_settings = settings;
}
@ -484,10 +490,67 @@ void UDPSource::webapiFormatChannelReport(SWGSDRangel::SWGChannelReport& respons
void UDPSource::webapiReverseSendSettings(QList<QString>& channelSettingsKeys, const UDPSourceSettings& settings, bool force)
{
SWGSDRangel::SWGChannelSettings *swgChannelSettings = new SWGSDRangel::SWGChannelSettings();
webapiFormatChannelSettings(channelSettingsKeys, swgChannelSettings, settings, force);
QString channelSettingsURL = QString("http://%1:%2/sdrangel/deviceset/%3/channel/%4/settings")
.arg(settings.m_reverseAPIAddress)
.arg(settings.m_reverseAPIPort)
.arg(settings.m_reverseAPIDeviceIndex)
.arg(settings.m_reverseAPIChannelIndex);
m_networkRequest.setUrl(QUrl(channelSettingsURL));
m_networkRequest.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
QBuffer *buffer = new QBuffer();
buffer->open((QBuffer::ReadWrite));
buffer->write(swgChannelSettings->asJson().toUtf8());
buffer->seek(0);
// Always use PATCH to avoid passing reverse API settings
QNetworkReply *reply = m_networkManager->sendCustomRequest(m_networkRequest, "PATCH", buffer);
buffer->setParent(reply);
delete swgChannelSettings;
}
void UDPSource::featuresSendSettings(QList<QString>& channelSettingsKeys, const UDPSourceSettings& settings, bool force)
{
QList<Feature*>::iterator it = m_featuresSettingsFeedback.begin();
MainCore *mainCore = MainCore::instance();
for (; it != m_featuresSettingsFeedback.end(); ++it)
{
if (mainCore->existsFeature(*it))
{
SWGSDRangel::SWGChannelSettings *swgChannelSettings = new SWGSDRangel::SWGChannelSettings();
webapiFormatChannelSettings(channelSettingsKeys, swgChannelSettings, settings, force);
Feature::MsgChannelSettings *msg = Feature::MsgChannelSettings::create(
this,
channelSettingsKeys,
swgChannelSettings,
force
);
(*it)->getInputMessageQueue()->push(msg);
}
else
{
m_featuresSettingsFeedback.removeOne(*it);
}
}
}
void UDPSource::webapiFormatChannelSettings(
QList<QString>& channelSettingsKeys,
SWGSDRangel::SWGChannelSettings *swgChannelSettings,
const UDPSourceSettings& settings,
bool force
)
{
swgChannelSettings->setDirection(1); // single source (Tx)
swgChannelSettings->setOriginatorChannelIndex(getIndexInDeviceSet());
swgChannelSettings->setOriginatorDeviceSetIndex(getDeviceSetIndex());
swgChannelSettings->setChannelType(new QString("UDPSource"));
swgChannelSettings->setChannelType(new QString(m_channelId));
swgChannelSettings->setUdpSourceSettings(new SWGSDRangel::SWGUDPSourceSettings());
SWGSDRangel::SWGUDPSourceSettings *swgUDPSourceSettings = swgChannelSettings->getUdpSourceSettings();
@ -559,25 +622,6 @@ void UDPSource::webapiReverseSendSettings(QList<QString>& channelSettingsKeys, c
if (channelSettingsKeys.contains("streamIndex") || force) {
swgUDPSourceSettings->setStreamIndex(settings.m_streamIndex);
}
QString channelSettingsURL = QString("http://%1:%2/sdrangel/deviceset/%3/channel/%4/settings")
.arg(settings.m_reverseAPIAddress)
.arg(settings.m_reverseAPIPort)
.arg(settings.m_reverseAPIDeviceIndex)
.arg(settings.m_reverseAPIChannelIndex);
m_networkRequest.setUrl(QUrl(channelSettingsURL));
m_networkRequest.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
QBuffer *buffer = new QBuffer();
buffer->open((QBuffer::ReadWrite));
buffer->write(swgChannelSettings->asJson().toUtf8());
buffer->seek(0);
// Always use PATCH to avoid passing reverse API settings
QNetworkReply *reply = m_networkManager->sendCustomRequest(m_networkRequest, "PATCH", buffer);
buffer->setParent(reply);
delete swgChannelSettings;
}
void UDPSource::networkManagerFinished(QNetworkReply *reply)
@ -628,4 +672,4 @@ bool UDPSource::getSquelchOpen() const
uint32_t UDPSource::getNumberOfDeviceStreams() const
{
return m_deviceAPI->getNbSinkStreams();
}
}

View File

@ -176,6 +176,13 @@ private:
void webapiFormatChannelReport(SWGSDRangel::SWGChannelReport& response);
void webapiReverseSendSettings(QList<QString>& channelSettingsKeys, const UDPSourceSettings& settings, bool force);
void featuresSendSettings(QList<QString>& channelSettingsKeys, const UDPSourceSettings& settings, bool force);
void webapiFormatChannelSettings(
QList<QString>& channelSettingsKeys,
SWGSDRangel::SWGChannelSettings *swgChannelSettings,
const UDPSourceSettings& settings,
bool force
);
};

View File

@ -3,5 +3,6 @@ project(feature)
if (Qt5SerialPort_FOUND)
add_subdirectory(gs232controller)
endif()
add_subdirectory(afc)
add_subdirectory(rigctlserver)
add_subdirectory(simpleptt)

View File

@ -0,0 +1,58 @@
project(afc)
set(afc_SOURCES
afc.cpp
afcsettings.cpp
afcplugin.cpp
afcworker.cpp
afcreport.cpp
afcwebapiadapter.cpp
)
set(afc_HEADERS
afc.h
afcsettings.h
afcplugin.h
afcworker.h
afcreport.h
afcwebapiadapter.h
)
include_directories(
${CMAKE_SOURCE_DIR}/swagger/sdrangel/code/qt5/client
)
if(NOT SERVER_MODE)
set(afc_SOURCES
${afc_SOURCES}
afcgui.cpp
afcgui.ui
)
set(afc_HEADERS
${afc_HEADERS}
afcgui.h
)
set(TARGET_NAME featureafc)
set(TARGET_LIB "Qt5::Widgets")
set(TARGET_LIB_GUI "sdrgui")
set(INSTALL_FOLDER ${INSTALL_PLUGINS_DIR})
else()
set(TARGET_NAME featureafcsrv)
set(TARGET_LIB "")
set(TARGET_LIB_GUI "")
set(INSTALL_FOLDER ${INSTALL_PLUGINSSRV_DIR})
endif()
add_library(${TARGET_NAME} SHARED
${afc_SOURCES}
)
target_link_libraries(${TARGET_NAME}
Qt5::Core
${TARGET_LIB}
sdrbase
${TARGET_LIB_GUI}
)
install(TARGETS ${TARGET_NAME} DESTINATION ${INSTALL_FOLDER})

580
plugins/feature/afc/afc.cpp Normal file
View File

@ -0,0 +1,580 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2020 Edouard Griffiths, F4EXB //
// //
// This program is free software; you can redistribute it and/or modify //
// it under the terms of the GNU General Public License as published by //
// the Free Software Foundation as version 3 of the License, or //
// (at your option) any later version. //
// //
// This program is distributed in the hope that it will be useful, //
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
// GNU General Public License V3 for more details. //
// //
// You should have received a copy of the GNU General Public License //
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#include <QDebug>
#include <QNetworkAccessManager>
#include <QNetworkReply>
#include <QBuffer>
#include "SWGFeatureSettings.h"
#include "SWGFeatureReport.h"
#include "SWGFeatureActions.h"
#include "SWGAFCReport.h"
#include "SWGDeviceState.h"
#include "SWGChannelSettings.h"
#include "dsp/dspengine.h"
#include "device/deviceset.h"
#include "channel/channelapi.h"
#include "maincore.h"
#include "afcworker.h"
#include "afc.h"
MESSAGE_CLASS_DEFINITION(AFC::MsgConfigureAFC, Message)
MESSAGE_CLASS_DEFINITION(AFC::MsgStartStop, Message)
MESSAGE_CLASS_DEFINITION(AFC::MsgDeviceTrack, Message)
MESSAGE_CLASS_DEFINITION(AFC::MsgDevicesApply, Message)
const QString AFC::m_featureIdURI = "sdrangel.feature.afc";
const QString AFC::m_featureId = "AFC";
AFC::AFC(WebAPIAdapterInterface *webAPIAdapterInterface) :
Feature(m_featureIdURI, webAPIAdapterInterface),
m_trackerDeviceSet(nullptr),
m_trackedDeviceSet(nullptr),
m_trackerIndexInDeviceSet(-1),
m_trackerChannelAPI(nullptr)
{
setObjectName(m_featureId);
m_worker = new AFCWorker(webAPIAdapterInterface);
m_state = StIdle;
m_errorMessage = "AFC error";
}
AFC::~AFC()
{
if (m_worker->isRunning()) {
stop();
}
delete m_worker;
removeTrackerFeatureReference();
removeTrackedFeatureReferences();
}
void AFC::start()
{
qDebug("AFC::start");
m_worker->reset();
m_worker->setMessageQueueToGUI(getMessageQueueToGUI());
bool ok = m_worker->startWork();
m_state = ok ? StRunning : StError;
m_thread.start();
AFCWorker::MsgConfigureAFCWorker *msg = AFCWorker::MsgConfigureAFCWorker::create(m_settings, true);
m_worker->getInputMessageQueue()->push(msg);
}
void AFC::stop()
{
qDebug("AFC::stop");
m_worker->stopWork();
m_state = StIdle;
m_thread.quit();
m_thread.wait();
}
bool AFC::handleMessage(const Message& cmd)
{
if (MsgConfigureAFC::match(cmd))
{
MsgConfigureAFC& cfg = (MsgConfigureAFC&) cmd;
qDebug() << "AFC::handleMessage: MsgConfigureAFC";
applySettings(cfg.getSettings(), cfg.getForce());
return true;
}
else if (MsgStartStop::match(cmd))
{
MsgStartStop& cfg = (MsgStartStop&) cmd;
qDebug() << "AFC::handleMessage: MsgStartStop: start:" << cfg.getStartStop();
if (cfg.getStartStop()) {
start();
} else {
stop();
}
return true;
}
else if (Feature::MsgChannelSettings::match(cmd))
{
Feature::MsgChannelSettings& cfg = (Feature::MsgChannelSettings&) cmd;
SWGSDRangel::SWGChannelSettings *swgChannelSettings = cfg.getSWGSettings();
QString *channelType = swgChannelSettings->getChannelType();
qDebug() << "AFC::handleMessage: Feature::MsgChannelSettings: " << *channelType;
if (m_worker->isRunning())
{
m_worker->getInputMessageQueue()->push(&cfg);
}
else
{
delete swgChannelSettings;
return true;
}
}
else if (MsgDeviceTrack::match(cmd))
{
if (m_worker->isRunning())
{
AFCWorker::MsgDeviceTrack *msg = AFCWorker::MsgDeviceTrack::create();
m_worker->getInputMessageQueue()->push(msg);
}
return true;
}
else if (MsgDevicesApply::match(cmd))
{
removeTrackerFeatureReference();
trackerDeviceChange(m_settings.m_trackerDeviceSetIndex);
removeTrackedFeatureReferences();
trackedDeviceChange(m_settings.m_trackedDeviceSetIndex);
if (m_worker->isRunning())
{
AFCWorker::MsgDevicesApply *msg = AFCWorker::MsgDevicesApply::create();
m_worker->getInputMessageQueue()->push(msg);
}
return true;
}
return false;
}
QByteArray AFC::serialize() const
{
return m_settings.serialize();
}
bool AFC::deserialize(const QByteArray& data)
{
if (m_settings.deserialize(data))
{
MsgConfigureAFC *msg = MsgConfigureAFC::create(m_settings, true);
m_inputMessageQueue.push(msg);
return true;
}
else
{
m_settings.resetToDefaults();
MsgConfigureAFC *msg = MsgConfigureAFC::create(m_settings, true);
m_inputMessageQueue.push(msg);
return false;
}
}
void AFC::applySettings(const AFCSettings& settings, bool force)
{
qDebug() << "AFC::applySettings:"
<< " m_title: " << settings.m_title
<< " m_rgbColor: " << settings.m_rgbColor
<< " m_trackerDeviceSetIndex: " << settings.m_trackerDeviceSetIndex
<< " m_trackedDeviceSetIndex: " << settings.m_trackedDeviceSetIndex
<< " m_hasTargetFrequency: " << settings.m_hasTargetFrequency
<< " m_transverterTarget: " << settings.m_transverterTarget
<< " m_targetFrequency: " << settings.m_targetFrequency
<< " m_freqTolerance: " << settings.m_freqTolerance
<< " m_trackerAdjustPeriod:" << settings.m_trackerAdjustPeriod
<< " force: " << force;
QList<QString> reverseAPIKeys;
if ((m_settings.m_title != settings.m_title) || force) {
reverseAPIKeys.append("title");
}
if ((m_settings.m_rgbColor != settings.m_rgbColor) || force) {
reverseAPIKeys.append("rgbColor");
}
if ((m_settings.m_trackerDeviceSetIndex != settings.m_trackerDeviceSetIndex) || force) {
reverseAPIKeys.append("trackerDeviceSetIndex");
}
if ((m_settings.m_trackedDeviceSetIndex != settings.m_trackedDeviceSetIndex) || force) {
reverseAPIKeys.append("trackedDeviceSetIndex");
}
if ((m_settings.m_hasTargetFrequency != settings.m_hasTargetFrequency) || force) {
reverseAPIKeys.append("hasTargetFrequency");
}
if ((m_settings.m_transverterTarget != settings.m_transverterTarget) || force) {
reverseAPIKeys.append("transverterTarget");
}
if ((m_settings.m_targetFrequency != settings.m_targetFrequency) || force) {
reverseAPIKeys.append("targetFrequency");
}
if ((m_settings.m_freqTolerance != settings.m_freqTolerance) || force) {
reverseAPIKeys.append("freqTolerance");
}
if ((m_settings.m_trackerAdjustPeriod != settings.m_trackerAdjustPeriod) || force) {
reverseAPIKeys.append("trackerAdjustPeriod");
}
if ((m_settings.m_trackerDeviceSetIndex != settings.m_trackerDeviceSetIndex) || force)
{
removeTrackerFeatureReference();
trackerDeviceChange(settings.m_trackerDeviceSetIndex);
}
if ((m_settings.m_trackedDeviceSetIndex != settings.m_trackedDeviceSetIndex) || force)
{
removeTrackedFeatureReferences();
trackedDeviceChange(settings.m_trackedDeviceSetIndex);
}
AFCWorker::MsgConfigureAFCWorker *msg = AFCWorker::MsgConfigureAFCWorker::create(
settings, force
);
m_worker->getInputMessageQueue()->push(msg);
if (settings.m_useReverseAPI)
{
bool fullUpdate = ((m_settings.m_useReverseAPI != settings.m_useReverseAPI) && settings.m_useReverseAPI) ||
(m_settings.m_reverseAPIAddress != settings.m_reverseAPIAddress) ||
(m_settings.m_reverseAPIPort != settings.m_reverseAPIPort) ||
(m_settings.m_reverseAPIFeatureSetIndex != settings.m_reverseAPIFeatureSetIndex) ||
(m_settings.m_reverseAPIFeatureIndex != settings.m_reverseAPIFeatureIndex);
webapiReverseSendSettings(reverseAPIKeys, settings, fullUpdate || force);
}
m_settings = settings;
}
int AFC::webapiRun(bool run,
SWGSDRangel::SWGDeviceState& response,
QString& errorMessage)
{
getFeatureStateStr(*response.getState());
MsgStartStop *msg = MsgStartStop::create(run);
getInputMessageQueue()->push(msg);
return 202;
}
int AFC::webapiSettingsGet(
SWGSDRangel::SWGFeatureSettings& response,
QString& errorMessage)
{
(void) errorMessage;
response.setAfcSettings(new SWGSDRangel::SWGAFCSettings());
response.getAfcSettings()->init();
webapiFormatFeatureSettings(response, m_settings);
return 200;
}
int AFC::webapiSettingsPutPatch(
bool force,
const QStringList& featureSettingsKeys,
SWGSDRangel::SWGFeatureSettings& response,
QString& errorMessage)
{
(void) errorMessage;
AFCSettings settings = m_settings;
webapiUpdateFeatureSettings(settings, featureSettingsKeys, response);
MsgConfigureAFC *msg = MsgConfigureAFC::create(settings, force);
m_inputMessageQueue.push(msg);
qDebug("AFC::webapiSettingsPutPatch: forward to GUI: %p", m_guiMessageQueue);
if (m_guiMessageQueue) // forward to GUI if any
{
MsgConfigureAFC *msgToGUI = MsgConfigureAFC::create(settings, force);
m_guiMessageQueue->push(msgToGUI);
}
webapiFormatFeatureSettings(response, settings);
return 200;
}
int AFC::webapiReportGet(
SWGSDRangel::SWGFeatureReport& response,
QString& errorMessage)
{
(void) errorMessage;
response.setAfcReport(new SWGSDRangel::SWGAFCReport());
response.getAfcReport()->init();
webapiFormatFeatureReport(response);
return 200;
}
int AFC::webapiActionsPost(
const QStringList& featureActionsKeys,
SWGSDRangel::SWGFeatureActions& query,
QString& errorMessage)
{
SWGSDRangel::SWGAFCActions *swgAFCActions = query.getAfcActions();
if (swgAFCActions)
{
if (featureActionsKeys.contains("deviceTrack"))
{
bool deviceTrack = swgAFCActions->getDeviceTrack() != 0;
if (deviceTrack)
{
MsgDeviceTrack *msg = MsgDeviceTrack::create();
getInputMessageQueue()->push(msg);
}
}
if (featureActionsKeys.contains("devicesApply"))
{
bool devicesApply = swgAFCActions->getDevicesApply() != 0;
if (devicesApply)
{
MsgDevicesApply *msg = MsgDevicesApply::create();
getInputMessageQueue()->push(msg);
}
}
return 202;
}
else
{
errorMessage = "Missing AFCActions in query";
return 400;
}
}
void AFC::webapiFormatFeatureSettings(
SWGSDRangel::SWGFeatureSettings& response,
const AFCSettings& settings)
{
if (response.getAfcSettings()->getTitle()) {
*response.getAfcSettings()->getTitle() = settings.m_title;
} else {
response.getAfcSettings()->setTitle(new QString(settings.m_title));
}
response.getAfcSettings()->setRgbColor(settings.m_rgbColor);
response.getAfcSettings()->setTrackerDeviceSetIndex(settings.m_trackerDeviceSetIndex);
response.getAfcSettings()->setTrackedDeviceSetIndex(settings.m_trackedDeviceSetIndex);
response.getAfcSettings()->setHasTargetFrequency(settings.m_hasTargetFrequency);
response.getAfcSettings()->setTransverterTarget(settings.m_transverterTarget);
response.getAfcSettings()->setTargetFrequency(settings.m_targetFrequency);
response.getAfcSettings()->setFreqTolerance(settings.m_freqTolerance);
response.getAfcSettings()->setTrackerAdjustPeriod(settings.m_trackerAdjustPeriod);
response.getAfcSettings()->setUseReverseApi(settings.m_useReverseAPI ? 1 : 0);
if (response.getAfcSettings()->getReverseApiAddress()) {
*response.getAfcSettings()->getReverseApiAddress() = settings.m_reverseAPIAddress;
} else {
response.getAfcSettings()->setReverseApiAddress(new QString(settings.m_reverseAPIAddress));
}
response.getAfcSettings()->setReverseApiPort(settings.m_reverseAPIPort);
response.getAfcSettings()->setReverseApiDeviceIndex(settings.m_reverseAPIFeatureSetIndex);
response.getAfcSettings()->setReverseApiChannelIndex(settings.m_reverseAPIFeatureIndex);
}
void AFC::webapiUpdateFeatureSettings(
AFCSettings& settings,
const QStringList& featureSettingsKeys,
SWGSDRangel::SWGFeatureSettings& response)
{
if (featureSettingsKeys.contains("title")) {
settings.m_title = *response.getAfcSettings()->getTitle();
}
if (featureSettingsKeys.contains("rgbColor")) {
settings.m_rgbColor = response.getAfcSettings()->getRgbColor();
}
if (featureSettingsKeys.contains("trackerDeviceSetIndex")) {
settings.m_trackerDeviceSetIndex = response.getAfcSettings()->getTrackerDeviceSetIndex();
}
if (featureSettingsKeys.contains("trackedDeviceSetIndex")) {
settings.m_trackedDeviceSetIndex = response.getAfcSettings()->getTrackedDeviceSetIndex();
}
if (featureSettingsKeys.contains("hasTargetFrequency")) {
settings.m_hasTargetFrequency = response.getAfcSettings()->getHasTargetFrequency() != 0;
}
if (featureSettingsKeys.contains("hasTargetFrequency")) {
settings.m_hasTargetFrequency = response.getAfcSettings()->getHasTargetFrequency() != 0;
}
if (featureSettingsKeys.contains("targetFrequency")) {
settings.m_targetFrequency = response.getAfcSettings()->getTargetFrequency();
}
if (featureSettingsKeys.contains("freqTolerance")) {
settings.m_freqTolerance = response.getAfcSettings()->getFreqTolerance();
}
if (featureSettingsKeys.contains("trackerAdjustPeriod")) {
settings.m_trackerAdjustPeriod = response.getAfcSettings()->getTrackerAdjustPeriod();
}
if (featureSettingsKeys.contains("useReverseAPI")) {
settings.m_useReverseAPI = response.getAfcSettings()->getUseReverseApi() != 0;
}
if (featureSettingsKeys.contains("reverseAPIAddress")) {
settings.m_reverseAPIAddress = *response.getAfcSettings()->getReverseApiAddress();
}
if (featureSettingsKeys.contains("reverseAPIPort")) {
settings.m_reverseAPIPort = response.getAfcSettings()->getReverseApiPort();
}
if (featureSettingsKeys.contains("reverseAPIDeviceIndex")) {
settings.m_reverseAPIFeatureSetIndex = response.getAfcSettings()->getReverseApiDeviceIndex();
}
if (featureSettingsKeys.contains("reverseAPIChannelIndex")) {
settings.m_reverseAPIFeatureIndex = response.getAfcSettings()->getReverseApiChannelIndex();
}
}
void AFC::webapiFormatFeatureReport(SWGSDRangel::SWGFeatureReport& response)
{
response.getAfcReport()->setTrackerChannelIndex(m_trackerIndexInDeviceSet);
response.getAfcReport()->setTrackerDeviceFrequency(m_worker->getTrackerDeviceFrequency());
response.getAfcReport()->setTrackerChannelOffset(m_worker->getTrackerChannelOffset());
}
void AFC::webapiReverseSendSettings(QList<QString>& channelSettingsKeys, const AFCSettings& settings, bool force)
{
SWGSDRangel::SWGFeatureSettings *swgFeatureSettings = new SWGSDRangel::SWGFeatureSettings();
// swgFeatureSettings->setOriginatorFeatureIndex(getIndexInDeviceSet());
// swgFeatureSettings->setOriginatorFeatureSetIndex(getDeviceSetIndex());
swgFeatureSettings->setFeatureType(new QString("AFC"));
swgFeatureSettings->setAfcSettings(new SWGSDRangel::SWGAFCSettings());
SWGSDRangel::SWGAFCSettings *swgAFCSettings = swgFeatureSettings->getAfcSettings();
// transfer data that has been modified. When force is on transfer all data except reverse API data
if (channelSettingsKeys.contains("title") || force) {
swgAFCSettings->setTitle(new QString(settings.m_title));
}
if (channelSettingsKeys.contains("rgbColor") || force) {
swgAFCSettings->setRgbColor(settings.m_rgbColor);
}
if (channelSettingsKeys.contains("trackerDeviceSetIndex") || force) {
swgAFCSettings->setTrackerDeviceSetIndex(settings.m_trackerDeviceSetIndex);
}
if (channelSettingsKeys.contains("trackedDeviceSetIndex") || force) {
swgAFCSettings->setTrackedDeviceSetIndex(settings.m_trackedDeviceSetIndex);
}
if (channelSettingsKeys.contains("hasTargetFrequency") || force) {
swgAFCSettings->setHasTargetFrequency(settings.m_hasTargetFrequency ? 1 : 0);
}
if (channelSettingsKeys.contains("targetFrequency") || force) {
swgAFCSettings->setTargetFrequency(settings.m_targetFrequency ? 1 : 0);
}
if (channelSettingsKeys.contains("targetFrequency") || force) {
swgAFCSettings->setTargetFrequency(settings.m_targetFrequency);
}
if (channelSettingsKeys.contains("freqTolerance") || force) {
swgAFCSettings->setFreqTolerance(settings.m_freqTolerance);
}
if (channelSettingsKeys.contains("trackerAdjustPeriod") || force) {
swgAFCSettings->setTrackerAdjustPeriod(settings.m_trackerAdjustPeriod);
}
QString channelSettingsURL = QString("http://%1:%2/sdrangel/featureset/%3/feature/%4/settings")
.arg(settings.m_reverseAPIAddress)
.arg(settings.m_reverseAPIPort)
.arg(settings.m_reverseAPIFeatureSetIndex)
.arg(settings.m_reverseAPIFeatureIndex);
m_networkRequest.setUrl(QUrl(channelSettingsURL));
m_networkRequest.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
QBuffer *buffer = new QBuffer();
buffer->open((QBuffer::ReadWrite));
buffer->write(swgFeatureSettings->asJson().toUtf8());
buffer->seek(0);
// Always use PATCH to avoid passing reverse API settings
QNetworkReply *reply = m_networkManager->sendCustomRequest(m_networkRequest, "PATCH", buffer);
buffer->setParent(reply);
delete swgFeatureSettings;
}
void AFC::networkManagerFinished(QNetworkReply *reply)
{
QNetworkReply::NetworkError replyError = reply->error();
if (replyError)
{
qWarning() << "AFC::networkManagerFinished:"
<< " error(" << (int) replyError
<< "): " << replyError
<< ": " << reply->errorString();
}
else
{
QString answer = reply->readAll();
answer.chop(1); // remove last \n
qDebug("AFC::networkManagerFinished: reply:\n%s", answer.toStdString().c_str());
}
reply->deleteLater();
}
void AFC::trackerDeviceChange(int deviceIndex)
{
MainCore *mainCore = MainCore::instance();
m_trackerDeviceSet = mainCore->getDeviceSets()[deviceIndex];
for (int i = 0; i < m_trackerDeviceSet->getNumberOfChannels(); i++)
{
ChannelAPI *channel = m_trackerDeviceSet->getChannelAt(i);
if (channel->getURI() == "sdrangel.channel.freqtracker")
{
channel->addFeatureSettingsFeedback(this);
m_trackerChannelAPI = channel;
break;
}
}
}
void AFC::trackedDeviceChange(int deviceIndex)
{
MainCore *mainCore = MainCore::instance();
m_trackedDeviceSet = mainCore->getDeviceSets()[deviceIndex];
for (int i = 0; i < m_trackedDeviceSet->getNumberOfChannels(); i++)
{
ChannelAPI *channel = m_trackedDeviceSet->getChannelAt(i);
if (channel->getURI() != "sdrangel.channel.freqtracker")
{
channel->addFeatureSettingsFeedback(this);
m_trackerIndexInDeviceSet = i;
}
}
}
void AFC::removeTrackerFeatureReference()
{
if (m_trackerChannelAPI)
{
if (MainCore::instance()->existsChannel(m_trackerChannelAPI)) {
m_trackerChannelAPI->removeFeatureSettingsFeedback(this);
}
}
}
void AFC::removeTrackedFeatureReferences()
{
for (QList<ChannelAPI*>::iterator it = m_trackedChannelAPIs.begin(); it != m_trackedChannelAPIs.end(); ++it)
{
ChannelAPI *channel = *it;
if (MainCore::instance()->existsChannel(channel)) {
channel->removeFeatureSettingsFeedback(this);
}
}
m_trackedChannelAPIs.clear();
}

184
plugins/feature/afc/afc.h Normal file
View File

@ -0,0 +1,184 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2020 Edouard Griffiths, F4EXB //
// //
// This program is free software; you can redistribute it and/or modify //
// it under the terms of the GNU General Public License as published by //
// the Free Software Foundation as version 3 of the License, or //
// (at your option) any later version. //
// //
// This program is distributed in the hope that it will be useful, //
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
// GNU General Public License V3 for more details. //
// //
// You should have received a copy of the GNU General Public License //
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#ifndef INCLUDE_FEATURE_AFC_H_
#define INCLUDE_FEATURE_AFC_H_
#include <QThread>
#include <QNetworkRequest>
#include "feature/feature.h"
#include "util/message.h"
#include "afcsettings.h"
class QNetworkAccessManager;
class QNetworkReply;
class WebAPIAdapterInterface;
class DeviceSet;
class AFCWorker;
namespace SWGSDRangel {
class SWGDeviceState;
}
class AFC : public Feature
{
Q_OBJECT
public:
class MsgConfigureAFC : public Message {
MESSAGE_CLASS_DECLARATION
public:
const AFCSettings& getSettings() const { return m_settings; }
bool getForce() const { return m_force; }
static MsgConfigureAFC* create(const AFCSettings& settings, bool force) {
return new MsgConfigureAFC(settings, force);
}
private:
AFCSettings m_settings;
bool m_force;
MsgConfigureAFC(const AFCSettings& settings, bool force) :
Message(),
m_settings(settings),
m_force(force)
{ }
};
class MsgStartStop : public Message {
MESSAGE_CLASS_DECLARATION
public:
bool getStartStop() const { return m_startStop; }
static MsgStartStop* create(bool startStop) {
return new MsgStartStop(startStop);
}
protected:
bool m_startStop;
MsgStartStop(bool startStop) :
Message(),
m_startStop(startStop)
{ }
};
class MsgDeviceTrack : public Message {
MESSAGE_CLASS_DECLARATION
public:
static MsgDeviceTrack* create() {
return new MsgDeviceTrack();
}
protected:
MsgDeviceTrack() :
Message()
{ }
};
class MsgDevicesApply : public Message {
MESSAGE_CLASS_DECLARATION
public:
static MsgDevicesApply* create() {
return new MsgDevicesApply();
}
protected:
MsgDevicesApply() :
Message()
{ }
};
AFC(WebAPIAdapterInterface *webAPIAdapterInterface);
virtual ~AFC();
virtual void destroy() { delete this; }
virtual bool handleMessage(const Message& cmd);
virtual const QString& getURI() const { return m_featureIdURI; }
virtual void getIdentifier(QString& id) const { id = m_featureId; }
virtual void getTitle(QString& title) const { title = m_settings.m_title; }
virtual QByteArray serialize() const;
virtual bool deserialize(const QByteArray& data);
virtual int webapiRun(bool run,
SWGSDRangel::SWGDeviceState& response,
QString& errorMessage);
virtual int webapiSettingsGet(
SWGSDRangel::SWGFeatureSettings& response,
QString& errorMessage);
virtual int webapiSettingsPutPatch(
bool force,
const QStringList& featureSettingsKeys,
SWGSDRangel::SWGFeatureSettings& response,
QString& errorMessage);
virtual int webapiReportGet(
SWGSDRangel::SWGFeatureReport& response,
QString& errorMessage);
virtual int webapiActionsPost(
const QStringList& featureActionsKeys,
SWGSDRangel::SWGFeatureActions& query,
QString& errorMessage);
static void webapiFormatFeatureSettings(
SWGSDRangel::SWGFeatureSettings& response,
const AFCSettings& settings);
static void webapiUpdateFeatureSettings(
AFCSettings& settings,
const QStringList& featureSettingsKeys,
SWGSDRangel::SWGFeatureSettings& response);
static const QString m_featureIdURI;
static const QString m_featureId;
private:
QThread m_thread;
AFCWorker *m_worker;
AFCSettings m_settings;
DeviceSet *m_trackerDeviceSet;
DeviceSet *m_trackedDeviceSet;
int m_trackerIndexInDeviceSet;
ChannelAPI *m_trackerChannelAPI;
QList<ChannelAPI*> m_trackedChannelAPIs;
QNetworkAccessManager *m_networkManager;
QNetworkRequest m_networkRequest;
void start();
void stop();
void applySettings(const AFCSettings& settings, bool force = false);
void webapiFormatFeatureReport(SWGSDRangel::SWGFeatureReport& response);
void webapiReverseSendSettings(QList<QString>& featureSettingsKeys, const AFCSettings& settings, bool force);
void trackerDeviceChange(int deviceIndex);
void trackedDeviceChange(int deviceIndex);
void removeTrackerFeatureReference();
void removeTrackedFeatureReferences();
private slots:
void networkManagerFinished(QNetworkReply *reply);
};
#endif // INCLUDE_FEATURE_AFC_H_

View File

@ -0,0 +1,417 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2020 Edouard Griffiths, F4EXB //
// //
// This program is free software; you can redistribute it and/or modify //
// it under the terms of the GNU General Public License as published by //
// the Free Software Foundation as version 3 of the License, or //
// (at your option) any later version. //
// //
// This program is distributed in the hope that it will be useful, //
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
// GNU General Public License V3 for more details. //
// //
// You should have received a copy of the GNU General Public License //
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#include <QMessageBox>
#include "feature/featureuiset.h"
#include "device/deviceset.h"
#include "channel/channelapi.h"
#include "gui/basicfeaturesettingsdialog.h"
#include "maincore.h"
#include "ui_afcgui.h"
#include "afcreport.h"
#include "afc.h"
#include "afcgui.h"
AFCGUI* AFCGUI::create(PluginAPI* pluginAPI, FeatureUISet *featureUISet, Feature *feature)
{
AFCGUI* gui = new AFCGUI(pluginAPI, featureUISet, feature);
return gui;
}
void AFCGUI::destroy()
{
delete this;
}
void AFCGUI::resetToDefaults()
{
m_settings.resetToDefaults();
displaySettings();
applySettings(true);
}
QByteArray AFCGUI::serialize() const
{
return m_settings.serialize();
}
bool AFCGUI::deserialize(const QByteArray& data)
{
if (m_settings.deserialize(data))
{
displaySettings();
applySettings(true);
return true;
}
else
{
resetToDefaults();
return false;
}
}
bool AFCGUI::handleMessage(const Message& message)
{
if (AFC::MsgConfigureAFC::match(message))
{
qDebug("AFCGUI::handleMessage: AFC::MsgConfigureAFC");
const AFC::MsgConfigureAFC& cfg = (AFC::MsgConfigureAFC&) message;
m_settings = cfg.getSettings();
blockApplySettings(true);
displaySettings();
blockApplySettings(false);
return true;
}
else if (AFCReport::MsgUpdateTarget::match(message))
{
const AFCReport::MsgUpdateTarget& cfg = (AFCReport::MsgUpdateTarget&) message;
bool frequencyChanged = cfg.getFrequencyChanged();
if (cfg.getFrequencyChanged()) {
ui->statusIndicator->setStyleSheet("QLabel { background-color: rgb(232, 85, 85); border-radius: 8px; }"); // red
} else {
ui->statusIndicator->setStyleSheet("QLabel { background-color: rgb(85, 232, 85); border-radius: 8px; }"); // green
}
ui->statusIndicator->setToolTip(tr("%1 Hz").arg(cfg.getFrequencyAdjustment()));
m_autoTargetStatusTimer.start(500);
return true;
}
return false;
}
void AFCGUI::handleInputMessages()
{
Message* message;
while ((message = getInputMessageQueue()->pop()))
{
if (handleMessage(*message)) {
delete message;
}
}
}
void AFCGUI::onWidgetRolled(QWidget* widget, bool rollDown)
{
(void) widget;
(void) rollDown;
}
AFCGUI::AFCGUI(PluginAPI* pluginAPI, FeatureUISet *featureUISet, Feature *feature, QWidget* parent) :
FeatureGUI(parent),
ui(new Ui::AFCGUI),
m_pluginAPI(pluginAPI),
m_featureUISet(featureUISet),
m_doApplySettings(true),
m_lastFeatureState(0)
{
ui->setupUi(this);
setAttribute(Qt::WA_DeleteOnClose, true);
ui->targetFrequency->setColorMapper(ColorMapper(ColorMapper::GrayGold));
ui->targetFrequency->setValueRange(10, 0, 9999999999L);
ui->toleranceFrequency->setColorMapper(ColorMapper(ColorMapper::GrayYellow));
ui->toleranceFrequency->setValueRange(5, 0, 99999L);
setChannelWidget(false);
connect(this, SIGNAL(widgetRolled(QWidget*,bool)), this, SLOT(onWidgetRolled(QWidget*,bool)));
m_afc = reinterpret_cast<AFC*>(feature);
m_afc->setMessageQueueToGUI(&m_inputMessageQueue);
m_featureUISet->addRollupWidget(this);
connect(this, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(onMenuDialogCalled(const QPoint &)));
connect(getInputMessageQueue(), SIGNAL(messageEnqueued()), this, SLOT(handleInputMessages()));
connect(&m_statusTimer, SIGNAL(timeout()), this, SLOT(updateStatus()));
m_statusTimer.start(1000);
connect(&m_autoTargetStatusTimer, SIGNAL(timeout()), this, SLOT(resetAutoTargetStatus()));
m_autoTargetStatusTimer.setSingleShot(true);
ui->statusIndicator->setStyleSheet("QLabel { background-color: gray; border-radius: 8px; }");
updateDeviceSetLists();
displaySettings();
applySettings(true);
}
AFCGUI::~AFCGUI()
{
delete ui;
}
void AFCGUI::blockApplySettings(bool block)
{
m_doApplySettings = !block;
}
void AFCGUI::displaySettings()
{
setTitleColor(m_settings.m_rgbColor);
setWindowTitle(m_settings.m_title);
blockApplySettings(true);
ui->hasTargetFrequency->setChecked(m_settings.m_hasTargetFrequency);
ui->transverterTarget->setChecked(m_settings.m_transverterTarget);
ui->targetFrequency->setValue(m_settings.m_targetFrequency);
ui->toleranceFrequency->setValue(m_settings.m_freqTolerance);
ui->targetPeriod->setValue(m_settings.m_trackerAdjustPeriod);
ui->targetPeriodText->setText(tr("%1").arg(m_settings.m_trackerAdjustPeriod));
blockApplySettings(false);
}
void AFCGUI::updateDeviceSetLists()
{
MainCore *mainCore = MainCore::instance();
std::vector<DeviceSet*>& deviceSets = mainCore->getDeviceSets();
std::vector<DeviceSet*>::const_iterator it = deviceSets.begin();
ui->trackerDevice->blockSignals(true);
ui->trackedDevice->blockSignals(true);
ui->trackerDevice->clear();
ui->trackedDevice->clear();
unsigned int deviceIndex = 0;
for (; it != deviceSets.end(); ++it, deviceIndex++)
{
DSPDeviceSourceEngine *deviceSourceEngine = (*it)->m_deviceSourceEngine;
DSPDeviceSinkEngine *deviceSinkEngine = (*it)->m_deviceSinkEngine;
if (deviceSourceEngine) {
ui->trackedDevice->addItem(QString("R%1").arg(deviceIndex), deviceIndex);
} else if (deviceSinkEngine) {
ui->trackedDevice->addItem(QString("T%1").arg(deviceIndex), deviceIndex);
}
for (int chi = 0; chi < (*it)->getNumberOfChannels(); chi++)
{
ChannelAPI *channel = (*it)->getChannelAt(chi);
if (channel->getURI() == "sdrangel.channel.freqtracker")
{
ui->trackerDevice->addItem(QString("R%1").arg(deviceIndex), deviceIndex);
break;
}
}
}
int trackedDeviceIndex;
int trackerDeviceIndex;
if (deviceIndex > 0)
{
if (m_settings.m_trackedDeviceSetIndex < 0) {
ui->trackedDevice->setCurrentIndex(0);
} else {
ui->trackedDevice->setCurrentIndex(m_settings.m_trackedDeviceSetIndex);
}
if (m_settings.m_trackerDeviceSetIndex < 0) {
ui->trackerDevice->setCurrentIndex(0);
} else {
ui->trackerDevice->setCurrentIndex(m_settings.m_trackerDeviceSetIndex);
}
trackedDeviceIndex = ui->trackedDevice->currentData().toInt();
trackerDeviceIndex = ui->trackerDevice->currentData().toInt();
}
else
{
trackedDeviceIndex = -1;
trackerDeviceIndex = -1;
}
if ((trackedDeviceIndex != m_settings.m_trackedDeviceSetIndex) ||
(trackerDeviceIndex != m_settings.m_trackerDeviceSetIndex))
{
qDebug("AFCGUI::updateDeviceSetLists: device index changed: %d:%d", trackerDeviceIndex, trackedDeviceIndex);
m_settings.m_trackerDeviceSetIndex = trackerDeviceIndex;
m_settings.m_trackedDeviceSetIndex = trackedDeviceIndex;
applySettings();
}
ui->trackerDevice->blockSignals(false);
ui->trackedDevice->blockSignals(false);
}
void AFCGUI::leaveEvent(QEvent*)
{
}
void AFCGUI::enterEvent(QEvent*)
{
}
void AFCGUI::onMenuDialogCalled(const QPoint &p)
{
if (m_contextMenuType == ContextMenuChannelSettings)
{
BasicFeatureSettingsDialog dialog(this);
dialog.setTitle(m_settings.m_title);
dialog.setColor(m_settings.m_rgbColor);
dialog.setUseReverseAPI(m_settings.m_useReverseAPI);
dialog.setReverseAPIAddress(m_settings.m_reverseAPIAddress);
dialog.setReverseAPIPort(m_settings.m_reverseAPIPort);
dialog.setReverseAPIFeatureSetIndex(m_settings.m_reverseAPIFeatureSetIndex);
dialog.setReverseAPIFeatureIndex(m_settings.m_reverseAPIFeatureIndex);
dialog.move(p);
dialog.exec();
m_settings.m_rgbColor = dialog.getColor().rgb();
m_settings.m_title = dialog.getTitle();
m_settings.m_useReverseAPI = dialog.useReverseAPI();
m_settings.m_reverseAPIAddress = dialog.getReverseAPIAddress();
m_settings.m_reverseAPIPort = dialog.getReverseAPIPort();
m_settings.m_reverseAPIFeatureSetIndex = dialog.getReverseAPIFeatureSetIndex();
m_settings.m_reverseAPIFeatureIndex = dialog.getReverseAPIFeatureIndex();
setWindowTitle(m_settings.m_title);
setTitleColor(m_settings.m_rgbColor);
applySettings();
}
resetContextMenuType();
}
void AFCGUI::on_startStop_toggled(bool checked)
{
if (m_doApplySettings)
{
AFC::MsgStartStop *message = AFC::MsgStartStop::create(checked);
m_afc->getInputMessageQueue()->push(message);
}
}
void AFCGUI::on_hasTargetFrequency_toggled(bool checked)
{
m_settings.m_hasTargetFrequency = checked;
applySettings();
}
void AFCGUI::on_targetFrequency_changed(quint64 value)
{
m_settings.m_targetFrequency = value;
applySettings();
}
void AFCGUI::on_transverterTarget_toggled(bool checked)
{
m_settings.m_transverterTarget = checked;
applySettings();
}
void AFCGUI::on_toleranceFrequency_changed(quint64 value)
{
m_settings.m_freqTolerance = value;
applySettings();
}
void AFCGUI::on_deviceTrack_clicked()
{
AFC::MsgDeviceTrack *msg = AFC::MsgDeviceTrack::create();
m_afc->getInputMessageQueue()->push(msg);
}
void AFCGUI::on_devicesRefresh_clicked()
{
updateDeviceSetLists();
displaySettings();
}
void AFCGUI::on_trackerDevice_currentIndexChanged(int index)
{
if (index >= 0)
{
m_settings.m_trackerDeviceSetIndex = index;
applySettings();
}
}
void AFCGUI::on_trackedDevice_currentIndexChanged(int index)
{
if (index >= 0)
{
m_settings.m_trackedDeviceSetIndex = index;
applySettings();
}
}
void AFCGUI::on_devicesApply_clicked()
{
AFC::MsgDevicesApply *msg = AFC::MsgDevicesApply::create();
m_afc->getInputMessageQueue()->push(msg);
}
void AFCGUI::on_targetPeriod_valueChanged(int value)
{
m_settings.m_trackerAdjustPeriod = value;
ui->targetPeriodText->setText(tr("%1").arg(m_settings.m_trackerAdjustPeriod));
applySettings();
}
void AFCGUI::updateStatus()
{
int state = m_afc->getState();
if (m_lastFeatureState != state)
{
switch (state)
{
case Feature::StNotStarted:
ui->startStop->setStyleSheet("QToolButton { background:rgb(79,79,79); }");
break;
case Feature::StIdle:
ui->startStop->setStyleSheet("QToolButton { background-color : blue; }");
break;
case Feature::StRunning:
ui->startStop->setStyleSheet("QToolButton { background-color : green; }");
break;
case Feature::StError:
ui->startStop->setStyleSheet("QToolButton { background-color : red; }");
QMessageBox::information(this, tr("Message"), m_afc->getErrorMessage());
break;
default:
break;
}
m_lastFeatureState = state;
}
}
void AFCGUI::resetAutoTargetStatus()
{
ui->statusIndicator->setStyleSheet("QLabel { background-color: gray; border-radius: 8px; }");
}
void AFCGUI::applySettings(bool force)
{
if (m_doApplySettings)
{
AFC::MsgConfigureAFC* message = AFC::MsgConfigureAFC::create( m_settings, force);
m_afc->getInputMessageQueue()->push(message);
}
}

View File

@ -0,0 +1,91 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2020 Edouard Griffiths, F4EXB //
// //
// This program is free software; you can redistribute it and/or modify //
// it under the terms of the GNU General Public License as published by //
// the Free Software Foundation as version 3 of the License, or //
// (at your option) any later version. //
// //
// This program is distributed in the hope that it will be useful, //
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
// GNU General Public License V3 for more details. //
// //
// You should have received a copy of the GNU General Public License //
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#ifndef INCLUDE_FEATURE_AFCGUI_H_
#define INCLUDE_FEATURE_AFCGUI_H_
#include <QTimer>
#include "feature/featuregui.h"
#include "util/messagequeue.h"
#include "afcsettings.h"
class PluginAPI;
class FeatureUISet;
class AFC;
namespace Ui {
class AFCGUI;
}
class AFCGUI : public FeatureGUI {
Q_OBJECT
public:
static AFCGUI* create(PluginAPI* pluginAPI, FeatureUISet *featureUISet, Feature *feature);
virtual void destroy();
void resetToDefaults();
QByteArray serialize() const;
bool deserialize(const QByteArray& data);
virtual MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; }
private:
Ui::AFCGUI* ui;
PluginAPI* m_pluginAPI;
FeatureUISet* m_featureUISet;
AFCSettings m_settings;
bool m_doApplySettings;
AFC* m_afc;
MessageQueue m_inputMessageQueue;
QTimer m_statusTimer;
QTimer m_autoTargetStatusTimer;
int m_lastFeatureState;
explicit AFCGUI(PluginAPI* pluginAPI, FeatureUISet *featureUISet, Feature *feature, QWidget* parent = nullptr);
virtual ~AFCGUI();
void blockApplySettings(bool block);
void applySettings(bool force = false);
void displaySettings();
void updateDeviceSetLists();
bool handleMessage(const Message& message);
void leaveEvent(QEvent*);
void enterEvent(QEvent*);
private slots:
void onMenuDialogCalled(const QPoint &p);
void onWidgetRolled(QWidget* widget, bool rollDown);
void handleInputMessages();
void on_startStop_toggled(bool checked);
void on_hasTargetFrequency_toggled(bool checked);
void on_targetFrequency_changed(quint64 value);
void on_transverterTarget_toggled(bool checked);
void on_toleranceFrequency_changed(quint64 value);
void on_deviceTrack_clicked();
void on_devicesRefresh_clicked();
void on_trackerDevice_currentIndexChanged(int index);
void on_trackedDevice_currentIndexChanged(int index);
void on_devicesApply_clicked();
void on_targetPeriod_valueChanged(int value);
void updateStatus();
void resetAutoTargetStatus();
};
#endif // INCLUDE_FEATURE_AFCGUI_H_

View File

@ -0,0 +1,431 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>AFCGUI</class>
<widget class="RollupWidget" name="AFCGUI">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>340</width>
<height>160</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Minimum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>340</width>
<height>100</height>
</size>
</property>
<property name="font">
<font>
<family>Liberation Sans</family>
<pointsize>9</pointsize>
</font>
</property>
<property name="windowTitle">
<string>AFC</string>
</property>
<widget class="QWidget" name="settingsContainer" native="true">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>340</width>
<height>151</height>
</rect>
</property>
<property name="windowTitle">
<string>Settings</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<property name="spacing">
<number>3</number>
</property>
<property name="leftMargin">
<number>2</number>
</property>
<property name="topMargin">
<number>2</number>
</property>
<property name="rightMargin">
<number>2</number>
</property>
<property name="bottomMargin">
<number>2</number>
</property>
<item>
<layout class="QHBoxLayout" name="mainLayout">
<item>
<widget class="ButtonSwitch" name="startStop">
<property name="toolTip">
<string>start/stop acquisition</string>
</property>
<property name="text">
<string/>
</property>
<property name="icon">
<iconset resource="../../../sdrgui/resources/res.qrc">
<normaloff>:/play.png</normaloff>
<normalon>:/stop.png</normalon>:/play.png</iconset>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="devicesRefresh">
<property name="maximumSize">
<size>
<width>24</width>
<height>16777215</height>
</size>
</property>
<property name="toolTip">
<string>Refresh indexes of available device sets</string>
</property>
<property name="text">
<string/>
</property>
<property name="icon">
<iconset resource="../../../sdrgui/resources/res.qrc">
<normaloff>:/recycle.png</normaloff>:/recycle.png</iconset>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="trackerLabel">
<property name="text">
<string>Tracker</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="trackerDevice">
<property name="minimumSize">
<size>
<width>55</width>
<height>0</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>50</width>
<height>16777215</height>
</size>
</property>
<property name="toolTip">
<string>Tracker deviceset index</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="trackedLabel">
<property name="text">
<string>Tracked</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="trackedDevice">
<property name="minimumSize">
<size>
<width>55</width>
<height>0</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>50</width>
<height>16777215</height>
</size>
</property>
<property name="toolTip">
<string>Tracked deviceset index</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="devicesApply">
<property name="maximumSize">
<size>
<width>24</width>
<height>24</height>
</size>
</property>
<property name="toolTip">
<string>Reinitialization of device data</string>
</property>
<property name="text">
<string/>
</property>
<property name="icon">
<iconset resource="../../../sdrgui/resources/res.qrc">
<normaloff>:/arrow_left.png</normaloff>:/arrow_left.png</iconset>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="targetLayout">
<item>
<widget class="ButtonSwitch" name="hasTargetFrequency">
<property name="toolTip">
<string>Tracker target frequency auto adjust</string>
</property>
<property name="text">
<string>T</string>
</property>
</widget>
</item>
<item>
<widget class="ValueDial" name="targetFrequency" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Maximum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>32</width>
<height>16</height>
</size>
</property>
<property name="font">
<font>
<family>Liberation Mono</family>
<pointsize>12</pointsize>
</font>
</property>
<property name="cursor">
<cursorShape>PointingHandCursor</cursorShape>
</property>
<property name="focusPolicy">
<enum>Qt::StrongFocus</enum>
</property>
<property name="toolTip">
<string>Tracker target tracker frequency in Hz</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="targetFrequencyUnits">
<property name="text">
<string>Hz</string>
</property>
</widget>
</item>
<item>
<widget class="ButtonSwitch" name="transverterTarget">
<property name="toolTip">
<string>Use transverter frequency for tracker target frequency adjustment</string>
</property>
<property name="text">
<string>X</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="toleranceLayout">
<item>
<widget class="QLabel" name="toleranceLabel">
<property name="toolTip">
<string/>
</property>
<property name="text">
<string>&amp;plusmn;</string>
</property>
<property name="textFormat">
<enum>Qt::RichText</enum>
</property>
</widget>
</item>
<item>
<widget class="ValueDial" name="toleranceFrequency" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Maximum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>32</width>
<height>16</height>
</size>
</property>
<property name="font">
<font>
<family>Liberation Mono</family>
<pointsize>12</pointsize>
</font>
</property>
<property name="cursor">
<cursorShape>PointingHandCursor</cursorShape>
</property>
<property name="focusPolicy">
<enum>Qt::StrongFocus</enum>
</property>
<property name="toolTip">
<string>Tracker target frequency error tolerance (Hz)</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="toleranceUnits">
<property name="text">
<string>Hz</string>
</property>
</widget>
</item>
<item>
<widget class="QDial" name="targetPeriod">
<property name="maximumSize">
<size>
<width>24</width>
<height>24</height>
</size>
</property>
<property name="toolTip">
<string>Tracker target frequency adjustment period (seconds)</string>
</property>
<property name="minimum">
<number>1</number>
</property>
<property name="maximum">
<number>120</number>
</property>
<property name="pageStep">
<number>1</number>
</property>
<property name="value">
<number>20</number>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="targetPeriodText">
<property name="minimumSize">
<size>
<width>24</width>
<height>0</height>
</size>
</property>
<property name="toolTip">
<string>Tracker target frequency adjustment period (seconds)</string>
</property>
<property name="text">
<string>000</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="deviceTrack">
<property name="maximumSize">
<size>
<width>24</width>
<height>24</height>
</size>
</property>
<property name="toolTip">
<string>Force tracker target frequency adjustment</string>
</property>
<property name="text">
<string/>
</property>
<property name="icon">
<iconset resource="../../../sdrgui/resources/res.qrc">
<normaloff>:/arrow_left.png</normaloff>:/arrow_left.png</iconset>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_3">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QLabel" name="statusIndicator">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Maximum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>16</width>
<height>16</height>
</size>
</property>
<property name="toolTip">
<string>Idle</string>
</property>
<property name="styleSheet">
<string notr="true">QLabel { background-color: gray; border-radius: 8px; }</string>
</property>
<property name="text">
<string/>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</widget>
<customwidgets>
<customwidget>
<class>RollupWidget</class>
<extends>QWidget</extends>
<header>gui/rollupwidget.h</header>
<container>1</container>
</customwidget>
<customwidget>
<class>ButtonSwitch</class>
<extends>QToolButton</extends>
<header>gui/buttonswitch.h</header>
</customwidget>
<customwidget>
<class>ValueDial</class>
<extends>QWidget</extends>
<header>gui/valuedial.h</header>
<container>1</container>
</customwidget>
</customwidgets>
<resources>
<include location="../../../sdrgui/resources/res.qrc"/>
</resources>
<connections/>
</ui>

View File

@ -0,0 +1,80 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2020 Edouard Griffiths, F4EXB //
// //
// This program is free software; you can redistribute it and/or modify //
// it under the terms of the GNU General Public License as published by //
// the Free Software Foundation as version 3 of the License, or //
// (at your option) any later version. //
// //
// This program is distributed in the hope that it will be useful, //
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
// GNU General Public License V3 for more details. //
// //
// You should have received a copy of the GNU General Public License //
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#include <QtPlugin>
#include "plugin/pluginapi.h"
#ifndef SERVER_MODE
#include "afcgui.h"
#endif
#include "afc.h"
#include "afcplugin.h"
#include "afcwebapiadapter.h"
const PluginDescriptor AFCPlugin::m_pluginDescriptor = {
AFC::m_featureId,
QString("AFC"),
QString("4.21.0"),
QString("(c) Edouard Griffiths, F4EXB"),
QString("https://github.com/f4exb/sdrangel"),
true,
QString("https://github.com/f4exb/sdrangel")
};
AFCPlugin::AFCPlugin(QObject* parent) :
QObject(parent),
m_pluginAPI(nullptr)
{
}
const PluginDescriptor& AFCPlugin::getPluginDescriptor() const
{
return m_pluginDescriptor;
}
void AFCPlugin::initPlugin(PluginAPI* pluginAPI)
{
m_pluginAPI = pluginAPI;
// register AFC feature
m_pluginAPI->registerFeature(AFC::m_featureIdURI, AFC::m_featureId, this);
}
#ifdef SERVER_MODE
FeatureGUI* AFCPlugin::createFeatureGUI(FeatureUISet *featureUISet, Feature *feature) const
{
(void) featureUISet;
(void) feature;
return nullptr;
}
#else
FeatureGUI* AFCPlugin::createFeatureGUI(FeatureUISet *featureUISet, Feature *feature) const
{
return AFCGUI::create(m_pluginAPI, featureUISet, feature);
}
#endif
Feature* AFCPlugin::createFeature(WebAPIAdapterInterface* webAPIAdapterInterface) const
{
return new AFC(webAPIAdapterInterface);
}
FeatureWebAPIAdapter* AFCPlugin::createFeatureWebAPIAdapter() const
{
return new AFCWebAPIAdapter();
}

View File

@ -0,0 +1,48 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2020 Edouard Griffiths, F4EXB //
// //
// This program is free software; you can redistribute it and/or modify //
// it under the terms of the GNU General Public License as published by //
// the Free Software Foundation as version 3 of the License, or //
// (at your option) any later version. //
// //
// This program is distributed in the hope that it will be useful, //
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
// GNU General Public License V3 for more details. //
// //
// You should have received a copy of the GNU General Public License //
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#ifndef INCLUDE_FEATURE_AFCPLUGIN_H
#define INCLUDE_FEATURE_AFCPLUGIN_H
#include <QObject>
#include "plugin/plugininterface.h"
class FeatureGUI;
class WebAPIAdapterInterface;
class AFCPlugin : public QObject, PluginInterface {
Q_OBJECT
Q_INTERFACES(PluginInterface)
Q_PLUGIN_METADATA(IID "sdrangel.feature.afc")
public:
explicit AFCPlugin(QObject* parent = nullptr);
const PluginDescriptor& getPluginDescriptor() const;
void initPlugin(PluginAPI* pluginAPI);
virtual FeatureGUI* createFeatureGUI(FeatureUISet *featureUISet, Feature *feature) const;
virtual Feature* createFeature(WebAPIAdapterInterface *webAPIAdapterInterface) const;
virtual FeatureWebAPIAdapter* createFeatureWebAPIAdapter() const;
private:
static const PluginDescriptor m_pluginDescriptor;
PluginAPI* m_pluginAPI;
};
#endif // INCLUDE_FEATURE_AFCPLUGIN_H

View File

@ -0,0 +1,26 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2020 Edouard Griffiths, F4EXB //
// //
// This program is free software; you can redistribute it and/or modify //
// it under the terms of the GNU General Public License as published by //
// the Free Software Foundation as version 3 of the License, or //
// (at your option) any later version. //
// //
// This program is distributed in the hope that it will be useful, //
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
// GNU General Public License V3 for more details. //
// //
// You should have received a copy of the GNU General Public License //
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#include "afcreport.h"
MESSAGE_CLASS_DEFINITION(AFCReport::MsgUpdateTarget, Message)
AFCReport::AFCReport()
{}
AFCReport::~AFCReport()
{}

View File

@ -0,0 +1,58 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2020 Edouard Griffiths, F4EXB //
// //
// This program is free software; you can redistribute it and/or modify //
// it under the terms of the GNU General Public License as published by //
// the Free Software Foundation as version 3 of the License, or //
// (at your option) any later version. //
// //
// This program is distributed in the hope that it will be useful, //
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
// GNU General Public License V3 for more details. //
// //
// You should have received a copy of the GNU General Public License //
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#ifndef INCLUDE_FEATURE_AFCREPORT_H_
#define INCLUDE_FEATURE_AFCREPORT_H_
#include "util/message.h"
class AFCReport
{
public:
enum RadioState {
RadioIdle,
RadioRx,
RadioTx
};
class MsgUpdateTarget : public Message {
MESSAGE_CLASS_DECLARATION
public:
int getFrequencyAdjustment() const { return m_frequencyAdjustment; }
bool getFrequencyChanged() const { return m_frequencyChanged; }
static MsgUpdateTarget* create(int frequencyAdjustment, bool frequencyChanged)
{
return new MsgUpdateTarget(frequencyAdjustment, frequencyChanged);
}
private:
int m_frequencyAdjustment;
bool m_frequencyChanged;
MsgUpdateTarget(int frequencyAdjustment, bool frequencyChanged) :
Message(),
m_frequencyAdjustment(frequencyAdjustment),
m_frequencyChanged(frequencyChanged)
{ }
};
AFCReport();
~AFCReport();
};
#endif // INCLUDE_FEATURE_AFCREPORT_H_

View File

@ -0,0 +1,118 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2020 Edouard Griffiths, F4EXB //
// //
// This program is free software; you can redistribute it and/or modify //
// it under the terms of the GNU General Public License as published by //
// the Free Software Foundation as version 3 of the License, or //
// (at your option) any later version. //
// //
// This program is distributed in the hope that it will be useful, //
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
// GNU General Public License V3 for more details. //
// //
// You should have received a copy of the GNU General Public License //
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#include <QColor>
#include "util/simpleserializer.h"
#include "settings/serializable.h"
#include "afcsettings.h"
AFCSettings::AFCSettings()
{
resetToDefaults();
}
void AFCSettings::resetToDefaults()
{
m_title = "AFC";
m_rgbColor = QColor(255, 255, 0).rgb();
m_trackerDeviceSetIndex = -1;
m_trackedDeviceSetIndex = -1;
m_hasTargetFrequency = false;
m_transverterTarget = false;
m_targetFrequency = 0;
m_freqTolerance = 1000;
m_trackerAdjustPeriod = 20;
m_useReverseAPI = false;
m_reverseAPIAddress = "127.0.0.1";
m_reverseAPIPort = 8888;
m_reverseAPIFeatureSetIndex = 0;
m_reverseAPIFeatureIndex = 0;
}
QByteArray AFCSettings::serialize() const
{
SimpleSerializer s(1);
s.writeString(1, m_title);
s.writeU32(2, m_rgbColor);
s.writeS32(3, m_trackerDeviceSetIndex);
s.writeU32(4, m_trackerAdjustPeriod);
s.writeS32(5, m_trackedDeviceSetIndex);
s.writeBool(6, m_hasTargetFrequency);
s.writeBool(7, m_transverterTarget);
s.writeU64(8, m_targetFrequency);
s.writeU64(9, m_freqTolerance);
s.writeBool(10, m_useReverseAPI);
s.writeString(11, m_reverseAPIAddress);
s.writeU32(12, m_reverseAPIPort);
s.writeU32(13, m_reverseAPIFeatureSetIndex);
s.writeU32(14, m_reverseAPIFeatureIndex);
return s.final();
}
bool AFCSettings::deserialize(const QByteArray& data)
{
SimpleDeserializer d(data);
if(!d.isValid())
{
resetToDefaults();
return false;
}
if(d.getVersion() == 1)
{
QByteArray bytetmp;
qint32 tmp;
uint32_t utmp;
QString strtmp;
d.readString(1, &m_title, "AFC");
d.readU32(2, &m_rgbColor, QColor(255, 255, 0).rgb());
d.readS32(3, &m_trackerDeviceSetIndex, -1);
d.readU32(4, &m_trackerAdjustPeriod, 20);
d.readS32(5, &m_trackedDeviceSetIndex, -1);
d.readBool(6, &m_hasTargetFrequency, false);
d.readBool(7, &m_transverterTarget, false);
d.readU64(8, &m_targetFrequency, 0);
d.readU64(9, &m_freqTolerance, 1000);
d.readBool(10, &m_useReverseAPI, false);
d.readString(11, &m_reverseAPIAddress, "127.0.0.1");
d.readU32(12, &utmp, 0);
if ((utmp > 1023) && (utmp < 65535)) {
m_reverseAPIPort = utmp;
} else {
m_reverseAPIPort = 8888;
}
d.readU32(13, &utmp, 0);
m_reverseAPIFeatureSetIndex = utmp > 99 ? 99 : utmp;
d.readU32(14, &utmp, 0);
m_reverseAPIFeatureIndex = utmp > 99 ? 99 : utmp;
return true;
}
else
{
resetToDefaults();
return false;
}
}

View File

@ -0,0 +1,49 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2020 Edouard Griffiths, F4EXB //
// //
// This program is free software; you can redistribute it and/or modify //
// it under the terms of the GNU General Public License as published by //
// the Free Software Foundation as version 3 of the License, or //
// (at your option) any later version. //
// //
// This program is distributed in the hope that it will be useful, //
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
// GNU General Public License V3 for more details. //
// //
// You should have received a copy of the GNU General Public License //
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#ifndef INCLUDE_FEATURE_AFCSETTINGS_H_
#define INCLUDE_FEATURE_AFCSETTINGS_H_
#include <QByteArray>
#include <QString>
class Serializable;
struct AFCSettings
{
QString m_title;
quint32 m_rgbColor;
int m_trackerDeviceSetIndex; //!< will take the first instance of freq tracker in the list of channels
int m_trackedDeviceSetIndex;
bool m_hasTargetFrequency;
bool m_transverterTarget;
quint64 m_targetFrequency;
quint64 m_freqTolerance;
unsigned int m_trackerAdjustPeriod; //!< tracker channel frequency adjustment period in seconds
bool m_useReverseAPI;
QString m_reverseAPIAddress;
uint16_t m_reverseAPIPort;
uint16_t m_reverseAPIFeatureSetIndex;
uint16_t m_reverseAPIFeatureIndex;
AFCSettings();
void resetToDefaults();
QByteArray serialize() const;
bool deserialize(const QByteArray& data);
};
#endif // INCLUDE_FEATURE_AFCSETTINGS_H_

View File

@ -0,0 +1,50 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2020 Edouard Griffiths, F4EXB. //
// //
// This program is free software; you can redistribute it and/or modify //
// it under the terms of the GNU General Public License as published by //
// the Free Software Foundation as version 3 of the License, or //
// (at your option) any later version. //
// //
// This program is distributed in the hope that it will be useful, //
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
// GNU General Public License V3 for more details. //
// //
// You should have received a copy of the GNU General Public License //
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#include "SWGFeatureSettings.h"
#include "afc.h"
#include "afcwebapiadapter.h"
AFCWebAPIAdapter::AFCWebAPIAdapter()
{}
AFCWebAPIAdapter::~AFCWebAPIAdapter()
{}
int AFCWebAPIAdapter::webapiSettingsGet(
SWGSDRangel::SWGFeatureSettings& response,
QString& errorMessage)
{
(void) errorMessage;
response.setAfcSettings(new SWGSDRangel::SWGAFCSettings());
response.getAfcSettings()->init();
AFC::webapiFormatFeatureSettings(response, m_settings);
return 200;
}
int AFCWebAPIAdapter::webapiSettingsPutPatch(
bool force,
const QStringList& featureSettingsKeys,
SWGSDRangel::SWGFeatureSettings& response,
QString& errorMessage)
{
(void) errorMessage;
AFC::webapiUpdateFeatureSettings(m_settings, featureSettingsKeys, response);
return 200;
}

View File

@ -0,0 +1,49 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2020 Edouard Griffiths, F4EXB. //
// //
// This program is free software; you can redistribute it and/or modify //
// it under the terms of the GNU General Public License as published by //
// the Free Software Foundation as version 3 of the License, or //
// (at your option) any later version. //
// //
// This program is distributed in the hope that it will be useful, //
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
// GNU General Public License V3 for more details. //
// //
// You should have received a copy of the GNU General Public License //
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#ifndef INCLUDE_AFC_WEBAPIADAPTER_H
#define INCLUDE_AFC_WEBAPIADAPTER_H
#include "feature/featurewebapiadapter.h"
#include "afcsettings.h"
/**
* Standalone API adapter only for the settings
*/
class AFCWebAPIAdapter : public FeatureWebAPIAdapter {
public:
AFCWebAPIAdapter();
virtual ~AFCWebAPIAdapter();
virtual QByteArray serialize() const { return m_settings.serialize(); }
virtual bool deserialize(const QByteArray& data) { return m_settings.deserialize(data); }
virtual int webapiSettingsGet(
SWGSDRangel::SWGFeatureSettings& response,
QString& errorMessage);
virtual int webapiSettingsPutPatch(
bool force,
const QStringList& featureSettingsKeys,
SWGSDRangel::SWGFeatureSettings& response,
QString& errorMessage);
private:
AFCSettings m_settings;
};
#endif // INCLUDE_AFC_WEBAPIADAPTER_H

View File

@ -0,0 +1,532 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2020 Edouard Griffiths, F4EXB //
// //
// This program is free software; you can redistribute it and/or modify //
// it under the terms of the GNU General Public License as published by //
// the Free Software Foundation as version 3 of the License, or //
// (at your option) any later version. //
// //
// This program is distributed in the hope that it will be useful, //
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
// GNU General Public License V3 for more details. //
// //
// You should have received a copy of the GNU General Public License //
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#include <QDebug>
#include "SWGDeviceState.h"
#include "SWGSuccessResponse.h"
#include "SWGDeviceSettings.h"
#include "SWGChannelSettings.h"
#include "SWGErrorResponse.h"
#include "webapi/webapiadapterinterface.h"
#include "webapi/webapiutils.h"
#include "device/deviceset.h"
#include "device/deviceapi.h"
#include "channel/channelapi.h"
#include "feature/feature.h"
#include "maincore.h"
#include "afcreport.h"
#include "afcworker.h"
MESSAGE_CLASS_DEFINITION(AFCWorker::MsgConfigureAFCWorker, Message)
MESSAGE_CLASS_DEFINITION(AFCWorker::MsgTrackedDeviceChange, Message)
MESSAGE_CLASS_DEFINITION(AFCWorker::MsgDeviceTrack, Message)
MESSAGE_CLASS_DEFINITION(AFCWorker::MsgDevicesApply, Message)
AFCWorker::AFCWorker(WebAPIAdapterInterface *webAPIAdapterInterface) :
m_webAPIAdapterInterface(webAPIAdapterInterface),
m_msgQueueToGUI(nullptr),
m_running(false),
m_freqTracker(nullptr),
m_trackerDeviceFrequency(0),
m_trackerChannelOffset(0),
m_mutex(QMutex::Recursive)
{
qDebug("AFCWorker::AFCWorker");
connect(&m_updateTimer, SIGNAL(timeout()), this, SLOT(updateTarget()));
if (m_settings.m_hasTargetFrequency) {
m_updateTimer.start(m_settings.m_trackerAdjustPeriod * 1000);
}
}
AFCWorker::~AFCWorker()
{
m_inputMessageQueue.clear();
}
void AFCWorker::reset()
{
QMutexLocker mutexLocker(&m_mutex);
m_inputMessageQueue.clear();
}
bool AFCWorker::startWork()
{
QMutexLocker mutexLocker(&m_mutex);
connect(&m_inputMessageQueue, SIGNAL(messageEnqueued()), this, SLOT(handleInputMessages()));
m_running = true;
return m_running;
}
void AFCWorker::stopWork()
{
QMutexLocker mutexLocker(&m_mutex);
disconnect(&m_inputMessageQueue, SIGNAL(messageEnqueued()), this, SLOT(handleInputMessages()));
m_running = false;
}
void AFCWorker::handleInputMessages()
{
Message* message;
while ((message = m_inputMessageQueue.pop()) != nullptr)
{
if (handleMessage(*message)) {
delete message;
}
}
}
bool AFCWorker::handleMessage(const Message& cmd)
{
if (MsgConfigureAFCWorker::match(cmd))
{
qDebug() << "AFCWorker::handleMessage: MsgConfigureAFCWorker";
QMutexLocker mutexLocker(&m_mutex);
MsgConfigureAFCWorker& cfg = (MsgConfigureAFCWorker&) cmd;
applySettings(cfg.getSettings(), cfg.getForce());
return true;
}
else if (Feature::MsgChannelSettings::match(cmd))
{
QMutexLocker mutexLocker(&m_mutex);
Feature::MsgChannelSettings& cfg = (Feature::MsgChannelSettings&) cmd;
SWGSDRangel::SWGChannelSettings *swgChannelSettings = cfg.getSWGSettings();
qDebug() << "AFCWorker::handleMessage: Feature::MsgChannelSettings:" << *swgChannelSettings->getChannelType();
processChannelSettings(cfg.getChannelAPI(), cfg.getChannelSettingsKeys(), swgChannelSettings);
delete swgChannelSettings;
return true;
}
else if (MsgDeviceTrack::match(cmd))
{
qDebug() << "AFCWorker::handleMessage: MsgDeviceTrack";
QMutexLocker mutexLocker(&m_mutex);
updateTarget();
return true;
}
else if (MsgDevicesApply::match(cmd))
{
qDebug() << "AFCWorker::handleMessage: MsgDevicesApply";
QMutexLocker mutexLocker(&m_mutex);
initTrackerDeviceSet(m_settings.m_trackerDeviceSetIndex);
initTrackedDeviceSet(m_settings.m_trackedDeviceSetIndex);
return true;
}
else
{
return false;
}
}
void AFCWorker::applySettings(const AFCSettings& settings, bool force)
{
qDebug() << "AFCWorker::applySettings:"
<< " m_title: " << settings.m_title
<< " m_rgbColor: " << settings.m_rgbColor
<< " m_trackerDeviceSetIndex: " << settings.m_trackerDeviceSetIndex
<< " m_trackedDeviceSetIndex: " << settings.m_trackedDeviceSetIndex
<< " m_hasTargetFrequency: " << settings.m_hasTargetFrequency
<< " m_transverterTarget: " << settings.m_transverterTarget
<< " m_targetFrequency: " << settings.m_targetFrequency
<< " m_freqTolerance: " << settings.m_freqTolerance
<< " force: " << force;
if ((settings.m_trackerDeviceSetIndex != m_settings.m_trackerDeviceSetIndex) || force) {
initTrackerDeviceSet(settings.m_trackerDeviceSetIndex);
}
if ((settings.m_trackedDeviceSetIndex != m_settings.m_trackedDeviceSetIndex) || force) {
initTrackedDeviceSet(settings.m_trackedDeviceSetIndex);
}
if ((settings.m_trackerAdjustPeriod != m_settings.m_trackerAdjustPeriod) || force) {
m_updateTimer.setInterval(settings.m_trackerAdjustPeriod * 1000);
}
if ((settings.m_hasTargetFrequency != m_settings.m_hasTargetFrequency) || force)
{
if (settings.m_hasTargetFrequency) {
m_updateTimer.start(m_settings.m_trackerAdjustPeriod * 1000);
} else {
m_updateTimer.stop();
}
}
m_settings = settings;
}
void AFCWorker::initTrackerDeviceSet(int deviceSetIndex)
{
MainCore *mainCore = MainCore::instance();
m_trackerDeviceSet = mainCore->getDeviceSets()[deviceSetIndex];
for (int i = 0; i < m_trackerDeviceSet->getNumberOfChannels(); i++)
{
ChannelAPI *channel = m_trackerDeviceSet->getChannelAt(i);
if (channel->getURI() == "sdrangel.channel.freqtracker")
{
m_freqTracker = channel;
SWGSDRangel::SWGDeviceSettings resDevice;
SWGSDRangel::SWGChannelSettings resChannel;
SWGSDRangel::SWGErrorResponse error;
int rc = m_webAPIAdapterInterface->devicesetDeviceSettingsGet(deviceSetIndex, resDevice, error);
if (rc / 100 == 2)
{
QJsonObject *jsonObj = resDevice.asJsonObject();
QJsonValue freqValue;
if (WebAPIUtils::extractValue(*jsonObj, "centerFrequency", freqValue))
{
double freq = freqValue.toDouble();
m_trackerDeviceFrequency = freq;
}
else
{
qDebug() << "AFCWorker::initTrackerDeviceSet: cannot find device frequency";
}
}
else
{
qDebug() << "AFCWorker::initTrackerDeviceSet: devicesetDeviceSettingsGet error" << rc << ":" << *error.getMessage();
}
rc = m_webAPIAdapterInterface->devicesetChannelSettingsGet(deviceSetIndex, i, resChannel, error);
if (rc / 100 == 2) {
m_trackerChannelOffset = resChannel.getFreqTrackerSettings()->getInputFrequencyOffset();
} else {
qDebug() << "AFCWorker::initTrackerDeviceSet: devicesetChannelSettingsGet error" << rc << ":" << *error.getMessage();
}
break;
}
}
}
void AFCWorker::initTrackedDeviceSet(int deviceSetIndex)
{
MainCore *mainCore = MainCore::instance();
m_trackedDeviceSet = mainCore->getDeviceSets()[deviceSetIndex];
m_channelsMap.clear();
for (int i = 0; i < m_trackedDeviceSet->getNumberOfChannels(); i++)
{
ChannelAPI *channel = m_trackedDeviceSet->getChannelAt(i);
if (channel->getURI() != "sdrangel.channel.freqtracker")
{
SWGSDRangel::SWGChannelSettings resChannel;
SWGSDRangel::SWGErrorResponse error;
int rc = m_webAPIAdapterInterface->devicesetChannelSettingsGet(deviceSetIndex, i, resChannel, error);
if (rc / 100 == 2)
{
QJsonObject *jsonObj = resChannel.asJsonObject();
QJsonValue directionValue;
QJsonValue channelOffsetValue;
if (WebAPIUtils::extractValue(*jsonObj, "direction", directionValue))
{
int direction = directionValue.toInt();
if (WebAPIUtils::extractValue(*jsonObj, "inputFrequencyOffset", channelOffsetValue))
{
int channelOffset = channelOffsetValue.toInt();
m_channelsMap.insert(channel, ChannelTracking{channelOffset, m_trackerChannelOffset, direction});
}
else
{
qDebug() << "AFCWorker::initTrackedDeviceSet: cannot find channel offset frequency";
}
}
else
{
qDebug() << "AFCWorker::initTrackedDeviceSet: cannot find channel direction";
}
}
else
{
qDebug() << "AFCWorker::initTrackedDeviceSet: devicesetChannelSettingsGet error" << rc << ":" << *error.getMessage();
}
}
}
}
void AFCWorker::processChannelSettings(
const ChannelAPI *channelAPI,
const QList<QString> &channelSettingsKeys,
SWGSDRangel::SWGChannelSettings *swgChannelSettings)
{
MainCore *mainCore = MainCore::instance();
QJsonObject *jsonObj = swgChannelSettings->asJsonObject();
QJsonValue channelOffsetValue;
if (WebAPIUtils::extractValue(*jsonObj, "inputFrequencyOffset", channelOffsetValue))
{
if (*swgChannelSettings->getChannelType() == "FreqTracker")
{
int trackerChannelOffset = channelOffsetValue.toInt();
if (trackerChannelOffset != m_trackerChannelOffset)
{
qDebug("AFCWorker::processChannelSettings: FreqTracker offset change: %d", trackerChannelOffset);
m_trackerChannelOffset = trackerChannelOffset;
QMap<ChannelAPI*, ChannelTracking>::iterator it = m_channelsMap.begin();
for (; it != m_channelsMap.end(); ++it)
{
if (mainCore->existsChannel(it.key()))
{
int channelOffset = it.value().m_channelOffset + trackerChannelOffset - it.value().m_trackerOffset;
updateChannelOffset(it.key(), it.value().m_channelDirection, channelOffset);
}
else
{
m_channelsMap.erase(it);
}
}
}
}
else if (m_channelsMap.contains(const_cast<ChannelAPI*>(channelAPI)))
{
int channelOffset = channelOffsetValue.toInt();
m_channelsMap[const_cast<ChannelAPI*>(channelAPI)].m_channelOffset = channelOffset;
m_channelsMap[const_cast<ChannelAPI*>(channelAPI)].m_trackerOffset = m_trackerChannelOffset;
}
}
}
bool AFCWorker::updateChannelOffset(ChannelAPI *channelAPI, int direction, int offset, unsigned int blockCount)
{
SWGSDRangel::SWGChannelSettings swgChannelSettings;
SWGSDRangel::SWGErrorResponse errorResponse;
QString channelId;
channelAPI->getIdentifier(channelId);
swgChannelSettings.init();
qDebug() << "AFCWorker::updateChannelOffset:" << channelId << ":" << offset;
QStringList channelSettingsKeys;
channelSettingsKeys.append("inputFrequencyOffset");
QString jsonSettingsStr = tr("\"inputFrequencyOffset\":%1").arg(offset);
QString jsonStr = tr("{ \"channelType\": \"%1\", \"direction\": \"%2\", \"%3Settings\": {%4}}")
.arg(QString(channelId))
.arg(direction)
.arg(QString(channelId))
.arg(jsonSettingsStr);
swgChannelSettings.fromJson(jsonStr);
channelAPI->setFeatureSettingsFeedbackBlockCount(1);
int httpRC = m_webAPIAdapterInterface->devicesetChannelSettingsPutPatch(
m_trackedDeviceSet->getIndex(),
channelAPI->getIndexInDeviceSet(),
false, // PATCH
channelSettingsKeys,
swgChannelSettings,
errorResponse
);
if (httpRC / 100 != 2)
{
qDebug() << "AFCWorker::updateChannelOffset: error code" << httpRC << ":" << *errorResponse.getMessage();
return false;
}
return true;
}
void AFCWorker::updateTarget()
{
SWGSDRangel::SWGDeviceSettings resDevice;
SWGSDRangel::SWGChannelSettings resChannel;
SWGSDRangel::SWGErrorResponse error;
int rc = m_webAPIAdapterInterface->devicesetDeviceSettingsGet(m_settings.m_trackerDeviceSetIndex, resDevice, error);
if (rc / 100 == 2)
{
QJsonObject *jsonObj = resDevice.asJsonObject();
QJsonValue freqValue;
if (WebAPIUtils::extractValue(*jsonObj, "centerFrequency", freqValue))
{
double freq = freqValue.toDouble();
m_trackerDeviceFrequency = freq;
}
else
{
qDebug() << "AFCWorker::updateTarget: cannot find device frequency";
return;
}
}
else
{
qDebug() << "AFCWorker::updateTarget: devicesetDeviceSettingsGet error" << rc << ":" << *error.getMessage();
return;
}
int64_t trackerFrequency = m_trackerDeviceFrequency + m_trackerChannelOffset;
int64_t correction = m_settings.m_targetFrequency - trackerFrequency;
int64_t tolerance = m_settings.m_freqTolerance;
if ((correction > -tolerance) && (correction < tolerance))
{
reportUpdateTarget(correction, false);
return;
}
if (m_settings.m_transverterTarget) // act on transverter
{
QJsonObject *jsonObj = resDevice.asJsonObject();
QJsonValue xverterFrequencyValue;
// adjust transverter
if (WebAPIUtils::extractValue(*jsonObj, "transverterDeltaFrequency", xverterFrequencyValue))
{
double xverterFrequency = xverterFrequencyValue.toDouble();
updateDeviceFrequency(m_trackerDeviceSet, "transverterDeltaFrequency", xverterFrequency + correction);
}
else
{
qDebug() << "AFCWorker::updateTarget: cannot find device transverter frequency";
return;
}
// adjust tracker offset
if (updateChannelOffset(m_freqTracker, 0, m_trackerChannelOffset + correction, 1)) {
m_trackerChannelOffset += correction;
}
reportUpdateTarget(correction, true);
}
else // act on device
{
QJsonObject *jsonObj = resDevice.asJsonObject();
QJsonValue deviceFrequencyValue;
if (WebAPIUtils::extractValue(*jsonObj, "centerFrequency", deviceFrequencyValue))
{
double deviceFrequency = deviceFrequencyValue.toDouble();
updateDeviceFrequency(m_trackerDeviceSet, "centerFrequency", deviceFrequency + correction);
}
else
{
qDebug() << "AFCWorker::updateTarget: cannot find device transverter frequency";
return;
}
reportUpdateTarget(correction, true);
}
}
bool AFCWorker::updateDeviceFrequency(DeviceSet *deviceSet, const QString& key, int64_t frequency)
{
SWGSDRangel::SWGDeviceSettings swgDeviceSettings;
SWGSDRangel::SWGErrorResponse errorResponse;
QStringList deviceSettingsKeys;
deviceSettingsKeys.append(key);
int deviceIndex = deviceSet->getIndex();
DeviceAPI *deviceAPI = deviceSet->m_deviceAPI;
swgDeviceSettings.init();
QString jsonSettingsStr = tr("\"%1\":%2").arg(key).arg(frequency);
QString deviceSettingsKey;
getDeviceSettingsKey(deviceAPI, deviceSettingsKey);
qDebug() << "AFCWorker::updateDeviceFrequency:"
<< deviceAPI->getHardwareId()
<< ":" << key
<< ":" << frequency;
QString jsonStr = tr("{ \"deviceHwType\": \"%1\", \"direction\": \"%2\", \"%3\": {%4}}")
.arg(deviceAPI->getHardwareId())
.arg(getDeviceDirection(deviceAPI))
.arg(deviceSettingsKey)
.arg(jsonSettingsStr);
swgDeviceSettings.fromJson(jsonStr);
int httpRC = m_webAPIAdapterInterface->devicesetDeviceSettingsPutPatch
(
deviceIndex,
false, // PATCH
deviceSettingsKeys,
swgDeviceSettings,
errorResponse
);
if (httpRC / 100 != 2)
{
qDebug("AFCWorker::updateDeviceFrequency: error %d: %s", httpRC, qPrintable(*errorResponse.getMessage()));
return false;
}
return true;
}
int AFCWorker::getDeviceDirection(DeviceAPI *deviceAPI)
{
if (deviceAPI->getSampleSink()) {
return 1;
} else if (deviceAPI->getSampleMIMO()) {
return 2;
}
return 0;
}
void AFCWorker::getDeviceSettingsKey(DeviceAPI *deviceAPI, QString& settingsKey)
{
const QString& deviceHwId = deviceAPI->getHardwareId();
if (deviceAPI->getSampleSink())
{
if (WebAPIUtils::m_sinkDeviceHwIdToSettingsKey.contains(deviceHwId)) {
settingsKey = WebAPIUtils::m_sinkDeviceHwIdToSettingsKey[deviceHwId];
}
}
else if (deviceAPI->getSampleMIMO())
{
if (WebAPIUtils::m_mimoDeviceHwIdToSettingsKey.contains(deviceHwId)) {
settingsKey = WebAPIUtils::m_mimoDeviceHwIdToSettingsKey[deviceHwId];
}
}
else
{
if (WebAPIUtils::m_sourceDeviceHwIdToSettingsKey.contains(deviceHwId)) {
settingsKey = WebAPIUtils::m_sourceDeviceHwIdToSettingsKey[deviceHwId];
}
}
}
void AFCWorker::reportUpdateTarget(int correction, bool done)
{
if (m_msgQueueToGUI)
{
AFCReport::MsgUpdateTarget *msg = AFCReport::MsgUpdateTarget::create(correction, done);
m_msgQueueToGUI->push(msg);
}
}

View File

@ -0,0 +1,178 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2020 Edouard Griffiths, F4EXB //
// //
// This program is free software; you can redistribute it and/or modify //
// it under the terms of the GNU General Public License as published by //
// the Free Software Foundation as version 3 of the License, or //
// (at your option) any later version. //
// //
// This program is distributed in the hope that it will be useful, //
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
// GNU General Public License V3 for more details. //
// //
// You should have received a copy of the GNU General Public License //
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#ifndef INCLUDE_FEATURE_AFCWORKER_H_
#define INCLUDE_FEATURE_AFCWORKER_H_
#include <QObject>
#include <QMap>
#include <QTimer>
#include "util/message.h"
#include "util/messagequeue.h"
#include "afcsettings.h"
class WebAPIAdapterInterface;
class DeviceSet;
class ChannelAPI;
class AFCWorker : public QObject
{
Q_OBJECT
public:
class MsgConfigureAFCWorker : public Message {
MESSAGE_CLASS_DECLARATION
public:
const AFCSettings& getSettings() const { return m_settings; }
bool getForce() const { return m_force; }
static MsgConfigureAFCWorker* create(const AFCSettings& settings, bool force)
{
return new MsgConfigureAFCWorker(settings, force);
}
private:
AFCSettings m_settings;
bool m_force;
MsgConfigureAFCWorker(const AFCSettings& settings, bool force) :
Message(),
m_settings(settings),
m_force(force)
{ }
};
class MsgTrackedDeviceChange : public Message {
MESSAGE_CLASS_DECLARATION
public:
int getDeviceIndex() const { return m_deviceIndex; }
static MsgTrackedDeviceChange* create(int deviceIndex)
{
return new MsgTrackedDeviceChange(deviceIndex);
}
private:
int m_deviceIndex;
MsgTrackedDeviceChange(int deviceIndex) :
Message(),
m_deviceIndex(deviceIndex)
{ }
};
class MsgDeviceTrack : public Message {
MESSAGE_CLASS_DECLARATION
public:
static MsgDeviceTrack* create() {
return new MsgDeviceTrack();
}
protected:
MsgDeviceTrack() :
Message()
{ }
};
class MsgDevicesApply : public Message {
MESSAGE_CLASS_DECLARATION
public:
static MsgDevicesApply* create() {
return new MsgDevicesApply();
}
protected:
MsgDevicesApply() :
Message()
{ }
};
AFCWorker(WebAPIAdapterInterface *webAPIAdapterInterface);
~AFCWorker();
void reset();
bool startWork();
void stopWork();
bool isRunning() const { return m_running; }
MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; }
void setMessageQueueToGUI(MessageQueue *messageQueue) { m_msgQueueToGUI = messageQueue; }
uint64_t getTrackerDeviceFrequency() const { return m_trackerDeviceFrequency; }
int getTrackerChannelOffset() const { return m_trackerChannelOffset; }
private:
struct ChannelTracking
{
int m_channelOffset;
int m_trackerOffset;
int m_channelDirection;
ChannelTracking() :
m_channelOffset(0),
m_trackerOffset(0),
m_channelDirection(0)
{}
ChannelTracking(int channelOffset, int trackerOffset, int channelDirection) :
m_channelOffset(channelOffset),
m_trackerOffset(trackerOffset),
m_channelDirection(m_channelDirection)
{}
ChannelTracking(const ChannelTracking& other) :
m_channelOffset(other.m_channelOffset),
m_trackerOffset(other.m_trackerOffset),
m_channelDirection(other.m_channelDirection)
{}
};
WebAPIAdapterInterface *m_webAPIAdapterInterface;
MessageQueue m_inputMessageQueue; //!< Queue for asynchronous inbound communication
MessageQueue *m_msgQueueToGUI; //!< Queue to report state to GUI
AFCSettings m_settings;
bool m_running;
DeviceSet *m_trackerDeviceSet;
DeviceSet *m_trackedDeviceSet;
ChannelAPI *m_freqTracker;
uint64_t m_trackerDeviceFrequency;
int m_trackerChannelOffset;
QMap<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
);
bool updateChannelOffset(ChannelAPI *channelAPI, int direction, int offset, unsigned int blockCount = 0);
bool updateDeviceFrequency(DeviceSet *deviceSet, const QString& key, int64_t frequency);
int getDeviceDirection(DeviceAPI *deviceAPI);
void getDeviceSettingsKey(DeviceAPI *deviceAPI, QString& settingsKey);
void reportUpdateTarget(int correction, bool done);
private slots:
void updateTarget();
void handleInputMessages();
};
#endif // INCLUDE_FEATURE_SIMPLEPTTWORKER_H_

View File

@ -0,0 +1,67 @@
<h1>Automatic Frequency Control plugin</h1>
<h2>Introduction</h2>
This plugin makes the link between a [frequency tracker](../../channelrx/freqtracker/readme.md) and other channels in order to have them controlled by the frequency tracker. Thus it closes the loop to effectively make an automatic frequency control system.
<h2>Interface</h2>
![File source channel plugin GUI](../../../doc/img/AFC_plugin.png)
<h3>1: Start/Stop plugin</h3>
This button starts or stops the plugin
<h3>2: Update device sets lists</h3>
It updates the tracker device set and tracked device set combo boxes (3) and (4) respectively with the available device sets.
<h3>3: Tracker device set selection</h3>
The first frequency tracker in this device set will be used to control frequency. Thus only Rx device sets can be selected.
<h3>4: Tracked device set selection</h3>
All channels but frequency tracker(s) in this device set will have their offset frequency controlled by the frequency tracker selected with (3).
<h3>5: (Re)apply device sets selection</h3>
Use this button to force evaluation of selected device sets i.e. the first frequency tracker used for tracking and the tracked channels.
<h3>6: Automatic target frequency readjustment</h3>
When the frequency tracker drifts following the signal it is tracking its effective frequency will move accordingly. To avoid it going too far from a nominal frequency set by (7) the device or transverter frequency can be used to re-adjust the frequency tracker center frequency periodically.
<h3>7: Tracker target frequency</h3>
This is the nominal frequency of the signal being tracked. For example (as in the picture) when tracking the QO-100 center beacon this is 10489.750 MHz thus with the transverter shift set at -250 kHz this is 489.750 MHz (The actual downconverted Rx frequency is 739.750 MHz).
<h3>8: Use transverter shift to adjust target frequency</h3>
When unset the device center frequency is used and when set the device center frequency setting is unchanged and the transverter shift is adjusted.
You would use the transverter adjustment for QO-100 tracking for example thus the resulting IF frequency is unchanged maintaining the center beacon around 489.750 MHz.
The transverter shift can be adjusted down to the Hz but depending on the device actual steps such granularity may not be effectively achievable.
<h3>9: Target frequency tolerance</h3>
Frequency readjustment will actually take place only if the frequency tracker frequency moves further away than &plusmn; this value from the nominal frequency (7).
You should not choose a value that is too tight else the frequency tracker frequency will keep moving around the target frequency without stabilizing. In practice you may set a low value and trigger a single shot adjustment with the (11) button and once stabilized choose a value significantly higher than the offset from nominal that is obtained.
Please note that if the device frequency adjustment is used the steps are in kHz so multiples of the kHz should be used.
<h3>10. Target frequency readjustment period (seconds)</h3>
The target frequency readjustment is periodically activated and frequency change is effectively activated if the tracker frequency offset from nominal is larger than the tolerance (9).
Depending on how fast the frequency drift occurs you should set a value in combination with the frequency tolerance (9) so that the frequency is not readjusted too frequently.
<h3>11. Activate target frequency readjustment immediately</h3>
This forces target readjustment process described above immediately.
<h3>12. Target readjustement indicator</h3>
This indicator will flash briefly when the readjustment process takes place. Its color is green if the frequency is not changed and is red if frequency changes. The tooltip shows the last frequency difference that was calculated.

View File

@ -21,10 +21,22 @@
#include "channelapi.h"
ChannelAPI::ChannelAPI(const QString& name, StreamType streamType) :
m_featuresSettingsFeedbackBlockCount(0),
m_streamType(streamType),
m_name(name),
m_indexInDeviceSet(-1),
m_deviceSetIndex(0),
m_deviceAPI(0),
m_uid(UidCalculator::getNewObjectId())
{ }
{ }
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,20 @@ public:
void setDeviceAPI(DeviceAPI *deviceAPI) { m_deviceAPI = deviceAPI; }
uint64_t getUID() const { return m_uid; }
// Features support
void addFeatureSettingsFeedback(Feature *feature);
void removeFeatureSettingsFeedback(Feature *feature);
void setFeatureSettingsFeedbackBlockCount(unsigned int count) { m_featuresSettingsFeedbackBlockCount = count; }
// MIMO support
StreamType getStreamType() const { return m_streamType; }
virtual int getNbSinkStreams() const = 0;
virtual int getNbSourceStreams() const = 0;
virtual qint64 getStreamCenterFrequency(int streamIndex, bool sinkElseSource) const = 0;
protected:
QList<Feature*> m_featuresSettingsFeedback; //!< list of features to report back settings changes in swagger API format
unsigned int m_featuresSettingsFeedbackBlockCount; //!< actually send feedback if 0. Decremented at each potential feedback
private:
StreamType m_streamType;

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

@ -776,6 +776,91 @@ margin-bottom: 20px;
}
},
"description" : "ADSBDemod"
};
defs.AFCActions = {
"properties" : {
"deviceTrack" : {
"type" : "integer",
"description" : "(Re)initialize tracker target frequency adjustment\n * 0 - release\n * 1 - engage\n"
},
"devicesApply" : {
"type" : "integer",
"description" : "(Re)initialize device sets tracking\n * 0 - release\n * 1 - engage\n"
}
},
"description" : "AFC actions"
};
defs.AFCReport = {
"properties" : {
"trackerChannelIndex" : {
"type" : "integer",
"description" : "Tracker index in device set"
},
"trackerDeviceFrequency" : {
"type" : "integer",
"format" : "int64"
},
"trackerChannelOffset" : {
"type" : "integer",
"description" : "Tracker channel offset from device center frequency"
}
},
"description" : "AFC report"
};
defs.AFCSettings = {
"properties" : {
"title" : {
"type" : "string"
},
"rgbColor" : {
"type" : "integer"
},
"trackerDeviceSetIndex" : {
"type" : "integer",
"description" : "index of the device set of frequency tracker being used"
},
"trackedDeviceSetIndex" : {
"type" : "integer",
"description" : "index of the device set being tracked (channels and possibly device)"
},
"hasTargetFrequency" : {
"type" : "integer",
"description" : "Adjust device frequency to match tracker frequency\n * 0 - disabled\n * 1 - enabled\n"
},
"transverterTarget" : {
"type" : "integer",
"description" : "Use transverter or device frequency for tracker frequency adjustment\n * 0 - device\n * 1 - transverter\n"
},
"targetFrequency" : {
"type" : "integer",
"format" : "int64",
"description" : "Target frequency for the tracker"
},
"freqTolerance" : {
"type" : "integer"
},
"trackerAdjustPeriod" : {
"type" : "integer",
"description" : "Tracker channel frequency adjustment period in seconds"
},
"useReverseAPI" : {
"type" : "integer",
"description" : "Synchronize with reverse API (1 for yes, 0 for no)"
},
"reverseAPIAddress" : {
"type" : "string"
},
"reverseAPIPort" : {
"type" : "integer"
},
"reverseAPIDeviceIndex" : {
"type" : "integer"
},
"reverseAPIChannelIndex" : {
"type" : "integer"
}
},
"description" : "AFC settings"
};
defs.AMBEDevice = {
"properties" : {
@ -3289,6 +3374,9 @@ margin-bottom: 20px;
"type" : "integer",
"description" : "Optional for reverse API. This is the feature index from where the message comes from."
},
"AFCActions" : {
"$ref" : "#/definitions/AFCActions"
},
"SimplePTTActions" : {
"$ref" : "#/definitions/SimplePTTActions"
}
@ -3315,6 +3403,9 @@ margin-bottom: 20px;
"type" : "string",
"description" : "Feature type code"
},
"AFCReport" : {
"$ref" : "#/definitions/AFCReport"
},
"SimplePTTReport" : {
"$ref" : "#/definitions/SimplePTTReport"
}
@ -3390,6 +3481,9 @@ margin-bottom: 20px;
"GS232ControllerSettings" : {
"$ref" : "#/definitions/GS232ControllerSettings"
},
"AFCSettings" : {
"$ref" : "#/definitions/AFCSettings"
},
"SimplePTTSettings" : {
"$ref" : "#/definitions/SimplePTTSettings"
},
@ -3878,6 +3972,9 @@ margin-bottom: 20px;
"title" : {
"type" : "string"
},
"spanLog2" : {
"type" : "integer"
},
"alphaEMA" : {
"type" : "number",
"format" : "float",
@ -40117,7 +40214,7 @@ except ApiException as e:
</div>
<div id="generator">
<div class="content">
Generated 2020-10-27T19:23:34.436+01:00
Generated 2020-10-27T23:03:34.026+01:00
</div>
</div>
</div>

View File

@ -0,0 +1,58 @@
ADSBDemodSettings:
description: ADSBDemod
properties:
inputFrequencyOffset:
description: channel center frequency shift from baseband center in Hz
type: integer
format: int64
rfBandwidth:
description: channel RF bandwidth in Hz
type: number
format: float
correlationThreshold:
type: number
format: float
samplesPerBit:
type: integer
removeTimeout:
type: integer
beastEnabled:
type: integer
beastHost:
type: string
beastPort:
type: integer
rgbColor:
type: integer
title:
type: string
streamIndex:
description: MIMO channel. Not relevant when connected to SI (single Rx).
type: integer
useReverseAPI:
description: Synchronize with reverse API (1 for yes, 0 for no)
type: integer
reverseAPIAddress:
type: string
reverseAPIPort:
type: integer
reverseAPIDeviceIndex:
type: integer
reverseAPIChannelIndex:
type: integer
ADSBDemodReport:
description: ADSBDemod
properties:
channelPowerDB:
description: power received in channel (dB)
type: number
format: float
channelSampleRate:
type: integer
targetAzimuth:
type: number
format: float
targetElevation:
type: number
format: float

View File

@ -0,0 +1,76 @@
AFCSettings:
description: "AFC settings"
properties:
title:
type: string
rgbColor:
type: integer
trackerDeviceSetIndex:
description: index of the device set of frequency tracker being used
type: integer
trackedDeviceSetIndex:
description: index of the device set being tracked (channels and possibly device)
type: integer
hasTargetFrequency:
type: integer
description: >
Adjust device frequency to match tracker frequency
* 0 - disabled
* 1 - enabled
transverterTarget:
type: integer
description: >
Use transverter or device frequency for tracker frequency adjustment
* 0 - device
* 1 - transverter
targetFrequency:
description: Target frequency for the tracker
type: integer
format: int64
freqTolerance:
descritpion: Frequency shift tolerance before tracker frequency is (re)adjusted
type: integer
trackerAdjustPeriod:
description: Tracker channel frequency adjustment period in seconds
type: integer
useReverseAPI:
description: Synchronize with reverse API (1 for yes, 0 for no)
type: integer
reverseAPIAddress:
type: string
reverseAPIPort:
type: integer
reverseAPIDeviceIndex:
type: integer
reverseAPIChannelIndex:
type: integer
AFCReport:
description: "AFC report"
properties:
trackerChannelIndex:
description: Tracker index in device set
type: integer
trackerDeviceFrequency:
descritpion: Center frequency of tracker device
type: integer
format: int64
trackerChannelOffset:
description: Tracker channel offset from device center frequency
type: integer
AFCActions:
description: "AFC actions"
properties:
deviceTrack:
type: integer
description: >
(Re)initialize tracker target frequency adjustment
* 0 - release
* 1 - engage
devicesApply:
type: integer
description: >
(Re)initialize device sets tracking
* 0 - release
* 1 - engage

View File

@ -11,6 +11,8 @@ ChannelReport:
direction:
description: 0 for Rx only, 1 for Tx only or 2 for any number and direction (default 0)
type: integer
ADSBDemodReport:
$ref: "/doc/swagger/include/ADSBDemod.yaml#/ADSBDemodReport"
AMDemodReport:
$ref: "/doc/swagger/include/AMDemod.yaml#/AMDemodReport"
AMModReport:

View File

@ -17,6 +17,8 @@ ChannelSettings:
originatorChannelIndex:
description: Optional for reverse API. This is the channel index from where the message comes from.
type: integer
ADSBDemodSettings:
$ref: "/doc/swagger/include/ADSBDemod.yaml#/ADSBDemodSettings"
AMDemodSettings:
$ref: "/doc/swagger/include/AMDemod.yaml#/AMDemodSettings"
AMModSettings:

View File

@ -13,5 +13,7 @@ FeatureActions:
originatorFeatureIndex:
description: Optional for reverse API. This is the feature index from where the message comes from.
type: integer
AFCActions:
$ref: "/doc/swagger/include/AFC.yaml#/AFCActions"
SimplePTTActions:
$ref: "/doc/swagger/include/SimplePTT.yaml#/SimplePTTActions"

View File

@ -7,5 +7,7 @@ FeatureReport:
featureType:
description: Feature type code
type: string
AFCReport:
$ref: "/doc/swagger/include/AFC.yaml#/AFCReport"
SimplePTTReport:
$ref: "/doc/swagger/include/SimplePTT.yaml#/SimplePTTReport"

View File

@ -13,6 +13,10 @@ FeatureSettings:
originatorFeatureIndex:
description: Optional for reverse API. This is the feature index from where the message comes from.
type: integer
GS232ControllerSettings:
$ref: "/doc/swagger/include/GS232Controller.yaml#/GS232ControllerSettings"
AFCSettings:
$ref: "/doc/swagger/include/AFC.yaml#/AFCSettings"
SimplePTTSettings:
$ref: "/doc/swagger/include/SimplePTT.yaml#/SimplePTTSettings"
RigCtlServerSettings:

View File

@ -19,6 +19,8 @@ FreqTrackerSettings:
type: integer
title:
type: string
spanLog2:
type: integer
alphaEMA:
description: Alpha factor for delta frequency EMA
type: number

View File

@ -0,0 +1,36 @@
GS232ControllerSettings:
description: "GS-232 Controller settings"
properties:
azimuth:
description: Target azimuth in degrees (0-450)
type: integer
elevation:
description: Target elevation in degrees (0-180)
type: integer
serialPort:
description: The serial port the GS-232 controller is connected to
type: string
baudRate:
description: The baud rate to use for the serial connection to the GS-232 controller
type: integer
track:
type: integer
title:
type: string
rgbColor:
type: integer
deviceIndex:
type: integer
channelIndex:
type: integer
useReverseAPI:
description: Synchronize with reverse API (1 for yes, 0 for no)
type: integer
reverseAPIAddress:
type: string
reverseAPIPort:
type: integer
reverseAPIDeviceIndex:
type: integer
reverseAPIChannelIndex:
type: integer

View File

@ -6,6 +6,8 @@ USRPInputSettings:
format: int64
devSampleRate:
type: integer
loOffset:
type: integer
dcBlock:
type: integer
iqCorrection:
@ -46,6 +48,8 @@ USRPOutputSettings:
format: int64
devSampleRate:
type: integer
loOffset:
type: integer
log2SoftInterp:
type: integer
lpfBW:

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,209 +57,6 @@
#include "SWGFeatureReport.h"
#include "SWGFeatureActions.h"
const QMap<QString, QString> WebAPIRequestMapper::m_channelURIToSettingsKey = {
{"sdrangel.channel.adsbdemod", "ADSBDemodSettings"},
{"sdrangel.channel.amdemod", "AMDemodSettings"},
{"de.maintech.sdrangelove.channel.am", "AMDemodSettings"}, // remap
{"sdrangel.channeltx.modam", "AMModSettings"},
{"sdrangel.channeltx.modatv", "ATVModSettings"},
{"sdrangel.channel.bfm", "BFMDemodSettings"},
{"sdrangel.channel.chanalyzer", "ChannelAnalyzerSettings"},
{"sdrangel.channel.chanalyzerng", "ChannelAnalyzerSettings"}, // remap
{"org.f4exb.sdrangelove.channel.chanalyzer", "ChannelAnalyzerSettings"}, // remap
{"sdrangel.channel.demodatv", "ATVDemodSettings"},
{"sdrangel.channel.demoddatv", "DATVDemodSettings"},
{"sdrangel.channel.dsddemod", "DSDDemodSettings"},
{"sdrangel.channel.filesink", "FileSinkSettings"},
{"sdrangel.channeltx.filesource", "FileSourceSettings"},
{"sdrangel.channel.freedvdemod", "FreeDVDemodSettings"},
{"sdrangel.channeltx.freedvmod", "FreeDVModSettings"},
{"sdrangel.channel.freqtracker", "FreqTrackerSettings"},
{"sdrangel.channel.nfmdemod", "NFMDemodSettings"},
{"de.maintech.sdrangelove.channel.nfm", "NFMDemodSettings"}, // remap
{"sdrangel.channeltx.modnfm", "NFMModSettings"},
{"sdrangel.demod.localsink", "LocalSinkSettings"},
{"sdrangel.channel.localsink", "LocalSinkSettings"}, // remap
{"sdrangel.channel.localsource", "LocalSourceSettings"},
{"sdrangel.channeltx.modpacket", "PacketModSettings"},
{"sdrangel.channeltx.mod802.15.4", "IEEE_802_15_4_ModSettings"},
{"sdrangel.demod.remotesink", "RemoteSinkSettings"},
{"sdrangel.channeltx.remotesource", "RemoteSourceSettings"},
{"sdrangel.channeltx.modssb", "SSBModSettings"},
{"sdrangel.channel.ssbdemod", "SSBDemodSettings"},
{"de.maintech.sdrangelove.channel.ssb", "SSBDemodSettings"}, // remap
{"sdrangel.channeltx.udpsource", "UDPSourceSettings"},
{"sdrangel.channeltx.udpsink", "UDPSourceSettings"}, // remap
{"sdrangel.channel.udpsink", "UDPSinkSettings"},
{"sdrangel.channel.udpsrc", "UDPSinkSettings"}, // remap
{"sdrangel.channel.wfmdemod", "WFMDemodSettings"},
{"de.maintech.sdrangelove.channel.wfm", "WFMDemodSettings"}, // remap
{"sdrangel.channeltx.modwfm", "WFMModSettings"}
};
const QMap<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 = {
{"ADSBDemod", "ADSBDemodSettings"},
{"AMDemod", "AMDemodSettings"},
{"AMMod", "AMModSettings"},
{"ATVDemod", "ATVDemodSettings"},
{"ATVMod", "ATVModSettings"},
{"BFMDemod", "BFMDemodSettings"},
{"ChannelAnalyzer", "ChannelAnalyzerSettings"},
{"DATVDemod", "DATVDemodSettings"},
{"DSDDemod", "DSDDemodSettings"},
{"FileSink", "FileSinkSettings"},
{"FileSource", "FileSourceSettings"},
{"FreeDVDemod", "FreeDVDemodSettings"},
{"FreeDVMod", "FreeDVModSettings"},
{"FreqTracker", "FreqTrackerSettings"},
{"IEEE_802_15_4_Mod", "IEEE_802_15_4_ModSettings"},
{"NFMDemod", "NFMDemodSettings"},
{"NFMMod", "NFMModSettings"},
{"PacketMod", "PacketModSettings"},
{"LocalSink", "LocalSinkSettings"},
{"LocalSource", "LocalSourceSettings"},
{"RemoteSink", "RemoteSinkSettings"},
{"RemoteSource", "RemoteSourceSettings"},
{"SSBMod", "SSBModSettings"},
{"SSBDemod", "SSBDemodSettings"},
{"UDPSink", "UDPSourceSettings"},
{"UDPSource", "UDPSinkSettings"},
{"WFMDemod", "WFMDemodSettings"},
{"WFMMod", "WFMModSettings"}
};
const QMap<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 = {
{"GS232Controller", "GS232ControllerSettings"},
{"SimplePTT", "SimplePTTSettings"},
{"RigCtlServer", "RigCtlServerSettings"}
};
const QMap<QString, QString> WebAPIRequestMapper::m_featureTypeToActionsKey = {
{"SimplePTT", "SimplePTTActions"}
};
const QMap<QString, QString> WebAPIRequestMapper::m_featureURIToSettingsKey = {
{"sdrangel.feature.gs232controller", "GS232ControllerSettings"},
{"sdrangel.feature.simpleptt", "SimplePTTSettings"},
{"sdrangel.feature.rigctlserver", "RigCtlServerSettings"}
};
WebAPIRequestMapper::WebAPIRequestMapper(QObject* parent) :
HttpRequestHandler(parent),
m_adapter(0)
@ -3029,16 +2827,24 @@ bool WebAPIRequestMapper::validateDeviceSettings(
if (deviceSettings.getDirection() == 0) // source
{
if (m_sourceDeviceHwIdToSettingsKey.contains(*deviceHwType)) {
deviceSettingsKey = m_sourceDeviceHwIdToSettingsKey[*deviceHwType];
if (WebAPIUtils::m_sourceDeviceHwIdToSettingsKey.contains(*deviceHwType)) {
deviceSettingsKey = WebAPIUtils::m_sourceDeviceHwIdToSettingsKey[*deviceHwType];
} else {
return false;
}
}
else if (deviceSettings.getDirection() == 1) // sink
{
if (m_sinkDeviceHwIdToSettingsKey.contains(*deviceHwType)) {
deviceSettingsKey = m_sinkDeviceHwIdToSettingsKey[*deviceHwType];
if (WebAPIUtils::m_sinkDeviceHwIdToSettingsKey.contains(*deviceHwType)) {
deviceSettingsKey = WebAPIUtils::m_sinkDeviceHwIdToSettingsKey[*deviceHwType];
} else {
return false;
}
}
else if (deviceSettings.getDirection() == 2) // MIMO
{
if (WebAPIUtils::m_mimoDeviceHwIdToSettingsKey.contains(*deviceHwType)) {
deviceSettingsKey = WebAPIUtils::m_mimoDeviceHwIdToSettingsKey[*deviceHwType];
} else {
return false;
}
@ -3073,24 +2879,24 @@ bool WebAPIRequestMapper::validateDeviceActions(
if (deviceActions.getDirection() == 0) // source
{
if (m_sourceDeviceHwIdToSettingsKey.contains(*deviceHwType)) {
deviceActionsKey = m_sourceDeviceHwIdToActionsKey[*deviceHwType];
if (WebAPIUtils::m_sourceDeviceHwIdToSettingsKey.contains(*deviceHwType)) {
deviceActionsKey = WebAPIUtils::m_sourceDeviceHwIdToActionsKey[*deviceHwType];
} else {
return false;
}
}
else if (deviceActions.getDirection() == 1) // sink
{
if (m_sinkDeviceHwIdToSettingsKey.contains(*deviceHwType)) {
deviceActionsKey = m_sinkDeviceHwIdToActionsKey[*deviceHwType];
if (WebAPIUtils::m_sinkDeviceHwIdToSettingsKey.contains(*deviceHwType)) {
deviceActionsKey = WebAPIUtils::m_sinkDeviceHwIdToActionsKey[*deviceHwType];
} else {
return false;
}
}
else if (deviceActions.getDirection() == 2) // MIMO
{
if (m_mimoDeviceHwIdToSettingsKey.contains(*deviceHwType)) {
deviceActionsKey = m_mimoDeviceHwIdToActionsKey[*deviceHwType];
if (WebAPIUtils::m_mimoDeviceHwIdToSettingsKey.contains(*deviceHwType)) {
deviceActionsKey = WebAPIUtils::m_mimoDeviceHwIdToActionsKey[*deviceHwType];
} else {
return false;
}
@ -3122,8 +2928,8 @@ bool WebAPIRequestMapper::validateChannelSettings(
QString *channelType = channelSettings.getChannelType();
if (m_channelTypeToSettingsKey.contains(*channelType)) {
return getChannelSettings(m_channelTypeToSettingsKey[*channelType], &channelSettings, jsonObject, channelSettingsKeys);
if (WebAPIUtils::m_channelTypeToSettingsKey.contains(*channelType)) {
return getChannelSettings(WebAPIUtils::m_channelTypeToSettingsKey[*channelType], &channelSettings, jsonObject, channelSettingsKeys);
} else {
return false;
}
@ -3148,8 +2954,8 @@ bool WebAPIRequestMapper::validateChannelActions(
QString *channelType = channelActions.getChannelType();
if (m_channelTypeToActionsKey.contains(*channelType)) {
return getChannelActions(m_channelTypeToActionsKey[*channelType], &channelActions, jsonObject, channelActionsKeys);
if (WebAPIUtils::m_channelTypeToActionsKey.contains(*channelType)) {
return getChannelActions(WebAPIUtils::m_channelTypeToActionsKey[*channelType], &channelActions, jsonObject, channelActionsKeys);
} else {
return false;
}
@ -3168,8 +2974,8 @@ bool WebAPIRequestMapper::validateFeatureSettings(
QString *featureType = featureSettings.getFeatureType();
if (m_featureTypeToSettingsKey.contains(*featureType)) {
return getFeatureSettings(m_featureTypeToSettingsKey[*featureType], &featureSettings, jsonObject, featureSettingsKeys);
if (WebAPIUtils::m_featureTypeToSettingsKey.contains(*featureType)) {
return getFeatureSettings(WebAPIUtils::m_featureTypeToSettingsKey[*featureType], &featureSettings, jsonObject, featureSettingsKeys);
} else {
return false;
}
@ -3188,8 +2994,8 @@ bool WebAPIRequestMapper::validateFeatureActions(
QString *featureType = featureActions.getFeatureType();
if (m_featureTypeToActionsKey.contains(*featureType)) {
return getFeatureActions(m_featureTypeToActionsKey[*featureType], &featureActions, jsonObject, featureActionsKeys);
if (WebAPIUtils::m_featureTypeToActionsKey.contains(*featureType)) {
return getFeatureActions(WebAPIUtils::m_featureTypeToActionsKey[*featureType], &featureActions, jsonObject, featureActionsKeys);
} else {
return false;
}
@ -3647,12 +3453,12 @@ bool WebAPIRequestMapper::appendPresetFeatureKeys(
feature->setFeatureIdUri(featureURI);
featureKeys.m_keys.append("featureIdURI");
if (featureSettingsJson.contains("config") && m_featureURIToSettingsKey.contains(*featureURI))
if (featureSettingsJson.contains("config") && WebAPIUtils::m_featureURIToSettingsKey.contains(*featureURI))
{
SWGSDRangel::SWGFeatureSettings *featureSettings = new SWGSDRangel::SWGFeatureSettings();
feature->setConfig(featureSettings);
return getFeatureSettings(
m_channelURIToSettingsKey[*featureURI],
WebAPIUtils::m_channelURIToSettingsKey[*featureURI],
featureSettings,
featureSettingsJson["config"].toObject(),
featureKeys.m_featureKeys
@ -3681,11 +3487,11 @@ bool WebAPIRequestMapper::appendPresetChannelKeys(
channel->setChannelIdUri(channelURI);
channelKeys.m_keys.append("channelIdURI");
if (channelSettingsJson.contains("config") && m_channelURIToSettingsKey.contains(*channelURI))
if (channelSettingsJson.contains("config") && WebAPIUtils::m_channelURIToSettingsKey.contains(*channelURI))
{
SWGSDRangel::SWGChannelSettings *channelSettings = new SWGSDRangel::SWGChannelSettings();
channel->setConfig(channelSettings);
return getChannelSettings(m_channelURIToSettingsKey[*channelURI], channelSettings, channelSettingsJson["config"].toObject(), channelKeys.m_channelKeys);
return getChannelSettings(WebAPIUtils::m_channelURIToSettingsKey[*channelURI], channelSettings, channelSettingsJson["config"].toObject(), channelKeys.m_channelKeys);
}
else
{
@ -3942,11 +3748,11 @@ bool WebAPIRequestMapper::appendPresetDeviceKeys(
devicelKeys.m_keys.append("deviceSequence");
}
if (deviceSettngsJson.contains("config") && m_deviceIdToSettingsKey.contains(*deviceId))
if (deviceSettngsJson.contains("config") && WebAPIUtils::m_deviceIdToSettingsKey.contains(*deviceId))
{
SWGSDRangel::SWGDeviceSettings *deviceSettings = new SWGSDRangel::SWGDeviceSettings();
device->setConfig(deviceSettings);
return getDeviceSettings(m_deviceIdToSettingsKey[*deviceId], deviceSettings, deviceSettngsJson["config"].toObject(), devicelKeys.m_deviceKeys);
return getDeviceSettings(WebAPIUtils::m_deviceIdToSettingsKey[*deviceId], deviceSettings, deviceSettngsJson["config"].toObject(), devicelKeys.m_deviceKeys);
}
else
{

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 724 B

View File

@ -11,6 +11,7 @@
<file>aircraft_drone.png</file>
<file>map_antenna.png</file>
<file>map_truck.png</file>
<file>arrow_left.png</file>
<file>star.png</file>
<file>swap.png</file>
<file>gridpolar.png</file>

View File

@ -0,0 +1,76 @@
AFCSettings:
description: "AFC settings"
properties:
title:
type: string
rgbColor:
type: integer
trackerDeviceSetIndex:
description: index of the device set of frequency tracker being used
type: integer
trackedDeviceSetIndex:
description: index of the device set being tracked (channels and possibly device)
type: integer
hasTargetFrequency:
type: integer
description: >
Adjust device frequency to match tracker frequency
* 0 - disabled
* 1 - enabled
transverterTarget:
type: integer
description: >
Use transverter or device frequency for tracker frequency adjustment
* 0 - device
* 1 - transverter
targetFrequency:
description: Target frequency for the tracker
type: integer
format: int64
freqTolerance:
descritpion: Frequency shift tolerance before tracker frequency is (re)adjusted
type: integer
trackerAdjustPeriod:
description: Tracker channel frequency adjustment period in seconds
type: integer
useReverseAPI:
description: Synchronize with reverse API (1 for yes, 0 for no)
type: integer
reverseAPIAddress:
type: string
reverseAPIPort:
type: integer
reverseAPIDeviceIndex:
type: integer
reverseAPIChannelIndex:
type: integer
AFCReport:
description: "AFC report"
properties:
trackerChannelIndex:
description: Tracker index in device set
type: integer
trackerDeviceFrequency:
descritpion: Center frequency of tracker device
type: integer
format: int64
trackerChannelOffset:
description: Tracker channel offset from device center frequency
type: integer
AFCActions:
description: "AFC actions"
properties:
deviceTrack:
type: integer
description: >
(Re)initialize tracker target frequency adjustment
* 0 - release
* 1 - engage
devicesApply:
type: integer
description: >
(Re)initialize device sets tracking
* 0 - release
* 1 - engage

Some files were not shown because too many files have changed in this diff Show More