1
0
mirror of https://github.com/f4exb/sdrangel.git synced 2026-05-14 21:32:41 -04:00

feat: implement FreqDisplay WebAPI (webapiSettingsGet/PutPatch, format/update, reverseSend)

Agent-Logs-Url: https://github.com/srcejon/sdrangel/sessions/373fd0a8-4ef8-4849-8b8e-adb0a988230d

Co-authored-by: srcejon <57259258+srcejon@users.noreply.github.com>
This commit is contained in:
copilot-swe-agent[bot] 2026-04-22 18:28:48 +00:00 committed by GitHub
parent 8abbe204b4
commit 219ece573c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 385 additions and 4 deletions

View File

@ -17,9 +17,19 @@
///////////////////////////////////////////////////////////////////////////////////
#include <QDebug>
#include <QNetworkAccessManager>
#include <QNetworkReply>
#include <QBuffer>
#include "SWGFeatureSettings.h"
#include "SWGFreqDisplaySettings.h"
#include "settings/serializable.h"
#include "freqdisplay.h"
MESSAGE_CLASS_DEFINITION(FreqDisplay::MsgConfigureFreqDisplay, Message)
const char* const FreqDisplay::m_featureIdURI = "sdrangel.feature.freqdisplay";
const char* const FreqDisplay::m_featureId = "FreqDisplay";
@ -29,11 +39,36 @@ FreqDisplay::FreqDisplay(WebAPIAdapterInterface *webAPIAdapterInterface) :
qDebug("FreqDisplay::FreqDisplay: webAPIAdapterInterface: %p", webAPIAdapterInterface);
setObjectName(m_featureId);
m_state = StIdle;
m_networkManager = new QNetworkAccessManager();
QObject::connect(
m_networkManager,
&QNetworkAccessManager::finished,
this,
&FreqDisplay::networkManagerFinished
);
}
FreqDisplay::~FreqDisplay()
{
QObject::disconnect(
m_networkManager,
&QNetworkAccessManager::finished,
this,
&FreqDisplay::networkManagerFinished
);
delete m_networkManager;
}
bool FreqDisplay::handleMessage(const Message& cmd)
{
(void) cmd;
if (MsgConfigureFreqDisplay::match(cmd))
{
MsgConfigureFreqDisplay& cfg = (MsgConfigureFreqDisplay&) cmd;
qDebug() << "FreqDisplay::handleMessage: MsgConfigureFreqDisplay";
applySettings(cfg.getSettings(), cfg.getSettingsKeys(), cfg.getForce());
return true;
}
return false;
}
@ -54,9 +89,261 @@ bool FreqDisplay::deserialize(const QByteArray& data)
void FreqDisplay::applySettings(const FreqDisplaySettings& settings, const QStringList& settingsKeys, bool force)
{
qDebug() << "FreqDisplay::applySettings:" << " force: " << force;
if (settings.m_useReverseAPI)
{
bool fullUpdate = (settingsKeys.contains("useReverseAPI") && settings.m_useReverseAPI) ||
settingsKeys.contains("reverseAPIAddress") ||
settingsKeys.contains("reverseAPIPort") ||
settingsKeys.contains("reverseAPIFeatureSetIndex") ||
settingsKeys.contains("reverseAPIFeatureIndex");
webapiReverseSendSettings(settingsKeys, settings, fullUpdate || force);
}
if (force) {
m_settings = settings;
} else {
m_settings.applySettings(settingsKeys, settings);
}
}
int FreqDisplay::webapiSettingsGet(
SWGSDRangel::SWGFeatureSettings& response,
QString& errorMessage)
{
(void) errorMessage;
response.setFreqDisplaySettings(new SWGSDRangel::SWGFreqDisplaySettings());
response.getFreqDisplaySettings()->init();
webapiFormatFeatureSettings(response, m_settings);
return 200;
}
int FreqDisplay::webapiSettingsPutPatch(
bool force,
const QStringList& featureSettingsKeys,
SWGSDRangel::SWGFeatureSettings& response,
QString& errorMessage)
{
(void) errorMessage;
FreqDisplaySettings settings = m_settings;
webapiUpdateFeatureSettings(settings, featureSettingsKeys, response);
MsgConfigureFreqDisplay *msg = MsgConfigureFreqDisplay::create(settings, featureSettingsKeys, force);
m_inputMessageQueue.push(msg);
qDebug("FreqDisplay::webapiSettingsPutPatch: forward to GUI: %p", m_guiMessageQueue);
if (m_guiMessageQueue)
{
MsgConfigureFreqDisplay *msgToGUI = MsgConfigureFreqDisplay::create(settings, featureSettingsKeys, force);
m_guiMessageQueue->push(msgToGUI);
}
webapiFormatFeatureSettings(response, settings);
return 200;
}
void FreqDisplay::webapiFormatFeatureSettings(
SWGSDRangel::SWGFeatureSettings& response,
const FreqDisplaySettings& settings)
{
if (response.getFreqDisplaySettings()->getTitle()) {
*response.getFreqDisplaySettings()->getTitle() = settings.m_title;
} else {
response.getFreqDisplaySettings()->setTitle(new QString(settings.m_title));
}
response.getFreqDisplaySettings()->setRgbColor(settings.m_rgbColor);
if (response.getFreqDisplaySettings()->getSelectedChannel()) {
*response.getFreqDisplaySettings()->getSelectedChannel() = settings.m_selectedChannel;
} else {
response.getFreqDisplaySettings()->setSelectedChannel(new QString(settings.m_selectedChannel));
}
if (response.getFreqDisplaySettings()->getFontName()) {
*response.getFreqDisplaySettings()->getFontName() = settings.m_fontName;
} else {
response.getFreqDisplaySettings()->setFontName(new QString(settings.m_fontName));
}
response.getFreqDisplaySettings()->setTransparentBackground(settings.m_transparentBackground ? 1 : 0);
response.getFreqDisplaySettings()->setDisplayMode(static_cast<int>(settings.m_displayMode));
response.getFreqDisplaySettings()->setSpeechEnabled(settings.m_speechEnabled ? 1 : 0);
response.getFreqDisplaySettings()->setFrequencyUnits(static_cast<int>(settings.m_frequencyUnits));
response.getFreqDisplaySettings()->setShowUnits(settings.m_showUnits ? 1 : 0);
response.getFreqDisplaySettings()->setPowerDecimalPlaces(settings.m_powerDecimalPlaces);
response.getFreqDisplaySettings()->setTextcolor(settings.m_textColor.rgba());
response.getFreqDisplaySettings()->setDropShadowEnabled(settings.m_dropShadowEnabled ? 1 : 0);
response.getFreqDisplaySettings()->setUseReverseApi(settings.m_useReverseAPI ? 1 : 0);
if (response.getFreqDisplaySettings()->getReverseApiAddress()) {
*response.getFreqDisplaySettings()->getReverseApiAddress() = settings.m_reverseAPIAddress;
} else {
response.getFreqDisplaySettings()->setReverseApiAddress(new QString(settings.m_reverseAPIAddress));
}
response.getFreqDisplaySettings()->setReverseApiPort(settings.m_reverseAPIPort);
response.getFreqDisplaySettings()->setReverseApiFeatureSetIndex(settings.m_reverseAPIFeatureSetIndex);
response.getFreqDisplaySettings()->setReverseApiFeatureIndex(settings.m_reverseAPIFeatureIndex);
if (settings.m_rollupState)
{
if (response.getFreqDisplaySettings()->getRollupState())
{
settings.m_rollupState->formatTo(response.getFreqDisplaySettings()->getRollupState());
}
else
{
SWGSDRangel::SWGRollupState *swgRollupState = new SWGSDRangel::SWGRollupState();
settings.m_rollupState->formatTo(swgRollupState);
response.getFreqDisplaySettings()->setRollupState(swgRollupState);
}
}
}
void FreqDisplay::webapiUpdateFeatureSettings(
FreqDisplaySettings& settings,
const QStringList& featureSettingsKeys,
SWGSDRangel::SWGFeatureSettings& response)
{
if (featureSettingsKeys.contains("title")) {
settings.m_title = *response.getFreqDisplaySettings()->getTitle();
}
if (featureSettingsKeys.contains("rgbColor")) {
settings.m_rgbColor = response.getFreqDisplaySettings()->getRgbColor();
}
if (featureSettingsKeys.contains("selectedChannel")) {
settings.m_selectedChannel = *response.getFreqDisplaySettings()->getSelectedChannel();
}
if (featureSettingsKeys.contains("fontName")) {
settings.m_fontName = *response.getFreqDisplaySettings()->getFontName();
}
if (featureSettingsKeys.contains("transparentBackground")) {
settings.m_transparentBackground = response.getFreqDisplaySettings()->getTransparentBackground() != 0;
}
if (featureSettingsKeys.contains("displayMode")) {
settings.m_displayMode = static_cast<FreqDisplaySettings::DisplayMode>(response.getFreqDisplaySettings()->getDisplayMode());
}
if (featureSettingsKeys.contains("speechEnabled")) {
settings.m_speechEnabled = response.getFreqDisplaySettings()->getSpeechEnabled() != 0;
}
if (featureSettingsKeys.contains("frequencyUnits")) {
settings.m_frequencyUnits = static_cast<FreqDisplaySettings::FrequencyUnits>(response.getFreqDisplaySettings()->getFrequencyUnits());
}
if (featureSettingsKeys.contains("showUnits")) {
settings.m_showUnits = response.getFreqDisplaySettings()->getShowUnits() != 0;
}
if (featureSettingsKeys.contains("powerDecimalPlaces")) {
settings.m_powerDecimalPlaces = response.getFreqDisplaySettings()->getPowerDecimalPlaces();
}
if (featureSettingsKeys.contains("textColor")) {
settings.m_textColor = QColor::fromRgba(response.getFreqDisplaySettings()->getTextcolor());
}
if (featureSettingsKeys.contains("dropShadowEnabled")) {
settings.m_dropShadowEnabled = response.getFreqDisplaySettings()->getDropShadowEnabled() != 0;
}
if (featureSettingsKeys.contains("useReverseAPI")) {
settings.m_useReverseAPI = response.getFreqDisplaySettings()->getUseReverseApi() != 0;
}
if (featureSettingsKeys.contains("reverseAPIAddress")) {
settings.m_reverseAPIAddress = *response.getFreqDisplaySettings()->getReverseApiAddress();
}
if (featureSettingsKeys.contains("reverseAPIPort")) {
settings.m_reverseAPIPort = response.getFreqDisplaySettings()->getReverseApiPort();
}
if (featureSettingsKeys.contains("reverseAPIFeatureSetIndex")) {
settings.m_reverseAPIFeatureSetIndex = response.getFreqDisplaySettings()->getReverseApiFeatureSetIndex();
}
if (featureSettingsKeys.contains("reverseAPIFeatureIndex")) {
settings.m_reverseAPIFeatureIndex = response.getFreqDisplaySettings()->getReverseApiFeatureIndex();
}
if (settings.m_rollupState && featureSettingsKeys.contains("rollupState")) {
settings.m_rollupState->updateFrom(featureSettingsKeys, response.getFreqDisplaySettings()->getRollupState());
}
}
void FreqDisplay::webapiReverseSendSettings(const QStringList& featureSettingsKeys, const FreqDisplaySettings& settings, bool force)
{
SWGSDRangel::SWGFeatureSettings *swgFeatureSettings = new SWGSDRangel::SWGFeatureSettings();
swgFeatureSettings->setFeatureType(new QString("FreqDisplay"));
swgFeatureSettings->setFreqDisplaySettings(new SWGSDRangel::SWGFreqDisplaySettings());
SWGSDRangel::SWGFreqDisplaySettings *swgFreqDisplaySettings = swgFeatureSettings->getFreqDisplaySettings();
if (featureSettingsKeys.contains("title") || force) {
swgFreqDisplaySettings->setTitle(new QString(settings.m_title));
}
if (featureSettingsKeys.contains("rgbColor") || force) {
swgFreqDisplaySettings->setRgbColor(settings.m_rgbColor);
}
if (featureSettingsKeys.contains("selectedChannel") || force) {
swgFreqDisplaySettings->setSelectedChannel(new QString(settings.m_selectedChannel));
}
if (featureSettingsKeys.contains("fontName") || force) {
swgFreqDisplaySettings->setFontName(new QString(settings.m_fontName));
}
if (featureSettingsKeys.contains("transparentBackground") || force) {
swgFreqDisplaySettings->setTransparentBackground(settings.m_transparentBackground ? 1 : 0);
}
if (featureSettingsKeys.contains("displayMode") || force) {
swgFreqDisplaySettings->setDisplayMode(static_cast<int>(settings.m_displayMode));
}
if (featureSettingsKeys.contains("speechEnabled") || force) {
swgFreqDisplaySettings->setSpeechEnabled(settings.m_speechEnabled ? 1 : 0);
}
if (featureSettingsKeys.contains("frequencyUnits") || force) {
swgFreqDisplaySettings->setFrequencyUnits(static_cast<int>(settings.m_frequencyUnits));
}
if (featureSettingsKeys.contains("showUnits") || force) {
swgFreqDisplaySettings->setShowUnits(settings.m_showUnits ? 1 : 0);
}
if (featureSettingsKeys.contains("powerDecimalPlaces") || force) {
swgFreqDisplaySettings->setPowerDecimalPlaces(settings.m_powerDecimalPlaces);
}
if (featureSettingsKeys.contains("textColor") || force) {
swgFreqDisplaySettings->setTextcolor(settings.m_textColor.rgba());
}
if (featureSettingsKeys.contains("dropShadowEnabled") || force) {
swgFreqDisplaySettings->setDropShadowEnabled(settings.m_dropShadowEnabled ? 1 : 0);
}
QString featureSettingsURL = 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(featureSettingsURL));
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 FreqDisplay::networkManagerFinished(QNetworkReply *reply)
{
QNetworkReply::NetworkError replyError = reply->error();
if (replyError)
{
qWarning() << "FreqDisplay::networkManagerFinished:"
<< " error(" << (int) replyError
<< "): " << replyError
<< ": " << reply->errorString();
}
else
{
QString answer = reply->readAll();
answer.chop(1); // remove last \n
qDebug("FreqDisplay::networkManagerFinished: reply:\n%s", answer.toStdString().c_str());
}
reply->deleteLater();
}

View File

@ -19,20 +19,53 @@
#ifndef INCLUDE_FEATURE_FREQDISPLAY_H_
#define INCLUDE_FEATURE_FREQDISPLAY_H_
#include <QNetworkRequest>
#include <QStringList>
#include "feature/feature.h"
#include "util/message.h"
#include "freqdisplaysettings.h"
class WebAPIAdapterInterface;
class QNetworkAccessManager;
class QNetworkReply;
namespace SWGSDRangel {
class SWGFeatureSettings;
}
class FreqDisplay : public Feature
{
Q_OBJECT
public:
class MsgConfigureFreqDisplay : public Message {
MESSAGE_CLASS_DECLARATION
public:
const FreqDisplaySettings& getSettings() const { return m_settings; }
const QStringList& getSettingsKeys() const { return m_settingsKeys; }
bool getForce() const { return m_force; }
static MsgConfigureFreqDisplay* create(const FreqDisplaySettings& settings, const QStringList& settingsKeys, bool force) {
return new MsgConfigureFreqDisplay(settings, settingsKeys, force);
}
private:
FreqDisplaySettings m_settings;
QStringList m_settingsKeys;
bool m_force;
MsgConfigureFreqDisplay(const FreqDisplaySettings& settings, const QStringList& settingsKeys, bool force) :
Message(),
m_settings(settings),
m_settingsKeys(settingsKeys),
m_force(force)
{ }
};
FreqDisplay(WebAPIAdapterInterface *webAPIAdapterInterface);
~FreqDisplay() override = default;
~FreqDisplay() override;
void destroy() override { delete this; }
bool handleMessage(const Message& cmd) override;
@ -44,6 +77,25 @@ public:
QByteArray serialize() const override;
bool deserialize(const QByteArray& data) override;
int webapiSettingsGet(
SWGSDRangel::SWGFeatureSettings& response,
QString& errorMessage) override;
int webapiSettingsPutPatch(
bool force,
const QStringList& featureSettingsKeys,
SWGSDRangel::SWGFeatureSettings& response,
QString& errorMessage) override;
static void webapiFormatFeatureSettings(
SWGSDRangel::SWGFeatureSettings& response,
const FreqDisplaySettings& settings);
static void webapiUpdateFeatureSettings(
FreqDisplaySettings& settings,
const QStringList& featureSettingsKeys,
SWGSDRangel::SWGFeatureSettings& response);
const FreqDisplaySettings& getSettings() const { return m_settings; }
void applySettings(const FreqDisplaySettings& settings, const QStringList& settingsKeys, bool force = false);
@ -52,6 +104,13 @@ public:
private:
FreqDisplaySettings m_settings;
QNetworkAccessManager *m_networkManager;
QNetworkRequest m_networkRequest;
void webapiReverseSendSettings(const QStringList& featureSettingsKeys, const FreqDisplaySettings& settings, bool force);
private slots:
void networkManagerFinished(QNetworkReply *reply);
};
#endif // INCLUDE_FEATURE_FREQDISPLAY_H_

View File

@ -110,6 +110,35 @@ void FreqDisplayGUI::destroy()
delete this;
}
bool FreqDisplayGUI::handleMessage(const Message& message)
{
if (FreqDisplay::MsgConfigureFreqDisplay::match(message))
{
qDebug("FreqDisplayGUI::handleMessage: FreqDisplay::MsgConfigureFreqDisplay");
const FreqDisplay::MsgConfigureFreqDisplay& cfg = (FreqDisplay::MsgConfigureFreqDisplay&) message;
m_settings = cfg.getSettings();
m_doApplySettings = false;
displaySettings();
m_doApplySettings = true;
updateFrequencyText();
return true;
}
return false;
}
void FreqDisplayGUI::handleInputMessages()
{
Message* message;
while ((message = getInputMessageQueue()->pop()))
{
if (handleMessage(*message)) {
delete message;
}
}
}
void FreqDisplayGUI::resetToDefaults()
{
m_settings.resetToDefaults();
@ -175,6 +204,7 @@ FreqDisplayGUI::FreqDisplayGUI(PluginAPI* pluginAPI, FeatureUISet *featureUISet,
m_freqDisplay->setMessageQueueToGUI(&m_inputMessageQueue);
m_settings = m_freqDisplay->getSettings();
connect(getInputMessageQueue(), SIGNAL(messageEnqueued()), this, SLOT(handleInputMessages()));
connect(
&m_availableChannelOrFeatureHandler,

View File

@ -92,6 +92,8 @@ public:
static FreqDisplayGUI* create(PluginAPI* pluginAPI, FeatureUISet *featureUISet, Feature *feature);
void destroy() override;
bool handleMessage(const Message& message) override;
void resetToDefaults() override;
QByteArray serialize() const override;
bool deserialize(const QByteArray& data) override;
@ -162,6 +164,7 @@ private:
private slots:
void onMenuDialogCalled(const QPoint &p);
void onWidgetRolled(QWidget* widget, bool rollDown);
void handleInputMessages();
void channelsOrFeaturesChanged(const QStringList& renameFrom, const QStringList& renameTo, const QStringList& removed, const QStringList& added);
void on_channels_currentIndexChanged(int index);
void on_displayMode_currentIndexChanged(int index);

View File

@ -17,6 +17,8 @@
///////////////////////////////////////////////////////////////////////////////////
#include "SWGFeatureSettings.h"
#include "SWGFreqDisplaySettings.h"
#include "freqdisplay.h"
#include "freqdisplaywebapiadapter.h"
int FreqDisplayWebAPIAdapter::webapiSettingsGet(
@ -26,7 +28,7 @@ int FreqDisplayWebAPIAdapter::webapiSettingsGet(
(void) errorMessage;
response.setFreqDisplaySettings(new SWGSDRangel::SWGFreqDisplaySettings());
response.getFreqDisplaySettings()->init();
//FreqDisplay::webapiFormatFeatureSettings(response, m_settings);
FreqDisplay::webapiFormatFeatureSettings(response, m_settings);
return 200;
}
@ -39,7 +41,7 @@ int FreqDisplayWebAPIAdapter::webapiSettingsPutPatch(
{
(void) force; // no action
(void) errorMessage;
//FreqDisplay::webapiUpdateFeatureSettings(m_settings, featureSettingsKeys, response);
FreqDisplay::webapiUpdateFeatureSettings(m_settings, featureSettingsKeys, response);
return 200;
}