1
0
mirror of https://github.com/f4exb/sdrangel.git synced 2024-12-23 01:55:48 -05:00

Aaronia RTSA output: initial commit

This commit is contained in:
f4exb 2023-05-23 10:23:18 +02:00
parent ef5f4c5d9f
commit a6fa12ab3b
32 changed files with 996 additions and 152 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

BIN
doc/img/aaronia_http_tx.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

View File

@ -5,6 +5,7 @@ set(aaroniartsaoutput_SOURCES
aaroniartsaoutputplugin.cpp aaroniartsaoutputplugin.cpp
aaroniartsaoutputsettings.cpp aaroniartsaoutputsettings.cpp
aaroniartsaoutputwebapiadapter.cpp aaroniartsaoutputwebapiadapter.cpp
aaroniartsaoutputworker.cpp
) )
set(aaroniartsaoutput_HEADERS set(aaroniartsaoutput_HEADERS
@ -12,6 +13,7 @@ set(aaroniartsaoutput_HEADERS
aaroniartsaoutputplugin.h aaroniartsaoutputplugin.h
aaroniartsaoutputsettings.h aaroniartsaoutputsettings.h
aaroniartsaoutputwebapiadapter.h aaroniartsaoutputwebapiadapter.h
aaroniartsaoutputworker.h
) )
include_directories( include_directories(

View File

@ -21,6 +21,7 @@
#include <QDebug> #include <QDebug>
#include <QNetworkReply> #include <QNetworkReply>
#include <QBuffer> #include <QBuffer>
#include <QThread>
#include "SWGDeviceSettings.h" #include "SWGDeviceSettings.h"
#include "SWGDeviceState.h" #include "SWGDeviceState.h"
@ -32,18 +33,23 @@
#include "dsp/dspengine.h" #include "dsp/dspengine.h"
#include "device/deviceapi.h" #include "device/deviceapi.h"
#include "aaroniartsaoutputworker.h"
#include "aaroniartsaoutput.h" #include "aaroniartsaoutput.h"
MESSAGE_CLASS_DEFINITION(AaroniaRTSAOutput::MsgConfigureAaroniaRTSAOutput, Message) MESSAGE_CLASS_DEFINITION(AaroniaRTSAOutput::MsgConfigureAaroniaRTSAOutput, Message)
MESSAGE_CLASS_DEFINITION(AaroniaRTSAOutput::MsgStartStop, Message) MESSAGE_CLASS_DEFINITION(AaroniaRTSAOutput::MsgStartStop, Message)
MESSAGE_CLASS_DEFINITION(AaroniaRTSAOutput::MsgReportSampleRateAndFrequency, Message) MESSAGE_CLASS_DEFINITION(AaroniaRTSAOutput::MsgReportSampleRateAndFrequency, Message)
MESSAGE_CLASS_DEFINITION(AaroniaRTSAOutput::MsgSetStatus, Message)
AaroniaRTSAOutput::AaroniaRTSAOutput(DeviceAPI *deviceAPI) : AaroniaRTSAOutput::AaroniaRTSAOutput(DeviceAPI *deviceAPI) :
m_deviceAPI(deviceAPI), m_deviceAPI(deviceAPI),
m_settings(), m_settings(),
m_centerFrequency(0), m_centerFrequency(0),
m_sampleRate(48000), m_sampleRate(48000),
m_deviceDescription("AaroniaRTSAOutput") m_deviceDescription("AaroniaRTSAOutput"),
m_worker(nullptr),
m_workerThread(nullptr),
m_running(false)
{ {
m_sampleSourceFifo.resize(SampleSourceFifo::getSizePolicy(m_sampleRate)); m_sampleSourceFifo.resize(SampleSourceFifo::getSizePolicy(m_sampleRate));
m_deviceAPI->setNbSinkStreams(1); m_deviceAPI->setNbSinkStreams(1);
@ -80,13 +86,53 @@ void AaroniaRTSAOutput::init()
bool AaroniaRTSAOutput::start() bool AaroniaRTSAOutput::start()
{ {
QMutexLocker mutexLocker(&m_mutex);
if (m_running) {
return true;
}
qDebug() << "AaroniaRTSAOutput::start"; qDebug() << "AaroniaRTSAOutput::start";
m_workerThread = new QThread();
m_worker = new AaroniaRTSAOutputWorker(&m_sampleSourceFifo);
m_worker->moveToThread(m_workerThread);
QObject::connect(m_workerThread, &QThread::started, m_worker, &AaroniaRTSAOutputWorker::startWork);
QObject::connect(m_workerThread, &QThread::finished, m_worker, &QObject::deleteLater);
QObject::connect(m_workerThread, &QThread::finished, m_workerThread, &QThread::deleteLater);
QObject::connect(m_worker, &AaroniaRTSAOutputWorker::updateStatus, this, &AaroniaRTSAOutput::setWorkerStatus);
m_workerThread->start();
m_running = true;
mutexLocker.unlock();
applySettings(m_settings, QList<QString>(), true);
qDebug("AaroniaRTSAOutput::start: started");
return true; return true;
} }
void AaroniaRTSAOutput::stop() void AaroniaRTSAOutput::stop()
{ {
QMutexLocker mutexLocker(&m_mutex);
if (!m_running) {
return;
}
qDebug() << "AaroniaRTSAOutput::stop"; qDebug() << "AaroniaRTSAOutput::stop";
m_running = false;
if (m_workerThread)
{
m_worker->stopWork();
m_workerThread->quit();
m_workerThread->wait();
m_worker = nullptr;
m_workerThread = nullptr;
}
} }
QByteArray AaroniaRTSAOutput::serialize() const QByteArray AaroniaRTSAOutput::serialize() const
@ -165,6 +211,13 @@ void AaroniaRTSAOutput::setCenterFrequency(qint64 centerFrequency)
} }
} }
void AaroniaRTSAOutput::setWorkerStatus(int status)
{
if (m_guiMessageQueue) {
m_guiMessageQueue->push(MsgSetStatus::create(status));
}
}
bool AaroniaRTSAOutput::handleMessage(const Message& message) bool AaroniaRTSAOutput::handleMessage(const Message& message)
{ {
if (DSPSignalNotification::match(message)) if (DSPSignalNotification::match(message))
@ -206,13 +259,48 @@ bool AaroniaRTSAOutput::handleMessage(const Message& message)
} }
} }
int AaroniaRTSAOutput::getStatus() const
{
// TODO
// if (m_aaroniaRTSAWorker) {
// return m_aaroniaRTSAWorker->getStatus();
// } else {
return 0;
// }
}
void AaroniaRTSAOutput::applySettings(const AaroniaRTSAOutputSettings& settings, const QList<QString>& settingsKeys, bool force) void AaroniaRTSAOutput::applySettings(const AaroniaRTSAOutputSettings& settings, const QList<QString>& settingsKeys, bool force)
{ {
qDebug() << "AaroniaRTSAOutput::applySettings: force:" << force << settings.getDebugString(settingsKeys, force); qDebug() << "AaroniaRTSAOutput::applySettings: force:" << force << settings.getDebugString(settingsKeys, force);
QMutexLocker mutexLocker(&m_mutex); QMutexLocker mutexLocker(&m_mutex);
std::ostringstream os; std::ostringstream os;
QString remoteAddress;
QList<QString> reverseAPIKeys; QList<QString> reverseAPIKeys;
bool forwardChangeToDSP = false;
if (settingsKeys.contains("centerFrequency") || force)
{
if (m_worker) {
m_worker->setCenterFrequency(settings.m_centerFrequency);
}
forwardChangeToDSP = true;
}
if (settingsKeys.contains("sampleRate") || force)
{
if (m_worker) {
m_worker->setSampleRate(settings.m_sampleRate);
}
forwardChangeToDSP = true;
}
if (settingsKeys.contains("serverAddress") || force)
{
if (m_worker) {
m_worker->setServerAddress(settings.m_serverAddress);
}
}
if (settingsKeys.contains("useReverseAPI")) if (settingsKeys.contains("useReverseAPI"))
{ {
@ -223,13 +311,17 @@ void AaroniaRTSAOutput::applySettings(const AaroniaRTSAOutputSettings& settings,
webapiReverseSendSettings(settingsKeys, settings, fullUpdate || force); webapiReverseSendSettings(settingsKeys, settings, fullUpdate || force);
} }
if (forwardChangeToDSP)
{
DSPSignalNotification *notif = new DSPSignalNotification(settings.m_sampleRate, settings.m_centerFrequency);
m_deviceAPI->getDeviceEngineInputMessageQueue()->push(notif);
}
if (force) { if (force) {
m_settings = settings; m_settings = settings;
} else { } else {
m_settings.applySettings(settingsKeys, settings); m_settings.applySettings(settingsKeys, settings);
} }
m_remoteAddress = remoteAddress;
} }
int AaroniaRTSAOutput::webapiRunGet( int AaroniaRTSAOutput::webapiRunGet(
@ -299,6 +391,15 @@ void AaroniaRTSAOutput::webapiUpdateDeviceSettings(
const QStringList& deviceSettingsKeys, const QStringList& deviceSettingsKeys,
SWGSDRangel::SWGDeviceSettings& response) SWGSDRangel::SWGDeviceSettings& response)
{ {
if (deviceSettingsKeys.contains("centerFrequency")) {
settings.m_centerFrequency = response.getAaroniaRtsaOutputSettings()->getCenterFrequency();
}
if (deviceSettingsKeys.contains("sampleRate")) {
settings.m_sampleRate = response.getAaroniaRtsaOutputSettings()->getSampleRate();
}
if (deviceSettingsKeys.contains("serverAddress")) {
settings.m_serverAddress = *response.getAaroniaRtsaOutputSettings()->getServerAddress();
}
if (deviceSettingsKeys.contains("useReverseAPI")) { if (deviceSettingsKeys.contains("useReverseAPI")) {
settings.m_useReverseAPI = response.getAaroniaRtsaOutputSettings()->getUseReverseApi() != 0; settings.m_useReverseAPI = response.getAaroniaRtsaOutputSettings()->getUseReverseApi() != 0;
} }
@ -315,6 +416,15 @@ void AaroniaRTSAOutput::webapiUpdateDeviceSettings(
void AaroniaRTSAOutput::webapiFormatDeviceSettings(SWGSDRangel::SWGDeviceSettings& response, const AaroniaRTSAOutputSettings& settings) void AaroniaRTSAOutput::webapiFormatDeviceSettings(SWGSDRangel::SWGDeviceSettings& response, const AaroniaRTSAOutputSettings& settings)
{ {
response.getAaroniaRtsaOutputSettings()->setCenterFrequency(settings.m_centerFrequency);
response.getAaroniaRtsaOutputSettings()->setSampleRate(settings.m_sampleRate);
if (response.getAaroniaRtsaOutputSettings()->getServerAddress()) {
*response.getAaroniaRtsaOutputSettings()->getServerAddress() = settings.m_serverAddress;
} else {
response.getAaroniaRtsaOutputSettings()->setServerAddress(new QString(settings.m_serverAddress));
}
response.getAaroniaRtsaOutputSettings()->setUseReverseApi(settings.m_useReverseAPI ? 1 : 0); response.getAaroniaRtsaOutputSettings()->setUseReverseApi(settings.m_useReverseAPI ? 1 : 0);
if (response.getAaroniaRtsaOutputSettings()->getReverseApiAddress()) { if (response.getAaroniaRtsaOutputSettings()->getReverseApiAddress()) {
@ -340,8 +450,7 @@ int AaroniaRTSAOutput::webapiReportGet(
void AaroniaRTSAOutput::webapiFormatDeviceReport(SWGSDRangel::SWGDeviceReport& response) void AaroniaRTSAOutput::webapiFormatDeviceReport(SWGSDRangel::SWGDeviceReport& response)
{ {
response.getAaroniaRtsaOutputReport()->setCenterFrequency(m_centerFrequency); response.getAaroniaRtsaOutputReport()->setStatus(getStatus());
response.getAaroniaRtsaOutputReport()->setSampleRate(m_sampleRate);
} }
void AaroniaRTSAOutput::webapiReverseSendSettings(const QList<QString>& deviceSettingsKeys, const AaroniaRTSAOutputSettings& settings, bool force) void AaroniaRTSAOutput::webapiReverseSendSettings(const QList<QString>& deviceSettingsKeys, const AaroniaRTSAOutputSettings& settings, bool force)

View File

@ -15,8 +15,8 @@
// along with this program. If not, see <http://www.gnu.org/licenses/>. // // along with this program. If not, see <http://www.gnu.org/licenses/>. //
/////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////
#ifndef INCLUDE_LOCALOUTPUT_H #ifndef INCLUDE_AARONIARTSAOUTPUT_H
#define INCLUDE_LOCALOUTPUT_H #define INCLUDE_AARONIARTSAOUTPUT_H
#include <ctime> #include <ctime>
#include <iostream> #include <iostream>
@ -34,6 +34,8 @@
class QNetworkAccessManager; class QNetworkAccessManager;
class QNetworkReply; class QNetworkReply;
class DeviceAPI; class DeviceAPI;
class QThread;
class AaroniaRTSAOutputWorker;
class AaroniaRTSAOutput : public DeviceSampleSink { class AaroniaRTSAOutput : public DeviceSampleSink {
Q_OBJECT Q_OBJECT
@ -104,6 +106,25 @@ public:
{ } { }
}; };
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)
{ }
};
AaroniaRTSAOutput(DeviceAPI *deviceAPI); AaroniaRTSAOutput(DeviceAPI *deviceAPI);
virtual ~AaroniaRTSAOutput(); virtual ~AaroniaRTSAOutput();
virtual void destroy(); virtual void destroy();
@ -163,11 +184,14 @@ private:
AaroniaRTSAOutputSettings m_settings; AaroniaRTSAOutputSettings m_settings;
qint64 m_centerFrequency; qint64 m_centerFrequency;
int m_sampleRate; int m_sampleRate;
QString m_remoteAddress;
QString m_deviceDescription; QString m_deviceDescription;
QNetworkAccessManager *m_networkManager; QNetworkAccessManager *m_networkManager;
QNetworkRequest m_networkRequest; QNetworkRequest m_networkRequest;
AaroniaRTSAOutputWorker *m_worker;
QThread *m_workerThread;
bool m_running;
int getStatus() const;
void applySettings(const AaroniaRTSAOutputSettings& settings, const QList<QString>& settingsKeys, bool force = false); void applySettings(const AaroniaRTSAOutputSettings& settings, const QList<QString>& settingsKeys, bool force = false);
void webapiFormatDeviceReport(SWGSDRangel::SWGDeviceReport& response); void webapiFormatDeviceReport(SWGSDRangel::SWGDeviceReport& response);
void webapiReverseSendSettings(const QList<QString>& deviceSettingsKeys, const AaroniaRTSAOutputSettings& settings, bool force); void webapiReverseSendSettings(const QList<QString>& deviceSettingsKeys, const AaroniaRTSAOutputSettings& settings, bool force);
@ -175,6 +199,7 @@ private:
private slots: private slots:
void networkManagerFinished(QNetworkReply *reply); void networkManagerFinished(QNetworkReply *reply);
void setWorkerStatus(int status);
}; };
#endif // INCLUDE_LOCALOUTPUT_H #endif // INCLUDE_AARONIARTSAOUTPUT_H

View File

@ -62,10 +62,26 @@ AaroniaRTSAOutputGui::AaroniaRTSAOutputGui(DeviceUISet *deviceUISet, QWidget* pa
m_paletteGreenText.setColor(QPalette::WindowText, Qt::green); m_paletteGreenText.setColor(QPalette::WindowText, Qt::green);
m_paletteWhiteText.setColor(QPalette::WindowText, Qt::white); m_paletteWhiteText.setColor(QPalette::WindowText, Qt::white);
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()); ui->setupUi(getContents());
sizeToContents(); sizeToContents();
getContents()->setStyleSheet("#AaroniaRTSAOutputGui { background-color: rgb(64, 64, 64); }"); getContents()->setStyleSheet("#AaroniaRTSAOutputGui { background-color: rgb(64, 64, 64); }");
m_helpURL = "plugins/samplesink/localoutput/readme.md"; m_helpURL = "plugins/samplesink/aaroniartsaoutput/readme.md";
ui->centerFrequency->setColorMapper(ColorMapper(ColorMapper::GrayGold));
ui->centerFrequency->setValueRange(9, 0, 999999999);
ui->sampleRate->setColorMapper(ColorMapper(ColorMapper::GrayGreenYellow));
ui->sampleRate->setValueRange(7, 2000U, 8000000U);
connect(this, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(openDeviceSettingsDialog(const QPoint &))); connect(this, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(openDeviceSettingsDialog(const QPoint &)));
@ -168,6 +184,28 @@ bool AaroniaRTSAOutputGui::handleMessage(const Message& message)
return true; return true;
} }
else if (DSPSignalNotification::match(message))
{
DSPSignalNotification& notif = (DSPSignalNotification&) message;
m_streamSampleRate = notif.getSampleRate();
m_streamCenterFrequency = notif.getCenterFrequency();
qDebug("AaroniaRTSAOutputGui::handleInputMessages: DSPSignalNotification: SampleRate:%d, CenterFrequency:%llu",
notif.getSampleRate(),
notif.getCenterFrequency());
updateSampleRateAndFrequency();
return true;
}
else if (AaroniaRTSAOutput::MsgSetStatus::match(message))
{
qDebug("AaroniaRTSAOutputGui::handleMessage: MsgSetStatus");
AaroniaRTSAOutput::MsgSetStatus& notif = (AaroniaRTSAOutput::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 else
{ {
return false; return false;
@ -209,13 +247,12 @@ void AaroniaRTSAOutputGui::handleInputMessages()
} }
} }
void AaroniaRTSAOutputGui::updateSampleRateAndFrequency() void AaroniaRTSAOutputGui::updateSampleRateAndFrequency(){
{
m_deviceUISet->getSpectrum()->setSampleRate(m_streamSampleRate); m_deviceUISet->getSpectrum()->setSampleRate(m_streamSampleRate);
m_deviceUISet->getSpectrum()->setCenterFrequency(m_streamCenterFrequency); m_deviceUISet->getSpectrum()->setCenterFrequency(m_streamCenterFrequency);
ui->deviceRateText->setText(tr("%1k").arg((float)m_streamSampleRate / 1000)); ui->deviceRateText->setText(tr("%1k").arg((float)m_streamSampleRate / 1000));
blockApplySettings(true); blockApplySettings(true);
ui->centerFrequency->setText(QString("%L1").arg(m_streamCenterFrequency / 1000)); ui->centerFrequency->setValue(m_settings.m_centerFrequency / 1000);
blockApplySettings(false); blockApplySettings(false);
} }
@ -223,8 +260,10 @@ void AaroniaRTSAOutputGui::displaySettings()
{ {
blockApplySettings(true); blockApplySettings(true);
ui->centerFrequency->setText(QString("%L1").arg(m_streamCenterFrequency / 1000)); ui->centerFrequency->setValue(m_settings.m_centerFrequency / 1000);
ui->sampleRate->setValue(m_settings.m_sampleRate);
ui->deviceRateText->setText(tr("%1k").arg(m_streamSampleRate / 1000.0)); ui->deviceRateText->setText(tr("%1k").arg(m_streamSampleRate / 1000.0));
ui->serverAddress->setText(m_settings.m_serverAddress);
blockApplySettings(false); blockApplySettings(false);
} }
@ -245,6 +284,40 @@ void AaroniaRTSAOutputGui::on_startStop_toggled(bool checked)
} }
} }
void AaroniaRTSAOutputGui::on_centerFrequency_changed(quint64 value)
{
m_settings.m_centerFrequency = value * 1000;
m_settingsKeys.append("centerFrequency");
sendSettings();
}
void AaroniaRTSAOutputGui::on_sampleRate_changed(quint64 value)
{
m_settings.m_sampleRate = value;
m_settingsKeys.append("sampleRate");
sendSettings();
}
void AaroniaRTSAOutputGui::on_serverAddress_returnPressed()
{
on_serverAddressApplyButton_clicked();
}
void AaroniaRTSAOutputGui::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 AaroniaRTSAOutputGui::updateHardware() void AaroniaRTSAOutputGui::updateHardware()
{ {
if (m_doApplySettings) if (m_doApplySettings)
@ -320,4 +393,8 @@ void AaroniaRTSAOutputGui::openDeviceSettingsDialog(const QPoint& p)
void AaroniaRTSAOutputGui::makeUIConnections() void AaroniaRTSAOutputGui::makeUIConnections()
{ {
QObject::connect(ui->startStop, &ButtonSwitch::toggled, this, &AaroniaRTSAOutputGui::on_startStop_toggled); QObject::connect(ui->startStop, &ButtonSwitch::toggled, this, &AaroniaRTSAOutputGui::on_startStop_toggled);
QObject::connect(ui->centerFrequency, &ValueDial::changed, this, &AaroniaRTSAOutputGui::on_centerFrequency_changed);
QObject::connect(ui->sampleRate, &ValueDial::changed, this, &AaroniaRTSAOutputGui::on_sampleRate_changed);
QObject::connect(ui->serverAddress, &QLineEdit::returnPressed, this, &AaroniaRTSAOutputGui::on_serverAddress_returnPressed);
QObject::connect(ui->serverAddressApplyButton, &QPushButton::clicked, this, &AaroniaRTSAOutputGui::on_serverAddressApplyButton_clicked);
} }

View File

@ -15,8 +15,8 @@
// along with this program. If not, see <http://www.gnu.org/licenses/>. // // along with this program. If not, see <http://www.gnu.org/licenses/>. //
/////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////
#ifndef INCLUDE_LOCALOUTPUTGUI_H #ifndef INCLUDE_AARONIARTSAOUTPUTGUI_H
#define INCLUDE_LOCALOUTPUTGUI_H #define INCLUDE_AARONIARTSAOUTPUTGUI_H
#include <QTimer> #include <QTimer>
#include <QWidget> #include <QWidget>
@ -70,6 +70,9 @@ private:
QPalette m_paletteGreenText; QPalette m_paletteGreenText;
QPalette m_paletteWhiteText; QPalette m_paletteWhiteText;
std::vector<QString> m_statusColors;
std::vector<QString> m_statusTooltips;
void blockApplySettings(bool block); void blockApplySettings(bool block);
void displaySettings(); void displaySettings();
void sendSettings(); void sendSettings();
@ -80,9 +83,13 @@ private:
private slots: private slots:
void handleInputMessages(); void handleInputMessages();
void on_startStop_toggled(bool checked); 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 updateHardware(); void updateHardware();
void updateStatus(); void updateStatus();
void openDeviceSettingsDialog(const QPoint& p); void openDeviceSettingsDialog(const QPoint& p);
}; };
#endif // INCLUDE_LOCALOUTPUTGUI_H #endif // INCLUDE_AARONIARTSAOUTPUTGUI_H

View File

@ -7,7 +7,7 @@
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>360</width> <width>360</width>
<height>47</height> <height>130</height>
</rect> </rect>
</property> </property>
<property name="sizePolicy"> <property name="sizePolicy">
@ -19,13 +19,13 @@
<property name="minimumSize"> <property name="minimumSize">
<size> <size>
<width>360</width> <width>360</width>
<height>47</height> <height>130</height>
</size> </size>
</property> </property>
<property name="maximumSize"> <property name="maximumSize">
<size> <size>
<width>380</width> <width>380</width>
<height>68</height> <height>130</height>
</size> </size>
</property> </property>
<property name="font"> <property name="font">
@ -112,24 +112,36 @@
</spacer> </spacer>
</item> </item>
<item> <item>
<widget class="QLabel" name="centerFrequency"> <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"> <property name="minimumSize">
<size> <size>
<width>170</width> <width>32</width>
<height>0</height> <height>16</height>
</size> </size>
</property> </property>
<property name="font"> <property name="font">
<font> <font>
<family>Liberation Sans</family> <family>Liberation Mono</family>
<pointsize>16</pointsize> <pointsize>16</pointsize>
<weight>50</weight>
<italic>false</italic>
<bold>false</bold>
</font> </font>
</property> </property>
<property name="text"> <property name="cursor">
<string>10,000,000,000</string> <cursorShape>PointingHandCursor</cursorShape>
</property> </property>
<property name="alignment"> <property name="focusPolicy">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> <enum>Qt::StrongFocus</enum>
</property>
<property name="toolTip">
<string>Tuner center frequency in kHz</string>
</property> </property>
</widget> </widget>
</item> </item>
@ -142,7 +154,7 @@
</sizepolicy> </sizepolicy>
</property> </property>
<property name="text"> <property name="text">
<string> Hz</string> <string> kHz</string>
</property> </property>
<property name="alignment"> <property name="alignment">
<set>Qt::AlignCenter</set> <set>Qt::AlignCenter</set>
@ -164,6 +176,130 @@
</item> </item>
</layout> </layout>
</item> </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_6">
<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> </layout>
</widget> </widget>
<customwidgets> <customwidgets>
@ -172,6 +308,12 @@
<extends>QToolButton</extends> <extends>QToolButton</extends>
<header>gui/buttonswitch.h</header> <header>gui/buttonswitch.h</header>
</customwidget> </customwidget>
<customwidget>
<class>ValueDial</class>
<extends>QWidget</extends>
<header>gui/valuedial.h</header>
<container>1</container>
</customwidget>
</customwidgets> </customwidgets>
<resources> <resources>
<include location="../../../sdrgui/resources/res.qrc"/> <include location="../../../sdrgui/resources/res.qrc"/>

View File

@ -30,8 +30,8 @@
const PluginDescriptor AaroniaRTSAOutputPlugin::m_pluginDescriptor = { const PluginDescriptor AaroniaRTSAOutputPlugin::m_pluginDescriptor = {
QStringLiteral("AaroniaRTSAOutput"), QStringLiteral("AaroniaRTSAOutput"),
QStringLiteral("Local device output"), QStringLiteral("AaroniaRTSA output"),
QStringLiteral("7.8.2"), QStringLiteral("7.14.0"),
QStringLiteral("(c) Edouard Griffiths, F4EXB"), QStringLiteral("(c) Edouard Griffiths, F4EXB"),
QStringLiteral("https://github.com/f4exb/sdrangel"), QStringLiteral("https://github.com/f4exb/sdrangel"),
true, true,
@ -39,7 +39,7 @@ const PluginDescriptor AaroniaRTSAOutputPlugin::m_pluginDescriptor = {
}; };
static constexpr const char* const m_hardwareID = "AaroniaRTSAOutput"; static constexpr const char* const m_hardwareID = "AaroniaRTSAOutput";
static constexpr const char* const m_deviceTypeID = LOCALOUTPUT_DEVICE_TYPE_ID; static constexpr const char* const m_deviceTypeID = AARONIARTSAOUTPUT_DEVICE_TYPE_ID;
AaroniaRTSAOutputPlugin::AaroniaRTSAOutputPlugin(QObject* parent) : AaroniaRTSAOutputPlugin::AaroniaRTSAOutputPlugin(QObject* parent) :
QObject(parent) QObject(parent)

View File

@ -15,20 +15,20 @@
// along with this program. If not, see <http://www.gnu.org/licenses/>. // // along with this program. If not, see <http://www.gnu.org/licenses/>. //
/////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////
#ifndef INCLUDE_LOCALOUTPUTPLUGIN_H #ifndef INCLUDE_AARONIARTSAOUTPUTPLUGIN_H
#define INCLUDE_LOCALOUTPUTPLUGIN_H #define INCLUDE_AARONIARTSAOUTPUTPLUGIN_H
#include <QObject> #include <QObject>
#include "plugin/plugininterface.h" #include "plugin/plugininterface.h"
#define LOCALOUTPUT_DEVICE_TYPE_ID "sdrangel.samplesink.localoutput" #define AARONIARTSAOUTPUT_DEVICE_TYPE_ID "sdrangel.samplesink.aaroniartsaoutput"
class PluginAPI; class PluginAPI;
class AaroniaRTSAOutputPlugin : public QObject, public PluginInterface { class AaroniaRTSAOutputPlugin : public QObject, public PluginInterface {
Q_OBJECT Q_OBJECT
Q_INTERFACES(PluginInterface) Q_INTERFACES(PluginInterface)
Q_PLUGIN_METADATA(IID LOCALOUTPUT_DEVICE_TYPE_ID) Q_PLUGIN_METADATA(IID AARONIARTSAOUTPUT_DEVICE_TYPE_ID)
public: public:
explicit AaroniaRTSAOutputPlugin(QObject* parent = nullptr); explicit AaroniaRTSAOutputPlugin(QObject* parent = nullptr);
@ -49,4 +49,4 @@ private:
static const PluginDescriptor m_pluginDescriptor; static const PluginDescriptor m_pluginDescriptor;
}; };
#endif // INCLUDE_LOCALOUTPUTPLUGIN_H #endif // INCLUDE_AARONIARTSAOUTPUTPLUGIN_H

View File

@ -25,6 +25,9 @@ AaroniaRTSAOutputSettings::AaroniaRTSAOutputSettings()
void AaroniaRTSAOutputSettings::resetToDefaults() void AaroniaRTSAOutputSettings::resetToDefaults()
{ {
m_centerFrequency = 433200000;
m_sampleRate = 100000;
m_serverAddress = "127.0.0.1:5550";
m_useReverseAPI = false; m_useReverseAPI = false;
m_reverseAPIAddress = "127.0.0.1"; m_reverseAPIAddress = "127.0.0.1";
m_reverseAPIPort = 8888; m_reverseAPIPort = 8888;
@ -35,9 +38,12 @@ QByteArray AaroniaRTSAOutputSettings::serialize() const
{ {
SimpleSerializer s(1); SimpleSerializer s(1);
s.writeString(4, m_reverseAPIAddress); s.writeU64(1, m_centerFrequency);
s.writeU32(5, m_reverseAPIPort); s.writeString(2, m_serverAddress);
s.writeU32(6, m_reverseAPIDeviceIndex); s.writeS32(3, m_sampleRate);
s.writeString(20, m_reverseAPIAddress);
s.writeU32(21, m_reverseAPIPort);
s.writeU32(22, m_reverseAPIDeviceIndex);
return s.final(); return s.final();
} }
@ -56,8 +62,11 @@ bool AaroniaRTSAOutputSettings::deserialize(const QByteArray& data)
{ {
quint32 uintval; quint32 uintval;
d.readString(4, &m_reverseAPIAddress, "127.0.0.1"); d.readU64(1, &m_centerFrequency, 433200000);
d.readU32(5, &uintval, 0); d.readString(2, &m_serverAddress, "127.0.0.1:5550");
d.readS32(3, &m_sampleRate, 100000);
d.readString(20, &m_reverseAPIAddress, "127.0.0.1");
d.readU32(21, &uintval, 0);
if ((uintval > 1023) && (uintval < 65535)) { if ((uintval > 1023) && (uintval < 65535)) {
m_reverseAPIPort = uintval; m_reverseAPIPort = uintval;
@ -65,7 +74,7 @@ bool AaroniaRTSAOutputSettings::deserialize(const QByteArray& data)
m_reverseAPIPort = 8888; m_reverseAPIPort = 8888;
} }
d.readU32(6, &uintval, 0); d.readU32(22, &uintval, 0);
m_reverseAPIDeviceIndex = uintval > 99 ? 99 : uintval; m_reverseAPIDeviceIndex = uintval > 99 ? 99 : uintval;
return true; return true;
@ -79,6 +88,15 @@ bool AaroniaRTSAOutputSettings::deserialize(const QByteArray& data)
void AaroniaRTSAOutputSettings::applySettings(const QStringList& settingsKeys, const AaroniaRTSAOutputSettings& settings) void AaroniaRTSAOutputSettings::applySettings(const QStringList& settingsKeys, const AaroniaRTSAOutputSettings& 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")) { if (settingsKeys.contains("useReverseAPI")) {
m_useReverseAPI = settings.m_useReverseAPI; m_useReverseAPI = settings.m_useReverseAPI;
} }
@ -97,6 +115,15 @@ QString AaroniaRTSAOutputSettings::getDebugString(const QStringList& settingsKey
{ {
std::ostringstream ostr; 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) { if (settingsKeys.contains("useReverseAPI") || force) {
ostr << " m_useReverseAPI: " << m_useReverseAPI; ostr << " m_useReverseAPI: " << m_useReverseAPI;
} }

View File

@ -15,13 +15,28 @@
// along with this program. If not, see <http://www.gnu.org/licenses/>. // // along with this program. If not, see <http://www.gnu.org/licenses/>. //
/////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////
#ifndef PLUGINS_SAMPLESINK_LOCALOUTPUT_LOCALOUTPUTSETTINGS_H_ #ifndef PLUGINS_AARONIARTSAOUTPUTSETTINGS_H_
#define PLUGINS_SAMPLESINK_LOCALOUTPUT_LOCALOUTPUTSETTINGS_H_ #define PLUGINS_AARONIARTSAOUTPUTSETTINGS_H_
#include <QByteArray> #include <QByteArray>
#include <QString> #include <QString>
struct AaroniaRTSAOutputSettings { struct AaroniaRTSAOutputSettings
{
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; bool m_useReverseAPI;
QString m_reverseAPIAddress; QString m_reverseAPIAddress;
uint16_t m_reverseAPIPort; uint16_t m_reverseAPIPort;
@ -35,4 +50,4 @@ struct AaroniaRTSAOutputSettings {
QString getDebugString(const QStringList& settingsKeys, bool force=false) const; QString getDebugString(const QStringList& settingsKeys, bool force=false) const;
}; };
#endif /* PLUGINS_SAMPLESINK_LOCALOUTPUT_LOCALOUTPUTSETTINGS_H_ */ #endif /* PLUGINS_AARONIARTSAOUTPUTSETTINGS_H_ */

View File

@ -18,6 +18,9 @@
// along with this program. If not, see <http://www.gnu.org/licenses/>. // // along with this program. If not, see <http://www.gnu.org/licenses/>. //
/////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////
#ifndef PLUGINS_AARONIARTSAOUTPUTWEBAPIADAPTER_H_
#define PLUGINS_AARONIARTSAOUTPUTWEBAPIADAPTER_H_
#include "device/devicewebapiadapter.h" #include "device/devicewebapiadapter.h"
#include "aaroniartsaoutputsettings.h" #include "aaroniartsaoutputsettings.h"
@ -42,3 +45,5 @@ public:
private: private:
AaroniaRTSAOutputSettings m_settings; AaroniaRTSAOutputSettings m_settings;
}; };
#endif // PLUGINS_AARONIARTSAOUTPUTWEBAPIADAPTER_H_

View File

@ -0,0 +1,183 @@
///////////////////////////////////////////////////////////////////////////////////
// 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 <QJsonObject>
#include "aaroniartsaoutputsettings.h"
#include "aaroniartsaoutputworker.h"
AaroniaRTSAOutputWorker::AaroniaRTSAOutputWorker(SampleSourceFifo* sampleFifo, QObject* parent) :
QObject(parent),
m_running(false),
m_sampleFifo(sampleFifo),
m_sampleRate(100000),
m_packetsPerSecond(10),
m_samplesArrayInt16(nullptr)
{
m_samplesPerPacket = m_sampleRate / m_packetsPerSecond;
m_networkAccessManager = new QNetworkAccessManager(this);
m_timer = new QTimer(this);
m_timer->setTimerType(Qt::PreciseTimer);
m_centerFrequency = 145000000;
}
AaroniaRTSAOutputWorker::~AaroniaRTSAOutputWorker()
{
if (m_running) {
stopWork();
}
}
void AaroniaRTSAOutputWorker::startWork()
{
qDebug("aroniaRTSAOutputWorker::startWork");
m_samplesPerPacket = m_sampleRate / m_packetsPerSecond;
m_sampleResendTime = 1000 / (m_sampleRate / m_samplesPerPacket) ;
m_streamStartTime = ( QDateTime::currentDateTime().currentMSecsSinceEpoch() );
m_lastPacketEnd = m_streamStartTime / 1000.0;
m_sumSamples = 0;
connect(m_timer, SIGNAL(timeout()), this, SLOT(onGeneratePacket()));
qDebug("AaroniaRTSAOutputWorker::startWork: m_sampleResendTime: %f", m_sampleResendTime);
m_timer->start(m_sampleResendTime); //send period
m_running = true;
}
void AaroniaRTSAOutputWorker::stopWork()
{
qDebug("aroniaRTSAOutputWorker::stopWork");
m_running = false;
m_status = AaroniaRTSAOutputSettings::ConnectionIdle;
emit updateStatus(m_status);
disconnect(m_timer, SIGNAL(timeout()), this, SLOT(onGeneratePacket()));
m_timer->stop();
}
void AaroniaRTSAOutputWorker::setSampleRate(int sampleRate)
{
qDebug("aroniaRTSAOutputWorker::setSampleRate: %d", sampleRate);
if (sampleRate == m_sampleRate) {
return;
}
m_samplesPerPacket = sampleRate / m_packetsPerSecond;
m_sampleResendTime = 1000 / (sampleRate / m_samplesPerPacket) ;
m_timer->start(m_sampleResendTime); //send period
m_sampleRate = sampleRate;
}
void AaroniaRTSAOutputWorker::onGeneratePacket()
{
double sampleTimeUS = 1000000.0 / m_sampleRate;
qint64 deltaT = QDateTime::currentDateTime().currentMSecsSinceEpoch();
deltaT = deltaT - (m_lastPacketEnd*1000);
double ndiff = 1000*((double)deltaT + 1 ) / sampleTimeUS ;
double reawaketime = m_sampleResendTime - (sampleTimeUS*(ndiff - m_samplesPerPacket ))/1000 ;
// qDebug("AaroniaRTSAOutputWorker::onGeneratePacket: %f", reawaketime);
m_timer->setInterval( reawaketime );
double newStart = m_lastPacketEnd;
m_lastPacketEnd = newStart + ((m_samplesPerPacket + 1) * sampleTimeUS)/1000000 ;
double timeOffset = 0.4; //put it into future
buildSamples( newStart + timeOffset , m_lastPacketEnd + timeOffset);
}
void AaroniaRTSAOutputWorker::buildSamples(double startTime, double stopTime)
{
unsigned int iPart1Begin, iPart1End, iPart2Begin, iPart2End;
SampleVector& data = m_sampleFifo->getData();
m_sampleFifo->read(m_samplesPerPacket, iPart1Begin, iPart1End, iPart2Begin, iPart2End);
if (m_samplesArrayInt16 == nullptr) {
m_samplesArrayInt16 = new int16_t[2*m_samplesPerPacket];
}
if (iPart1Begin != iPart1End) {
callbackPart(m_samplesArrayInt16, data, iPart1Begin, iPart1End);
}
if (iPart2Begin != iPart2End) {
callbackPart(&m_samplesArrayInt16[(iPart1End - iPart1Begin)*2], data, iPart2Begin, iPart2End);
}
double startFrequency = m_centerFrequency - m_sampleRate/2;
double endFrequency = m_centerFrequency + m_sampleRate/2;
QJsonDocument jdoc(QJsonObject({
{"startTime", startTime },
{"endTime" , stopTime },
{"startFrequency", startFrequency },
{"endFrequency" , endFrequency },
{"minPower", -2},
{"maxPower" , 2},
{"sampleSize", 2},
{"sampleDepth" , 1},
{"payload", "iq"},
{"format", "int16"},
{"scale", 512.0},
{"unit" , "volt"},
{"samples" , 2*m_samplesPerPacket},
}));
postData(jdoc, m_samplesArrayInt16, 2*m_samplesPerPacket);
}
void AaroniaRTSAOutputWorker::callbackPart(int16_t *buf, SampleVector& data, unsigned int iBegin, unsigned int iEnd)
{
for (unsigned int j = 0, i = iBegin; i < iEnd; j++, i++)
{
buf[2*j] = data[i].m_real;
buf[2*j+1] = data[i].m_imag;
}
}
void AaroniaRTSAOutputWorker::postData(QJsonDocument jdoc, int16_t *samplesArray, int nSamples)
{
QUrl url(tr("http://%1/sample").arg(m_serverAddress));
qDebug() << "AaroniaRTSAOutputWorker::postData:" << url;
QNetworkRequest request(url);
request.setHeader(QNetworkRequest::ContentTypeHeader, QString("application/json"));
QByteArray byteArray = jdoc.toJson(QJsonDocument::Compact);
byteArray.append(0x1e);
byteArray.append(QByteArray::fromRawData(reinterpret_cast<char *>(samplesArray), nSamples*sizeof(int16_t)));
QNetworkReply *networkReply = m_networkAccessManager->post(request, byteArray);
connect(networkReply, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(onError(QNetworkReply::NetworkError)));
connect(m_networkAccessManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(onFinished(QNetworkReply*)));
}
void AaroniaRTSAOutputWorker::onError(QNetworkReply::NetworkError)
{
QNetworkReply* nReply = qobject_cast<QNetworkReply*>( sender() );
qDebug() << "AaroniaRTSAOutputWorker::onError: Network Error: " + nReply->errorString();
m_timer->stop();
m_status = AaroniaRTSAOutputSettings::ConnectionError;
emit updateStatus(m_status);
}
void AaroniaRTSAOutputWorker::onFinished(QNetworkReply *reply)
{
if ((m_status != AaroniaRTSAOutputSettings::ConnectionOK) && (reply->error() == QNetworkReply::NoError))
{
m_status = AaroniaRTSAOutputSettings::ConnectionOK;
emit updateStatus(m_status);
}
reply->deleteLater();
}

View File

@ -0,0 +1,88 @@
///////////////////////////////////////////////////////////////////////////////////
// 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_AARONIARTSAOUTPUTWORKER_H_
#define _AARONIARTSA_AARONIARTSAOUTPUTWORKER_H_
#include <QTimer>
#include "dsp/samplesourcefifo.h"
#include "util/message.h"
#include <QProcess>
#include <QNetworkAccessManager>
#include <QNetworkReply>
#include <QTimer>
#include <QJsonDocument>
#include <QObject>
#include "dsp/decimatorsfi.h"
class AaroniaRTSAOutputWorker : public QObject {
Q_OBJECT
public:
enum TxFormat {
FLOAT32,
INT16,
ASCII
};
AaroniaRTSAOutputWorker(SampleSourceFifo* sampleFifo, QObject* parent = nullptr);
~AaroniaRTSAOutputWorker();
void startWork();
void stopWork();
int getStatus() const { return m_status; }
void setServerAddress(const QString& serverAddress) { m_serverAddress = serverAddress; }
void setCenterFrequency(quint64 centerFrequency) { m_centerFrequency = centerFrequency; }
void setSampleRate(int sampleRate);
signals:
void updateStatus(int status);
private:
volatile bool m_running;
QTimer *m_timer;
SampleVector m_samplesBuf;
SampleSourceFifo* m_sampleFifo;
QString m_serverAddress;
quint64 m_centerFrequency;
int m_sampleRate;
int m_status; //!< See GUI for status number detail
QNetworkAccessManager *m_networkAccessManager;
int m_packetsPerSecond;
int m_samplesPerPacket;
TxFormat m_txFormat;
qint64 m_streamStartTime;
quint64 m_sumSamples;
long double m_lastPacketEnd;
double m_sampleResendTime;
int16_t *m_samplesArrayInt16;
void buildSamples(double startTime, double stopTime);
void callbackPart(int16_t *buf, SampleVector& data, unsigned int iBegin, unsigned int iEnd);
void postData(QJsonDocument jdoc, int16_t *samplesArray, int nSamples);
private slots:
void onGeneratePacket();
void onError(QNetworkReply::NetworkError code);
void onFinished(QNetworkReply *);
};
#endif // _AARONIARTSA_AARONIARTSAOUTPUTWORKER_H_

View File

@ -1,14 +1,28 @@
<h1>Local output plugin</h1> <h1>Aaronia RTSA output plugin</h1>
<h2>Introduction</h2> <h2>Introduction</h2>
This output sample sink plugin sends its samples to a Local Source channel in another device set. 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 followed by an `IQ Modulator` block.
An example flow graph could be the following (Stram Debugger is optional):
![Aaronia RTSA Tx flowgraph](../../../doc/img/aaronia_http_tx.jpg)
You have to check the "Adapt Center Frequency" and "Adapt Sample Rate" options in the IQ modulator settings so that SDRangel can control center frequency and sample rate:
![Aaronia RTSA Tx IQMod settings](../../../doc/img/aaronia_http_tx_iqmod.jpg)
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 perform the upsampling 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.
<h2>Interface</h2> <h2>Interface</h2>
The top and bottom bars of the device window are described [here](../../../sdrgui/device/readme.md) The top and bottom bars of the device window are described [here](../../../sdrgui/device/readme.md)
![SDR Local output plugin GUI](../../../doc/img/LocalOutput_plugin.png) ![Aaronia RTSA output plugin GUI](../../../doc/img/AaroniaRTSAOutput.png)
<h3>1: Start/Stop</h3> <h3>1: Start/Stop</h3>
@ -17,10 +31,34 @@ Device start / stop button.
- Blue triangle icon: device is ready and can be started - Blue triangle icon: device is ready and can be started
- Green square icon: device is running and can be stopped - Green square icon: device is running and can be stopped
<h3>2: Frequency</h3> <h3>2: Stream sample rate</h3>
This is the center frequency in Hz sent from the Local Source channel instance and corresponds to the center frequency of transmission. This is the sample rate of the I/Q stream sent to RTSA suite. It should be equal to the value set in (4)
<h3>3: Stream sample rate</h3> <h3>3: Frequency</h3>
Stream I/Q sample rate in kS/s This is the center frequency to which set the IQ modulator center frequency.
<h3>4: Stream sample rate</h3>
Sets the I/Q stream sample rate in S/s
<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:
* **Gray**: Idle
* **Yellow**: Unstable
* **Green**: Connected
* **Red**: Error
* **Magenta**: 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

@ -282,7 +282,7 @@ bool AaroniaRTSAInput::applySettings(const AaroniaRTSAInputSettings& settings, c
qDebug() << "AaroniaRTSAInput::applySettings: force: "<< force << settings.getDebugString(settingsKeys, force); qDebug() << "AaroniaRTSAInput::applySettings: force: "<< force << settings.getDebugString(settingsKeys, force);
if (settingsKeys.contains("serverAddress") || force) if (settingsKeys.contains("serverAddress") || force)
{ {
emit setWorkerServerAddress(settings.m_serverAddress); emit setWorkerServerAddress(settings.m_serverAddress);
} }
@ -412,7 +412,7 @@ int AaroniaRTSAInput::webapiReportGet(
QString& errorMessage) QString& errorMessage)
{ {
(void) errorMessage; (void) errorMessage;
response.setAaroniaSdrReport(new SWGSDRangel::SWGAaroniaRTSAReport()); response.setAaroniaRtsaReport(new SWGSDRangel::SWGAaroniaRTSAReport());
response.getAirspyHfReport()->init(); response.getAirspyHfReport()->init();
webapiFormatDeviceReport(response); webapiFormatDeviceReport(response);
return 200; return 200;
@ -443,7 +443,7 @@ void AaroniaRTSAInput::webapiFormatDeviceSettings(SWGSDRangel::SWGDeviceSettings
void AaroniaRTSAInput::webapiFormatDeviceReport(SWGSDRangel::SWGDeviceReport& response) void AaroniaRTSAInput::webapiFormatDeviceReport(SWGSDRangel::SWGDeviceReport& response)
{ {
response.getAaroniaSdrReport()->setStatus(getStatus()); response.getAaroniaRtsaReport()->setStatus(getStatus());
} }
void AaroniaRTSAInput::webapiReverseSendSettings(const QList<QString>& deviceSettingsKeys, const AaroniaRTSAInputSettings& settings, bool force) void AaroniaRTSAInput::webapiReverseSendSettings(const QList<QString>& deviceSettingsKeys, const AaroniaRTSAInputSettings& settings, bool force)

View File

@ -2100,18 +2100,28 @@ margin-bottom: 20px;
}; };
defs.AaroniaRTSAOutputReport = { defs.AaroniaRTSAOutputReport = {
"properties" : { "properties" : {
"centerFrequency" : { "status" : {
"type" : "integer", "type" : "integer",
"format" : "int64" "description" : "Connection to RTSA server status:\n * 0 - Idle\n * 1 - Unstable\n * 2 - Connected\n * 3 - Error\n * 4 - Disconnected\n"
},
"sampleRate" : {
"type" : "integer"
} }
}, },
"description" : "AaroniaRTSAOutput" "description" : "AaroniaRTSAOutput"
}; };
defs.AaroniaRTSAOutputSettings = { defs.AaroniaRTSAOutputSettings = {
"properties" : { "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" : { "useReverseAPI" : {
"type" : "integer", "type" : "integer",
"description" : "Synchronize with reverse API (1 for yes, 0 for no)" "description" : "Synchronize with reverse API (1 for yes, 0 for no)"
@ -2132,7 +2142,7 @@ margin-bottom: 20px;
"properties" : { "properties" : {
"status" : { "status" : {
"type" : "integer", "type" : "integer",
"description" : "0 for Idle, 1 for Connecting, 2 for Connected, 3 for Error, 4 for Disconnected" "description" : "Connection to RTSA server status:\n * 0 - Idle\n * 1 - Unstable\n * 2 - Connected\n * 3 - Error\n * 4 - Disconnected\n"
} }
}, },
"description" : "AaroniaRTSA" "description" : "AaroniaRTSA"
@ -5276,7 +5286,7 @@ margin-bottom: 20px;
"xtrxMIMOReport" : { "xtrxMIMOReport" : {
"$ref" : "#/definitions/XtrxMIMOReport" "$ref" : "#/definitions/XtrxMIMOReport"
}, },
"aaroniaSDRReport" : { "AaroniaRTSAReport" : {
"$ref" : "#/definitions/AaroniaRTSAReport" "$ref" : "#/definitions/AaroniaRTSAReport"
}, },
"aaroniaRTSAOutputReport" : { "aaroniaRTSAOutputReport" : {
@ -57561,7 +57571,7 @@ except ApiException as e:
</div> </div>
<div id="generator"> <div id="generator">
<div class="content"> <div class="content">
Generated 2023-04-10T20:01:50.318+02:00 Generated 2023-04-22T13:14:49.587+02:00
</div> </div>
</div> </div>
</div> </div>

View File

@ -25,12 +25,28 @@ AaroniaRTSAReport:
description: AaroniaRTSA description: AaroniaRTSA
properties: properties:
status: status:
description: 0 for Idle, 1 for Connecting, 2 for Connected, 3 for Error, 4 for Disconnected
type: integer type: integer
description: >
Connection to RTSA server status:
* 0 - Idle
* 1 - Unstable
* 2 - Connected
* 3 - Error
* 4 - Disconnected
AaroniaRTSAOutputSettings: AaroniaRTSAOutputSettings:
description: AaroniaRTSAOutput description: AaroniaRTSAOutput
properties: 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: useReverseAPI:
description: Synchronize with reverse API (1 for yes, 0 for no) description: Synchronize with reverse API (1 for yes, 0 for no)
type: integer type: integer
@ -44,8 +60,12 @@ AaroniaRTSAOutputSettings:
AaroniaRTSAOutputReport: AaroniaRTSAOutputReport:
description: AaroniaRTSAOutput description: AaroniaRTSAOutput
properties: properties:
centerFrequency: status:
type: integer
format: int64
sampleRate:
type: integer type: integer
description: >
Connection to RTSA server status:
* 0 - Idle
* 1 - Unstable
* 2 - Connected
* 3 - Error
* 4 - Disconnected

View File

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

View File

@ -50,7 +50,13 @@ GS232ControllerSettings:
type: number type: number
format: float format: float
protocol: protocol:
description: (0 GS-232, 1 SPID rot2prog) description: (0 GS-232, 1 SPID rot2prog, 2 rotcltd, 3 DFM)
type: integer
precision:
description: Precision of azimuth and elevation values
type: integer
coordinates:
description: (0 Az/El, 1 X/Y 85, 2 X/Y 30)
type: integer type: integer
title: title:
type: string type: string

View File

@ -25,12 +25,28 @@ AaroniaRTSAReport:
description: AaroniaRTSA description: AaroniaRTSA
properties: properties:
status: status:
description: 0 for Idle, 1 for Connecting, 2 for Connected, 3 for Error, 4 for Disconnected
type: integer type: integer
description: >
Connection to RTSA server status:
* 0 - Idle
* 1 - Unstable
* 2 - Connected
* 3 - Error
* 4 - Disconnected
AaroniaRTSAOutputSettings: AaroniaRTSAOutputSettings:
description: AaroniaRTSAOutput description: AaroniaRTSAOutput
properties: 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: useReverseAPI:
description: Synchronize with reverse API (1 for yes, 0 for no) description: Synchronize with reverse API (1 for yes, 0 for no)
type: integer type: integer
@ -44,8 +60,12 @@ AaroniaRTSAOutputSettings:
AaroniaRTSAOutputReport: AaroniaRTSAOutputReport:
description: AaroniaRTSAOutput description: AaroniaRTSAOutput
properties: properties:
centerFrequency: status:
type: integer
format: int64
sampleRate:
type: integer type: integer
description: >
Connection to RTSA server status:
* 0 - Idle
* 1 - Unstable
* 2 - Connected
* 3 - Error
* 4 - Disconnected

View File

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

View File

@ -2100,18 +2100,28 @@ margin-bottom: 20px;
}; };
defs.AaroniaRTSAOutputReport = { defs.AaroniaRTSAOutputReport = {
"properties" : { "properties" : {
"centerFrequency" : { "status" : {
"type" : "integer", "type" : "integer",
"format" : "int64" "description" : "Connection to RTSA server status:\n * 0 - Idle\n * 1 - Unstable\n * 2 - Connected\n * 3 - Error\n * 4 - Disconnected\n"
},
"sampleRate" : {
"type" : "integer"
} }
}, },
"description" : "AaroniaRTSAOutput" "description" : "AaroniaRTSAOutput"
}; };
defs.AaroniaRTSAOutputSettings = { defs.AaroniaRTSAOutputSettings = {
"properties" : { "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" : { "useReverseAPI" : {
"type" : "integer", "type" : "integer",
"description" : "Synchronize with reverse API (1 for yes, 0 for no)" "description" : "Synchronize with reverse API (1 for yes, 0 for no)"
@ -2132,7 +2142,7 @@ margin-bottom: 20px;
"properties" : { "properties" : {
"status" : { "status" : {
"type" : "integer", "type" : "integer",
"description" : "0 for Idle, 1 for Connecting, 2 for Connected, 3 for Error, 4 for Disconnected" "description" : "Connection to RTSA server status:\n * 0 - Idle\n * 1 - Unstable\n * 2 - Connected\n * 3 - Error\n * 4 - Disconnected\n"
} }
}, },
"description" : "AaroniaRTSA" "description" : "AaroniaRTSA"
@ -5276,7 +5286,7 @@ margin-bottom: 20px;
"xtrxMIMOReport" : { "xtrxMIMOReport" : {
"$ref" : "#/definitions/XtrxMIMOReport" "$ref" : "#/definitions/XtrxMIMOReport"
}, },
"aaroniaSDRReport" : { "AaroniaRTSAReport" : {
"$ref" : "#/definitions/AaroniaRTSAReport" "$ref" : "#/definitions/AaroniaRTSAReport"
}, },
"aaroniaRTSAOutputReport" : { "aaroniaRTSAOutputReport" : {
@ -57561,7 +57571,7 @@ except ApiException as e:
</div> </div>
<div id="generator"> <div id="generator">
<div class="content"> <div class="content">
Generated 2023-04-10T20:01:50.318+02:00 Generated 2023-04-22T13:14:49.587+02:00
</div> </div>
</div> </div>
</div> </div>

View File

@ -28,10 +28,8 @@ SWGAaroniaRTSAOutputReport::SWGAaroniaRTSAOutputReport(QString* json) {
} }
SWGAaroniaRTSAOutputReport::SWGAaroniaRTSAOutputReport() { SWGAaroniaRTSAOutputReport::SWGAaroniaRTSAOutputReport() {
center_frequency = 0L; status = 0;
m_center_frequency_isSet = false; m_status_isSet = false;
sample_rate = 0;
m_sample_rate_isSet = false;
} }
SWGAaroniaRTSAOutputReport::~SWGAaroniaRTSAOutputReport() { SWGAaroniaRTSAOutputReport::~SWGAaroniaRTSAOutputReport() {
@ -40,16 +38,13 @@ SWGAaroniaRTSAOutputReport::~SWGAaroniaRTSAOutputReport() {
void void
SWGAaroniaRTSAOutputReport::init() { SWGAaroniaRTSAOutputReport::init() {
center_frequency = 0L; status = 0;
m_center_frequency_isSet = false; m_status_isSet = false;
sample_rate = 0;
m_sample_rate_isSet = false;
} }
void void
SWGAaroniaRTSAOutputReport::cleanup() { SWGAaroniaRTSAOutputReport::cleanup() {
} }
SWGAaroniaRTSAOutputReport* SWGAaroniaRTSAOutputReport*
@ -63,9 +58,7 @@ SWGAaroniaRTSAOutputReport::fromJson(QString &json) {
void void
SWGAaroniaRTSAOutputReport::fromJsonObject(QJsonObject &pJson) { SWGAaroniaRTSAOutputReport::fromJsonObject(QJsonObject &pJson) {
::SWGSDRangel::setValue(&center_frequency, pJson["centerFrequency"], "qint64", ""); ::SWGSDRangel::setValue(&status, pJson["status"], "qint32", "");
::SWGSDRangel::setValue(&sample_rate, pJson["sampleRate"], "qint32", "");
} }
@ -83,34 +76,21 @@ SWGAaroniaRTSAOutputReport::asJson ()
QJsonObject* QJsonObject*
SWGAaroniaRTSAOutputReport::asJsonObject() { SWGAaroniaRTSAOutputReport::asJsonObject() {
QJsonObject* obj = new QJsonObject(); QJsonObject* obj = new QJsonObject();
if(m_center_frequency_isSet){ if(m_status_isSet){
obj->insert("centerFrequency", QJsonValue(center_frequency)); obj->insert("status", QJsonValue(status));
}
if(m_sample_rate_isSet){
obj->insert("sampleRate", QJsonValue(sample_rate));
} }
return obj; return obj;
} }
qint64
SWGAaroniaRTSAOutputReport::getCenterFrequency() {
return center_frequency;
}
void
SWGAaroniaRTSAOutputReport::setCenterFrequency(qint64 center_frequency) {
this->center_frequency = center_frequency;
this->m_center_frequency_isSet = true;
}
qint32 qint32
SWGAaroniaRTSAOutputReport::getSampleRate() { SWGAaroniaRTSAOutputReport::getStatus() {
return sample_rate; return status;
} }
void void
SWGAaroniaRTSAOutputReport::setSampleRate(qint32 sample_rate) { SWGAaroniaRTSAOutputReport::setStatus(qint32 status) {
this->sample_rate = sample_rate; this->status = status;
this->m_sample_rate_isSet = true; this->m_status_isSet = true;
} }
@ -118,10 +98,7 @@ bool
SWGAaroniaRTSAOutputReport::isSet(){ SWGAaroniaRTSAOutputReport::isSet(){
bool isObjectUpdated = false; bool isObjectUpdated = false;
do{ do{
if(m_center_frequency_isSet){ if(m_status_isSet){
isObjectUpdated = true; break;
}
if(m_sample_rate_isSet){
isObjectUpdated = true; break; isObjectUpdated = true; break;
} }
}while(false); }while(false);

View File

@ -41,21 +41,15 @@ public:
virtual void fromJsonObject(QJsonObject &json) override; virtual void fromJsonObject(QJsonObject &json) override;
virtual SWGAaroniaRTSAOutputReport* fromJson(QString &jsonString) override; virtual SWGAaroniaRTSAOutputReport* fromJson(QString &jsonString) override;
qint64 getCenterFrequency(); qint32 getStatus();
void setCenterFrequency(qint64 center_frequency); void setStatus(qint32 status);
qint32 getSampleRate();
void setSampleRate(qint32 sample_rate);
virtual bool isSet() override; virtual bool isSet() override;
private: private:
qint64 center_frequency; qint32 status;
bool m_center_frequency_isSet; bool m_status_isSet;
qint32 sample_rate;
bool m_sample_rate_isSet;
}; };

View File

@ -28,6 +28,12 @@ SWGAaroniaRTSAOutputSettings::SWGAaroniaRTSAOutputSettings(QString* json) {
} }
SWGAaroniaRTSAOutputSettings::SWGAaroniaRTSAOutputSettings() { SWGAaroniaRTSAOutputSettings::SWGAaroniaRTSAOutputSettings() {
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; use_reverse_api = 0;
m_use_reverse_api_isSet = false; m_use_reverse_api_isSet = false;
reverse_api_address = nullptr; reverse_api_address = nullptr;
@ -44,6 +50,12 @@ SWGAaroniaRTSAOutputSettings::~SWGAaroniaRTSAOutputSettings() {
void void
SWGAaroniaRTSAOutputSettings::init() { SWGAaroniaRTSAOutputSettings::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; use_reverse_api = 0;
m_use_reverse_api_isSet = false; m_use_reverse_api_isSet = false;
reverse_api_address = new QString(""); reverse_api_address = new QString("");
@ -57,6 +69,11 @@ SWGAaroniaRTSAOutputSettings::init() {
void void
SWGAaroniaRTSAOutputSettings::cleanup() { SWGAaroniaRTSAOutputSettings::cleanup() {
if(server_address != nullptr) {
delete server_address;
}
if(reverse_api_address != nullptr) { if(reverse_api_address != nullptr) {
delete reverse_api_address; delete reverse_api_address;
} }
@ -75,6 +92,12 @@ SWGAaroniaRTSAOutputSettings::fromJson(QString &json) {
void void
SWGAaroniaRTSAOutputSettings::fromJsonObject(QJsonObject &pJson) { SWGAaroniaRTSAOutputSettings::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(&use_reverse_api, pJson["useReverseAPI"], "qint32", "");
::SWGSDRangel::setValue(&reverse_api_address, pJson["reverseAPIAddress"], "QString", "QString"); ::SWGSDRangel::setValue(&reverse_api_address, pJson["reverseAPIAddress"], "QString", "QString");
@ -99,6 +122,15 @@ SWGAaroniaRTSAOutputSettings::asJson ()
QJsonObject* QJsonObject*
SWGAaroniaRTSAOutputSettings::asJsonObject() { SWGAaroniaRTSAOutputSettings::asJsonObject() {
QJsonObject* obj = new QJsonObject(); 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){ if(m_use_reverse_api_isSet){
obj->insert("useReverseAPI", QJsonValue(use_reverse_api)); obj->insert("useReverseAPI", QJsonValue(use_reverse_api));
} }
@ -115,6 +147,36 @@ SWGAaroniaRTSAOutputSettings::asJsonObject() {
return obj; return obj;
} }
qint64
SWGAaroniaRTSAOutputSettings::getCenterFrequency() {
return center_frequency;
}
void
SWGAaroniaRTSAOutputSettings::setCenterFrequency(qint64 center_frequency) {
this->center_frequency = center_frequency;
this->m_center_frequency_isSet = true;
}
qint32
SWGAaroniaRTSAOutputSettings::getSampleRate() {
return sample_rate;
}
void
SWGAaroniaRTSAOutputSettings::setSampleRate(qint32 sample_rate) {
this->sample_rate = sample_rate;
this->m_sample_rate_isSet = true;
}
QString*
SWGAaroniaRTSAOutputSettings::getServerAddress() {
return server_address;
}
void
SWGAaroniaRTSAOutputSettings::setServerAddress(QString* server_address) {
this->server_address = server_address;
this->m_server_address_isSet = true;
}
qint32 qint32
SWGAaroniaRTSAOutputSettings::getUseReverseApi() { SWGAaroniaRTSAOutputSettings::getUseReverseApi() {
return use_reverse_api; return use_reverse_api;
@ -160,6 +222,15 @@ bool
SWGAaroniaRTSAOutputSettings::isSet(){ SWGAaroniaRTSAOutputSettings::isSet(){
bool isObjectUpdated = false; bool isObjectUpdated = false;
do{ 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){ if(m_use_reverse_api_isSet){
isObjectUpdated = true; break; isObjectUpdated = true; break;
} }

View File

@ -42,6 +42,15 @@ public:
virtual void fromJsonObject(QJsonObject &json) override; virtual void fromJsonObject(QJsonObject &json) override;
virtual SWGAaroniaRTSAOutputSettings* fromJson(QString &jsonString) override; virtual SWGAaroniaRTSAOutputSettings* 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(); qint32 getUseReverseApi();
void setUseReverseApi(qint32 use_reverse_api); void setUseReverseApi(qint32 use_reverse_api);
@ -58,6 +67,15 @@ public:
virtual bool isSet() override; virtual bool isSet() override;
private: 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; qint32 use_reverse_api;
bool m_use_reverse_api_isSet; bool m_use_reverse_api_isSet;

View File

@ -92,8 +92,8 @@ SWGDeviceReport::SWGDeviceReport() {
m_xtrx_output_report_isSet = false; m_xtrx_output_report_isSet = false;
xtrx_mimo_report = nullptr; xtrx_mimo_report = nullptr;
m_xtrx_mimo_report_isSet = false; m_xtrx_mimo_report_isSet = false;
aaronia_sdr_report = nullptr; aaronia_rtsa_report = nullptr;
m_aaronia_sdr_report_isSet = false; m_aaronia_rtsa_report_isSet = false;
aaronia_rtsa_output_report = nullptr; aaronia_rtsa_output_report = nullptr;
m_aaronia_rtsa_output_report_isSet = false; m_aaronia_rtsa_output_report_isSet = false;
} }
@ -168,8 +168,8 @@ SWGDeviceReport::init() {
m_xtrx_output_report_isSet = false; m_xtrx_output_report_isSet = false;
xtrx_mimo_report = new SWGXtrxMIMOReport(); xtrx_mimo_report = new SWGXtrxMIMOReport();
m_xtrx_mimo_report_isSet = false; m_xtrx_mimo_report_isSet = false;
aaronia_sdr_report = new SWGAaroniaRTSAReport(); aaronia_rtsa_report = new SWGAaroniaRTSAReport();
m_aaronia_sdr_report_isSet = false; m_aaronia_rtsa_report_isSet = false;
aaronia_rtsa_output_report = new SWGAaroniaRTSAOutputReport(); aaronia_rtsa_output_report = new SWGAaroniaRTSAOutputReport();
m_aaronia_rtsa_output_report_isSet = false; m_aaronia_rtsa_output_report_isSet = false;
} }
@ -270,8 +270,8 @@ SWGDeviceReport::cleanup() {
if(xtrx_mimo_report != nullptr) { if(xtrx_mimo_report != nullptr) {
delete xtrx_mimo_report; delete xtrx_mimo_report;
} }
if(aaronia_sdr_report != nullptr) { if(aaronia_rtsa_report != nullptr) {
delete aaronia_sdr_report; delete aaronia_rtsa_report;
} }
if(aaronia_rtsa_output_report != nullptr) { if(aaronia_rtsa_output_report != nullptr) {
delete aaronia_rtsa_output_report; delete aaronia_rtsa_output_report;
@ -353,7 +353,7 @@ SWGDeviceReport::fromJsonObject(QJsonObject &pJson) {
::SWGSDRangel::setValue(&xtrx_mimo_report, pJson["xtrxMIMOReport"], "SWGXtrxMIMOReport", "SWGXtrxMIMOReport"); ::SWGSDRangel::setValue(&xtrx_mimo_report, pJson["xtrxMIMOReport"], "SWGXtrxMIMOReport", "SWGXtrxMIMOReport");
::SWGSDRangel::setValue(&aaronia_sdr_report, pJson["aaroniaSDRReport"], "SWGAaroniaRTSAReport", "SWGAaroniaRTSAReport"); ::SWGSDRangel::setValue(&aaronia_rtsa_report, pJson["AaroniaRTSAReport"], "SWGAaroniaRTSAReport", "SWGAaroniaRTSAReport");
::SWGSDRangel::setValue(&aaronia_rtsa_output_report, pJson["aaroniaRTSAOutputReport"], "SWGAaroniaRTSAOutputReport", "SWGAaroniaRTSAOutputReport"); ::SWGSDRangel::setValue(&aaronia_rtsa_output_report, pJson["aaroniaRTSAOutputReport"], "SWGAaroniaRTSAOutputReport", "SWGAaroniaRTSAOutputReport");
@ -469,8 +469,8 @@ SWGDeviceReport::asJsonObject() {
if((xtrx_mimo_report != nullptr) && (xtrx_mimo_report->isSet())){ if((xtrx_mimo_report != nullptr) && (xtrx_mimo_report->isSet())){
toJsonValue(QString("xtrxMIMOReport"), xtrx_mimo_report, obj, QString("SWGXtrxMIMOReport")); toJsonValue(QString("xtrxMIMOReport"), xtrx_mimo_report, obj, QString("SWGXtrxMIMOReport"));
} }
if((aaronia_sdr_report != nullptr) && (aaronia_sdr_report->isSet())){ if((aaronia_rtsa_report != nullptr) && (aaronia_rtsa_report->isSet())){
toJsonValue(QString("aaroniaSDRReport"), aaronia_sdr_report, obj, QString("SWGAaroniaRTSAReport")); toJsonValue(QString("AaroniaRTSAReport"), aaronia_rtsa_report, obj, QString("SWGAaroniaRTSAReport"));
} }
if((aaronia_rtsa_output_report != nullptr) && (aaronia_rtsa_output_report->isSet())){ if((aaronia_rtsa_output_report != nullptr) && (aaronia_rtsa_output_report->isSet())){
toJsonValue(QString("aaroniaRTSAOutputReport"), aaronia_rtsa_output_report, obj, QString("SWGAaroniaRTSAOutputReport")); toJsonValue(QString("aaroniaRTSAOutputReport"), aaronia_rtsa_output_report, obj, QString("SWGAaroniaRTSAOutputReport"));
@ -800,13 +800,13 @@ SWGDeviceReport::setXtrxMimoReport(SWGXtrxMIMOReport* xtrx_mimo_report) {
} }
SWGAaroniaRTSAReport* SWGAaroniaRTSAReport*
SWGDeviceReport::getAaroniaSdrReport() { SWGDeviceReport::getAaroniaRtsaReport() {
return aaronia_sdr_report; return aaronia_rtsa_report;
} }
void void
SWGDeviceReport::setAaroniaSdrReport(SWGAaroniaRTSAReport* aaronia_sdr_report) { SWGDeviceReport::setAaroniaRtsaReport(SWGAaroniaRTSAReport* aaronia_rtsa_report) {
this->aaronia_sdr_report = aaronia_sdr_report; this->aaronia_rtsa_report = aaronia_rtsa_report;
this->m_aaronia_sdr_report_isSet = true; this->m_aaronia_rtsa_report_isSet = true;
} }
SWGAaroniaRTSAOutputReport* SWGAaroniaRTSAOutputReport*
@ -920,7 +920,7 @@ SWGDeviceReport::isSet(){
if(xtrx_mimo_report && xtrx_mimo_report->isSet()){ if(xtrx_mimo_report && xtrx_mimo_report->isSet()){
isObjectUpdated = true; break; isObjectUpdated = true; break;
} }
if(aaronia_sdr_report && aaronia_sdr_report->isSet()){ if(aaronia_rtsa_report && aaronia_rtsa_report->isSet()){
isObjectUpdated = true; break; isObjectUpdated = true; break;
} }
if(aaronia_rtsa_output_report && aaronia_rtsa_output_report->isSet()){ if(aaronia_rtsa_output_report && aaronia_rtsa_output_report->isSet()){

View File

@ -169,8 +169,8 @@ public:
SWGXtrxMIMOReport* getXtrxMimoReport(); SWGXtrxMIMOReport* getXtrxMimoReport();
void setXtrxMimoReport(SWGXtrxMIMOReport* xtrx_mimo_report); void setXtrxMimoReport(SWGXtrxMIMOReport* xtrx_mimo_report);
SWGAaroniaRTSAReport* getAaroniaSdrReport(); SWGAaroniaRTSAReport* getAaroniaRtsaReport();
void setAaroniaSdrReport(SWGAaroniaRTSAReport* aaronia_sdr_report); void setAaroniaRtsaReport(SWGAaroniaRTSAReport* aaronia_rtsa_report);
SWGAaroniaRTSAOutputReport* getAaroniaRtsaOutputReport(); SWGAaroniaRTSAOutputReport* getAaroniaRtsaOutputReport();
void setAaroniaRtsaOutputReport(SWGAaroniaRTSAOutputReport* aaronia_rtsa_output_report); void setAaroniaRtsaOutputReport(SWGAaroniaRTSAOutputReport* aaronia_rtsa_output_report);
@ -275,8 +275,8 @@ private:
SWGXtrxMIMOReport* xtrx_mimo_report; SWGXtrxMIMOReport* xtrx_mimo_report;
bool m_xtrx_mimo_report_isSet; bool m_xtrx_mimo_report_isSet;
SWGAaroniaRTSAReport* aaronia_sdr_report; SWGAaroniaRTSAReport* aaronia_rtsa_report;
bool m_aaronia_sdr_report_isSet; bool m_aaronia_rtsa_report_isSet;
SWGAaroniaRTSAOutputReport* aaronia_rtsa_output_report; SWGAaroniaRTSAOutputReport* aaronia_rtsa_output_report;
bool m_aaronia_rtsa_output_report_isSet; bool m_aaronia_rtsa_output_report_isSet;