mirror of
				https://github.com/f4exb/sdrangel.git
				synced 2025-10-30 20:40:20 -04:00 
			
		
		
		
	
		
			
				
	
	
		
			848 lines
		
	
	
		
			26 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			848 lines
		
	
	
		
			26 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| ///////////////////////////////////////////////////////////////////////////////////
 | |
| // Copyright (C) 2020 Jon Beniston, M7RCE                                        //
 | |
| // 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 <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_tcpServer(nullptr),
 | |
|     m_clientConnection(nullptr),
 | |
|     m_webAPIAdapterInterface(webAPIAdapterInterface),
 | |
|     m_msgQueueToFeature(nullptr),
 | |
|     m_running(false),
 | |
|     m_mutex(QMutex::Recursive)
 | |
| {
 | |
|     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()) != nullptr)
 | |
| 	{
 | |
| 		if (handleMessage(*message)) {
 | |
| 			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.getForce());
 | |
| 
 | |
|         return true;
 | |
|     }
 | |
|     else
 | |
|     {
 | |
|         return false;
 | |
|     }
 | |
| }
 | |
| 
 | |
| void RigCtlServerWorker::applySettings(const RigCtlServerSettings& settings, bool force)
 | |
| {
 | |
|     qDebug() << "RigCtlServerWorker::applySettings:"
 | |
|             << " m_title: " << settings.m_title
 | |
|             << " m_rgbColor: " << settings.m_rgbColor
 | |
|             << " m_enabled: " << settings.m_enabled
 | |
|             << " m_deviceIndex: " << settings.m_deviceIndex
 | |
|             << " m_channelIndex: " << settings.m_channelIndex
 | |
|             << " m_rigCtlPort: " << settings.m_rigCtlPort
 | |
|             << " m_maxFrequencyOffset: " << settings.m_maxFrequencyOffset
 | |
|             << " force: " << force;
 | |
| 
 | |
|     if ((settings.m_rigCtlPort != m_settings.m_rigCtlPort) ||
 | |
|         (settings.m_enabled != m_settings.m_enabled) ||  force)
 | |
|     {
 | |
|         restartServer(settings.m_enabled, settings.m_rigCtlPort);
 | |
|     }
 | |
| 
 | |
|     m_settings = 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);
 | |
|             sprintf(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)) {
 | |
|                 sprintf(response, "%u\n", (unsigned int) frequency);
 | |
|             } else {
 | |
|                 sprintf(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);
 | |
|                 sprintf(response, "RPRT %d\n", rigCtlRC);
 | |
|             }
 | |
|             else
 | |
|             {
 | |
|                 sprintf(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) {
 | |
|                     sprintf(response, "%s\n", mode);
 | |
|                 } else {
 | |
|                     sprintf(response, "%s %u\n", mode, (unsigned int) passband);
 | |
|                 }
 | |
|             }
 | |
|             else
 | |
|             {
 | |
|                 sprintf(response, "RPRT %d\n", rigCtlRC);
 | |
|             }
 | |
|         }
 | |
|         else if (!strncmp(cmd, "set_powerstat 0", 15))
 | |
|         {
 | |
|             // Power off radio
 | |
|             setPowerOff(rigCtlRC);
 | |
|             sprintf(response, "RPRT %d\n", rigCtlRC);
 | |
|         }
 | |
|         else if (!strncmp(cmd, "set_powerstat 1", 15))
 | |
|         {
 | |
|             // Power on radio
 | |
|             setPowerOn(rigCtlRC);
 | |
|             sprintf(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) {
 | |
|                     sprintf(response, "1\n");
 | |
|                 } else {
 | |
|                     sprintf(response, "0\n");
 | |
|                 }
 | |
|             }
 | |
|             else
 | |
|             {
 | |
|                 sprintf(response, "RPRT %d\n", rigCtlRC);
 | |
|             }
 | |
|         }
 | |
|         else
 | |
|         {
 | |
|             // Unimplemented command
 | |
|             sprintf(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 containg 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 containg 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;
 | |
| }
 |