From 300c428f8c706e6c4964b41b2977f124798e8606 Mon Sep 17 00:00:00 2001 From: Jon Beniston Date: Wed, 7 Apr 2021 20:25:12 +0100 Subject: [PATCH] Add PER tester feature --- doc/img/PERTester_plugin.png | Bin 0 -> 14916 bytes plugins/feature/CMakeLists.txt | 1 + plugins/feature/pertester/CMakeLists.txt | 57 ++ plugins/feature/pertester/pertester.cpp | 556 +++++++++++++++++ plugins/feature/pertester/pertester.h | 178 ++++++ plugins/feature/pertester/pertestergui.cpp | 349 +++++++++++ plugins/feature/pertester/pertestergui.h | 91 +++ plugins/feature/pertester/pertestergui.ui | 576 ++++++++++++++++++ .../pertester/pertestergui.ui.autosave | 576 ++++++++++++++++++ plugins/feature/pertester/pertesterplugin.cpp | 80 +++ plugins/feature/pertester/pertesterplugin.h | 49 ++ plugins/feature/pertester/pertesterreport.h | 63 ++ .../feature/pertester/pertestersettings.cpp | 159 +++++ plugins/feature/pertester/pertestersettings.h | 60 ++ .../pertester/pertesterwebapiadapter.cpp | 52 ++ .../pertester/pertesterwebapiadapter.h | 50 ++ plugins/feature/pertester/pertesterworker.cpp | 321 ++++++++++ plugins/feature/pertester/pertesterworker.h | 98 +++ plugins/feature/pertester/readme.md | 103 ++++ sdrbase/webapi/webapirequestmapper.cpp | 6 + sdrbase/webapi/webapiutils.cpp | 2 + .../api/swagger/include/FeatureActions.yaml | 2 + .../api/swagger/include/FeatureSettings.yaml | 2 + .../api/swagger/include/PERTester.yaml | 67 ++ swagger/sdrangel/code/html2/index.html | 209 +++++-- .../code/qt5/client/SWGFeatureActions.cpp | 25 + .../code/qt5/client/SWGFeatureActions.h | 7 + .../code/qt5/client/SWGFeatureSettings.cpp | 25 + .../code/qt5/client/SWGFeatureSettings.h | 7 + .../code/qt5/client/SWGModelFactory.h | 12 + .../code/qt5/client/SWGPERTesterActions.cpp | 110 ++++ .../code/qt5/client/SWGPERTesterActions.h | 59 ++ .../qt5/client/SWGPERTesterActions_aos.cpp | 160 +++++ .../code/qt5/client/SWGPERTesterActions_aos.h | 71 +++ .../code/qt5/client/SWGPERTesterSettings.cpp | 515 ++++++++++++++++ .../code/qt5/client/SWGPERTesterSettings.h | 162 +++++ 36 files changed, 4812 insertions(+), 48 deletions(-) create mode 100644 doc/img/PERTester_plugin.png create mode 100644 plugins/feature/pertester/CMakeLists.txt create mode 100644 plugins/feature/pertester/pertester.cpp create mode 100644 plugins/feature/pertester/pertester.h create mode 100644 plugins/feature/pertester/pertestergui.cpp create mode 100644 plugins/feature/pertester/pertestergui.h create mode 100644 plugins/feature/pertester/pertestergui.ui create mode 100644 plugins/feature/pertester/pertestergui.ui.autosave create mode 100644 plugins/feature/pertester/pertesterplugin.cpp create mode 100644 plugins/feature/pertester/pertesterplugin.h create mode 100644 plugins/feature/pertester/pertesterreport.h create mode 100644 plugins/feature/pertester/pertestersettings.cpp create mode 100644 plugins/feature/pertester/pertestersettings.h create mode 100644 plugins/feature/pertester/pertesterwebapiadapter.cpp create mode 100644 plugins/feature/pertester/pertesterwebapiadapter.h create mode 100644 plugins/feature/pertester/pertesterworker.cpp create mode 100644 plugins/feature/pertester/pertesterworker.h create mode 100644 plugins/feature/pertester/readme.md create mode 100644 swagger/sdrangel/api/swagger/include/PERTester.yaml create mode 100644 swagger/sdrangel/code/qt5/client/SWGPERTesterActions.cpp create mode 100644 swagger/sdrangel/code/qt5/client/SWGPERTesterActions.h create mode 100644 swagger/sdrangel/code/qt5/client/SWGPERTesterActions_aos.cpp create mode 100644 swagger/sdrangel/code/qt5/client/SWGPERTesterActions_aos.h create mode 100644 swagger/sdrangel/code/qt5/client/SWGPERTesterSettings.cpp create mode 100644 swagger/sdrangel/code/qt5/client/SWGPERTesterSettings.h diff --git a/doc/img/PERTester_plugin.png b/doc/img/PERTester_plugin.png new file mode 100644 index 0000000000000000000000000000000000000000..7865dc54172cd3b59d562e69ed83826e93f38a8d GIT binary patch literal 14916 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 literal 0 HcmV?d00001 diff --git a/plugins/feature/CMakeLists.txt b/plugins/feature/CMakeLists.txt index df3ba354d..2e95e860d 100644 --- a/plugins/feature/CMakeLists.txt +++ b/plugins/feature/CMakeLists.txt @@ -14,6 +14,7 @@ endif() add_subdirectory(afc) add_subdirectory(aprs) add_subdirectory(demodanalyzer) +add_subdirectory(pertester) add_subdirectory(rigctlserver) add_subdirectory(simpleptt) if (SGP4_FOUND) diff --git a/plugins/feature/pertester/CMakeLists.txt b/plugins/feature/pertester/CMakeLists.txt new file mode 100644 index 000000000..3546ef793 --- /dev/null +++ b/plugins/feature/pertester/CMakeLists.txt @@ -0,0 +1,57 @@ +project(pertester) + +set(pertester_SOURCES + pertester.cpp + pertestersettings.cpp + pertesterplugin.cpp + pertesterworker.cpp + pertesterwebapiadapter.cpp +) + +set(pertester_HEADERS + pertester.h + pertestersettings.h + pertesterplugin.h + pertesterreport.h + pertesterworker.h + pertesterwebapiadapter.h +) + +include_directories( + ${CMAKE_SOURCE_DIR}/swagger/sdrangel/code/qt5/client +) + +if(NOT SERVER_MODE) + set(pertester_SOURCES + ${pertester_SOURCES} + pertestergui.cpp + pertestergui.ui + ) + set(pertester_HEADERS + ${pertester_HEADERS} + pertestergui.h + ) + + set(TARGET_NAME featurepertester) + set(TARGET_LIB Qt5::Widgets) + set(TARGET_LIB_GUI "sdrgui") + set(INSTALL_FOLDER ${INSTALL_PLUGINS_DIR}) +else() + set(TARGET_NAME featurepertestersrv) + set(TARGET_LIB "") + set(TARGET_LIB_GUI "") + set(INSTALL_FOLDER ${INSTALL_PLUGINSSRV_DIR}) +endif() + +add_library(${TARGET_NAME} SHARED + ${pertester_SOURCES} +) + +target_link_libraries(${TARGET_NAME} + Qt5::Core + ${TARGET_LIB} + sdrbase + ${TARGET_LIB_GUI} +) + +install(TARGETS ${TARGET_NAME} DESTINATION ${INSTALL_FOLDER}) diff --git a/plugins/feature/pertester/pertester.cpp b/plugins/feature/pertester/pertester.cpp new file mode 100644 index 000000000..e6e38fec7 --- /dev/null +++ b/plugins/feature/pertester/pertester.cpp @@ -0,0 +1,556 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2020 Jon Beniston, M7RCE // +// Copyright (C) 2020 Edouard Griffiths, F4EXB // +// // +// This program is free software; you can redistribute it and/or modify // +// it under the terms of the GNU General Public License as published by // +// the Free Software Foundation as version 3 of the License, or // +// (at your option) any later version. // +// // +// This program is distributed in the hope that it will be useful, // +// but WITHOUT ANY WARRANTY; without even the implied warranty of // +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // +// GNU General Public License V3 for more details. // +// // +// You should have received a copy of the GNU General Public License // +// along with this program. If not, see . // +/////////////////////////////////////////////////////////////////////////////////// + +#include +#include +#include +#include +#include + +#include "SWGFeatureSettings.h" +#include "SWGFeatureReport.h" +#include "SWGFeatureActions.h" +#include "SWGDeviceState.h" +#include "SWGPERTesterActions.h" + +#include "dsp/dspengine.h" +#include "device/deviceset.h" +#include "channel/channelapi.h" +#include "feature/featureset.h" +#include "maincore.h" + +#include "pertester.h" +#include "pertesterworker.h" +#include "pertesterreport.h" + +MESSAGE_CLASS_DEFINITION(PERTester::MsgConfigurePERTester, Message) +MESSAGE_CLASS_DEFINITION(PERTester::MsgStartStop, Message) +MESSAGE_CLASS_DEFINITION(PERTester::MsgResetStats, Message) +MESSAGE_CLASS_DEFINITION(PERTester::MsgReportWorker, Message) + +const char* const PERTester::m_featureIdURI = "sdrangel.feature.pertester"; +const char* const PERTester::m_featureId = "PERTester"; + +PERTester::PERTester(WebAPIAdapterInterface *webAPIAdapterInterface) : + Feature(m_featureIdURI, webAPIAdapterInterface) +{ + qDebug("PERTester::PERTester: webAPIAdapterInterface: %p", webAPIAdapterInterface); + setObjectName(m_featureId); + m_worker = new PERTesterWorker(); + m_state = StIdle; + m_errorMessage = "PERTester error"; + m_networkManager = new QNetworkAccessManager(); + connect(m_networkManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(networkManagerFinished(QNetworkReply*))); +} + +PERTester::~PERTester() +{ + disconnect(m_networkManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(networkManagerFinished(QNetworkReply*))); + delete m_networkManager; + if (m_worker->isRunning()) { + stop(); + } + + delete m_worker; +} + +void PERTester::start() +{ + qDebug("PERTester::start"); + + m_worker->setMessageQueueToFeature(getInputMessageQueue()); + m_worker->setMessageQueueToGUI(getMessageQueueToGUI()); + m_worker->getInputMessageQueue()->push(PERTesterWorker::MsgConfigurePERTesterWorker::create(m_settings, true)); + if (m_settings.m_start == PERTesterSettings::START_IMMEDIATELY) + { + bool ok = m_worker->startWork(); + m_state = ok ? StRunning : StError; + } + else + { + // Wait for AOS + m_state = StIdle; + } + m_thread.start(); +} + +void PERTester::stop() +{ + qDebug("PERTester::stop"); + m_worker->stopWork(); + m_state = StIdle; + m_thread.quit(); + m_thread.wait(); +} + +bool PERTester::handleMessage(const Message& cmd) +{ + if (MsgConfigurePERTester::match(cmd)) + { + MsgConfigurePERTester& cfg = (MsgConfigurePERTester&) cmd; + qDebug() << "PERTester::handleMessage: MsgConfigurePERTester"; + applySettings(cfg.getSettings(), cfg.getForce()); + + return true; + } + else if (MsgStartStop::match(cmd)) + { + MsgStartStop& cfg = (MsgStartStop&) cmd; + qDebug() << "PERTester::handleMessage: MsgStartStop: start:" << cfg.getStartStop(); + + if (cfg.getStartStop()) { + start(); + } else { + stop(); + } + + return true; + } + else if (MsgResetStats::match(cmd)) + { + m_worker->getInputMessageQueue()->push(MsgResetStats::create()); + return true; + } + else if (MsgReportWorker::match(cmd)) + { + MsgReportWorker& report = (MsgReportWorker&) cmd; + if (report.getMessage() == "Complete") + m_state = StIdle; + else + { + m_state = StError; + m_errorMessage = report.getMessage(); + } + return true; + } + else + { + return false; + } +} + +QByteArray PERTester::serialize() const +{ + return m_settings.serialize(); +} + +bool PERTester::deserialize(const QByteArray& data) +{ + if (m_settings.deserialize(data)) + { + MsgConfigurePERTester *msg = MsgConfigurePERTester::create(m_settings, true); + m_inputMessageQueue.push(msg); + return true; + } + else + { + m_settings.resetToDefaults(); + MsgConfigurePERTester *msg = MsgConfigurePERTester::create(m_settings, true); + m_inputMessageQueue.push(msg); + return false; + } +} + +void PERTester::applySettings(const PERTesterSettings& settings, bool force) +{ + qDebug() << "PERTester::applySettings:" + << " m_packetCount: " << settings.m_packetCount + << " m_interval: " << settings.m_interval + << " m_start: " << settings.m_start + << " m_satellites: " << settings.m_satellites + << " m_packet: " << settings.m_packet + << " m_ignoreLeadingBytes: " << settings.m_ignoreLeadingBytes + << " m_ignoreTrailingBytes: " << settings.m_ignoreTrailingBytes + << " m_txUDPAddress: " << settings.m_txUDPAddress + << " m_txUDPPort: " << settings.m_txUDPPort + << " m_rxUDPAddress: " << settings.m_rxUDPAddress + << " m_rxUDPPort: " << settings.m_rxUDPPort + << " m_title: " << settings.m_title + << " m_rgbColor: " << settings.m_rgbColor + << " m_useReverseAPI: " << settings.m_useReverseAPI + << " m_reverseAPIAddress: " << settings.m_reverseAPIAddress + << " m_reverseAPIPort: " << settings.m_reverseAPIPort + << " m_reverseAPIFeatureSetIndex: " << settings.m_reverseAPIFeatureSetIndex + << " m_reverseAPIFeatureIndex: " << settings.m_reverseAPIFeatureIndex + << " force: " << force; + + QList reverseAPIKeys; + + if ((m_settings.m_packetCount != settings.m_packetCount) || force) { + reverseAPIKeys.append("packetCount"); + } + if ((m_settings.m_interval != settings.m_interval) || force) { + reverseAPIKeys.append("interval"); + } + if ((m_settings.m_start != settings.m_start) || force) { + reverseAPIKeys.append("start"); + } + if ((m_settings.m_satellites != settings.m_satellites) || force) { + reverseAPIKeys.append("satellites"); + } + if ((m_settings.m_packet != settings.m_packet) || force) { + reverseAPIKeys.append("packet"); + } + if ((m_settings.m_ignoreLeadingBytes != settings.m_ignoreLeadingBytes) || force) { + reverseAPIKeys.append("ignoreLeadingBytes"); + } + if ((m_settings.m_ignoreTrailingBytes != settings.m_ignoreTrailingBytes) || force) { + reverseAPIKeys.append("ignoreTrailingBytes"); + } + if ((m_settings.m_txUDPAddress != settings.m_txUDPAddress) || force) { + reverseAPIKeys.append("txUDPAddress"); + } + if ((m_settings.m_txUDPPort != settings.m_txUDPPort) || force) { + reverseAPIKeys.append("txUDPPort"); + } + if ((m_settings.m_rxUDPAddress != settings.m_rxUDPAddress) || force) { + reverseAPIKeys.append("rxUDPAddress"); + } + if ((m_settings.m_rxUDPPort != settings.m_rxUDPPort) || force) { + reverseAPIKeys.append("rxUDPPort"); + } + + if ((m_settings.m_title != settings.m_title) || force) { + reverseAPIKeys.append("title"); + } + if ((m_settings.m_rgbColor != settings.m_rgbColor) || force) { + reverseAPIKeys.append("rgbColor"); + } + + PERTesterWorker::MsgConfigurePERTesterWorker *msg = PERTesterWorker::MsgConfigurePERTesterWorker::create( + settings, force + ); + m_worker->getInputMessageQueue()->push(msg); + + if (settings.m_useReverseAPI) + { + bool fullUpdate = ((m_settings.m_useReverseAPI != settings.m_useReverseAPI) && settings.m_useReverseAPI) || + (m_settings.m_reverseAPIAddress != settings.m_reverseAPIAddress) || + (m_settings.m_reverseAPIPort != settings.m_reverseAPIPort) || + (m_settings.m_reverseAPIFeatureSetIndex != settings.m_reverseAPIFeatureSetIndex) || + (m_settings.m_reverseAPIFeatureIndex != settings.m_reverseAPIFeatureIndex); + webapiReverseSendSettings(reverseAPIKeys, settings, fullUpdate || force); + } + + m_settings = settings; +} + +int PERTester::webapiRun(bool run, + SWGSDRangel::SWGDeviceState& response, + QString& errorMessage) +{ + (void) errorMessage; + getFeatureStateStr(*response.getState()); + MsgStartStop *msg = MsgStartStop::create(run); + getInputMessageQueue()->push(msg); + return 202; +} + +int PERTester::webapiSettingsGet( + SWGSDRangel::SWGFeatureSettings& response, + QString& errorMessage) +{ + (void) errorMessage; + response.setPerTesterSettings(new SWGSDRangel::SWGPERTesterSettings()); + response.getPerTesterSettings()->init(); + webapiFormatFeatureSettings(response, m_settings); + return 200; +} + +int PERTester::webapiSettingsPutPatch( + bool force, + const QStringList& featureSettingsKeys, + SWGSDRangel::SWGFeatureSettings& response, + QString& errorMessage) +{ + (void) errorMessage; + PERTesterSettings settings = m_settings; + webapiUpdateFeatureSettings(settings, featureSettingsKeys, response); + + MsgConfigurePERTester *msg = MsgConfigurePERTester::create(settings, force); + m_inputMessageQueue.push(msg); + + if (m_guiMessageQueue) // forward to GUI if any + { + MsgConfigurePERTester *msgToGUI = MsgConfigurePERTester::create(settings, force); + m_guiMessageQueue->push(msgToGUI); + } + + webapiFormatFeatureSettings(response, settings); + + return 200; +} + +static QList *convertStringListToPtrs(QStringList listIn) +{ + QList *listOut = new QList(); + + for (int i = 0; i < listIn.size(); i++) + listOut->append(new QString(listIn[i])); + + return listOut; +} + +static QStringList convertPtrsToStringList(QList *listIn) +{ + QStringList listOut; + + for (int i = 0; i < listIn->size(); i++) + listOut.append(*listIn->at(i)); + + return listOut; +} + +void PERTester::webapiFormatFeatureSettings( + SWGSDRangel::SWGFeatureSettings& response, + const PERTesterSettings& settings) +{ + response.getPerTesterSettings()->setPacketCount(settings.m_packetCount); + response.getPerTesterSettings()->setInterval(settings.m_interval); + response.getPerTesterSettings()->setStart((int)settings.m_start); + response.getPerTesterSettings()->setSatellites(convertStringListToPtrs(settings.m_satellites)); + response.getPerTesterSettings()->setPacket(new QString(settings.m_packet)); + response.getPerTesterSettings()->setIgnoreLeadingBytes(settings.m_ignoreLeadingBytes); + response.getPerTesterSettings()->setIgnoreTrailingBytes(settings.m_ignoreTrailingBytes); + response.getPerTesterSettings()->setTxUdpAddress(new QString(settings.m_txUDPAddress)); + response.getPerTesterSettings()->setTxUdpPort(settings.m_txUDPPort); + response.getPerTesterSettings()->setRxUdpAddress(new QString(settings.m_rxUDPAddress)); + response.getPerTesterSettings()->setRxUdpPort(settings.m_rxUDPPort); + + if (response.getPerTesterSettings()->getTitle()) { + *response.getPerTesterSettings()->getTitle() = settings.m_title; + } else { + response.getPerTesterSettings()->setTitle(new QString(settings.m_title)); + } + + response.getPerTesterSettings()->setRgbColor(settings.m_rgbColor); + response.getPerTesterSettings()->setUseReverseApi(settings.m_useReverseAPI ? 1 : 0); + + if (response.getPerTesterSettings()->getReverseApiAddress()) { + *response.getPerTesterSettings()->getReverseApiAddress() = settings.m_reverseAPIAddress; + } else { + response.getPerTesterSettings()->setReverseApiAddress(new QString(settings.m_reverseAPIAddress)); + } + + response.getPerTesterSettings()->setReverseApiPort(settings.m_reverseAPIPort); +} + +void PERTester::webapiUpdateFeatureSettings( + PERTesterSettings& settings, + const QStringList& featureSettingsKeys, + SWGSDRangel::SWGFeatureSettings& response) +{ + if (featureSettingsKeys.contains("packetCount")) { + settings.m_packetCount = response.getPerTesterSettings()->getPacketCount(); + } + if (featureSettingsKeys.contains("interval")) { + settings.m_interval = response.getPerTesterSettings()->getInterval(); + } + if (featureSettingsKeys.contains("start")) { + settings.m_start = (PERTesterSettings::Start)response.getPerTesterSettings()->getStart(); + } + if (featureSettingsKeys.contains("satellites")) { + settings.m_satellites = convertPtrsToStringList(response.getPerTesterSettings()->getSatellites()); + } + if (featureSettingsKeys.contains("packet")) { + settings.m_packet = *response.getPerTesterSettings()->getPacket(); + } + if (featureSettingsKeys.contains("ignoreLeadingBytes")) { + settings.m_ignoreLeadingBytes = response.getPerTesterSettings()->getIgnoreLeadingBytes(); + } + if (featureSettingsKeys.contains("ignoreTrailingBytes")) { + settings.m_ignoreTrailingBytes = response.getPerTesterSettings()->getIgnoreTrailingBytes(); + } + if (featureSettingsKeys.contains("txUDPAddress")) { + settings.m_txUDPAddress = *response.getPerTesterSettings()->getTxUdpAddress(); + } + if (featureSettingsKeys.contains("txUDPPort")) { + settings.m_txUDPPort = response.getPerTesterSettings()->getTxUdpPort(); + } + if (featureSettingsKeys.contains("rxUDPAddress")) { + settings.m_txUDPAddress = *response.getPerTesterSettings()->getRxUdpAddress(); + } + if (featureSettingsKeys.contains("rxUDPPort")) { + settings.m_rxUDPPort = response.getPerTesterSettings()->getRxUdpPort(); + } + if (featureSettingsKeys.contains("title")) { + settings.m_title = *response.getPerTesterSettings()->getTitle(); + } + if (featureSettingsKeys.contains("rgbColor")) { + settings.m_rgbColor = response.getPerTesterSettings()->getRgbColor(); + } + if (featureSettingsKeys.contains("useReverseAPI")) { + settings.m_useReverseAPI = response.getPerTesterSettings()->getUseReverseApi() != 0; + } + if (featureSettingsKeys.contains("reverseAPIAddress")) { + settings.m_reverseAPIAddress = *response.getPerTesterSettings()->getReverseApiAddress(); + } + if (featureSettingsKeys.contains("reverseAPIPort")) { + settings.m_reverseAPIPort = response.getPerTesterSettings()->getReverseApiPort(); + } +} + +void PERTester::webapiReverseSendSettings(QList& featureSettingsKeys, const PERTesterSettings& settings, bool force) +{ + SWGSDRangel::SWGFeatureSettings *swgFeatureSettings = new SWGSDRangel::SWGFeatureSettings(); + // swgFeatureSettings->setOriginatorFeatureIndex(getIndexInDeviceSet()); + // swgFeatureSettings->setOriginatorFeatureSetIndex(getDeviceSetIndex()); + swgFeatureSettings->setFeatureType(new QString("PERTester")); + swgFeatureSettings->setPerTesterSettings(new SWGSDRangel::SWGPERTesterSettings()); + SWGSDRangel::SWGPERTesterSettings *swgPERTesterSettings = swgFeatureSettings->getPerTesterSettings(); + + // transfer data that has been modified. When force is on transfer all data except reverse API data + + if (featureSettingsKeys.contains("packetCount") || force) { + swgPERTesterSettings->setPacketCount(settings.m_packetCount); + } + if (featureSettingsKeys.contains("interval") || force) { + swgPERTesterSettings->setInterval(settings.m_interval); + } + if (featureSettingsKeys.contains("start") || force) { + swgPERTesterSettings->setStart((int)settings.m_start); + } + if (featureSettingsKeys.contains("satellites") || force) { + swgPERTesterSettings->setSatellites(convertStringListToPtrs(settings.m_satellites)); + } + if (featureSettingsKeys.contains("packet") || force) { + swgPERTesterSettings->setPacket(new QString(settings.m_packet)); + } + if (featureSettingsKeys.contains("ignoreLeadingBytes") || force) { + swgPERTesterSettings->setIgnoreLeadingBytes(settings.m_ignoreLeadingBytes); + } + if (featureSettingsKeys.contains("ignoreTrailingBytes") || force) { + swgPERTesterSettings->setIgnoreTrailingBytes(settings.m_ignoreTrailingBytes); + } + if (featureSettingsKeys.contains("txUDPAddress") || force) { + swgPERTesterSettings->setTxUdpAddress(new QString(settings.m_txUDPAddress)); + } + if (featureSettingsKeys.contains("txUDPPort") || force) { + swgPERTesterSettings->setTxUdpPort(settings.m_txUDPPort); + } + if (featureSettingsKeys.contains("rxUDPAddress") || force) { + swgPERTesterSettings->setRxUdpAddress(new QString(settings.m_rxUDPAddress)); + } + if (featureSettingsKeys.contains("rxUDPPort") || force) { + swgPERTesterSettings->setRxUdpPort(settings.m_rxUDPPort); + } + + if (featureSettingsKeys.contains("title") || force) { + swgPERTesterSettings->setTitle(new QString(settings.m_title)); + } + if (featureSettingsKeys.contains("rgbColor") || force) { + swgPERTesterSettings->setRgbColor(settings.m_rgbColor); + } + + QString channelSettingsURL = QString("http://%1:%2/sdrangel/featureset/%3/feature/%4/settings") + .arg(settings.m_reverseAPIAddress) + .arg(settings.m_reverseAPIPort) + .arg(settings.m_reverseAPIFeatureSetIndex) + .arg(settings.m_reverseAPIFeatureIndex); + m_networkRequest.setUrl(QUrl(channelSettingsURL)); + m_networkRequest.setHeader(QNetworkRequest::ContentTypeHeader, "application/json"); + + QBuffer *buffer = new QBuffer(); + buffer->open((QBuffer::ReadWrite)); + buffer->write(swgFeatureSettings->asJson().toUtf8()); + buffer->seek(0); + + // Always use PATCH to avoid passing reverse API settings + QNetworkReply *reply = m_networkManager->sendCustomRequest(m_networkRequest, "PATCH", buffer); + buffer->setParent(reply); + + delete swgFeatureSettings; +} + +int PERTester::webapiActionsPost( + const QStringList& featureActionsKeys, + SWGSDRangel::SWGFeatureActions& query, + QString& errorMessage) +{ + SWGSDRangel::SWGPERTesterActions *swgPERTesterActions = query.getPerTesterActions(); + + if (swgPERTesterActions) + { + if (featureActionsKeys.contains("aos")) + { + SWGSDRangel::SWGPERTesterActions_aos* aos = swgPERTesterActions->getAos(); + QString *satelliteName = aos->getSatelliteName(); + if (satelliteName != nullptr) + { + if (m_settings.m_satellites.contains(*satelliteName)) + { + if (m_settings.m_start == PERTesterSettings::START_ON_AOS) + { + bool ok = m_worker->startWork(); + m_state = ok ? StRunning : StError; + } + else if (m_settings.m_start == PERTesterSettings::START_ON_MID_PASS) + { + QString aosTimeString = *aos->getAosTime(); + QString losTimeString = *aos->getLosTime(); + QDateTime aosTime = QDateTime::fromString(aosTimeString); + QDateTime losTime = QDateTime::fromString(losTimeString); + qint64 msecs = aosTime.msecsTo(losTime) / 2; + QTimer::singleShot(msecs, [this] { + bool ok = m_worker->startWork(); + m_state = ok ? StRunning : StError; + }); + } + } + + return 202; + } + else + { + errorMessage = "Missing satellite name"; + return 400; + } + } + else + { + errorMessage = "Unknown action"; + return 400; + } + } + else + { + errorMessage = "Missing PERTesterActions in query"; + return 400; + } +} + +void PERTester::networkManagerFinished(QNetworkReply *reply) +{ + QNetworkReply::NetworkError replyError = reply->error(); + + if (replyError) + { + qWarning() << "PERTester::networkManagerFinished:" + << " error(" << (int) replyError + << "): " << replyError + << ": " << reply->errorString(); + } + else + { + QString answer = reply->readAll(); + answer.chop(1); // remove last \n + qDebug("PERTester::networkManagerFinished: reply:\n%s", answer.toStdString().c_str()); + } + + reply->deleteLater(); +} diff --git a/plugins/feature/pertester/pertester.h b/plugins/feature/pertester/pertester.h new file mode 100644 index 000000000..2732b79b2 --- /dev/null +++ b/plugins/feature/pertester/pertester.h @@ -0,0 +1,178 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2020 Jon Beniston, M7RCE // +// Copyright (C) 2020 Edouard Griffiths, F4EXB // +// // +// This program is free software; you can redistribute it and/or modify // +// it under the terms of the GNU General Public License as published by // +// the Free Software Foundation as version 3 of the License, or // +// (at your option) any later version. // +// // +// This program is distributed in the hope that it will be useful, // +// but WITHOUT ANY WARRANTY; without even the implied warranty of // +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // +// GNU General Public License V3 for more details. // +// // +// You should have received a copy of the GNU General Public License // +// along with this program. If not, see . // +/////////////////////////////////////////////////////////////////////////////////// + +#ifndef INCLUDE_FEATURE_PERTESTER_H_ +#define INCLUDE_FEATURE_PERTESTER_H_ + +#include +#include +#include + +#include "feature/feature.h" +#include "util/message.h" + +#include "pertestersettings.h" + +class WebAPIAdapterInterface; +class PERTesterWorker; +class QNetworkAccessManager; +class QNetworkReply; + +namespace SWGSDRangel { + class SWGDeviceState; +} + +class PERTester : public Feature +{ + Q_OBJECT +public: + class MsgConfigurePERTester : public Message { + MESSAGE_CLASS_DECLARATION + + public: + const PERTesterSettings& getSettings() const { return m_settings; } + bool getForce() const { return m_force; } + + static MsgConfigurePERTester* create(const PERTesterSettings& settings, bool force) { + return new MsgConfigurePERTester(settings, force); + } + + private: + PERTesterSettings m_settings; + bool m_force; + + MsgConfigurePERTester(const PERTesterSettings& settings, bool force) : + Message(), + m_settings(settings), + 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 MsgResetStats : public Message { + MESSAGE_CLASS_DECLARATION + + public: + + static MsgResetStats* create() { + return new MsgResetStats(); + } + + protected: + MsgResetStats() : + Message() + { } + }; + + class MsgReportWorker : public Message { + MESSAGE_CLASS_DECLARATION + + public: + QString getMessage() { return m_message; } + + static MsgReportWorker* create(QString message) { + return new MsgReportWorker(message); + } + + private: + QString m_message; + + MsgReportWorker(QString message) : + Message(), + m_message(message) + {} + }; + + PERTester(WebAPIAdapterInterface *webAPIAdapterInterface); + virtual ~PERTester(); + virtual void destroy() { delete this; } + virtual bool handleMessage(const Message& cmd); + + virtual void getIdentifier(QString& id) const { id = objectName(); } + virtual void getTitle(QString& title) const { title = m_settings.m_title; } + + virtual QByteArray serialize() const; + virtual bool deserialize(const QByteArray& data); + + virtual int webapiRun(bool run, + SWGSDRangel::SWGDeviceState& response, + QString& errorMessage); + + virtual int webapiSettingsGet( + SWGSDRangel::SWGFeatureSettings& response, + QString& errorMessage); + + virtual int webapiSettingsPutPatch( + bool force, + const QStringList& featureSettingsKeys, + SWGSDRangel::SWGFeatureSettings& response, + QString& errorMessage); + + virtual int webapiActionsPost( + const QStringList& featureActionsKeys, + SWGSDRangel::SWGFeatureActions& query, + QString& errorMessage); + + static void webapiFormatFeatureSettings( + SWGSDRangel::SWGFeatureSettings& response, + const PERTesterSettings& settings); + + static void webapiUpdateFeatureSettings( + PERTesterSettings& settings, + const QStringList& featureSettingsKeys, + SWGSDRangel::SWGFeatureSettings& response); + + static const char* const m_featureIdURI; + static const char* const m_featureId; + +private: + QThread m_thread; + PERTesterWorker *m_worker; + PERTesterSettings m_settings; + + QNetworkAccessManager *m_networkManager; + QNetworkRequest m_networkRequest; + + void start(); + void stop(); + void applySettings(const PERTesterSettings& settings, bool force = false); + void webapiReverseSendSettings(QList& featureSettingsKeys, const PERTesterSettings& settings, bool force); + +private slots: + void networkManagerFinished(QNetworkReply *reply); +}; + +#endif // INCLUDE_FEATURE_PERTESTER_H_ diff --git a/plugins/feature/pertester/pertestergui.cpp b/plugins/feature/pertester/pertestergui.cpp new file mode 100644 index 000000000..2ddd75c78 --- /dev/null +++ b/plugins/feature/pertester/pertestergui.cpp @@ -0,0 +1,349 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2020 Jon Beniston, M7RCE // +// Copyright (C) 2020 Edouard Griffiths, F4EXB // +// // +// This program is free software; you can redistribute it and/or modify // +// it under the terms of the GNU General Public License as published by // +// the Free Software Foundation as version 3 of the License, or // +// (at your option) any later version. // +// // +// This program is distributed in the hope that it will be useful, // +// but WITHOUT ANY WARRANTY; without even the implied warranty of // +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // +// GNU General Public License V3 for more details. // +// // +// You should have received a copy of the GNU General Public License // +// along with this program. If not, see . // +/////////////////////////////////////////////////////////////////////////////////// + +#include +#include +#include + +#include "feature/featureuiset.h" +#include "gui/basicfeaturesettingsdialog.h" +#include "mainwindow.h" +#include "device/deviceuiset.h" + +#include "ui_pertestergui.h" +#include "pertester.h" +#include "pertestergui.h" +#include "pertesterreport.h" + +PERTesterGUI* PERTesterGUI::create(PluginAPI* pluginAPI, FeatureUISet *featureUISet, Feature *feature) +{ + PERTesterGUI* gui = new PERTesterGUI(pluginAPI, featureUISet, feature); + return gui; +} + +void PERTesterGUI::destroy() +{ + delete this; +} + +void PERTesterGUI::resetToDefaults() +{ + m_settings.resetToDefaults(); + displaySettings(); + applySettings(true); +} + +QByteArray PERTesterGUI::serialize() const +{ + return m_settings.serialize(); +} + +bool PERTesterGUI::deserialize(const QByteArray& data) +{ + if (m_settings.deserialize(data)) + { + displaySettings(); + applySettings(true); + return true; + } + else + { + resetToDefaults(); + return false; + } +} + +bool PERTesterGUI::handleMessage(const Message& message) +{ + if (PERTester::MsgConfigurePERTester::match(message)) + { + qDebug("PERTesterGUI::handleMessage: PERTester::MsgConfigurePERTester"); + const PERTester::MsgConfigurePERTester& cfg = (PERTester::MsgConfigurePERTester&) message; + m_settings = cfg.getSettings(); + blockApplySettings(true); + displaySettings(); + blockApplySettings(false); + + return true; + } + else if (PERTesterReport::MsgReportStats::match(message)) + { + PERTesterReport::MsgReportStats& stats = (PERTesterReport::MsgReportStats&) message; + int tx = stats.getTx(); + int rxMatched = stats.getRxMatched(); + double per = tx == 0 ? 0.0 : 100.0 - (rxMatched/(double)tx)*100.0; + ui->transmittedText->setText(QString("%1").arg(tx)); + ui->receivedMatchedText->setText(QString("%1").arg(rxMatched)); + ui->receivedUnmatchedText->setText(QString("%1").arg(stats.getRxUnmatched())); + ui->perText->setText(QString("%1%").arg(per, 0, 'f', 1)); + return true; + } + + return false; +} + +void PERTesterGUI::handleInputMessages() +{ + Message* message; + + while ((message = getInputMessageQueue()->pop())) + { + if (handleMessage(*message)) { + delete message; + } + } +} + +void PERTesterGUI::onWidgetRolled(QWidget* widget, bool rollDown) +{ + (void) widget; + (void) rollDown; +} + +PERTesterGUI::PERTesterGUI(PluginAPI* pluginAPI, FeatureUISet *featureUISet, Feature *feature, QWidget* parent) : + FeatureGUI(parent), + ui(new Ui::PERTesterGUI), + m_pluginAPI(pluginAPI), + m_featureUISet(featureUISet), + m_doApplySettings(true), + m_lastFeatureState(0) +{ + ui->setupUi(this); + setAttribute(Qt::WA_DeleteOnClose, true); + setChannelWidget(false); + connect(this, SIGNAL(widgetRolled(QWidget*,bool)), this, SLOT(onWidgetRolled(QWidget*,bool))); + m_perTester = reinterpret_cast(feature); + m_perTester->setMessageQueueToGUI(&m_inputMessageQueue); + + m_featureUISet->addRollupWidget(this); + + connect(this, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(onMenuDialogCalled(const QPoint &))); + connect(getInputMessageQueue(), SIGNAL(messageEnqueued()), this, SLOT(handleInputMessages())); + + connect(&m_statusTimer, SIGNAL(timeout()), this, SLOT(updateStatus())); + m_statusTimer.start(1000); + + displaySettings(); + applySettings(true); +} + +PERTesterGUI::~PERTesterGUI() +{ + delete ui; +} + +void PERTesterGUI::blockApplySettings(bool block) +{ + m_doApplySettings = !block; +} + +void PERTesterGUI::displaySettings() +{ + setTitleColor(m_settings.m_rgbColor); + setWindowTitle(m_settings.m_title); + blockApplySettings(true); + ui->packetCount->setValue(m_settings.m_packetCount); + ui->start->setCurrentIndex((int)m_settings.m_start); + ui->satellites->setVisible(m_settings.m_start != PERTesterSettings::START_IMMEDIATELY); + ui->satellitesLabel->setVisible(m_settings.m_start != PERTesterSettings::START_IMMEDIATELY); + ui->satellites->setText(m_settings.m_satellites.join(" ")); + ui->interval->setValue(m_settings.m_interval); + ui->packet->setPlainText(m_settings.m_packet); + ui->leading->setValue(m_settings.m_ignoreLeadingBytes); + ui->trailing->setValue(m_settings.m_ignoreTrailingBytes); + ui->txUDPAddress->setText(m_settings.m_txUDPAddress); + ui->txUDPPort->setText(QString::number(m_settings.m_txUDPPort)); + ui->rxUDPAddress->setText(m_settings.m_rxUDPAddress); + ui->rxUDPPort->setText(QString::number(m_settings.m_rxUDPPort)); + blockApplySettings(false); + arrangeRollups(); +} + +void PERTesterGUI::leaveEvent(QEvent*) +{ +} + +void PERTesterGUI::enterEvent(QEvent*) +{ +} + +void PERTesterGUI::onMenuDialogCalled(const QPoint &p) +{ + if (m_contextMenuType == ContextMenuChannelSettings) + { + BasicFeatureSettingsDialog dialog(this); + dialog.setTitle(m_settings.m_title); + dialog.setColor(m_settings.m_rgbColor); + dialog.setUseReverseAPI(m_settings.m_useReverseAPI); + dialog.setReverseAPIAddress(m_settings.m_reverseAPIAddress); + dialog.setReverseAPIPort(m_settings.m_reverseAPIPort); + dialog.setReverseAPIFeatureSetIndex(m_settings.m_reverseAPIFeatureSetIndex); + dialog.setReverseAPIFeatureIndex(m_settings.m_reverseAPIFeatureIndex); + + dialog.move(p); + dialog.exec(); + + m_settings.m_rgbColor = dialog.getColor().rgb(); + m_settings.m_title = dialog.getTitle(); + m_settings.m_useReverseAPI = dialog.useReverseAPI(); + m_settings.m_reverseAPIAddress = dialog.getReverseAPIAddress(); + m_settings.m_reverseAPIPort = dialog.getReverseAPIPort(); + m_settings.m_reverseAPIFeatureSetIndex = dialog.getReverseAPIFeatureSetIndex(); + m_settings.m_reverseAPIFeatureIndex = dialog.getReverseAPIFeatureIndex(); + + setWindowTitle(m_settings.m_title); + setTitleColor(m_settings.m_rgbColor); + + applySettings(); + } + + resetContextMenuType(); +} + +void PERTesterGUI::on_startStop_toggled(bool checked) +{ + if (m_doApplySettings) + { + PERTester::MsgStartStop *message = PERTester::MsgStartStop::create(checked); + m_perTester->getInputMessageQueue()->push(message); + } +} + +void PERTesterGUI::on_resetStats_clicked() +{ + if (m_doApplySettings) + { + PERTester::MsgResetStats *message = PERTester::MsgResetStats::create(); + m_perTester->getInputMessageQueue()->push(message); + } +} + +void PERTesterGUI::on_packetCount_valueChanged(int value) +{ + m_settings.m_packetCount = value; + applySettings(); +} + +void PERTesterGUI::on_start_currentIndexChanged(int index) +{ + m_settings.m_start = (PERTesterSettings::Start)index; + ui->satellites->setVisible(m_settings.m_start != PERTesterSettings::START_IMMEDIATELY); + ui->satellitesLabel->setVisible(m_settings.m_start != PERTesterSettings::START_IMMEDIATELY); + applySettings(); + arrangeRollups(); +} + +void PERTesterGUI::on_satellites_editingFinished() +{ + m_settings.m_satellites = ui->satellites->text().trimmed().split(" "); + applySettings(); +} + +void PERTesterGUI::on_interval_valueChanged(double value) +{ + m_settings.m_interval = value; + applySettings(); +} + +void PERTesterGUI::on_packet_textChanged() +{ + m_settings.m_packet = ui->packet->toPlainText(); + applySettings(); +} + +void PERTesterGUI::on_leading_valueChanged(int value) +{ + m_settings.m_ignoreLeadingBytes = value; + applySettings(); +} + +void PERTesterGUI::on_trailing_valueChanged(int value) +{ + m_settings.m_ignoreTrailingBytes = value; + applySettings(); +} + +void PERTesterGUI::on_txUDPAddress_editingFinished() +{ + m_settings.m_txUDPAddress = ui->txUDPAddress->text(); + applySettings(); +} + +void PERTesterGUI::on_txUDPPort_editingFinished() +{ + m_settings.m_txUDPPort = ui->txUDPPort->text().toInt(); + applySettings(); +} + +void PERTesterGUI::on_rxUDPAddress_editingFinished() +{ + m_settings.m_rxUDPAddress = ui->rxUDPAddress->text(); + applySettings(); +} + +void PERTesterGUI::on_rxUDPPort_editingFinished() +{ + m_settings.m_rxUDPPort = ui->rxUDPPort->text().toInt(); + applySettings(); +} + +void PERTesterGUI::updateStatus() +{ + int state = m_perTester->getState(); + + if (m_lastFeatureState != state) + { + // We set checked state of start/stop button, in case it was changed via API + bool oldState; + switch (state) + { + case Feature::StNotStarted: + ui->startStop->setStyleSheet("QToolButton { background:rgb(79,79,79); }"); + break; + case Feature::StIdle: + oldState = ui->startStop->blockSignals(true); + ui->startStop->setChecked(false); + ui->startStop->blockSignals(oldState); + ui->startStop->setStyleSheet("QToolButton { background-color : blue; }"); + break; + case Feature::StRunning: + oldState = ui->startStop->blockSignals(true); + ui->startStop->setChecked(true); + ui->startStop->blockSignals(oldState); + ui->startStop->setStyleSheet("QToolButton { background-color : green; }"); + break; + case Feature::StError: + ui->startStop->setStyleSheet("QToolButton { background-color : red; }"); + QMessageBox::information(this, tr("Message"), m_perTester->getErrorMessage()); + break; + default: + break; + } + + m_lastFeatureState = state; + } +} + +void PERTesterGUI::applySettings(bool force) +{ + if (m_doApplySettings) + { + PERTester::MsgConfigurePERTester* message = PERTester::MsgConfigurePERTester::create(m_settings, force); + m_perTester->getInputMessageQueue()->push(message); + } +} diff --git a/plugins/feature/pertester/pertestergui.h b/plugins/feature/pertester/pertestergui.h new file mode 100644 index 000000000..45039f877 --- /dev/null +++ b/plugins/feature/pertester/pertestergui.h @@ -0,0 +1,91 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2020 Jon Beniston, M7RCE // +// Copyright (C) 2020 Edouard Griffiths, F4EXB // +// // +// This program is free software; you can redistribute it and/or modify // +// it under the terms of the GNU General Public License as published by // +// the Free Software Foundation as version 3 of the License, or // +// (at your option) any later version. // +// // +// This program is distributed in the hope that it will be useful, // +// but WITHOUT ANY WARRANTY; without even the implied warranty of // +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // +// GNU General Public License V3 for more details. // +// // +// You should have received a copy of the GNU General Public License // +// along with this program. If not, see . // +/////////////////////////////////////////////////////////////////////////////////// + +#ifndef INCLUDE_FEATURE_PERTESTERGUI_H_ +#define INCLUDE_FEATURE_PERTESTERGUI_H_ + +#include + +#include "feature/featuregui.h" +#include "util/messagequeue.h" +#include "pipes/pipeendpoint.h" +#include "pertestersettings.h" + +class PluginAPI; +class FeatureUISet; +class PERTester; + +namespace Ui { + class PERTesterGUI; +} + +class PERTesterGUI : public FeatureGUI { + Q_OBJECT +public: + static PERTesterGUI* create(PluginAPI* pluginAPI, FeatureUISet *featureUISet, Feature *feature); + virtual void destroy(); + + void resetToDefaults(); + QByteArray serialize() const; + bool deserialize(const QByteArray& data); + virtual MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; } + +private: + Ui::PERTesterGUI* ui; + PluginAPI* m_pluginAPI; + FeatureUISet* m_featureUISet; + PERTesterSettings m_settings; + bool m_doApplySettings; + + PERTester* m_perTester; + MessageQueue m_inputMessageQueue; + QTimer m_statusTimer; + int m_lastFeatureState; + + explicit PERTesterGUI(PluginAPI* pluginAPI, FeatureUISet *featureUISet, Feature *feature, QWidget* parent = nullptr); + virtual ~PERTesterGUI(); + + void blockApplySettings(bool block); + void applySettings(bool force = false); + void displaySettings(); + bool handleMessage(const Message& message); + + void leaveEvent(QEvent*); + void enterEvent(QEvent*); + +private slots: + void onMenuDialogCalled(const QPoint &p); + void onWidgetRolled(QWidget* widget, bool rollDown); + void handleInputMessages(); + void on_startStop_toggled(bool checked); + void on_resetStats_clicked(); + void on_packetCount_valueChanged(int value); + void on_start_currentIndexChanged(int index); + void on_satellites_editingFinished(); + void on_interval_valueChanged(double value); + void on_packet_textChanged(); + void on_leading_valueChanged(int value); + void on_trailing_valueChanged(int value); + void on_txUDPAddress_editingFinished(); + void on_txUDPPort_editingFinished(); + void on_rxUDPAddress_editingFinished(); + void on_rxUDPPort_editingFinished(); + void updateStatus(); +}; + +#endif // INCLUDE_FEATURE_PERTESTERGUI_H_ diff --git a/plugins/feature/pertester/pertestergui.ui b/plugins/feature/pertester/pertestergui.ui new file mode 100644 index 000000000..ff1e2d391 --- /dev/null +++ b/plugins/feature/pertester/pertestergui.ui @@ -0,0 +1,576 @@ + + + PERTesterGUI + + + + 0 + 0 + 350 + 430 + + + + + 0 + 0 + + + + + 320 + 100 + + + + + 350 + 16777215 + + + + + Liberation Sans + 9 + + + + GS-232 Rotator Controller + + + + + 10 + 10 + 331 + 291 + + + + Settings + + + + 3 + + + 2 + + + 2 + + + 2 + + + 2 + + + + + + + Start/stop PER Test + + + + + + + :/play.png + :/stop.png:/play.png + + + + + + + Reset statistics + + + + + + + :/recycle.png:/recycle.png + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + Start test + + + + + + + Number of packets to transmit + + + 1 + + + 2000000000 + + + + + + + When to start the test, after the start button is pressed + + + + Immediately + + + + + On satellite AOS + + + + + On satellite mid pass + + + + + + + + Packets + + + + + + + Interval in seconds between packets + + + 3 + + + 1000000.000000000000000 + + + + + + + Interval (s) + + + + + + + Satellites + + + + + + + Space separated list of satellite names to start the PER test on + + + ISS + + + + + + + + + + + Packet + + + + + + + + 0 + 0 + + + + + 0 + 80 + + + + Hex encoded packet to transmit. + +Substitutions: +%{ax25.src=CALLSIGN} +%{ax25.dst=CALLSIGN} +%{num} +%{data=min,max} + + + + + + + + + + + Ignore + + + + + + + Leading + + + + + + + 10000 + + + + + + + Trailing + + + + + + + 10000 + + + + + + + bytes + + + + + + + + + + + TX UDP + + + + + + + + 120 + 0 + + + + Qt::ClickFocus + + + Destination UDP address + + + 000.000.000.000 + + + 127.0.0.1 + + + + + + + : + + + Qt::AlignCenter + + + + + + + + 50 + 0 + + + + + 50 + 16777215 + + + + Qt::ClickFocus + + + Destination UDP port + + + 00000 + + + 9997 + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + RX UDP + + + + + + + + 120 + 0 + + + + Qt::ClickFocus + + + Destination UDP address + + + 000.000.000.000 + + + 127.0.0.1 + + + + + + + : + + + Qt::AlignCenter + + + + + + + + 50 + 0 + + + + + 50 + 16777215 + + + + Qt::ClickFocus + + + Destination UDP port + + + 00000 + + + 9998 + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + 10 + 310 + 331 + 91 + + + + Statistics + + + + 3 + + + 2 + + + 2 + + + 2 + + + 2 + + + + + + + Number of packets received that match a transmitted packet + + + 0 + + + + + + + Received and Matched + + + + + + + PER + + + + + + + 0% + + + + + + + Number of packets that have been transmitted + + + 0 + + + + + + + Transmitted + + + + + + + Received and Unmatched + + + + + + + Number of packets received that do not match a transmitted packet + + + 0 + + + + + + + + + + + RollupWidget + QWidget +
gui/rollupwidget.h
+ 1 +
+ + ButtonSwitch + QToolButton +
gui/buttonswitch.h
+
+
+ + startStop + + + + + +
diff --git a/plugins/feature/pertester/pertestergui.ui.autosave b/plugins/feature/pertester/pertestergui.ui.autosave new file mode 100644 index 000000000..d7b16de17 --- /dev/null +++ b/plugins/feature/pertester/pertestergui.ui.autosave @@ -0,0 +1,576 @@ + + + PERTesterGUI + + + + 0 + 0 + 350 + 430 + + + + + 0 + 0 + + + + + 320 + 100 + + + + + 350 + 16777215 + + + + + Liberation Sans + 9 + + + + GS-232 Rotator Controller + + + + + 10 + 10 + 331 + 291 + + + + Settings + + + + 3 + + + 2 + + + 2 + + + 2 + + + 2 + + + + + + + Start/stop PER Test + + + + + + + :/play.png + :/stop.png:/play.png + + + + + + + Reset statistics + + + + + + + :/recycle.png:/recycle.png + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + Start test + + + + + + + Number of packets to transmit + + + 1 + + + 2000000000 + + + + + + + When to start the test, after the start button is pressed + + + + Immediately + + + + + On satellite AOS + + + + + On satellite mid pass + + + + + + + + Packets + + + + + + + Interval in seconds between packets + + + 3 + + + 1000000.000000000000000 + + + + + + + Interval (s) + + + + + + + Satellites + + + + + + + Space separated list of satellite names to start the PER test on + + + ISS + + + + + + + + + + + Packet + + + + + + + + 0 + 0 + + + + + 0 + 0 + + + + Hex encoded packet to transmit. + +Substitutions: +%{ax25.src=CALLSIGN} +%{ax25.dst=CALLSIGN} +%{num} +%{data=min,max} + + + + + + + + + + + Ignore + + + + + + + Leading + + + + + + + 10000 + + + + + + + Trailing + + + + + + + 10000 + + + + + + + bytes + + + + + + + + + + + TX UDP + + + + + + + + 120 + 0 + + + + Qt::ClickFocus + + + Destination UDP address + + + 000.000.000.000 + + + 127.0.0.1 + + + + + + + : + + + Qt::AlignCenter + + + + + + + + 50 + 0 + + + + + 50 + 16777215 + + + + Qt::ClickFocus + + + Destination UDP port + + + 00000 + + + 9997 + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + RX UDP + + + + + + + + 120 + 0 + + + + Qt::ClickFocus + + + Destination UDP address + + + 000.000.000.000 + + + 127.0.0.1 + + + + + + + : + + + Qt::AlignCenter + + + + + + + + 50 + 0 + + + + + 50 + 16777215 + + + + Qt::ClickFocus + + + Destination UDP port + + + 00000 + + + 9998 + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + 10 + 310 + 331 + 91 + + + + Statistics + + + + 3 + + + 2 + + + 2 + + + 2 + + + 2 + + + + + + + Number of packets received that match a transmitted packet + + + 0 + + + + + + + Received and Matched + + + + + + + PER + + + + + + + 0% + + + + + + + Number of packets that have been transmitted + + + 0 + + + + + + + Transmitted + + + + + + + Received and Unmatched + + + + + + + Number of packets received that do not match a transmitted packet + + + 0 + + + + + + + + + + + RollupWidget + QWidget +
gui/rollupwidget.h
+ 1 +
+ + ButtonSwitch + QToolButton +
gui/buttonswitch.h
+
+
+ + startStop + + + + + +
diff --git a/plugins/feature/pertester/pertesterplugin.cpp b/plugins/feature/pertester/pertesterplugin.cpp new file mode 100644 index 000000000..d8fa9d389 --- /dev/null +++ b/plugins/feature/pertester/pertesterplugin.cpp @@ -0,0 +1,80 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2020 Jon Beniston, M7RCE // +// Copyright (C) 2020 Edouard Griffiths, F4EXB // +// // +// This program is free software; you can redistribute it and/or modify // +// it under the terms of the GNU General Public License as published by // +// the Free Software Foundation as version 3 of the License, or // +// (at your option) any later version. // +// // +// This program is distributed in the hope that it will be useful, // +// but WITHOUT ANY WARRANTY; without even the implied warranty of // +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // +// GNU General Public License V3 for more details. // +// // +// You should have received a copy of the GNU General Public License // +// along with this program. If not, see . // +/////////////////////////////////////////////////////////////////////////////////// + + +#include +#include "plugin/pluginapi.h" + +#ifndef SERVER_MODE +#include "pertestergui.h" +#endif +#include "pertester.h" +#include "pertesterplugin.h" +#include "pertesterwebapiadapter.h" + +const PluginDescriptor PERTesterPlugin::m_pluginDescriptor = { + PERTester::m_featureId, + QStringLiteral("Packet Error Rate Tester"), + QStringLiteral("6.7.1"), + QStringLiteral("(c) Jon Beniston, M7RCE"), + QStringLiteral("https://github.com/f4exb/sdrangel"), + true, + QStringLiteral("https://github.com/f4exb/sdrangel") +}; + +PERTesterPlugin::PERTesterPlugin(QObject* parent) : + QObject(parent), + m_pluginAPI(nullptr) +{ +} + +const PluginDescriptor& PERTesterPlugin::getPluginDescriptor() const +{ + return m_pluginDescriptor; +} + +void PERTesterPlugin::initPlugin(PluginAPI* pluginAPI) +{ + m_pluginAPI = pluginAPI; + + m_pluginAPI->registerFeature(PERTester::m_featureIdURI, PERTester::m_featureId, this); +} + +#ifdef SERVER_MODE +FeatureGUI* PERTesterPlugin::createFeatureGUI(FeatureUISet *featureUISet, Feature *feature) const +{ + (void) featureUISet; + (void) feature; + return nullptr; +} +#else +FeatureGUI* PERTesterPlugin::createFeatureGUI(FeatureUISet *featureUISet, Feature *feature) const +{ + return PERTesterGUI::create(m_pluginAPI, featureUISet, feature); +} +#endif + +Feature* PERTesterPlugin::createFeature(WebAPIAdapterInterface* webAPIAdapterInterface) const +{ + return new PERTester(webAPIAdapterInterface); +} + +FeatureWebAPIAdapter* PERTesterPlugin::createFeatureWebAPIAdapter() const +{ + return new PERTesterWebAPIAdapter(); +} diff --git a/plugins/feature/pertester/pertesterplugin.h b/plugins/feature/pertester/pertesterplugin.h new file mode 100644 index 000000000..dc8f7c2ad --- /dev/null +++ b/plugins/feature/pertester/pertesterplugin.h @@ -0,0 +1,49 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2020 Jon Beniston, M7RCE // +// Copyright (C) 2020 Edouard Griffiths, F4EXB // +// // +// This program is free software; you can redistribute it and/or modify // +// it under the terms of the GNU General Public License as published by // +// the Free Software Foundation as version 3 of the License, or // +// (at your option) any later version. // +// // +// This program is distributed in the hope that it will be useful, // +// but WITHOUT ANY WARRANTY; without even the implied warranty of // +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // +// GNU General Public License V3 for more details. // +// // +// You should have received a copy of the GNU General Public License // +// along with this program. If not, see . // +/////////////////////////////////////////////////////////////////////////////////// + +#ifndef INCLUDE_FEATURE_PERTESTERPLUGIN_H +#define INCLUDE_FEATURE_PERTESTERPLUGIN_H + +#include +#include "plugin/plugininterface.h" + +class FeatureGUI; +class WebAPIAdapterInterface; + +class PERTesterPlugin : public QObject, PluginInterface { + Q_OBJECT + Q_INTERFACES(PluginInterface) + Q_PLUGIN_METADATA(IID "sdrangel.feature.pertester") + +public: + explicit PERTesterPlugin(QObject* parent = nullptr); + + const PluginDescriptor& getPluginDescriptor() const; + void initPlugin(PluginAPI* pluginAPI); + + virtual FeatureGUI* createFeatureGUI(FeatureUISet *featureUISet, Feature *feature) const; + virtual Feature* createFeature(WebAPIAdapterInterface *webAPIAdapterInterface) const; + virtual FeatureWebAPIAdapter* createFeatureWebAPIAdapter() const; + +private: + static const PluginDescriptor m_pluginDescriptor; + + PluginAPI* m_pluginAPI; +}; + +#endif // INCLUDE_FEATURE_PERTESTERPLUGIN_H diff --git a/plugins/feature/pertester/pertesterreport.h b/plugins/feature/pertester/pertesterreport.h new file mode 100644 index 000000000..f8f565bd3 --- /dev/null +++ b/plugins/feature/pertester/pertesterreport.h @@ -0,0 +1,63 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2019 Edouard Griffiths, F4EXB // +// Copyright (C) 2020 Jon Beniston, M7RCE // +// // +// 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 . // +/////////////////////////////////////////////////////////////////////////////////// + +#ifndef INCLUDE_FEATURE_PERTESTERREPORT_H_ +#define INCLUDE_FEATURE_PERTESTERREPORT_H_ + +#include + +#include "util/message.h" + +class PERTesterReport : public QObject +{ + Q_OBJECT +public: + + class MsgReportStats : public Message { + MESSAGE_CLASS_DECLARATION + + public: + int getTx() const { return m_tx; } + int getRxMatched() const { return m_rxMatched; } + int getRxUnmatched() const { return m_rxUnmatched; } + + static MsgReportStats* create(int tx, int rxMatched, int rxUnmatched) + { + return new MsgReportStats(tx, rxMatched, rxUnmatched); + } + + private: + int m_tx; + int m_rxMatched; + int m_rxUnmatched; + + MsgReportStats(int tx, int rxMatched, int rxUnmatched) : + Message(), + m_tx(tx), + m_rxMatched(rxMatched), + m_rxUnmatched(rxUnmatched) + { + } + }; + +public: + PERTesterReport() {} + ~PERTesterReport() {} +}; + +#endif // INCLUDE_FEATURE_PERTESTERREPORT_H_ diff --git a/plugins/feature/pertester/pertestersettings.cpp b/plugins/feature/pertester/pertestersettings.cpp new file mode 100644 index 000000000..523ed1675 --- /dev/null +++ b/plugins/feature/pertester/pertestersettings.cpp @@ -0,0 +1,159 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2020 Jon Beniston, M7RCE // +// Copyright (C) 2020 Edouard Griffiths, F4EXB // +// // +// This program is free software; you can redistribute it and/or modify // +// it under the terms of the GNU General Public License as published by // +// the Free Software Foundation as version 3 of the License, or // +// (at your option) any later version. // +// // +// This program is distributed in the hope that it will be useful, // +// but WITHOUT ANY WARRANTY; without even the implied warranty of // +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // +// GNU General Public License V3 for more details. // +// // +// You should have received a copy of the GNU General Public License // +// along with this program. If not, see . // +/////////////////////////////////////////////////////////////////////////////////// + +#include +#include + +#include "util/simpleserializer.h" +#include "settings/serializable.h" + +#include "pertestersettings.h" + +PERTesterSettings::PERTesterSettings() +{ + resetToDefaults(); +} + +void PERTesterSettings::resetToDefaults() +{ + m_packetCount = 10; + m_interval = 1.0f; + m_packet = "%{ax25.dst=MYCALL} %{ax25.src=MYCALL} 03 f0 %{num} %{data=0,100}"; + m_txUDPAddress = "127.0.0.1"; + m_txUDPPort = 9998; + m_rxUDPAddress = "127.0.0.1"; + m_rxUDPPort = 9999; + m_ignoreLeadingBytes = 0; + m_ignoreTrailingBytes = 2; // Ignore CRC + m_start = START_IMMEDIATELY; + m_satellites = {QString("ISS")}; + m_title = "Packet Error Rate Tester"; + m_rgbColor = QColor(225, 25, 99).rgb(); + m_useReverseAPI = false; + m_reverseAPIAddress = "127.0.0.1"; + m_reverseAPIPort = 8888; + m_reverseAPIFeatureSetIndex = 0; + m_reverseAPIFeatureIndex = 0; +} + +QByteArray PERTesterSettings::serialize() const +{ + SimpleSerializer s(1); + + s.writeS32(1, m_packetCount); + s.writeFloat(2, m_interval); + s.writeString(3, m_txUDPAddress); + s.writeU32(4, m_txUDPPort); + s.writeString(5, m_rxUDPAddress); + s.writeU32(6, m_rxUDPPort); + s.writeS32(7, m_ignoreLeadingBytes); + s.writeS32(8, m_ignoreTrailingBytes); + s.writeS32(9, (int)m_start); + s.writeBlob(10, serializeStringList(m_satellites)); + + s.writeString(20, m_title); + s.writeU32(21, m_rgbColor); + s.writeBool(22, m_useReverseAPI); + s.writeString(23, m_reverseAPIAddress); + s.writeU32(24, m_reverseAPIPort); + s.writeU32(25, m_reverseAPIFeatureSetIndex); + s.writeU32(26, m_reverseAPIFeatureIndex); + + return s.final(); +} + +bool PERTesterSettings::deserialize(const QByteArray& data) +{ + SimpleDeserializer d(data); + + if (!d.isValid()) + { + resetToDefaults(); + return false; + } + + if (d.getVersion() == 1) + { + QByteArray bytetmp; + uint32_t utmp; + QString strtmp; + QByteArray blob; + + d.readS32(1, &m_packetCount); + d.readFloat(2, &m_interval, 1.0f); + d.readString(3, &m_txUDPAddress); + d.readU32(4, &utmp); + if ((utmp > 1023) && (utmp < 65535)) { + m_txUDPPort = utmp; + } else { + m_txUDPPort = 8888; + } + d.readString(5, &m_rxUDPAddress); + d.readU32(6, &utmp); + if ((utmp > 1023) && (utmp < 65535)) { + m_rxUDPPort = utmp; + } else { + m_rxUDPPort = 8888; + } + d.readS32(7, &m_ignoreLeadingBytes, 0); + d.readS32(8, &m_ignoreTrailingBytes, 2); + d.readS32(9, (int*)&m_start, (int)START_IMMEDIATELY); + d.readBlob(10, &blob); + deserializeStringList(blob, m_satellites); + + d.readString(20, &m_title, "Packet Error Rate Tester"); + d.readU32(21, &m_rgbColor, QColor(225, 25, 99).rgb()); + d.readBool(22, &m_useReverseAPI, false); + d.readString(23, &m_reverseAPIAddress, "127.0.0.1"); + d.readU32(24, &utmp, 0); + + if ((utmp > 1023) && (utmp < 65535)) { + m_reverseAPIPort = utmp; + } else { + m_reverseAPIPort = 8888; + } + + d.readU32(25, &utmp, 0); + m_reverseAPIFeatureSetIndex = utmp > 99 ? 99 : utmp; + d.readU32(26, &utmp, 0); + m_reverseAPIFeatureIndex = utmp > 99 ? 99 : utmp; + + return true; + } + else + { + resetToDefaults(); + return false; + } +} + +QByteArray PERTesterSettings::serializeStringList(const QList& strings) const +{ + QByteArray data; + QDataStream *stream = new QDataStream(&data, QIODevice::WriteOnly); + (*stream) << strings; + delete stream; + return data; +} + +void PERTesterSettings::deserializeStringList(const QByteArray& data, QList& strings) +{ + QDataStream *stream = new QDataStream(data); + (*stream) >> strings; + delete stream; +} diff --git a/plugins/feature/pertester/pertestersettings.h b/plugins/feature/pertester/pertestersettings.h new file mode 100644 index 000000000..76741e0fa --- /dev/null +++ b/plugins/feature/pertester/pertestersettings.h @@ -0,0 +1,60 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2020 Jon Beniston, M7RCE // +// Copyright (C) 2020 Edouard Griffiths, F4EXB // +// // +// This program is free software; you can redistribute it and/or modify // +// it under the terms of the GNU General Public License as published by // +// the Free Software Foundation as version 3 of the License, or // +// (at your option) any later version. // +// // +// This program is distributed in the hope that it will be useful, // +// but WITHOUT ANY WARRANTY; without even the implied warranty of // +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // +// GNU General Public License V3 for more details. // +// // +// You should have received a copy of the GNU General Public License // +// along with this program. If not, see . // +/////////////////////////////////////////////////////////////////////////////////// + +#ifndef INCLUDE_FEATURE_PERTESTERSETTINGS_H_ +#define INCLUDE_FEATURE_PERTESTERSETTINGS_H_ + +#include +#include + +#include "util/message.h" + +class Serializable; + +struct PERTesterSettings +{ + int m_packetCount; //!< How many packets to send + float m_interval; //!< Interval between packets in seconds + QString m_packet; //!< Contents of the packet + QString m_txUDPAddress; //!< UDP port of modulator to send packets too + uint16_t m_txUDPPort; + QString m_rxUDPAddress; //!< UDP port to receive packets from demodulator on + uint16_t m_rxUDPPort; + int m_ignoreLeadingBytes; //!< Number of bytes to ignore at start of received frame (E.g. header) + int m_ignoreTrailingBytes; //!< Number of bytes to ignore at end of received frame (E.g. CRC) + enum Start {START_IMMEDIATELY, START_ON_AOS, START_ON_MID_PASS} m_start; //!< When to start test + QList m_satellites; //!< Which satellites to start test on + + QString m_title; + quint32 m_rgbColor; + bool m_useReverseAPI; + QString m_reverseAPIAddress; + uint16_t m_reverseAPIPort; + uint16_t m_reverseAPIFeatureSetIndex; + uint16_t m_reverseAPIFeatureIndex; + + PERTesterSettings(); + void resetToDefaults(); + QByteArray serialize() const; + bool deserialize(const QByteArray& data); + + QByteArray serializeStringList(const QList& strings) const; + void deserializeStringList(const QByteArray& data, QList& strings); +}; + +#endif // INCLUDE_FEATURE_PERTESTERSETTINGS_H_ diff --git a/plugins/feature/pertester/pertesterwebapiadapter.cpp b/plugins/feature/pertester/pertesterwebapiadapter.cpp new file mode 100644 index 000000000..e8ec0f819 --- /dev/null +++ b/plugins/feature/pertester/pertesterwebapiadapter.cpp @@ -0,0 +1,52 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2020 Jon Beniston, M7RCE // +// Copyright (C) 2020 Edouard Griffiths, F4EXB. // +// // +// This program is free software; you can redistribute it and/or modify // +// it under the terms of the GNU General Public License as published by // +// the Free Software Foundation as version 3 of the License, or // +// (at your option) any later version. // +// // +// This program is distributed in the hope that it will be useful, // +// but WITHOUT ANY WARRANTY; without even the implied warranty of // +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // +// GNU General Public License V3 for more details. // +// // +// You should have received a copy of the GNU General Public License // +// along with this program. If not, see . // +/////////////////////////////////////////////////////////////////////////////////// + +#include "SWGFeatureSettings.h" +#include "pertester.h" +#include "pertesterwebapiadapter.h" + +PERTesterWebAPIAdapter::PERTesterWebAPIAdapter() +{} + +PERTesterWebAPIAdapter::~PERTesterWebAPIAdapter() +{} + +int PERTesterWebAPIAdapter::webapiSettingsGet( + SWGSDRangel::SWGFeatureSettings& response, + QString& errorMessage) +{ + (void) errorMessage; + response.setPerTesterSettings(new SWGSDRangel::SWGPERTesterSettings()); + response.getPerTesterSettings()->init(); + PERTester::webapiFormatFeatureSettings(response, m_settings); + + return 200; +} + +int PERTesterWebAPIAdapter::webapiSettingsPutPatch( + bool force, + const QStringList& featureSettingsKeys, + SWGSDRangel::SWGFeatureSettings& response, + QString& errorMessage) +{ + (void) force; // no action + (void) errorMessage; + PERTester::webapiUpdateFeatureSettings(m_settings, featureSettingsKeys, response); + + return 200; +} diff --git a/plugins/feature/pertester/pertesterwebapiadapter.h b/plugins/feature/pertester/pertesterwebapiadapter.h new file mode 100644 index 000000000..6afc6c150 --- /dev/null +++ b/plugins/feature/pertester/pertesterwebapiadapter.h @@ -0,0 +1,50 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2020 Jon Beniston, M7RCE // +// Copyright (C) 2020 Edouard Griffiths, F4EXB. // +// // +// This program is free software; you can redistribute it and/or modify // +// it under the terms of the GNU General Public License as published by // +// the Free Software Foundation as version 3 of the License, or // +// (at your option) any later version. // +// // +// This program is distributed in the hope that it will be useful, // +// but WITHOUT ANY WARRANTY; without even the implied warranty of // +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // +// GNU General Public License V3 for more details. // +// // +// You should have received a copy of the GNU General Public License // +// along with this program. If not, see . // +/////////////////////////////////////////////////////////////////////////////////// + +#ifndef INCLUDE_PERTESTER_WEBAPIADAPTER_H +#define INCLUDE_PERTESTER_WEBAPIADAPTER_H + +#include "feature/featurewebapiadapter.h" +#include "pertestersettings.h" + +/** + * Standalone API adapter only for the settings + */ +class PERTesterWebAPIAdapter : public FeatureWebAPIAdapter { +public: + PERTesterWebAPIAdapter(); + virtual ~PERTesterWebAPIAdapter(); + + virtual QByteArray serialize() const { return m_settings.serialize(); } + virtual bool deserialize(const QByteArray& data) { return m_settings.deserialize(data); } + + virtual int webapiSettingsGet( + SWGSDRangel::SWGFeatureSettings& response, + QString& errorMessage); + + virtual int webapiSettingsPutPatch( + bool force, + const QStringList& featureSettingsKeys, + SWGSDRangel::SWGFeatureSettings& response, + QString& errorMessage); + +private: + PERTesterSettings m_settings; +}; + +#endif // INCLUDE_PERTESTER_WEBAPIADAPTER_H diff --git a/plugins/feature/pertester/pertesterworker.cpp b/plugins/feature/pertester/pertesterworker.cpp new file mode 100644 index 000000000..ab888f0ac --- /dev/null +++ b/plugins/feature/pertester/pertesterworker.cpp @@ -0,0 +1,321 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2020 Jon Beniston, M7RCE // +// Copyright (C) 2020 Edouard Griffiths, F4EXB // +// // +// This program is free software; you can redistribute it and/or modify // +// it under the terms of the GNU General Public License as published by // +// the Free Software Foundation as version 3 of the License, or // +// (at your option) any later version. // +// // +// This program is distributed in the hope that it will be useful, // +// but WITHOUT ANY WARRANTY; without even the implied warranty of // +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // +// GNU General Public License V3 for more details. // +// // +// You should have received a copy of the GNU General Public License // +// along with this program. If not, see . // +/////////////////////////////////////////////////////////////////////////////////// + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "util/ax25.h" + +#include "pertester.h" +#include "pertesterworker.h" +#include "pertesterreport.h" + +MESSAGE_CLASS_DEFINITION(PERTesterWorker::MsgConfigurePERTesterWorker, Message) +MESSAGE_CLASS_DEFINITION(PERTesterReport::MsgReportStats, Message) + +PERTesterWorker::PERTesterWorker() : + m_msgQueueToFeature(nullptr), + m_msgQueueToGUI(nullptr), + m_running(false), + m_mutex(QMutex::Recursive), + m_rxUDPSocket(nullptr), + m_tx(0), + m_rxMatched(0), + m_rxUnmatched(0) +{ + connect(&m_inputMessageQueue, SIGNAL(messageEnqueued()), this, SLOT(handleInputMessages())); +} + +PERTesterWorker::~PERTesterWorker() +{ + closeUDP(); + disconnect(&m_inputMessageQueue, SIGNAL(messageEnqueued()), this, SLOT(handleInputMessages())); + m_inputMessageQueue.clear(); +} + +void PERTesterWorker::reset() +{ + QMutexLocker mutexLocker(&m_mutex); + m_inputMessageQueue.clear(); +} + +bool PERTesterWorker::startWork() +{ + qDebug() << "PERTesterWorker::startWork"; + QMutexLocker mutexLocker(&m_mutex); + openUDP(m_settings); + // Automatically restart if previous run had finished, otherwise continue + if (m_tx >= m_settings.m_packetCount) + resetStats(); + connect(&m_txTimer, SIGNAL(timeout()), this, SLOT(tx())); + m_txTimer.start(m_settings.m_interval * 1000.0); + m_running = true; + return m_running; +} + +void PERTesterWorker::stopWork() +{ + QMutexLocker mutexLocker(&m_mutex); + m_txTimer.stop(); + closeUDP(); + disconnect(&m_txTimer, SIGNAL(timeout()), this, SLOT(tx())); + m_running = false; +} + +void PERTesterWorker::handleInputMessages() +{ + Message* message; + + while ((message = m_inputMessageQueue.pop()) != nullptr) + { + if (handleMessage(*message)) { + delete message; + } + } +} + +void PERTesterWorker::resetStats() +{ + m_tx = 0; + m_rxMatched = 0; + m_rxUnmatched = 0; + if (getMessageQueueToGUI()) + getMessageQueueToGUI()->push(PERTesterReport::MsgReportStats::create(m_tx, m_rxMatched, m_rxUnmatched)); +} + +bool PERTesterWorker::handleMessage(const Message& cmd) +{ + if (MsgConfigurePERTesterWorker::match(cmd)) + { + QMutexLocker mutexLocker(&m_mutex); + MsgConfigurePERTesterWorker& cfg = (MsgConfigurePERTesterWorker&) cmd; + + applySettings(cfg.getSettings(), cfg.getForce()); + return true; + } + else if (PERTester::MsgResetStats::match(cmd)) + { + resetStats(); + return true; + } + else + { + return false; + } +} + +void PERTesterWorker::applySettings(const PERTesterSettings& settings, bool force) +{ + qDebug() << "PERTesterWorker::applySettings:" + << " force: " << force; + + if ( (settings.m_rxUDPAddress != m_settings.m_rxUDPAddress) + || (settings.m_rxUDPPort != m_settings.m_rxUDPPort) + || force) + { + openUDP(settings); + } + + if ((settings.m_interval != m_settings.m_interval) || force) + m_txTimer.setInterval(settings.m_interval * 1000.0); + + m_settings = settings; +} + +void PERTesterWorker::openUDP(const PERTesterSettings& settings) +{ + closeUDP(); + m_rxUDPSocket = new QUdpSocket(); + if (!m_rxUDPSocket->bind(QHostAddress(settings.m_rxUDPAddress), settings.m_rxUDPPort)) + { + qCritical() << "PERTesterWorker::openUDP: Failed to bind to port " << settings.m_rxUDPAddress << ":" << settings.m_rxUDPPort << ". Error: " << m_rxUDPSocket->error(); + if (m_msgQueueToFeature) + m_msgQueueToFeature->push(PERTester::MsgReportWorker::create(QString("Failed to bind to port %1:%2 - %3").arg(settings.m_rxUDPAddress).arg(settings.m_rxUDPPort).arg(m_rxUDPSocket->error()))); + } + else + qDebug() << "PERTesterWorker::openUDP: Listening on port " << settings.m_rxUDPAddress << ":" << settings.m_rxUDPPort << "."; + connect(m_rxUDPSocket, &QUdpSocket::readyRead, this, &PERTesterWorker::rx); +} + +void PERTesterWorker::closeUDP() +{ + if (m_rxUDPSocket != nullptr) + { + qDebug() << "PERTesterWorker::closeUDP: Closing port " << m_settings.m_rxUDPAddress << ":" << m_settings.m_rxUDPPort << "."; + disconnect(m_rxUDPSocket, &QUdpSocket::readyRead, this, &PERTesterWorker::rx); + delete m_rxUDPSocket; + m_rxUDPSocket = nullptr; + } +} + +void PERTesterWorker::rx() +{ + while (m_rxUDPSocket->hasPendingDatagrams()) + { + QNetworkDatagram datagram = m_rxUDPSocket->receiveDatagram(); + QByteArray packet = datagram.data(); + // Ignore header and CRC, if requested + packet = packet.mid(m_settings.m_ignoreLeadingBytes, packet.size() - m_settings.m_ignoreLeadingBytes - m_settings.m_ignoreTrailingBytes); + // Remove from list of transmitted packets + int i; + for (i = 0; i < m_txPackets.size(); i++) + { + if (packet == m_txPackets[i]) + { + m_rxMatched++; + m_txPackets.removeAt(i); + break; + } + } + if (i == m_txPackets.size()) + { + qDebug() << "PERTesterWorker::rx: Received packet that was not transmitted: " << packet.toHex(); + m_rxUnmatched++; + } + } + if (getMessageQueueToGUI()) + getMessageQueueToGUI()->push(PERTesterReport::MsgReportStats::create(m_tx, m_rxMatched, m_rxUnmatched)); +} + +void PERTesterWorker::tx() +{ + QRegExp ax25Dst("^%\\{ax25\\.dst=([A-Za-z0-9-]+)\\}"); + QRegExp ax25Src("^%\\{ax25\\.src=([A-Za-z0-9-]+)\\}"); + QRegExp num("^%\\{num\\}"); + QRegExp data("^%\\{data=([0-9]+),([0-9]+)\\}"); + QRegExp hex("^(0x)?([0-9a-fA-F]?[0-9a-fA-F])"); + QByteArray bytes; + int pos = 0; + + while (pos < m_settings.m_packet.size()) + { + if (m_settings.m_packet[pos] == '%') + { + if (ax25Dst.indexIn(m_settings.m_packet, pos, QRegExp::CaretAtOffset) != -1) + { + // AX.25 destination callsign & SSID + QString address = ax25Dst.capturedTexts()[1]; + bytes.append(AX25Packet::encodeAddress(address)); + pos += ax25Dst.matchedLength(); + } + else if (ax25Src.indexIn(m_settings.m_packet, pos, QRegExp::CaretAtOffset) != -1) + { + // AX.25 source callsign & SSID + QString address = ax25Src.capturedTexts()[1]; + bytes.append(AX25Packet::encodeAddress(address, 1)); + pos += ax25Src.matchedLength(); + } + else if (num.indexIn(m_settings.m_packet, pos, QRegExp::CaretAtOffset) != -1) + { + // Big endian packet number + bytes.append((m_tx >> 24) & 0xff); + bytes.append((m_tx >> 16) & 0xff); + bytes.append((m_tx >> 8) & 0xff); + bytes.append(m_tx & 0xff); + pos += num.matchedLength(); + } + else if (data.indexIn(m_settings.m_packet, pos, QRegExp::CaretAtOffset) != -1) + { + // Constrained random number of random bytes + int minBytes = data.capturedTexts()[1].toInt(); + int maxBytes = data.capturedTexts()[2].toInt(); + std::random_device rd; + std::mt19937 gen(rd()); + std::uniform_int_distribution<> distr0(minBytes, maxBytes); + std::uniform_int_distribution<> distr1(0, 255); + int count = distr0(gen); + for (int i = 0; i < count; i++) + bytes.append(distr1(gen)); + pos += data.matchedLength(); + } + else + { + qWarning() << "PERTester: Unsupported substitution in packet: pos=" << pos << " in " << m_settings.m_packet; + break; + } + } + else if (m_settings.m_packet[pos] == '\"') + { + // ASCII string in double quotes + int startIdx = pos + 1; + int endQuoteIdx = m_settings.m_packet.indexOf('\"', startIdx); + if (endQuoteIdx != -1) + { + int len = endQuoteIdx - startIdx; + QString string = m_settings.m_packet.mid(startIdx, len); + bytes.append(string.toLocal8Bit()); + pos = endQuoteIdx + 1; + } + else + { + qWarning() << "PERTester: Unterminated string: pos=" << pos << " in " << m_settings.m_packet; + break; + } + } + else if (hex.indexIn(m_settings.m_packet, pos, QRegExp::CaretAtOffset) != -1) + { + // Hex byte + int value = hex.capturedTexts()[2].toInt(nullptr, 16); + bytes.append(value); + pos += hex.matchedLength(); + } + else if ((m_settings.m_packet[pos] == ' ') || (m_settings.m_packet[pos] == ',') || (m_settings.m_packet[pos] == ':')) + { + pos++; + } + else + { + qWarning() << "PERTester: Unexpected character in packet: pos=" << pos << " in " << m_settings.m_packet; + break; + } + } + + if ((pos >= m_settings.m_packet.size()) && (m_tx < m_settings.m_packetCount)) + { + // Send packet via UDP + m_txUDPSocket.writeDatagram(bytes.data(), bytes.size(), QHostAddress(m_settings.m_txUDPAddress), m_settings.m_txUDPPort); + m_tx++; + m_txPackets.append(bytes); + if (getMessageQueueToGUI()) + getMessageQueueToGUI()->push(PERTesterReport::MsgReportStats::create(m_tx, m_rxMatched, m_rxUnmatched)); + } + + if (m_tx >= m_settings.m_packetCount) + { + // Test complete + m_txTimer.stop(); + // Wait for a couple of seconds for the last packet to be received + QTimer::singleShot(2000, this, &PERTesterWorker::testComplete); + } +} + +void PERTesterWorker::testComplete() +{ + stopWork(); + if (m_msgQueueToFeature != nullptr) + m_msgQueueToFeature->push(PERTester::MsgReportWorker::create("Complete")); + qDebug() << "PERTesterWorker::tx: Test complete"; +} diff --git a/plugins/feature/pertester/pertesterworker.h b/plugins/feature/pertester/pertesterworker.h new file mode 100644 index 000000000..7f6c0110c --- /dev/null +++ b/plugins/feature/pertester/pertesterworker.h @@ -0,0 +1,98 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2020 Jon Beniston, M7RCE // +// Copyright (C) 2020 Edouard Griffiths, F4EXB // +// // +// This program is free software; you can redistribute it and/or modify // +// it under the terms of the GNU General Public License as published by // +// the Free Software Foundation as version 3 of the License, or // +// (at your option) any later version. // +// // +// This program is distributed in the hope that it will be useful, // +// but WITHOUT ANY WARRANTY; without even the implied warranty of // +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // +// GNU General Public License V3 for more details. // +// // +// You should have received a copy of the GNU General Public License // +// along with this program. If not, see . // +/////////////////////////////////////////////////////////////////////////////////// + +#ifndef INCLUDE_FEATURE_PERTESTERWORKER_H_ +#define INCLUDE_FEATURE_PERTESTERWORKER_H_ + +#include +#include +#include + +#include "util/message.h" +#include "util/messagequeue.h" + +#include "pertestersettings.h" + +class PERTesterWorker : public QObject +{ + Q_OBJECT +public: + class MsgConfigurePERTesterWorker : public Message { + MESSAGE_CLASS_DECLARATION + + public: + const PERTesterSettings& getSettings() const { return m_settings; } + bool getForce() const { return m_force; } + + static MsgConfigurePERTesterWorker* create(const PERTesterSettings& settings, bool force) + { + return new MsgConfigurePERTesterWorker(settings, force); + } + + private: + PERTesterSettings m_settings; + bool m_force; + + MsgConfigurePERTesterWorker(const PERTesterSettings& settings, bool force) : + Message(), + m_settings(settings), + m_force(force) + { } + }; + + PERTesterWorker(); + ~PERTesterWorker(); + void reset(); + bool startWork(); + void stopWork(); + bool isRunning() const { return m_running; } + MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; } + void setMessageQueueToFeature(MessageQueue *messageQueue) { m_msgQueueToFeature = messageQueue; } + void setMessageQueueToGUI(MessageQueue *messageQueue) { m_msgQueueToGUI = messageQueue; } + +private: + + MessageQueue m_inputMessageQueue; + MessageQueue *m_msgQueueToFeature; + MessageQueue *m_msgQueueToGUI; + PERTesterSettings m_settings; + bool m_running; + QMutex m_mutex; + QUdpSocket *m_rxUDPSocket; //!< UDP socket to receive packets on + QUdpSocket m_txUDPSocket; + QTimer m_txTimer; + int m_tx; //!< Number of packets we've transmitted + int m_rxMatched; //!< Number of packets we've received that match a transmitted packet + int m_rxUnmatched; //!< Number of packets received that didn't match a transmitted packet + QList m_txPackets; //!< Packets we've transmitted, but not yet received + + bool handleMessage(const Message& cmd); + void applySettings(const PERTesterSettings& settings, bool force = false); + MessageQueue *getMessageQueueToGUI() { return m_msgQueueToGUI; } + void openUDP(const PERTesterSettings& settings); + void closeUDP(); + void resetStats(); + +private slots: + void handleInputMessages(); + void rx(); + void tx(); + void testComplete(); +}; + +#endif // INCLUDE_FEATURE_PERTESTERWORKER_H_ diff --git a/plugins/feature/pertester/readme.md b/plugins/feature/pertester/readme.md new file mode 100644 index 000000000..100b1e6fd --- /dev/null +++ b/plugins/feature/pertester/readme.md @@ -0,0 +1,103 @@ +

Packer Error Rate (PER) Tester Feature Plugin

+ +

Introduction

+ +The Packet Error Rate (PER) Tester feature can be used to measure the packet error rate over digital, packet based protcols such as AX.25 (Packet mod/demod), LoRa (ChipChat mod/demod) and 802.15.4. + +The PER Tester feature allows you to define the contents of the packets to transmit, which can include a per-packet 32-bit identifier, as well as a user-defined or random payload, how many packets are sent and the interval between them. + +Packets are sent and received from the feature to modulators and demodulators via UDP. This allows the transmitter or receiver to be connected to remote computer. + +

Interface

+ +![PER Tester feature plugin GUI](../../../doc/img/PERTester_plugin.png) + +

1: Start/Stop plugin

+ +This button starts or stops the PER test. If when starting the test, the number of transmitted packets is equal to the number of packets to transmit, the statistics will be reset and the test restarted. Otherwise, the test will be resumed. + +

2: Reset Statistics

+ +Pressing the reset statistics button will clear the number of packets transmitted and received. + +

3: Packets

+ +Specify the number of packets to transmit. + +

4: Start test

+ +Controls when the test is started, after the start button (1) is pressed. This can be either: + +* Immediately +* On satellite AOS (Acquistion of signal) +* On satellite mid pass ((AOS-LOS)/2) + +When either satellite option is selected, the Satellites field appears, allowing you to enter the names of satellites which should start the test. + +

5: Interval

+ +Specify the interval in seconds between packet transmissions. + +

6: Packet

+ +Specify the contents of the packet to transmit and expect to be received. Data should be entered in hexidecimal bytes (E.g: 00 11 22 33 44). + +The exact format required will depend on the underlying protocol being used. For AX.25 using the Packet modulator, LoRo using the ChirpChat modulator and 802.15.4, it is not necessary to include the trailing CRC, as this is appended automatically by the SDRangel modulators. + +Aside from hex values, a number of variables can be used: + +* %{num} - Inserts a 32-bit packet identifier, that counts from 0 to the number of packets to be transmitted minus 1. +* %{data=n,m} - Inserts a random number of bytes, ranging in length from n to m bytes. +* %{ax25.dst=MYCALL} - Encodes the callsign MYCALL as an AX.25 destination address. +* %{ax25.src=MYCALL} - Encodes the callsign MYCALL as an AX.25 source address. +* "some text" - Encode the string contained within the quotes as ASCII. + +As an example, for AX.25, the following packet could be used: + + %{ax25.dst=MYCALL} %{ax25.src=MYCALL} 03 f0 %{num} "Hello" %{data=0,100} + +This: + +* Encodes MYCALL as a 7-byte AX.25 destination address. +* Encodes MYCALL as a 7-byte AX.25 source address. +* Inserts hex value 0x03. +* Inserts hex value 0xf0. +* Inserts a 32-bit packet identifer. +* Inserts the 5 bytes of the ASCII encoding of Hello. +* Inserts a random payload of between 0 and 100 bytes. + +

7: Ignore Leading and Trailing bytes

+ +When the PER Tester receives a packet, it compares it against a list of packets that it has transmitted. The ignore Leading and Trailing bytes field, reduce the number of bytes in the received packet, used for this comparison. + +This can be used in cases where the demodulator outputs a different byte sequence than what the modulator requires. For example, the Packet Modulator does not require the CRC to be included, but the Packet Demodulator includes the CRC in the packet it outputs. Therefore, for the packet to match, the trailing two bytes should be ignored. + +* For AX.25 (with Packet mod/demod), set Leading to 0 and Trailing to 2. +* For LoRa (with ChirpChat mod/demod), set Leading to 0 and Trailing to 0. + +

8: TX UDP port

+ +Specifies the IP address and UDP port number of the modulator to send to packets to, to be transmitted. + +

9: RX UDP port

+ +Specifies the IP address and UDP port number of the demodulator to receive packets from. + +

Statistics

+ +The statistics fields display the statistics for the current test: + +* Transmitted - number of packets transmitted. +* Received and Matched - number of packets received that matched a packet that was transmitted. +* Received and Unmatched - number of packets received that did not match a packet that was transmitted. +* PER - packet error rate - calculated as 100-(matched/transmitted)*100. + +

API

+ +Full details of the API can be found in the Swagger documentation. Here is a quick example of how to set the azimuth and elevation from the command line: + + curl -X PATCH "http://127.0.0.1:8091/sdrangel/featureset/0/feature/0/settings" -d '{"featureType": "PERTester", "PERTesterSettings": { "packetCount": 100 }}' + +To start sending the test: + + curl -X POST "http://127.0.0.1:8091/sdrangel/featureset/0/feature/0/run" diff --git a/sdrbase/webapi/webapirequestmapper.cpp b/sdrbase/webapi/webapirequestmapper.cpp index deb13f9bc..0c16ec371 100644 --- a/sdrbase/webapi/webapirequestmapper.cpp +++ b/sdrbase/webapi/webapirequestmapper.cpp @@ -4410,6 +4410,11 @@ bool WebAPIRequestMapper::getFeatureSettings( featureSettings->setMapSettings(new SWGSDRangel::SWGMapSettings()); featureSettings->getMapSettings()->fromJsonObject(settingsJsonObject); } + else if (featureSettingsKey == "PERTesterSettings") + { + featureSettings->setPerTesterSettings(new SWGSDRangel::SWGPERTesterSettings()); + featureSettings->getPerTesterSettings()->fromJsonObject(settingsJsonObject); + } else if (featureSettingsKey == "SimplePTTSettings") { featureSettings->setSimplePttSettings(new SWGSDRangel::SWGSimplePTTSettings()); @@ -4655,6 +4660,7 @@ void WebAPIRequestMapper::resetFeatureSettings(SWGSDRangel::SWGFeatureSettings& featureSettings.setAprsSettings(nullptr); featureSettings.setGs232ControllerSettings(nullptr); featureSettings.setMapSettings(nullptr); + featureSettings.setPerTesterSettings(nullptr); featureSettings.setSimplePttSettings(nullptr); featureSettings.setStarTrackerSettings(nullptr); featureSettings.setRigCtlServerSettings(nullptr); diff --git a/sdrbase/webapi/webapiutils.cpp b/sdrbase/webapi/webapiutils.cpp index f30c70cb4..b5b1d5214 100644 --- a/sdrbase/webapi/webapiutils.cpp +++ b/sdrbase/webapi/webapiutils.cpp @@ -247,6 +247,7 @@ const QMap WebAPIUtils::m_featureTypeToSettingsKey = { {"APRS", "APRSSettings"}, {"GS232Controller", "GS232ControllerSettings"}, {"Map", "MapSettings"}, + {"PERTester", "PERTesterSettings"}, {"SimplePTT", "SimplePTTSettings"}, {"StarTracker", "StarTrackerSettings"}, {"RigCtlServer", "RigCtlServerSettings"} @@ -261,6 +262,7 @@ const QMap WebAPIUtils::m_featureURIToSettingsKey = { {"sdrangel.feature.aprs", "APRSSettings"}, {"sdrangel.feature.gs232controller", "GS232ControllerSettings"}, {"sdrangel.feature.map", "MapSettings"}, + {"sdrangel.feature.pertester", "PERTesterSettings"}, {"sdrangel.feature.simpleptt", "SimplePTTSettings"}, {"sdrangel.feature.startracker", "StarTrackerSettings"}, {"sdrangel.feature.rigctlserver", "RigCtlServerSettings"} diff --git a/swagger/sdrangel/api/swagger/include/FeatureActions.yaml b/swagger/sdrangel/api/swagger/include/FeatureActions.yaml index 0d9b38e3a..32a5fc094 100644 --- a/swagger/sdrangel/api/swagger/include/FeatureActions.yaml +++ b/swagger/sdrangel/api/swagger/include/FeatureActions.yaml @@ -17,5 +17,7 @@ FeatureActions: $ref: "http://swgserver:8081/api/swagger/include/AFC.yaml#/AFCActions" MapActions: $ref: "http://swgserver:8081/api/swagger/include/Map.yaml#/MapActions" + PERTesterActions: + $ref: "http://swgserver:8081/api/swagger/include/PERTester.yaml#/PERTesterActions" SimplePTTActions: $ref: "http://swgserver:8081/api/swagger/include/SimplePTT.yaml#/SimplePTTActions" diff --git a/swagger/sdrangel/api/swagger/include/FeatureSettings.yaml b/swagger/sdrangel/api/swagger/include/FeatureSettings.yaml index 9cbaa9f35..ceaf98c74 100644 --- a/swagger/sdrangel/api/swagger/include/FeatureSettings.yaml +++ b/swagger/sdrangel/api/swagger/include/FeatureSettings.yaml @@ -23,6 +23,8 @@ FeatureSettings: $ref: "http://swgserver:8081/api/swagger/include/GS232Controller.yaml#/GS232ControllerSettings" MapSettings: $ref: "http://swgserver:8081/api/swagger/include/Map.yaml#/MapSettings" + PERTesterSettings: + $ref: "http://swgserver:8081/api/swagger/include/PERTester.yaml#/PERTesterSettings" RigCtlServerSettings: $ref: "http://swgserver:8081/api/swagger/include/RigCtlServer.yaml#/RigCtlServerSettings" SatelliteTrackerSettings: diff --git a/swagger/sdrangel/api/swagger/include/PERTester.yaml b/swagger/sdrangel/api/swagger/include/PERTester.yaml new file mode 100644 index 000000000..20e5d3fbb --- /dev/null +++ b/swagger/sdrangel/api/swagger/include/PERTester.yaml @@ -0,0 +1,67 @@ +PERTesterSettings: + description: "PER Tester settings" + properties: + packetCount: + type: integer + interval: + type: number + format: float + start: + description: "0 - immediately, 1 - on satellite AOS, 2 - on satellite mid pass" + type: integer + satellites: + description: "Satellite names to start test on" + type: array + items: + type: string + packet: + description: "Packet of data to send" + type: string + ignoreLeadingBytes: + type: integer + ignoreTrailingBytes: + type: integer + txUDPAddress: + description: "UDP address to sent packets to be transmitted to" + type: string + txUDPPort: + description: "UDP port to sent packets to be transmitted to" + type: integer + rxUDPAddress: + description: "UDP address to receive packets via" + type: string + rxUDPPort: + description: "UDP port to receive packets via" + type: integer + title: + type: string + rgbColor: + type: integer + useReverseAPI: + description: Synchronize with reverse API (1 for yes, 0 for no) + type: integer + reverseAPIAddress: + type: string + reverseAPIPort: + type: integer + reverseAPIDeviceIndex: + type: integer + reverseAPIChannelIndex: + type: integer + +PERTesterActions: + description: PERTester + properties: + aos: + description: "Acquisition of signal" + type: object + properties: + satelliteName: + description: "Name of the satellite" + type: string + aosTime: + description: "Time of AOS" + type: string + losTime: + description: "Time of LOS" + type: string diff --git a/swagger/sdrangel/code/html2/index.html b/swagger/sdrangel/code/html2/index.html index 9a1f4a958..635abc699 100644 --- a/swagger/sdrangel/code/html2/index.html +++ b/swagger/sdrangel/code/html2/index.html @@ -3256,6 +3256,18 @@ margin-bottom: 20px; "type" : "integer", "description" : "number of repetitions of the same message (0 for infinite)" }, + "udpEnabled" : { + "type" : "integer", + "description" : "boolean 1 to enable forwarding messages via UDP else 0" + }, + "udpAddress" : { + "type" : "string", + "description" : "UDP address to listen for messages to transmit on" + }, + "udpPort" : { + "type" : "integer", + "description" : "UDP port to listen for messages to transmit on" + }, "rgbColor" : { "type" : "integer" }, @@ -3346,35 +3358,19 @@ margin-bottom: 20px; }, "standard" : { "type" : "integer", - "description" : "DVB bersion (see DATVDemodSettings::dvb_version)\n * 0 - DVB-S\n * 1 - DVB-S2\n" + "description" : "see DATVDemodSettings::dvb_version" }, "modulation" : { "type" : "integer", - "description" : "Modulation type (DATVDemodSettings::DATVModulation)\n * 0 - BPSK\n * 1 - QPSK\n * 2 - PSK8\n * 3 - APSK16\n * 4 - APSK32\n * 5 - APSK64E\n * 6 - QAM16\n * 7 - QAM64\n * 8 - QAM256\n" + "description" : "see DATVDemodSettings::DATVModulation" }, "fec" : { "type" : "integer", - "description" : "FEC rate (see DATVDemodSettings::DATVCodeRate)\n * 0 - 1/2\n * 1 - 2/3\n * 2 - 4/6\n * 3 - 3/4\n * 4 - 4/6\n * 5 - 7/8\n * 6 - 4/5\n * 7 - 8/9\n * 8 - 9/10\n * 9 - 1/4\n * 10 - 1/3\n * 11 - 2/5\n * 12 - 3/5\n" - }, - "softLDPC" : { - "type" : "integer", - "description" : "(boolean) engage sodt LDPC with LDPC tool sub processes (Linux only)" - }, - "softLDPCToolPath" : { - "type" : "string", - "description" : "O/S path to the LDPC tool binary" - }, - "softLDPCMaxTrials" : { - "type" : "integer", - "description" : "maximum number of trials in the soft LDPC algorithm (LDPC tool parameter)" - }, - "maxBitflips" : { - "type" : "integer", - "description" : "maximum number of bit flips allowed in hard LDPC algorithm" + "description" : "see DATVDemodSettings::DATVCodeRate" }, "audioMute" : { "type" : "integer", - "description" : "(boolean) mute audio output" + "description" : "boolean" }, "audioDeviceName" : { "type" : "string" @@ -3387,28 +3383,27 @@ margin-bottom: 20px; }, "allowDrift" : { "type" : "integer", - "description" : "(boolean) allow a larger frequency drift (DVB-S)" + "description" : "boolean" }, "fastLock" : { "type" : "integer", - "description" : "(boolean) faster locking algorithm (DVB-S)" + "description" : "boolean" }, "filter" : { "type" : "integer", - "description" : "Type of sumbol filtering (see DATVDemodSettings::dvb_sampler)\n * 0 - Nearest\n * 1 - Linear\n * 2 - Root Raised Cosine\n" + "description" : "see DATVDemodSettings::dvb_sampler" }, "hardMetric" : { "type" : "integer", - "description" : "(boolean) (DVB-S)" + "description" : "boolean" }, "rollOff" : { "type" : "number", - "format" : "float", - "description" : "RRC filter roll-off factor (0..1)" + "format" : "float" }, "viterbi" : { "type" : "integer", - "description" : "(boolean) (DVB-S)" + "description" : "boolean" }, "excursion" : { "type" : "integer" @@ -3429,26 +3424,6 @@ margin-bottom: 20px; "udpTS" : { "type" : "integer", "description" : "boolean" - }, - "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" } }, "description" : "DATVDemod" @@ -4352,6 +4327,9 @@ margin-bottom: 20px; "MapActions" : { "$ref" : "#/definitions/MapActions" }, + "PERTesterActions" : { + "$ref" : "#/definitions/PERTesterActions" + }, "SimplePTTActions" : { "$ref" : "#/definitions/SimplePTTActions" } @@ -4468,6 +4446,9 @@ margin-bottom: 20px; "MapSettings" : { "$ref" : "#/definitions/MapSettings" }, + "PERTesterSettings" : { + "$ref" : "#/definitions/PERTesterSettings" + }, "RigCtlServerSettings" : { "$ref" : "#/definitions/RigCtlServerSettings" }, @@ -5466,6 +5447,18 @@ margin-bottom: 20px; "type" : "integer", "description" : "Number of times to repeat the frame (-1 for infinite)." }, + "udpEnabled" : { + "type" : "integer", + "description" : "Enable forwarding of frames via UDP" + }, + "udpAddress" : { + "type" : "string", + "description" : "UDP address to listen for frames to transmit on" + }, + "udpPort" : { + "type" : "integer", + "description" : "UDP port to listen for frames to transmit on" + }, "rgbColor" : { "type" : "integer" }, @@ -7092,6 +7085,102 @@ margin-bottom: 20px; } }, "description" : "Enumeration with name for values" +}; + defs.PERTesterActions = { + "properties" : { + "aos" : { + "$ref" : "#/definitions/PERTesterActions_aos" + } + }, + "description" : "PERTester" +}; + defs.PERTesterActions_aos = { + "properties" : { + "satelliteName" : { + "type" : "string", + "description" : "Name of the satellite" + }, + "aosTime" : { + "type" : "string", + "description" : "Time of AOS" + }, + "losTime" : { + "type" : "string", + "description" : "Time of LOS" + } + }, + "description" : "Acquisition of signal" +}; + defs.PERTesterSettings = { + "properties" : { + "packetCount" : { + "type" : "integer" + }, + "interval" : { + "type" : "number", + "format" : "float" + }, + "start" : { + "type" : "integer", + "description" : "0 - immediately, 1 - on satellite AOS, 2 - on satellite mid pass" + }, + "satellites" : { + "type" : "array", + "description" : "Satellite names to start test on", + "items" : { + "type" : "string" + } + }, + "packet" : { + "type" : "string", + "description" : "Packet of data to send" + }, + "ignoreLeadingBytes" : { + "type" : "integer" + }, + "ignoreTrailingBytes" : { + "type" : "integer" + }, + "txUDPAddress" : { + "type" : "string", + "description" : "UDP address to sent packets to be transmitted to" + }, + "txUDPPort" : { + "type" : "integer", + "description" : "UDP port to sent packets to be transmitted to" + }, + "rxUDPAddress" : { + "type" : "string", + "description" : "UDP address to receive packets via" + }, + "rxUDPPort" : { + "type" : "integer", + "description" : "UDP port to receive packets via" + }, + "title" : { + "type" : "string" + }, + "rgbColor" : { + "type" : "integer" + }, + "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" + } + }, + "description" : "PER Tester settings" }; defs.PacketDemodSettings = { "properties" : { @@ -7111,6 +7200,18 @@ margin-bottom: 20px; "type" : "number", "format" : "float" }, + "udpEnabled" : { + "type" : "integer", + "description" : "Whether to forward received packets to specified UDP port" + }, + "udpAddress" : { + "type" : "string", + "description" : "UDP address to forward received packets to" + }, + "udpPort" : { + "type" : "integer", + "description" : "UDP port to forward received packets to" + }, "rgbColor" : { "type" : "integer" }, @@ -7320,6 +7421,18 @@ margin-bottom: 20px; "symbolSpan" : { "type" : "integer" }, + "udpEnabled" : { + "type" : "integer", + "description" : "Whether to receive packets to transmit on specified UDP port" + }, + "udpAddress" : { + "type" : "string", + "description" : "UDP address to receive packets to transmit via" + }, + "udpPort" : { + "type" : "integer", + "description" : "UDP port to receive packets to transmit via" + }, "rgbColor" : { "type" : "integer" }, @@ -45779,7 +45892,7 @@ except ApiException as e:
- Generated 2021-04-01T20:39:21.587+02:00 + Generated 2021-04-02T23:43:06.310+02:00
diff --git a/swagger/sdrangel/code/qt5/client/SWGFeatureActions.cpp b/swagger/sdrangel/code/qt5/client/SWGFeatureActions.cpp index f4f0a2fe7..d61db2da1 100644 --- a/swagger/sdrangel/code/qt5/client/SWGFeatureActions.cpp +++ b/swagger/sdrangel/code/qt5/client/SWGFeatureActions.cpp @@ -38,6 +38,8 @@ SWGFeatureActions::SWGFeatureActions() { m_afc_actions_isSet = false; map_actions = nullptr; m_map_actions_isSet = false; + per_tester_actions = nullptr; + m_per_tester_actions_isSet = false; simple_ptt_actions = nullptr; m_simple_ptt_actions_isSet = false; } @@ -58,6 +60,8 @@ SWGFeatureActions::init() { m_afc_actions_isSet = false; map_actions = new SWGMapActions(); m_map_actions_isSet = false; + per_tester_actions = new SWGPERTesterActions(); + m_per_tester_actions_isSet = false; simple_ptt_actions = new SWGSimplePTTActions(); m_simple_ptt_actions_isSet = false; } @@ -75,6 +79,9 @@ SWGFeatureActions::cleanup() { if(map_actions != nullptr) { delete map_actions; } + if(per_tester_actions != nullptr) { + delete per_tester_actions; + } if(simple_ptt_actions != nullptr) { delete simple_ptt_actions; } @@ -101,6 +108,8 @@ SWGFeatureActions::fromJsonObject(QJsonObject &pJson) { ::SWGSDRangel::setValue(&map_actions, pJson["MapActions"], "SWGMapActions", "SWGMapActions"); + ::SWGSDRangel::setValue(&per_tester_actions, pJson["PERTesterActions"], "SWGPERTesterActions", "SWGPERTesterActions"); + ::SWGSDRangel::setValue(&simple_ptt_actions, pJson["SimplePTTActions"], "SWGSimplePTTActions", "SWGSimplePTTActions"); } @@ -134,6 +143,9 @@ SWGFeatureActions::asJsonObject() { if((map_actions != nullptr) && (map_actions->isSet())){ toJsonValue(QString("MapActions"), map_actions, obj, QString("SWGMapActions")); } + if((per_tester_actions != nullptr) && (per_tester_actions->isSet())){ + toJsonValue(QString("PERTesterActions"), per_tester_actions, obj, QString("SWGPERTesterActions")); + } if((simple_ptt_actions != nullptr) && (simple_ptt_actions->isSet())){ toJsonValue(QString("SimplePTTActions"), simple_ptt_actions, obj, QString("SWGSimplePTTActions")); } @@ -191,6 +203,16 @@ SWGFeatureActions::setMapActions(SWGMapActions* map_actions) { this->m_map_actions_isSet = true; } +SWGPERTesterActions* +SWGFeatureActions::getPerTesterActions() { + return per_tester_actions; +} +void +SWGFeatureActions::setPerTesterActions(SWGPERTesterActions* per_tester_actions) { + this->per_tester_actions = per_tester_actions; + this->m_per_tester_actions_isSet = true; +} + SWGSimplePTTActions* SWGFeatureActions::getSimplePttActions() { return simple_ptt_actions; @@ -221,6 +243,9 @@ SWGFeatureActions::isSet(){ if(map_actions && map_actions->isSet()){ isObjectUpdated = true; break; } + if(per_tester_actions && per_tester_actions->isSet()){ + isObjectUpdated = true; break; + } if(simple_ptt_actions && simple_ptt_actions->isSet()){ isObjectUpdated = true; break; } diff --git a/swagger/sdrangel/code/qt5/client/SWGFeatureActions.h b/swagger/sdrangel/code/qt5/client/SWGFeatureActions.h index 1d980a669..9c047f7b9 100644 --- a/swagger/sdrangel/code/qt5/client/SWGFeatureActions.h +++ b/swagger/sdrangel/code/qt5/client/SWGFeatureActions.h @@ -24,6 +24,7 @@ #include "SWGAFCActions.h" #include "SWGMapActions.h" +#include "SWGPERTesterActions.h" #include "SWGSimplePTTActions.h" #include @@ -60,6 +61,9 @@ public: SWGMapActions* getMapActions(); void setMapActions(SWGMapActions* map_actions); + SWGPERTesterActions* getPerTesterActions(); + void setPerTesterActions(SWGPERTesterActions* per_tester_actions); + SWGSimplePTTActions* getSimplePttActions(); void setSimplePttActions(SWGSimplePTTActions* simple_ptt_actions); @@ -82,6 +86,9 @@ private: SWGMapActions* map_actions; bool m_map_actions_isSet; + SWGPERTesterActions* per_tester_actions; + bool m_per_tester_actions_isSet; + SWGSimplePTTActions* simple_ptt_actions; bool m_simple_ptt_actions_isSet; diff --git a/swagger/sdrangel/code/qt5/client/SWGFeatureSettings.cpp b/swagger/sdrangel/code/qt5/client/SWGFeatureSettings.cpp index a7b1fd4a4..68846af33 100644 --- a/swagger/sdrangel/code/qt5/client/SWGFeatureSettings.cpp +++ b/swagger/sdrangel/code/qt5/client/SWGFeatureSettings.cpp @@ -44,6 +44,8 @@ SWGFeatureSettings::SWGFeatureSettings() { m_gs232_controller_settings_isSet = false; map_settings = nullptr; m_map_settings_isSet = false; + per_tester_settings = nullptr; + m_per_tester_settings_isSet = false; rig_ctl_server_settings = nullptr; m_rig_ctl_server_settings_isSet = false; satellite_tracker_settings = nullptr; @@ -78,6 +80,8 @@ SWGFeatureSettings::init() { m_gs232_controller_settings_isSet = false; map_settings = new SWGMapSettings(); m_map_settings_isSet = false; + per_tester_settings = new SWGPERTesterSettings(); + m_per_tester_settings_isSet = false; rig_ctl_server_settings = new SWGRigCtlServerSettings(); m_rig_ctl_server_settings_isSet = false; satellite_tracker_settings = new SWGSatelliteTrackerSettings(); @@ -112,6 +116,9 @@ SWGFeatureSettings::cleanup() { if(map_settings != nullptr) { delete map_settings; } + if(per_tester_settings != nullptr) { + delete per_tester_settings; + } if(rig_ctl_server_settings != nullptr) { delete rig_ctl_server_settings; } @@ -156,6 +163,8 @@ SWGFeatureSettings::fromJsonObject(QJsonObject &pJson) { ::SWGSDRangel::setValue(&map_settings, pJson["MapSettings"], "SWGMapSettings", "SWGMapSettings"); + ::SWGSDRangel::setValue(&per_tester_settings, pJson["PERTesterSettings"], "SWGPERTesterSettings", "SWGPERTesterSettings"); + ::SWGSDRangel::setValue(&rig_ctl_server_settings, pJson["RigCtlServerSettings"], "SWGRigCtlServerSettings", "SWGRigCtlServerSettings"); ::SWGSDRangel::setValue(&satellite_tracker_settings, pJson["SatelliteTrackerSettings"], "SWGSatelliteTrackerSettings", "SWGSatelliteTrackerSettings"); @@ -206,6 +215,9 @@ SWGFeatureSettings::asJsonObject() { if((map_settings != nullptr) && (map_settings->isSet())){ toJsonValue(QString("MapSettings"), map_settings, obj, QString("SWGMapSettings")); } + if((per_tester_settings != nullptr) && (per_tester_settings->isSet())){ + toJsonValue(QString("PERTesterSettings"), per_tester_settings, obj, QString("SWGPERTesterSettings")); + } if((rig_ctl_server_settings != nullptr) && (rig_ctl_server_settings->isSet())){ toJsonValue(QString("RigCtlServerSettings"), rig_ctl_server_settings, obj, QString("SWGRigCtlServerSettings")); } @@ -305,6 +317,16 @@ SWGFeatureSettings::setMapSettings(SWGMapSettings* map_settings) { this->m_map_settings_isSet = true; } +SWGPERTesterSettings* +SWGFeatureSettings::getPerTesterSettings() { + return per_tester_settings; +} +void +SWGFeatureSettings::setPerTesterSettings(SWGPERTesterSettings* per_tester_settings) { + this->per_tester_settings = per_tester_settings; + this->m_per_tester_settings_isSet = true; +} + SWGRigCtlServerSettings* SWGFeatureSettings::getRigCtlServerSettings() { return rig_ctl_server_settings; @@ -384,6 +406,9 @@ SWGFeatureSettings::isSet(){ if(map_settings && map_settings->isSet()){ isObjectUpdated = true; break; } + if(per_tester_settings && per_tester_settings->isSet()){ + isObjectUpdated = true; break; + } if(rig_ctl_server_settings && rig_ctl_server_settings->isSet()){ isObjectUpdated = true; break; } diff --git a/swagger/sdrangel/code/qt5/client/SWGFeatureSettings.h b/swagger/sdrangel/code/qt5/client/SWGFeatureSettings.h index b746d3c67..c9fb52814 100644 --- a/swagger/sdrangel/code/qt5/client/SWGFeatureSettings.h +++ b/swagger/sdrangel/code/qt5/client/SWGFeatureSettings.h @@ -27,6 +27,7 @@ #include "SWGDemodAnalyzerSettings.h" #include "SWGGS232ControllerSettings.h" #include "SWGMapSettings.h" +#include "SWGPERTesterSettings.h" #include "SWGRigCtlServerSettings.h" #include "SWGSatelliteTrackerSettings.h" #include "SWGSimplePTTSettings.h" @@ -76,6 +77,9 @@ public: SWGMapSettings* getMapSettings(); void setMapSettings(SWGMapSettings* map_settings); + SWGPERTesterSettings* getPerTesterSettings(); + void setPerTesterSettings(SWGPERTesterSettings* per_tester_settings); + SWGRigCtlServerSettings* getRigCtlServerSettings(); void setRigCtlServerSettings(SWGRigCtlServerSettings* rig_ctl_server_settings); @@ -119,6 +123,9 @@ private: SWGMapSettings* map_settings; bool m_map_settings_isSet; + SWGPERTesterSettings* per_tester_settings; + bool m_per_tester_settings_isSet; + SWGRigCtlServerSettings* rig_ctl_server_settings; bool m_rig_ctl_server_settings_isSet; diff --git a/swagger/sdrangel/code/qt5/client/SWGModelFactory.h b/swagger/sdrangel/code/qt5/client/SWGModelFactory.h index 6f2c27c15..c2c54478e 100644 --- a/swagger/sdrangel/code/qt5/client/SWGModelFactory.h +++ b/swagger/sdrangel/code/qt5/client/SWGModelFactory.h @@ -162,6 +162,9 @@ #include "SWGNFMModReport.h" #include "SWGNFMModSettings.h" #include "SWGNamedEnum.h" +#include "SWGPERTesterActions.h" +#include "SWGPERTesterActions_aos.h" +#include "SWGPERTesterSettings.h" #include "SWGPacketDemodSettings.h" #include "SWGPacketModActions.h" #include "SWGPacketModActions_tx.h" @@ -701,6 +704,15 @@ namespace SWGSDRangel { if(QString("SWGNamedEnum").compare(type) == 0) { return new SWGNamedEnum(); } + if(QString("SWGPERTesterActions").compare(type) == 0) { + return new SWGPERTesterActions(); + } + if(QString("SWGPERTesterActions_aos").compare(type) == 0) { + return new SWGPERTesterActions_aos(); + } + if(QString("SWGPERTesterSettings").compare(type) == 0) { + return new SWGPERTesterSettings(); + } if(QString("SWGPacketDemodSettings").compare(type) == 0) { return new SWGPacketDemodSettings(); } diff --git a/swagger/sdrangel/code/qt5/client/SWGPERTesterActions.cpp b/swagger/sdrangel/code/qt5/client/SWGPERTesterActions.cpp new file mode 100644 index 000000000..268f21859 --- /dev/null +++ b/swagger/sdrangel/code/qt5/client/SWGPERTesterActions.cpp @@ -0,0 +1,110 @@ +/** + * 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: 6.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 "SWGPERTesterActions.h" + +#include "SWGHelpers.h" + +#include +#include +#include +#include + +namespace SWGSDRangel { + +SWGPERTesterActions::SWGPERTesterActions(QString* json) { + init(); + this->fromJson(*json); +} + +SWGPERTesterActions::SWGPERTesterActions() { + aos = nullptr; + m_aos_isSet = false; +} + +SWGPERTesterActions::~SWGPERTesterActions() { + this->cleanup(); +} + +void +SWGPERTesterActions::init() { + aos = new SWGPERTesterActions_aos(); + m_aos_isSet = false; +} + +void +SWGPERTesterActions::cleanup() { + if(aos != nullptr) { + delete aos; + } +} + +SWGPERTesterActions* +SWGPERTesterActions::fromJson(QString &json) { + QByteArray array (json.toStdString().c_str()); + QJsonDocument doc = QJsonDocument::fromJson(array); + QJsonObject jsonObject = doc.object(); + this->fromJsonObject(jsonObject); + return this; +} + +void +SWGPERTesterActions::fromJsonObject(QJsonObject &pJson) { + ::SWGSDRangel::setValue(&aos, pJson["aos"], "SWGPERTesterActions_aos", "SWGPERTesterActions_aos"); + +} + +QString +SWGPERTesterActions::asJson () +{ + QJsonObject* obj = this->asJsonObject(); + + QJsonDocument doc(*obj); + QByteArray bytes = doc.toJson(); + delete obj; + return QString(bytes); +} + +QJsonObject* +SWGPERTesterActions::asJsonObject() { + QJsonObject* obj = new QJsonObject(); + if((aos != nullptr) && (aos->isSet())){ + toJsonValue(QString("aos"), aos, obj, QString("SWGPERTesterActions_aos")); + } + + return obj; +} + +SWGPERTesterActions_aos* +SWGPERTesterActions::getAos() { + return aos; +} +void +SWGPERTesterActions::setAos(SWGPERTesterActions_aos* aos) { + this->aos = aos; + this->m_aos_isSet = true; +} + + +bool +SWGPERTesterActions::isSet(){ + bool isObjectUpdated = false; + do{ + if(aos && aos->isSet()){ + isObjectUpdated = true; break; + } + }while(false); + return isObjectUpdated; +} +} + diff --git a/swagger/sdrangel/code/qt5/client/SWGPERTesterActions.h b/swagger/sdrangel/code/qt5/client/SWGPERTesterActions.h new file mode 100644 index 000000000..c7418b74a --- /dev/null +++ b/swagger/sdrangel/code/qt5/client/SWGPERTesterActions.h @@ -0,0 +1,59 @@ +/** + * 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: 6.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. + */ + +/* + * SWGPERTesterActions.h + * + * PERTester + */ + +#ifndef SWGPERTesterActions_H_ +#define SWGPERTesterActions_H_ + +#include + + +#include "SWGPERTesterActions_aos.h" + +#include "SWGObject.h" +#include "export.h" + +namespace SWGSDRangel { + +class SWG_API SWGPERTesterActions: public SWGObject { +public: + SWGPERTesterActions(); + SWGPERTesterActions(QString* json); + virtual ~SWGPERTesterActions(); + void init(); + void cleanup(); + + virtual QString asJson () override; + virtual QJsonObject* asJsonObject() override; + virtual void fromJsonObject(QJsonObject &json) override; + virtual SWGPERTesterActions* fromJson(QString &jsonString) override; + + SWGPERTesterActions_aos* getAos(); + void setAos(SWGPERTesterActions_aos* aos); + + + virtual bool isSet() override; + +private: + SWGPERTesterActions_aos* aos; + bool m_aos_isSet; + +}; + +} + +#endif /* SWGPERTesterActions_H_ */ diff --git a/swagger/sdrangel/code/qt5/client/SWGPERTesterActions_aos.cpp b/swagger/sdrangel/code/qt5/client/SWGPERTesterActions_aos.cpp new file mode 100644 index 000000000..dbfb30db6 --- /dev/null +++ b/swagger/sdrangel/code/qt5/client/SWGPERTesterActions_aos.cpp @@ -0,0 +1,160 @@ +/** + * 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: 6.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 "SWGPERTesterActions_aos.h" + +#include "SWGHelpers.h" + +#include +#include +#include +#include + +namespace SWGSDRangel { + +SWGPERTesterActions_aos::SWGPERTesterActions_aos(QString* json) { + init(); + this->fromJson(*json); +} + +SWGPERTesterActions_aos::SWGPERTesterActions_aos() { + satellite_name = nullptr; + m_satellite_name_isSet = false; + aos_time = nullptr; + m_aos_time_isSet = false; + los_time = nullptr; + m_los_time_isSet = false; +} + +SWGPERTesterActions_aos::~SWGPERTesterActions_aos() { + this->cleanup(); +} + +void +SWGPERTesterActions_aos::init() { + satellite_name = new QString(""); + m_satellite_name_isSet = false; + aos_time = new QString(""); + m_aos_time_isSet = false; + los_time = new QString(""); + m_los_time_isSet = false; +} + +void +SWGPERTesterActions_aos::cleanup() { + if(satellite_name != nullptr) { + delete satellite_name; + } + if(aos_time != nullptr) { + delete aos_time; + } + if(los_time != nullptr) { + delete los_time; + } +} + +SWGPERTesterActions_aos* +SWGPERTesterActions_aos::fromJson(QString &json) { + QByteArray array (json.toStdString().c_str()); + QJsonDocument doc = QJsonDocument::fromJson(array); + QJsonObject jsonObject = doc.object(); + this->fromJsonObject(jsonObject); + return this; +} + +void +SWGPERTesterActions_aos::fromJsonObject(QJsonObject &pJson) { + ::SWGSDRangel::setValue(&satellite_name, pJson["satelliteName"], "QString", "QString"); + + ::SWGSDRangel::setValue(&aos_time, pJson["aosTime"], "QString", "QString"); + + ::SWGSDRangel::setValue(&los_time, pJson["losTime"], "QString", "QString"); + +} + +QString +SWGPERTesterActions_aos::asJson () +{ + QJsonObject* obj = this->asJsonObject(); + + QJsonDocument doc(*obj); + QByteArray bytes = doc.toJson(); + delete obj; + return QString(bytes); +} + +QJsonObject* +SWGPERTesterActions_aos::asJsonObject() { + QJsonObject* obj = new QJsonObject(); + if(satellite_name != nullptr && *satellite_name != QString("")){ + toJsonValue(QString("satelliteName"), satellite_name, obj, QString("QString")); + } + if(aos_time != nullptr && *aos_time != QString("")){ + toJsonValue(QString("aosTime"), aos_time, obj, QString("QString")); + } + if(los_time != nullptr && *los_time != QString("")){ + toJsonValue(QString("losTime"), los_time, obj, QString("QString")); + } + + return obj; +} + +QString* +SWGPERTesterActions_aos::getSatelliteName() { + return satellite_name; +} +void +SWGPERTesterActions_aos::setSatelliteName(QString* satellite_name) { + this->satellite_name = satellite_name; + this->m_satellite_name_isSet = true; +} + +QString* +SWGPERTesterActions_aos::getAosTime() { + return aos_time; +} +void +SWGPERTesterActions_aos::setAosTime(QString* aos_time) { + this->aos_time = aos_time; + this->m_aos_time_isSet = true; +} + +QString* +SWGPERTesterActions_aos::getLosTime() { + return los_time; +} +void +SWGPERTesterActions_aos::setLosTime(QString* los_time) { + this->los_time = los_time; + this->m_los_time_isSet = true; +} + + +bool +SWGPERTesterActions_aos::isSet(){ + bool isObjectUpdated = false; + do{ + if(satellite_name && *satellite_name != QString("")){ + isObjectUpdated = true; break; + } + if(aos_time && *aos_time != QString("")){ + isObjectUpdated = true; break; + } + if(los_time && *los_time != QString("")){ + isObjectUpdated = true; break; + } + }while(false); + return isObjectUpdated; +} +} + diff --git a/swagger/sdrangel/code/qt5/client/SWGPERTesterActions_aos.h b/swagger/sdrangel/code/qt5/client/SWGPERTesterActions_aos.h new file mode 100644 index 000000000..990c6cf2d --- /dev/null +++ b/swagger/sdrangel/code/qt5/client/SWGPERTesterActions_aos.h @@ -0,0 +1,71 @@ +/** + * 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: 6.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. + */ + +/* + * SWGPERTesterActions_aos.h + * + * Acquisition of signal + */ + +#ifndef SWGPERTesterActions_aos_H_ +#define SWGPERTesterActions_aos_H_ + +#include + + +#include + +#include "SWGObject.h" +#include "export.h" + +namespace SWGSDRangel { + +class SWG_API SWGPERTesterActions_aos: public SWGObject { +public: + SWGPERTesterActions_aos(); + SWGPERTesterActions_aos(QString* json); + virtual ~SWGPERTesterActions_aos(); + void init(); + void cleanup(); + + virtual QString asJson () override; + virtual QJsonObject* asJsonObject() override; + virtual void fromJsonObject(QJsonObject &json) override; + virtual SWGPERTesterActions_aos* fromJson(QString &jsonString) override; + + QString* getSatelliteName(); + void setSatelliteName(QString* satellite_name); + + QString* getAosTime(); + void setAosTime(QString* aos_time); + + QString* getLosTime(); + void setLosTime(QString* los_time); + + + virtual bool isSet() override; + +private: + QString* satellite_name; + bool m_satellite_name_isSet; + + QString* aos_time; + bool m_aos_time_isSet; + + QString* los_time; + bool m_los_time_isSet; + +}; + +} + +#endif /* SWGPERTesterActions_aos_H_ */ diff --git a/swagger/sdrangel/code/qt5/client/SWGPERTesterSettings.cpp b/swagger/sdrangel/code/qt5/client/SWGPERTesterSettings.cpp new file mode 100644 index 000000000..dc88e7702 --- /dev/null +++ b/swagger/sdrangel/code/qt5/client/SWGPERTesterSettings.cpp @@ -0,0 +1,515 @@ +/** + * 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: 6.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 "SWGPERTesterSettings.h" + +#include "SWGHelpers.h" + +#include +#include +#include +#include + +namespace SWGSDRangel { + +SWGPERTesterSettings::SWGPERTesterSettings(QString* json) { + init(); + this->fromJson(*json); +} + +SWGPERTesterSettings::SWGPERTesterSettings() { + packet_count = 0; + m_packet_count_isSet = false; + interval = 0.0f; + m_interval_isSet = false; + start = 0; + m_start_isSet = false; + satellites = nullptr; + m_satellites_isSet = false; + packet = nullptr; + m_packet_isSet = false; + ignore_leading_bytes = 0; + m_ignore_leading_bytes_isSet = false; + ignore_trailing_bytes = 0; + m_ignore_trailing_bytes_isSet = false; + tx_udp_address = nullptr; + m_tx_udp_address_isSet = false; + tx_udp_port = 0; + m_tx_udp_port_isSet = false; + rx_udp_address = nullptr; + m_rx_udp_address_isSet = false; + rx_udp_port = 0; + m_rx_udp_port_isSet = false; + title = nullptr; + m_title_isSet = false; + rgb_color = 0; + m_rgb_color_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; + reverse_api_channel_index = 0; + m_reverse_api_channel_index_isSet = false; +} + +SWGPERTesterSettings::~SWGPERTesterSettings() { + this->cleanup(); +} + +void +SWGPERTesterSettings::init() { + packet_count = 0; + m_packet_count_isSet = false; + interval = 0.0f; + m_interval_isSet = false; + start = 0; + m_start_isSet = false; + satellites = new QList(); + m_satellites_isSet = false; + packet = new QString(""); + m_packet_isSet = false; + ignore_leading_bytes = 0; + m_ignore_leading_bytes_isSet = false; + ignore_trailing_bytes = 0; + m_ignore_trailing_bytes_isSet = false; + tx_udp_address = new QString(""); + m_tx_udp_address_isSet = false; + tx_udp_port = 0; + m_tx_udp_port_isSet = false; + rx_udp_address = new QString(""); + m_rx_udp_address_isSet = false; + rx_udp_port = 0; + m_rx_udp_port_isSet = false; + title = new QString(""); + m_title_isSet = false; + rgb_color = 0; + m_rgb_color_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; + reverse_api_channel_index = 0; + m_reverse_api_channel_index_isSet = false; +} + +void +SWGPERTesterSettings::cleanup() { + + + + if(satellites != nullptr) { + auto arr = satellites; + for(auto o: *arr) { + delete o; + } + delete satellites; + } + if(packet != nullptr) { + delete packet; + } + + + if(tx_udp_address != nullptr) { + delete tx_udp_address; + } + + if(rx_udp_address != nullptr) { + delete rx_udp_address; + } + + if(title != nullptr) { + delete title; + } + + + if(reverse_api_address != nullptr) { + delete reverse_api_address; + } + + + +} + +SWGPERTesterSettings* +SWGPERTesterSettings::fromJson(QString &json) { + QByteArray array (json.toStdString().c_str()); + QJsonDocument doc = QJsonDocument::fromJson(array); + QJsonObject jsonObject = doc.object(); + this->fromJsonObject(jsonObject); + return this; +} + +void +SWGPERTesterSettings::fromJsonObject(QJsonObject &pJson) { + ::SWGSDRangel::setValue(&packet_count, pJson["packetCount"], "qint32", ""); + + ::SWGSDRangel::setValue(&interval, pJson["interval"], "float", ""); + + ::SWGSDRangel::setValue(&start, pJson["start"], "qint32", ""); + + + ::SWGSDRangel::setValue(&satellites, pJson["satellites"], "QList", "QString"); + ::SWGSDRangel::setValue(&packet, pJson["packet"], "QString", "QString"); + + ::SWGSDRangel::setValue(&ignore_leading_bytes, pJson["ignoreLeadingBytes"], "qint32", ""); + + ::SWGSDRangel::setValue(&ignore_trailing_bytes, pJson["ignoreTrailingBytes"], "qint32", ""); + + ::SWGSDRangel::setValue(&tx_udp_address, pJson["txUDPAddress"], "QString", "QString"); + + ::SWGSDRangel::setValue(&tx_udp_port, pJson["txUDPPort"], "qint32", ""); + + ::SWGSDRangel::setValue(&rx_udp_address, pJson["rxUDPAddress"], "QString", "QString"); + + ::SWGSDRangel::setValue(&rx_udp_port, pJson["rxUDPPort"], "qint32", ""); + + ::SWGSDRangel::setValue(&title, pJson["title"], "QString", "QString"); + + ::SWGSDRangel::setValue(&rgb_color, pJson["rgbColor"], "qint32", ""); + + ::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", ""); + + ::SWGSDRangel::setValue(&reverse_api_channel_index, pJson["reverseAPIChannelIndex"], "qint32", ""); + +} + +QString +SWGPERTesterSettings::asJson () +{ + QJsonObject* obj = this->asJsonObject(); + + QJsonDocument doc(*obj); + QByteArray bytes = doc.toJson(); + delete obj; + return QString(bytes); +} + +QJsonObject* +SWGPERTesterSettings::asJsonObject() { + QJsonObject* obj = new QJsonObject(); + if(m_packet_count_isSet){ + obj->insert("packetCount", QJsonValue(packet_count)); + } + if(m_interval_isSet){ + obj->insert("interval", QJsonValue(interval)); + } + if(m_start_isSet){ + obj->insert("start", QJsonValue(start)); + } + if(satellites && satellites->size() > 0){ + toJsonArray((QList*)satellites, obj, "satellites", "QString"); + } + if(packet != nullptr && *packet != QString("")){ + toJsonValue(QString("packet"), packet, obj, QString("QString")); + } + if(m_ignore_leading_bytes_isSet){ + obj->insert("ignoreLeadingBytes", QJsonValue(ignore_leading_bytes)); + } + if(m_ignore_trailing_bytes_isSet){ + obj->insert("ignoreTrailingBytes", QJsonValue(ignore_trailing_bytes)); + } + if(tx_udp_address != nullptr && *tx_udp_address != QString("")){ + toJsonValue(QString("txUDPAddress"), tx_udp_address, obj, QString("QString")); + } + if(m_tx_udp_port_isSet){ + obj->insert("txUDPPort", QJsonValue(tx_udp_port)); + } + if(rx_udp_address != nullptr && *rx_udp_address != QString("")){ + toJsonValue(QString("rxUDPAddress"), rx_udp_address, obj, QString("QString")); + } + if(m_rx_udp_port_isSet){ + obj->insert("rxUDPPort", QJsonValue(rx_udp_port)); + } + if(title != nullptr && *title != QString("")){ + toJsonValue(QString("title"), title, obj, QString("QString")); + } + if(m_rgb_color_isSet){ + obj->insert("rgbColor", QJsonValue(rgb_color)); + } + 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)); + } + if(m_reverse_api_channel_index_isSet){ + obj->insert("reverseAPIChannelIndex", QJsonValue(reverse_api_channel_index)); + } + + return obj; +} + +qint32 +SWGPERTesterSettings::getPacketCount() { + return packet_count; +} +void +SWGPERTesterSettings::setPacketCount(qint32 packet_count) { + this->packet_count = packet_count; + this->m_packet_count_isSet = true; +} + +float +SWGPERTesterSettings::getInterval() { + return interval; +} +void +SWGPERTesterSettings::setInterval(float interval) { + this->interval = interval; + this->m_interval_isSet = true; +} + +qint32 +SWGPERTesterSettings::getStart() { + return start; +} +void +SWGPERTesterSettings::setStart(qint32 start) { + this->start = start; + this->m_start_isSet = true; +} + +QList* +SWGPERTesterSettings::getSatellites() { + return satellites; +} +void +SWGPERTesterSettings::setSatellites(QList* satellites) { + this->satellites = satellites; + this->m_satellites_isSet = true; +} + +QString* +SWGPERTesterSettings::getPacket() { + return packet; +} +void +SWGPERTesterSettings::setPacket(QString* packet) { + this->packet = packet; + this->m_packet_isSet = true; +} + +qint32 +SWGPERTesterSettings::getIgnoreLeadingBytes() { + return ignore_leading_bytes; +} +void +SWGPERTesterSettings::setIgnoreLeadingBytes(qint32 ignore_leading_bytes) { + this->ignore_leading_bytes = ignore_leading_bytes; + this->m_ignore_leading_bytes_isSet = true; +} + +qint32 +SWGPERTesterSettings::getIgnoreTrailingBytes() { + return ignore_trailing_bytes; +} +void +SWGPERTesterSettings::setIgnoreTrailingBytes(qint32 ignore_trailing_bytes) { + this->ignore_trailing_bytes = ignore_trailing_bytes; + this->m_ignore_trailing_bytes_isSet = true; +} + +QString* +SWGPERTesterSettings::getTxUdpAddress() { + return tx_udp_address; +} +void +SWGPERTesterSettings::setTxUdpAddress(QString* tx_udp_address) { + this->tx_udp_address = tx_udp_address; + this->m_tx_udp_address_isSet = true; +} + +qint32 +SWGPERTesterSettings::getTxUdpPort() { + return tx_udp_port; +} +void +SWGPERTesterSettings::setTxUdpPort(qint32 tx_udp_port) { + this->tx_udp_port = tx_udp_port; + this->m_tx_udp_port_isSet = true; +} + +QString* +SWGPERTesterSettings::getRxUdpAddress() { + return rx_udp_address; +} +void +SWGPERTesterSettings::setRxUdpAddress(QString* rx_udp_address) { + this->rx_udp_address = rx_udp_address; + this->m_rx_udp_address_isSet = true; +} + +qint32 +SWGPERTesterSettings::getRxUdpPort() { + return rx_udp_port; +} +void +SWGPERTesterSettings::setRxUdpPort(qint32 rx_udp_port) { + this->rx_udp_port = rx_udp_port; + this->m_rx_udp_port_isSet = true; +} + +QString* +SWGPERTesterSettings::getTitle() { + return title; +} +void +SWGPERTesterSettings::setTitle(QString* title) { + this->title = title; + this->m_title_isSet = true; +} + +qint32 +SWGPERTesterSettings::getRgbColor() { + return rgb_color; +} +void +SWGPERTesterSettings::setRgbColor(qint32 rgb_color) { + this->rgb_color = rgb_color; + this->m_rgb_color_isSet = true; +} + +qint32 +SWGPERTesterSettings::getUseReverseApi() { + return use_reverse_api; +} +void +SWGPERTesterSettings::setUseReverseApi(qint32 use_reverse_api) { + this->use_reverse_api = use_reverse_api; + this->m_use_reverse_api_isSet = true; +} + +QString* +SWGPERTesterSettings::getReverseApiAddress() { + return reverse_api_address; +} +void +SWGPERTesterSettings::setReverseApiAddress(QString* reverse_api_address) { + this->reverse_api_address = reverse_api_address; + this->m_reverse_api_address_isSet = true; +} + +qint32 +SWGPERTesterSettings::getReverseApiPort() { + return reverse_api_port; +} +void +SWGPERTesterSettings::setReverseApiPort(qint32 reverse_api_port) { + this->reverse_api_port = reverse_api_port; + this->m_reverse_api_port_isSet = true; +} + +qint32 +SWGPERTesterSettings::getReverseApiDeviceIndex() { + return reverse_api_device_index; +} +void +SWGPERTesterSettings::setReverseApiDeviceIndex(qint32 reverse_api_device_index) { + this->reverse_api_device_index = reverse_api_device_index; + this->m_reverse_api_device_index_isSet = true; +} + +qint32 +SWGPERTesterSettings::getReverseApiChannelIndex() { + return reverse_api_channel_index; +} +void +SWGPERTesterSettings::setReverseApiChannelIndex(qint32 reverse_api_channel_index) { + this->reverse_api_channel_index = reverse_api_channel_index; + this->m_reverse_api_channel_index_isSet = true; +} + + +bool +SWGPERTesterSettings::isSet(){ + bool isObjectUpdated = false; + do{ + if(m_packet_count_isSet){ + isObjectUpdated = true; break; + } + if(m_interval_isSet){ + isObjectUpdated = true; break; + } + if(m_start_isSet){ + isObjectUpdated = true; break; + } + if(satellites && (satellites->size() > 0)){ + isObjectUpdated = true; break; + } + if(packet && *packet != QString("")){ + isObjectUpdated = true; break; + } + if(m_ignore_leading_bytes_isSet){ + isObjectUpdated = true; break; + } + if(m_ignore_trailing_bytes_isSet){ + isObjectUpdated = true; break; + } + if(tx_udp_address && *tx_udp_address != QString("")){ + isObjectUpdated = true; break; + } + if(m_tx_udp_port_isSet){ + isObjectUpdated = true; break; + } + if(rx_udp_address && *rx_udp_address != QString("")){ + isObjectUpdated = true; break; + } + if(m_rx_udp_port_isSet){ + isObjectUpdated = true; break; + } + if(title && *title != QString("")){ + isObjectUpdated = true; break; + } + if(m_rgb_color_isSet){ + 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; + } + if(m_reverse_api_channel_index_isSet){ + isObjectUpdated = true; break; + } + }while(false); + return isObjectUpdated; +} +} + diff --git a/swagger/sdrangel/code/qt5/client/SWGPERTesterSettings.h b/swagger/sdrangel/code/qt5/client/SWGPERTesterSettings.h new file mode 100644 index 000000000..3f5dfac95 --- /dev/null +++ b/swagger/sdrangel/code/qt5/client/SWGPERTesterSettings.h @@ -0,0 +1,162 @@ +/** + * 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: 6.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. + */ + +/* + * SWGPERTesterSettings.h + * + * PER Tester settings + */ + +#ifndef SWGPERTesterSettings_H_ +#define SWGPERTesterSettings_H_ + +#include + + +#include +#include + +#include "SWGObject.h" +#include "export.h" + +namespace SWGSDRangel { + +class SWG_API SWGPERTesterSettings: public SWGObject { +public: + SWGPERTesterSettings(); + SWGPERTesterSettings(QString* json); + virtual ~SWGPERTesterSettings(); + void init(); + void cleanup(); + + virtual QString asJson () override; + virtual QJsonObject* asJsonObject() override; + virtual void fromJsonObject(QJsonObject &json) override; + virtual SWGPERTesterSettings* fromJson(QString &jsonString) override; + + qint32 getPacketCount(); + void setPacketCount(qint32 packet_count); + + float getInterval(); + void setInterval(float interval); + + qint32 getStart(); + void setStart(qint32 start); + + QList* getSatellites(); + void setSatellites(QList* satellites); + + QString* getPacket(); + void setPacket(QString* packet); + + qint32 getIgnoreLeadingBytes(); + void setIgnoreLeadingBytes(qint32 ignore_leading_bytes); + + qint32 getIgnoreTrailingBytes(); + void setIgnoreTrailingBytes(qint32 ignore_trailing_bytes); + + QString* getTxUdpAddress(); + void setTxUdpAddress(QString* tx_udp_address); + + qint32 getTxUdpPort(); + void setTxUdpPort(qint32 tx_udp_port); + + QString* getRxUdpAddress(); + void setRxUdpAddress(QString* rx_udp_address); + + qint32 getRxUdpPort(); + void setRxUdpPort(qint32 rx_udp_port); + + QString* getTitle(); + void setTitle(QString* title); + + qint32 getRgbColor(); + void setRgbColor(qint32 rgb_color); + + 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); + + qint32 getReverseApiChannelIndex(); + void setReverseApiChannelIndex(qint32 reverse_api_channel_index); + + + virtual bool isSet() override; + +private: + qint32 packet_count; + bool m_packet_count_isSet; + + float interval; + bool m_interval_isSet; + + qint32 start; + bool m_start_isSet; + + QList* satellites; + bool m_satellites_isSet; + + QString* packet; + bool m_packet_isSet; + + qint32 ignore_leading_bytes; + bool m_ignore_leading_bytes_isSet; + + qint32 ignore_trailing_bytes; + bool m_ignore_trailing_bytes_isSet; + + QString* tx_udp_address; + bool m_tx_udp_address_isSet; + + qint32 tx_udp_port; + bool m_tx_udp_port_isSet; + + QString* rx_udp_address; + bool m_rx_udp_address_isSet; + + qint32 rx_udp_port; + bool m_rx_udp_port_isSet; + + QString* title; + bool m_title_isSet; + + qint32 rgb_color; + bool m_rgb_color_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; + + qint32 reverse_api_channel_index; + bool m_reverse_api_channel_index_isSet; + +}; + +} + +#endif /* SWGPERTesterSettings_H_ */