1
0
mirror of https://github.com/f4exb/sdrangel.git synced 2024-11-10 10:33:29 -05:00

Merge branch 'aaroniartsa'

This commit is contained in:
f4exb 2023-04-06 22:55:54 +02:00
commit d3fbf73ce3
47 changed files with 3417 additions and 438 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 124 KiB

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 750 KiB

View File

@ -751,8 +751,13 @@ void DATVDemodGUI::on_spiSymbolRate_valueChanged(int value)
void DATVDemodGUI::on_datvStdSR_valueChanged(int value)
{
m_settings.m_symbolRate = symbolRateFromIndex(value);
m_settings.m_rfBandwidth = (m_settings.m_symbolRate * 3) / 2;
ui->spiSymbolRate->blockSignals(true);
ui->rfBandwidth->blockSignals(true);
ui->spiSymbolRate->setValue(m_settings.m_symbolRate);
ui->rfBandwidth->setValue(m_settings.m_rfBandwidth);
m_channelMarker.setBandwidth(m_settings.m_rfBandwidth);
ui->rfBandwidth->blockSignals(false);
ui->spiSymbolRate->blockSignals(false);
applySettings();
}

View File

@ -73,3 +73,4 @@ endif()
add_subdirectory(audioinput)
add_subdirectory(kiwisdr)
add_subdirectory(remotetcpinput)
add_subdirectory(aaroniartsainput)

View File

@ -0,0 +1,63 @@
project(aaroniartsainput)
set(aaroniartsainput_SOURCES
aaroniartsainput.cpp
aaroniartsainputplugin.cpp
aaroniartsainputworker.cpp
aaroniartsainputsettings.cpp
aaroniartsainputwebapiadapter.cpp
)
set(aaroniartsainput_HEADERS
aaroniartsainput.h
aaroniartsainputplugin.h
aaroniartsainputworker.h
aaroniartsainputsettings.h
aaroniartsainputwebapiadapter.h
)
include_directories(
${CMAKE_SOURCE_DIR}/swagger/sdrangel/code/qt5/client
${Boost_INCLUDE_DIRS}
)
if(NOT SERVER_MODE)
set(aaroniartsainput_SOURCES
${aaroniartsainput_SOURCES}
aaroniartsainputgui.cpp
aaroniartsainputgui.ui
)
set(aaroniartsainput_HEADERS
${aaroniartsainput_HEADERS}
aaroniartsainputgui.h
)
set(TARGET_NAME inputaaroniartsa)
set(TARGET_LIB "Qt::Widgets")
set(TARGET_LIB_GUI "sdrgui")
set(INSTALL_FOLDER ${INSTALL_PLUGINS_DIR})
else()
set(TARGET_NAME inputaaroniartsasrv)
set(TARGET_LIB "")
set(TARGET_LIB_GUI "")
set(INSTALL_FOLDER ${INSTALL_PLUGINSSRV_DIR})
endif()
add_library(${TARGET_NAME} SHARED
${aaroniartsainput_SOURCES}
)
target_link_libraries(${TARGET_NAME}
Qt::Core
Qt::WebSockets
${TARGET_LIB}
sdrbase
${TARGET_LIB_GUI}
)
install(TARGETS ${TARGET_NAME} DESTINATION ${INSTALL_FOLDER})
# Install debug symbols
if (WIN32)
install(FILES $<TARGET_PDB_FILE:${TARGET_NAME}> CONFIGURATIONS Debug RelWithDebInfo DESTINATION ${INSTALL_FOLDER} )
endif()

View File

@ -0,0 +1,535 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2023 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 <string.h>
#include <errno.h>
#include <QDebug>
#include <QNetworkReply>
#include <QNetworkAccessManager>
#include <QBuffer>
#include <QThread>
#include "SWGDeviceSettings.h"
#include "SWGDeviceState.h"
#include "SWGDeviceReport.h"
#include "SWGAaroniaRTSAReport.h"
#include "aaroniartsainput.h"
#include "device/deviceapi.h"
#include "aaroniartsainputworker.h"
#include "dsp/dspcommands.h"
#include "dsp/dspengine.h"
MESSAGE_CLASS_DEFINITION(AaroniaRTSAInput::MsgConfigureAaroniaRTSA, Message)
MESSAGE_CLASS_DEFINITION(AaroniaRTSAInput::MsgStartStop, Message)
MESSAGE_CLASS_DEFINITION(AaroniaRTSAInput::MsgSetStatus, Message)
AaroniaRTSAInput::AaroniaRTSAInput(DeviceAPI *deviceAPI) :
m_deviceAPI(deviceAPI),
m_sampleRate(10000000),
m_centerFrequency(1450000),
m_settings(),
m_aaroniaRTSAWorker(nullptr),
m_aaroniaRTSAWorkerThread(nullptr),
m_deviceDescription("AaroniaRTSA"),
m_running(false),
m_masterTimer(deviceAPI->getMasterTimer())
{
m_sampleFifo.setLabel(m_deviceDescription);
m_deviceAPI->setNbSourceStreams(1);
if (!m_sampleFifo.setSize(getSampleRate() * 2)) {
qCritical("AaroniaRTSAInput::AaroniaRTSAInput: Could not allocate SampleFifo");
}
m_networkManager = new QNetworkAccessManager();
QObject::connect(
m_networkManager,
&QNetworkAccessManager::finished,
this,
&AaroniaRTSAInput::networkManagerFinished
);
}
AaroniaRTSAInput::~AaroniaRTSAInput()
{
QObject::disconnect(
m_networkManager,
&QNetworkAccessManager::finished,
this,
&AaroniaRTSAInput::networkManagerFinished
);
delete m_networkManager;
if (m_running) {
stop();
}
}
void AaroniaRTSAInput::destroy()
{
delete this;
}
void AaroniaRTSAInput::init()
{
applySettings(m_settings, QList<QString>(), true);
}
bool AaroniaRTSAInput::start()
{
QMutexLocker mutexLocker(&m_mutex);
if (m_running) {
return true;
}
m_aaroniaRTSAWorkerThread = new QThread();
m_aaroniaRTSAWorker = new AaroniaRTSAInputWorker(&m_sampleFifo);
m_aaroniaRTSAWorker->setInputMessageQueue(getInputMessageQueue());
m_aaroniaRTSAWorker->moveToThread(m_aaroniaRTSAWorkerThread);
QObject::connect(m_aaroniaRTSAWorkerThread, &QThread::finished, m_aaroniaRTSAWorker, &QObject::deleteLater);
QObject::connect(m_aaroniaRTSAWorkerThread, &QThread::finished, m_aaroniaRTSAWorkerThread, &QThread::deleteLater);
connect(this, &AaroniaRTSAInput::setWorkerCenterFrequency, m_aaroniaRTSAWorker, &AaroniaRTSAInputWorker::onCenterFrequencyChanged);
connect(this, &AaroniaRTSAInput::setWorkerSampleRate, m_aaroniaRTSAWorker, &AaroniaRTSAInputWorker::onSampleRateChanged);
connect(this, &AaroniaRTSAInput::setWorkerServerAddress, m_aaroniaRTSAWorker, &AaroniaRTSAInputWorker::onServerAddressChanged);
connect(m_aaroniaRTSAWorker, &AaroniaRTSAInputWorker::updateStatus, this, &AaroniaRTSAInput::setWorkerStatus);
m_aaroniaRTSAWorkerThread->start();
m_running = true;
mutexLocker.unlock();
applySettings(m_settings, QList<QString>(), true);
return true;
}
void AaroniaRTSAInput::stop()
{
QMutexLocker mutexLocker(&m_mutex);
if (!m_running) {
return;
}
m_running = false;
setWorkerStatus(0);
if (m_aaroniaRTSAWorkerThread)
{
m_aaroniaRTSAWorkerThread->quit();
m_aaroniaRTSAWorkerThread->wait();
m_aaroniaRTSAWorker = nullptr;
m_aaroniaRTSAWorkerThread = nullptr;
}
}
QByteArray AaroniaRTSAInput::serialize() const
{
return m_settings.serialize();
}
bool AaroniaRTSAInput::deserialize(const QByteArray& data)
{
bool success = true;
if (!m_settings.deserialize(data))
{
m_settings.resetToDefaults();
success = false;
}
MsgConfigureAaroniaRTSA* message = MsgConfigureAaroniaRTSA::create(m_settings, QList<QString>(), true);
m_inputMessageQueue.push(message);
if (m_guiMessageQueue)
{
MsgConfigureAaroniaRTSA* messageToGUI = MsgConfigureAaroniaRTSA::create(m_settings, QList<QString>(), true);
m_guiMessageQueue->push(messageToGUI);
}
return success;
}
const QString& AaroniaRTSAInput::getDeviceDescription() const
{
return m_deviceDescription;
}
int AaroniaRTSAInput::getSampleRate() const
{
return m_sampleRate;
}
quint64 AaroniaRTSAInput::getCenterFrequency() const
{
return m_settings.m_centerFrequency;
}
void AaroniaRTSAInput::setCenterFrequency(qint64 centerFrequency)
{
AaroniaRTSAInputSettings settings = m_settings;
settings.m_centerFrequency = centerFrequency;
MsgConfigureAaroniaRTSA* message = MsgConfigureAaroniaRTSA::create(settings, QList<QString>{"centerFrequency"}, false);
m_inputMessageQueue.push(message);
if (m_guiMessageQueue)
{
MsgConfigureAaroniaRTSA* messageToGUI = MsgConfigureAaroniaRTSA::create(settings, QList<QString>{"centerFrequency"}, false);
m_guiMessageQueue->push(messageToGUI);
}
}
void AaroniaRTSAInput::setWorkerStatus(int status)
{
if (m_guiMessageQueue) {
m_guiMessageQueue->push(MsgSetStatus::create(status));
}
}
bool AaroniaRTSAInput::handleMessage(const Message& message)
{
if (MsgConfigureAaroniaRTSA::match(message))
{
MsgConfigureAaroniaRTSA& conf = (MsgConfigureAaroniaRTSA&) message;
qDebug() << "AaroniaRTSAInput::handleMessage: MsgConfigureAaroniaRTSA";
bool success = applySettings(conf.getSettings(), conf.getSettingsKeys(), conf.getForce());
if (!success) {
qDebug("AaroniaRTSAInput::handleMessage: config error");
}
return true;
}
else if (AaroniaRTSAInputWorker::MsgReportSampleRateAndFrequency::match(message))
{
AaroniaRTSAInputWorker::MsgReportSampleRateAndFrequency& report = (AaroniaRTSAInputWorker::MsgReportSampleRateAndFrequency&) message;
m_sampleRate = report.getSampleRate();
m_centerFrequency = report.getCenterFrequency();
qDebug() << "AaroniaRTSAInput::handleMessage: AaroniaRTSAInputWorker::MsgReportSampleRateAndFrequency:"
<< " m_sampleRate: " << m_sampleRate
<< " m-centerFrequency" << m_centerFrequency;
if (!m_sampleFifo.setSize(m_sampleRate * 2)) {
qCritical("AaroniaRTSAInput::AaroniaRTSAInput: Could not allocate SampleFifo");
}
DSPSignalNotification *notif = new DSPSignalNotification(
m_sampleRate, m_centerFrequency);
m_deviceAPI->getDeviceEngineInputMessageQueue()->push(notif);
return true;
}
else if (MsgStartStop::match(message))
{
MsgStartStop& cmd = (MsgStartStop&) message;
qDebug() << "AaroniaRTSAInput::handleMessage: MsgStartStop: " << (cmd.getStartStop() ? "start" : "stop");
if (cmd.getStartStop())
{
if (m_deviceAPI->initDeviceEngine()) {
m_deviceAPI->startDeviceEngine();
}
}
else
{
m_deviceAPI->stopDeviceEngine();
}
if (m_settings.m_useReverseAPI) {
webapiReverseSendStartStop(cmd.getStartStop());
}
return true;
}
else
{
return false;
}
}
int AaroniaRTSAInput::getStatus() const
{
if (m_aaroniaRTSAWorker) {
return m_aaroniaRTSAWorker->getStatus();
} else {
return 0;
}
}
bool AaroniaRTSAInput::applySettings(const AaroniaRTSAInputSettings& settings, const QList<QString>& settingsKeys, bool force)
{
qDebug() << "AaroniaRTSAInput::applySettings: force: "<< force << settings.getDebugString(settingsKeys, force);
if (settingsKeys.contains("serverAddress") || force)
{
emit setWorkerServerAddress(settings.m_serverAddress);
}
if (settingsKeys.contains("centerFrequency") || force)
{
emit setWorkerCenterFrequency(settings.m_centerFrequency);
// DSPSignalNotification *notif = new DSPSignalNotification(
// getSampleRate(), settings.m_centerFrequency);
// m_deviceAPI->getDeviceEngineInputMessageQueue()->push(notif);
}
if (settingsKeys.contains("sampleRate")) {
emit setWorkerSampleRate(settings.m_sampleRate);
}
if (settingsKeys.contains("useReverseAPI"))
{
bool fullUpdate = (settingsKeys.contains("useReverseAPI") && settings.m_useReverseAPI) ||
settingsKeys.contains("reverseAPIAddress") ||
settingsKeys.contains("reverseAPIPort") ||
settingsKeys.contains("reverseAPIDeviceIndex");
webapiReverseSendSettings(settingsKeys, settings, fullUpdate || force);
}
if (force) {
m_settings = settings;
} else {
m_settings.applySettings(settingsKeys, settings);
}
return true;
}
int AaroniaRTSAInput::webapiRunGet(
SWGSDRangel::SWGDeviceState& response,
QString& errorMessage)
{
(void) errorMessage;
m_deviceAPI->getDeviceEngineStateStr(*response.getState());
return 200;
}
int AaroniaRTSAInput::webapiRun(
bool run,
SWGSDRangel::SWGDeviceState& response,
QString& errorMessage)
{
(void) errorMessage;
m_deviceAPI->getDeviceEngineStateStr(*response.getState());
MsgStartStop *message = MsgStartStop::create(run);
m_inputMessageQueue.push(message);
if (m_guiMessageQueue) // forward to GUI if any
{
MsgStartStop *msgToGUI = MsgStartStop::create(run);
m_guiMessageQueue->push(msgToGUI);
}
return 200;
}
int AaroniaRTSAInput::webapiSettingsGet(
SWGSDRangel::SWGDeviceSettings& response,
QString& errorMessage)
{
(void) errorMessage;
response.setAaroniaRtsaSettings(new SWGSDRangel::SWGAaroniaRTSASettings());
response.getAaroniaRtsaSettings()->init();
webapiFormatDeviceSettings(response, m_settings);
return 200;
}
int AaroniaRTSAInput::webapiSettingsPutPatch(
bool force,
const QStringList& deviceSettingsKeys,
SWGSDRangel::SWGDeviceSettings& response, // query + response
QString& errorMessage)
{
(void) errorMessage;
AaroniaRTSAInputSettings settings = m_settings;
webapiUpdateDeviceSettings(settings, deviceSettingsKeys, response);
MsgConfigureAaroniaRTSA *msg = MsgConfigureAaroniaRTSA::create(settings, deviceSettingsKeys, force);
m_inputMessageQueue.push(msg);
if (m_guiMessageQueue) // forward to GUI if any
{
MsgConfigureAaroniaRTSA *msgToGUI = MsgConfigureAaroniaRTSA::create(settings, deviceSettingsKeys, force);
m_guiMessageQueue->push(msgToGUI);
}
webapiFormatDeviceSettings(response, settings);
return 200;
}
void AaroniaRTSAInput::webapiUpdateDeviceSettings(
AaroniaRTSAInputSettings& settings,
const QStringList& deviceSettingsKeys,
SWGSDRangel::SWGDeviceSettings& response)
{
if (deviceSettingsKeys.contains("centerFrequency")) {
settings.m_centerFrequency = response.getAaroniaRtsaSettings()->getCenterFrequency();
}
if (deviceSettingsKeys.contains("centerFrequency")) {
settings.m_sampleRate = response.getAaroniaRtsaSettings()->getSampleRate();
}
if (deviceSettingsKeys.contains("serverAddress")) {
settings.m_serverAddress = *response.getAaroniaRtsaSettings()->getServerAddress();
}
if (deviceSettingsKeys.contains("useReverseAPI")) {
settings.m_useReverseAPI = response.getAaroniaRtsaSettings()->getUseReverseApi() != 0;
}
if (deviceSettingsKeys.contains("reverseAPIAddress")) {
settings.m_reverseAPIAddress = *response.getAaroniaRtsaSettings()->getReverseApiAddress();
}
if (deviceSettingsKeys.contains("reverseAPIPort")) {
settings.m_reverseAPIPort = response.getAaroniaRtsaSettings()->getReverseApiPort();
}
if (deviceSettingsKeys.contains("reverseAPIDeviceIndex")) {
settings.m_reverseAPIDeviceIndex = response.getAaroniaRtsaSettings()->getReverseApiDeviceIndex();
}
}
int AaroniaRTSAInput::webapiReportGet(
SWGSDRangel::SWGDeviceReport& response,
QString& errorMessage)
{
(void) errorMessage;
response.setAaroniaSdrReport(new SWGSDRangel::SWGAaroniaRTSAReport());
response.getAirspyHfReport()->init();
webapiFormatDeviceReport(response);
return 200;
}
void AaroniaRTSAInput::webapiFormatDeviceSettings(SWGSDRangel::SWGDeviceSettings& response, const AaroniaRTSAInputSettings& settings)
{
response.getAaroniaRtsaSettings()->setCenterFrequency(settings.m_centerFrequency);
response.getAaroniaRtsaSettings()->setSampleRate(settings.m_sampleRate);
if (response.getAaroniaRtsaSettings()->getServerAddress()) {
*response.getAaroniaRtsaSettings()->getServerAddress() = settings.m_serverAddress;
} else {
response.getAaroniaRtsaSettings()->setServerAddress(new QString(settings.m_serverAddress));
}
response.getAaroniaRtsaSettings()->setUseReverseApi(settings.m_useReverseAPI ? 1 : 0);
if (response.getAaroniaRtsaSettings()->getReverseApiAddress()) {
*response.getAaroniaRtsaSettings()->getReverseApiAddress() = settings.m_reverseAPIAddress;
} else {
response.getAaroniaRtsaSettings()->setReverseApiAddress(new QString(settings.m_reverseAPIAddress));
}
response.getAaroniaRtsaSettings()->setReverseApiPort(settings.m_reverseAPIPort);
response.getAaroniaRtsaSettings()->setReverseApiDeviceIndex(settings.m_reverseAPIDeviceIndex);
}
void AaroniaRTSAInput::webapiFormatDeviceReport(SWGSDRangel::SWGDeviceReport& response)
{
response.getAaroniaSdrReport()->setStatus(getStatus());
}
void AaroniaRTSAInput::webapiReverseSendSettings(const QList<QString>& deviceSettingsKeys, const AaroniaRTSAInputSettings& settings, bool force)
{
SWGSDRangel::SWGDeviceSettings *swgDeviceSettings = new SWGSDRangel::SWGDeviceSettings();
swgDeviceSettings->setDirection(0); // single Rx
swgDeviceSettings->setOriginatorIndex(m_deviceAPI->getDeviceSetIndex());
swgDeviceSettings->setDeviceHwType(new QString("AaroniaRTSA"));
swgDeviceSettings->setAaroniaRtsaSettings(new SWGSDRangel::SWGAaroniaRTSASettings());
SWGSDRangel::SWGAaroniaRTSASettings *swgAaroniaRTSASettings = swgDeviceSettings->getAaroniaRtsaSettings();
// transfer data that has been modified. When force is on transfer all data except reverse API data
if (deviceSettingsKeys.contains("centerFrequency") || force) {
swgAaroniaRTSASettings->setCenterFrequency(settings.m_centerFrequency);
}
if (deviceSettingsKeys.contains("serverAddress") || force) {
swgAaroniaRTSASettings->setServerAddress(new QString(settings.m_serverAddress));
}
QString deviceSettingsURL = QString("http://%1:%2/sdrangel/deviceset/%3/device/settings")
.arg(settings.m_reverseAPIAddress)
.arg(settings.m_reverseAPIPort)
.arg(settings.m_reverseAPIDeviceIndex);
m_networkRequest.setUrl(QUrl(deviceSettingsURL));
m_networkRequest.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
QBuffer *buffer = new QBuffer();
buffer->open((QBuffer::ReadWrite));
buffer->write(swgDeviceSettings->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 swgDeviceSettings;
}
void AaroniaRTSAInput::webapiReverseSendStartStop(bool start)
{
SWGSDRangel::SWGDeviceSettings *swgDeviceSettings = new SWGSDRangel::SWGDeviceSettings();
swgDeviceSettings->setDirection(0); // single Rx
swgDeviceSettings->setOriginatorIndex(m_deviceAPI->getDeviceSetIndex());
swgDeviceSettings->setDeviceHwType(new QString("AaroniaRTSA"));
QString deviceSettingsURL = QString("http://%1:%2/sdrangel/deviceset/%3/device/run")
.arg(m_settings.m_reverseAPIAddress)
.arg(m_settings.m_reverseAPIPort)
.arg(m_settings.m_reverseAPIDeviceIndex);
m_networkRequest.setUrl(QUrl(deviceSettingsURL));
m_networkRequest.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
QBuffer *buffer = new QBuffer();
buffer->open((QBuffer::ReadWrite));
buffer->write(swgDeviceSettings->asJson().toUtf8());
buffer->seek(0);
QNetworkReply *reply;
if (start) {
reply = m_networkManager->sendCustomRequest(m_networkRequest, "POST", buffer);
} else {
reply = m_networkManager->sendCustomRequest(m_networkRequest, "DELETE", buffer);
}
buffer->setParent(reply);
delete swgDeviceSettings;
}
void AaroniaRTSAInput::networkManagerFinished(QNetworkReply *reply)
{
QNetworkReply::NetworkError replyError = reply->error();
if (replyError)
{
qWarning() << "AaroniaRTSAInput::networkManagerFinished:"
<< " error(" << (int) replyError
<< "): " << replyError
<< ": " << reply->errorString();
}
else
{
QString answer = reply->readAll();
answer.chop(1); // remove last \n
qDebug("AaroniaRTSAInput::networkManagerFinished: reply:\n%s", answer.toStdString().c_str());
}
reply->deleteLater();
}

View File

@ -0,0 +1,186 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2023 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 _AARONIARTSA_AARONIARTSAINPUT_H_
#define _AARONIARTSA_AARONIARTSAINPUT_H_
#include <QString>
#include <QByteArray>
#include <QTimer>
#include <QNetworkRequest>
#include <dsp/devicesamplesource.h>
#include "aaroniartsainputsettings.h"
class DeviceAPI;
class AaroniaRTSAInputWorker;
class QNetworkAccessManager;
class QNetworkReply;
class QThread;
class AaroniaRTSAInput : public DeviceSampleSource {
Q_OBJECT
public:
class MsgConfigureAaroniaRTSA : public Message {
MESSAGE_CLASS_DECLARATION
public:
const AaroniaRTSAInputSettings& getSettings() const { return m_settings; }
const QList<QString>& getSettingsKeys() const { return m_settingsKeys; }
bool getForce() const { return m_force; }
static MsgConfigureAaroniaRTSA* create(const AaroniaRTSAInputSettings& settings, const QList<QString>& settingsKeys, bool force)
{
return new MsgConfigureAaroniaRTSA(settings, settingsKeys, force);
}
private:
AaroniaRTSAInputSettings m_settings;
QList<QString> m_settingsKeys;
bool m_force;
MsgConfigureAaroniaRTSA(const AaroniaRTSAInputSettings& settings, const QList<QString>& settingsKeys, bool force) :
Message(),
m_settings(settings),
m_settingsKeys(settingsKeys),
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 MsgSetStatus : public Message {
MESSAGE_CLASS_DECLARATION
public:
int getStatus() const { return m_status; }
static MsgSetStatus* create(int status) {
return new MsgSetStatus(status);
}
protected:
int m_status;
MsgSetStatus(int status) :
Message(),
m_status(status)
{ }
};
AaroniaRTSAInput(DeviceAPI *deviceAPI);
virtual ~AaroniaRTSAInput();
virtual void destroy();
virtual void init();
virtual bool start();
virtual void stop();
virtual QByteArray serialize() const;
virtual bool deserialize(const QByteArray& data);
virtual void setMessageQueueToGUI(MessageQueue *queue) { m_guiMessageQueue = queue; }
virtual const QString& getDeviceDescription() const;
virtual int getSampleRate() const;
virtual void setSampleRate(int sampleRate) { (void) sampleRate; }
virtual quint64 getCenterFrequency() const;
virtual void setCenterFrequency(qint64 centerFrequency);
virtual bool handleMessage(const Message& message);
virtual int webapiSettingsGet(
SWGSDRangel::SWGDeviceSettings& response,
QString& errorMessage);
virtual int webapiSettingsPutPatch(
bool force,
const QStringList& deviceSettingsKeys,
SWGSDRangel::SWGDeviceSettings& response, // query + response
QString& errorMessage);
virtual int webapiRunGet(
SWGSDRangel::SWGDeviceState& response,
QString& errorMessage);
virtual int webapiRun(
bool run,
SWGSDRangel::SWGDeviceState& response,
QString& errorMessage);
virtual int webapiReportGet(
SWGSDRangel::SWGDeviceReport& response,
QString& errorMessage);
static void webapiFormatDeviceSettings(
SWGSDRangel::SWGDeviceSettings& response,
const AaroniaRTSAInputSettings& settings);
static void webapiUpdateDeviceSettings(
AaroniaRTSAInputSettings& settings,
const QStringList& deviceSettingsKeys,
SWGSDRangel::SWGDeviceSettings& response);
private:
DeviceAPI *m_deviceAPI;
QMutex m_mutex;
int m_sampleRate;
quint64 m_centerFrequency;
AaroniaRTSAInputSettings m_settings;
AaroniaRTSAInputWorker* m_aaroniaRTSAWorker;
QThread *m_aaroniaRTSAWorkerThread;
QString m_deviceDescription;
bool m_running;
const QTimer& m_masterTimer;
QNetworkAccessManager *m_networkManager;
QNetworkRequest m_networkRequest;
int getStatus() const;
bool applySettings(const AaroniaRTSAInputSettings& settings, const QList<QString>& settingsKeys, bool force);
void webapiFormatDeviceReport(SWGSDRangel::SWGDeviceReport& response);
void webapiReverseSendSettings(const QList<QString>& deviceSettingsKeys, const AaroniaRTSAInputSettings& settings, bool force);
void webapiReverseSendStartStop(bool start);
signals:
void startWorker();
void stopWorker();
void setWorkerCenterFrequency(quint64 centerFrequency);
void setWorkerSampleRate(int sampleRate);
void setWorkerServerAddress(QString serverAddress);
private slots:
void setWorkerStatus(int status);
void networkManagerFinished(QNetworkReply *reply);
};
#endif // _AARONIARTSA_AARONIARTSAINPUT_H_

View File

@ -0,0 +1,347 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2023 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 <QTime>
#include <QDateTime>
#include <QString>
#include <QMessageBox>
#include <QFileDialog>
#include "ui_aaroniartsainputgui.h"
#include "plugin/pluginapi.h"
#include "gui/colormapper.h"
#include "gui/glspectrum.h"
#include "gui/basicdevicesettingsdialog.h"
#include "gui/dialogpositioner.h"
#include "dsp/dspengine.h"
#include "dsp/dspcommands.h"
#include "util/db.h"
#include "mainwindow.h"
#include "aaroniartsainputgui.h"
#include "device/deviceapi.h"
#include "device/deviceuiset.h"
AaroniaRTSAInputGui::AaroniaRTSAInputGui(DeviceUISet *deviceUISet, QWidget* parent) :
DeviceGUI(parent),
ui(new Ui::AaroniaRTSAInputGui),
m_settings(),
m_doApplySettings(true),
m_forceSettings(true),
m_sampleSource(0),
m_tickCount(0),
m_lastEngineState(DeviceAPI::StNotStarted)
{
qDebug("AaroniaRTSAInputGui::AaroniaRTSAInputGui");
m_deviceUISet = deviceUISet;
setAttribute(Qt::WA_DeleteOnClose, true);
m_sampleSource = m_deviceUISet->m_deviceAPI->getSampleSource();
m_statusTooltips.push_back("Idle"); // 0
m_statusTooltips.push_back("Unstable"); // 1
m_statusTooltips.push_back("Connected"); // 2
m_statusTooltips.push_back("Error"); // 3
m_statusTooltips.push_back("Disconnected"); // 4
m_statusColors.push_back("gray"); // Idle
m_statusColors.push_back("rgb(232, 212, 35)"); // Unstable (yellow)
m_statusColors.push_back("rgb(35, 138, 35)"); // Connected (green)
m_statusColors.push_back("rgb(232, 85, 85)"); // Error (red)
m_statusColors.push_back("rgb(232, 85, 232)"); // Disconnected (magenta)
ui->setupUi(getContents());
sizeToContents();
getContents()->setStyleSheet("#AaroniaRTSAInputGui { background-color: rgb(64, 64, 64); }");
m_helpURL = "plugins/samplesource/aaroniartsainput/readme.md";
ui->centerFrequency->setColorMapper(ColorMapper(ColorMapper::GrayGold));
ui->centerFrequency->setValueRange(9, 0, 999999999);
ui->sampleRate->setColorMapper(ColorMapper(ColorMapper::GrayGreenYellow));
ui->sampleRate->setValueRange(8, 2000U, 20000000U);
displaySettings();
makeUIConnections();
connect(&m_updateTimer, SIGNAL(timeout()), this, SLOT(updateHardware()));
connect(&m_statusTimer, SIGNAL(timeout()), this, SLOT(updateStatus()));
m_statusTimer.start(500);
connect(&m_inputMessageQueue, SIGNAL(messageEnqueued()), this, SLOT(handleInputMessages()), Qt::QueuedConnection);
m_sampleSource->setMessageQueueToGUI(&m_inputMessageQueue);
connect(this, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(openDeviceSettingsDialog(const QPoint &)));
}
AaroniaRTSAInputGui::~AaroniaRTSAInputGui()
{
delete ui;
}
void AaroniaRTSAInputGui::destroy()
{
delete this;
}
void AaroniaRTSAInputGui::resetToDefaults()
{
m_settings.resetToDefaults();
displaySettings();
m_forceSettings = true;
sendSettings();
}
QByteArray AaroniaRTSAInputGui::serialize() const
{
return m_settings.serialize();
}
bool AaroniaRTSAInputGui::deserialize(const QByteArray& data)
{
if(m_settings.deserialize(data)) {
displaySettings();
m_forceSettings = true;
sendSettings();
return true;
} else {
resetToDefaults();
return false;
}
}
void AaroniaRTSAInputGui::on_startStop_toggled(bool checked)
{
if (m_doApplySettings)
{
AaroniaRTSAInput::MsgStartStop *message = AaroniaRTSAInput::MsgStartStop::create(checked);
m_sampleSource->getInputMessageQueue()->push(message);
}
}
void AaroniaRTSAInputGui::on_centerFrequency_changed(quint64 value)
{
m_settings.m_centerFrequency = value * 1000;
m_settingsKeys.append("centerFrequency");
sendSettings();
}
void AaroniaRTSAInputGui::on_sampleRate_changed(quint64 value)
{
m_settings.m_sampleRate = value;
m_settingsKeys.append("sampleRate");
sendSettings();
}
void AaroniaRTSAInputGui::on_serverAddress_returnPressed()
{
on_serverAddressApplyButton_clicked();
}
void AaroniaRTSAInputGui::on_serverAddressApplyButton_clicked()
{
QString serverAddress = ui->serverAddress->text();
QUrl url(serverAddress);
if (QStringList{"ws", "wss", "http", "https"}.contains(url.scheme())) {
m_settings.m_serverAddress = QString("%1:%2").arg(url.host()).arg(url.port());
} else {
m_settings.m_serverAddress = serverAddress;
}
m_settingsKeys.append("serverAddress");
sendSettings();
}
void AaroniaRTSAInputGui::displaySettings()
{
blockApplySettings(true);
ui->centerFrequency->setValue(m_settings.m_centerFrequency / 1000);
ui->serverAddress->setText(m_settings.m_serverAddress);
blockApplySettings(false);
}
void AaroniaRTSAInputGui::sendSettings()
{
if (!m_updateTimer.isActive()) {
m_updateTimer.start(100);
}
}
void AaroniaRTSAInputGui::updateHardware()
{
if (m_doApplySettings)
{
AaroniaRTSAInput::MsgConfigureAaroniaRTSA* message = AaroniaRTSAInput::MsgConfigureAaroniaRTSA::create(m_settings, m_settingsKeys, m_forceSettings);
m_sampleSource->getInputMessageQueue()->push(message);
m_forceSettings = false;
m_settingsKeys.clear();
m_updateTimer.stop();
}
}
void AaroniaRTSAInputGui::updateStatus()
{
int state = m_deviceUISet->m_deviceAPI->state();
if (m_lastEngineState != state)
{
switch (state)
{
case DeviceAPI::StNotStarted:
ui->startStop->setStyleSheet("QToolButton { background:rgb(79,79,79); }");
break;
case DeviceAPI::StIdle:
ui->startStop->setStyleSheet("QToolButton { background-color : blue; }");
break;
case DeviceAPI::StRunning:
ui->startStop->setStyleSheet("QToolButton { background-color : green; }");
break;
case DeviceAPI::StError:
ui->startStop->setStyleSheet("QToolButton { background-color : red; }");
QMessageBox::information(this, tr("Message"), m_deviceUISet->m_deviceAPI->errorMessage());
break;
default:
break;
}
m_lastEngineState = state;
}
}
bool AaroniaRTSAInputGui::handleMessage(const Message& message)
{
if (AaroniaRTSAInput::MsgConfigureAaroniaRTSA::match(message))
{
qDebug("AaroniaRTSAInputGui::handleMessage: MsgConfigureAaroniaRTSA");
const AaroniaRTSAInput::MsgConfigureAaroniaRTSA& cfg = (AaroniaRTSAInput::MsgConfigureAaroniaRTSA&) message;
if (cfg.getForce()) {
m_settings = cfg.getSettings();
} else {
m_settings.applySettings(cfg.getSettingsKeys(), cfg.getSettings());
}
displaySettings();
return true;
}
else if (AaroniaRTSAInput::MsgStartStop::match(message))
{
qDebug("AaroniaRTSAInputGui::handleMessage: MsgStartStop");
AaroniaRTSAInput::MsgStartStop& notif = (AaroniaRTSAInput::MsgStartStop&) message;
blockApplySettings(true);
ui->startStop->setChecked(notif.getStartStop());
blockApplySettings(false);
return true;
}
else if (AaroniaRTSAInput::MsgSetStatus::match(message))
{
qDebug("AaroniaRTSAInputGui::handleMessage: MsgSetStatus");
AaroniaRTSAInput::MsgSetStatus& notif = (AaroniaRTSAInput::MsgSetStatus&) message;
int status = notif.getStatus();
ui->statusIndicator->setToolTip(m_statusTooltips[status]);
ui->statusIndicator->setStyleSheet("QLabel { background-color: " +
m_statusColors[status] + "; border-radius: 7px; }");
return true;
}
else
{
return false;
}
}
void AaroniaRTSAInputGui::handleInputMessages()
{
Message* message;
while ((message = m_inputMessageQueue.pop()) != 0)
{
if (DSPSignalNotification::match(*message))
{
DSPSignalNotification* notif = (DSPSignalNotification*) message;
m_deviceSampleRate = notif->getSampleRate();
m_deviceCenterFrequency = notif->getCenterFrequency();
qDebug("AaroniaRTSAInputGui::handleInputMessages: DSPSignalNotification: SampleRate:%d, CenterFrequency:%llu",
notif->getSampleRate(),
notif->getCenterFrequency());
updateSampleRateAndFrequency();
delete message;
}
else
{
if (handleMessage(*message))
{
delete message;
}
}
}
}
void AaroniaRTSAInputGui::updateSampleRateAndFrequency()
{
m_deviceUISet->getSpectrum()->setSampleRate(m_deviceSampleRate);
m_deviceUISet->getSpectrum()->setCenterFrequency(m_deviceCenterFrequency);
// ui->deviceRateText->setText(tr("%1M").arg((float)m_deviceSampleRate / 1000 / 1000));
ui->deviceRateText->setText(tr("%1k").arg(QString::number(m_deviceSampleRate / 1000.0f, 'g', 5)));
blockApplySettings(true);
ui->centerFrequency->setValue(m_deviceCenterFrequency / 1000);
ui->sampleRate->setValue(m_deviceSampleRate);
blockApplySettings(false);
}
void AaroniaRTSAInputGui::openDeviceSettingsDialog(const QPoint& p)
{
if (m_contextMenuType == ContextMenuDeviceSettings)
{
BasicDeviceSettingsDialog dialog(this);
dialog.setUseReverseAPI(m_settings.m_useReverseAPI);
dialog.setReverseAPIAddress(m_settings.m_reverseAPIAddress);
dialog.setReverseAPIPort(m_settings.m_reverseAPIPort);
dialog.setReverseAPIDeviceIndex(m_settings.m_reverseAPIDeviceIndex);
dialog.move(p);
new DialogPositioner(&dialog, false);
dialog.exec();
m_settings.m_useReverseAPI = dialog.useReverseAPI();
m_settings.m_reverseAPIAddress = dialog.getReverseAPIAddress();
m_settings.m_reverseAPIPort = dialog.getReverseAPIPort();
m_settings.m_reverseAPIDeviceIndex = dialog.getReverseAPIDeviceIndex();
m_settingsKeys.append("useReverseAPI");
m_settingsKeys.append("reverseAPIAddress");
m_settingsKeys.append("reverseAPIPort");
m_settingsKeys.append("reverseAPIDeviceIndex");
sendSettings();
}
resetContextMenuType();
}
void AaroniaRTSAInputGui::makeUIConnections()
{
QObject::connect(ui->startStop, &ButtonSwitch::toggled, this, &AaroniaRTSAInputGui::on_startStop_toggled);
QObject::connect(ui->centerFrequency, &ValueDial::changed, this, &AaroniaRTSAInputGui::on_centerFrequency_changed);
QObject::connect(ui->sampleRate, &ValueDial::changed, this, &AaroniaRTSAInputGui::on_sampleRate_changed);
QObject::connect(ui->serverAddress, &QLineEdit::returnPressed, this, &AaroniaRTSAInputGui::on_serverAddress_returnPressed);
QObject::connect(ui->serverAddressApplyButton, &QPushButton::clicked, this, &AaroniaRTSAInputGui::on_serverAddressApplyButton_clicked);
}

View File

@ -0,0 +1,86 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2023 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 _AARONIARTSA_AARONIARTSAGUI_H_
#define _AARONIARTSA_AARONIARTSAGUI_H_
#include <QTimer>
#include <QWidget>
#include "device/devicegui.h"
#include "util/messagequeue.h"
#include "aaroniartsainputsettings.h"
#include "aaroniartsainput.h"
class DeviceUISet;
namespace Ui {
class AaroniaRTSAInputGui;
}
class AaroniaRTSAInputGui : public DeviceGUI {
Q_OBJECT
public:
explicit AaroniaRTSAInputGui(DeviceUISet *deviceUISet, QWidget* parent = 0);
virtual ~AaroniaRTSAInputGui();
virtual void destroy();
void resetToDefaults();
QByteArray serialize() const;
bool deserialize(const QByteArray& data);
virtual MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; }
private:
Ui::AaroniaRTSAInputGui* ui;
AaroniaRTSAInputSettings m_settings;
QList<QString> m_settingsKeys;
QTimer m_updateTimer;
QTimer m_statusTimer;
bool m_doApplySettings;
bool m_forceSettings;
DeviceSampleSource* m_sampleSource;
std::size_t m_tickCount;
int m_deviceSampleRate;
quint64 m_deviceCenterFrequency; //!< Center frequency in device
int m_lastEngineState;
MessageQueue m_inputMessageQueue;
std::vector<QString> m_statusColors;
std::vector<QString> m_statusTooltips;
void blockApplySettings(bool block) { m_doApplySettings = !block; }
void displaySettings();
void sendSettings();
void updateSampleRateAndFrequency();
bool handleMessage(const Message& message);
void makeUIConnections();
private slots:
void handleInputMessages();
void on_startStop_toggled(bool checked);
void on_centerFrequency_changed(quint64 value);
void on_sampleRate_changed(quint64 value);
void on_serverAddress_returnPressed();
void on_serverAddressApplyButton_clicked();
void openDeviceSettingsDialog(const QPoint& p);
void updateStatus();
void updateHardware();
};
#endif // _AARONIARTSA_AARONIARTSAGUI_H_

View File

@ -0,0 +1,326 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>AaroniaRTSAInputGui</class>
<widget class="QWidget" name="AaroniaRTSAInputGui">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>360</width>
<height>131</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>360</width>
<height>130</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>380</width>
<height>131</height>
</size>
</property>
<property name="font">
<font>
<family>Liberation Sans</family>
<pointsize>9</pointsize>
<weight>50</weight>
<italic>false</italic>
<bold>false</bold>
</font>
</property>
<property name="windowTitle">
<string>AaroniaRTSA</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="horizontalLayout_freq">
<item>
<layout class="QVBoxLayout" name="deviceUILayout">
<item>
<layout class="QHBoxLayout" name="deviceButtonsLayout">
<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>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="deviceRateLayout">
<item>
<widget class="QLabel" name="deviceRateText">
<property name="minimumSize">
<size>
<width>58</width>
<height>0</height>
</size>
</property>
<property name="toolTip">
<string>I/Q sample rate kS/s</string>
</property>
<property name="text">
<string>0000.00k</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</item>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="ValueDial" name="centerFrequency" 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>16</pointsize>
<weight>50</weight>
<italic>false</italic>
<bold>false</bold>
</font>
</property>
<property name="cursor">
<cursorShape>PointingHandCursor</cursorShape>
</property>
<property name="focusPolicy">
<enum>Qt::StrongFocus</enum>
</property>
<property name="toolTip">
<string>Tuner center frequency in kHz</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="freqUnits">
<property name="text">
<string> kHz</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item>
<widget class="Line" name="line_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="sampleRateLayout">
<property name="topMargin">
<number>2</number>
</property>
<item>
<widget class="QLabel" name="sampleRateLabel">
<property name="text">
<string>SR</string>
</property>
</widget>
</item>
<item>
<widget class="ValueDial" name="sampleRate" 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>
<weight>50</weight>
<italic>false</italic>
<bold>false</bold>
</font>
</property>
<property name="cursor">
<cursorShape>PointingHandCursor</cursorShape>
</property>
<property name="toolTip">
<string>Device sample rate</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="rateUnits">
<property name="text">
<string>S/s</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_4">
<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="serverAddressLayout">
<item>
<widget class="QLabel" name="serverAddressLabel">
<property name="text">
<string>Addr</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="serverAddress">
<property name="toolTip">
<string>Server address</string>
</property>
<property name="text">
<string>127.0.0.1:8073</string>
</property>
</widget>
</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>14</width>
<height>14</height>
</size>
</property>
<property name="toolTip">
<string>Idle</string>
</property>
<property name="styleSheet">
<string notr="true">QLabel { background-color: gray; border-radius: 7px; }</string>
</property>
<property name="text">
<string/>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="serverAddressApplyButton">
<property name="maximumSize">
<size>
<width>30</width>
<height>16777215</height>
</size>
</property>
<property name="text">
<string>Set</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>ValueDial</class>
<extends>QWidget</extends>
<header>gui/valuedial.h</header>
<container>1</container>
</customwidget>
<customwidget>
<class>ButtonSwitch</class>
<extends>QToolButton</extends>
<header>gui/buttonswitch.h</header>
</customwidget>
</customwidgets>
<resources>
<include location="../../../sdrgui/resources/res.qrc"/>
</resources>
<connections/>
</ui>

View File

@ -0,0 +1,145 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2023 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"
#include "util/simpleserializer.h"
#ifdef SERVER_MODE
#include "aaroniartsainput.h"
#else
#include "aaroniartsainputgui.h"
#endif
#include "aaroniartsainputplugin.h"
#include "aaroniartsainputwebapiadapter.h"
const PluginDescriptor AaroniaRTSAInputPlugin::m_pluginDescriptor = {
QStringLiteral("AaroniaRTSA"),
QStringLiteral("AaroniaRTSA input"),
QStringLiteral("7.12.0"),
QStringLiteral("(c) Edouard Griffiths, F4EXB"),
QStringLiteral("https://github.com/f4exb/sdrangel"),
true,
QStringLiteral("https://github.com/f4exb/sdrangel")
};
static constexpr const char* const m_hardwareID = "AaroniaRTSA";
static constexpr const char* const m_deviceTypeID = AARONIARTSA_DEVICE_TYPE_ID;
AaroniaRTSAInputPlugin::AaroniaRTSAInputPlugin(QObject* parent) :
QObject(parent)
{
}
const PluginDescriptor& AaroniaRTSAInputPlugin::getPluginDescriptor() const
{
return m_pluginDescriptor;
}
void AaroniaRTSAInputPlugin::initPlugin(PluginAPI* pluginAPI)
{
pluginAPI->registerSampleSource(m_deviceTypeID, this);
}
void AaroniaRTSAInputPlugin::enumOriginDevices(QStringList& listedHwIds, OriginDevices& originDevices)
{
if (listedHwIds.contains(m_hardwareID)) { // check if it was done
return;
}
originDevices.append(OriginDevice(
"AaroniaRTSA",
m_hardwareID,
QString(),
0,
1, // nb Rx
0 // nb Tx
));
listedHwIds.append(m_hardwareID);
}
PluginInterface::SamplingDevices AaroniaRTSAInputPlugin::enumSampleSources(const OriginDevices& originDevices)
{
SamplingDevices result;
for (OriginDevices::const_iterator it = originDevices.begin(); it != originDevices.end(); ++it)
{
if (it->hardwareId == m_hardwareID)
{
result.append(SamplingDevice(
it->displayableName,
m_hardwareID,
m_deviceTypeID,
it->serial,
it->sequence,
PluginInterface::SamplingDevice::BuiltInDevice,
PluginInterface::SamplingDevice::StreamSingleRx,
1,
0
));
}
}
return result;
}
#ifdef SERVER_MODE
DeviceGUI* AaroniaRTSAInputPlugin::createSampleSourcePluginInstanceGUI(
const QString& sourceId,
QWidget **widget,
DeviceUISet *deviceUISet)
{
(void) sourceId;
(void) widget;
(void) deviceUISet;
return 0;
}
#else
DeviceGUI* AaroniaRTSAInputPlugin::createSampleSourcePluginInstanceGUI(
const QString& sourceId,
QWidget **widget,
DeviceUISet *deviceUISet)
{
if(sourceId == m_deviceTypeID) {
AaroniaRTSAInputGui* gui = new AaroniaRTSAInputGui(deviceUISet);
*widget = gui;
return gui;
} else {
return 0;
}
}
#endif
DeviceSampleSource *AaroniaRTSAInputPlugin::createSampleSourcePluginInstance(const QString& sourceId, DeviceAPI *deviceAPI)
{
if (sourceId == m_deviceTypeID)
{
AaroniaRTSAInput* input = new AaroniaRTSAInput(deviceAPI);
return input;
}
else
{
return 0;
}
}
DeviceWebAPIAdapter *AaroniaRTSAInputPlugin::createDeviceWebAPIAdapter() const
{
return new AaroniaRTSAInputWebAPIAdapter();
}

View File

@ -0,0 +1,52 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2023 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 _AARONIARTSA_AARONIARTSAPLUGIN_H
#define _AARONIARTSA_AARONIARTSAPLUGIN_H
#include <QObject>
#include "plugin/plugininterface.h"
class PluginAPI;
#define AARONIARTSA_DEVICE_TYPE_ID "sdrangel.samplesource.aaroniartsasource"
class AaroniaRTSAInputPlugin : public QObject, public PluginInterface {
Q_OBJECT
Q_INTERFACES(PluginInterface)
Q_PLUGIN_METADATA(IID AARONIARTSA_DEVICE_TYPE_ID)
public:
explicit AaroniaRTSAInputPlugin(QObject* parent = NULL);
const PluginDescriptor& getPluginDescriptor() const;
void initPlugin(PluginAPI* pluginAPI);
virtual void enumOriginDevices(QStringList& listedHwIds, OriginDevices& originDevices);
virtual SamplingDevices enumSampleSources(const OriginDevices& originDevices);
virtual DeviceGUI* createSampleSourcePluginInstanceGUI(
const QString& sourceId,
QWidget **widget,
DeviceUISet *deviceUISet);
virtual DeviceSampleSource* createSampleSourcePluginInstance(const QString& sourceId, DeviceAPI *deviceAPI);
virtual DeviceWebAPIAdapter* createDeviceWebAPIAdapter() const;
private:
static const PluginDescriptor m_pluginDescriptor;
};
#endif // _AARONIARTSA_AARONIARTSAPLUGIN_H

View File

@ -0,0 +1,142 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2023 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 "util/simpleserializer.h"
#include "aaroniartsainputsettings.h"
AaroniaRTSAInputSettings::AaroniaRTSAInputSettings()
{
resetToDefaults();
}
void AaroniaRTSAInputSettings::resetToDefaults()
{
m_centerFrequency = 1450000;
m_sampleRate = 200000;
m_serverAddress = "127.0.0.1:8073";
m_useReverseAPI = false;
m_reverseAPIAddress = "127.0.0.1";
m_reverseAPIPort = 8888;
m_reverseAPIDeviceIndex = 0;
}
QByteArray AaroniaRTSAInputSettings::serialize() const
{
SimpleSerializer s(2);
s.writeString(2, m_serverAddress);
s.writeS32(3, m_sampleRate);
s.writeBool(100, m_useReverseAPI);
s.writeString(101, m_reverseAPIAddress);
s.writeU32(102, m_reverseAPIPort);
s.writeU32(103, m_reverseAPIDeviceIndex);
return s.final();
}
bool AaroniaRTSAInputSettings::deserialize(const QByteArray& data)
{
SimpleDeserializer d(data);
if (!d.isValid())
{
resetToDefaults();
return false;
}
if (d.getVersion() == 2)
{
uint32_t utmp;
d.readString(2, &m_serverAddress, "127.0.0.1:8073");
d.readS32(3, &m_sampleRate, 200000);
d.readBool(100, &m_useReverseAPI, false);
d.readString(101, &m_reverseAPIAddress, "127.0.0.1");
d.readU32(102, &utmp, 0);
if ((utmp > 1023) && (utmp < 65535)) {
m_reverseAPIPort = utmp;
}
else {
m_reverseAPIPort = 8888;
}
d.readU32(103, &utmp, 0);
m_reverseAPIDeviceIndex = utmp > 99 ? 99 : utmp;
return true;
}
else
{
resetToDefaults();
return false;
}
}
void AaroniaRTSAInputSettings::applySettings(const QStringList& settingsKeys, const AaroniaRTSAInputSettings& settings)
{
if (settingsKeys.contains("centerFrequency")) {
m_centerFrequency = settings.m_centerFrequency;
}
if (settingsKeys.contains("sampleRate")) {
m_sampleRate = settings.m_sampleRate;
}
if (settingsKeys.contains("serverAddress")) {
m_serverAddress = settings.m_serverAddress;
}
if (settingsKeys.contains("useReverseAPI")) {
m_useReverseAPI = settings.m_useReverseAPI;
}
if (settingsKeys.contains("reverseAPIAddress")) {
m_reverseAPIAddress = settings.m_reverseAPIAddress;
}
if (settingsKeys.contains("reverseAPIPort")) {
m_reverseAPIPort = settings.m_reverseAPIPort;
}
if (settingsKeys.contains("reverseAPIDeviceIndex")) {
m_reverseAPIDeviceIndex = settings.m_reverseAPIDeviceIndex;
}
}
QString AaroniaRTSAInputSettings::getDebugString(const QStringList& settingsKeys, bool force) const
{
std::ostringstream ostr;
if (settingsKeys.contains("centerFrequency") || force) {
ostr << " m_centerFrequency: " << m_centerFrequency;
}
if (settingsKeys.contains("sampleRate") || force) {
ostr << " m_sampleRate: " << m_sampleRate;
}
if (settingsKeys.contains("serverAddress") || force) {
ostr << " m_serverAddress: " << m_serverAddress.toStdString();
}
if (settingsKeys.contains("useReverseAPI") || force) {
ostr << " m_useReverseAPI: " << m_useReverseAPI;
}
if (settingsKeys.contains("reverseAPIAddress") || force) {
ostr << " m_reverseAPIAddress: " << m_reverseAPIAddress.toStdString();
}
if (settingsKeys.contains("reverseAPIPort") || force) {
ostr << " m_reverseAPIPort: " << m_reverseAPIPort;
}
if (settingsKeys.contains("reverseAPIDeviceIndex") || force) {
ostr << " m_reverseAPIDeviceIndex: " << m_reverseAPIDeviceIndex;
}
return QString(ostr.str().c_str());
}

View File

@ -0,0 +1,52 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2023 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 _AARONIARTSA_AARONIARTSASETTINGS_H_
#define _AARONIARTSA_AARONIARTSASETTINGS_H_
#include <QString>
#include <QByteArray>
struct AaroniaRTSAInputSettings {
enum ConnectionStatus
{
ConnectionIdle, // 0 - gray
ConnectionUnstable, // 1 - yellow
ConnectionOK, // 2 - green
ConnectionError, // 3 - red
ConnectionDisconnected // 4 - magenta
};
quint64 m_centerFrequency;
int m_sampleRate;
QString m_serverAddress;
bool m_useReverseAPI;
QString m_reverseAPIAddress;
uint16_t m_reverseAPIPort;
uint16_t m_reverseAPIDeviceIndex;
AaroniaRTSAInputSettings();
void resetToDefaults();
QByteArray serialize() const;
bool deserialize(const QByteArray& data);
void applySettings(const QStringList& settingsKeys, const AaroniaRTSAInputSettings& settings);
QString getDebugString(const QStringList& settingsKeys, bool force=false) const;
};
#endif /* _AARONIARTSA_AARONIARTSASETTINGS_H_ */

View File

@ -0,0 +1,52 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2023 Edouard Griffiths, F4EXB //
// //
// Implementation of static web API adapters used for preset serialization and //
// deserialization //
// //
// 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 "SWGDeviceSettings.h"
#include "aaroniartsainput.h"
#include "aaroniartsainputwebapiadapter.h"
AaroniaRTSAInputWebAPIAdapter::AaroniaRTSAInputWebAPIAdapter()
{}
AaroniaRTSAInputWebAPIAdapter::~AaroniaRTSAInputWebAPIAdapter()
{}
int AaroniaRTSAInputWebAPIAdapter::webapiSettingsGet(
SWGSDRangel::SWGDeviceSettings& response,
QString& errorMessage)
{
(void) errorMessage;
response.setAaroniaRtsaSettings(new SWGSDRangel::SWGAaroniaRTSASettings());
response.getAaroniaRtsaSettings()->init();
AaroniaRTSAInput::webapiFormatDeviceSettings(response, m_settings);
return 200;
}
int AaroniaRTSAInputWebAPIAdapter::webapiSettingsPutPatch(
bool force,
const QStringList& deviceSettingsKeys,
SWGSDRangel::SWGDeviceSettings& response, // query + response
QString& errorMessage)
{
(void) force; // no action
(void) errorMessage;
AaroniaRTSAInput::webapiUpdateDeviceSettings(m_settings, deviceSettingsKeys, response);
return 200;
}

View File

@ -0,0 +1,44 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2023 Edouard Griffiths, F4EXB //
// //
// Implementation of static web API adapters used for preset serialization and //
// deserialization //
// //
// 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 "device/devicewebapiadapter.h"
#include "aaroniartsainputsettings.h"
class AaroniaRTSAInputWebAPIAdapter : public DeviceWebAPIAdapter
{
public:
AaroniaRTSAInputWebAPIAdapter();
virtual ~AaroniaRTSAInputWebAPIAdapter();
virtual QByteArray serialize() { return m_settings.serialize(); }
virtual bool deserialize(const QByteArray& data) { return m_settings.deserialize(data); }
virtual int webapiSettingsGet(
SWGSDRangel::SWGDeviceSettings& response,
QString& errorMessage);
virtual int webapiSettingsPutPatch(
bool force,
const QStringList& deviceSettingsKeys,
SWGSDRangel::SWGDeviceSettings& response, // query + response
QString& errorMessage);
private:
AaroniaRTSAInputSettings m_settings;
};

View File

@ -0,0 +1,422 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2023 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 <boost/endian/conversion.hpp>
#include <QJsonObject>
#include <QJsonArray>
#include <QJsonValue>
#include "util/messagequeue.h"
#include "dsp/dspcommands.h"
#include "aaroniartsainputsettings.h"
#include "aaroniartsainputworker.h"
MESSAGE_CLASS_DEFINITION(AaroniaRTSAInputWorker::MsgReportSampleRateAndFrequency, Message)
AaroniaRTSAInputWorker::AaroniaRTSAInputWorker(SampleSinkFifo* sampleFifo) :
QObject(),
m_timer(this),
m_samplesBuf(),
m_sampleFifo(sampleFifo),
m_centerFrequency(0),
m_sampleRate(1),
m_inputMessageQueue(nullptr),
m_status(AaroniaRTSAInputSettings::ConnectionIdle),
mReply(nullptr),
m_convertBuffer(64e6)
{
// Initialize network managers
m_networkAccessManager = new QNetworkAccessManager(this);
m_networkAccessManagerConfig = new QNetworkAccessManager(this);
QObject::connect(
m_networkAccessManagerConfig,
&QNetworkAccessManager::finished,
this,
&AaroniaRTSAInputWorker::handleConfigReply
);
// Request 16bit raw samples
// m_serverAddress = "localhost:55123";
// QUrl url(tr("http://%1/stream?format=float32").arg(m_serverAddress));
// QNetworkRequest req(url);
// mReply = m_networkAccessManager->get(req);
// // Connect Qt slots to network events
// connect(mReply, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(onError(QNetworkReply::NetworkError)));
// connect(mReply, SIGNAL(finished()), this, SLOT(onFinished()));
// connect(mReply, SIGNAL(readyRead()), this, SLOT(onReadyRead()));
mPrevTime = 0;
mPacketSamples = 0;
}
AaroniaRTSAInputWorker::~AaroniaRTSAInputWorker()
{
if (mReply)
{
// disconnect previous sugnals
disconnect(mReply, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(onError(QNetworkReply::NetworkError)));
disconnect(mReply, SIGNAL(finished()), this, SLOT(onFinished()));
disconnect(mReply, SIGNAL(readyRead()), this, SLOT(onReadyRead()));
mReply->abort();
mReply->deleteLater();
}
m_networkAccessManager->deleteLater();
QObject::disconnect(
m_networkAccessManagerConfig,
&QNetworkAccessManager::finished,
this,
&AaroniaRTSAInputWorker::handleConfigReply
);
m_networkAccessManagerConfig->deleteLater();
}
void AaroniaRTSAInputWorker::onSocketError(QAbstractSocket::SocketError error)
{
(void) error;
m_status = AaroniaRTSAInputSettings::ConnectionError;
emit updateStatus(m_status);
}
void AaroniaRTSAInputWorker::sendCenterFrequencyAndSampleRate()
{
if (m_iqDemodName.size() == 0) {
return;
}
qDebug("AaroniaRTSAInputWorker::sendCenterFrequencyAndSampleRate: %llu samplerate: %d", m_centerFrequency, m_sampleRate);
QJsonObject object {
{"receiverName", m_iqDemodName},
{"simpleconfig", QJsonObject({
{"main", QJsonObject({
{"centerfreq", QJsonValue((qint64) m_centerFrequency)},
{"samplerate", QJsonValue(m_sampleRate)},
{"spanfreq", QJsonValue(m_sampleRate)},
})}
})}
};
QJsonDocument document;
document.setObject(object);
QUrl url(tr("http://%1/remoteconfig").arg(m_serverAddress));
QNetworkRequest request(url);
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
m_networkAccessManagerConfig->put(request, document.toJson());
}
void AaroniaRTSAInputWorker::getConfig()
{
QUrl url(tr("http://%1/remoteconfig").arg(m_serverAddress));
QNetworkRequest request(url);
m_networkAccessManagerConfig->get(request);
}
void AaroniaRTSAInputWorker::onCenterFrequencyChanged(quint64 centerFrequency)
{
if (m_centerFrequency == centerFrequency) {
return;
}
m_centerFrequency = centerFrequency;
sendCenterFrequencyAndSampleRate();
}
void AaroniaRTSAInputWorker::onSampleRateChanged(int sampleRate)
{
if (m_sampleRate == sampleRate) {
return;
}
m_sampleRate = sampleRate;
sendCenterFrequencyAndSampleRate();
}
void AaroniaRTSAInputWorker::onServerAddressChanged(QString serverAddress)
{
m_status = AaroniaRTSAInputSettings::ConnectionDisconnected;
updateStatus(m_status);
if (mReply)
{
// disconnect previous sugnals
disconnect(mReply, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(onError(QNetworkReply::NetworkError)));
disconnect(mReply, SIGNAL(finished()), this, SLOT(onFinished()));
disconnect(mReply, SIGNAL(readyRead()), this, SLOT(onReadyRead()));
mReply->abort();
mReply->deleteLater();
}
QUrl url(tr("http://%1/stream?format=float32").arg(serverAddress));
QNetworkRequest req(url);
mReply = m_networkAccessManager->get(req);
// Connect Qt slots to network events
connect(mReply, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(onError(QNetworkReply::NetworkError)));
connect(mReply, SIGNAL(finished()), this, SLOT(onFinished()));
connect(mReply, SIGNAL(readyRead()), this, SLOT(onReadyRead()));
mPrevTime = 0;
mPacketSamples = 0;
m_serverAddress = serverAddress;
getConfig();
}
void AaroniaRTSAInputWorker::tick()
{
}
/**************************CPY ********************************* */
void AaroniaRTSAInputWorker::onError(QNetworkReply::NetworkError code)
{
(void) code;
qWarning() << "AaroniaRTSAInputWorker::onError: network Error: " << mReply->errorString();
m_status = 3;
emit updateStatus(3);
}
void AaroniaRTSAInputWorker::onFinished()
{
qDebug() << "AaroniaRTSAInputWorker::onFinished(: finished: " << mReply->errorString();
mBuffer.append(mReply->readAll());
mReply->deleteLater();
mReply = nullptr;
}
// bytes received from the socket
void AaroniaRTSAInputWorker::onReadyRead()
{
if (m_status != AaroniaRTSAInputSettings::ConnectionOK)
{
m_status = AaroniaRTSAInputSettings::ConnectionOK;
emit updateStatus(m_status);
}
// read as many bytes as possible into input buffer
qint64 n = mReply->bytesAvailable();
qint64 bs = mBuffer.size();
mBuffer.resize(bs + n);
qint64 done = mReply->read(mBuffer.data() + bs, n);
mBuffer.resize(bs + done);
// intialize parsing
int offset = 0;
int avail = mBuffer.size();
// consume all input data if possible
while (offset < avail)
{
// any samples so far (not looking for meta data)
if (mPacketSamples)
{
// enough samples
if (offset + mPacketSamples * 2 * sizeof(float) <= (unsigned long) avail)
{
// do something with the IQ data
const float *sp = (const float *)(mBuffer.constData() + offset);
SampleVector::iterator it = m_convertBuffer.begin();
m_decimatorsFloatIQ.decimate1(&it, sp, 2*mPacketSamples);
/*m_samplesBuf.clear();
for (int i = 0; i < mPacketSamples*2; i+=2)
{
m_samplesBuf.push_back(Sample(
sp[i] << (SDR_RX_SAMP_SZ - 8),
sp[i+1] << (SDR_RX_SAMP_SZ - 8)
));
}*/
//m_sampleFifo->write(m_samplesBuf.begin(), m_samplesBuf.end());
m_sampleFifo->write(m_convertBuffer.begin(), it);
//qDebug() << "IQ " << sp[0] << ", " << sp[1];
//m_sampleFifo->write()
// consume all samples from the input buffer
offset += mPacketSamples * 2 * sizeof(float);
mPacketSamples = 0;
}
else
{
break;
}
}
else
{
// is there a complete JSON metadata object in the buffer
int split = mBuffer.indexOf('\x1e', offset);
if (split != -1)
{
// Extract it
QByteArray data = mBuffer.mid(offset, split - offset);
offset = split + 1;
// Parse the JSON data
QJsonParseError error;
QJsonDocument jdoc = QJsonDocument::fromJson(data, &error);
if (error.error == QJsonParseError::NoError)
{
// Extract fields of interest
// double startTime = jdoc["startTime"].toDouble(), endTime = jdoc["endTime"].toDouble();
int samples = jdoc["samples"].toInt();
// Dump packet loss
// if (startTime != mPrevTime)
// {
// qDebug() << "AaroniaRTSAInputWorker::onReadyRead: packet loss: "
// << QDateTime::fromMSecsSinceEpoch(startTime * 1000).toString()
// << " D " << endTime - startTime
// << " O " << startTime - mPrevTime
// << " S " << samples
// << " L " << QDateTime::currentMSecsSinceEpoch() / 1000.0 - startTime;
// if (m_status != AaroniaRTSAInputSettings::ConnectionUnstable)
// {
// m_status = AaroniaRTSAInputSettings::ConnectionUnstable;
// emit updateStatus(m_status);
// }
// }
// Switch to data phase
// mPrevTime = endTime;
mPacketSamples = samples;
// qDebug() << jdoc.toJson();
quint64 endFreq = jdoc["endFrequency"].toDouble();
quint64 startFreq = jdoc["startFrequency"].toDouble();
int bw = endFreq - startFreq;
quint64 midFreq = (endFreq + startFreq) / 2;
if ((bw != m_sampleRate) || (midFreq != m_centerFrequency))
{
if (m_inputMessageQueue)
{
MsgReportSampleRateAndFrequency *msg = MsgReportSampleRateAndFrequency::create(bw, midFreq);
m_inputMessageQueue->push(msg);
}
}
m_sampleRate = bw;
m_centerFrequency = midFreq;
}
else
{
QTextStream qerr(stderr);
qerr << "Json Parse Error: " + error.errorString();
}
}
else
{
break;
}
}
}
// Remove consumed data from the buffer
mBuffer.remove(0, offset);
}
void AaroniaRTSAInputWorker::handleConfigReply(QNetworkReply* reply)
{
if (reply->operation() == QNetworkAccessManager::GetOperation) // return from GET to /remoteconfig
{
parseConfig(reply->readAll());
}
else if (reply->operation() == QNetworkAccessManager::PutOperation) // return from PUT to /remoteconfig
{
int httpStatusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
if ((httpStatusCode / 100) == 2) {
qDebug("AaroniaRTSAInputWorker::handleConfigReply: remoteconfig OK (%d)", httpStatusCode);
} else {
qWarning("AaroniaRTSAInputWorker::handleConfigReply: remoteconfig ended with error (%d)", httpStatusCode);
}
}
reply->deleteLater();
}
void AaroniaRTSAInputWorker::parseConfig(QByteArray bytes)
{
QJsonDocument document = QJsonDocument::fromJson(bytes);
m_iqDemodName = "";
if (document.isObject())
{
QJsonObject documentObject = document.object();
if (documentObject.contains(QStringLiteral("config")))
{
QJsonObject config = documentObject.value(QStringLiteral("config")).toObject();
if (config.contains(QStringLiteral("items")))
{
QJsonArray configItems = config.value(QStringLiteral("items")).toArray();
for (const auto& configIem : configItems)
{
QJsonObject configIemObject = configIem.toObject();
if (configIemObject.contains(QStringLiteral("name")))
{
QString nameItem = configIemObject.value(QStringLiteral("name")).toString();
if (nameItem.startsWith("Block_IQDemodulator"))
{
m_iqDemodName = nameItem;
break;
}
}
}
}
else
{
qDebug() << "AaroniaRTSAInputWorker::parseConfig: config has no items: " << config;
}
}
else
{
qDebug() << "AaroniaRTSAInputWorker::parseConfig: document has no config obhect: " << documentObject;
}
}
else
{
qDebug() << "AaroniaRTSAInputWorker::parseConfig: Document is not an object: " << document;
}
if (m_iqDemodName == "") {
qWarning("AaroniaRTSAInputWorker.parseConfig: could not find IQ demdulator");
} else {
qDebug("AaroniaRTSAInputWorker::parseConfig: IQ demdulator name: %s", qPrintable(m_iqDemodName));
}
}

View File

@ -0,0 +1,123 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2023 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 _AARONIARTSA_AARONIARTSAWORKER_H_
#define _AARONIARTSA_AARONIARTSAWORKER_H_
#include <QTimer>
#include "dsp/samplesinkfifo.h"
#include "util/message.h"
#include <QProcess>
#include <QNetworkAccessManager>
#include <QNetworkReply>
#include <QTimer>
#include <QJsonDocument>
#include <QObject>
#include "dsp/decimatorsfi.h"
class MessageQueue;
class AaroniaRTSAInputWorker : public QObject {
Q_OBJECT
public:
class MsgReportSampleRateAndFrequency : public Message {
MESSAGE_CLASS_DECLARATION
public:
int getSampleRate() const { return m_sampleRate; }
quint64 getCenterFrequency() const { return m_centerFrequency; }
static MsgReportSampleRateAndFrequency* create(int sampleRate, quint64 centerFrequency) {
return new MsgReportSampleRateAndFrequency(sampleRate, centerFrequency);
}
private:
int m_sampleRate;
quint64 m_centerFrequency;
MsgReportSampleRateAndFrequency(int sampleRate, qint64 centerFrequency) :
Message(),
m_sampleRate(sampleRate),
m_centerFrequency(centerFrequency)
{ }
};
AaroniaRTSAInputWorker(SampleSinkFifo* sampleFifo);
~AaroniaRTSAInputWorker();
int getStatus() const { return m_status; }
void setInputMessageQueue(MessageQueue *messageQueue) { m_inputMessageQueue = messageQueue; }
private:
QTimer m_timer;
SampleVector m_samplesBuf;
SampleSinkFifo* m_sampleFifo;
QString m_serverAddress;
quint64 m_centerFrequency;
int m_sampleRate;
MessageQueue *m_inputMessageQueue;
int m_status; //!< See GUI for status number detail
void sendCenterFrequencyAndSampleRate();
void getConfig();
void parseConfig(QByteArray bytes);
// QT htttp clients
QNetworkAccessManager *m_networkAccessManager;
QNetworkAccessManager *m_networkAccessManagerConfig;
// Reply from the HTTP server
QNetworkReply *mReply;
// Input buffer
QByteArray mBuffer;
// Number of IQ sample pairs in the current packet
int mPacketSamples;
// Previous sample end time to check for packet loss
double mPrevTime;
// Current iQ demodulator name
QString m_iqDemodName;
//Decimators<qint32, float, SDR_RX_SAMP_SZ, 32, true> m_decimatorsIQ;
DecimatorsFI<true> m_decimatorsFloatIQ;
SampleVector m_convertBuffer;
//void workIQ(unsigned int n_items);
signals:
void updateStatus(int status);
public slots:
void onCenterFrequencyChanged(quint64 centerFrequency);
void onSampleRateChanged(int sampleRate);
void onServerAddressChanged(QString serverAddress);
private slots:
void onSocketError(QAbstractSocket::SocketError error);
void onError(QNetworkReply::NetworkError code);
void onFinished(void);
void onReadyRead(void);
void handleConfigReply(QNetworkReply* reply);
void tick();
};
#endif // _AARONIARTSA_AARONIARTSAWORKER_H_

View File

@ -0,0 +1,66 @@
<h1>AaroniaRTSA input plugin</h1>
<h2>Introduction</h2>
You can use this plugin to interface with a http server block in the Aaronia RTSA suite connected to a Spectran V6 device. It is assumed that you have prior knowledge of the Aaronia RTSA suite software and operation of the Spectran V6 RTSA (Real Time Spectrum Analyzer). However in this context there are some specificities i.e. it assumes that the "mission" (in RTSA suite terms) that is the equivalent of a "configuration" in SDRangel has a `HTTP Server` block preceded by a `IQ Demodulator` block (the equivalent of the "Frequency translating FIR filter" in GNU radio). The center frequency and span (equal to decimated sample rate) can be controlled from either RTSA sutie or SDRangel.
An example flow graph could be the following (with two http servers) hence two possible Aaronia receivers in SDRangel:
![Aaronia RTSA dual server](../../../doc/img/AaroniaRTSAInput_mission.png)
On SDRangel side two instances of the plugin can listen to each one of the servers:
![Aaronia RTSA dual server](../../../doc/img/AaroniaRTSAInput_sdrangel.png)
Of course the `IQ Demodulator` span should fit in the bandwidth set in the Spectran V6 block else it will yield no output.
You can obviously run the RTSA suite and SDRangel on the same machine and connect via localhost but there are advantages on a split setup:
- The workload can be split between RTSA suite and SDRangel on two different machines. RTSA suite has to ingurgitate data from the Spectran and process it at a very high sample rate so this is demanding on CPU and latency. Often it is better to run it on its own dedicated machine.
- You can have the RTSA suite run on a machine close to the Spectran. This is in fact mandatory due to the length of the USB cables. And you can run SDRangel on another machine (possibly quite more lightweight) anywhere on the network. You can also multiply the client machines running SDRangel.
<h2>Interface</h2>
![Aaronia RTSA dual server](../../../doc/img/AaroniaRTSAInput.png)
The top and bottom bars of the device window are described [here](../../../sdrgui/device/readme.md)
<h3>1: Start/Stop</h3>
This button is used to start the "device" i.e connect to the remote and start stream or stop the "device" i.e. stop stream and disconnect from the remote. The button shows the following faces:
- Blue triangle icon: device is ready and can be started
- Green square icon: device is running and can be stopped
<h2>2: Stream sample rate</h2>
This is the stream sample rate in S/s with multiplier. It should be equal to what is displayed in (4).
<h3>3: Frequency</h3>
This is the center frequency received in he stream meta data. When setting it it will try to set the center frequency of the `IQ Demodulator` in RTSA suite the closest to the `HTTP server`.
<h3>4: Stream sample rate</h3>
This is sample rate (actually the frequency span) received in the stream meta data. When setting it it will try to set the sample rate and frequency span of the IQ Demodulator` in RTSA suite the closest to the `HTTP server`.
<h3>5: Remote address and port</h3>
This is the remote address and port of the `HTTP server` block in RTSA suite. The address has to be in the form of an IPv4 address.
Press button (7) to validate your change.
<h3>6: Status indicator</h3>
This ball can take the following colors depending on the status:
- <span style="color:gray">**Gray**</span>: Idle
- <span style="color:yellow">**Yellow**</span>: Unstable
- <span style="color:green">**Green**</span>: Connected
- <span style="color:red">**Red**</span>: Error
- <span style="color:magenta">**Magenta**</span>: Disconnected
<h3>7: Set address</h3>
When you change the address in (5) you have to push this button to validate the change.

View File

@ -399,8 +399,8 @@ void AirspyGui::on_transverter_clicked()
updateFrequencyLimits();
m_settings.m_centerFrequency = ui->centerFrequency->getValueNew()*1000;
m_settingsKeys.append("transverterMode");
m_settingsKeys.append("m_transverterDeltaFrequency");
m_settingsKeys.append("m_iqOrder");
m_settingsKeys.append("transverterDeltaFrequency");
m_settingsKeys.append("iqOrder");
m_settingsKeys.append("centerFrequency");
sendSettings();
}

View File

@ -55,7 +55,7 @@ private:
int m_fcPos;
bool m_iqOrder;
Decimators<qint32, qint16, SDR_RX_SAMP_SZ, 12, true> m_decimatorsIQ;
Decimators<qint32, qint16, SDR_RX_SAMP_SZ, 12, true> m_decimatorsIQ;
Decimators<qint32, qint16, SDR_RX_SAMP_SZ, 12, false> m_decimatorsQI;
void run();

View File

@ -2,6 +2,7 @@
<qresource prefix="/">
<file>webapi/doc/html2/index.html</file>
<file>webapi/doc/swagger/swagger.yaml</file>
<file>webapi/doc/swagger/include/AaroniaRTSA.yaml</file>
<file>webapi/doc/swagger/include/ADSBDemod.yaml</file>
<file>webapi/doc/swagger/include/AFC.yaml</file>
<file>webapi/doc/swagger/include/Airspy.yaml</file>

View File

@ -2097,6 +2097,46 @@ margin-bottom: 20px;
}
},
"description" : "ATVMod"
};
defs.AaroniaRTSAReport = {
"properties" : {
"status" : {
"type" : "integer",
"description" : "0 for Idle, 1 for Connecting, 2 for Connected, 3 for Error, 4 for Disconnected"
}
},
"description" : "AaroniaRTSA"
};
defs.AaroniaRTSASettings = {
"properties" : {
"centerFrequency" : {
"type" : "integer",
"format" : "int64",
"description" : "Sets the center frequency (Hz) of the distant IQ demodulator"
},
"sampleRate" : {
"type" : "integer",
"description" : "Sets the sample rate (S/s) and span (Hz) of the distant IQ demodulator"
},
"serverAddress" : {
"type" : "string",
"description" : "Distant AaroniaRTSA instance URL or IPv4 address with port"
},
"useReverseAPI" : {
"type" : "integer",
"description" : "Synchronize with reverse API (1 for yes, 0 for no)"
},
"reverseAPIAddress" : {
"type" : "string"
},
"reverseAPIPort" : {
"type" : "integer"
},
"reverseAPIDeviceIndex" : {
"type" : "integer"
}
},
"description" : "AaroniaRTSA"
};
defs.AirspyHFReport = {
"properties" : {
@ -3538,9 +3578,6 @@ margin-bottom: 20px;
"HeatMapReport" : {
"$ref" : "#/definitions/HeatMapReport"
},
"ILSDemodReport" : {
"$ref" : "#/definitions/ILSDemodReport"
},
"M17DemodReport" : {
"$ref" : "#/definitions/M17DemodReport"
},
@ -3705,9 +3742,6 @@ margin-bottom: 20px;
"HeatMapSettings" : {
"$ref" : "#/definitions/HeatMapSettings"
},
"ILSDemodSettings" : {
"$ref" : "#/definitions/ILSDemodSettings"
},
"InterferometerSettings" : {
"$ref" : "#/definitions/InterferometerSettings"
},
@ -5205,6 +5239,9 @@ margin-bottom: 20px;
},
"xtrxMIMOReport" : {
"$ref" : "#/definitions/XtrxMIMOReport"
},
"aaroniaSDRReport" : {
"$ref" : "#/definitions/AaroniaRTSAReport"
}
},
"description" : "Base device report. Only the device report corresponding to the device specified in the deviceHwType is or should be present."
@ -5393,6 +5430,9 @@ margin-bottom: 20px;
},
"xtrxMIMOSettings" : {
"$ref" : "#/definitions/XtrxMIMOSettings"
},
"aaroniaRTSASettings" : {
"$ref" : "#/definitions/AaroniaRTSASettings"
}
},
"description" : "Base device settings. Only the device settings corresponding to the device specified in the deviceHwType field is or should be present."
@ -7413,143 +7453,6 @@ margin-bottom: 20px;
}
},
"description" : "IEEE_802_15_4_Mod"
};
defs.ILSDemodReport = {
"properties" : {
"channelPowerDB" : {
"type" : "number",
"format" : "float",
"description" : "power received in channel (dB)"
},
"channelSampleRate" : {
"type" : "integer"
}
},
"description" : "ILSDemod"
};
defs.ILSDemodSettings = {
"properties" : {
"inputFrequencyOffset" : {
"type" : "integer",
"format" : "int64"
},
"rfBandwidth" : {
"type" : "number",
"format" : "float"
},
"mode" : {
"type" : "integer",
"description" : "(0 for LOC, 1 for G/S)"
},
"frequencyIndex" : {
"type" : "integer"
},
"squelch" : {
"type" : "integer"
},
"volume" : {
"type" : "number",
"format" : "float"
},
"audioMute" : {
"type" : "integer"
},
"average" : {
"type" : "integer"
},
"ddmUnits" : {
"type" : "integer"
},
"identThreshold" : {
"type" : "number",
"format" : "float"
},
"ident" : {
"type" : "string"
},
"runway" : {
"type" : "string"
},
"trueBearing" : {
"type" : "number",
"format" : "float"
},
"latitude" : {
"type" : "string"
},
"longitude" : {
"type" : "string"
},
"elevation" : {
"type" : "integer"
},
"glidePath" : {
"type" : "number",
"format" : "float"
},
"refHeight" : {
"type" : "number",
"format" : "float"
},
"courseWidth" : {
"type" : "number",
"format" : "float"
},
"udpEnabled" : {
"type" : "integer",
"description" : "Whether to forward DDM to specified UDP port"
},
"udpAddress" : {
"type" : "string",
"description" : "UDP address to forward DDM to"
},
"udpPort" : {
"type" : "integer",
"description" : "UDP port to forward DDM to"
},
"logFilename" : {
"type" : "string"
},
"logEnabled" : {
"type" : "integer"
},
"rgbColor" : {
"type" : "integer"
},
"title" : {
"type" : "string"
},
"streamIndex" : {
"type" : "integer",
"description" : "MIMO channel. Not relevant when connected to SI (single Rx)."
},
"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"
},
"scopeConfig" : {
"$ref" : "#/definitions/GLScope"
},
"channelMarker" : {
"$ref" : "#/definitions/ChannelMarker"
},
"rollupState" : {
"$ref" : "#/definitions/RollupState"
}
},
"description" : "ILSDemod"
};
defs.InstanceChannelsResponse = {
"required" : [ "channelcount" ],
@ -9209,7 +9112,7 @@ margin-bottom: 20px;
},
"altitudeReference" : {
"type" : "integer",
"description" : "0 - NONE (Absolute), 1 - CLAMP_TO_GROUND, 2 - RELATIVE_TO_GROUND, 3 - CLIP_TO_GROUND."
"description" : "0 - NONE (Absolute), 1 - CLAMP_TO_GROUND, 2 - RELATIVE_TO_GROUND, 3 - CLIP_TO_GROUND"
},
"animations" : {
"type" : "array",
@ -9258,14 +9161,6 @@ margin-bottom: 20px;
"availableUntil" : {
"type" : "string",
"description" : "Date and time until after which this item should no longer appear on 3D map"
},
"colorValid" : {
"type" : "integer",
"description" : "0 - Use default color, 1 - Use specified color"
},
"color" : {
"type" : "integer",
"description" : "RGBA for polygon and polyline"
}
},
"description" : "An item to draw on the map. Set image to an empty string to remove item from the map."
@ -9368,7 +9263,7 @@ margin-bottom: 20px;
},
"altitudeReference" : {
"type" : "integer",
"description" : "0 - NONE (Absolute), 1 - CLAMP_TO_GROUND, 2 - RELATIVE_TO_GROUND, 3 - CLIP_TO_GROUND."
"description" : "0 - NONE (Absolute), 1 - CLAMP_TO_GROUND, 2 - RELATIVE_TO_GROUND, 3 - CLIP_TO_GROUND"
},
"animations" : {
"type" : "array",
@ -9417,14 +9312,6 @@ margin-bottom: 20px;
"availableUntil" : {
"type" : "string",
"description" : "Date and time until after which this item should no longer appear on 3D map"
},
"colorValid" : {
"type" : "integer",
"description" : "0 - Use default color, 1 - Use specified color"
},
"color" : {
"type" : "integer",
"description" : "RGBA for polygon and polyline"
}
},
"description" : "An item to draw on the map. Set image to an empty string to remove item from the map."
@ -9444,10 +9331,6 @@ margin-bottom: 20px;
"type" : "integer",
"description" : "Display object names on the map (1 for yes, 0 for no)"
},
"terrain" : {
"type" : "string",
"description" : "Terrain used for 3D map (E.g: 'Ellipsoid' or 'Cesium World Terrain')"
},
"title" : {
"type" : "string"
},
@ -13615,54 +13498,6 @@ margin-bottom: 20px;
"audioDeviceName" : {
"type" : "string"
},
"gpioControl" : {
"type" : "integer",
"description" : "GPIO control\n * 0 - No GPIO control\n * 1 - Rx side controls GPIO\n * 2 - Tx side controls GPIO\n"
},
"rx2txGPIOEnable" : {
"type" : "integer",
"description" : "Enable Rx to Tx GPIO control\n * 0 - disable\n * 1 - enable\n"
},
"rx2txGPIOMask" : {
"type" : "integer",
"format" : "int8",
"description" : "Rx to Tx change GPIO mask"
},
"rx2txGPIOValues" : {
"type" : "integer",
"format" : "int8",
"description" : "Rx to Tx change GPIO values"
},
"rx2txCommandEnable" : {
"type" : "integer",
"description" : "Enable Rx to Tx command\n * 0 - disable\n * 1 - enable\n"
},
"rx2txCommand" : {
"type" : "string",
"description" : "Command to be executed when Rx switches to Tx"
},
"tx2rxGPIOEnable" : {
"type" : "integer",
"description" : "Enable Tx to Rx GPIO control\n * 0 - disable\n * 1 - enable\n"
},
"tx2rxGPIOMask" : {
"type" : "integer",
"format" : "int8",
"description" : "Tx to Rx change GPIO mask"
},
"tx2rxGPIOValues" : {
"type" : "integer",
"format" : "int8",
"description" : "Tx to Rx change GPIO values"
},
"tx2rxCommandEnable" : {
"type" : "integer",
"description" : "Enable Tx to Rx command\n * 0 - disable\n * 1 - enable\n"
},
"tx2rxCommand" : {
"type" : "string",
"description" : "Command to be executed when Tx switches to Rx"
},
"useReverseAPI" : {
"type" : "integer",
"description" : "Synchronize with reverse API (1 for yes, 0 for no)"
@ -57471,7 +57306,7 @@ except ApiException as e:
</div>
<div id="generator">
<div class="content">
Generated 2023-04-01T18:43:55.658+02:00
Generated 2023-03-23T18:22:37.731+01:00
</div>
</div>
</div>

View File

@ -0,0 +1,29 @@
AaroniaRTSASettings:
description: AaroniaRTSA
properties:
centerFrequency:
description: Sets the center frequency (Hz) of the distant IQ demodulator
type: integer
format: int64
sampleRate:
description: Sets the sample rate (S/s) and span (Hz) of the distant IQ demodulator
type: integer
serverAddress:
description: Distant AaroniaRTSA instance URL or IPv4 address with port
type: string
useReverseAPI:
description: Synchronize with reverse API (1 for yes, 0 for no)
type: integer
reverseAPIAddress:
type: string
reverseAPIPort:
type: integer
reverseAPIDeviceIndex:
type: integer
AaroniaRTSAReport:
description: AaroniaRTSA
properties:
status:
description: 0 for Idle, 1 for Connecting, 2 for Connected, 3 for Error, 4 for Disconnected
type: integer

View File

@ -71,3 +71,5 @@ DeviceReport:
$ref: "/doc/swagger/include/Xtrx.yaml#/XtrxOutputReport"
xtrxMIMOReport:
$ref: "/doc/swagger/include/Xtrx.yaml#/XtrxMIMOReport"
aaroniaSDRReport:
$ref: "/doc/swagger/include/AaroniaRTSA.yaml#/AaroniaRTSAReport"

View File

@ -100,3 +100,5 @@ DeviceSettings:
$ref: "/doc/swagger/include/Xtrx.yaml#/XtrxOutputSettings"
xtrxMIMOSettings:
$ref: "/doc/swagger/include/Xtrx.yaml#/XtrxMIMOSettings"
aaroniaRTSASettings:
$ref: "/doc/swagger/include/AaroniaRTSA.yaml#/AaroniaRTSASettings"

View File

@ -108,6 +108,7 @@ void ValueDial::setColorMapper(ColorMapper colorMapper)
void ValueDial::setValue(quint64 value)
{
m_valueNew = value;
m_textNew = formatText(m_valueNew);
if (m_valueNew < m_valueMin) {
m_valueNew = m_valueMin;
@ -115,16 +116,21 @@ void ValueDial::setValue(quint64 value)
m_valueNew = m_valueMax;
}
if (m_valueNew < m_value) {
if (m_valueNew < m_value)
{
m_animationState = 1;
} else if (m_valueNew > m_value) {
}
else if (m_valueNew > m_value)
{
m_animationState = -1;
} else {
}
else
{
m_text = m_textNew;
return;
}
m_animationTimer.start(20);
m_textNew = formatText(m_valueNew);
}
void ValueDial::setValueRange(uint numDigits, quint64 min, quint64 max)

View File

@ -18,7 +18,7 @@ EOF
branch_name="sdrangel"
clone_label=$(date)
image_tag="latest"
uid=$(id -u)
uid=1000
docker_file="."
while getopts "h?b:c:t:j:f:" opt; do

View File

@ -2,6 +2,7 @@ version: '3'
services:
swgcodegen:
image: "sdrangel/swagger/codegen:${IMAGE_CODEGEN_VERSION}"
user: "1000:1000"
container_name: "sdrangel_swgcodegen"
volumes:
- "${SDRANGEL_BASE}:/opt/build/sdrangel:rw"
@ -12,6 +13,7 @@ services:
tty: true
swgserver:
image: "sdrangel/swagger/server:${IMAGE_SERVER_VERSION}"
user: "1000:1000"
container_name: "sdrangel_swgserver"
volumes:
- "${SDRANGEL_BASE}:/opt/build/sdrangel:rw"

View File

@ -51,4 +51,4 @@ export IMAGE_CODEGEN_VERSION=${image_tag_codegen}
export IMAGE_SERVER_VERSION=${image_tag_server}
export SDRANGEL_BASE=${sdrangel_codebase}
docker-compose -f compose.yml ${stack_name} ${action}
docker compose -f compose.yml ${stack_name} ${action}

View File

@ -15,7 +15,7 @@ EOF
image_name="sdrangel/swagger/server"
image_tag="latest"
uid=$(id -u)
uid=1000
docker_file="."
while getopts "h?t:f:" opt; do

View File

@ -0,0 +1,29 @@
AaroniaRTSASettings:
description: AaroniaRTSA
properties:
centerFrequency:
description: Sets the center frequency (Hz) of the distant IQ demodulator
type: integer
format: int64
sampleRate:
description: Sets the sample rate (S/s) and span (Hz) of the distant IQ demodulator
type: integer
serverAddress:
description: Distant AaroniaRTSA instance URL or IPv4 address with port
type: string
useReverseAPI:
description: Synchronize with reverse API (1 for yes, 0 for no)
type: integer
reverseAPIAddress:
type: string
reverseAPIPort:
type: integer
reverseAPIDeviceIndex:
type: integer
AaroniaRTSAReport:
description: AaroniaRTSA
properties:
status:
description: 0 for Idle, 1 for Connecting, 2 for Connected, 3 for Error, 4 for Disconnected
type: integer

View File

@ -71,3 +71,5 @@ DeviceReport:
$ref: "http://swgserver:8081/api/swagger/include/Xtrx.yaml#/XtrxOutputReport"
xtrxMIMOReport:
$ref: "http://swgserver:8081/api/swagger/include/Xtrx.yaml#/XtrxMIMOReport"
aaroniaSDRReport:
$ref: "http://swgserver:8081/api/swagger/include/AaroniaRTSA.yaml#/AaroniaRTSAReport"

View File

@ -100,3 +100,5 @@ DeviceSettings:
$ref: "http://swgserver:8081/api/swagger/include/Xtrx.yaml#/XtrxOutputSettings"
xtrxMIMOSettings:
$ref: "http://swgserver:8081/api/swagger/include/Xtrx.yaml#/XtrxMIMOSettings"
aaroniaRTSASettings:
$ref: "http://swgserver:8081/api/swagger/include/AaroniaRTSA.yaml#/AaroniaRTSASettings"

View File

@ -2097,6 +2097,46 @@ margin-bottom: 20px;
}
},
"description" : "ATVMod"
};
defs.AaroniaRTSAReport = {
"properties" : {
"status" : {
"type" : "integer",
"description" : "0 for Idle, 1 for Connecting, 2 for Connected, 3 for Error, 4 for Disconnected"
}
},
"description" : "AaroniaRTSA"
};
defs.AaroniaRTSASettings = {
"properties" : {
"centerFrequency" : {
"type" : "integer",
"format" : "int64",
"description" : "Sets the center frequency (Hz) of the distant IQ demodulator"
},
"sampleRate" : {
"type" : "integer",
"description" : "Sets the sample rate (S/s) and span (Hz) of the distant IQ demodulator"
},
"serverAddress" : {
"type" : "string",
"description" : "Distant AaroniaRTSA instance URL or IPv4 address with port"
},
"useReverseAPI" : {
"type" : "integer",
"description" : "Synchronize with reverse API (1 for yes, 0 for no)"
},
"reverseAPIAddress" : {
"type" : "string"
},
"reverseAPIPort" : {
"type" : "integer"
},
"reverseAPIDeviceIndex" : {
"type" : "integer"
}
},
"description" : "AaroniaRTSA"
};
defs.AirspyHFReport = {
"properties" : {
@ -3538,9 +3578,6 @@ margin-bottom: 20px;
"HeatMapReport" : {
"$ref" : "#/definitions/HeatMapReport"
},
"ILSDemodReport" : {
"$ref" : "#/definitions/ILSDemodReport"
},
"M17DemodReport" : {
"$ref" : "#/definitions/M17DemodReport"
},
@ -3705,9 +3742,6 @@ margin-bottom: 20px;
"HeatMapSettings" : {
"$ref" : "#/definitions/HeatMapSettings"
},
"ILSDemodSettings" : {
"$ref" : "#/definitions/ILSDemodSettings"
},
"InterferometerSettings" : {
"$ref" : "#/definitions/InterferometerSettings"
},
@ -5205,6 +5239,9 @@ margin-bottom: 20px;
},
"xtrxMIMOReport" : {
"$ref" : "#/definitions/XtrxMIMOReport"
},
"aaroniaSDRReport" : {
"$ref" : "#/definitions/AaroniaRTSAReport"
}
},
"description" : "Base device report. Only the device report corresponding to the device specified in the deviceHwType is or should be present."
@ -5393,6 +5430,9 @@ margin-bottom: 20px;
},
"xtrxMIMOSettings" : {
"$ref" : "#/definitions/XtrxMIMOSettings"
},
"aaroniaRTSASettings" : {
"$ref" : "#/definitions/AaroniaRTSASettings"
}
},
"description" : "Base device settings. Only the device settings corresponding to the device specified in the deviceHwType field is or should be present."
@ -7413,143 +7453,6 @@ margin-bottom: 20px;
}
},
"description" : "IEEE_802_15_4_Mod"
};
defs.ILSDemodReport = {
"properties" : {
"channelPowerDB" : {
"type" : "number",
"format" : "float",
"description" : "power received in channel (dB)"
},
"channelSampleRate" : {
"type" : "integer"
}
},
"description" : "ILSDemod"
};
defs.ILSDemodSettings = {
"properties" : {
"inputFrequencyOffset" : {
"type" : "integer",
"format" : "int64"
},
"rfBandwidth" : {
"type" : "number",
"format" : "float"
},
"mode" : {
"type" : "integer",
"description" : "(0 for LOC, 1 for G/S)"
},
"frequencyIndex" : {
"type" : "integer"
},
"squelch" : {
"type" : "integer"
},
"volume" : {
"type" : "number",
"format" : "float"
},
"audioMute" : {
"type" : "integer"
},
"average" : {
"type" : "integer"
},
"ddmUnits" : {
"type" : "integer"
},
"identThreshold" : {
"type" : "number",
"format" : "float"
},
"ident" : {
"type" : "string"
},
"runway" : {
"type" : "string"
},
"trueBearing" : {
"type" : "number",
"format" : "float"
},
"latitude" : {
"type" : "string"
},
"longitude" : {
"type" : "string"
},
"elevation" : {
"type" : "integer"
},
"glidePath" : {
"type" : "number",
"format" : "float"
},
"refHeight" : {
"type" : "number",
"format" : "float"
},
"courseWidth" : {
"type" : "number",
"format" : "float"
},
"udpEnabled" : {
"type" : "integer",
"description" : "Whether to forward DDM to specified UDP port"
},
"udpAddress" : {
"type" : "string",
"description" : "UDP address to forward DDM to"
},
"udpPort" : {
"type" : "integer",
"description" : "UDP port to forward DDM to"
},
"logFilename" : {
"type" : "string"
},
"logEnabled" : {
"type" : "integer"
},
"rgbColor" : {
"type" : "integer"
},
"title" : {
"type" : "string"
},
"streamIndex" : {
"type" : "integer",
"description" : "MIMO channel. Not relevant when connected to SI (single Rx)."
},
"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"
},
"scopeConfig" : {
"$ref" : "#/definitions/GLScope"
},
"channelMarker" : {
"$ref" : "#/definitions/ChannelMarker"
},
"rollupState" : {
"$ref" : "#/definitions/RollupState"
}
},
"description" : "ILSDemod"
};
defs.InstanceChannelsResponse = {
"required" : [ "channelcount" ],
@ -9209,7 +9112,7 @@ margin-bottom: 20px;
},
"altitudeReference" : {
"type" : "integer",
"description" : "0 - NONE (Absolute), 1 - CLAMP_TO_GROUND, 2 - RELATIVE_TO_GROUND, 3 - CLIP_TO_GROUND."
"description" : "0 - NONE (Absolute), 1 - CLAMP_TO_GROUND, 2 - RELATIVE_TO_GROUND, 3 - CLIP_TO_GROUND"
},
"animations" : {
"type" : "array",
@ -9258,14 +9161,6 @@ margin-bottom: 20px;
"availableUntil" : {
"type" : "string",
"description" : "Date and time until after which this item should no longer appear on 3D map"
},
"colorValid" : {
"type" : "integer",
"description" : "0 - Use default color, 1 - Use specified color"
},
"color" : {
"type" : "integer",
"description" : "RGBA for polygon and polyline"
}
},
"description" : "An item to draw on the map. Set image to an empty string to remove item from the map."
@ -9368,7 +9263,7 @@ margin-bottom: 20px;
},
"altitudeReference" : {
"type" : "integer",
"description" : "0 - NONE (Absolute), 1 - CLAMP_TO_GROUND, 2 - RELATIVE_TO_GROUND, 3 - CLIP_TO_GROUND."
"description" : "0 - NONE (Absolute), 1 - CLAMP_TO_GROUND, 2 - RELATIVE_TO_GROUND, 3 - CLIP_TO_GROUND"
},
"animations" : {
"type" : "array",
@ -9417,14 +9312,6 @@ margin-bottom: 20px;
"availableUntil" : {
"type" : "string",
"description" : "Date and time until after which this item should no longer appear on 3D map"
},
"colorValid" : {
"type" : "integer",
"description" : "0 - Use default color, 1 - Use specified color"
},
"color" : {
"type" : "integer",
"description" : "RGBA for polygon and polyline"
}
},
"description" : "An item to draw on the map. Set image to an empty string to remove item from the map."
@ -9444,10 +9331,6 @@ margin-bottom: 20px;
"type" : "integer",
"description" : "Display object names on the map (1 for yes, 0 for no)"
},
"terrain" : {
"type" : "string",
"description" : "Terrain used for 3D map (E.g: 'Ellipsoid' or 'Cesium World Terrain')"
},
"title" : {
"type" : "string"
},
@ -13615,54 +13498,6 @@ margin-bottom: 20px;
"audioDeviceName" : {
"type" : "string"
},
"gpioControl" : {
"type" : "integer",
"description" : "GPIO control\n * 0 - No GPIO control\n * 1 - Rx side controls GPIO\n * 2 - Tx side controls GPIO\n"
},
"rx2txGPIOEnable" : {
"type" : "integer",
"description" : "Enable Rx to Tx GPIO control\n * 0 - disable\n * 1 - enable\n"
},
"rx2txGPIOMask" : {
"type" : "integer",
"format" : "int8",
"description" : "Rx to Tx change GPIO mask"
},
"rx2txGPIOValues" : {
"type" : "integer",
"format" : "int8",
"description" : "Rx to Tx change GPIO values"
},
"rx2txCommandEnable" : {
"type" : "integer",
"description" : "Enable Rx to Tx command\n * 0 - disable\n * 1 - enable\n"
},
"rx2txCommand" : {
"type" : "string",
"description" : "Command to be executed when Rx switches to Tx"
},
"tx2rxGPIOEnable" : {
"type" : "integer",
"description" : "Enable Tx to Rx GPIO control\n * 0 - disable\n * 1 - enable\n"
},
"tx2rxGPIOMask" : {
"type" : "integer",
"format" : "int8",
"description" : "Tx to Rx change GPIO mask"
},
"tx2rxGPIOValues" : {
"type" : "integer",
"format" : "int8",
"description" : "Tx to Rx change GPIO values"
},
"tx2rxCommandEnable" : {
"type" : "integer",
"description" : "Enable Tx to Rx command\n * 0 - disable\n * 1 - enable\n"
},
"tx2rxCommand" : {
"type" : "string",
"description" : "Command to be executed when Tx switches to Rx"
},
"useReverseAPI" : {
"type" : "integer",
"description" : "Synchronize with reverse API (1 for yes, 0 for no)"
@ -57471,7 +57306,7 @@ except ApiException as e:
</div>
<div id="generator">
<div class="content">
Generated 2023-04-01T18:43:55.658+02:00
Generated 2023-03-23T18:22:37.731+01:00
</div>
</div>
</div>

View File

@ -0,0 +1,108 @@
/**
* SDRangel
* This is the web REST/JSON API of SDRangel SDR software. SDRangel is an Open Source Qt5/OpenGL 3.0+ (4.3+ in Windows) GUI and server Software Defined Radio and signal analyzer in software. It supports Airspy, BladeRF, HackRF, LimeSDR, PlutoSDR, RTL-SDR, SDRplay RSP1 and FunCube --- Limitations and specifcities: * In SDRangel GUI the first Rx device set cannot be deleted. Conversely the server starts with no device sets and its number of device sets can be reduced to zero by as many calls as necessary to /sdrangel/deviceset with DELETE method. * Preset import and export from/to file is a server only feature. * Device set focus is a GUI only feature. * The following channels are not implemented (status 501 is returned): ATV and DATV demodulators, Channel Analyzer NG, LoRa demodulator * The device settings and report structures contains only the sub-structure corresponding to the device type. The DeviceSettings and DeviceReport structures documented here shows all of them but only one will be or should be present at a time * The channel settings and report structures contains only the sub-structure corresponding to the channel type. The ChannelSettings and ChannelReport structures documented here shows all of them but only one will be or should be present at a time ---
*
* OpenAPI spec version: 7.0.0
* Contact: f4exb06@gmail.com
*
* NOTE: This class is auto generated by the swagger code generator program.
* https://github.com/swagger-api/swagger-codegen.git
* Do not edit the class manually.
*/
#include "SWGAaroniaRTSAReport.h"
#include "SWGHelpers.h"
#include <QJsonDocument>
#include <QJsonArray>
#include <QObject>
#include <QDebug>
namespace SWGSDRangel {
SWGAaroniaRTSAReport::SWGAaroniaRTSAReport(QString* json) {
init();
this->fromJson(*json);
}
SWGAaroniaRTSAReport::SWGAaroniaRTSAReport() {
status = 0;
m_status_isSet = false;
}
SWGAaroniaRTSAReport::~SWGAaroniaRTSAReport() {
this->cleanup();
}
void
SWGAaroniaRTSAReport::init() {
status = 0;
m_status_isSet = false;
}
void
SWGAaroniaRTSAReport::cleanup() {
}
SWGAaroniaRTSAReport*
SWGAaroniaRTSAReport::fromJson(QString &json) {
QByteArray array (json.toStdString().c_str());
QJsonDocument doc = QJsonDocument::fromJson(array);
QJsonObject jsonObject = doc.object();
this->fromJsonObject(jsonObject);
return this;
}
void
SWGAaroniaRTSAReport::fromJsonObject(QJsonObject &pJson) {
::SWGSDRangel::setValue(&status, pJson["status"], "qint32", "");
}
QString
SWGAaroniaRTSAReport::asJson ()
{
QJsonObject* obj = this->asJsonObject();
QJsonDocument doc(*obj);
QByteArray bytes = doc.toJson();
delete obj;
return QString(bytes);
}
QJsonObject*
SWGAaroniaRTSAReport::asJsonObject() {
QJsonObject* obj = new QJsonObject();
if(m_status_isSet){
obj->insert("status", QJsonValue(status));
}
return obj;
}
qint32
SWGAaroniaRTSAReport::getStatus() {
return status;
}
void
SWGAaroniaRTSAReport::setStatus(qint32 status) {
this->status = status;
this->m_status_isSet = true;
}
bool
SWGAaroniaRTSAReport::isSet(){
bool isObjectUpdated = false;
do{
if(m_status_isSet){
isObjectUpdated = true; break;
}
}while(false);
return isObjectUpdated;
}
}

View File

@ -0,0 +1,58 @@
/**
* SDRangel
* This is the web REST/JSON API of SDRangel SDR software. SDRangel is an Open Source Qt5/OpenGL 3.0+ (4.3+ in Windows) GUI and server Software Defined Radio and signal analyzer in software. It supports Airspy, BladeRF, HackRF, LimeSDR, PlutoSDR, RTL-SDR, SDRplay RSP1 and FunCube --- Limitations and specifcities: * In SDRangel GUI the first Rx device set cannot be deleted. Conversely the server starts with no device sets and its number of device sets can be reduced to zero by as many calls as necessary to /sdrangel/deviceset with DELETE method. * Preset import and export from/to file is a server only feature. * Device set focus is a GUI only feature. * The following channels are not implemented (status 501 is returned): ATV and DATV demodulators, Channel Analyzer NG, LoRa demodulator * The device settings and report structures contains only the sub-structure corresponding to the device type. The DeviceSettings and DeviceReport structures documented here shows all of them but only one will be or should be present at a time * The channel settings and report structures contains only the sub-structure corresponding to the channel type. The ChannelSettings and ChannelReport structures documented here shows all of them but only one will be or should be present at a time ---
*
* OpenAPI spec version: 7.0.0
* Contact: f4exb06@gmail.com
*
* NOTE: This class is auto generated by the swagger code generator program.
* https://github.com/swagger-api/swagger-codegen.git
* Do not edit the class manually.
*/
/*
* SWGAaroniaRTSAReport.h
*
* AaroniaRTSA
*/
#ifndef SWGAaroniaRTSAReport_H_
#define SWGAaroniaRTSAReport_H_
#include <QJsonObject>
#include "SWGObject.h"
#include "export.h"
namespace SWGSDRangel {
class SWG_API SWGAaroniaRTSAReport: public SWGObject {
public:
SWGAaroniaRTSAReport();
SWGAaroniaRTSAReport(QString* json);
virtual ~SWGAaroniaRTSAReport();
void init();
void cleanup();
virtual QString asJson () override;
virtual QJsonObject* asJsonObject() override;
virtual void fromJsonObject(QJsonObject &json) override;
virtual SWGAaroniaRTSAReport* fromJson(QString &jsonString) override;
qint32 getStatus();
void setStatus(qint32 status);
virtual bool isSet() override;
private:
qint32 status;
bool m_status_isSet;
};
}
#endif /* SWGAaroniaRTSAReport_H_ */

View File

@ -0,0 +1,250 @@
/**
* SDRangel
* This is the web REST/JSON API of SDRangel SDR software. SDRangel is an Open Source Qt5/OpenGL 3.0+ (4.3+ in Windows) GUI and server Software Defined Radio and signal analyzer in software. It supports Airspy, BladeRF, HackRF, LimeSDR, PlutoSDR, RTL-SDR, SDRplay RSP1 and FunCube --- Limitations and specifcities: * In SDRangel GUI the first Rx device set cannot be deleted. Conversely the server starts with no device sets and its number of device sets can be reduced to zero by as many calls as necessary to /sdrangel/deviceset with DELETE method. * Preset import and export from/to file is a server only feature. * Device set focus is a GUI only feature. * The following channels are not implemented (status 501 is returned): ATV and DATV demodulators, Channel Analyzer NG, LoRa demodulator * The device settings and report structures contains only the sub-structure corresponding to the device type. The DeviceSettings and DeviceReport structures documented here shows all of them but only one will be or should be present at a time * The channel settings and report structures contains only the sub-structure corresponding to the channel type. The ChannelSettings and ChannelReport structures documented here shows all of them but only one will be or should be present at a time ---
*
* OpenAPI spec version: 7.0.0
* Contact: f4exb06@gmail.com
*
* NOTE: This class is auto generated by the swagger code generator program.
* https://github.com/swagger-api/swagger-codegen.git
* Do not edit the class manually.
*/
#include "SWGAaroniaRTSASettings.h"
#include "SWGHelpers.h"
#include <QJsonDocument>
#include <QJsonArray>
#include <QObject>
#include <QDebug>
namespace SWGSDRangel {
SWGAaroniaRTSASettings::SWGAaroniaRTSASettings(QString* json) {
init();
this->fromJson(*json);
}
SWGAaroniaRTSASettings::SWGAaroniaRTSASettings() {
center_frequency = 0L;
m_center_frequency_isSet = false;
sample_rate = 0;
m_sample_rate_isSet = false;
server_address = nullptr;
m_server_address_isSet = false;
use_reverse_api = 0;
m_use_reverse_api_isSet = false;
reverse_api_address = nullptr;
m_reverse_api_address_isSet = false;
reverse_api_port = 0;
m_reverse_api_port_isSet = false;
reverse_api_device_index = 0;
m_reverse_api_device_index_isSet = false;
}
SWGAaroniaRTSASettings::~SWGAaroniaRTSASettings() {
this->cleanup();
}
void
SWGAaroniaRTSASettings::init() {
center_frequency = 0L;
m_center_frequency_isSet = false;
sample_rate = 0;
m_sample_rate_isSet = false;
server_address = new QString("");
m_server_address_isSet = false;
use_reverse_api = 0;
m_use_reverse_api_isSet = false;
reverse_api_address = new QString("");
m_reverse_api_address_isSet = false;
reverse_api_port = 0;
m_reverse_api_port_isSet = false;
reverse_api_device_index = 0;
m_reverse_api_device_index_isSet = false;
}
void
SWGAaroniaRTSASettings::cleanup() {
if(server_address != nullptr) {
delete server_address;
}
if(reverse_api_address != nullptr) {
delete reverse_api_address;
}
}
SWGAaroniaRTSASettings*
SWGAaroniaRTSASettings::fromJson(QString &json) {
QByteArray array (json.toStdString().c_str());
QJsonDocument doc = QJsonDocument::fromJson(array);
QJsonObject jsonObject = doc.object();
this->fromJsonObject(jsonObject);
return this;
}
void
SWGAaroniaRTSASettings::fromJsonObject(QJsonObject &pJson) {
::SWGSDRangel::setValue(&center_frequency, pJson["centerFrequency"], "qint64", "");
::SWGSDRangel::setValue(&sample_rate, pJson["sampleRate"], "qint32", "");
::SWGSDRangel::setValue(&server_address, pJson["serverAddress"], "QString", "QString");
::SWGSDRangel::setValue(&use_reverse_api, pJson["useReverseAPI"], "qint32", "");
::SWGSDRangel::setValue(&reverse_api_address, pJson["reverseAPIAddress"], "QString", "QString");
::SWGSDRangel::setValue(&reverse_api_port, pJson["reverseAPIPort"], "qint32", "");
::SWGSDRangel::setValue(&reverse_api_device_index, pJson["reverseAPIDeviceIndex"], "qint32", "");
}
QString
SWGAaroniaRTSASettings::asJson ()
{
QJsonObject* obj = this->asJsonObject();
QJsonDocument doc(*obj);
QByteArray bytes = doc.toJson();
delete obj;
return QString(bytes);
}
QJsonObject*
SWGAaroniaRTSASettings::asJsonObject() {
QJsonObject* obj = new QJsonObject();
if(m_center_frequency_isSet){
obj->insert("centerFrequency", QJsonValue(center_frequency));
}
if(m_sample_rate_isSet){
obj->insert("sampleRate", QJsonValue(sample_rate));
}
if(server_address != nullptr && *server_address != QString("")){
toJsonValue(QString("serverAddress"), server_address, obj, QString("QString"));
}
if(m_use_reverse_api_isSet){
obj->insert("useReverseAPI", QJsonValue(use_reverse_api));
}
if(reverse_api_address != nullptr && *reverse_api_address != QString("")){
toJsonValue(QString("reverseAPIAddress"), reverse_api_address, obj, QString("QString"));
}
if(m_reverse_api_port_isSet){
obj->insert("reverseAPIPort", QJsonValue(reverse_api_port));
}
if(m_reverse_api_device_index_isSet){
obj->insert("reverseAPIDeviceIndex", QJsonValue(reverse_api_device_index));
}
return obj;
}
qint64
SWGAaroniaRTSASettings::getCenterFrequency() {
return center_frequency;
}
void
SWGAaroniaRTSASettings::setCenterFrequency(qint64 center_frequency) {
this->center_frequency = center_frequency;
this->m_center_frequency_isSet = true;
}
qint32
SWGAaroniaRTSASettings::getSampleRate() {
return sample_rate;
}
void
SWGAaroniaRTSASettings::setSampleRate(qint32 sample_rate) {
this->sample_rate = sample_rate;
this->m_sample_rate_isSet = true;
}
QString*
SWGAaroniaRTSASettings::getServerAddress() {
return server_address;
}
void
SWGAaroniaRTSASettings::setServerAddress(QString* server_address) {
this->server_address = server_address;
this->m_server_address_isSet = true;
}
qint32
SWGAaroniaRTSASettings::getUseReverseApi() {
return use_reverse_api;
}
void
SWGAaroniaRTSASettings::setUseReverseApi(qint32 use_reverse_api) {
this->use_reverse_api = use_reverse_api;
this->m_use_reverse_api_isSet = true;
}
QString*
SWGAaroniaRTSASettings::getReverseApiAddress() {
return reverse_api_address;
}
void
SWGAaroniaRTSASettings::setReverseApiAddress(QString* reverse_api_address) {
this->reverse_api_address = reverse_api_address;
this->m_reverse_api_address_isSet = true;
}
qint32
SWGAaroniaRTSASettings::getReverseApiPort() {
return reverse_api_port;
}
void
SWGAaroniaRTSASettings::setReverseApiPort(qint32 reverse_api_port) {
this->reverse_api_port = reverse_api_port;
this->m_reverse_api_port_isSet = true;
}
qint32
SWGAaroniaRTSASettings::getReverseApiDeviceIndex() {
return reverse_api_device_index;
}
void
SWGAaroniaRTSASettings::setReverseApiDeviceIndex(qint32 reverse_api_device_index) {
this->reverse_api_device_index = reverse_api_device_index;
this->m_reverse_api_device_index_isSet = true;
}
bool
SWGAaroniaRTSASettings::isSet(){
bool isObjectUpdated = false;
do{
if(m_center_frequency_isSet){
isObjectUpdated = true; break;
}
if(m_sample_rate_isSet){
isObjectUpdated = true; break;
}
if(server_address && *server_address != QString("")){
isObjectUpdated = true; break;
}
if(m_use_reverse_api_isSet){
isObjectUpdated = true; break;
}
if(reverse_api_address && *reverse_api_address != QString("")){
isObjectUpdated = true; break;
}
if(m_reverse_api_port_isSet){
isObjectUpdated = true; break;
}
if(m_reverse_api_device_index_isSet){
isObjectUpdated = true; break;
}
}while(false);
return isObjectUpdated;
}
}

View File

@ -0,0 +1,95 @@
/**
* SDRangel
* This is the web REST/JSON API of SDRangel SDR software. SDRangel is an Open Source Qt5/OpenGL 3.0+ (4.3+ in Windows) GUI and server Software Defined Radio and signal analyzer in software. It supports Airspy, BladeRF, HackRF, LimeSDR, PlutoSDR, RTL-SDR, SDRplay RSP1 and FunCube --- Limitations and specifcities: * In SDRangel GUI the first Rx device set cannot be deleted. Conversely the server starts with no device sets and its number of device sets can be reduced to zero by as many calls as necessary to /sdrangel/deviceset with DELETE method. * Preset import and export from/to file is a server only feature. * Device set focus is a GUI only feature. * The following channels are not implemented (status 501 is returned): ATV and DATV demodulators, Channel Analyzer NG, LoRa demodulator * The device settings and report structures contains only the sub-structure corresponding to the device type. The DeviceSettings and DeviceReport structures documented here shows all of them but only one will be or should be present at a time * The channel settings and report structures contains only the sub-structure corresponding to the channel type. The ChannelSettings and ChannelReport structures documented here shows all of them but only one will be or should be present at a time ---
*
* OpenAPI spec version: 7.0.0
* Contact: f4exb06@gmail.com
*
* NOTE: This class is auto generated by the swagger code generator program.
* https://github.com/swagger-api/swagger-codegen.git
* Do not edit the class manually.
*/
/*
* SWGAaroniaRTSASettings.h
*
* AaroniaRTSA
*/
#ifndef SWGAaroniaRTSASettings_H_
#define SWGAaroniaRTSASettings_H_
#include <QJsonObject>
#include <QString>
#include "SWGObject.h"
#include "export.h"
namespace SWGSDRangel {
class SWG_API SWGAaroniaRTSASettings: public SWGObject {
public:
SWGAaroniaRTSASettings();
SWGAaroniaRTSASettings(QString* json);
virtual ~SWGAaroniaRTSASettings();
void init();
void cleanup();
virtual QString asJson () override;
virtual QJsonObject* asJsonObject() override;
virtual void fromJsonObject(QJsonObject &json) override;
virtual SWGAaroniaRTSASettings* fromJson(QString &jsonString) override;
qint64 getCenterFrequency();
void setCenterFrequency(qint64 center_frequency);
qint32 getSampleRate();
void setSampleRate(qint32 sample_rate);
QString* getServerAddress();
void setServerAddress(QString* server_address);
qint32 getUseReverseApi();
void setUseReverseApi(qint32 use_reverse_api);
QString* getReverseApiAddress();
void setReverseApiAddress(QString* reverse_api_address);
qint32 getReverseApiPort();
void setReverseApiPort(qint32 reverse_api_port);
qint32 getReverseApiDeviceIndex();
void setReverseApiDeviceIndex(qint32 reverse_api_device_index);
virtual bool isSet() override;
private:
qint64 center_frequency;
bool m_center_frequency_isSet;
qint32 sample_rate;
bool m_sample_rate_isSet;
QString* server_address;
bool m_server_address_isSet;
qint32 use_reverse_api;
bool m_use_reverse_api_isSet;
QString* reverse_api_address;
bool m_reverse_api_address_isSet;
qint32 reverse_api_port;
bool m_reverse_api_port_isSet;
qint32 reverse_api_device_index;
bool m_reverse_api_device_index_isSet;
};
}
#endif /* SWGAaroniaRTSASettings_H_ */

View File

@ -92,6 +92,8 @@ SWGDeviceReport::SWGDeviceReport() {
m_xtrx_output_report_isSet = false;
xtrx_mimo_report = nullptr;
m_xtrx_mimo_report_isSet = false;
aaronia_sdr_report = nullptr;
m_aaronia_sdr_report_isSet = false;
}
SWGDeviceReport::~SWGDeviceReport() {
@ -164,6 +166,8 @@ SWGDeviceReport::init() {
m_xtrx_output_report_isSet = false;
xtrx_mimo_report = new SWGXtrxMIMOReport();
m_xtrx_mimo_report_isSet = false;
aaronia_sdr_report = new SWGAaroniaRTSAReport();
m_aaronia_sdr_report_isSet = false;
}
void
@ -262,6 +266,9 @@ SWGDeviceReport::cleanup() {
if(xtrx_mimo_report != nullptr) {
delete xtrx_mimo_report;
}
if(aaronia_sdr_report != nullptr) {
delete aaronia_sdr_report;
}
}
SWGDeviceReport*
@ -339,6 +346,8 @@ SWGDeviceReport::fromJsonObject(QJsonObject &pJson) {
::SWGSDRangel::setValue(&xtrx_mimo_report, pJson["xtrxMIMOReport"], "SWGXtrxMIMOReport", "SWGXtrxMIMOReport");
::SWGSDRangel::setValue(&aaronia_sdr_report, pJson["aaroniaSDRReport"], "SWGAaroniaRTSAReport", "SWGAaroniaRTSAReport");
}
QString
@ -451,6 +460,9 @@ SWGDeviceReport::asJsonObject() {
if((xtrx_mimo_report != nullptr) && (xtrx_mimo_report->isSet())){
toJsonValue(QString("xtrxMIMOReport"), xtrx_mimo_report, obj, QString("SWGXtrxMIMOReport"));
}
if((aaronia_sdr_report != nullptr) && (aaronia_sdr_report->isSet())){
toJsonValue(QString("aaroniaSDRReport"), aaronia_sdr_report, obj, QString("SWGAaroniaRTSAReport"));
}
return obj;
}
@ -775,6 +787,16 @@ SWGDeviceReport::setXtrxMimoReport(SWGXtrxMIMOReport* xtrx_mimo_report) {
this->m_xtrx_mimo_report_isSet = true;
}
SWGAaroniaRTSAReport*
SWGDeviceReport::getAaroniaSdrReport() {
return aaronia_sdr_report;
}
void
SWGDeviceReport::setAaroniaSdrReport(SWGAaroniaRTSAReport* aaronia_sdr_report) {
this->aaronia_sdr_report = aaronia_sdr_report;
this->m_aaronia_sdr_report_isSet = true;
}
bool
SWGDeviceReport::isSet(){
@ -876,6 +898,9 @@ SWGDeviceReport::isSet(){
if(xtrx_mimo_report && xtrx_mimo_report->isSet()){
isObjectUpdated = true; break;
}
if(aaronia_sdr_report && aaronia_sdr_report->isSet()){
isObjectUpdated = true; break;
}
}while(false);
return isObjectUpdated;
}

View File

@ -22,6 +22,7 @@
#include <QJsonObject>
#include "SWGAaroniaRTSAReport.h"
#include "SWGAirspyHFReport.h"
#include "SWGAirspyReport.h"
#include "SWGBladeRF2InputReport.h"
@ -167,6 +168,9 @@ public:
SWGXtrxMIMOReport* getXtrxMimoReport();
void setXtrxMimoReport(SWGXtrxMIMOReport* xtrx_mimo_report);
SWGAaroniaRTSAReport* getAaroniaSdrReport();
void setAaroniaSdrReport(SWGAaroniaRTSAReport* aaronia_sdr_report);
virtual bool isSet() override;
@ -267,6 +271,9 @@ private:
SWGXtrxMIMOReport* xtrx_mimo_report;
bool m_xtrx_mimo_report_isSet;
SWGAaroniaRTSAReport* aaronia_sdr_report;
bool m_aaronia_sdr_report_isSet;
};
}

View File

@ -120,6 +120,8 @@ SWGDeviceSettings::SWGDeviceSettings() {
m_xtrx_output_settings_isSet = false;
xtrx_mimo_settings = nullptr;
m_xtrx_mimo_settings_isSet = false;
aaronia_rtsa_settings = nullptr;
m_aaronia_rtsa_settings_isSet = false;
}
SWGDeviceSettings::~SWGDeviceSettings() {
@ -220,6 +222,8 @@ SWGDeviceSettings::init() {
m_xtrx_output_settings_isSet = false;
xtrx_mimo_settings = new SWGXtrxMIMOSettings();
m_xtrx_mimo_settings_isSet = false;
aaronia_rtsa_settings = new SWGAaroniaRTSASettings();
m_aaronia_rtsa_settings_isSet = false;
}
void
@ -358,6 +362,9 @@ SWGDeviceSettings::cleanup() {
if(xtrx_mimo_settings != nullptr) {
delete xtrx_mimo_settings;
}
if(aaronia_rtsa_settings != nullptr) {
delete aaronia_rtsa_settings;
}
}
SWGDeviceSettings*
@ -463,6 +470,8 @@ SWGDeviceSettings::fromJsonObject(QJsonObject &pJson) {
::SWGSDRangel::setValue(&xtrx_mimo_settings, pJson["xtrxMIMOSettings"], "SWGXtrxMIMOSettings", "SWGXtrxMIMOSettings");
::SWGSDRangel::setValue(&aaronia_rtsa_settings, pJson["aaroniaRTSASettings"], "SWGAaroniaRTSASettings", "SWGAaroniaRTSASettings");
}
QString
@ -617,6 +626,9 @@ SWGDeviceSettings::asJsonObject() {
if((xtrx_mimo_settings != nullptr) && (xtrx_mimo_settings->isSet())){
toJsonValue(QString("xtrxMIMOSettings"), xtrx_mimo_settings, obj, QString("SWGXtrxMIMOSettings"));
}
if((aaronia_rtsa_settings != nullptr) && (aaronia_rtsa_settings->isSet())){
toJsonValue(QString("aaroniaRTSASettings"), aaronia_rtsa_settings, obj, QString("SWGAaroniaRTSASettings"));
}
return obj;
}
@ -1081,6 +1093,16 @@ SWGDeviceSettings::setXtrxMimoSettings(SWGXtrxMIMOSettings* xtrx_mimo_settings)
this->m_xtrx_mimo_settings_isSet = true;
}
SWGAaroniaRTSASettings*
SWGDeviceSettings::getAaroniaRtsaSettings() {
return aaronia_rtsa_settings;
}
void
SWGDeviceSettings::setAaroniaRtsaSettings(SWGAaroniaRTSASettings* aaronia_rtsa_settings) {
this->aaronia_rtsa_settings = aaronia_rtsa_settings;
this->m_aaronia_rtsa_settings_isSet = true;
}
bool
SWGDeviceSettings::isSet(){
@ -1224,6 +1246,9 @@ SWGDeviceSettings::isSet(){
if(xtrx_mimo_settings && xtrx_mimo_settings->isSet()){
isObjectUpdated = true; break;
}
if(aaronia_rtsa_settings && aaronia_rtsa_settings->isSet()){
isObjectUpdated = true; break;
}
}while(false);
return isObjectUpdated;
}

View File

@ -22,6 +22,7 @@
#include <QJsonObject>
#include "SWGAaroniaRTSASettings.h"
#include "SWGAirspyHFSettings.h"
#include "SWGAirspySettings.h"
#include "SWGAudioInputSettings.h"
@ -223,6 +224,9 @@ public:
SWGXtrxMIMOSettings* getXtrxMimoSettings();
void setXtrxMimoSettings(SWGXtrxMIMOSettings* xtrx_mimo_settings);
SWGAaroniaRTSASettings* getAaroniaRtsaSettings();
void setAaroniaRtsaSettings(SWGAaroniaRTSASettings* aaronia_rtsa_settings);
virtual bool isSet() override;
@ -365,6 +369,9 @@ private:
SWGXtrxMIMOSettings* xtrx_mimo_settings;
bool m_xtrx_mimo_settings_isSet;
SWGAaroniaRTSASettings* aaronia_rtsa_settings;
bool m_aaronia_rtsa_settings_isSet;
};
}

View File

@ -43,6 +43,8 @@
#include "SWGATVDemodSettings.h"
#include "SWGATVModReport.h"
#include "SWGATVModSettings.h"
#include "SWGAaroniaRTSAReport.h"
#include "SWGAaroniaRTSASettings.h"
#include "SWGAirspyHFReport.h"
#include "SWGAirspyHFSettings.h"
#include "SWGAirspyReport.h"
@ -498,6 +500,16 @@ namespace SWGSDRangel {
obj->init();
return obj;
}
if(QString("SWGAaroniaRTSAReport").compare(type) == 0) {
SWGAaroniaRTSAReport *obj = new SWGAaroniaRTSAReport();
obj->init();
return obj;
}
if(QString("SWGAaroniaRTSASettings").compare(type) == 0) {
SWGAaroniaRTSASettings *obj = new SWGAaroniaRTSASettings();
obj->init();
return obj;
}
if(QString("SWGAirspyHFReport").compare(type) == 0) {
SWGAirspyHFReport *obj = new SWGAirspyHFReport();
obj->init();