diff --git a/CMakeLists.txt b/CMakeLists.txt
index 133ef301d..1d39b60f0 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -222,6 +222,7 @@ endif()
add_subdirectory(sdrbase)
add_subdirectory(sdrgui)
add_subdirectory(sdrsrv)
+add_subdirectory(sdrdaemon)
add_subdirectory(sdrbench)
add_subdirectory(httpserver)
add_subdirectory(logging)
diff --git a/sdrdaemon/CMakeLists.txt b/sdrdaemon/CMakeLists.txt
new file mode 100644
index 000000000..e5c707520
--- /dev/null
+++ b/sdrdaemon/CMakeLists.txt
@@ -0,0 +1,55 @@
+project (sdrdaemon)
+
+set(sdrdaemon_SOURCES
+ sdrdaemonmain.cpp
+ sdrdaemonpreferences.cpp
+ sdrdaemonsettings.cpp
+ webapi/webapiadapterdaemon.cpp
+ webapi/webapirequestmapper.cpp
+ webapi/webapiserver.cpp
+)
+
+set(sdrdaemon_HEADERS
+ sdrdaemonmain.h
+ sdrdaemonpreferences.h
+ sdrdaemonsettings.h
+ webapi/webapiadapterdaemon.h
+ webapi/webapirequestmapper.h
+ webapi/webapiserver.h
+)
+
+set(sdrdaemon_SOURCES
+ ${sdrdaemon_SOURCES}
+ ${sdrdaemon_HEADERS}
+)
+
+add_definitions(${QT_DEFINITIONS})
+add_definitions(-DQT_SHARED)
+
+add_library(sdrdaemon SHARED
+ ${sdrdaemon_SOURCES}
+ ${sdrdaemon_HEADERS_MOC}
+)
+
+include_directories(
+ .
+ ${CMAKE_SOURCE_DIR}/exports
+ ${CMAKE_SOURCE_DIR}/sdrbase
+ ${CMAKE_SOURCE_DIR}/logging
+ ${CMAKE_SOURCE_DIR}/httpserver
+ ${CMAKE_SOURCE_DIR}/swagger/sdrangel/code/qt5/client
+ ${CMAKE_CURRENT_BINARY_DIR}
+)
+
+target_link_libraries(sdrdaemon
+ ${QT_LIBRARIES}
+ sdrbase
+ logging
+)
+
+target_compile_features(sdrdaemon PRIVATE cxx_generalized_initializers) # cmake >= 3.1.0
+
+target_link_libraries(sdrdaemon Qt5::Core Qt5::Multimedia)
+
+install(TARGETS sdrdaemon DESTINATION lib)
+
diff --git a/sdrdaemon/sdrdaemonmain.cpp b/sdrdaemon/sdrdaemonmain.cpp
new file mode 100644
index 000000000..db2567772
--- /dev/null
+++ b/sdrdaemon/sdrdaemonmain.cpp
@@ -0,0 +1,162 @@
+///////////////////////////////////////////////////////////////////////////////////
+// Copyright (C) 2018 Edouard Griffiths, F4EXB. //
+// //
+// SDRdaemon instance //
+// //
+// SDRdaemon is a detached SDR front end that handles the interface with a //
+// physical device and sends or receives the I/Q samples stream to or from a //
+// SDRangel instance via UDP. It is controlled via a Web REST API. //
+// //
+// 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 //
+// //
+// 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 "dsp/dspengine.h"
+#include "dsp/dspdevicesourceengine.h"
+#include "plugin/pluginmanager.h"
+#include "util/message.h"
+#include "loggerwithfile.h"
+#include "sdrdaemonmain.h"
+
+#include "webapi/webapiadapterdaemon.h"
+#include "webapi/webapirequestmapper.h"
+#include "webapi/webapiserver.h"
+
+SDRDaemonMain *SDRDaemonMain::m_instance = 0;
+
+SDRDaemonMain::SDRDaemonMain(qtwebapp::LoggerWithFile *logger, const MainParser& parser, QObject *parent) :
+ QObject(parent),
+ m_logger(logger),
+ m_settings(),
+ m_dspEngine(DSPEngine::instance()),
+ m_lastEngineState(DSPDeviceSourceEngine::StNotStarted)
+{
+ qDebug() << "SDRdaemon::SDRdaemon: start";
+
+ m_instance = this;
+
+ m_pluginManager = new PluginManager(this);
+ m_pluginManager->loadPlugins(QString("pluginssrv"));
+
+ connect(&m_inputMessageQueue, SIGNAL(messageEnqueued()), this, SLOT(handleMessages()), Qt::QueuedConnection);
+ m_masterTimer.start(50);
+
+ loadSettings();
+
+ QString applicationDirPath = QCoreApplication::instance()->applicationDirPath();
+
+ if (QResource::registerResource(applicationDirPath + "/sdrbase.rcc")) {
+ qDebug("MainCore::MainCore: registered resource file %s/%s", qPrintable(applicationDirPath), "sdrbase.rcc");
+ } else {
+ qWarning("MainCore::MainCore: could not register resource file %s/%s", qPrintable(applicationDirPath), "sdrbase.rcc");
+ }
+
+ m_apiAdapter = new WebAPIAdapterDaemon(*this);
+ m_requestMapper = new SDRDaemon::WebAPIRequestMapper(this);
+ m_requestMapper->setAdapter(m_apiAdapter);
+ m_apiServer = new SDRDaemon::WebAPIServer(parser.getServerAddress(), parser.getServerPort(), m_requestMapper);
+ m_apiServer->start();
+
+ qDebug() << "SDRdaemon::SDRdaemon: end";
+}
+
+SDRDaemonMain::~SDRDaemonMain()
+{
+ m_apiServer->stop();
+ m_settings.save();
+ delete m_apiServer;
+ delete m_requestMapper;
+ delete m_apiAdapter;
+
+ delete m_pluginManager;
+
+ qDebug() << "SDRdaemon::~SDRdaemon: end";
+ delete m_logger;
+}
+
+void SDRDaemonMain::loadSettings()
+{
+ qDebug() << "SDRdaemon::loadSettings";
+
+ m_settings.load();
+ setLoggingOptions();
+}
+
+void SDRDaemonMain::setLoggingOptions()
+{
+ m_logger->setConsoleMinMessageLevel(m_settings.getConsoleMinLogLevel());
+
+ if (m_settings.getUseLogFile())
+ {
+ qtwebapp::FileLoggerSettings fileLoggerSettings; // default values
+
+ if (m_logger->hasFileLogger()) {
+ fileLoggerSettings = m_logger->getFileLoggerSettings(); // values from file logger if it exists
+ }
+
+ fileLoggerSettings.fileName = m_settings.getLogFileName(); // put new values
+ m_logger->createOrSetFileLogger(fileLoggerSettings, 2000); // create file logger if it does not exist and apply settings in any case
+ }
+
+ if (m_logger->hasFileLogger()) {
+ m_logger->setFileMinMessageLevel(m_settings.getFileMinLogLevel());
+ }
+
+ m_logger->setUseFileLogger(m_settings.getUseLogFile());
+
+ if (m_settings.getUseLogFile())
+ {
+#if QT_VERSION >= 0x050400
+ QString appInfoStr(tr("%1 %2 Qt %3 %4b %5 %6 DSP Rx:%7b Tx:%8b PID %9")
+ .arg(QCoreApplication::applicationName())
+ .arg(QCoreApplication::applicationVersion())
+ .arg(QT_VERSION_STR)
+ .arg(QT_POINTER_SIZE*8)
+ .arg(QSysInfo::currentCpuArchitecture())
+ .arg(QSysInfo::prettyProductName())
+ .arg(SDR_RX_SAMP_SZ)
+ .arg(SDR_TX_SAMP_SZ)
+ .arg(QCoreApplication::applicationPid()));
+#else
+ QString appInfoStr(tr("%1 %2 Qt %3 %4b DSP Rx:%5b Tx:%6b PID %7")
+ .arg(QCoreApplication::applicationName())
+ .arg(QCoreApplication::applicationVersion())
+ .arg(QT_VERSION_STR)
+ .arg(QT_POINTER_SIZE*8)
+ .arg(SDR_RX_SAMP_SZ)
+ .arg(SDR_RX_SAMP_SZ)
+ .arg(QCoreApplication::applicationPid());
+ #endif
+ m_logger->logToFile(QtInfoMsg, appInfoStr);
+ }
+}
+
+bool SDRDaemonMain::handleMessage(const Message& cmd __attribute__((unused)))
+{
+ return false;
+}
+
+void SDRDaemonMain::handleMessages()
+{
+ Message* message;
+
+ while ((message = m_inputMessageQueue.pop()) != 0)
+ {
+ qDebug("SDRdaemon::handleMessages: message: %s", message->getIdentifier());
+ handleMessage(*message);
+ delete message;
+ }
+}
diff --git a/sdrdaemon/sdrdaemonmain.h b/sdrdaemon/sdrdaemonmain.h
new file mode 100644
index 000000000..1d9fe0862
--- /dev/null
+++ b/sdrdaemon/sdrdaemonmain.h
@@ -0,0 +1,76 @@
+///////////////////////////////////////////////////////////////////////////////////
+// Copyright (C) 2018 Edouard Griffiths, F4EXB. //
+// //
+// SDRdaemon instance //
+// //
+// SDRdaemon is a detached SDR front end that handles the interface with a //
+// physical device and sends or receives the I/Q samples stream to or from a //
+// SDRangel instance via UDP. It is controlled via a Web REST API. //
+// //
+// 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 //
+// //
+// 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 SDRDAEMON_SDRDAEMONMAIN_H_
+#define SDRDAEMON_SDRDAEMONMAIN_H_
+
+#include
+#include
+
+#include "mainparser.h"
+#include "sdrdaemonsettings.h"
+#include "util/messagequeue.h"
+
+namespace SDRDaemon {
+ class WebAPIRequestMapper;
+ class WebAPIServer;
+}
+
+namespace qtwebapp {
+ class LoggerWithFile;
+}
+
+class DSPEngine;
+class PluginManager;
+class Message;
+class WebAPIAdapterDaemon;
+
+class SDRDaemonMain : public QObject {
+ Q_OBJECT
+public:
+ explicit SDRDaemonMain(qtwebapp::LoggerWithFile *logger, const MainParser& parser, QObject *parent = 0);
+ ~SDRDaemonMain();
+ static SDRDaemonMain *getInstance() { return m_instance; } // Main Core is de facto a singleton so this just returns its reference
+
+private:
+ static SDRDaemonMain *m_instance;
+ qtwebapp::LoggerWithFile *m_logger;
+ SDRDaemonSettings m_settings;
+ DSPEngine* m_dspEngine;
+ int m_lastEngineState;
+ PluginManager* m_pluginManager;
+ MessageQueue m_inputMessageQueue;
+ QTimer m_masterTimer;
+
+ SDRDaemon::WebAPIRequestMapper *m_requestMapper;
+ SDRDaemon::WebAPIServer *m_apiServer;
+ WebAPIAdapterDaemon *m_apiAdapter;
+
+ void loadSettings();
+ void setLoggingOptions();
+ bool handleMessage(const Message& cmd);
+
+private slots:
+ void handleMessages();
+};
+
+#endif /* SDRDAEMON_SDRDAEMONMAIN_H_ */
diff --git a/sdrdaemon/sdrdaemonpreferences.cpp b/sdrdaemon/sdrdaemonpreferences.cpp
new file mode 100644
index 000000000..a194cc46f
--- /dev/null
+++ b/sdrdaemon/sdrdaemonpreferences.cpp
@@ -0,0 +1,95 @@
+///////////////////////////////////////////////////////////////////////////////////
+// Copyright (C) 2018 Edouard Griffiths, F4EXB. //
+// //
+// SDRdaemon instance //
+// //
+// SDRdaemon is a detached SDR front end that handles the interface with a //
+// physical device and sends or receives the I/Q samples stream to or from a //
+// SDRangel instance via UDP. It is controlled via a Web REST API. //
+// //
+// 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 //
+// //
+// 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 "util/simpleserializer.h"
+#include "sdrdaemonpreferences.h"
+
+SDRDaemonPreferences::SDRDaemonPreferences()
+{
+ resetToDefaults();
+}
+
+void SDRDaemonPreferences::resetToDefaults()
+{
+ m_useLogFile = false;
+ m_logFileName = "sdrangel.log";
+ m_consoleMinLogLevel = QtDebugMsg;
+ m_fileMinLogLevel = QtDebugMsg;
+}
+
+QByteArray SDRDaemonPreferences::serialize() const
+{
+ SimpleSerializer s(1);
+ s.writeS32(1, (int) m_consoleMinLogLevel);
+ s.writeBool(2, m_useLogFile);
+ s.writeString(3, m_logFileName);
+ s.writeS32(4, (int) m_fileMinLogLevel);
+ return s.final();
+}
+
+bool SDRDaemonPreferences::deserialize(const QByteArray& data)
+{
+ int tmpInt;
+
+ SimpleDeserializer d(data);
+
+ if(!d.isValid()) {
+ resetToDefaults();
+ return false;
+ }
+
+ if(d.getVersion() == 1)
+ {
+ d.readS32(1, &tmpInt, (int) QtDebugMsg);
+
+ if ((tmpInt == (int) QtDebugMsg) ||
+ (tmpInt == (int) QtInfoMsg) ||
+ (tmpInt == (int) QtWarningMsg) ||
+ (tmpInt == (int) QtCriticalMsg) ||
+ (tmpInt == (int) QtFatalMsg)) {
+ m_consoleMinLogLevel = (QtMsgType) tmpInt;
+ } else {
+ m_consoleMinLogLevel = QtDebugMsg;
+ }
+
+ d.readBool(2, &m_useLogFile, false);
+ d.readString(3, &m_logFileName, "sdrangel.log");
+
+ d.readS32(4, &tmpInt, (int) QtDebugMsg);
+
+ if ((tmpInt == (int) QtDebugMsg) ||
+ (tmpInt == (int) QtInfoMsg) ||
+ (tmpInt == (int) QtWarningMsg) ||
+ (tmpInt == (int) QtCriticalMsg) ||
+ (tmpInt == (int) QtFatalMsg)) {
+ m_fileMinLogLevel = (QtMsgType) tmpInt;
+ } else {
+ m_fileMinLogLevel = QtDebugMsg;
+ }
+
+ return true;
+ } else
+ {
+ resetToDefaults();
+ return false;
+ }
+}
diff --git a/sdrdaemon/sdrdaemonpreferences.h b/sdrdaemon/sdrdaemonpreferences.h
new file mode 100644
index 000000000..c3ea5c1f2
--- /dev/null
+++ b/sdrdaemon/sdrdaemonpreferences.h
@@ -0,0 +1,53 @@
+///////////////////////////////////////////////////////////////////////////////////
+// Copyright (C) 2018 Edouard Griffiths, F4EXB. //
+// //
+// SDRdaemon instance //
+// //
+// SDRdaemon is a detached SDR front end that handles the interface with a //
+// physical device and sends or receives the I/Q samples stream to or from a //
+// SDRangel instance via UDP. It is controlled via a Web REST API. //
+// //
+// 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 //
+// //
+// 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 SDRDAEMON_SDRDAEMONPREFERENCES_H_
+#define SDRDAEMON_SDRDAEMONPREFERENCES_H_
+
+#include
+
+class SDRDaemonPreferences
+{
+public:
+ SDRDaemonPreferences();
+
+ void resetToDefaults();
+ QByteArray serialize() const;
+ bool deserialize(const QByteArray& data);
+
+ void setConsoleMinLogLevel(const QtMsgType& minLogLevel) { m_consoleMinLogLevel = minLogLevel; }
+ void setFileMinLogLevel(const QtMsgType& minLogLevel) { m_fileMinLogLevel = minLogLevel; }
+ void setUseLogFile(bool useLogFile) { m_useLogFile = useLogFile; }
+ void setLogFileName(const QString& value) { m_logFileName = value; }
+ QtMsgType getConsoleMinLogLevel() const { return m_consoleMinLogLevel; }
+ QtMsgType getFileMinLogLevel() const { return m_fileMinLogLevel; }
+ bool getUseLogFile() const { return m_useLogFile; }
+ const QString& getLogFileName() const { return m_logFileName; }
+
+private:
+ QtMsgType m_consoleMinLogLevel;
+ QtMsgType m_fileMinLogLevel;
+ bool m_useLogFile;
+ QString m_logFileName;
+};
+
+#endif /* SDRDAEMON_SDRDAEMONPREFERENCES_H_ */
diff --git a/sdrdaemon/sdrdaemonsettings.cpp b/sdrdaemon/sdrdaemonsettings.cpp
new file mode 100644
index 000000000..2fc177701
--- /dev/null
+++ b/sdrdaemon/sdrdaemonsettings.cpp
@@ -0,0 +1,51 @@
+///////////////////////////////////////////////////////////////////////////////////
+// Copyright (C) 2018 Edouard Griffiths, F4EXB. //
+// //
+// SDRdaemon instance //
+// //
+// SDRdaemon is a detached SDR front end that handles the interface with a //
+// physical device and sends or receives the I/Q samples stream to or from a //
+// SDRangel instance via UDP. It is controlled via a Web REST API. //
+// //
+// 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 //
+// //
+// 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 "sdrdaemonpreferences.h"
+#include "sdrdaemonsettings.h"
+
+SDRDaemonSettings::SDRDaemonSettings()
+{
+ resetToDefaults();
+}
+
+SDRDaemonSettings::~SDRDaemonSettings()
+{}
+
+void SDRDaemonSettings::load()
+{
+ QSettings s;
+ m_preferences.deserialize(qUncompress(QByteArray::fromBase64(s.value("preferences").toByteArray())));
+}
+
+void SDRDaemonSettings::save() const
+{
+ QSettings s;
+ s.setValue("preferences", qCompress(m_preferences.serialize()).toBase64());
+}
+
+void SDRDaemonSettings::resetToDefaults()
+{
+ m_preferences.resetToDefaults();
+}
diff --git a/sdrdaemon/sdrdaemonsettings.h b/sdrdaemon/sdrdaemonsettings.h
new file mode 100644
index 000000000..ef909a8fe
--- /dev/null
+++ b/sdrdaemon/sdrdaemonsettings.h
@@ -0,0 +1,54 @@
+///////////////////////////////////////////////////////////////////////////////////
+// Copyright (C) 2018 Edouard Griffiths, F4EXB. //
+// //
+// SDRdaemon instance //
+// //
+// SDRdaemon is a detached SDR front end that handles the interface with a //
+// physical device and sends or receives the I/Q samples stream to or from a //
+// SDRangel instance via UDP. It is controlled via a Web REST API. //
+// //
+// 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 //
+// //
+// 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 SDRDAEMON_SDRDAEMONSETTINGS_H_
+#define SDRDAEMON_SDRDAEMONSETTINGS_H_
+
+#include "sdrdaemonpreferences.h"
+
+class SDRDaemonSettings
+{
+public:
+ SDRDaemonSettings();
+ ~SDRDaemonSettings();
+
+ void load();
+ void save() const;
+
+ void resetToDefaults();
+
+ void setConsoleMinLogLevel(const QtMsgType& minLogLevel) { m_preferences.setConsoleMinLogLevel(minLogLevel); }
+ void setFileMinLogLevel(const QtMsgType& minLogLevel) { m_preferences.setFileMinLogLevel(minLogLevel); }
+ void setUseLogFile(bool useLogFile) { m_preferences.setUseLogFile(useLogFile); }
+ void setLogFileName(const QString& value) { m_preferences.setLogFileName(value); }
+ QtMsgType getConsoleMinLogLevel() const { return m_preferences.getConsoleMinLogLevel(); }
+ QtMsgType getFileMinLogLevel() const { return m_preferences.getFileMinLogLevel(); }
+ bool getUseLogFile() const { return m_preferences.getUseLogFile(); }
+ const QString& getLogFileName() const { return m_preferences.getLogFileName(); }
+
+private:
+ SDRDaemonPreferences m_preferences;
+};
+
+
+
+#endif /* SDRDAEMON_SDRDAEMONSETTINGS_H_ */
diff --git a/sdrdaemon/webapi/webapiadapterdaemon.cpp b/sdrdaemon/webapi/webapiadapterdaemon.cpp
new file mode 100644
index 000000000..5703a3736
--- /dev/null
+++ b/sdrdaemon/webapi/webapiadapterdaemon.cpp
@@ -0,0 +1,164 @@
+///////////////////////////////////////////////////////////////////////////////////
+// Copyright (C) 2018 Edouard Griffiths, F4EXB. //
+// //
+// SDRDaemon Swagger server adapter interface //
+// //
+// 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 //
+// //
+// 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 "SWGDaemonSummaryResponse.h"
+#include "SWGDeviceSettings.h"
+#include "SWGDeviceState.h"
+#include "SWGDeviceReport.h"
+#include "SWGErrorResponse.h"
+
+#include "webapiadapterdaemon.h"
+
+QString WebAPIAdapterDaemon::daemonInstanceSummaryURL = "/sdrdaemon";
+QString WebAPIAdapterDaemon::daemonInstanceLoggingURL = "/sdrdaemon/logging";
+QString WebAPIAdapterDaemon::daemonSettingsURL = "/sdrdaemon/settings";
+QString WebAPIAdapterDaemon::daemonReportURL = "/sdrdaemon/report";
+QString WebAPIAdapterDaemon::daemonRunURL = "/sdrdaemon/run";
+
+WebAPIAdapterDaemon::WebAPIAdapterDaemon(SDRDaemonMain& sdrDaemonMain) :
+ m_sdrDaemonMain(sdrDaemonMain)
+{
+}
+
+WebAPIAdapterDaemon::~WebAPIAdapterDaemon()
+{
+}
+
+int WebAPIAdapterDaemon::daemonInstanceSummary(
+ SWGSDRangel::SWGDaemonSummaryResponse& response __attribute__((unused)),
+ SWGSDRangel::SWGErrorResponse& error)
+{
+ error.init();
+ *error.getMessage() = "Not implemented";
+ return 501;
+}
+
+int WebAPIAdapterDaemon::daemonInstanceLoggingGet(
+ SWGSDRangel::SWGLoggingInfo& response __attribute__((unused)),
+ SWGSDRangel::SWGErrorResponse& error)
+{
+ error.init();
+ *error.getMessage() = "Not implemented";
+ return 501;
+}
+
+int WebAPIAdapterDaemon::daemonInstanceLoggingPut(
+ SWGSDRangel::SWGLoggingInfo& query __attribute__((unused)),
+ SWGSDRangel::SWGLoggingInfo& response __attribute__((unused)),
+ SWGSDRangel::SWGErrorResponse& error)
+{
+ error.init();
+ *error.getMessage() = "Not implemented";
+ return 501;
+}
+
+int WebAPIAdapterDaemon::daemonSettingsGet(
+ SWGSDRangel::SWGDeviceSettings& response __attribute__((unused)),
+ SWGSDRangel::SWGErrorResponse& error)
+{
+ error.init();
+ *error.getMessage() = "Not implemented";
+ return 501;
+}
+
+int WebAPIAdapterDaemon::daemonSettingsPutPatch(
+ bool force __attribute__((unused)),
+ const QStringList& deviceSettingsKeys __attribute__((unused)),
+ SWGSDRangel::SWGDeviceSettings& response __attribute__((unused)),
+ SWGSDRangel::SWGErrorResponse& error)
+{
+ error.init();
+ *error.getMessage() = "Not implemented";
+ return 501;
+}
+
+int WebAPIAdapterDaemon::daemonRunGet(
+ SWGSDRangel::SWGDeviceState& response __attribute__((unused)),
+ SWGSDRangel::SWGErrorResponse& error)
+{
+ error.init();
+ *error.getMessage() = "Not implemented";
+ return 501;
+}
+
+int WebAPIAdapterDaemon::daemonRunPost(
+ SWGSDRangel::SWGDeviceState& response __attribute__((unused)),
+ SWGSDRangel::SWGErrorResponse& error)
+{
+ error.init();
+ *error.getMessage() = "Not implemented";
+ return 501;
+}
+
+int WebAPIAdapterDaemon::daemonRunDelete(
+ SWGSDRangel::SWGDeviceState& response __attribute__((unused)),
+ SWGSDRangel::SWGErrorResponse& error)
+{
+ error.init();
+ *error.getMessage() = "Not implemented";
+ return 501;
+}
+
+int WebAPIAdapterDaemon::daemonReportGet(
+ SWGSDRangel::SWGDeviceReport& response __attribute__((unused)),
+ SWGSDRangel::SWGErrorResponse& error)
+{
+ error.init();
+ *error.getMessage() = "Not implemented";
+ return 501;
+}
+
+// TODO: put in library in common with SDRangel. Can be static.
+QtMsgType WebAPIAdapterDaemon::getMsgTypeFromString(const QString& msgTypeString)
+{
+ if (msgTypeString == "debug") {
+ return QtDebugMsg;
+ } else if (msgTypeString == "info") {
+ return QtInfoMsg;
+ } else if (msgTypeString == "warning") {
+ return QtWarningMsg;
+ } else if (msgTypeString == "error") {
+ return QtCriticalMsg;
+ } else {
+ return QtDebugMsg;
+ }
+}
+
+// TODO: put in library in common with SDRangel. Can be static.
+void WebAPIAdapterDaemon::getMsgTypeString(const QtMsgType& msgType, QString& levelStr)
+{
+ switch (msgType)
+ {
+ case QtDebugMsg:
+ levelStr = "debug";
+ break;
+ case QtInfoMsg:
+ levelStr = "info";
+ break;
+ case QtWarningMsg:
+ levelStr = "warning";
+ break;
+ case QtCriticalMsg:
+ case QtFatalMsg:
+ levelStr = "error";
+ break;
+ default:
+ levelStr = "debug";
+ break;
+ }
+}
diff --git a/sdrdaemon/webapi/webapiadapterdaemon.h b/sdrdaemon/webapi/webapiadapterdaemon.h
new file mode 100644
index 000000000..8cd5af801
--- /dev/null
+++ b/sdrdaemon/webapi/webapiadapterdaemon.h
@@ -0,0 +1,98 @@
+///////////////////////////////////////////////////////////////////////////////////
+// Copyright (C) 2018 Edouard Griffiths, F4EXB. //
+// //
+// SDRDaemon Swagger server adapter interface //
+// //
+// 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 //
+// //
+// 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 SDRDAEMON_WEBAPI_WEBAPIADAPTERDAEMON_H_
+#define SDRDAEMON_WEBAPI_WEBAPIADAPTERDAEMON_H_
+
+#include
+#include
+
+namespace SWGSDRangel
+{
+ class SWGDaemonSummaryResponse;
+ class SWGDeviceSet;
+ class SWGDeviceListItem;
+ class SWGDeviceSettings;
+ class SWGDeviceState;
+ class SWGDeviceReport;
+ class SWGSuccessResponse;
+ class SWGErrorResponse;
+ class SWGLoggingInfo;
+}
+
+class SDRDaemonMain;
+
+class WebAPIAdapterDaemon
+{
+public:
+ WebAPIAdapterDaemon(SDRDaemonMain& sdrDaemonMain);
+ ~WebAPIAdapterDaemon();
+
+ int daemonInstanceSummary(
+ SWGSDRangel::SWGDaemonSummaryResponse& response,
+ SWGSDRangel::SWGErrorResponse& error);
+
+ int daemonInstanceLoggingGet(
+ SWGSDRangel::SWGLoggingInfo& response,
+ SWGSDRangel::SWGErrorResponse& error);
+
+ int daemonInstanceLoggingPut(
+ SWGSDRangel::SWGLoggingInfo& query,
+ SWGSDRangel::SWGLoggingInfo& response,
+ SWGSDRangel::SWGErrorResponse& error);
+
+ int daemonSettingsGet(
+ SWGSDRangel::SWGDeviceSettings& response,
+ SWGSDRangel::SWGErrorResponse& error);
+
+ int daemonSettingsPutPatch(
+ bool force,
+ const QStringList& deviceSettingsKeys,
+ SWGSDRangel::SWGDeviceSettings& response,
+ SWGSDRangel::SWGErrorResponse& error);
+
+ int daemonRunGet(
+ SWGSDRangel::SWGDeviceState& response,
+ SWGSDRangel::SWGErrorResponse& error);
+
+ int daemonRunPost(
+ SWGSDRangel::SWGDeviceState& response,
+ SWGSDRangel::SWGErrorResponse& error);
+
+ int daemonRunDelete(
+ SWGSDRangel::SWGDeviceState& response,
+ SWGSDRangel::SWGErrorResponse& error);
+
+ int daemonReportGet(
+ SWGSDRangel::SWGDeviceReport& response,
+ SWGSDRangel::SWGErrorResponse& error);
+
+ static QString daemonInstanceSummaryURL;
+ static QString daemonInstanceLoggingURL;
+ static QString daemonSettingsURL;
+ static QString daemonReportURL;
+ static QString daemonRunURL;
+
+private:
+ SDRDaemonMain& m_sdrDaemonMain;
+
+ static QtMsgType getMsgTypeFromString(const QString& msgTypeString);
+ static void getMsgTypeString(const QtMsgType& msgType, QString& level);
+};
+
+#endif /* SDRDAEMON_WEBAPI_WEBAPIADAPTERDAEMON_H_ */
diff --git a/sdrdaemon/webapi/webapirequestmapper.cpp b/sdrdaemon/webapi/webapirequestmapper.cpp
new file mode 100644
index 000000000..3b2a6eb7f
--- /dev/null
+++ b/sdrdaemon/webapi/webapirequestmapper.cpp
@@ -0,0 +1,706 @@
+///////////////////////////////////////////////////////////////////////////////////
+// Copyright (C) 2018 Edouard Griffiths, F4EXB. //
+// //
+// SDRDaemon Swagger server adapter interface //
+// //
+// 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 //
+// //
+// 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 "httpdocrootsettings.h"
+#include "webapirequestmapper.h"
+#include "SWGDaemonSummaryResponse.h"
+#include "SWGInstanceDevicesResponse.h"
+#include "SWGDeviceSettings.h"
+#include "SWGDeviceState.h"
+#include "SWGDeviceReport.h"
+#include "SWGSuccessResponse.h"
+#include "SWGErrorResponse.h"
+#include "SWGLoggingInfo.h"
+
+#include "webapirequestmapper.h"
+#include "webapiadapterdaemon.h"
+
+namespace SDRDaemon
+{
+
+WebAPIRequestMapper::WebAPIRequestMapper(QObject* parent) :
+ HttpRequestHandler(parent),
+ m_adapter(0)
+{
+ qtwebapp::HttpDocrootSettings docrootSettings;
+ docrootSettings.path = ":/webapi";
+ m_staticFileController = new qtwebapp::StaticFileController(docrootSettings, parent);
+}
+
+WebAPIRequestMapper::~WebAPIRequestMapper()
+{
+ delete m_staticFileController;
+}
+
+void WebAPIRequestMapper::service(qtwebapp::HttpRequest& request, qtwebapp::HttpResponse& response)
+{
+ if (m_adapter == 0) // format service unavailable if adapter is null
+ {
+ SWGSDRangel::SWGErrorResponse errorResponse;
+ response.setHeader("Content-Type", "application/json");
+ response.setHeader("Access-Control-Allow-Origin", "*");
+ response.setStatus(500,"Service not available");
+
+ errorResponse.init();
+ *errorResponse.getMessage() = "Service not available";
+ response.write(errorResponse.asJson().toUtf8());
+ }
+ else // normal processing
+ {
+ QByteArray path=request.getPath();
+
+ // Handle pre-flight requests
+ if (request.getMethod() == "OPTIONS")
+ {
+ qDebug("WebAPIRequestMapper::service: method OPTIONS: assume pre-flight");
+ response.setHeader("Access-Control-Allow-Origin", "*");
+ response.setHeader("Access-Control-Allow-Headers", "*");
+ response.setHeader("Access-Control-Allow-Methods", "*");
+ response.setStatus(200, "OK");
+ return;
+ }
+
+ if (path.startsWith("/sdrangel"))
+ {
+ SWGSDRangel::SWGErrorResponse errorResponse;
+ response.setStatus(501,"Not implemented");
+ errorResponse.init();
+ *errorResponse.getMessage() = "Not implemented";
+ response.write(errorResponse.asJson().toUtf8());
+ return;
+ }
+
+ if (path == WebAPIAdapterDaemon::daemonInstanceSummaryURL) {
+ daemonInstanceSummaryService(request, response);
+ } else if (path == WebAPIAdapterDaemon::daemonInstanceLoggingURL) {
+ daemonInstanceLoggingService(request, response);
+ } else if (path == WebAPIAdapterDaemon::daemonSettingsURL) {
+ daemonSettingsService(request, response);
+ } else if (path == WebAPIAdapterDaemon::daemonReportURL) {
+ daemonReportService(request, response);
+ } else if (path == WebAPIAdapterDaemon::daemonRunURL) {
+ daemonRunService(request, response);
+ } else {
+ m_staticFileController->service(request, response); // serve static pages
+ }
+ }
+}
+
+void WebAPIRequestMapper::daemonInstanceSummaryService(qtwebapp::HttpRequest& request, qtwebapp::HttpResponse& response)
+{
+ SWGSDRangel::SWGErrorResponse errorResponse;
+ response.setHeader("Content-Type", "application/json");
+ response.setHeader("Access-Control-Allow-Origin", "*");
+
+ if (request.getMethod() == "GET")
+ {
+ SWGSDRangel::SWGDaemonSummaryResponse normalResponse;
+
+ int status = m_adapter->daemonInstanceSummary(normalResponse, errorResponse);
+ response.setStatus(status);
+
+ if (status/100 == 2) {
+ response.write(normalResponse.asJson().toUtf8());
+ } else {
+ response.write(errorResponse.asJson().toUtf8());
+ }
+ }
+ else
+ {
+ response.setStatus(405,"Invalid HTTP method");
+ errorResponse.init();
+ *errorResponse.getMessage() = "Invalid HTTP method";
+ response.write(errorResponse.asJson().toUtf8());
+ }
+}
+
+void WebAPIRequestMapper::daemonInstanceLoggingService(qtwebapp::HttpRequest& request, qtwebapp::HttpResponse& response)
+{
+ SWGSDRangel::SWGLoggingInfo query;
+ SWGSDRangel::SWGLoggingInfo normalResponse;
+ SWGSDRangel::SWGErrorResponse errorResponse;
+ response.setHeader("Content-Type", "application/json");
+ response.setHeader("Access-Control-Allow-Origin", "*");
+
+ if (request.getMethod() == "GET")
+ {
+ int status = m_adapter->daemonInstanceLoggingGet(normalResponse, errorResponse);
+ response.setStatus(status);
+
+ if (status/100 == 2) {
+ response.write(normalResponse.asJson().toUtf8());
+ } else {
+ response.write(errorResponse.asJson().toUtf8());
+ }
+ }
+ else if (request.getMethod() == "PUT")
+ {
+ QString jsonStr = request.getBody();
+ QJsonObject jsonObject;
+
+ if (parseJsonBody(jsonStr, jsonObject, response))
+ {
+ query.fromJson(jsonStr);
+ int status = m_adapter->daemonInstanceLoggingPut(query, normalResponse, errorResponse);
+ response.setStatus(status);
+
+ if (status/100 == 2) {
+ response.write(normalResponse.asJson().toUtf8());
+ } else {
+ response.write(errorResponse.asJson().toUtf8());
+ }
+ }
+ else
+ {
+ response.setStatus(400,"Invalid JSON format");
+ errorResponse.init();
+ *errorResponse.getMessage() = "Invalid JSON format";
+ response.write(errorResponse.asJson().toUtf8());
+ }
+ }
+ else
+ {
+ response.setStatus(405,"Invalid HTTP method");
+ errorResponse.init();
+ *errorResponse.getMessage() = "Invalid HTTP method";
+ response.write(errorResponse.asJson().toUtf8());
+ }
+}
+
+void WebAPIRequestMapper::daemonSettingsService(qtwebapp::HttpRequest& request, qtwebapp::HttpResponse& response)
+{
+ SWGSDRangel::SWGErrorResponse errorResponse;
+ response.setHeader("Content-Type", "application/json");
+ response.setHeader("Access-Control-Allow-Origin", "*");
+
+ if ((request.getMethod() == "PUT") || (request.getMethod() == "PATCH"))
+ {
+ QString jsonStr = request.getBody();
+ QJsonObject jsonObject;
+
+ if (parseJsonBody(jsonStr, jsonObject, response))
+ {
+ SWGSDRangel::SWGDeviceSettings normalResponse;
+ resetDeviceSettings(normalResponse);
+ QStringList deviceSettingsKeys;
+
+ if (validateDeviceSettings(normalResponse, jsonObject, deviceSettingsKeys))
+ {
+ int status = m_adapter->daemonSettingsPutPatch(
+ (request.getMethod() == "PUT"), // force settings on PUT
+ deviceSettingsKeys,
+ normalResponse,
+ errorResponse);
+ response.setStatus(status);
+
+ if (status/100 == 2) {
+ response.write(normalResponse.asJson().toUtf8());
+ } else {
+ response.write(errorResponse.asJson().toUtf8());
+ }
+ }
+ else
+ {
+ response.setStatus(400,"Invalid JSON request");
+ errorResponse.init();
+ *errorResponse.getMessage() = "Invalid JSON request";
+ response.write(errorResponse.asJson().toUtf8());
+ }
+ }
+ else
+ {
+ response.setStatus(400,"Invalid JSON format");
+ errorResponse.init();
+ *errorResponse.getMessage() = "Invalid JSON format";
+ response.write(errorResponse.asJson().toUtf8());
+ }
+ }
+ else if (request.getMethod() == "GET")
+ {
+ SWGSDRangel::SWGDeviceSettings normalResponse;
+ resetDeviceSettings(normalResponse);
+ int status = m_adapter->daemonSettingsGet(normalResponse, errorResponse);
+ response.setStatus(status);
+
+ if (status/100 == 2) {
+ response.write(normalResponse.asJson().toUtf8());
+ } else {
+ response.write(errorResponse.asJson().toUtf8());
+ }
+ }
+ else
+ {
+ response.setStatus(405,"Invalid HTTP method");
+ errorResponse.init();
+ *errorResponse.getMessage() = "Invalid HTTP method";
+ response.write(errorResponse.asJson().toUtf8());
+ }
+}
+
+void WebAPIRequestMapper::daemonReportService(qtwebapp::HttpRequest& request, qtwebapp::HttpResponse& response)
+{
+ SWGSDRangel::SWGErrorResponse errorResponse;
+ response.setHeader("Content-Type", "application/json");
+ response.setHeader("Access-Control-Allow-Origin", "*");
+
+ if (request.getMethod() == "GET")
+ {
+ SWGSDRangel::SWGDeviceReport normalResponse;
+ resetDeviceReport(normalResponse);
+ int status = m_adapter->daemonReportGet(normalResponse, errorResponse);
+ response.setStatus(status);
+
+ if (status/100 == 2) {
+ response.write(normalResponse.asJson().toUtf8());
+ } else {
+ response.write(errorResponse.asJson().toUtf8());
+ }
+ }
+ else
+ {
+ response.setStatus(405,"Invalid HTTP method");
+ errorResponse.init();
+ *errorResponse.getMessage() = "Invalid HTTP method";
+ response.write(errorResponse.asJson().toUtf8());
+ }
+}
+
+void WebAPIRequestMapper::daemonRunService(qtwebapp::HttpRequest& request, qtwebapp::HttpResponse& response)
+{
+ SWGSDRangel::SWGErrorResponse errorResponse;
+ response.setHeader("Content-Type", "application/json");
+ response.setHeader("Access-Control-Allow-Origin", "*");
+
+ if (request.getMethod() == "GET")
+ {
+ SWGSDRangel::SWGDeviceState normalResponse;
+ int status = m_adapter->daemonRunGet(normalResponse, errorResponse);
+
+ response.setStatus(status);
+
+ if (status/100 == 2) {
+ response.write(normalResponse.asJson().toUtf8());
+ } else {
+ response.write(errorResponse.asJson().toUtf8());
+ }
+ }
+ else if (request.getMethod() == "POST")
+ {
+ SWGSDRangel::SWGDeviceState normalResponse;
+ int status = m_adapter->daemonRunPost(normalResponse, errorResponse);
+
+ response.setStatus(status);
+
+ if (status/100 == 2) {
+ response.write(normalResponse.asJson().toUtf8());
+ } else {
+ response.write(errorResponse.asJson().toUtf8());
+ }
+ }
+ else if (request.getMethod() == "DELETE")
+ {
+ SWGSDRangel::SWGDeviceState normalResponse;
+ int status = m_adapter->daemonRunDelete(normalResponse, errorResponse);
+
+ response.setStatus(status);
+
+ if (status/100 == 2) {
+ response.write(normalResponse.asJson().toUtf8());
+ } else {
+ response.write(errorResponse.asJson().toUtf8());
+ }
+ }
+ else
+ {
+ response.setStatus(405,"Invalid HTTP method");
+ errorResponse.init();
+ *errorResponse.getMessage() = "Invalid HTTP method";
+ response.write(errorResponse.asJson().toUtf8());
+ }
+}
+
+// TODO: put in library in common with SDRangel. Can be static.
+bool WebAPIRequestMapper::validateDeviceSettings(SWGSDRangel::SWGDeviceSettings& deviceSettings, QJsonObject& jsonObject, QStringList& deviceSettingsKeys)
+{
+ if (jsonObject.contains("tx")) {
+ deviceSettings.setTx(jsonObject["tx"].toInt());
+ } else {
+ deviceSettings.setTx(0); // assume Rx
+ }
+
+ if (jsonObject.contains("deviceHwType") && jsonObject["deviceHwType"].isString()) {
+ deviceSettings.setDeviceHwType(new QString(jsonObject["deviceHwType"].toString()));
+ } else {
+ return false;
+ }
+
+ QString *deviceHwType = deviceSettings.getDeviceHwType();
+
+ if ((*deviceHwType == "Airspy") && (deviceSettings.getTx() == 0))
+ {
+ if (jsonObject.contains("airspySettings") && jsonObject["airspySettings"].isObject())
+ {
+ QJsonObject airspySettingsJsonObject = jsonObject["airspySettings"].toObject();
+ deviceSettingsKeys = airspySettingsJsonObject.keys();
+ deviceSettings.setAirspySettings(new SWGSDRangel::SWGAirspySettings());
+ deviceSettings.getAirspySettings()->fromJsonObject(airspySettingsJsonObject);
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+ }
+ else if ((*deviceHwType == "AirspyHF") && (deviceSettings.getTx() == 0))
+ {
+ if (jsonObject.contains("airspyHFSettings") && jsonObject["airspyHFSettings"].isObject())
+ {
+ QJsonObject airspyHFSettingsJsonObject = jsonObject["airspyHFSettings"].toObject();
+ deviceSettingsKeys = airspyHFSettingsJsonObject.keys();
+ deviceSettings.setAirspyHfSettings(new SWGSDRangel::SWGAirspyHFSettings());
+ deviceSettings.getAirspyHfSettings()->fromJsonObject(airspyHFSettingsJsonObject);
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+ }
+ else if ((*deviceHwType == "BladeRF") && (deviceSettings.getTx() == 0))
+ {
+ if (jsonObject.contains("bladeRFInputSettings") && jsonObject["bladeRFInputSettings"].isObject())
+ {
+ QJsonObject bladeRFInputSettingsJsonObject = jsonObject["bladeRFInputSettings"].toObject();
+ deviceSettingsKeys = bladeRFInputSettingsJsonObject.keys();
+ deviceSettings.setBladeRfInputSettings(new SWGSDRangel::SWGBladeRFInputSettings());
+ deviceSettings.getBladeRfInputSettings()->fromJsonObject(bladeRFInputSettingsJsonObject);
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+ }
+ else if ((*deviceHwType == "BladeRF") && (deviceSettings.getTx() != 0))
+ {
+ if (jsonObject.contains("bladeRFOutputSettings") && jsonObject["bladeRFOutputSettings"].isObject())
+ {
+ QJsonObject bladeRFOutputSettingsJsonObject = jsonObject["bladeRFOutputSettings"].toObject();
+ deviceSettingsKeys = bladeRFOutputSettingsJsonObject.keys();
+ deviceSettings.setBladeRfOutputSettings(new SWGSDRangel::SWGBladeRFOutputSettings());
+ deviceSettings.getBladeRfOutputSettings()->fromJsonObject(bladeRFOutputSettingsJsonObject);
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+ }
+ else if (*deviceHwType == "FCDPro")
+ {
+ if (jsonObject.contains("fcdProSettings") && jsonObject["fcdProSettings"].isObject())
+ {
+ QJsonObject fcdProSettingsJsonObject = jsonObject["fcdProSettings"].toObject();
+ deviceSettingsKeys = fcdProSettingsJsonObject.keys();
+ deviceSettings.setFcdProSettings(new SWGSDRangel::SWGFCDProSettings());
+ deviceSettings.getFcdProSettings()->fromJsonObject(fcdProSettingsJsonObject);
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+ }
+ else if (*deviceHwType == "FCDProPlus")
+ {
+ if (jsonObject.contains("fcdProPlusSettings") && jsonObject["fcdProPlusSettings"].isObject())
+ {
+ QJsonObject fcdProPlusSettingsJsonObject = jsonObject["fcdProPlusSettings"].toObject();
+ deviceSettingsKeys = fcdProPlusSettingsJsonObject.keys();
+ deviceSettings.setFcdProPlusSettings(new SWGSDRangel::SWGFCDProPlusSettings());
+ deviceSettings.getFcdProPlusSettings()->fromJsonObject(fcdProPlusSettingsJsonObject);
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+ }
+ else if (*deviceHwType == "FileSource")
+ {
+ if (jsonObject.contains("fileSourceSettings") && jsonObject["fileSourceSettings"].isObject())
+ {
+ QJsonObject fileSourceSettingsJsonObject = jsonObject["fileSourceSettings"].toObject();
+ deviceSettingsKeys = fileSourceSettingsJsonObject.keys();
+ deviceSettings.setFileSourceSettings(new SWGSDRangel::SWGFileSourceSettings());
+ deviceSettings.getFileSourceSettings()->fromJsonObject(fileSourceSettingsJsonObject);
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+ }
+ else if ((*deviceHwType == "HackRF") && (deviceSettings.getTx() == 0))
+ {
+ if (jsonObject.contains("hackRFInputSettings") && jsonObject["hackRFInputSettings"].isObject())
+ {
+ QJsonObject hackRFInputSettingsJsonObject = jsonObject["hackRFInputSettings"].toObject();
+ deviceSettingsKeys = hackRFInputSettingsJsonObject.keys();
+ deviceSettings.setHackRfInputSettings(new SWGSDRangel::SWGHackRFInputSettings());
+ deviceSettings.getHackRfInputSettings()->fromJsonObject(hackRFInputSettingsJsonObject);
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+ }
+ else if ((*deviceHwType == "HackRF") && (deviceSettings.getTx() != 0))
+ {
+ if (jsonObject.contains("hackRFOutputSettings") && jsonObject["hackRFOutputSettings"].isObject())
+ {
+ QJsonObject hackRFOutputSettingsJsonObject = jsonObject["hackRFOutputSettings"].toObject();
+ deviceSettingsKeys = hackRFOutputSettingsJsonObject.keys();
+ deviceSettings.setHackRfOutputSettings(new SWGSDRangel::SWGHackRFOutputSettings());
+ deviceSettings.getHackRfOutputSettings()->fromJsonObject(hackRFOutputSettingsJsonObject);
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+ }
+ else if ((*deviceHwType == "LimeSDR") && (deviceSettings.getTx() == 0))
+ {
+ if (jsonObject.contains("limeSdrInputSettings") && jsonObject["limeSdrInputSettings"].isObject())
+ {
+ QJsonObject limeSdrInputSettingsJsonObject = jsonObject["limeSdrInputSettings"].toObject();
+ deviceSettingsKeys = limeSdrInputSettingsJsonObject.keys();
+ deviceSettings.setLimeSdrInputSettings(new SWGSDRangel::SWGLimeSdrInputSettings());
+ deviceSettings.getLimeSdrInputSettings()->fromJsonObject(limeSdrInputSettingsJsonObject);
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+ }
+ else if ((*deviceHwType == "LimeSDR") && (deviceSettings.getTx() != 0))
+ {
+ if (jsonObject.contains("limeSdrOutputSettings") && jsonObject["limeSdrOutputSettings"].isObject())
+ {
+ QJsonObject limeSdrOutputSettingsJsonObject = jsonObject["limeSdrOutputSettings"].toObject();
+ deviceSettingsKeys = limeSdrOutputSettingsJsonObject.keys();
+ deviceSettings.setLimeSdrOutputSettings(new SWGSDRangel::SWGLimeSdrOutputSettings());
+ deviceSettings.getLimeSdrOutputSettings()->fromJsonObject(limeSdrOutputSettingsJsonObject);
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+ }
+ else if (*deviceHwType == "Perseus")
+ {
+ if (jsonObject.contains("perseusSettings") && jsonObject["perseusSettings"].isObject())
+ {
+ QJsonObject perseusSettingsJsonObject = jsonObject["perseusSettings"].toObject();
+ deviceSettingsKeys = perseusSettingsJsonObject.keys();
+ deviceSettings.setPerseusSettings(new SWGSDRangel::SWGPerseusSettings());
+ deviceSettings.getPerseusSettings()->fromJsonObject(perseusSettingsJsonObject);
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+ }
+ else if ((*deviceHwType == "PlutoSDR") && (deviceSettings.getTx() == 0))
+ {
+ if (jsonObject.contains("plutoSdrInputSettings") && jsonObject["plutoSdrInputSettings"].isObject())
+ {
+ QJsonObject plutoSdrInputSettingsJsonObject = jsonObject["plutoSdrInputSettings"].toObject();
+ deviceSettingsKeys = plutoSdrInputSettingsJsonObject.keys();
+ deviceSettings.setPlutoSdrInputSettings(new SWGSDRangel::SWGPlutoSdrInputSettings());
+ deviceSettings.getPlutoSdrInputSettings()->fromJsonObject(plutoSdrInputSettingsJsonObject);
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+ }
+ else if ((*deviceHwType == "PlutoSDR") && (deviceSettings.getTx() != 0))
+ {
+ if (jsonObject.contains("plutoSdrOutputSettings") && jsonObject["plutoSdrOutputSettings"].isObject())
+ {
+ QJsonObject plutoSdrOutputSettingsJsonObject = jsonObject["plutoSdrOutputSettings"].toObject();
+ deviceSettingsKeys = plutoSdrOutputSettingsJsonObject.keys();
+ deviceSettings.setPlutoSdrOutputSettings(new SWGSDRangel::SWGPlutoSdrOutputSettings());
+ deviceSettings.getPlutoSdrOutputSettings()->fromJsonObject(plutoSdrOutputSettingsJsonObject);
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+ }
+ else if (*deviceHwType == "RTLSDR")
+ {
+ if (jsonObject.contains("rtlSdrSettings") && jsonObject["rtlSdrSettings"].isObject())
+ {
+ QJsonObject rtlSdrSettingsJsonObject = jsonObject["rtlSdrSettings"].toObject();
+ deviceSettingsKeys = rtlSdrSettingsJsonObject.keys();
+ deviceSettings.setRtlSdrSettings(new SWGSDRangel::SWGRtlSdrSettings());
+ deviceSettings.getRtlSdrSettings()->fromJsonObject(rtlSdrSettingsJsonObject);
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+ }
+ else if (*deviceHwType == "TestSource")
+ {
+ if (jsonObject.contains("testSourceSettings") && jsonObject["testSourceSettings"].isObject())
+ {
+ QJsonObject testSourceSettingsJsonObject = jsonObject["testSourceSettings"].toObject();
+ deviceSettingsKeys = testSourceSettingsJsonObject.keys();
+ deviceSettings.setTestSourceSettings(new SWGSDRangel::SWGTestSourceSettings());
+ deviceSettings.getTestSourceSettings()->fromJsonObject(testSourceSettingsJsonObject);
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+ }
+ else
+ {
+ return false;
+ }
+}
+
+// TODO: put in library in common with SDRangel. Can be static.
+void WebAPIRequestMapper::appendSettingsSubKeys(
+ const QJsonObject& parentSettingsJsonObject,
+ QJsonObject& childSettingsJsonObject,
+ const QString& parentKey,
+ QStringList& keyList)
+{
+ childSettingsJsonObject = parentSettingsJsonObject[parentKey].toObject();
+ QStringList childSettingsKeys = childSettingsJsonObject.keys();
+
+ for (int i = 0; i < childSettingsKeys.size(); i++) {
+ keyList.append(parentKey + QString(".") + childSettingsKeys.at(i));
+ }
+}
+
+// TODO: put in library in common with SDRangel. Can be static.
+bool WebAPIRequestMapper::parseJsonBody(QString& jsonStr, QJsonObject& jsonObject, qtwebapp::HttpResponse& response)
+{
+ SWGSDRangel::SWGErrorResponse errorResponse;
+
+ try
+ {
+ QByteArray jsonBytes(jsonStr.toStdString().c_str());
+ QJsonParseError error;
+ QJsonDocument doc = QJsonDocument::fromJson(jsonBytes, &error);
+
+ if (error.error == QJsonParseError::NoError)
+ {
+ jsonObject = doc.object();
+ }
+ else
+ {
+ QString errorMsg = QString("Input JSON error: ") + error.errorString() + QString(" at offset ") + QString::number(error.offset);
+ errorResponse.init();
+ *errorResponse.getMessage() = errorMsg;
+ response.setStatus(400, errorMsg.toUtf8());
+ response.write(errorResponse.asJson().toUtf8());
+ }
+
+ return (error.error == QJsonParseError::NoError);
+ }
+ catch (const std::exception& ex)
+ {
+ QString errorMsg = QString("Error parsing request: ") + ex.what();
+ errorResponse.init();
+ *errorResponse.getMessage() = errorMsg;
+ response.setStatus(500, errorMsg.toUtf8());
+ response.write(errorResponse.asJson().toUtf8());
+
+ return false;
+ }
+}
+
+// TODO: put in library in common with SDRangel. Can be static.
+void WebAPIRequestMapper::resetDeviceSettings(SWGSDRangel::SWGDeviceSettings& deviceSettings)
+{
+ deviceSettings.cleanup();
+ deviceSettings.setDeviceHwType(0);
+ deviceSettings.setAirspySettings(0);
+ deviceSettings.setAirspyHfSettings(0);
+ deviceSettings.setBladeRfInputSettings(0);
+ deviceSettings.setBladeRfOutputSettings(0);
+ deviceSettings.setFcdProPlusSettings(0);
+ deviceSettings.setFcdProSettings(0);
+ deviceSettings.setFileSourceSettings(0);
+ deviceSettings.setHackRfInputSettings(0);
+ deviceSettings.setHackRfOutputSettings(0);
+ deviceSettings.setLimeSdrInputSettings(0);
+ deviceSettings.setLimeSdrOutputSettings(0);
+ deviceSettings.setPerseusSettings(0);
+ deviceSettings.setPlutoSdrInputSettings(0);
+ deviceSettings.setPlutoSdrOutputSettings(0);
+ deviceSettings.setRtlSdrSettings(0);
+ deviceSettings.setSdrDaemonSinkSettings(0);
+ deviceSettings.setSdrDaemonSourceSettings(0);
+ deviceSettings.setSdrPlaySettings(0);
+ deviceSettings.setTestSourceSettings(0);
+}
+
+// TODO: put in library in common with SDRangel. Can be static.
+void WebAPIRequestMapper::resetDeviceReport(SWGSDRangel::SWGDeviceReport& deviceReport)
+{
+ deviceReport.cleanup();
+ deviceReport.setDeviceHwType(0);
+ deviceReport.setAirspyHfReport(0);
+ deviceReport.setAirspyReport(0);
+ deviceReport.setFileSourceReport(0);
+ deviceReport.setLimeSdrInputReport(0);
+ deviceReport.setLimeSdrOutputReport(0);
+ deviceReport.setPerseusReport(0);
+ deviceReport.setPlutoSdrInputReport(0);
+ deviceReport.setPlutoSdrOutputReport(0);
+ deviceReport.setRtlSdrReport(0);
+ deviceReport.setSdrDaemonSinkReport(0);
+ deviceReport.setSdrDaemonSourceReport(0);
+ deviceReport.setSdrPlayReport(0);
+}
+
+} // namespace SDRDaemon
+
+
diff --git a/sdrdaemon/webapi/webapirequestmapper.h b/sdrdaemon/webapi/webapirequestmapper.h
new file mode 100644
index 000000000..14cc361c8
--- /dev/null
+++ b/sdrdaemon/webapi/webapirequestmapper.h
@@ -0,0 +1,76 @@
+///////////////////////////////////////////////////////////////////////////////////
+// Copyright (C) 2017 Edouard Griffiths, F4EXB. //
+// //
+// SDRDaemon Swagger server adapter interface //
+// //
+// 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 //
+// //
+// 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 SDRDAEMON_WEBAPI_WEBAPIREQUESTMAPPER_H_
+#define SDRDAEMON_WEBAPI_WEBAPIREQUESTMAPPER_H_
+
+#include
+
+#include "httprequesthandler.h"
+#include "httprequest.h"
+#include "httpresponse.h"
+#include "staticfilecontroller.h"
+
+#include "export.h"
+
+namespace SWGSDRangel
+{
+ class SWGDeviceSettings;
+ class SWGDeviceReport;
+}
+
+class WebAPIAdapterDaemon;
+
+namespace SDRDaemon
+{
+
+class SDRBASE_API WebAPIRequestMapper : public qtwebapp::HttpRequestHandler {
+ Q_OBJECT
+public:
+ WebAPIRequestMapper(QObject* parent=0);
+ ~WebAPIRequestMapper();
+ void service(qtwebapp::HttpRequest& request, qtwebapp::HttpResponse& response);
+ void setAdapter(WebAPIAdapterDaemon *adapter) { m_adapter = adapter; }
+
+private:
+ WebAPIAdapterDaemon *m_adapter;
+ qtwebapp::StaticFileController *m_staticFileController;
+
+ void daemonInstanceSummaryService(qtwebapp::HttpRequest& request, qtwebapp::HttpResponse& response);
+ void daemonInstanceLoggingService(qtwebapp::HttpRequest& request, qtwebapp::HttpResponse& response);
+ void daemonSettingsService(qtwebapp::HttpRequest& request, qtwebapp::HttpResponse& response);
+ void daemonRunService(qtwebapp::HttpRequest& request, qtwebapp::HttpResponse& response);
+ void daemonReportService(qtwebapp::HttpRequest& request, qtwebapp::HttpResponse& response);
+
+ bool validateDeviceSettings(SWGSDRangel::SWGDeviceSettings& deviceSettings, QJsonObject& jsonObject, QStringList& deviceSettingsKeys);
+
+ void appendSettingsSubKeys(
+ const QJsonObject& parentSettingsJsonObject,
+ QJsonObject& childSettingsJsonObject,
+ const QString& parentKey,
+ QStringList& keyList);
+
+ bool parseJsonBody(QString& jsonStr, QJsonObject& jsonObject, qtwebapp::HttpResponse& response);
+
+ void resetDeviceSettings(SWGSDRangel::SWGDeviceSettings& deviceSettings);
+ void resetDeviceReport(SWGSDRangel::SWGDeviceReport& deviceReport);
+};
+
+} // namespace SDRdaemon
+
+#endif /* SDRDAEMON_WEBAPI_WEBAPIREQUESTMAPPER_H_ */
diff --git a/sdrdaemon/webapi/webapiserver.cpp b/sdrdaemon/webapi/webapiserver.cpp
new file mode 100644
index 000000000..b76993e61
--- /dev/null
+++ b/sdrdaemon/webapi/webapiserver.cpp
@@ -0,0 +1,67 @@
+///////////////////////////////////////////////////////////////////////////////////
+// Copyright (C) 2018 Edouard Griffiths, F4EXB. //
+// //
+// SDRdaemon Swagger server adapter interface //
+// //
+// 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 //
+// //
+// 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 "httplistener.h"
+#include "webapirequestmapper.h"
+#include "webapiserver.h"
+
+namespace SDRDaemon {
+
+WebAPIServer::WebAPIServer(const QString& host, uint16_t port, WebAPIRequestMapper *requestMapper) :
+ m_requestMapper(requestMapper),
+ m_listener(0)
+{
+ m_settings.host = host;
+ m_settings.port = port;
+}
+
+WebAPIServer::~WebAPIServer()
+{
+ if (m_listener) { delete m_listener; }
+}
+
+void WebAPIServer::start()
+{
+ if (!m_listener)
+ {
+ m_listener = new qtwebapp::HttpListener(m_settings, m_requestMapper, qApp);
+ qInfo("WebAPIServer::start: starting web API server at http://%s:%d", qPrintable(m_settings.host), m_settings.port);
+ }
+}
+
+void WebAPIServer::stop()
+{
+ if (m_listener)
+ {
+ delete m_listener;
+ m_listener = 0;
+ qInfo("WebAPIServer::stop: stopped web API server at http://%s:%d", qPrintable(m_settings.host), m_settings.port);
+ }
+}
+
+void WebAPIServer::setHostAndPort(const QString& host, uint16_t port)
+{
+ stop();
+ m_settings.host = host;
+ m_settings.port = port;
+ m_listener = new qtwebapp::HttpListener(m_settings, m_requestMapper, qApp);
+}
+
+} // namespace SDRdaemon
diff --git a/sdrdaemon/webapi/webapiserver.h b/sdrdaemon/webapi/webapiserver.h
new file mode 100644
index 000000000..a337412e6
--- /dev/null
+++ b/sdrdaemon/webapi/webapiserver.h
@@ -0,0 +1,56 @@
+///////////////////////////////////////////////////////////////////////////////////
+// Copyright (C) 2018 Edouard Griffiths, F4EXB. //
+// //
+// SDRdaemon Swagger server adapter interface //
+// //
+// 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 //
+// //
+// 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 SDRDAEMON_WEBAPI_WEBAPISERVER_H_
+#define SDRDAEMON_WEBAPI_WEBAPISERVER_H_
+
+#include
+#include "export.h"
+
+namespace qtwebapp
+{
+ class HttpListener;
+ class HttpListenerSettings;
+}
+
+namespace SDRDaemon {
+
+class WebAPIRequestMapper;
+
+class SDRBASE_API WebAPIServer
+{
+public:
+ WebAPIServer(const QString& host, uint16_t port, WebAPIRequestMapper *requestMapper);
+ ~WebAPIServer();
+
+ void start();
+ void stop();
+
+ void setHostAndPort(const QString& host, uint16_t port);
+ const QString& getHost() const { return m_settings.host; }
+ int getPort() const { return m_settings.port; }
+
+private:
+ WebAPIRequestMapper *m_requestMapper;
+ qtwebapp::HttpListener *m_listener;
+ qtwebapp::HttpListenerSettings m_settings;
+};
+
+} // namespace SDRdaemon
+
+#endif /* SDRDAEMON_WEBAPI_WEBAPISERVER_H_ */