Files
sdrangel/plugins/feature/rigctlserver/rigctlserverworker.cpp
T
Robin Getz c2b30d4fa8 tree wide: Fix message ownership and reporting for unhandled queue messages
MessageQueue::pop() transfers ownership of the popped message to the
caller, but many handleInputMessages() implementations only deleted
the message when handleMessage() returned true. When a message was not
handled, ownership had already been transferred from the queue and the
message was leaked.

This was identified while investigating an ASAN leak in the audio
subsystem.

Update the applicable handleInputMessages() implementations to always
delete messages after handleMessage() returns. Unhandled messages are
also logged with the component and message identifier so unexpected
message routing is visible during debugging.

This change:
- Ensures every message popped from a queue has its ownership resolved.
- Prevents leaks when handleMessage() returns false.
- Makes unhandled messages visible instead of silently discarding them.
- Preserves the existing message handling logic and does not require
  components to handle message types that are legitimately irrelevant
  to them.

The changes are intentionally mechanical and limited to the common
message queue ownership and diagnostic pattern.

Signed-off-by: Robin Getz <rgetz503@gmail.com>
2026-09-25 23:49:05 -04:00

848 lines
26 KiB
C++

///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2020, 2022 Edouard Griffiths, F4EXB <f4exb06@gmail.com> //
// Copyright (C) 2020 Christian W. Zuckschwerdt <christian@zuckschwerdt.org> //
// Copyright (C) 2022 Jiří Pinkava <jiri.pinkava@rossum.ai> //
// //
// 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 <QTcpServer>
#include <QTcpSocket>
#include <QEventLoop>
#include <QTimer>
#include <cmath>
#include "SWGDeviceState.h"
#include "SWGSuccessResponse.h"
#include "SWGErrorResponse.h"
#include "SWGDeviceSettings.h"
#include "SWGChannelSettings.h"
#include "SWGDeviceSet.h"
#include "webapi/webapiadapterinterface.h"
#include "webapi/webapiutils.h"
#include "rigctlserverworker.h"
MESSAGE_CLASS_DEFINITION(RigCtlServerWorker::MsgConfigureRigCtlServerWorker, Message)
const unsigned int RigCtlServerWorker::m_CmdLength = 1024;
const unsigned int RigCtlServerWorker::m_ResponseLength = 1024;
const struct RigCtlServerWorker::ModeDemod RigCtlServerWorker::m_modeMap[] = {
{"FM", "NFMDemod"},
{"WFM", "WFMDemod"},
{"AM", "AMDemod"},
{"LSB", "SSBDemod"},
{"USB", "SSBDemod"},
{nullptr, nullptr}
};
RigCtlServerWorker::RigCtlServerWorker(WebAPIAdapterInterface *webAPIAdapterInterface) :
m_state(idle),
m_targetFrequency(0.0),
m_targetOffset(0.0),
m_targetBW(0),
m_tcpServer(nullptr),
m_clientConnection(nullptr),
m_webAPIAdapterInterface(webAPIAdapterInterface),
m_msgQueueToFeature(nullptr),
m_running(false)
{
qDebug("RigCtlServerWorker::RigCtlServerWorker");
}
RigCtlServerWorker::~RigCtlServerWorker()
{
m_inputMessageQueue.clear();
}
void RigCtlServerWorker::reset()
{
QMutexLocker mutexLocker(&m_mutex);
m_inputMessageQueue.clear();
}
bool RigCtlServerWorker::startWork()
{
QMutexLocker mutexLocker(&m_mutex);
connect(&m_inputMessageQueue, SIGNAL(messageEnqueued()), this, SLOT(handleInputMessages()));
m_running = true;
return m_running;
}
void RigCtlServerWorker::stopWork()
{
QMutexLocker mutexLocker(&m_mutex);
disconnect(&m_inputMessageQueue, SIGNAL(messageEnqueued()), this, SLOT(handleInputMessages()));
restartServer(false, 0);
m_running = false;
}
void RigCtlServerWorker::handleInputMessages()
{
Message* message;
while ((message = m_inputMessageQueue.pop()))
{
if (!handleMessage(*message)) {
qDebug("%s: unhandled message: %s", Q_FUNC_INFO, message->getIdentifier());
}
delete message;
}
}
bool RigCtlServerWorker::handleMessage(const Message& cmd)
{
if (MsgConfigureRigCtlServerWorker::match(cmd))
{
QMutexLocker mutexLocker(&m_mutex);
MsgConfigureRigCtlServerWorker& cfg = (MsgConfigureRigCtlServerWorker&) cmd;
qDebug() << "RigCtlServerWorker::handleMessage: MsgConfigureRigCtlServerWorker";
applySettings(cfg.getSettings(), cfg.getSettingsKeys(), cfg.getForce());
return true;
}
else
{
return false;
}
}
void RigCtlServerWorker::applySettings(const RigCtlServerSettings& settings, const QList<QString>& settingsKeys, bool force)
{
qDebug() << "RigCtlServerWorker::applySettings:" << settings.getDebugString(settingsKeys, force) << " force: " << force;
if (settingsKeys.contains("rigCtlPort") ||
settingsKeys.contains("enabled") || force)
{
restartServer(settings.m_enabled, settings.m_rigCtlPort);
}
if (force) {
m_settings = settings;
} else {
m_settings.applySettings(settingsKeys, settings);
}
}
void RigCtlServerWorker::restartServer(bool enabled, uint32_t port)
{
if (m_tcpServer)
{
if (m_clientConnection)
{
m_clientConnection->close();
delete m_clientConnection;
m_clientConnection = nullptr;
}
disconnect(m_tcpServer, &QTcpServer::newConnection, this, &RigCtlServerWorker::acceptConnection);
m_tcpServer->close();
delete m_tcpServer;
m_tcpServer = nullptr;
}
if (enabled)
{
qDebug() << "RigCtlServerWorker::restartServer: server enabled on port " << port;
m_tcpServer = new QTcpServer(this);
if (!m_tcpServer->listen(QHostAddress::Any, port)) {
qWarning("RigCtrl failed to listen on port %u. Check it is not already in use.", port);
} else {
connect(m_tcpServer, &QTcpServer::newConnection, this, &RigCtlServerWorker::acceptConnection);
}
}
else
{
qDebug() << "RigCtlServerWorker::restartServer: server disabled";
}
}
void RigCtlServerWorker::acceptConnection()
{
QMutexLocker mutexLocker(&m_mutex);
m_clientConnection = m_tcpServer->nextPendingConnection();
if (!m_clientConnection) {
return;
}
connect(m_clientConnection, &QIODevice::readyRead, this, &RigCtlServerWorker::getCommand);
connect(m_clientConnection, &QAbstractSocket::disconnected, m_clientConnection, &QObject::deleteLater);
}
// Get rigctl command and start processing it
void RigCtlServerWorker::getCommand()
{
QMutexLocker mutexLocker(&m_mutex);
char cmd[m_CmdLength];
qint64 len;
rig_errcode_e rigCtlRC;
char response[m_ResponseLength];
std::fill(response, response + m_ResponseLength, '\0');
// Get rigctld command from client
len = m_clientConnection->readLine(cmd, sizeof(cmd));
if (len != -1)
{
//qDebug() << "RigCtrl::getCommand - " << cmd;
if (!strncmp(cmd, "F ", 2) || !strncmp(cmd, "set_freq ", 9))
{
// Set frequency
double targetFrequency = atof(cmd[0] == 'F' ? &cmd[2] : &cmd[9]);
setFrequency(targetFrequency, rigCtlRC);
snprintf(response, sizeof(response), "RPRT %d\n", rigCtlRC);
}
else if (!strncmp(cmd, "f", 1) || !strncmp(cmd, "get_freq", 8))
{
// Get frequency - need to add centerFrequency and inputFrequencyOffset
double frequency;
if (getFrequency(frequency, rigCtlRC)) {
snprintf(response, sizeof(response), "%u\n", (unsigned int) frequency);
} else {
snprintf(response, sizeof(response), "RPRT %d\n", rigCtlRC);
}
}
else if (!strncmp(cmd, "M ?", 3) || !(strncmp(cmd, "set_mode ?", 10)))
{
// Return list of modes supported
char *p = response;
for (int i = 0; m_modeMap[i].mode != nullptr; i++) {
p += sprintf(p, "%s ", m_modeMap[i].mode);
}
p += sprintf(p, "\n");
}
else if (!strncmp(cmd, "M ", 2) || !(strncmp(cmd, "set_mode ", 9)))
{
// Set mode
// Map rigctrl mode name to SDRangel modem name
const char *targetModem = nullptr;
const char *targetMode = nullptr;
int targetBW = -1;
char *p = (cmd[0] == 'M' ? &cmd[2] : &cmd[9]);
int i, l;
for (i = 0; m_modeMap[i].mode != nullptr; i++)
{
l = strlen(m_modeMap[i].mode);
if (!strncmp(p, m_modeMap[i].mode, l))
{
targetMode = m_modeMap[i].mode;
targetModem = m_modeMap[i].modem;
p += l;
break;
}
}
// Save bandwidth, if given
while(isspace(*p)) {
p++;
}
if (isdigit(*p))
{
targetBW = atoi(p);
}
if (m_modeMap[i].modem != nullptr)
{
changeModem(targetMode, targetModem, targetBW, rigCtlRC);
snprintf(response, sizeof(response), "RPRT %d\n", rigCtlRC);
}
else
{
snprintf(response, sizeof(response), "RPRT %d\n", RIG_EINVAL);
m_clientConnection->write(response, strlen(response));
}
}
else if (!strncmp(cmd, "m", 1) || !(strncmp(cmd, "get_mode", 8)))
{
// Get mode
const char *mode;
double passband;
if (getMode(&mode, passband, rigCtlRC))
{
if (passband < 0) {
snprintf(response, sizeof(response), "%s\n", mode);
} else {
snprintf(response, sizeof(response), "%s %u\n", mode, (unsigned int) passband);
}
}
else
{
snprintf(response, sizeof(response), "RPRT %d\n", rigCtlRC);
}
}
else if (!strncmp(cmd, "set_powerstat 0", 15))
{
// Power off radio
setPowerOff(rigCtlRC);
snprintf(response, sizeof(response), "RPRT %d\n", rigCtlRC);
}
else if (!strncmp(cmd, "set_powerstat 1", 15))
{
// Power on radio
setPowerOn(rigCtlRC);
snprintf(response, sizeof(response), "RPRT %d\n", rigCtlRC);
}
else if (!strncmp(cmd, "get_powerstat", 13))
{
// Return if powered on or off
bool power;
if (getPower(power, rigCtlRC))
{
if (power) {
snprintf(response, sizeof(response), "1\n");
} else {
snprintf(response, sizeof(response), "0\n");
}
}
else
{
snprintf(response, sizeof(response), "RPRT %d\n", rigCtlRC);
}
}
else
{
// Unimplemented command
snprintf(response, sizeof(response), "RPRT %d\n", RIG_ENIMPL);
m_clientConnection->write(response, strlen(response));
}
}
m_clientConnection->write(response, strlen(response));
}
bool RigCtlServerWorker::setFrequency(double targetFrequency, rig_errcode_e& rigCtlRC)
{
SWGSDRangel::SWGDeviceSettings deviceSettingsResponse;
SWGSDRangel::SWGErrorResponse errorResponse;
int httpRC;
// Get current device center frequency
httpRC = m_webAPIAdapterInterface->devicesetDeviceSettingsGet(
m_settings.m_deviceIndex,
deviceSettingsResponse,
errorResponse
);
if (httpRC/100 != 2)
{
qWarning("RigCtlServerWorker::setFrequency: get device frequency error %d: %s",
httpRC, qPrintable(*errorResponse.getMessage()));
rigCtlRC = RIG_EINVAL;
return false;
}
QJsonObject *jsonObj = deviceSettingsResponse.asJsonObject();
double freq;
if (WebAPIUtils::getSubObjectDouble(*jsonObj, "centerFrequency", freq))
{
bool outOfRange = std::abs(freq - targetFrequency) > m_settings.m_maxFrequencyOffset;
if (outOfRange)
{
// Update centerFrequency
WebAPIUtils::setSubObjectDouble(*jsonObj, "centerFrequency", targetFrequency);
QStringList deviceSettingsKeys;
deviceSettingsKeys.append("centerFrequency");
deviceSettingsResponse.init();
deviceSettingsResponse.fromJsonObject(*jsonObj);
SWGSDRangel::SWGErrorResponse errorResponse2;
httpRC = m_webAPIAdapterInterface->devicesetDeviceSettingsPutPatch(
m_settings.m_deviceIndex,
false, // PATCH
deviceSettingsKeys,
deviceSettingsResponse,
errorResponse2
);
if (httpRC/100 == 2)
{
qDebug("RigCtlServerWorker::setFrequency: set device frequency %f OK", targetFrequency);
}
else
{
qWarning("RigCtlServerWorker::setFrequency: set device frequency error %d: %s",
httpRC, qPrintable(*errorResponse2.getMessage()));
rigCtlRC = RIG_EINVAL;
return false;
}
}
// Update inputFrequencyOffset (offet if in range else zero)
float targetOffset = outOfRange ? 0 : targetFrequency - freq;
SWGSDRangel::SWGChannelSettings channelSettingsResponse;
// Get channel settings containing inputFrequencyOffset, so we can patch it
httpRC = m_webAPIAdapterInterface->devicesetChannelSettingsGet(
m_settings.m_deviceIndex,
m_settings.m_channelIndex,
channelSettingsResponse,
errorResponse
);
if (httpRC/100 != 2)
{
qWarning("RigCtlServerWorker::setFrequency: get channel offset frequency error %d: %s",
httpRC, qPrintable(*errorResponse.getMessage()));
rigCtlRC = RIG_EINVAL;
return false;
}
jsonObj = channelSettingsResponse.asJsonObject();
if (WebAPIUtils::setSubObjectDouble(*jsonObj, "inputFrequencyOffset", targetOffset))
{
QStringList channelSettingsKeys;
channelSettingsKeys.append("inputFrequencyOffset");
channelSettingsResponse.init();
channelSettingsResponse.fromJsonObject(*jsonObj);
httpRC = m_webAPIAdapterInterface->devicesetChannelSettingsPutPatch(
m_settings.m_deviceIndex,
m_settings.m_channelIndex,
false, // PATCH
channelSettingsKeys,
channelSettingsResponse,
errorResponse
);
if (httpRC/100 == 2)
{
qDebug("RigCtlServerWorker::setFrequency: set channel offset frequency %f OK", targetOffset);
}
else
{
qWarning("RigCtlServerWorker::setFrequency: set channel frequency offset error %d: %s",
httpRC, qPrintable(*errorResponse.getMessage()));
rigCtlRC = RIG_EINVAL;
return false;
}
}
else
{
qWarning("RigCtlServerWorker::setFrequency: No inputFrequencyOffset key in channel settings");
rigCtlRC = RIG_ENIMPL;
return false;
}
}
else
{
qWarning("RigCtlServerWorker::setFrequency: no centerFrequency key in device settings");
rigCtlRC = RIG_ENIMPL;
return false;
}
rigCtlRC = RIG_OK; // return OK
return true;
}
bool RigCtlServerWorker::getFrequency(double& frequency, rig_errcode_e& rigCtlRC)
{
SWGSDRangel::SWGDeviceSettings deviceSettingsResponse;
SWGSDRangel::SWGErrorResponse errorResponse;
int httpRC;
// Get current device center frequency
httpRC = m_webAPIAdapterInterface->devicesetDeviceSettingsGet(
m_settings.m_deviceIndex,
deviceSettingsResponse,
errorResponse
);
if (httpRC/100 != 2)
{
qWarning("RigCtlServerWorker::getFrequency: get device frequency error %d: %s",
httpRC, qPrintable(*errorResponse.getMessage()));
rigCtlRC = RIG_EINVAL;
return false;
}
QJsonObject *jsonObj = deviceSettingsResponse.asJsonObject();
double deviceFreq;
if (WebAPIUtils::getSubObjectDouble(*jsonObj, "centerFrequency", deviceFreq))
{
SWGSDRangel::SWGChannelSettings channelSettingsResponse;
// Get channel settings containing inputFrequencyOffset, so we can patch them
httpRC = m_webAPIAdapterInterface->devicesetChannelSettingsGet(
m_settings.m_deviceIndex,
m_settings.m_channelIndex,
channelSettingsResponse,
errorResponse
);
if (httpRC/100 != 2)
{
qWarning("RigCtlServerWorker::setFrequency: get channel offset frequency error %d: %s",
httpRC, qPrintable(*errorResponse.getMessage()));
rigCtlRC = RIG_EINVAL;
return false;
}
QJsonObject *jsonObj2 = channelSettingsResponse.asJsonObject();
double channelOffset;
if (WebAPIUtils::getSubObjectDouble(*jsonObj2, "inputFrequencyOffset", channelOffset))
{
frequency = deviceFreq + channelOffset;
}
else
{
qWarning("RigCtlServerWorker::setFrequency: No inputFrequencyOffset key in channel settings");
rigCtlRC = RIG_ENIMPL;
return false;
}
}
else
{
qWarning("RigCtlServerWorker::setFrequency: no centerFrequency key in device settings");
rigCtlRC = RIG_ENIMPL;
return false;
}
rigCtlRC = RIG_OK;
return true;
}
bool RigCtlServerWorker::changeModem(const char *newMode, const char *newModemId, int newModemBw, rig_errcode_e& rigCtlRC)
{
SWGSDRangel::SWGDeviceSet deviceSetResponse;
SWGSDRangel::SWGSuccessResponse successResponse;
SWGSDRangel::SWGErrorResponse errorResponse;
int httpRC;
int nbChannels;
int currentOffset;
// get deviceset details to get the number of channel modems
httpRC = m_webAPIAdapterInterface->devicesetGet(
m_settings.m_deviceIndex,
deviceSetResponse,
errorResponse
);
if (httpRC/100 != 2) // error
{
qWarning("RigCtlServerWorker::changeModem: deevice set get information error %d: %s",
httpRC, qPrintable(*errorResponse.getMessage()));
rigCtlRC = RIG_EINVAL;
return false;
}
if (!WebAPIUtils::getObjectInt(*deviceSetResponse.asJsonObject(), "channelcount", nbChannels))
{
qWarning("RigCtlServerWorker::changeModem: no channelcount key in device set information");
rigCtlRC = RIG_ENIMPL;
return false;
}
QList<QJsonObject> channelObjects;
if (!WebAPIUtils::getObjectObjects(*deviceSetResponse.asJsonObject(), "channels", channelObjects))
{
qWarning("RigCtlServerWorker::changeModem: no channels key in device set information");
rigCtlRC = RIG_ENIMPL;
return false;
}
if (m_settings.m_channelIndex < channelObjects.size())
{
const QJsonObject& channelInfo = channelObjects.at(m_settings.m_channelIndex);
if (!WebAPIUtils::getObjectInt(channelInfo, "deltaFrequency", currentOffset))
{
qWarning("RigCtlServerWorker::changeModem: no deltaFrequency key in device set channel information");
rigCtlRC = RIG_ENIMPL;
return false;
}
}
else
{
qWarning("RigCtlServerWorker::changeModem: channel not found in device set channels information");
rigCtlRC = RIG_ENIMPL;
return false;
}
// delete current modem
httpRC = m_webAPIAdapterInterface->devicesetChannelDelete(
m_settings.m_deviceIndex,
m_settings.m_channelIndex,
successResponse,
errorResponse
);
if (httpRC/100 != 2) // error
{
qWarning("RigCtlServerWorker::changeModem: delete channel error %d: %s",
httpRC, qPrintable(*errorResponse.getMessage()));
rigCtlRC = RIG_EINVAL;
return false;
}
// create new modem
SWGSDRangel::SWGChannelSettings query;
QString newModemIdStr(newModemId);
bool lsb = !strncmp(newMode, "LSB", 3);
query.init();
query.setChannelType(new QString(newModemIdStr));
query.setDirection(0);
httpRC = m_webAPIAdapterInterface->devicesetChannelPost(
m_settings.m_deviceIndex,
query,
successResponse,
errorResponse
);
if (httpRC/100 != 2)
{
qWarning("RigCtlServerWorker::changeModem: create channel error %d: %s",
httpRC, qPrintable(*errorResponse.getMessage()));
rigCtlRC = RIG_EINVAL;
return false;
}
// wait for channel switchover
QEventLoop loop;
QTimer *timer = new QTimer(this);
connect(timer, SIGNAL(timeout()), &loop, SLOT(quit()));
timer->start(200);
loop.exec();
delete timer;
// when a new channel is created it is put last in the list
qDebug("RigCtlServerWorker::changeModem: created %s at %d", newModemId, nbChannels-1);
if (m_msgQueueToFeature)
{
RigCtlServerSettings::MsgChannelIndexChange *msg = RigCtlServerSettings::MsgChannelIndexChange::create(nbChannels-1);
m_msgQueueToFeature->push(msg);
}
SWGSDRangel::SWGChannelSettings swgChannelSettings;
QStringList channelSettingsKeys;
channelSettingsKeys.append("inputFrequencyOffset");
QString jsonSettingsStr = tr("\"inputFrequencyOffset\":%1").arg(currentOffset);
if (lsb || (newModemBw >= 0))
{
int bw = lsb ? (newModemBw < 0 ? -3000 : -newModemBw) : newModemBw;
channelSettingsKeys.append("rfBandwidth");
jsonSettingsStr.append(tr(",\"rfBandwidth\":%2").arg(bw));
}
QString jsonStr = tr("{ \"channelType\": \"%1\", \"%2Settings\": {%3}}")
.arg(QString(newModemId))
.arg(QString(newModemId))
.arg(jsonSettingsStr);
swgChannelSettings.fromJson(jsonStr);
httpRC = m_webAPIAdapterInterface->devicesetChannelSettingsPutPatch(
m_settings.m_deviceIndex,
nbChannels-1, // new index
false, // PATCH
channelSettingsKeys,
swgChannelSettings,
errorResponse
);
if (httpRC/100 != 2)
{
qWarning("RigCtlServerWorker::changeModem: set channel settings error %d: %s",
httpRC, qPrintable(*errorResponse.getMessage()));
rigCtlRC = RIG_EINVAL;
return false;
}
rigCtlRC = RIG_OK;
return true;
}
bool RigCtlServerWorker::getMode(const char **mode, double& passband, rig_errcode_e& rigCtlRC)
{
SWGSDRangel::SWGChannelSettings channelSettingsResponse;
SWGSDRangel::SWGErrorResponse errorResponse;
int httpRC;
// Get channel settings containing inputFrequencyOffset, so we can patch them
httpRC = m_webAPIAdapterInterface->devicesetChannelSettingsGet(
m_settings.m_deviceIndex,
m_settings.m_channelIndex,
channelSettingsResponse,
errorResponse
);
if (httpRC/100 != 2)
{
qWarning("RigCtlServerWorker::getModem: get channel settings error %d: %s",
httpRC, qPrintable(*errorResponse.getMessage()));
rigCtlRC = RIG_EINVAL;
return false;
}
QJsonObject *jsonObj = channelSettingsResponse.asJsonObject();
QString channelType;
int i;
if (!WebAPIUtils::getObjectString(*jsonObj, "channelType", channelType))
{
qWarning("RigCtlServerWorker::getModem: no channelType key in channel settings");
rigCtlRC = RIG_ENIMPL;
return false;
}
for (i = 0; m_modeMap[i].mode != nullptr; i++)
{
if (!channelType.compare(m_modeMap[i].modem))
{
*mode = m_modeMap[i].mode;
break;
}
}
if (!m_modeMap[i].mode)
{
qWarning("RigCtlServerWorker::getModem: channel type not implemented: %s", qPrintable(channelType));
rigCtlRC = RIG_ENIMPL;
return false;
}
if (WebAPIUtils::getSubObjectDouble(*jsonObj, "rfBandwidth", passband))
{
if (!channelType.compare("SSBDemod"))
{
if (passband < 0) { // LSB
passband = -passband;
} else { // USB
*mode = m_modeMap[i+1].mode;
}
}
}
else
{
passband = -1;
}
rigCtlRC = RIG_OK;
return true;
}
bool RigCtlServerWorker::setPowerOn(rig_errcode_e& rigCtlRC)
{
SWGSDRangel::SWGDeviceState response;
SWGSDRangel::SWGErrorResponse errorResponse;
int httpRC = m_webAPIAdapterInterface->devicesetDeviceRunPost(
m_settings.m_deviceIndex,
response,
errorResponse
);
if (httpRC/100 == 2)
{
qDebug("RigCtlServerWorker::setPowerOn: set device start OK");
rigCtlRC = RIG_OK;
return true;
}
else
{
qWarning("RigCtlServerWorker::setPowerOn: set device start error %d: %s",
httpRC, qPrintable(*errorResponse.getMessage()));
rigCtlRC = RIG_EINVAL;
return false;
}
}
bool RigCtlServerWorker::setPowerOff(rig_errcode_e& rigCtlRC)
{
SWGSDRangel::SWGDeviceState response;
SWGSDRangel::SWGErrorResponse errorResponse;
int httpRC = m_webAPIAdapterInterface->devicesetDeviceRunDelete(
m_settings.m_deviceIndex,
response,
errorResponse
);
if (httpRC/100 == 2)
{
qDebug("RigCtlServerWorker::setPowerOff: set device stop OK");
rigCtlRC = RIG_OK;
return true;
}
else
{
qWarning("RigCtlServerWorker::setPowerOff: set device stop error %d: %s",
httpRC, qPrintable(*errorResponse.getMessage()));
rigCtlRC = RIG_EINVAL;
return false;
}
}
bool RigCtlServerWorker::getPower(bool& power, rig_errcode_e& rigCtlRC)
{
SWGSDRangel::SWGDeviceState response;
SWGSDRangel::SWGErrorResponse errorResponse;
int httpRC = m_webAPIAdapterInterface->devicesetDeviceRunGet(
m_settings.m_deviceIndex,
response,
errorResponse
);
if (httpRC/100 != 2)
{
qWarning("RigCtlServerWorker::getPower: get device run state error %d: %s",
httpRC, qPrintable(*errorResponse.getMessage()));
rigCtlRC = RIG_EINVAL;
return false;
}
QJsonObject *jsonObj = response.asJsonObject();
QString state;
if (WebAPIUtils::getObjectString(*jsonObj, "state", state))
{
qDebug("RigCtlServerWorker::getPower: run state is %s", qPrintable(state));
if (state.compare("running")) {
power = false; // not equal
} else {
power = true; // equal
}
}
else
{
qWarning("RigCtlServerWorker::getPower: get device run state error %d: %s",
httpRC, qPrintable(*errorResponse.getMessage()));
rigCtlRC = RIG_EINVAL;
return false;
}
return true;
}