From 153429cc7f014ba8a2bccf90e56983cdc58dfee1 Mon Sep 17 00:00:00 2001 From: f4exb Date: Mon, 21 Sep 2020 03:13:36 +0200 Subject: [PATCH] Feature plugins framework: REST API and server implementationo --- plugins/feature/simpleptt/simpleptt.cpp | 271 ++++++++++- plugins/feature/simpleptt/simpleptt.h | 60 ++- plugins/feature/simpleptt/simplepttgui.cpp | 68 ++- plugins/feature/simpleptt/simplepttgui.ui | 2 +- .../feature/simpleptt/simplepttsettings.cpp | 34 +- plugins/feature/simpleptt/simplepttsettings.h | 5 + plugins/feature/simpleptt/simplepttworker.cpp | 1 + sdrbase/feature/feature.cpp | 38 +- sdrbase/feature/feature.h | 86 +++- sdrbase/resources/webapi/doc/html2/index.html | 2 +- sdrbase/webapi/webapiadapterinterface.h | 5 + sdrgui/feature/featureuiset.cpp | 22 +- sdrgui/feature/featureuiset.h | 14 +- sdrgui/gui/basicfeaturesettingsdialog.h | 15 + sdrgui/gui/basicfeaturesettingsdialog.ui | 148 ++++++ sdrgui/mainwindow.cpp | 25 ++ sdrgui/mainwindow.h | 46 ++ sdrgui/webapi/webapiadaptergui.cpp | 421 +++++++++++++++++- sdrgui/webapi/webapiadaptergui.h | 69 +++ sdrsrv/CMakeLists.txt | 2 + sdrsrv/feature/featureset.cpp | 102 +++++ sdrsrv/feature/featureset.h | 71 +++ sdrsrv/maincore.cpp | 34 ++ sdrsrv/maincore.h | 49 ++ sdrsrv/webapi/webapiadaptersrv.cpp | 418 +++++++++++++++++ sdrsrv/webapi/webapiadaptersrv.h | 70 +++ swagger/sdrangel/code/html2/index.html | 2 +- 27 files changed, 2032 insertions(+), 48 deletions(-) create mode 100644 sdrsrv/feature/featureset.cpp create mode 100644 sdrsrv/feature/featureset.h diff --git a/plugins/feature/simpleptt/simpleptt.cpp b/plugins/feature/simpleptt/simpleptt.cpp index 40d799bd5..00822721b 100644 --- a/plugins/feature/simpleptt/simpleptt.cpp +++ b/plugins/feature/simpleptt/simpleptt.cpp @@ -16,6 +16,15 @@ /////////////////////////////////////////////////////////////////////////////////// #include +#include +#include +#include + +#include "SWGFeatureSettings.h" +#include "SWGFeatureReport.h" +#include "SWGFeatureActions.h" +#include "SWGSimplePTTReport.h" +#include "SWGDeviceState.h" #include "dsp/dspengine.h" @@ -30,7 +39,8 @@ const QString SimplePTT::m_featureIdURI = "sdrangel.feature.simpleptt"; const QString SimplePTT::m_featureId = "SimplePTT"; SimplePTT::SimplePTT(WebAPIAdapterInterface *webAPIAdapterInterface) : - Feature(m_featureIdURI, webAPIAdapterInterface) + Feature(m_featureIdURI, webAPIAdapterInterface), + m_ptt(false) { setObjectName(m_featureId); m_worker = new SimplePTTWorker(webAPIAdapterInterface); @@ -44,7 +54,7 @@ SimplePTT::~SimplePTT() stop(); } - delete m_worker; + delete m_worker; } void SimplePTT::start() @@ -83,9 +93,10 @@ bool SimplePTT::handleMessage(const Message& cmd) else if (MsgPTT::match(cmd)) { MsgPTT& cfg = (MsgPTT&) cmd; - qDebug() << "SimplePTT::handleMessage: MsgPTT: tx:" << cfg.getTx(); + m_ptt = cfg.getTx(); + qDebug() << "SimplePTT::handleMessage: MsgPTT: tx:" << m_ptt; - SimplePTTWorker::MsgPTT *msg = SimplePTTWorker::MsgPTT::create(cfg.getTx()); + SimplePTTWorker::MsgPTT *msg = SimplePTTWorker::MsgPTT::create(m_ptt); m_worker->getInputMessageQueue()->push(msg); return true; @@ -142,10 +153,260 @@ void SimplePTT::applySettings(const SimplePTTSettings& settings, bool force) << " m_tx2RxDelayMs: " << settings.m_tx2RxDelayMs << " force: " << force; + QList reverseAPIKeys; + + if ((m_settings.m_title != settings.m_title) || force) { + reverseAPIKeys.append("title"); + } + if ((m_settings.m_rgbColor != settings.m_rgbColor) || force) { + reverseAPIKeys.append("rgbColor"); + } + if ((m_settings.m_rxDeviceSetIndex != settings.m_rxDeviceSetIndex) || force) { + reverseAPIKeys.append("rxDeviceSetIndex"); + } + if ((m_settings.m_txDeviceSetIndex != settings.m_txDeviceSetIndex) || force) { + reverseAPIKeys.append("txDeviceSetIndex"); + } + if ((m_settings.m_rx2TxDelayMs != settings.m_rx2TxDelayMs) || force) { + reverseAPIKeys.append("rx2TxDelayMs"); + } + if ((m_settings.m_tx2RxDelayMs != settings.m_tx2RxDelayMs) || force) { + reverseAPIKeys.append("tx2RxDelayMs"); + } + SimplePTTWorker::MsgConfigureSimplePTTWorker *msg = SimplePTTWorker::MsgConfigureSimplePTTWorker::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_reverseAPIDeviceIndex != settings.m_reverseAPIDeviceIndex) || + (m_settings.m_reverseAPIChannelIndex != settings.m_reverseAPIChannelIndex); + webapiReverseSendSettings(reverseAPIKeys, settings, fullUpdate || force); + } + m_settings = settings; } + +int SimplePTT::webapiRun(bool run, + SWGSDRangel::SWGDeviceState& response, + QString& errorMessage) +{ + getFeatureStateStr(*response.getState()); + MsgStartStop *msg = MsgStartStop::create(run); + getInputMessageQueue()->push(msg); + return 202; +} + +int SimplePTT::webapiSettingsGet( + SWGSDRangel::SWGFeatureSettings& response, + QString& errorMessage) +{ + (void) errorMessage; + response.setSimplePttSettings(new SWGSDRangel::SWGSimplePTTSettings()); + response.getSimplePttSettings()->init(); + webapiFormatFeatureSettings(response, m_settings); + return 200; +} + +int SimplePTT::webapiSettingsPutPatch( + bool force, + const QStringList& featureSettingsKeys, + SWGSDRangel::SWGFeatureSettings& response, + QString& errorMessage) +{ + (void) errorMessage; + SimplePTTSettings settings = m_settings; + webapiUpdateFeatureSettings(settings, featureSettingsKeys, response); + + MsgConfigureSimplePTT *msg = MsgConfigureSimplePTT::create(settings, force); + m_inputMessageQueue.push(msg); + + qDebug("SimplePTT::webapiSettingsPutPatch: forward to GUI: %p", m_guiMessageQueue); + if (m_guiMessageQueue) // forward to GUI if any + { + MsgConfigureSimplePTT *msgToGUI = MsgConfigureSimplePTT::create(settings, force); + m_guiMessageQueue->push(msgToGUI); + } + + webapiFormatFeatureSettings(response, settings); + + return 200; +} + +int SimplePTT::webapiReportGet( + SWGSDRangel::SWGFeatureReport& response, + QString& errorMessage) +{ + (void) errorMessage; + response.setSimplePttReport(new SWGSDRangel::SWGSimplePTTReport()); + response.getSimplePttReport()->init(); + webapiFormatFeatureReport(response); + return 200; +} + +int SimplePTT::webapiActionsPost( + const QStringList& featureActionsKeys, + SWGSDRangel::SWGFeatureActions& query, + QString& errorMessage) +{ + SWGSDRangel::SWGSimplePTTActions *swgSimplePTTActions = query.getSimplePttActions(); + + if (swgSimplePTTActions) + { + if (featureActionsKeys.contains("ptt")) + { + bool ptt = swgSimplePTTActions->getPtt() != 0; + + MsgPTT *msg = MsgPTT::create(ptt); + getInputMessageQueue()->push(msg); + + if (getMessageQueueToGUI()) + { + MsgPTT *msgToGUI = MsgPTT::create(ptt); + getMessageQueueToGUI()->push(msgToGUI); + } + } + + return 202; + } + else + { + errorMessage = "Missing SimplePTTActions in query"; + return 400; + } +} + +void SimplePTT::webapiFormatFeatureSettings( + SWGSDRangel::SWGFeatureSettings& response, + const SimplePTTSettings& settings) +{ + if (response.getSimplePttSettings()->getTitle()) { + *response.getSimplePttSettings()->getTitle() = settings.m_title; + } else { + response.getSimplePttSettings()->setTitle(new QString(settings.m_title)); + } + + response.getSimplePttSettings()->setRgbColor(settings.m_rgbColor); + response.getSimplePttSettings()->setRxDeviceSetIndex(settings.m_rxDeviceSetIndex); + response.getSimplePttSettings()->setTxDeviceSetIndex(settings.m_txDeviceSetIndex); + response.getSimplePttSettings()->setRx2TxDelayMs(settings.m_rx2TxDelayMs); + response.getSimplePttSettings()->setTx2RxDelayMs(settings.m_tx2RxDelayMs); + + response.getSimplePttSettings()->setUseReverseApi(settings.m_useReverseAPI ? 1 : 0); + + if (response.getSimplePttSettings()->getReverseApiAddress()) { + *response.getSimplePttSettings()->getReverseApiAddress() = settings.m_reverseAPIAddress; + } else { + response.getSimplePttSettings()->setReverseApiAddress(new QString(settings.m_reverseAPIAddress)); + } + + response.getSimplePttSettings()->setReverseApiPort(settings.m_reverseAPIPort); + response.getSimplePttSettings()->setReverseApiDeviceIndex(settings.m_reverseAPIDeviceIndex); + response.getSimplePttSettings()->setReverseApiChannelIndex(settings.m_reverseAPIChannelIndex); +} + +void SimplePTT::webapiUpdateFeatureSettings( + SimplePTTSettings& settings, + const QStringList& featureSettingsKeys, + SWGSDRangel::SWGFeatureSettings& response) +{ + if (featureSettingsKeys.contains("title")) { + settings.m_title = *response.getSimplePttSettings()->getTitle(); + } + if (featureSettingsKeys.contains("rgbColor")) { + settings.m_rgbColor = response.getSimplePttSettings()->getRgbColor(); + } + if (featureSettingsKeys.contains("rxDeviceSetIndex")) { + settings.m_rxDeviceSetIndex = response.getSimplePttSettings()->getRxDeviceSetIndex(); + } + if (featureSettingsKeys.contains("txDeviceSetIndex")) { + settings.m_txDeviceSetIndex = response.getSimplePttSettings()->getTxDeviceSetIndex(); + } + if (featureSettingsKeys.contains("rx2TxDelayMs")) { + settings.m_rx2TxDelayMs = response.getSimplePttSettings()->getRx2TxDelayMs(); + } + if (featureSettingsKeys.contains("tx2RxDelayMs")) { + settings.m_tx2RxDelayMs = response.getSimplePttSettings()->getTx2RxDelayMs(); + } +} + +void SimplePTT::webapiFormatFeatureReport(SWGSDRangel::SWGFeatureReport& response) +{ + response.getSimplePttReport()->setPtt(m_ptt ? 1 : 0); +} + +void SimplePTT::webapiReverseSendSettings(QList& channelSettingsKeys, const SimplePTTSettings& settings, bool force) +{ + SWGSDRangel::SWGFeatureSettings *swgFeatureSettings = new SWGSDRangel::SWGFeatureSettings(); + // swgFeatureSettings->setOriginatorFeatureIndex(getIndexInDeviceSet()); + // swgFeatureSettings->setOriginatorFeatureSetIndex(getDeviceSetIndex()); + swgFeatureSettings->setFeatureType(new QString("SimplePTT")); + swgFeatureSettings->setSimplePttSettings(new SWGSDRangel::SWGSimplePTTSettings()); + SWGSDRangel::SWGSimplePTTSettings *swgSimplePTTSettings = swgFeatureSettings->getSimplePttSettings(); + + // transfer data that has been modified. When force is on transfer all data except reverse API data + + if (channelSettingsKeys.contains("title") || force) { + swgSimplePTTSettings->setTitle(new QString(settings.m_title)); + } + if (channelSettingsKeys.contains("rgbColor") || force) { + swgSimplePTTSettings->setRgbColor(settings.m_rgbColor); + } + if (channelSettingsKeys.contains("rxDeviceSetIndex") || force) { + swgSimplePTTSettings->setRxDeviceSetIndex(settings.m_rxDeviceSetIndex); + } + if (channelSettingsKeys.contains("txDeviceSetIndex") || force) { + swgSimplePTTSettings->setTxDeviceSetIndex(settings.m_txDeviceSetIndex); + } + if (channelSettingsKeys.contains("rx2TxDelayMs") || force) { + swgSimplePTTSettings->setRx2TxDelayMs(settings.m_rx2TxDelayMs); + } + if (channelSettingsKeys.contains("tx2RxDelayMs") || force) { + swgSimplePTTSettings->setTx2RxDelayMs(settings.m_tx2RxDelayMs); + } + + QString channelSettingsURL = QString("http://%1:%2/sdrangel/featureset/%3/feature/%4/settings") + .arg(settings.m_reverseAPIAddress) + .arg(settings.m_reverseAPIPort) + .arg(settings.m_reverseAPIDeviceIndex) + .arg(settings.m_reverseAPIChannelIndex); + 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; +} + +void SimplePTT::networkManagerFinished(QNetworkReply *reply) +{ + QNetworkReply::NetworkError replyError = reply->error(); + + if (replyError) + { + qWarning() << "SimplePTT::networkManagerFinished:" + << " error(" << (int) replyError + << "): " << replyError + << ": " << reply->errorString(); + } + else + { + QString answer = reply->readAll(); + answer.chop(1); // remove last \n + qDebug("SimplePTT::networkManagerFinished: reply:\n%s", answer.toStdString().c_str()); + } + + reply->deleteLater(); +} diff --git a/plugins/feature/simpleptt/simpleptt.h b/plugins/feature/simpleptt/simpleptt.h index 8a22d3d71..19dafc336 100644 --- a/plugins/feature/simpleptt/simpleptt.h +++ b/plugins/feature/simpleptt/simpleptt.h @@ -19,6 +19,7 @@ #define INCLUDE_FEATURE_SIMPLEPTT_H_ #include +#include #include "feature/feature.h" #include "util/message.h" @@ -27,6 +28,12 @@ class WebAPIAdapterInterface; class SimplePTTWorker; +class QNetworkAccessManager; +class QNetworkReply; + +namespace SWGSDRangel { + class SWGDeviceState; +} class SimplePTT : public Feature { @@ -91,18 +98,50 @@ public: m_startStop(startStop) { } }; - + SimplePTT(WebAPIAdapterInterface *webAPIAdapterInterface); ~SimplePTT(); virtual void destroy() { delete this; } - virtual bool handleMessage(const Message& cmd); - - virtual void getIdentifier(QString& id) { id = objectName(); } - virtual void getTitle(QString& title) { title = m_settings.m_title; } + 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 webapiReportGet( + SWGSDRangel::SWGFeatureReport& response, + QString& errorMessage); + + virtual int webapiActionsPost( + const QStringList& featureActionsKeys, + SWGSDRangel::SWGFeatureActions& query, + QString& errorMessage); + + static void webapiFormatFeatureSettings( + SWGSDRangel::SWGFeatureSettings& response, + const SimplePTTSettings& settings); + + static void webapiUpdateFeatureSettings( + SimplePTTSettings& settings, + const QStringList& featureSettingsKeys, + SWGSDRangel::SWGFeatureSettings& response); + static const QString m_featureIdURI; static const QString m_featureId; @@ -110,10 +149,19 @@ private: QThread m_thread; SimplePTTWorker *m_worker; SimplePTTSettings m_settings; + bool m_ptt; + + QNetworkAccessManager *m_networkManager; + QNetworkRequest m_networkRequest; void start(); void stop(); void applySettings(const SimplePTTSettings& settings, bool force = false); + void webapiFormatFeatureReport(SWGSDRangel::SWGFeatureReport& response); + void webapiReverseSendSettings(QList& featureSettingsKeys, const SimplePTTSettings& settings, bool force); + +private slots: + void networkManagerFinished(QNetworkReply *reply); }; -#endif // INCLUDE_FEATURE_SIMPLEPTT_H_ \ No newline at end of file +#endif // INCLUDE_FEATURE_SIMPLEPTT_H_ diff --git a/plugins/feature/simpleptt/simplepttgui.cpp b/plugins/feature/simpleptt/simplepttgui.cpp index e71c6d3f8..7dbdefc2a 100644 --- a/plugins/feature/simpleptt/simplepttgui.cpp +++ b/plugins/feature/simpleptt/simplepttgui.cpp @@ -62,13 +62,13 @@ QByteArray SimplePTTGUI::serialize() const bool SimplePTTGUI::deserialize(const QByteArray& data) { - if (m_settings.deserialize(data)) + if (m_settings.deserialize(data)) { displaySettings(); applySettings(true); return true; - } - else + } + else { resetToDefaults(); return false; @@ -87,7 +87,7 @@ bool SimplePTTGUI::handleMessage(const Message& message) blockApplySettings(false); return true; - } + } else if (SimplePTTReport::MsgRadioState::match(message)) { qDebug("SimplePTTGUI::handleMessage: SimplePTTReport::MsgRadioState"); @@ -95,8 +95,19 @@ bool SimplePTTGUI::handleMessage(const Message& message) SimplePTTReport::RadioState state = cfg.getState(); ui->statusIndicator->setStyleSheet("QLabel { background-color: " + m_statusColors[(int) state] + "; border-radius: 12px; }"); - ui->statusIndicator->setToolTip(m_statusTooltips[(int) state]); - + ui->statusIndicator->setToolTip(m_statusTooltips[(int) state]); + + return true; + } + else if (SimplePTT::MsgPTT::match(message)) + { + qDebug("SimplePTTGUI::handleMessage: SimplePTT::MsgPTT"); + const SimplePTT::MsgPTT& cfg = (SimplePTT::MsgPTT&) message; + bool ptt = cfg.getTx(); + ui->ptt->blockSignals(true); + ui->ptt->setChecked(ptt); + ui->ptt->blockSignals(false); + return true; } @@ -136,12 +147,12 @@ SimplePTTGUI::SimplePTTGUI(PluginAPI* pluginAPI, FeatureUISet *featureUISet, Fea m_simplePTT = reinterpret_cast(feature); m_simplePTT->setMessageQueueToGUI(&m_inputMessageQueue); - m_featureUISet->registerFeatureInstance(SimplePTT::m_featureIdURI, this); + m_featureUISet->registerFeatureInstance(SimplePTT::m_featureIdURI, this, m_simplePTT); 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); @@ -174,6 +185,10 @@ void SimplePTTGUI::displaySettings() { setTitleColor(m_settings.m_rgbColor); setWindowTitle(m_settings.m_title); + blockApplySettings(true); + ui->rxtxDelay->setValue(m_settings.m_rx2TxDelayMs); + ui->txrxDelay->setValue(m_settings.m_tx2RxDelayMs); + blockApplySettings(false); } void SimplePTTGUI::updateDeviceSetLists() @@ -208,26 +223,39 @@ void SimplePTTGUI::updateDeviceSetLists() } } + int rxDeviceIndex; + int txDeviceIndex; + if (rxIndex > 0) { if (m_settings.m_rxDeviceSetIndex < 0) { - ui->rxDevice->setCurrentIndex(0); + ui->rxDevice->setCurrentIndex(0); } else { - ui->rxDevice->setCurrentIndex(m_settings.m_rxDeviceSetIndex); + ui->rxDevice->setCurrentIndex(m_settings.m_rxDeviceSetIndex); } + + rxDeviceIndex = ui->rxDevice->currentData().toInt(); } - + else + { + rxDeviceIndex = -1; + } + + if (txIndex > 0) { if (m_settings.m_txDeviceSetIndex < 0) { - ui->txDevice->setCurrentIndex(0); + ui->txDevice->setCurrentIndex(0); } else { ui->txDevice->setCurrentIndex(m_settings.m_txDeviceSetIndex); } + + txDeviceIndex = ui->txDevice->currentData().toInt(); + } + else + { + txDeviceIndex = -1; } - - int rxDeviceIndex = ui->rxDevice->currentData().toInt(); - int txDeviceIndex = ui->txDevice->currentData().toInt(); if ((rxDeviceIndex != m_settings.m_rxDeviceSetIndex) || (txDeviceIndex != m_settings.m_txDeviceSetIndex)) @@ -257,12 +285,22 @@ void SimplePTTGUI::onMenuDialogCalled(const QPoint &p) 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.setReverseAPIDeviceIndex(m_settings.m_reverseAPIDeviceIndex); + dialog.setReverseAPIChannelIndex(m_settings.m_reverseAPIChannelIndex); 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_reverseAPIDeviceIndex = dialog.getReverseAPIDeviceIndex(); + m_settings.m_reverseAPIChannelIndex = dialog.getReverseAPIChannelIndex(); setWindowTitle(m_settings.m_title); setTitleColor(m_settings.m_rgbColor); diff --git a/plugins/feature/simpleptt/simplepttgui.ui b/plugins/feature/simpleptt/simplepttgui.ui index ebe97b6fb..43519b0ad 100644 --- a/plugins/feature/simpleptt/simplepttgui.ui +++ b/plugins/feature/simpleptt/simplepttgui.ui @@ -146,7 +146,7 @@ - Refresh indexes of available local devices + Refresh indexes of available device sets diff --git a/plugins/feature/simpleptt/simplepttsettings.cpp b/plugins/feature/simpleptt/simplepttsettings.cpp index bfe9434d6..f84bde6ce 100644 --- a/plugins/feature/simpleptt/simplepttsettings.cpp +++ b/plugins/feature/simpleptt/simplepttsettings.cpp @@ -33,8 +33,13 @@ void SimplePTTSettings::resetToDefaults() m_rgbColor = QColor(255, 0, 0).rgb(); m_rxDeviceSetIndex = -1; m_txDeviceSetIndex = -1; - m_rx2TxDelayMs = 0; - m_tx2RxDelayMs = 0; + m_rx2TxDelayMs = 100; + m_tx2RxDelayMs = 100; + m_useReverseAPI = false; + m_reverseAPIAddress = "127.0.0.1"; + m_reverseAPIPort = 8888; + m_reverseAPIDeviceIndex = 0; + m_reverseAPIChannelIndex = 0; } QByteArray SimplePTTSettings::serialize() const @@ -47,7 +52,12 @@ QByteArray SimplePTTSettings::serialize() const s.writeS32(4, m_txDeviceSetIndex); s.writeU32(5, m_rx2TxDelayMs); s.writeU32(6, m_tx2RxDelayMs); - + s.writeBool(7, m_useReverseAPI); + s.writeString(8, m_reverseAPIAddress); + s.writeU32(9, m_reverseAPIPort); + s.writeU32(10, m_reverseAPIDeviceIndex); + s.writeU32(11, m_reverseAPIChannelIndex); + return s.final(); } @@ -72,8 +82,22 @@ bool SimplePTTSettings::deserialize(const QByteArray& data) d.readU32(2, &m_rgbColor, QColor(255, 0, 0).rgb()); d.readS32(3, &m_rxDeviceSetIndex, -1); d.readS32(4, &m_txDeviceSetIndex, -1); - d.readU32(5, &m_rx2TxDelayMs, 0); - d.readU32(6, &m_tx2RxDelayMs, 0); + d.readU32(5, &m_rx2TxDelayMs, 100); + d.readU32(6, &m_tx2RxDelayMs, 100); + d.readBool(7, &m_useReverseAPI, false); + d.readString(8, &m_reverseAPIAddress, "127.0.0.1"); + d.readU32(9, &utmp, 0); + + if ((utmp > 1023) && (utmp < 65535)) { + m_reverseAPIPort = utmp; + } else { + m_reverseAPIPort = 8888; + } + + d.readU32(10, &utmp, 0); + m_reverseAPIDeviceIndex = utmp > 99 ? 99 : utmp; + d.readU32(11, &utmp, 0); + m_reverseAPIChannelIndex = utmp > 99 ? 99 : utmp; return true; } diff --git a/plugins/feature/simpleptt/simplepttsettings.h b/plugins/feature/simpleptt/simplepttsettings.h index 9d003141f..de89d72d1 100644 --- a/plugins/feature/simpleptt/simplepttsettings.h +++ b/plugins/feature/simpleptt/simplepttsettings.h @@ -31,6 +31,11 @@ struct SimplePTTSettings int m_txDeviceSetIndex; unsigned int m_rx2TxDelayMs; unsigned int m_tx2RxDelayMs; + bool m_useReverseAPI; + QString m_reverseAPIAddress; + uint16_t m_reverseAPIPort; + uint16_t m_reverseAPIDeviceIndex; + uint16_t m_reverseAPIChannelIndex; SimplePTTSettings(); void resetToDefaults(); diff --git a/plugins/feature/simpleptt/simplepttworker.cpp b/plugins/feature/simpleptt/simplepttworker.cpp index c1d47d635..6aceb3d56 100644 --- a/plugins/feature/simpleptt/simplepttworker.cpp +++ b/plugins/feature/simpleptt/simplepttworker.cpp @@ -33,6 +33,7 @@ SimplePTTWorker::SimplePTTWorker(WebAPIAdapterInterface *webAPIAdapterInterface) m_webAPIAdapterInterface(webAPIAdapterInterface), m_msgQueueToGUI(nullptr), m_running(false), + m_tx(false), m_mutex(QMutex::Recursive) { qDebug("SimplePTTWorker::SimplePTTWorker"); diff --git a/sdrbase/feature/feature.cpp b/sdrbase/feature/feature.cpp index 7435be7da..75ce9f970 100644 --- a/sdrbase/feature/feature.cpp +++ b/sdrbase/feature/feature.cpp @@ -20,14 +20,16 @@ #include "util/uid.h" #include "util/message.h" +#include "SWGDeviceState.h" + #include "feature.h" Feature::Feature(const QString& name, WebAPIAdapterInterface *webAPIAdapterInterface) : m_name(name), m_uid(UidCalculator::getNewObjectId()), m_webAPIAdapterInterface(webAPIAdapterInterface) -{ - connect(&m_inputMessageQueue, SIGNAL(messageEnqueued()), this, SLOT(handleInputMessages())); +{ + connect(&m_inputMessageQueue, SIGNAL(messageEnqueued()), this, SLOT(handleInputMessages())); } void Feature::handleInputMessages() @@ -40,4 +42,34 @@ void Feature::handleInputMessages() delete message; } } -} \ No newline at end of file +} + +int Feature::webapiRunGet( + SWGSDRangel::SWGDeviceState& response, + QString& errorMessage) const +{ + getFeatureStateStr(*response.getState()); + return 200; +} + +void Feature::getFeatureStateStr(QString& stateStr) const +{ + switch(m_state) + { + case StNotStarted: + stateStr = "notStarted"; + break; + case StIdle: + stateStr = "idle"; + break; + case StRunning: + stateStr = "running"; + break; + case StError: + stateStr = "error"; + break; + default: + stateStr = "notStarted"; + break; + } +} diff --git a/sdrbase/feature/feature.h b/sdrbase/feature/feature.h index ed051fa24..e07769440 100644 --- a/sdrbase/feature/feature.h +++ b/sdrbase/feature/feature.h @@ -25,10 +25,19 @@ #include #include "export.h" +#include "util/message.h" #include "util/messagequeue.h" class WebAPIAdapterInterface; +namespace SWGSDRangel +{ + class SWGFeatureSettings; + class SWGFeatureReport; + class SWGFeatureActions; + class SWGDeviceState; +} + class SDRBASE_API Feature : public QObject { Q_OBJECT public: @@ -44,14 +53,83 @@ public: virtual void destroy() = 0; virtual bool handleMessage(const Message& cmd) = 0; //!< Processing of a message. Returns true if message has actually been processed - virtual void getIdentifier(QString& id) = 0; - virtual void getTitle(QString& title) = 0; + virtual void getIdentifier(QString& id) const = 0; + virtual void getTitle(QString& title) const = 0; virtual void setName(const QString& name) { m_name = name; } virtual const QString& getName() const { return m_name; } virtual QByteArray serialize() const = 0; virtual bool deserialize(const QByteArray& data) = 0; + /** + * API adapter for the feature run GET requests + */ + virtual int webapiRunGet( + SWGSDRangel::SWGDeviceState& response, + QString& errorMessage) const; + + /** + * API adapter for the feature run POST and DELETE requests + */ + virtual int webapiRun(bool run, + SWGSDRangel::SWGDeviceState& response, + QString& errorMessage) + { + (void) run; + (void) response; + errorMessage = "Not implemented"; + return 501; + } + + /** + * API adapter for the feature settings GET requests + */ + virtual int webapiSettingsGet( + SWGSDRangel::SWGFeatureSettings& response, + QString& errorMessage) + { + (void) response; + errorMessage = "Not implemented"; return 501; + } + + /** + * API adapter for the feature settings PUT and PATCH requests + */ + virtual int webapiSettingsPutPatch( + bool force, + const QStringList& featureSettingsKeys, + SWGSDRangel::SWGFeatureSettings& response, + QString& errorMessage) + { + (void) force; + (void) featureSettingsKeys; + (void) response; + errorMessage = "Not implemented"; return 501; + } + + /** + * API adapter for the feature report GET requests + */ + virtual int webapiReportGet( + SWGSDRangel::SWGFeatureReport& response, + QString& errorMessage) + { + (void) response; + errorMessage = "Not implemented"; return 501; + } + + /** + * API adapter for the feature actions POST requests + */ + virtual int webapiActionsPost( + const QStringList& featureActionsKeys, + SWGSDRangel::SWGFeatureActions& query, + QString& errorMessage) + { + (void) query; + (void) featureActionsKeys; + errorMessage = "Not implemented"; return 501; + } uint64_t getUID() const { return m_uid; } FeatureState getState() const { return m_state; } @@ -68,6 +146,8 @@ protected: QString m_errorMessage; WebAPIAdapterInterface *m_webAPIAdapterInterface; + void getFeatureStateStr(QString& stateStr) const; + protected slots: void handleInputMessages(); @@ -76,4 +156,4 @@ private: uint64_t m_uid; }; -#endif // SDRBASE_FETURE_FEATUREAPI_H_ \ No newline at end of file +#endif // SDRBASE_FETURE_FEATUREAPI_H_ diff --git a/sdrbase/resources/webapi/doc/html2/index.html b/sdrbase/resources/webapi/doc/html2/index.html index a38dae6ec..00f0c9695 100644 --- a/sdrbase/resources/webapi/doc/html2/index.html +++ b/sdrbase/resources/webapi/doc/html2/index.html @@ -38907,7 +38907,7 @@ except ApiException as e:
- Generated 2020-09-28T13:19:26.040+02:00 + Generated 2020-09-28T13:34:44.975+02:00
diff --git a/sdrbase/webapi/webapiadapterinterface.h b/sdrbase/webapi/webapiadapterinterface.h index c5f409e84..f5fe01fc8 100644 --- a/sdrbase/webapi/webapiadapterinterface.h +++ b/sdrbase/webapi/webapiadapterinterface.h @@ -62,6 +62,11 @@ namespace SWGSDRangel class SWGChannelReport; class SWGChannelActions; class SWGSuccessResponse; + class SWGFeatureSetList; + class SWGFeatureSet; + class SWGFeatureSettings; + class SWGFeatureReport; + class SWGFeatureActions; } class SDRBASE_API WebAPIAdapterInterface diff --git a/sdrgui/feature/featureuiset.cpp b/sdrgui/feature/featureuiset.cpp index 35f659ca1..85a8673ab 100644 --- a/sdrgui/feature/featureuiset.cpp +++ b/sdrgui/feature/featureuiset.cpp @@ -36,9 +36,9 @@ void FeatureUISet::addRollupWidget(QWidget *widget) m_featureWindow->addRollupWidget(widget); } -void FeatureUISet::registerFeatureInstance(const QString& featureName, PluginInstanceGUI* pluginGUI) +void FeatureUISet::registerFeatureInstance(const QString& featureName, PluginInstanceGUI* pluginGUI, Feature *feature) { - m_featureInstanceRegistrations.append(FeatureInstanceRegistration(featureName, pluginGUI)); + m_featureInstanceRegistrations.append(FeatureInstanceRegistration(featureName, pluginGUI, feature)); renameFeatureInstances(); } @@ -83,3 +83,21 @@ void FeatureUISet::deleteFeature(int featureIndex) renameFeatureInstances(); } } + +const Feature *FeatureUISet::getFeatureAt(int featureIndex) const +{ + if ((featureIndex >= 0) && (featureIndex < m_featureInstanceRegistrations.count())) { + return m_featureInstanceRegistrations[featureIndex].m_feature; + } else{ + return nullptr; + } +} + +Feature *FeatureUISet::getFeatureAt(int featureIndex) +{ + if ((featureIndex >= 0) && (featureIndex < m_featureInstanceRegistrations.count())) { + return m_featureInstanceRegistrations[featureIndex].m_feature; + } else{ + return nullptr; + } +} diff --git a/sdrgui/feature/featureuiset.h b/sdrgui/feature/featureuiset.h index b74a9929f..7bb36e578 100644 --- a/sdrgui/feature/featureuiset.h +++ b/sdrgui/feature/featureuiset.h @@ -26,6 +26,7 @@ class QWidget; class FeatureWindow; class PluginInstanceGUI; +class Feature; class SDRGUI_API FeatureUISet { @@ -35,10 +36,12 @@ public: void addRollupWidget(QWidget *widget); //!< Add feature rollup widget to feature window int getNumberOfFeatures() const { return m_featureInstanceRegistrations.size(); } - void registerFeatureInstance(const QString& featureName, PluginInstanceGUI* pluginGUI); + void registerFeatureInstance(const QString& featureName, PluginInstanceGUI* pluginGUI, Feature *feature); void removeFeatureInstance(PluginInstanceGUI* pluginGUI); void freeFeatures(); void deleteFeature(int featureIndex); + const Feature *getFeatureAt(int featureIndex) const; + Feature *getFeatureAt(int featureIndex); FeatureWindow *m_featureWindow; @@ -47,15 +50,18 @@ private: { QString m_featureName; PluginInstanceGUI* m_gui; + Feature* m_feature; FeatureInstanceRegistration() : m_featureName(), - m_gui(nullptr) + m_gui(nullptr), + m_feature(nullptr) { } - FeatureInstanceRegistration(const QString& featureName, PluginInstanceGUI* pluginGUI) : + FeatureInstanceRegistration(const QString& featureName, PluginInstanceGUI* pluginGUI, Feature *feature) : m_featureName(featureName), - m_gui(pluginGUI) + m_gui(pluginGUI), + m_feature(feature) { } bool operator<(const FeatureInstanceRegistration& other) const; diff --git a/sdrgui/gui/basicfeaturesettingsdialog.h b/sdrgui/gui/basicfeaturesettingsdialog.h index 79168809b..81563dcce 100644 --- a/sdrgui/gui/basicfeaturesettingsdialog.h +++ b/sdrgui/gui/basicfeaturesettingsdialog.h @@ -37,6 +37,16 @@ public: void setColor(const QColor& color); const QString& getTitle() const { return m_title; } const QColor& getColor() const { return m_color; } + bool useReverseAPI() const { return m_useReverseAPI; } + const QString& getReverseAPIAddress() const { return m_reverseAPIAddress; } + uint16_t getReverseAPIPort() const { return m_reverseAPIPort; } + uint16_t getReverseAPIDeviceIndex() const { return m_reverseAPIDeviceIndex; } + uint16_t getReverseAPIChannelIndex() const { return m_reverseAPIChannelIndex; } + void setUseReverseAPI(bool useReverseAPI); + void setReverseAPIAddress(const QString& address); + void setReverseAPIPort(uint16_t port); + void setReverseAPIDeviceIndex(uint16_t deviceIndex); + void setReverseAPIChannelIndex(uint16_t channelIndex); bool hasChanged() const { return m_hasChanged; } private slots: @@ -48,6 +58,11 @@ private: Ui::BasicFeatureSettingsDialog *ui; QColor m_color; QString m_title; + bool m_useReverseAPI; + QString m_reverseAPIAddress; + uint16_t m_reverseAPIPort; + uint16_t m_reverseAPIDeviceIndex; + uint16_t m_reverseAPIChannelIndex; bool m_hasChanged; void paintColor(); diff --git a/sdrgui/gui/basicfeaturesettingsdialog.ui b/sdrgui/gui/basicfeaturesettingsdialog.ui index db8ce091b..ae8788606 100644 --- a/sdrgui/gui/basicfeaturesettingsdialog.ui +++ b/sdrgui/gui/basicfeaturesettingsdialog.ui @@ -91,6 +91,154 @@ + + + + + + Sychronize with reverse API + + + reverse API + + + + + + + + 120 + 0 + + + + Reverse API address + + + 000.000.000.000 + + + 127.0.0.1 + + + + + + + : + + + + + + + + 45 + 0 + + + + + 45 + 16777215 + + + + Reverse API port + + + 00000 + + + 8888 + + + + + + + D + + + + + + + + 22 + 0 + + + + + 22 + 16777215 + + + + Reverse API destination device index + + + 00 + + + 0 + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + C + + + + + + + + 22 + 0 + + + + + 22 + 16777215 + + + + Reverse API destination channel index + + + 00 + + + 0 + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + diff --git a/sdrgui/mainwindow.cpp b/sdrgui/mainwindow.cpp index b492208b4..ed2743215 100644 --- a/sdrgui/mainwindow.cpp +++ b/sdrgui/mainwindow.cpp @@ -95,6 +95,8 @@ MESSAGE_CLASS_DEFINITION(MainWindow::MsgAddChannel, Message) MESSAGE_CLASS_DEFINITION(MainWindow::MsgDeleteChannel, Message) MESSAGE_CLASS_DEFINITION(MainWindow::MsgDeviceSetFocus, Message) MESSAGE_CLASS_DEFINITION(MainWindow::MsgApplySettings, Message) +MESSAGE_CLASS_DEFINITION(MainWindow::MsgAddFeature, Message) +MESSAGE_CLASS_DEFINITION(MainWindow::MsgDeleteFeature, Message) MainWindow *MainWindow::m_instance = 0; @@ -995,6 +997,20 @@ bool MainWindow::handleMessage(const Message& cmd) ui->tabInputsView->setCurrentIndex(index); } } + else if (MsgAddFeature::match(cmd)) + { + MsgAddFeature& notif = (MsgAddFeature&) cmd; + ui->tabFeatures->setCurrentIndex(notif.getFeatureSetIndex()); + featureAddClicked(notif.getFeatureRegistrationIndex()); + + return true; + } + else if (MsgDeleteFeature::match(cmd)) + { + MsgDeleteFeature& notif = (MsgDeleteFeature&) cmd; + deleteFeature(notif.getFeatureSetIndex(), notif.getFeatureIndex()); + return true; + } else if (MsgApplySettings::match(cmd)) { applySettings(); @@ -1901,6 +1917,15 @@ void MainWindow::featureAddClicked(int featureIndex) } } +void MainWindow::deleteFeature(int featureSetIndex, int featureIndex) +{ + if ((featureSetIndex >= 0) && (featureSetIndex < (int) m_featureUIs.size())) + { + FeatureUISet *featureSet = m_featureUIs[featureSetIndex]; + featureSet->deleteFeature(featureIndex); + } +} + void MainWindow::on_action_About_triggered() { AboutDialog dlg(m_apiHost, m_apiPort, m_settings, this); diff --git a/sdrgui/mainwindow.h b/sdrgui/mainwindow.h index 1ce970163..869520074 100644 --- a/sdrgui/mainwindow.h +++ b/sdrgui/mainwindow.h @@ -288,6 +288,51 @@ private: { } }; + class MsgAddFeature : public Message { + MESSAGE_CLASS_DECLARATION + + public: + int getFeatureSetIndex() const { return m_featureSetIndex; } + int getFeatureRegistrationIndex() const { return m_featureRegistrationIndex; } + + static MsgAddFeature* create(int featureSetIndex, int featureRegistrationIndex) + { + return new MsgAddFeature(featureSetIndex, featureRegistrationIndex); + } + + private: + int m_featureSetIndex; + int m_featureRegistrationIndex; + + MsgAddFeature(int featureSetIndex, int featureRegistrationIndex) : + Message(), + m_featureSetIndex(featureSetIndex), + m_featureRegistrationIndex(featureRegistrationIndex) + { } + }; + + class MsgDeleteFeature : public Message { + MESSAGE_CLASS_DECLARATION + + public: + int getFeatureSetIndex() const { return m_featureSetIndex; } + int getFeatureIndex() const { return m_featureIndex; } + + static MsgDeleteFeature* create(int m_featureSetIndex, int m_featureIndex) { + return new MsgDeleteFeature(m_featureSetIndex, m_featureIndex); + } + + private: + int m_featureSetIndex; + int m_featureIndex; + + MsgDeleteFeature(int m_featureSetIndex, int m_featureIndex) : + Message(), + m_featureSetIndex(m_featureSetIndex), + m_featureIndex(m_featureIndex) + { } + }; + enum { PGroup, PItem @@ -370,6 +415,7 @@ private: void deleteChannel(int deviceSetIndex, int channelIndex); void sampleSourceChanged(int tabIndex, int newDeviceIndex); void sampleSinkChanged(int tabIndex, int newDeviceIndex); + void deleteFeature(int featureSetIndex, int featureIndex); void setLoggingOptions(); diff --git a/sdrgui/webapi/webapiadaptergui.cpp b/sdrgui/webapi/webapiadaptergui.cpp index 9924946fc..55b8904a7 100644 --- a/sdrgui/webapi/webapiadaptergui.cpp +++ b/sdrgui/webapi/webapiadaptergui.cpp @@ -27,6 +27,8 @@ #include "device/deviceapi.h" #include "device/deviceuiset.h" #include "device/deviceenumerator.h" +#include "feature/featureuiset.h" +#include "feature/feature.h" #include "dsp/devicesamplesource.h" #include "dsp/devicesamplesink.h" #include "dsp/devicesamplemimo.h" @@ -69,6 +71,10 @@ #include "SWGLimeRFEDevices.h" #include "SWGLimeRFESettings.h" #include "SWGLimeRFEPower.h" +#include "SWGFeatureSetList.h" +#include "SWGFeatureSettings.h" +#include "SWGFeatureReport.h" +#include "SWGFeatureActions.h" #ifdef HAS_LIMERFEUSB #include "limerfe/limerfecontroller.h" @@ -1332,6 +1338,15 @@ int WebAPIAdapterGUI::instanceDeviceSetsGet( return 200; } +int WebAPIAdapterGUI::instanceFeatureSetsGet( + SWGSDRangel::SWGFeatureSetList& response, + SWGSDRangel::SWGErrorResponse& error) +{ + (void) error; + getFeatureSetList(&response); + return 200; +} + int WebAPIAdapterGUI::instanceDeviceSetPost( int direction, SWGSDRangel::SWGSuccessResponse& response, @@ -1389,7 +1404,7 @@ int WebAPIAdapterGUI::devicesetGet( return 404; } - } +} int WebAPIAdapterGUI::devicesetFocusPatch( int deviceSetIndex, @@ -2287,7 +2302,6 @@ int WebAPIAdapterGUI::devicesetChannelSettingsGet( } } - int WebAPIAdapterGUI::devicesetChannelReportGet( int deviceSetIndex, int channelIndex, @@ -2677,6 +2691,352 @@ int WebAPIAdapterGUI::devicesetChannelSettingsPutPatch( } } +int WebAPIAdapterGUI::featuresetFeaturePost( + int featureSetIndex, + SWGSDRangel::SWGFeatureSettings& query, + SWGSDRangel::SWGSuccessResponse& response, + SWGSDRangel::SWGErrorResponse& error) +{ + if ((featureSetIndex >= 0) && (featureSetIndex < (int) m_mainWindow.m_featureUIs.size())) + { + FeatureUISet *featureSet = m_mainWindow.m_featureUIs[featureSetIndex]; + + PluginAPI::FeatureRegistrations *featureRegistrations = m_mainWindow.m_pluginManager->getFeatureRegistrations(); + int nbRegistrations = featureRegistrations->size(); + int index = 0; + + for (; index < nbRegistrations; index++) + { + if (featureRegistrations->at(index).m_featureId == *query.getFeatureType()) { + break; + } + } + + if (index < nbRegistrations) + { + MainWindow::MsgAddFeature *msg = MainWindow::MsgAddFeature::create(featureSetIndex, index); + m_mainWindow.m_inputMessageQueue.push(msg); + + response.init(); + *response.getMessage() = QString("Message to add a feature (MsgAddFeature) was submitted successfully"); + + return 202; + } + else + { + error.init(); + *error.getMessage() = QString("There is no feature with id %1").arg(*query.getFeatureType()); + return 404; + } + } + else + { + error.init(); + *error.getMessage() = QString("There is no feature set with index %1").arg(featureSetIndex); + return 404; + } +} + +int WebAPIAdapterGUI::featuresetFeatureDelete( + int featureSetIndex, + int featureIndex, + SWGSDRangel::SWGSuccessResponse& response, + SWGSDRangel::SWGErrorResponse& error) +{ + if ((featureSetIndex >= 0) && (featureSetIndex < (int) m_mainWindow.m_featureUIs.size())) + { + FeatureUISet *featureSet = m_mainWindow.m_featureUIs[featureSetIndex]; + + if (featureIndex < featureSet->getNumberOfFeatures()) + { + MainWindow::MsgDeleteFeature *msg = MainWindow::MsgDeleteFeature::create(featureSetIndex, featureIndex); + m_mainWindow.m_inputMessageQueue.push(msg); + + response.init(); + *response.getMessage() = QString("Message to delete a feature (MsgDeleteFeature) was submitted successfully"); + + return 202; + } + else + { + error.init(); + *error.getMessage() = QString("There is no feature at index %1. %2 feature(s) left") + .arg(featureIndex) + .arg(featureSet->getNumberOfFeatures()); + return 400; + } + } + else + { + error.init(); + *error.getMessage() = QString("There is no device set with index %1").arg(featureSetIndex); + return 404; + } +} + +int WebAPIAdapterGUI::featuresetFeatureRunGet( + int featureSetIndex, + int featureIndex, + SWGSDRangel::SWGDeviceState& response, + SWGSDRangel::SWGErrorResponse& error) +{ + if ((featureSetIndex >= 0) && (featureSetIndex < (int) m_mainWindow.m_featureUIs.size())) + { + FeatureUISet *featureSet = m_mainWindow.m_featureUIs[featureSetIndex]; + + if (featureIndex < featureSet->getNumberOfFeatures()) + { + response.init(); + const Feature *feature = featureSet->getFeatureAt(featureIndex); + return feature->webapiRunGet(response, *error.getMessage()); + } + else + { + error.init(); + *error.getMessage() = QString("There is no feature at index %1. %2 feature(s) left") + .arg(featureIndex) + .arg(featureSet->getNumberOfFeatures()); + return 400; + } + } + else + { + error.init(); + *error.getMessage() = QString("There is no feature set with index %1").arg(featureSetIndex); + return 404; + } +} + +int WebAPIAdapterGUI::featuresetFeatureRunPost( + int featureSetIndex, + int featureIndex, + SWGSDRangel::SWGDeviceState& response, + SWGSDRangel::SWGErrorResponse& error) +{ + if ((featureSetIndex >= 0) && (featureSetIndex < (int) m_mainWindow.m_featureUIs.size())) + { + FeatureUISet *featureSet = m_mainWindow.m_featureUIs[featureSetIndex]; + + if (featureIndex < featureSet->getNumberOfFeatures()) + { + response.init(); + Feature *feature = featureSet->getFeatureAt(featureIndex); + return feature->webapiRun(true, response, *error.getMessage()); + } + else + { + error.init(); + *error.getMessage() = QString("There is no feature at index %1. %2 feature(s) left") + .arg(featureIndex) + .arg(featureSet->getNumberOfFeatures()); + return 400; + } + } + else + { + error.init(); + *error.getMessage() = QString("There is no feature set with index %1").arg(featureSetIndex); + return 404; + } +} + +int WebAPIAdapterGUI::featuresetFeatureRunDelete( + int featureSetIndex, + int featureIndex, + SWGSDRangel::SWGDeviceState& response, + SWGSDRangel::SWGErrorResponse& error) +{ + if ((featureSetIndex >= 0) && (featureSetIndex < (int) m_mainWindow.m_featureUIs.size())) + { + FeatureUISet *featureSet = m_mainWindow.m_featureUIs[featureSetIndex]; + + if (featureIndex < featureSet->getNumberOfFeatures()) + { + response.init(); + Feature *feature = featureSet->getFeatureAt(featureIndex); + return feature->webapiRun(false, response, *error.getMessage()); + } + else + { + error.init(); + *error.getMessage() = QString("There is no feature at index %1. %2 feature(s) left") + .arg(featureIndex) + .arg(featureSet->getNumberOfFeatures()); + return 400; + } + } + else + { + error.init(); + *error.getMessage() = QString("There is no feature set with index %1").arg(featureSetIndex); + return 404; + } +} + +int WebAPIAdapterGUI::featuresetFeatureSettingsGet( + int featureSetIndex, + int featureIndex, + SWGSDRangel::SWGFeatureSettings& response, + SWGSDRangel::SWGErrorResponse& error) +{ + error.init(); + + if ((featureSetIndex >= 0) && (featureSetIndex < (int) m_mainWindow.m_deviceUIs.size())) + { + FeatureUISet *featureSet = m_mainWindow.m_featureUIs[featureSetIndex]; + Feature *feature = featureSet->getFeatureAt(featureIndex); + + if (feature) + { + response.setFeatureType(new QString()); + feature->getIdentifier(*response.getFeatureType()); + return feature->webapiSettingsGet(response, *error.getMessage()); + } + else + { + *error.getMessage() = QString("There is no feature with index %1").arg(featureIndex); + return 404; + } + } + else + { + *error.getMessage() = QString("There is no feature set with index %1").arg(featureSetIndex); + return 404; + } +} + +int WebAPIAdapterGUI::featuresetFeatureSettingsPutPatch( + int featureSetIndex, + int featureIndex, + bool force, + const QStringList& featureSettingsKeys, + SWGSDRangel::SWGFeatureSettings& response, + SWGSDRangel::SWGErrorResponse& error) +{ + error.init(); + + if ((featureSetIndex >= 0) && (featureSetIndex < (int) m_mainWindow.m_featureUIs.size())) + { + FeatureUISet *featureSet = m_mainWindow.m_featureUIs[featureSetIndex]; + Feature *feature = featureSet->getFeatureAt(featureIndex); + + if (feature) + { + QString featureType; + feature->getIdentifier(featureType); + + if (featureType == *response.getFeatureType()) + { + return feature->webapiSettingsPutPatch(force, featureSettingsKeys, response, *error.getMessage()); + } + else + { + *error.getMessage() = QString("There is no feature type %1 at index %2. Found %3.") + .arg(*response.getFeatureType()) + .arg(featureIndex) + .arg(featureType); + return 404; + } + } + else + { + *error.getMessage() = QString("There is no feature with index %1").arg(featureIndex); + return 404; + } + } + else + { + *error.getMessage() = QString("There is no feature set with index %1").arg(featureSetIndex); + return 404; + } +} + +int WebAPIAdapterGUI::featuresetFeatureReportGet( + int featureSetIndex, + int featureIndex, + SWGSDRangel::SWGFeatureReport& response, + SWGSDRangel::SWGErrorResponse& error) +{ + error.init(); + + if ((featureSetIndex >= 0) && (featureSetIndex < (int) m_mainWindow.m_featureUIs.size())) + { + FeatureUISet *featureSet = m_mainWindow.m_featureUIs[featureSetIndex]; + Feature *feature = featureSet->getFeatureAt(featureIndex); + + if (feature) + { + response.setFeatureType(new QString()); + feature->getIdentifier(*response.getFeatureType()); + return feature->webapiReportGet(response, *error.getMessage()); + } + else + { + *error.getMessage() = QString("There is no feature with index %1").arg(featureIndex); + return 404; + } + } + else + { + *error.getMessage() = QString("There is no feature set with index %1").arg(featureIndex); + return 404; + } +} + +int WebAPIAdapterGUI::featuresetFeatureActionsPost( + int featureSetIndex, + int featureIndex, + const QStringList& featureActionsKeys, + SWGSDRangel::SWGFeatureActions& query, + SWGSDRangel::SWGSuccessResponse& response, + SWGSDRangel::SWGErrorResponse& error) +{ + error.init(); + + if ((featureSetIndex >= 0) && (featureSetIndex < (int) m_mainWindow.m_featureUIs.size())) + { + FeatureUISet *featureSet = m_mainWindow.m_featureUIs[featureSetIndex]; + Feature *feature = featureSet->getFeatureAt(featureIndex); + + if (feature) + { + QString featureType; + feature->getIdentifier(featureType); + + if (featureType == *query.getFeatureType()) + { + int res = feature->webapiActionsPost(featureActionsKeys, query, *error.getMessage()); + + if (res/100 == 2) + { + response.init(); + *response.getMessage() = QString("Message to post action was submitted successfully"); + } + + return res; + } + else + { + *error.getMessage() = QString("There is no feature type %1 at index %2. Found %3.") + .arg(*query.getFeatureType()) + .arg(featureIndex) + .arg(featureType); + return 404; + } + } + else + { + *error.getMessage() = QString("There is no feature with index %1").arg(featureIndex); + return 404; + } + } + else + { + *error.getMessage() = QString("There is no feature set with index %1").arg(featureIndex); + return 404; + } +} + void WebAPIAdapterGUI::getDeviceSetList(SWGSDRangel::SWGDeviceSetList* deviceSetList) { deviceSetList->init(); @@ -2969,6 +3329,63 @@ void WebAPIAdapterGUI::getChannelsDetail(SWGSDRangel::SWGChannelsDetail *channel } } +int WebAPIAdapterGUI::featuresetGet( + int featureSetIndex, + SWGSDRangel::SWGFeatureSet& response, + SWGSDRangel::SWGErrorResponse& error) +{ + if ((featureSetIndex >= 0) && (featureSetIndex < (int) m_mainWindow.m_featureUIs.size())) + { + const FeatureUISet *featureSet = m_mainWindow.m_featureUIs[featureSetIndex]; + getFeatureSet(&response, featureSet, featureSetIndex); + + return 200; + } + else + { + error.init(); + *error.getMessage() = QString("There is no feature set with index %1").arg(featureSetIndex); + + return 404; + } +} + +void WebAPIAdapterGUI::getFeatureSetList(SWGSDRangel::SWGFeatureSetList* featureSetList) +{ + featureSetList->init(); + featureSetList->setFeaturesetcount((int) m_mainWindow.m_featureUIs.size()); + + std::vector::const_iterator it = m_mainWindow.m_featureUIs.begin(); + + for (int i = 0; it != m_mainWindow.m_featureUIs.end(); ++it, i++) + { + QList *featureSets = featureSetList->getFeatureSets(); + featureSets->append(new SWGSDRangel::SWGFeatureSet()); + + getFeatureSet(featureSets->back(), *it, i); + } +} + +void WebAPIAdapterGUI::getFeatureSet(SWGSDRangel::SWGFeatureSet *featureSet, const FeatureUISet* featureUISet, int featureUISetIndex) +{ + featureSet->init(); + featureSet->setFeaturecount(featureUISet->getNumberOfFeatures()); + QList *features = featureSet->getFeatures(); + + for (int i = 0; i < featureUISet->getNumberOfFeatures(); i++) + { + const Feature *feature = featureUISet->getFeatureAt(i); + features->append(new SWGSDRangel::SWGFeature); + features->back()->setIndex(i); + QString s; + feature->getTitle(s); + features->back()->setTitle(new QString(s)); + feature->getIdentifier(s); + features->back()->setId(new QString(s)); + features->back()->setUid(feature->getUID()); + } +} + QtMsgType WebAPIAdapterGUI::getMsgTypeFromString(const QString& msgTypeString) { if (msgTypeString == "debug") { diff --git a/sdrgui/webapi/webapiadaptergui.h b/sdrgui/webapi/webapiadaptergui.h index 52568f68d..5fc414a77 100644 --- a/sdrgui/webapi/webapiadaptergui.h +++ b/sdrgui/webapi/webapiadaptergui.h @@ -193,6 +193,10 @@ public: SWGSDRangel::SWGDeviceSetList& response, SWGSDRangel::SWGErrorResponse& error); + virtual int instanceFeatureSetsGet( + SWGSDRangel::SWGFeatureSetList& response, + SWGSDRangel::SWGErrorResponse& error); + virtual int instanceDeviceSetPost( int direction, SWGSDRangel::SWGSuccessResponse& response, @@ -320,12 +324,77 @@ public: SWGSDRangel::SWGChannelReport& response, SWGSDRangel::SWGErrorResponse& error); + virtual int featuresetGet( + int deviceSetIndex, + SWGSDRangel::SWGFeatureSet& response, + SWGSDRangel::SWGErrorResponse& error); + + virtual int featuresetFeaturePost( + int featureSetIndex, + SWGSDRangel::SWGFeatureSettings& query, + SWGSDRangel::SWGSuccessResponse& response, + SWGSDRangel::SWGErrorResponse& error); + + virtual int featuresetFeatureDelete( + int featureSetIndex, + int featureIndex, + SWGSDRangel::SWGSuccessResponse& response, + SWGSDRangel::SWGErrorResponse& error); + + virtual int featuresetFeatureRunGet( + int featureSetIndex, + int featureIndex, + SWGSDRangel::SWGDeviceState& response, + SWGSDRangel::SWGErrorResponse& error); + + virtual int featuresetFeatureRunPost( + int featureSetIndex, + int featureIndex, + SWGSDRangel::SWGDeviceState& response, + SWGSDRangel::SWGErrorResponse& error); + + virtual int featuresetFeatureRunDelete( + int featureSetIndex, + int featureIndex, + SWGSDRangel::SWGDeviceState& response, + SWGSDRangel::SWGErrorResponse& error); + + virtual int featuresetFeatureSettingsGet( + int featureSetIndex, + int featureIndex, + SWGSDRangel::SWGFeatureSettings& response, + SWGSDRangel::SWGErrorResponse& error); + + virtual int featuresetFeatureSettingsPutPatch( + int featureSetIndex, + int featureIndex, + bool force, + const QStringList& featureSettingsKeys, + SWGSDRangel::SWGFeatureSettings& response, + SWGSDRangel::SWGErrorResponse& error); + + virtual int featuresetFeatureReportGet( + int featureSetIndex, + int featureIndex, + SWGSDRangel::SWGFeatureReport& response, + SWGSDRangel::SWGErrorResponse& error); + + virtual int featuresetFeatureActionsPost( + int featureSetIndex, + int featureIndex, + const QStringList& featureActionsKeys, + SWGSDRangel::SWGFeatureActions& query, + SWGSDRangel::SWGSuccessResponse& response, + SWGSDRangel::SWGErrorResponse& error); + private: MainWindow& m_mainWindow; void getDeviceSetList(SWGSDRangel::SWGDeviceSetList* deviceSetList); void getDeviceSet(SWGSDRangel::SWGDeviceSet *deviceSet, const DeviceUISet* deviceUISet, int deviceUISetIndex); void getChannelsDetail(SWGSDRangel::SWGChannelsDetail *channelsDetail, const DeviceUISet* deviceUISet); + void getFeatureSetList(SWGSDRangel::SWGFeatureSetList* featureSetList); + void getFeatureSet(SWGSDRangel::SWGFeatureSet *featureSet, const FeatureUISet* featureUISet, int featureUISetIndex); static QtMsgType getMsgTypeFromString(const QString& msgTypeString); static void getMsgTypeString(const QtMsgType& msgType, QString& level); }; diff --git a/sdrsrv/CMakeLists.txt b/sdrsrv/CMakeLists.txt index 30189c573..6fd67d9b3 100644 --- a/sdrsrv/CMakeLists.txt +++ b/sdrsrv/CMakeLists.txt @@ -3,12 +3,14 @@ project (sdrsrv) set(sdrsrv_SOURCES maincore.cpp device/deviceset.cpp + feature/featureset.cpp webapi/webapiadaptersrv.cpp ) set(sdrsrv_HEADERS maincore.h device/deviceset.h + feature/featureset.h webapi/webapiadaptersrv.h ) diff --git a/sdrsrv/feature/featureset.cpp b/sdrsrv/feature/featureset.cpp new file mode 100644 index 000000000..ec5452e46 --- /dev/null +++ b/sdrsrv/feature/featureset.cpp @@ -0,0 +1,102 @@ +/////////////////////////////////////////////////////////////////////////////////// +// 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" +#include "feature/feature.h" +#include "featureset.h" + +FeatureSet::FeatureSet(int tabIndex) +{ + m_featureTabIndex = tabIndex; +} + +FeatureSet::~FeatureSet() +{ +} + +void FeatureSet::addFeature(int selectedFeatureIndex, PluginAPI *pluginAPI, WebAPIAdapterInterface *apiAdapter) +{ + PluginAPI::FeatureRegistrations *featureRegistrations = pluginAPI->getFeatureRegistrations(); // Available feature plugins + Feature *feature = featureRegistrations->at(selectedFeatureIndex).m_plugin->createFeature(apiAdapter); + QString featureName; + feature->getIdentifier(featureName); + m_featureInstanceRegistrations.append(FeatureInstanceRegistration(featureName, feature)); + renameFeatureInstances(); +} + +void FeatureSet::removeFeatureInstance(Feature* feature) +{ + for (FeatureInstanceRegistrations::iterator it = m_featureInstanceRegistrations.begin(); it != m_featureInstanceRegistrations.end(); ++it) + { + if (it->m_feature == feature) + { + m_featureInstanceRegistrations.erase(it); + break; + } + } + + renameFeatureInstances(); +} + +void FeatureSet::renameFeatureInstances() +{ + for (int i = 0; i < m_featureInstanceRegistrations.count(); i++) { + m_featureInstanceRegistrations[i].m_feature->setName(QString("%1:%2").arg(m_featureInstanceRegistrations[i].m_featureName).arg(i)); + } +} + +void FeatureSet::freeFeatures() +{ + for(int i = 0; i < m_featureInstanceRegistrations.count(); i++) + { + qDebug("FeatureSet::freeFeatures: destroying feature [%s]", qPrintable(m_featureInstanceRegistrations[i].m_featureName)); + m_featureInstanceRegistrations[i].m_feature->destroy(); + } +} + +void FeatureSet::deleteFeature(int featureIndex) +{ + if ((featureIndex >= 0) && (featureIndex < m_featureInstanceRegistrations.count())) + { + qDebug("FeatureSet::deleteFeature: delete feature [%s] at %d", + qPrintable(m_featureInstanceRegistrations[featureIndex].m_featureName), + featureIndex); + m_featureInstanceRegistrations[featureIndex].m_feature->destroy(); + m_featureInstanceRegistrations.removeAt(featureIndex); + renameFeatureInstances(); + } +} + +const Feature *FeatureSet::getFeatureAt(int featureIndex) const +{ + if ((featureIndex >= 0) && (featureIndex < m_featureInstanceRegistrations.count())) { + return m_featureInstanceRegistrations[featureIndex].m_feature; + } else{ + return nullptr; + } +} + +Feature *FeatureSet::getFeatureAt(int featureIndex) +{ + if ((featureIndex >= 0) && (featureIndex < m_featureInstanceRegistrations.count())) { + return m_featureInstanceRegistrations[featureIndex].m_feature; + } else{ + return nullptr; + } +} diff --git a/sdrsrv/feature/featureset.h b/sdrsrv/feature/featureset.h new file mode 100644 index 000000000..dbcac91c5 --- /dev/null +++ b/sdrsrv/feature/featureset.h @@ -0,0 +1,71 @@ +/////////////////////////////////////////////////////////////////////////////////// +// 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 SDRSRV_FEATURE_FEATURESET_H_ +#define SDRSRV_FEATURE_FEATURESET_H_ + +#include +#include + +#include "export.h" + +class PluginAPI; +class Feature; +class WebAPIAdapterInterface; + +class SDRGUI_API FeatureSet +{ +public: + FeatureSet(int tabIndex); + ~FeatureSet(); + + int getNumberOfFeatures() const { return m_featureInstanceRegistrations.size(); } + void addFeature(int selectedFeatureIndex, PluginAPI *pluginAPI, WebAPIAdapterInterface *apiAdapter); + void removeFeatureInstance(Feature* feature); + void freeFeatures(); + void deleteFeature(int featureIndex); + const Feature *getFeatureAt(int featureIndex) const; + Feature *getFeatureAt(int featureIndex); + +private: + struct FeatureInstanceRegistration + { + QString m_featureName; + Feature* m_feature; + + FeatureInstanceRegistration() : + m_featureName(), + m_feature(nullptr) + { } + + FeatureInstanceRegistration(const QString& featureName, Feature *feature) : + m_featureName(featureName), + m_feature(feature) + { } + + bool operator<(const FeatureInstanceRegistration& other) const; + }; + + typedef QList FeatureInstanceRegistrations; + + FeatureInstanceRegistrations m_featureInstanceRegistrations; + int m_featureTabIndex; + + void renameFeatureInstances(); +}; + +#endif // SDRSRV_FEATURE_FEATURESET_H_ diff --git a/sdrsrv/maincore.cpp b/sdrsrv/maincore.cpp index b3ca11563..6f01f645e 100644 --- a/sdrsrv/maincore.cpp +++ b/sdrsrv/maincore.cpp @@ -28,6 +28,7 @@ #include "device/deviceapi.h" #include "device/deviceset.h" #include "device/deviceenumerator.h" +#include "feature/featureset.h" #include "plugin/pluginmanager.h" #include "loggerwithfile.h" #include "webapi/webapirequestmapper.h" @@ -46,6 +47,8 @@ MESSAGE_CLASS_DEFINITION(MainCore::MsgSetDevice, Message) MESSAGE_CLASS_DEFINITION(MainCore::MsgAddChannel, Message) MESSAGE_CLASS_DEFINITION(MainCore::MsgDeleteChannel, Message) MESSAGE_CLASS_DEFINITION(MainCore::MsgApplySettings, Message) +MESSAGE_CLASS_DEFINITION(MainCore::MsgAddFeature, Message) +MESSAGE_CLASS_DEFINITION(MainCore::MsgDeleteFeature, Message) MainCore *MainCore::m_instance = 0; @@ -190,6 +193,19 @@ bool MainCore::handleMessage(const Message& cmd) deleteChannel(notif.getDeviceSetIndex(), notif.getChannelIndex()); return true; } + else if (MsgAddFeature::match(cmd)) + { + MsgAddFeature& notif = (MsgAddFeature&) cmd; + addFeature(notif.getFeatureSetIndex(), notif.getFeatureRegistrationIndex()); + + return true; + } + else if (MsgDeleteFeature::match(cmd)) + { + MsgDeleteFeature& notif = (MsgDeleteFeature&) cmd; + deleteFeature(notif.getFeatureSetIndex(), notif.getFeatureIndex()); + return true; + } else if (MsgApplySettings::match(cmd)) { applySettings(); @@ -645,6 +661,24 @@ void MainCore::deleteChannel(int deviceSetIndex, int channelIndex) } } +void MainCore::addFeature(int featureSetIndex, int featureIndex) +{ + if (featureSetIndex >= 0) + { + FeatureSet *featureSet = m_featureSets[featureSetIndex]; + featureSet->addFeature(featureSetIndex, m_pluginManager->getPluginAPI(), m_apiAdapter); + } +} + +void MainCore::deleteFeature(int featureSetIndex, int featureIndex) +{ + if ((featureSetIndex >= 0) && (featureSetIndex < (int) m_featureSets.size())) + { + FeatureSet *featureSet = m_featureSets[featureSetIndex]; + featureSet->deleteFeature(featureIndex); + } +} + void MainCore::loadPresetSettings(const Preset* preset, int tabIndex) { qDebug("MainCore::loadPresetSettings: preset [%s | %s]", diff --git a/sdrsrv/maincore.h b/sdrsrv/maincore.h index f526b7916..5af3bd551 100644 --- a/sdrsrv/maincore.h +++ b/sdrsrv/maincore.h @@ -37,6 +37,7 @@ class PluginInterface; class PluginManager; class ChannelMarker; class DeviceSet; +class FeatureSet; class WebAPIRequestMapper; class WebAPIServer; class WebAPIAdapterSrv; @@ -67,6 +68,8 @@ public: void changeSampleMIMO(int deviceSetIndex, int selectedDeviceIndex); void addChannel(int deviceSetIndex, int selectedChannelIndex); void deleteChannel(int deviceSetIndex, int channelIndex); + void addFeature(int featureSetIndex, int featureIndex); + void deleteFeature(int featureSetIndex, int featureIndex); const QString& getAPIHost() const { return m_apiHost; } int getAPIPort() const { return m_apiPort; } @@ -285,6 +288,51 @@ private: { } }; + class MsgAddFeature : public Message { + MESSAGE_CLASS_DECLARATION + + public: + int getFeatureSetIndex() const { return m_featureSetIndex; } + int getFeatureRegistrationIndex() const { return m_featureRegistrationIndex; } + + static MsgAddFeature* create(int featureSetIndex, int featureRegistrationIndex) + { + return new MsgAddFeature(featureSetIndex, featureRegistrationIndex); + } + + private: + int m_featureSetIndex; + int m_featureRegistrationIndex; + + MsgAddFeature(int featureSetIndex, int featureRegistrationIndex) : + Message(), + m_featureSetIndex(featureSetIndex), + m_featureRegistrationIndex(featureRegistrationIndex) + { } + }; + + class MsgDeleteFeature : public Message { + MESSAGE_CLASS_DECLARATION + + public: + int getFeatureSetIndex() const { return m_featureSetIndex; } + int getFeatureIndex() const { return m_featureIndex; } + + static MsgDeleteFeature* create(int m_featureSetIndex, int m_featureIndex) { + return new MsgDeleteFeature(m_featureSetIndex, m_featureIndex); + } + + private: + int m_featureSetIndex; + int m_featureIndex; + + MsgDeleteFeature(int m_featureSetIndex, int m_featureIndex) : + Message(), + m_featureSetIndex(m_featureSetIndex), + m_featureIndex(m_featureIndex) + { } + }; + static MainCore *m_instance; MainSettings m_settings; int m_masterTabIndex; @@ -297,6 +345,7 @@ private: MessageQueue m_inputMessageQueue; QTimer m_masterTimer; std::vector m_deviceSets; + std::vector m_featureSets; PluginManager* m_pluginManager; WebAPIRequestMapper *m_requestMapper; diff --git a/sdrsrv/webapi/webapiadaptersrv.cpp b/sdrsrv/webapi/webapiadaptersrv.cpp index 5baa0aeef..db0ada307 100644 --- a/sdrsrv/webapi/webapiadaptersrv.cpp +++ b/sdrsrv/webapi/webapiadaptersrv.cpp @@ -48,6 +48,10 @@ #include "SWGLimeRFEDevices.h" #include "SWGLimeRFESettings.h" #include "SWGLimeRFEPower.h" +#include "SWGFeatureSetList.h" +#include "SWGFeatureSettings.h" +#include "SWGFeatureReport.h" +#include "SWGFeatureActions.h" #include "maincore.h" #include "loggerwithfile.h" @@ -62,6 +66,8 @@ #include "dsp/dspdevicemimoengine.h" #include "dsp/dspengine.h" #include "channel/channelapi.h" +#include "feature/featureset.h" +#include "feature/feature.h" #include "plugin/pluginapi.h" #include "plugin/pluginmanager.h" #include "util/serialutil.h" @@ -1440,6 +1446,15 @@ int WebAPIAdapterSrv::instanceDeviceSetsGet( return 200; } +int WebAPIAdapterSrv::instanceFeatureSetsGet( + SWGSDRangel::SWGFeatureSetList& response, + SWGSDRangel::SWGErrorResponse& error) +{ + (void) error; + getFeatureSetList(&response); + return 200; +} + int WebAPIAdapterSrv::instanceDeviceSetPost( int direction, SWGSDRangel::SWGSuccessResponse& response, @@ -2779,6 +2794,352 @@ int WebAPIAdapterSrv::devicesetChannelSettingsPutPatch( } } +int WebAPIAdapterSrv::featuresetFeaturePost( + int featureSetIndex, + SWGSDRangel::SWGFeatureSettings& query, + SWGSDRangel::SWGSuccessResponse& response, + SWGSDRangel::SWGErrorResponse& error) +{ + if ((featureSetIndex >= 0) && (featureSetIndex < (int) m_mainCore.m_featureSets.size())) + { + FeatureSet *featureSet = m_mainCore.m_featureSets[featureSetIndex]; + + PluginAPI::FeatureRegistrations *featureRegistrations = m_mainCore.m_pluginManager->getFeatureRegistrations(); + int nbRegistrations = featureRegistrations->size(); + int index = 0; + + for (; index < nbRegistrations; index++) + { + if (featureRegistrations->at(index).m_featureId == *query.getFeatureType()) { + break; + } + } + + if (index < nbRegistrations) + { + MainCore::MsgAddFeature *msg = MainCore::MsgAddFeature::create(featureSetIndex, index); + m_mainCore.m_inputMessageQueue.push(msg); + + response.init(); + *response.getMessage() = QString("Message to add a feature (MsgAddFeature) was submitted successfully"); + + return 202; + } + else + { + error.init(); + *error.getMessage() = QString("There is no feature with id %1").arg(*query.getFeatureType()); + return 404; + } + } + else + { + error.init(); + *error.getMessage() = QString("There is no feature set with index %1").arg(featureSetIndex); + return 404; + } +} + +int WebAPIAdapterSrv::featuresetFeatureDelete( + int featureSetIndex, + int featureIndex, + SWGSDRangel::SWGSuccessResponse& response, + SWGSDRangel::SWGErrorResponse& error) +{ + if ((featureSetIndex >= 0) && (featureSetIndex < (int) m_mainCore.m_featureSets.size())) + { + FeatureSet *featureSet = m_mainCore.m_featureSets[featureSetIndex]; + + if (featureIndex < featureSet->getNumberOfFeatures()) + { + MainCore::MsgDeleteFeature *msg = MainCore::MsgDeleteFeature::create(featureSetIndex, featureIndex); + m_mainCore.m_inputMessageQueue.push(msg); + + response.init(); + *response.getMessage() = QString("Message to delete a feature (MsgDeleteFeature) was submitted successfully"); + + return 202; + } + else + { + error.init(); + *error.getMessage() = QString("There is no feature at index %1. %2 feature(s) left") + .arg(featureIndex) + .arg(featureSet->getNumberOfFeatures()); + return 400; + } + } + else + { + error.init(); + *error.getMessage() = QString("There is no device set with index %1").arg(featureSetIndex); + return 404; + } +} + +int WebAPIAdapterSrv::featuresetFeatureRunGet( + int featureSetIndex, + int featureIndex, + SWGSDRangel::SWGDeviceState& response, + SWGSDRangel::SWGErrorResponse& error) +{ + if ((featureSetIndex >= 0) && (featureSetIndex < (int) m_mainCore.m_featureSets.size())) + { + FeatureSet *featureSet = m_mainCore.m_featureSets[featureSetIndex]; + + if (featureIndex < featureSet->getNumberOfFeatures()) + { + response.init(); + const Feature *feature = featureSet->getFeatureAt(featureIndex); + return feature->webapiRunGet(response, *error.getMessage()); + } + else + { + error.init(); + *error.getMessage() = QString("There is no feature at index %1. %2 feature(s) left") + .arg(featureIndex) + .arg(featureSet->getNumberOfFeatures()); + return 400; + } + } + else + { + error.init(); + *error.getMessage() = QString("There is no feature set with index %1").arg(featureSetIndex); + return 404; + } +} + +int WebAPIAdapterSrv::featuresetFeatureRunPost( + int featureSetIndex, + int featureIndex, + SWGSDRangel::SWGDeviceState& response, + SWGSDRangel::SWGErrorResponse& error) +{ + if ((featureSetIndex >= 0) && (featureSetIndex < (int) m_mainCore.m_featureSets.size())) + { + FeatureSet *featureSet = m_mainCore.m_featureSets[featureSetIndex]; + + if (featureIndex < featureSet->getNumberOfFeatures()) + { + response.init(); + Feature *feature = featureSet->getFeatureAt(featureIndex); + return feature->webapiRun(true, response, *error.getMessage()); + } + else + { + error.init(); + *error.getMessage() = QString("There is no feature at index %1. %2 feature(s) left") + .arg(featureIndex) + .arg(featureSet->getNumberOfFeatures()); + return 400; + } + } + else + { + error.init(); + *error.getMessage() = QString("There is no feature set with index %1").arg(featureSetIndex); + return 404; + } +} + +int WebAPIAdapterSrv::featuresetFeatureRunDelete( + int featureSetIndex, + int featureIndex, + SWGSDRangel::SWGDeviceState& response, + SWGSDRangel::SWGErrorResponse& error) +{ + if ((featureSetIndex >= 0) && (featureSetIndex < (int) m_mainCore.m_featureSets.size())) + { + FeatureSet *featureSet = m_mainCore.m_featureSets[featureSetIndex]; + + if (featureIndex < featureSet->getNumberOfFeatures()) + { + response.init(); + Feature *feature = featureSet->getFeatureAt(featureIndex); + return feature->webapiRun(false, response, *error.getMessage()); + } + else + { + error.init(); + *error.getMessage() = QString("There is no feature at index %1. %2 feature(s) left") + .arg(featureIndex) + .arg(featureSet->getNumberOfFeatures()); + return 400; + } + } + else + { + error.init(); + *error.getMessage() = QString("There is no feature set with index %1").arg(featureSetIndex); + return 404; + } +} + +int WebAPIAdapterSrv::featuresetFeatureSettingsGet( + int featureSetIndex, + int featureIndex, + SWGSDRangel::SWGFeatureSettings& response, + SWGSDRangel::SWGErrorResponse& error) +{ + error.init(); + + if ((featureSetIndex >= 0) && (featureSetIndex < (int) m_mainCore.m_featureSets.size())) + { + FeatureSet *featureSet = m_mainCore.m_featureSets[featureSetIndex]; + Feature *feature = featureSet->getFeatureAt(featureIndex); + + if (feature) + { + response.setFeatureType(new QString()); + feature->getIdentifier(*response.getFeatureType()); + return feature->webapiSettingsGet(response, *error.getMessage()); + } + else + { + *error.getMessage() = QString("There is no feature with index %1").arg(featureIndex); + return 404; + } + } + else + { + *error.getMessage() = QString("There is no feature set with index %1").arg(featureSetIndex); + return 404; + } +} + +int WebAPIAdapterSrv::featuresetFeatureSettingsPutPatch( + int featureSetIndex, + int featureIndex, + bool force, + const QStringList& featureSettingsKeys, + SWGSDRangel::SWGFeatureSettings& response, + SWGSDRangel::SWGErrorResponse& error) +{ + error.init(); + + if ((featureSetIndex >= 0) && (featureSetIndex < (int) m_mainCore.m_featureSets.size())) + { + FeatureSet *featureSet = m_mainCore.m_featureSets[featureSetIndex]; + Feature *feature = featureSet->getFeatureAt(featureIndex); + + if (feature) + { + QString featureType; + feature->getIdentifier(featureType); + + if (featureType == *response.getFeatureType()) + { + return feature->webapiSettingsPutPatch(force, featureSettingsKeys, response, *error.getMessage()); + } + else + { + *error.getMessage() = QString("There is no feature type %1 at index %2. Found %3.") + .arg(*response.getFeatureType()) + .arg(featureIndex) + .arg(featureType); + return 404; + } + } + else + { + *error.getMessage() = QString("There is no feature with index %1").arg(featureIndex); + return 404; + } + } + else + { + *error.getMessage() = QString("There is no feature set with index %1").arg(featureSetIndex); + return 404; + } +} + +int WebAPIAdapterSrv::featuresetFeatureReportGet( + int featureSetIndex, + int featureIndex, + SWGSDRangel::SWGFeatureReport& response, + SWGSDRangel::SWGErrorResponse& error) +{ + error.init(); + + if ((featureSetIndex >= 0) && (featureSetIndex < (int) m_mainCore.m_featureSets.size())) + { + FeatureSet *featureSet = m_mainCore.m_featureSets[featureSetIndex]; + Feature *feature = featureSet->getFeatureAt(featureIndex); + + if (feature) + { + response.setFeatureType(new QString()); + feature->getIdentifier(*response.getFeatureType()); + return feature->webapiReportGet(response, *error.getMessage()); + } + else + { + *error.getMessage() = QString("There is no feature with index %1").arg(featureIndex); + return 404; + } + } + else + { + *error.getMessage() = QString("There is no feature set with index %1").arg(featureIndex); + return 404; + } +} + +int WebAPIAdapterSrv::featuresetFeatureActionsPost( + int featureSetIndex, + int featureIndex, + const QStringList& featureActionsKeys, + SWGSDRangel::SWGFeatureActions& query, + SWGSDRangel::SWGSuccessResponse& response, + SWGSDRangel::SWGErrorResponse& error) +{ + error.init(); + + if ((featureSetIndex >= 0) && (featureSetIndex < (int) m_mainCore.m_featureSets.size())) + { + FeatureSet *featureSet = m_mainCore.m_featureSets[featureSetIndex]; + Feature *feature = featureSet->getFeatureAt(featureIndex); + + if (feature) + { + QString featureType; + feature->getIdentifier(featureType); + + if (featureType == *query.getFeatureType()) + { + int res = feature->webapiActionsPost(featureActionsKeys, query, *error.getMessage()); + + if (res/100 == 2) + { + response.init(); + *response.getMessage() = QString("Message to post action was submitted successfully"); + } + + return res; + } + else + { + *error.getMessage() = QString("There is no feature type %1 at index %2. Found %3.") + .arg(*query.getFeatureType()) + .arg(featureIndex) + .arg(featureType); + return 404; + } + } + else + { + *error.getMessage() = QString("There is no feature with index %1").arg(featureIndex); + return 404; + } + } + else + { + *error.getMessage() = QString("There is no feature set with index %1").arg(featureIndex); + return 404; + } +} + void WebAPIAdapterSrv::getDeviceSetList(SWGSDRangel::SWGDeviceSetList* deviceSetList) { deviceSetList->init(); @@ -3067,6 +3428,63 @@ void WebAPIAdapterSrv::getChannelsDetail(SWGSDRangel::SWGChannelsDetail *channel } } +int WebAPIAdapterSrv::featuresetGet( + int featureSetIndex, + SWGSDRangel::SWGFeatureSet& response, + SWGSDRangel::SWGErrorResponse& error) +{ + if ((featureSetIndex >= 0) && (featureSetIndex < (int) m_mainCore.m_featureSets.size())) + { + const FeatureSet *featureSet = m_mainCore.m_featureSets[featureSetIndex]; + getFeatureSet(&response, featureSet, featureSetIndex); + + return 200; + } + else + { + error.init(); + *error.getMessage() = QString("There is no feature set with index %1").arg(featureSetIndex); + + return 404; + } +} + +void WebAPIAdapterSrv::getFeatureSetList(SWGSDRangel::SWGFeatureSetList* featureSetList) +{ + featureSetList->init(); + featureSetList->setFeaturesetcount((int) m_mainCore.m_featureSets.size()); + + std::vector::const_iterator it = m_mainCore.m_featureSets.begin(); + + for (int i = 0; it != m_mainCore.m_featureSets.end(); ++it, i++) + { + QList *featureSets = featureSetList->getFeatureSets(); + featureSets->append(new SWGSDRangel::SWGFeatureSet()); + + getFeatureSet(featureSets->back(), *it, i); + } +} + +void WebAPIAdapterSrv::getFeatureSet(SWGSDRangel::SWGFeatureSet *swgFeatureSet, const FeatureSet* featureSet, int featureSetIndex) +{ + swgFeatureSet->init(); + swgFeatureSet->setFeaturecount(featureSet->getNumberOfFeatures()); + QList *features = swgFeatureSet->getFeatures(); + + for (int i = 0; i < featureSet->getNumberOfFeatures(); i++) + { + const Feature *feature = featureSet->getFeatureAt(i); + features->append(new SWGSDRangel::SWGFeature); + features->back()->setIndex(i); + QString s; + feature->getTitle(s); + features->back()->setTitle(new QString(s)); + feature->getIdentifier(s); + features->back()->setId(new QString(s)); + features->back()->setUid(feature->getUID()); + } +} + QtMsgType WebAPIAdapterSrv::getMsgTypeFromString(const QString& msgTypeString) { if (msgTypeString == "debug") { diff --git a/sdrsrv/webapi/webapiadaptersrv.h b/sdrsrv/webapi/webapiadaptersrv.h index a70f4bf27..3e34b1d34 100644 --- a/sdrsrv/webapi/webapiadaptersrv.h +++ b/sdrsrv/webapi/webapiadaptersrv.h @@ -26,6 +26,7 @@ class MainCore; class DeviceSet; +class FeatureSet; class WebAPIAdapterSrv: public WebAPIAdapterInterface { @@ -203,6 +204,10 @@ public: SWGSDRangel::SWGDeviceSetList& response, SWGSDRangel::SWGErrorResponse& error); + virtual int instanceFeatureSetsGet( + SWGSDRangel::SWGFeatureSetList& response, + SWGSDRangel::SWGErrorResponse& error); + virtual int instanceDeviceSetPost( int direction, SWGSDRangel::SWGSuccessResponse& response, @@ -330,12 +335,77 @@ public: SWGSDRangel::SWGChannelReport& response, SWGSDRangel::SWGErrorResponse& error); + virtual int featuresetGet( + int deviceSetIndex, + SWGSDRangel::SWGFeatureSet& response, + SWGSDRangel::SWGErrorResponse& error); + + virtual int featuresetFeaturePost( + int featureSetIndex, + SWGSDRangel::SWGFeatureSettings& query, + SWGSDRangel::SWGSuccessResponse& response, + SWGSDRangel::SWGErrorResponse& error); + + virtual int featuresetFeatureDelete( + int featureSetIndex, + int featureIndex, + SWGSDRangel::SWGSuccessResponse& response, + SWGSDRangel::SWGErrorResponse& error); + + virtual int featuresetFeatureRunGet( + int featureSetIndex, + int featureIndex, + SWGSDRangel::SWGDeviceState& response, + SWGSDRangel::SWGErrorResponse& error); + + virtual int featuresetFeatureRunPost( + int featureSetIndex, + int featureIndex, + SWGSDRangel::SWGDeviceState& response, + SWGSDRangel::SWGErrorResponse& error); + + virtual int featuresetFeatureRunDelete( + int featureSetIndex, + int featureIndex, + SWGSDRangel::SWGDeviceState& response, + SWGSDRangel::SWGErrorResponse& error); + + virtual int featuresetFeatureSettingsGet( + int featureSetIndex, + int featureIndex, + SWGSDRangel::SWGFeatureSettings& response, + SWGSDRangel::SWGErrorResponse& error); + + virtual int featuresetFeatureSettingsPutPatch( + int featureSetIndex, + int featureIndex, + bool force, + const QStringList& featureSettingsKeys, + SWGSDRangel::SWGFeatureSettings& response, + SWGSDRangel::SWGErrorResponse& error); + + virtual int featuresetFeatureReportGet( + int featureSetIndex, + int featureIndex, + SWGSDRangel::SWGFeatureReport& response, + SWGSDRangel::SWGErrorResponse& error); + + virtual int featuresetFeatureActionsPost( + int featureSetIndex, + int featureIndex, + const QStringList& featureActionsKeys, + SWGSDRangel::SWGFeatureActions& query, + SWGSDRangel::SWGSuccessResponse& response, + SWGSDRangel::SWGErrorResponse& error); + private: MainCore& m_mainCore; void getDeviceSetList(SWGSDRangel::SWGDeviceSetList* deviceSetList); void getDeviceSet(SWGSDRangel::SWGDeviceSet *swgDeviceSet, const DeviceSet* deviceSet, int deviceUISetIndex); void getChannelsDetail(SWGSDRangel::SWGChannelsDetail *channelsDetail, const DeviceSet* deviceSet); + void getFeatureSetList(SWGSDRangel::SWGFeatureSetList* featureSetList); + void getFeatureSet(SWGSDRangel::SWGFeatureSet *swgFeatureSet, const FeatureSet* featureSet, int featureSetIndex); static QtMsgType getMsgTypeFromString(const QString& msgTypeString); static void getMsgTypeString(const QtMsgType& msgType, QString& level); }; diff --git a/swagger/sdrangel/code/html2/index.html b/swagger/sdrangel/code/html2/index.html index a38dae6ec..00f0c9695 100644 --- a/swagger/sdrangel/code/html2/index.html +++ b/swagger/sdrangel/code/html2/index.html @@ -38907,7 +38907,7 @@ except ApiException as e:
- Generated 2020-09-28T13:19:26.040+02:00 + Generated 2020-09-28T13:34:44.975+02:00