Complete removal of SDRDaemon as a distinct binary

This commit is contained in:
f4exb 2018-09-11 13:41:09 +02:00
parent 4cd9055fe6
commit 6c77f2dfe5
41 changed files with 29 additions and 5274 deletions

View File

@ -13,7 +13,7 @@ set(CMAKE_SKIP_BUILD_RPATH FALSE)
# when building, don't use the install RPATH already
# (but later on when installing)
set(CMAKE_BUILD_WITH_INSTALL_RPATH FALSE)
set(CMAKE_BUILD_WITH_INSTALL_RPATH FALSE)
SET(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/lib")
@ -222,7 +222,6 @@ endif()
add_subdirectory(sdrbase)
add_subdirectory(sdrgui)
add_subdirectory(sdrsrv)
add_subdirectory(sdrdaemon)
add_subdirectory(sdrbench)
add_subdirectory(httpserver)
add_subdirectory(logging)
@ -327,31 +326,6 @@ target_link_libraries(sdrangelbench
target_compile_features(sdrangelbench PRIVATE cxx_generalized_initializers) # cmake >= 3.1.0
target_link_libraries(sdrangelbench Qt5::Multimedia)
##############################################################################
# SDRdaemon application
set(sdrdaemonsrv_SOURCES
appdaemon/main.cpp
)
add_executable(sdrdaemonsrv
${sdrdaemonsrv_SOURCES}
)
target_include_directories(sdrdaemonsrv
PUBLIC ${CMAKE_SOURCE_DIR}/sdrdaemon
)
target_link_libraries(sdrdaemonsrv
sdrdaemon
sdrbase
logging
${QT_LIBRARIES}
)
target_compile_features(sdrdaemonsrv PRIVATE cxx_generalized_initializers) # cmake >= 3.1.0
target_link_libraries(sdrdaemonsrv Qt5::Multimedia)
##############################################################################
if (BUILD_DEBIAN)
@ -385,7 +359,6 @@ endif(LIBUSB_FOUND AND UNIX)
install(TARGETS sdrangel DESTINATION bin)
install(TARGETS sdrangelsrv DESTINATION bin)
install(TARGETS sdrangelbench DESTINATION bin)
install(TARGETS sdrdaemonsrv DESTINATION bin)
#install(TARGETS sdrbase DESTINATION lib)
#install files and directories

View File

@ -1,122 +0,0 @@
///////////////////////////////////////////////////////////////////////////////////
// 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 <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#include <QCoreApplication>
#include <QSysInfo>
#include <signal.h>
#include <unistd.h>
#include <vector>
#include "dsp/dsptypes.h"
#include "loggerwithfile.h"
#include "sdrdaemonparser.h"
#include "sdrdaemonmain.h"
void handler(int sig) {
fprintf(stderr, "quit the application by signal(%d).\n", sig);
QCoreApplication::quit();
}
void catchUnixSignals(const std::vector<int>& quitSignals) {
sigset_t blocking_mask;
sigemptyset(&blocking_mask);
for (std::vector<int>::const_iterator it = quitSignals.begin(); it != quitSignals.end(); ++it) {
sigaddset(&blocking_mask, *it);
}
struct sigaction sa;
sa.sa_handler = handler;
sa.sa_mask = blocking_mask;
sa.sa_flags = 0;
for (std::vector<int>::const_iterator it = quitSignals.begin(); it != quitSignals.end(); ++it) {
sigaction(*it, &sa, 0);
}
}
static int runQtApplication(int argc, char* argv[], qtwebapp::LoggerWithFile *logger)
{
QCoreApplication a(argc, argv);
QCoreApplication::setOrganizationName("f4exb");
QCoreApplication::setApplicationName("SDRdaemonSrv");
QCoreApplication::setApplicationVersion("4.1.0");
int catchSignals[] = {SIGQUIT, SIGINT, SIGTERM, SIGHUP};
std::vector<int> vsig(catchSignals, catchSignals + sizeof(catchSignals) / sizeof(int));
catchUnixSignals(vsig);
SDRDaemonParser parser;
parser.parse(a);
#if QT_VERSION >= 0x050400
qInfo("%s %s Qt %s %db %s %s DSP Rx:%db Tx:%db PID %lld",
qPrintable(QCoreApplication::applicationName()),
qPrintable(QCoreApplication::applicationVersion()),
qPrintable(QString(QT_VERSION_STR)),
QT_POINTER_SIZE*8,
qPrintable(QSysInfo::currentCpuArchitecture()),
qPrintable(QSysInfo::prettyProductName()),
SDR_RX_SAMP_SZ,
SDR_TX_SAMP_SZ,
QCoreApplication::applicationPid());
#else
qInfo("%s %s Qt %s %db DSP Rx:%db Tx:%db PID %lld",
qPrintable(QCoreApplication::applicationName()),
qPrintable((QCoreApplication::>applicationVersion()),
qPrintable(QString(QT_VERSION_STR)),
QT_POINTER_SIZE*8,
SDR_RX_SAMP_SZ,
SDR_TX_SAMP_SZ,
QCoreApplication::applicationPid());
#endif
SDRDaemonMain m(logger, parser, &a);
if (m.doAbort())
{
return -1;
}
else
{
// This will cause the application to exit when SDRdaemon is finished
QObject::connect(&m, SIGNAL(finished()), &a, SLOT(quit()));
return a.exec();
}
}
int main(int argc, char* argv[])
{
qtwebapp::LoggerWithFile *logger = new qtwebapp::LoggerWithFile(qApp);
logger->installMsgHandler();
int res = runQtApplication(argc, argv, logger);
qWarning("SDRdaemon quit.");
return res;
}

View File

@ -25,9 +25,8 @@ set(daemonsink_FORMS
include_directories(
.
${CMAKE_CURRENT_BINARY_DIR}
${CMAKE_SOURCE_DIR}/sdrdaemon
${CM256CC_INCLUDE_DIR}
${CMAKE_SOURCE_DIR}/swagger/sdrangel/code/qt5/client
${CMAKE_SOURCE_DIR}/swagger/sdrangel/code/qt5/client
)
#include(${QT_USE_FILE})
@ -47,7 +46,6 @@ target_link_libraries(daemonsink
${QT_LIBRARIES}
${CM256CC_LIBRARIES}
sdrbase
sdrdaemon
sdrgui
swagger
)

View File

@ -25,7 +25,6 @@ set(daemonsrc_FORMS
include_directories(
.
${CMAKE_CURRENT_BINARY_DIR}
${CMAKE_SOURCE_DIR}/sdrdaemon
${CM256CC_INCLUDE_DIR}
${CMAKE_SOURCE_DIR}/swagger/sdrangel/code/qt5/client
)
@ -47,7 +46,6 @@ target_link_libraries(daemonsrc
${QT_LIBRARIES}
${CM256CC_LIBRARIES}
sdrbase
sdrdaemon
sdrgui
swagger
)

View File

@ -21,7 +21,6 @@
#include "channel/sdrdaemondataqueue.h"
#include "channel/sdrdaemondatablock.h"
#include "channel/sdrdaemonchannelsourcethread.h"
#include "daemonsrcthread.h"

View File

@ -20,9 +20,8 @@ set(daemonsink_HEADERS
include_directories(
.
${CMAKE_CURRENT_BINARY_DIR}
${CMAKE_SOURCE_DIR}/sdrdaemon
${CM256CC_INCLUDE_DIR}
${CMAKE_SOURCE_DIR}/swagger/sdrangel/code/qt5/client
${CMAKE_SOURCE_DIR}/swagger/sdrangel/code/qt5/client
)
#include(${QT_USE_FILE})
@ -39,7 +38,6 @@ target_link_libraries(daemonsinksrv
${QT_LIBRARIES}
${CM256CC_LIBRARIES}
sdrbase
sdrdaemon
swagger
)

View File

@ -20,7 +20,6 @@ set(daemonsrc_HEADERS
include_directories(
.
${CMAKE_CURRENT_BINARY_DIR}
${CMAKE_SOURCE_DIR}/sdrdaemon
${CM256CC_INCLUDE_DIR}
${CMAKE_SOURCE_DIR}/swagger/sdrangel/code/qt5/client
)
@ -39,7 +38,6 @@ target_link_libraries(daemonsrcsrv
${QT_LIBRARIES}
${CM256CC_LIBRARIES}
sdrbase
sdrdaemon
swagger
)

View File

@ -9,9 +9,12 @@ set(sdrbase_SOURCES
audio/audiooutput.cpp
audio/audioinput.cpp
audio/audionetsink.cpp
channel/channelsinkapi.cpp
channel/channelsourceapi.cpp
channel/sdrdaemondataqueue.cpp
channel/sdrdaemondatareadqueue.cpp
commands/command.cpp
dsp/afsquelch.cpp
@ -22,7 +25,7 @@ set(sdrbase_SOURCES
dsp/ctcssdetector.cpp
dsp/cwkeyer.cpp
dsp/cwkeyersettings.cpp
dsp/decimatorsif.cpp
dsp/decimatorsif.cpp
dsp/decimatorsff.cpp
dsp/decimatorsfi.cpp
dsp/dspcommands.cpp
@ -78,15 +81,15 @@ set(sdrbase_SOURCES
util/simpleserializer.cpp
#util/spinlock.cpp
util/uid.cpp
plugin/plugininterface.cpp
plugin/plugininterface.cpp
plugin/pluginapi.cpp
plugin/pluginmanager.cpp
webapi/webapiadapterinterface.cpp
webapi/webapirequestmapper.cpp
webapi/webapiserver.cpp
mainparser.cpp
)
@ -100,6 +103,10 @@ set(sdrbase_HEADERS
channel/channelsinkapi.h
channel/channelsourceapi.h
channel/sdrdaemondataqueue.h
channel/sdrdaemondatareadqueue.h
channel/sdrdaemondatablock.h
commands/command.h
dsp/afsquelch.h
@ -197,11 +204,11 @@ set(sdrbase_HEADERS
util/simpleserializer.h
#util/spinlock.h
util/uid.h
webapi/webapiadapterinterface.h
webapi/webapirequestmapper.h
webapi/webapiserver
mainparser.h
)

View File

@ -57,6 +57,8 @@ SOURCES += audio/audiodevicemanager.cpp\
audio/audionetsink.cpp\
channel/channelsinkapi.cpp\
channel/channelsourceapi.cpp\
channel/sdrdaemondataqueue.cpp\
channel/sdrdaemondatareadqueue.cpp\
commands/command.cpp\
device/devicesourceapi.cpp\
device/devicesinkapi.cpp\
@ -117,7 +119,7 @@ SOURCES += audio/audiodevicemanager.cpp\
util/simpleserializer.cpp\
util/uid.cpp\
plugin/plugininterface.cpp\
plugin/pluginapi.cpp\
plugin/pluginapi.cpp\
plugin/pluginmanager.cpp\
webapi/webapiadapterinterface.cpp\
webapi/webapirequestmapper.cpp\
@ -131,8 +133,11 @@ HEADERS += audio/audiodevicemanager.h\
audio/audioinput.h\
audio/audionetsink.h\
channel/channelsinkapi.h\
channel/channelsourceapi.h\
commands/command.h\
channel/channelsourceapi.h\
channel/sdrdaemondataqueue.h\
channel/sdrdaemondatareadqueue.h\
channel/sdrdaemondatablock.h\
commands/command.h\
device/devicesourceapi.h\
device/devicesinkapi.h\
device/deviceenumerator.h\
@ -195,9 +200,9 @@ HEADERS += audio/audiodevicemanager.h\
dsp/devicesamplesource.h\
dsp/devicesamplesink.h\
plugin/plugininstancegui.h\
plugin/plugininterface.h\
plugin/pluginapi.h\
plugin/pluginmanager.h\
plugin/plugininterface.h\
plugin/pluginapi.h\
plugin/pluginmanager.h\
settings/preferences.h\
settings/preset.h\
settings/mainsettings.h\

View File

@ -1,76 +0,0 @@
project (sdrdaemon)
set(sdrdaemon_SOURCES
sdrdaemonmain.cpp
sdrdaemonpreferences.cpp
sdrdaemonsettings.cpp
sdrdaemonparser.cpp
channel/sdrdaemonchannelsink.cpp
channel/sdrdaemonchannelsource.cpp
channel/sdrdaemondataqueue.cpp
channel/sdrdaemondatareadqueue.cpp
channel/sdrdaemonchannelsinkthread.cpp
channel/sdrdaemonchannelsinksettings.cpp
channel/sdrdaemonchannelsourcesettings.cpp
channel/sdrdaemonchannelsourcethread.cpp
webapi/webapiadapterdaemon.cpp
webapi/webapirequestmapper.cpp
webapi/webapiserver.cpp
)
set(sdrdaemon_HEADERS
sdrdaemonmain.h
sdrdaemonpreferences.h
sdrdaemonsettings.h
sdrdaemonparser.h
channel/sdrdaemonchannelsink.h
channel/sdrdaemonchannelsource.h
channel/sdrdaemondataqueue.h
channel/sdrdaemondatareadqueue.h
channel/sdrdaemondatablock.h
channel/sdrdaemonchannelsinkthread.h
channel/sdrdaemonchannelsinksettings.h
channel/sdrdaemonchannelsourcesettings.h
channel/sdrdaemonchannelsourcethread.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
${CM256CC_INCLUDE_DIR}
${CMAKE_CURRENT_BINARY_DIR}
)
target_link_libraries(sdrdaemon
${QT_LIBRARIES}
${CM256CC_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)

View File

@ -1,401 +0,0 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2018 Edouard Griffiths, F4EXB. //
// //
// SDRdaemon sink channel (Rx) //
// //
// 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 <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#include <sys/time.h>
#include <unistd.h>
#include <boost/crc.hpp>
#include <boost/cstdint.hpp>
#include "SWGChannelSettings.h"
#include "util/simpleserializer.h"
#include "dsp/threadedbasebandsamplesink.h"
#include "dsp/downchannelizer.h"
#include "dsp/dspcommands.h"
#include "device/devicesourceapi.h"
#include "channel/sdrdaemonchannelsinkthread.h"
#include "sdrdaemonchannelsink.h"
MESSAGE_CLASS_DEFINITION(SDRDaemonChannelSink::MsgConfigureSDRDaemonChannelSink, Message)
const QString SDRDaemonChannelSink::m_channelIdURI = "sdrangel.channel.sdrdaemonsink";
const QString SDRDaemonChannelSink::m_channelId = "SDRDaemonChannelSink";
SDRDaemonChannelSink::SDRDaemonChannelSink(DeviceSourceAPI *deviceAPI) :
ChannelSinkAPI(m_channelIdURI),
m_deviceAPI(deviceAPI),
m_running(false),
m_sinkThread(0),
m_txBlockIndex(0),
m_frameCount(0),
m_sampleIndex(0),
m_dataBlock(0),
m_centerFrequency(0),
m_sampleRate(48000),
m_sampleBytes(SDR_RX_SAMP_SZ == 24 ? 4 : 2),
m_nbBlocksFEC(0),
m_txDelay(100),
m_dataAddress("127.0.0.1"),
m_dataPort(9090)
{
setObjectName(m_channelId);
m_channelizer = new DownChannelizer(this);
m_threadedChannelizer = new ThreadedBasebandSampleSink(m_channelizer, this);
m_deviceAPI->addThreadedSink(m_threadedChannelizer);
m_deviceAPI->addChannelAPI(this);
m_cm256p = m_cm256.isInitialized() ? &m_cm256 : 0;
}
SDRDaemonChannelSink::~SDRDaemonChannelSink()
{
m_dataBlockMutex.lock();
if (m_dataBlock && !m_dataBlock->m_txControlBlock.m_complete) {
delete m_dataBlock;
}
m_dataBlockMutex.unlock();
m_deviceAPI->removeChannelAPI(this);
m_deviceAPI->removeThreadedSink(m_threadedChannelizer);
delete m_threadedChannelizer;
delete m_channelizer;
}
void SDRDaemonChannelSink::setTxDelay(int txDelay)
{
qDebug() << "SDRDaemonChannelSink::setTxDelay: txDelay: " << txDelay;
m_txDelay = txDelay;
}
void SDRDaemonChannelSink::setNbBlocksFEC(int nbBlocksFEC)
{
qDebug() << "SDRDaemonChannelSink::setNbBlocksFEC: nbBlocksFEC: " << nbBlocksFEC;
m_nbBlocksFEC = nbBlocksFEC;
}
void SDRDaemonChannelSink::feed(const SampleVector::const_iterator& begin, const SampleVector::const_iterator& end, bool firstOfBurst __attribute__((unused)))
{
SampleVector::const_iterator it = begin;
while (it != end)
{
int inSamplesIndex = it - begin;
int inRemainingSamples = end - it;
if (m_txBlockIndex == 0)
{
struct timeval tv;
SDRDaemonMetaDataFEC metaData;
gettimeofday(&tv, 0);
metaData.m_centerFrequency = m_centerFrequency;
metaData.m_sampleRate = m_sampleRate;
metaData.m_sampleBytes = m_sampleBytes;
metaData.m_sampleBits = 0; // TODO: deprecated
metaData.m_nbOriginalBlocks = SDRDaemonNbOrginalBlocks;
metaData.m_nbFECBlocks = m_nbBlocksFEC;
metaData.m_tv_sec = tv.tv_sec;
metaData.m_tv_usec = tv.tv_usec;
if (!m_dataBlock) { // on the very first cycle there is no data block allocated
m_dataBlock = new SDRDaemonDataBlock();
}
boost::crc_32_type crc32;
crc32.process_bytes(&metaData, 20);
metaData.m_crc32 = crc32.checksum();
SDRDaemonSuperBlock& superBlock = m_dataBlock->m_superBlocks[0]; // first block
superBlock.init();
superBlock.m_header.m_frameIndex = m_frameCount;
superBlock.m_header.m_blockIndex = m_txBlockIndex;
memcpy((void *) &superBlock.m_protectedBlock, (const void *) &metaData, sizeof(SDRDaemonMetaDataFEC));
if (!(metaData == m_currentMetaFEC))
{
qDebug() << "SDRDaemonChannelSink::feed: meta: "
<< "|" << metaData.m_centerFrequency
<< ":" << metaData.m_sampleRate
<< ":" << (int) (metaData.m_sampleBytes & 0xF)
<< ":" << (int) metaData.m_sampleBits
<< "|" << (int) metaData.m_nbOriginalBlocks
<< ":" << (int) metaData.m_nbFECBlocks
<< "|" << metaData.m_tv_sec
<< ":" << metaData.m_tv_usec;
m_currentMetaFEC = metaData;
}
m_txBlockIndex = 1; // next Tx block with data
} // block zero
// handle different sample sizes...
int samplesPerBlock = SDRDaemonNbBytesPerBlock / sizeof(Sample);
if (m_sampleIndex + inRemainingSamples < samplesPerBlock) // there is still room in the current super block
{
memcpy((void *) &m_superBlock.m_protectedBlock.buf[m_sampleIndex*sizeof(Sample)],
(const void *) &(*(begin+inSamplesIndex)),
inRemainingSamples * sizeof(Sample));
m_sampleIndex += inRemainingSamples;
it = end; // all input samples are consumed
}
else // complete super block and initiate the next if not end of frame
{
memcpy((void *) &m_superBlock.m_protectedBlock.buf[m_sampleIndex*sizeof(Sample)],
(const void *) &(*(begin+inSamplesIndex)),
(samplesPerBlock - m_sampleIndex) * sizeof(Sample));
it += samplesPerBlock - m_sampleIndex;
m_sampleIndex = 0;
m_superBlock.m_header.m_frameIndex = m_frameCount;
m_superBlock.m_header.m_blockIndex = m_txBlockIndex;
m_dataBlock->m_superBlocks[m_txBlockIndex] = m_superBlock;
if (m_txBlockIndex == SDRDaemonNbOrginalBlocks - 1) // frame complete
{
m_dataBlockMutex.lock();
m_dataBlock->m_txControlBlock.m_frameIndex = m_frameCount;
m_dataBlock->m_txControlBlock.m_processed = false;
m_dataBlock->m_txControlBlock.m_complete = true;
m_dataBlock->m_txControlBlock.m_nbBlocksFEC = m_nbBlocksFEC;
m_dataBlock->m_txControlBlock.m_txDelay = m_txDelay;
m_dataBlock->m_txControlBlock.m_dataAddress = m_dataAddress;
m_dataBlock->m_txControlBlock.m_dataPort = m_dataPort;
m_dataQueue.push(m_dataBlock);
m_dataBlock = new SDRDaemonDataBlock(); // create a new one immediately
m_dataBlockMutex.unlock();
m_txBlockIndex = 0;
m_frameCount++;
}
else
{
m_txBlockIndex++;
}
}
}
}
void SDRDaemonChannelSink::start()
{
qDebug("SDRDaemonChannelSink::start");
memset((void *) &m_currentMetaFEC, 0, sizeof(SDRDaemonMetaDataFEC));
if (m_running) {
stop();
}
m_sinkThread = new SDRDaemonChannelSinkThread(&m_dataQueue, m_cm256p);
m_sinkThread->startStop(true);
m_running = true;
}
void SDRDaemonChannelSink::stop()
{
qDebug("SDRDaemonChannelSink::stop");
if (m_sinkThread != 0)
{
m_sinkThread->startStop(false);
m_sinkThread->deleteLater();
m_sinkThread = 0;
}
m_running = false;
}
bool SDRDaemonChannelSink::handleMessage(const Message& cmd __attribute__((unused)))
{
if (DownChannelizer::MsgChannelizerNotification::match(cmd))
{
DownChannelizer::MsgChannelizerNotification& notif = (DownChannelizer::MsgChannelizerNotification&) cmd;
qDebug() << "SDRDaemonChannelSink::handleMessage: MsgChannelizerNotification:"
<< " channelSampleRate: " << notif.getSampleRate()
<< " offsetFrequency: " << notif.getFrequencyOffset();
if (notif.getSampleRate() > 0) {
setSampleRate(notif.getSampleRate());
}
return true;
}
else if (DSPSignalNotification::match(cmd))
{
DSPSignalNotification& notif = (DSPSignalNotification&) cmd;
qDebug() << "SDRDaemonChannelSink::handleMessage: DSPSignalNotification:"
<< " inputSampleRate: " << notif.getSampleRate()
<< " centerFrequency: " << notif.getCenterFrequency();
setCenterFrequency(notif.getCenterFrequency());
return true;
}
else if (MsgConfigureSDRDaemonChannelSink::match(cmd))
{
MsgConfigureSDRDaemonChannelSink& cfg = (MsgConfigureSDRDaemonChannelSink&) cmd;
qDebug() << "SDRDaemonChannelSink::handleMessage: MsgConfigureSDRDaemonChannelSink";
applySettings(cfg.getSettings(), cfg.getForce());
return true;
}
else
{
return false;
}
}
QByteArray SDRDaemonChannelSink::serialize() const
{
return m_settings.serialize();
}
bool SDRDaemonChannelSink::deserialize(const QByteArray& data __attribute__((unused)))
{
if (m_settings.deserialize(data))
{
MsgConfigureSDRDaemonChannelSink *msg = MsgConfigureSDRDaemonChannelSink::create(m_settings, true);
m_inputMessageQueue.push(msg);
return true;
}
else
{
m_settings.resetToDefaults();
MsgConfigureSDRDaemonChannelSink *msg = MsgConfigureSDRDaemonChannelSink::create(m_settings, true);
m_inputMessageQueue.push(msg);
return false;
}
}
void SDRDaemonChannelSink::applySettings(const SDRDaemonChannelSinkSettings& settings, bool force)
{
qDebug() << "SDRDaemonChannelSink::applySettings:"
<< " m_nbFECBlocks: " << settings.m_nbFECBlocks
<< " m_txDelay: " << settings.m_txDelay
<< " m_dataAddress: " << settings.m_dataAddress
<< " m_dataPort: " << settings.m_dataPort
<< " force: " << force;
if ((m_settings.m_nbFECBlocks != settings.m_nbFECBlocks) || force) {
m_nbBlocksFEC = settings.m_nbFECBlocks;
}
if ((m_settings.m_txDelay != settings.m_txDelay) || force) {
m_txDelay = settings.m_txDelay;
}
if ((m_settings.m_dataAddress != settings.m_dataAddress) || force) {
m_dataAddress = settings.m_dataAddress;
}
if ((m_settings.m_dataPort != settings.m_dataPort) || force) {
m_dataPort = settings.m_dataPort;
}
m_settings = settings;
}
int SDRDaemonChannelSink::webapiSettingsGet(
SWGSDRangel::SWGChannelSettings& response,
QString& errorMessage __attribute__((unused)))
{
response.setDaemonSinkSettings(new SWGSDRangel::SWGDaemonSinkSettings());
response.getDaemonSinkSettings()->init();
webapiFormatChannelSettings(response, m_settings);
return 200;
}
int SDRDaemonChannelSink::webapiSettingsPutPatch(
bool force,
const QStringList& channelSettingsKeys,
SWGSDRangel::SWGChannelSettings& response,
QString& errorMessage __attribute__((unused)))
{
SDRDaemonChannelSinkSettings settings = m_settings;
if (channelSettingsKeys.contains("nbFECBlocks"))
{
int nbFECBlocks = response.getDaemonSinkSettings()->getNbFecBlocks();
if ((nbFECBlocks < 0) || (nbFECBlocks > 127)) {
settings.m_nbFECBlocks = 8;
} else {
settings.m_nbFECBlocks = response.getDaemonSinkSettings()->getNbFecBlocks();
}
}
if (channelSettingsKeys.contains("txDelay"))
{
int txDelay = response.getDaemonSinkSettings()->getTxDelay();
if (txDelay < 0) {
settings.m_txDelay = 100;
} else {
settings.m_txDelay = txDelay;
}
}
if (channelSettingsKeys.contains("dataAddress")) {
settings.m_dataAddress = *response.getDaemonSinkSettings()->getDataAddress();
}
if (channelSettingsKeys.contains("dataPort"))
{
int dataPort = response.getDaemonSinkSettings()->getDataPort();
if ((dataPort < 1024) || (dataPort > 65535)) {
settings.m_dataPort = 9090;
} else {
settings.m_dataPort = dataPort;
}
}
MsgConfigureSDRDaemonChannelSink *msg = MsgConfigureSDRDaemonChannelSink::create(settings, force);
m_inputMessageQueue.push(msg);
qDebug("SDRDaemonChannelSink::webapiSettingsPutPatch: forward to GUI: %p", m_guiMessageQueue);
if (m_guiMessageQueue) // forward to GUI if any
{
MsgConfigureSDRDaemonChannelSink *msgToGUI = MsgConfigureSDRDaemonChannelSink::create(settings, force);
m_guiMessageQueue->push(msgToGUI);
}
webapiFormatChannelSettings(response, settings);
return 200;
}
void SDRDaemonChannelSink::webapiFormatChannelSettings(SWGSDRangel::SWGChannelSettings& response, const SDRDaemonChannelSinkSettings& settings)
{
response.getDaemonSinkSettings()->setNbFecBlocks(settings.m_nbFECBlocks);
response.getDaemonSinkSettings()->setTxDelay(settings.m_txDelay);
if (response.getDaemonSinkSettings()->getDataAddress()) {
*response.getDaemonSinkSettings()->getDataAddress() = settings.m_dataAddress;
} else {
response.getDaemonSinkSettings()->setDataAddress(new QString(settings.m_dataAddress));
}
response.getDaemonSinkSettings()->setDataPort(settings.m_dataPort);
}

View File

@ -1,139 +0,0 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2018 Edouard Griffiths, F4EXB. //
// //
// SDRdaemon sink channel (Rx) //
// //
// 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 <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#ifndef SDRDAEMON_CHANNEL_SDRDAEMONCHANNELSINK_H_
#define SDRDAEMON_CHANNEL_SDRDAEMONCHANNELSINK_H_
#include <QMutex>
#include "cm256.h"
#include "dsp/basebandsamplesink.h"
#include "channel/channelsinkapi.h"
#include "channel/sdrdaemondataqueue.h"
#include "channel/sdrdaemondatablock.h"
#include "channel/sdrdaemonchannelsinksettings.h"
class DeviceSourceAPI;
class ThreadedBasebandSampleSink;
class DownChannelizer;
class SDRDaemonChannelSinkThread;
class SDRDaemonChannelSink : public BasebandSampleSink, public ChannelSinkAPI {
Q_OBJECT
public:
class MsgConfigureSDRDaemonChannelSink : public Message {
MESSAGE_CLASS_DECLARATION
public:
const SDRDaemonChannelSinkSettings& getSettings() const { return m_settings; }
bool getForce() const { return m_force; }
static MsgConfigureSDRDaemonChannelSink* create(const SDRDaemonChannelSinkSettings& settings, bool force)
{
return new MsgConfigureSDRDaemonChannelSink(settings, force);
}
private:
SDRDaemonChannelSinkSettings m_settings;
bool m_force;
MsgConfigureSDRDaemonChannelSink(const SDRDaemonChannelSinkSettings& settings, bool force) :
Message(),
m_settings(settings),
m_force(force)
{ }
};
SDRDaemonChannelSink(DeviceSourceAPI *deviceAPI);
virtual ~SDRDaemonChannelSink();
virtual void destroy() { delete this; }
virtual void feed(const SampleVector::const_iterator& begin, const SampleVector::const_iterator& end, bool po);
virtual void start();
virtual void stop();
virtual bool handleMessage(const Message& cmd);
virtual void getIdentifier(QString& id) { id = objectName(); }
virtual void getTitle(QString& title) { title = "SDRDaemon Sink"; }
virtual qint64 getCenterFrequency() const { return 0; }
virtual QByteArray serialize() const;
virtual bool deserialize(const QByteArray& data);
virtual int webapiSettingsGet(
SWGSDRangel::SWGChannelSettings& response,
QString& errorMessage);
virtual int webapiSettingsPutPatch(
bool force,
const QStringList& channelSettingsKeys,
SWGSDRangel::SWGChannelSettings& response,
QString& errorMessage);
/** Set center frequency given in Hz */
void setCenterFrequency(uint64_t centerFrequency) { m_centerFrequency = centerFrequency / 1000; }
/** Set sample rate given in Hz */
void setSampleRate(uint32_t sampleRate) { m_sampleRate = sampleRate; }
void setNbBlocksFEC(int nbBlocksFEC);
void setTxDelay(int txDelay);
void setDataAddress(const QString& address) { m_dataAddress = address; }
void setDataPort(uint16_t port) { m_dataPort = port; }
static const QString m_channelIdURI;
static const QString m_channelId;
private:
DeviceSourceAPI *m_deviceAPI;
ThreadedBasebandSampleSink* m_threadedChannelizer;
DownChannelizer* m_channelizer;
bool m_running;
SDRDaemonChannelSinkSettings m_settings;
SDRDaemonDataQueue m_dataQueue;
SDRDaemonChannelSinkThread *m_sinkThread;
CM256 m_cm256;
CM256 *m_cm256p;
int m_txBlockIndex; //!< Current index in blocks to transmit in the Tx row
uint16_t m_frameCount; //!< transmission frame count
int m_sampleIndex; //!< Current sample index in protected block data
SDRDaemonSuperBlock m_superBlock;
SDRDaemonMetaDataFEC m_currentMetaFEC;
SDRDaemonDataBlock *m_dataBlock;
QMutex m_dataBlockMutex;
uint64_t m_centerFrequency;
uint32_t m_sampleRate;
uint8_t m_sampleBytes;
int m_nbBlocksFEC;
int m_txDelay;
QString m_dataAddress;
uint16_t m_dataPort;
void applySettings(const SDRDaemonChannelSinkSettings& settings, bool force = false);
void webapiFormatChannelSettings(SWGSDRangel::SWGChannelSettings& response, const SDRDaemonChannelSinkSettings& settings);
};
#endif /* SDRDAEMON_CHANNEL_SDRDAEMONCHANNELSINK_H_ */

View File

@ -1,96 +0,0 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2018 Edouard Griffiths, F4EXB. //
// //
// SDRdaemon sink channel (Rx) main settings //
// //
// 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 <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#include "util/simpleserializer.h"
#include "settings/serializable.h"
#include "channel/sdrdaemonchannelsinksettings.h"
SDRDaemonChannelSinkSettings::SDRDaemonChannelSinkSettings()
{
resetToDefaults();
}
void SDRDaemonChannelSinkSettings::resetToDefaults()
{
m_nbFECBlocks = 0;
m_txDelay = 100;
m_dataAddress = "127.0.0.1";
m_dataPort = 9090;
}
QByteArray SDRDaemonChannelSinkSettings::serialize() const
{
SimpleSerializer s(1);
s.writeU32(1, m_nbFECBlocks);
s.writeU32(2, m_txDelay);
s.writeString(3, m_dataAddress);
s.writeU32(4, m_dataPort);
return s.final();
}
bool SDRDaemonChannelSinkSettings::deserialize(const QByteArray& data)
{
SimpleDeserializer d(data);
if(!d.isValid())
{
resetToDefaults();
return false;
}
if(d.getVersion() == 1)
{
uint32_t tmp;
QString strtmp;
d.readU32(1, &tmp, 0);
if (tmp < 128) {
m_nbFECBlocks = tmp;
} else {
m_nbFECBlocks = 0;
}
d.readU32(2, &m_txDelay, 100);
d.readString(3, &m_dataAddress, "127.0.0.1");
d.readU32(4, &tmp, 0);
if ((tmp > 1023) && (tmp < 65535)) {
m_dataPort = tmp;
} else {
m_dataPort = 9090;
}
return true;
}
else
{
resetToDefaults();
return false;
}
}

View File

@ -1,43 +0,0 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2018 Edouard Griffiths, F4EXB. //
// //
// SDRdaemon sink channel (Rx) main settings //
// //
// 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 <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#ifndef SDRDAEMON_CHANNEL_SDRDAEMONCHANNELSINKSETTINGS_H_
#define SDRDAEMON_CHANNEL_SDRDAEMONCHANNELSINKSETTINGS_H_
#include <QByteArray>
class Serializable;
struct SDRDaemonChannelSinkSettings
{
uint16_t m_nbFECBlocks;
uint32_t m_txDelay;
QString m_dataAddress;
uint16_t m_dataPort;
SDRDaemonChannelSinkSettings();
void resetToDefaults();
QByteArray serialize() const;
bool deserialize(const QByteArray& data);
};
#endif /* SDRDAEMON_CHANNEL_SDRDAEMONCHANNELSINKSETTINGS_H_ */

View File

@ -1,198 +0,0 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2018 Edouard Griffiths, F4EXB. //
// //
// SDRdaemon sink channel (Rx) UDP sender thread //
// //
// 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 <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#include <QUdpSocket>
#include "channel/sdrdaemondataqueue.h"
#include "channel/sdrdaemondatablock.h"
#include "channel/sdrdaemonchannelsinkthread.h"
#include "cm256.h"
MESSAGE_CLASS_DEFINITION(SDRDaemonChannelSinkThread::MsgStartStop, Message)
SDRDaemonChannelSinkThread::SDRDaemonChannelSinkThread(SDRDaemonDataQueue *dataQueue, CM256 *cm256, QObject* parent) :
QThread(parent),
m_running(false),
m_dataQueue(dataQueue),
m_cm256(cm256),
m_address(QHostAddress::LocalHost),
m_socket(0)
{
connect(&m_inputMessageQueue, SIGNAL(messageEnqueued()), this, SLOT(handleInputMessages()), Qt::QueuedConnection);
connect(m_dataQueue, SIGNAL(dataBlockEnqueued()), this, SLOT(handleData()), Qt::QueuedConnection);
}
SDRDaemonChannelSinkThread::~SDRDaemonChannelSinkThread()
{
qDebug("SDRDaemonChannelSinkThread::~SDRDaemonChannelSinkThread");
}
void SDRDaemonChannelSinkThread::startStop(bool start)
{
MsgStartStop *msg = MsgStartStop::create(start);
m_inputMessageQueue.push(msg);
}
void SDRDaemonChannelSinkThread::startWork()
{
qDebug("SDRDaemonChannelSinkThread::startWork");
m_startWaitMutex.lock();
m_socket = new QUdpSocket(this);
start();
while(!m_running)
m_startWaiter.wait(&m_startWaitMutex, 100);
m_startWaitMutex.unlock();
}
void SDRDaemonChannelSinkThread::stopWork()
{
qDebug("SDRDaemonChannelSinkThread::stopWork");
delete m_socket;
m_socket = 0;
m_running = false;
wait();
}
void SDRDaemonChannelSinkThread::run()
{
qDebug("SDRDaemonChannelSinkThread::run: begin");
m_running = true;
m_startWaiter.wakeAll();
while (m_running)
{
sleep(1); // Do nothing as everything is in the data handler (dequeuer)
}
m_running = false;
qDebug("SDRDaemonChannelSinkThread::run: end");
}
bool SDRDaemonChannelSinkThread::handleDataBlock(SDRDaemonDataBlock& dataBlock)
{
CM256::cm256_encoder_params cm256Params; //!< Main interface with CM256 encoder
CM256::cm256_block descriptorBlocks[256]; //!< Pointers to data for CM256 encoder
SDRDaemonProtectedBlock fecBlocks[256]; //!< FEC data
uint16_t frameIndex = dataBlock.m_txControlBlock.m_frameIndex;
int nbBlocksFEC = dataBlock.m_txControlBlock.m_nbBlocksFEC;
int txDelay = dataBlock.m_txControlBlock.m_txDelay;
m_address.setAddress(dataBlock.m_txControlBlock.m_dataAddress);
uint16_t dataPort = dataBlock.m_txControlBlock.m_dataPort;
SDRDaemonSuperBlock *txBlockx = dataBlock.m_superBlocks;
if ((nbBlocksFEC == 0) || !m_cm256) // Do not FEC encode
{
if (m_socket)
{
for (int i = 0; i < SDRDaemonNbOrginalBlocks; i++)
{
// send block via UDP
m_socket->writeDatagram((const char*)&txBlockx[i], (qint64 ) SDRDaemonUdpSize, m_address, dataPort);
usleep(txDelay);
}
}
}
else
{
cm256Params.BlockBytes = sizeof(SDRDaemonProtectedBlock);
cm256Params.OriginalCount = SDRDaemonNbOrginalBlocks;
cm256Params.RecoveryCount = nbBlocksFEC;
// Fill pointers to data
for (int i = 0; i < cm256Params.OriginalCount + cm256Params.RecoveryCount; ++i)
{
if (i >= cm256Params.OriginalCount) {
memset((void *) &txBlockx[i].m_protectedBlock, 0, sizeof(SDRDaemonProtectedBlock));
}
txBlockx[i].m_header.m_frameIndex = frameIndex;
txBlockx[i].m_header.m_blockIndex = i;
descriptorBlocks[i].Block = (void *) &(txBlockx[i].m_protectedBlock);
descriptorBlocks[i].Index = txBlockx[i].m_header.m_blockIndex;
}
// Encode FEC blocks
if (m_cm256->cm256_encode(cm256Params, descriptorBlocks, fecBlocks))
{
qWarning("SDRDaemonChannelSinkThread::handleDataBlock: CM256 encode failed. No transmission.");
// TODO: send without FEC changing meta data to set indication of no FEC
return true;
}
// Merge FEC with data to transmit
for (int i = 0; i < cm256Params.RecoveryCount; i++)
{
txBlockx[i + cm256Params.OriginalCount].m_protectedBlock = fecBlocks[i];
}
// Transmit all blocks
if (m_socket)
{
for (int i = 0; i < cm256Params.OriginalCount + cm256Params.RecoveryCount; i++)
{
// send block via UDP
m_socket->writeDatagram((const char*)&txBlockx[i], (qint64 ) SDRDaemonUdpSize, m_address, dataPort);
usleep(txDelay);
}
}
}
dataBlock.m_txControlBlock.m_processed = true;
return true;
}
void SDRDaemonChannelSinkThread::handleData()
{
SDRDaemonDataBlock* dataBlock;
while (m_running && ((dataBlock = m_dataQueue->pop()) != 0))
{
if (handleDataBlock(*dataBlock))
{
delete dataBlock;
}
}
}
void SDRDaemonChannelSinkThread::handleInputMessages()
{
Message* message;
while ((message = m_inputMessageQueue.pop()) != 0)
{
if (MsgStartStop::match(*message))
{
MsgStartStop* notif = (MsgStartStop*) message;
qDebug("SDRDaemonChannelSinkThread::handleInputMessages: MsgStartStop: %s", notif->getStartStop() ? "start" : "stop");
if (notif->getStartStop()) {
startWork();
} else {
stopWork();
}
delete message;
}
}
}

View File

@ -1,86 +0,0 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2018 Edouard Griffiths, F4EXB. //
// //
// SDRdaemon sink channel (Rx) UDP sender thread //
// //
// 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 <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#include <QThread>
#include <QMutex>
#include <QWaitCondition>
#include <QHostAddress>
#include "util/message.h"
#include "util/messagequeue.h"
class SDRDaemonDataQueue;
class SDRDaemonDataBlock;
class CM256;
class QUdpSocket;
class SDRDaemonChannelSinkThread : public QThread {
Q_OBJECT
public:
class MsgStartStop : public Message {
MESSAGE_CLASS_DECLARATION
public:
bool getStartStop() const { return m_startStop; }
static MsgStartStop* create(bool startStop) {
return new MsgStartStop(startStop);
}
protected:
bool m_startStop;
MsgStartStop(bool startStop) :
Message(),
m_startStop(startStop)
{ }
};
SDRDaemonChannelSinkThread(SDRDaemonDataQueue *dataQueue, CM256 *cm256, QObject* parent = 0);
~SDRDaemonChannelSinkThread();
void startStop(bool start);
private:
QMutex m_startWaitMutex;
QWaitCondition m_startWaiter;
bool m_running;
SDRDaemonDataQueue *m_dataQueue;
CM256 *m_cm256; //!< CM256 library object
QHostAddress m_address;
QUdpSocket *m_socket;
MessageQueue m_inputMessageQueue;
void startWork();
void stopWork();
void run();
bool handleDataBlock(SDRDaemonDataBlock& dataBlock);
private slots:
void handleData();
void handleInputMessages();
};

View File

@ -1,414 +0,0 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2018 Edouard Griffiths, F4EXB. //
// //
// SDRdaemon source channel (Tx) //
// //
// 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 <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#include <sys/time.h>
#include <unistd.h>
#include <boost/crc.hpp>
#include <boost/cstdint.hpp>
#include <QDebug>
#include "SWGChannelSettings.h"
#include "SWGChannelReport.h"
#include "SWGSDRDaemonChannelSourceReport.h"
#include "util/simpleserializer.h"
#include "dsp/threadedbasebandsamplesource.h"
#include "dsp/upchannelizer.h"
#include "dsp/devicesamplesink.h"
#include "device/devicesinkapi.h"
#include "sdrdaemonchannelsource.h"
#include "channel/sdrdaemonchannelsourcethread.h"
#include "channel/sdrdaemondatablock.h"
MESSAGE_CLASS_DEFINITION(SDRDaemonChannelSource::MsgConfigureSDRDaemonChannelSource, Message)
const QString SDRDaemonChannelSource::m_channelIdURI = "sdrangel.channel.sdrdaemonsource";
const QString SDRDaemonChannelSource::m_channelId = "SDRDaemonChannelSource";
SDRDaemonChannelSource::SDRDaemonChannelSource(DeviceSinkAPI *deviceAPI) :
ChannelSourceAPI(m_channelIdURI),
m_deviceAPI(deviceAPI),
m_sourceThread(0),
m_running(false),
m_dataReadQueue(SDR_TX_SAMP_SZ <= 16 ? 4 : 8),
m_nbCorrectableErrors(0),
m_nbUncorrectableErrors(0)
{
setObjectName(m_channelId);
m_channelizer = new UpChannelizer(this);
m_threadedChannelizer = new ThreadedBasebandSampleSource(m_channelizer, this);
m_deviceAPI->addThreadedSource(m_threadedChannelizer);
m_deviceAPI->addChannelAPI(this);
connect(&m_dataQueue, SIGNAL(dataBlockEnqueued()), this, SLOT(handleData()), Qt::QueuedConnection);
m_cm256p = m_cm256.isInitialized() ? &m_cm256 : 0;
m_currentMeta.init();
}
SDRDaemonChannelSource::~SDRDaemonChannelSource()
{
m_deviceAPI->removeChannelAPI(this);
m_deviceAPI->removeThreadedSource(m_threadedChannelizer);
delete m_threadedChannelizer;
delete m_channelizer;
}
void SDRDaemonChannelSource::pull(Sample& sample)
{
m_dataReadQueue.readSample(sample);
}
void SDRDaemonChannelSource::start()
{
qDebug("SDRDaemonChannelSink::start");
if (m_running) {
stop();
}
m_sourceThread = new SDRDaemonChannelSourceThread(&m_dataQueue);
m_sourceThread->startStop(true);
m_sourceThread->dataBind(m_settings.m_dataAddress, m_settings.m_dataPort);
m_running = true;
}
void SDRDaemonChannelSource::stop()
{
qDebug("SDRDaemonChannelSink::stop");
if (m_sourceThread != 0)
{
m_sourceThread->startStop(false);
m_sourceThread->deleteLater();
m_sourceThread = 0;
}
m_running = false;
}
void SDRDaemonChannelSource::setDataLink(const QString& dataAddress, uint16_t dataPort)
{
SDRDaemonChannelSourceSettings settings = m_settings;
settings.m_dataAddress = dataAddress;
settings.m_dataPort = dataPort;
MsgConfigureSDRDaemonChannelSource *msg = MsgConfigureSDRDaemonChannelSource::create(settings, false);
m_inputMessageQueue.push(msg);
}
bool SDRDaemonChannelSource::handleMessage(const Message& cmd __attribute__((unused)))
{
if (UpChannelizer::MsgChannelizerNotification::match(cmd))
{
UpChannelizer::MsgChannelizerNotification& notif = (UpChannelizer::MsgChannelizerNotification&) cmd;
qDebug() << "SDRDaemonChannelSource::handleMessage: UpChannelizer::MsgChannelizerNotification:"
<< " basebandSampleRate: " << notif.getBasebandSampleRate()
<< " outputSampleRate: " << notif.getSampleRate()
<< " inputFrequencyOffset: " << notif.getFrequencyOffset();
//applyChannelSettings(notif.getBasebandSampleRate(), notif.getSampleRate(), notif.getFrequencyOffset());
return true;
}
else if (MsgConfigureSDRDaemonChannelSource::match(cmd))
{
MsgConfigureSDRDaemonChannelSource& cfg = (MsgConfigureSDRDaemonChannelSource&) cmd;
qDebug() << "SDRDaemonChannelSource::handleMessage: MsgConfigureSDRDaemonChannelSource";
applySettings(cfg.getSettings(), cfg.getForce());
return true;
}
else
{
return false;
}
}
QByteArray SDRDaemonChannelSource::serialize() const
{
return m_settings.serialize();
}
bool SDRDaemonChannelSource::deserialize(const QByteArray& data __attribute__((unused)))
{
if (m_settings.deserialize(data))
{
MsgConfigureSDRDaemonChannelSource *msg = MsgConfigureSDRDaemonChannelSource::create(m_settings, true);
m_inputMessageQueue.push(msg);
return true;
}
else
{
m_settings.resetToDefaults();
MsgConfigureSDRDaemonChannelSource *msg = MsgConfigureSDRDaemonChannelSource::create(m_settings, true);
m_inputMessageQueue.push(msg);
return false;
}
}
void SDRDaemonChannelSource::applySettings(const SDRDaemonChannelSourceSettings& settings, bool force)
{
qDebug() << "SDRDaemonChannelSource::applySettings:"
<< " m_dataAddress: " << settings.m_dataAddress
<< " m_dataPort: " << settings.m_dataPort
<< " force: " << force;
bool change = false;
if ((m_settings.m_dataAddress != settings.m_dataAddress) || force) {
change = true;
}
if ((m_settings.m_dataPort != settings.m_dataPort) || force) {
change = true;
}
if (change && m_sourceThread) {
m_sourceThread->dataBind(settings.m_dataAddress, settings.m_dataPort);
}
m_settings = settings;
}
void SDRDaemonChannelSource::handleDataBlock(SDRDaemonDataBlock* dataBlock)
{
if (dataBlock->m_rxControlBlock.m_blockCount < SDRDaemonNbOrginalBlocks)
{
qWarning("SDRDaemonChannelSource::handleDataBlock: incomplete data block: not processing");
}
else
{
int blockCount = 0;
for (int blockIndex = 0; blockIndex < 256; blockIndex++)
{
if ((blockIndex == 0) && (dataBlock->m_rxControlBlock.m_metaRetrieved))
{
m_cm256DescriptorBlocks[blockCount].Index = 0;
m_cm256DescriptorBlocks[blockCount].Block = (void *) &(dataBlock->m_superBlocks[0].m_protectedBlock);
blockCount++;
}
else if (dataBlock->m_superBlocks[blockIndex].m_header.m_blockIndex != 0)
{
m_cm256DescriptorBlocks[blockCount].Index = dataBlock->m_superBlocks[blockIndex].m_header.m_blockIndex;
m_cm256DescriptorBlocks[blockCount].Block = (void *) &(dataBlock->m_superBlocks[blockIndex].m_protectedBlock);
blockCount++;
}
}
//qDebug("SDRDaemonChannelSource::handleDataBlock: frame: %u blocks: %d", dataBlock.m_rxControlBlock.m_frameIndex, blockCount);
// Need to use the CM256 recovery
if (m_cm256p &&(dataBlock->m_rxControlBlock.m_originalCount < SDRDaemonNbOrginalBlocks))
{
qDebug("SDRDaemonChannelSource::handleDataBlock: %d recovery blocks", dataBlock->m_rxControlBlock.m_recoveryCount);
CM256::cm256_encoder_params paramsCM256;
paramsCM256.BlockBytes = sizeof(SDRDaemonProtectedBlock); // never changes
paramsCM256.OriginalCount = SDRDaemonNbOrginalBlocks; // never changes
if (m_currentMeta.m_tv_sec == 0) {
paramsCM256.RecoveryCount = dataBlock->m_rxControlBlock.m_recoveryCount;
} else {
paramsCM256.RecoveryCount = m_currentMeta.m_nbFECBlocks;
}
// update counters
if (dataBlock->m_rxControlBlock.m_originalCount < SDRDaemonNbOrginalBlocks - paramsCM256.RecoveryCount) {
m_nbUncorrectableErrors += SDRDaemonNbOrginalBlocks - paramsCM256.RecoveryCount - dataBlock->m_rxControlBlock.m_originalCount;
} else {
m_nbCorrectableErrors += dataBlock->m_rxControlBlock.m_recoveryCount;
}
if (m_cm256.cm256_decode(paramsCM256, m_cm256DescriptorBlocks)) // CM256 decode
{
qWarning() << "SDRDaemonChannelSource::handleDataBlock: decode CM256 error:"
<< " m_originalCount: " << dataBlock->m_rxControlBlock.m_originalCount
<< " m_recoveryCount: " << dataBlock->m_rxControlBlock.m_recoveryCount;
}
else
{
for (int ir = 0; ir < dataBlock->m_rxControlBlock.m_recoveryCount; ir++) // restore missing blocks
{
int recoveryIndex = SDRDaemonNbOrginalBlocks - dataBlock->m_rxControlBlock.m_recoveryCount + ir;
int blockIndex = m_cm256DescriptorBlocks[recoveryIndex].Index;
SDRDaemonProtectedBlock *recoveredBlock =
(SDRDaemonProtectedBlock *) m_cm256DescriptorBlocks[recoveryIndex].Block;
memcpy((void *) &(dataBlock->m_superBlocks[blockIndex].m_protectedBlock), recoveredBlock, sizeof(SDRDaemonProtectedBlock));
if ((blockIndex == 0) && !dataBlock->m_rxControlBlock.m_metaRetrieved) {
dataBlock->m_rxControlBlock.m_metaRetrieved = true;
}
}
}
}
// Validate block zero and retrieve its data
if (dataBlock->m_rxControlBlock.m_metaRetrieved)
{
SDRDaemonMetaDataFEC *metaData = (SDRDaemonMetaDataFEC *) &(dataBlock->m_superBlocks[0].m_protectedBlock);
boost::crc_32_type crc32;
crc32.process_bytes(metaData, 20);
if (crc32.checksum() == metaData->m_crc32)
{
if (!(m_currentMeta == *metaData))
{
printMeta("SDRDaemonChannelSource::handleDataBlock", metaData);
if (m_currentMeta.m_centerFrequency != metaData->m_centerFrequency) {
m_deviceAPI->getSampleSink()->setCenterFrequency(metaData->m_centerFrequency*1000); // frequency is in kHz
}
if (m_currentMeta.m_sampleRate != metaData->m_sampleRate)
{
m_channelizer->configure(m_channelizer->getInputMessageQueue(), metaData->m_sampleRate, 0);
m_dataReadQueue.setSize(calculateDataReadQueueSize(metaData->m_sampleRate));
}
}
m_currentMeta = *metaData;
}
else
{
qWarning() << "SDRDaemonChannelSource::handleDataBlock: recovered meta: invalid CRC32";
}
}
m_dataReadQueue.push(dataBlock); // Push into R/W buffer
}
}
void SDRDaemonChannelSource::handleData()
{
SDRDaemonDataBlock* dataBlock;
while (m_running && ((dataBlock = m_dataQueue.pop()) != 0)) {
handleDataBlock(dataBlock);
}
}
void SDRDaemonChannelSource::printMeta(const QString& header, SDRDaemonMetaDataFEC *metaData)
{
qDebug().noquote() << header << ": "
<< "|" << metaData->m_centerFrequency
<< ":" << metaData->m_sampleRate
<< ":" << (int) (metaData->m_sampleBytes & 0xF)
<< ":" << (int) metaData->m_sampleBits
<< ":" << (int) metaData->m_nbOriginalBlocks
<< ":" << (int) metaData->m_nbFECBlocks
<< "|" << metaData->m_tv_sec
<< ":" << metaData->m_tv_usec
<< "|";
}
uint32_t SDRDaemonChannelSource::calculateDataReadQueueSize(int sampleRate)
{
// scale for 20 blocks at 48 kS/s. Take next even number.
uint32_t maxSize = sampleRate / 2400;
maxSize = (maxSize % 2 == 0) ? maxSize : maxSize + 1;
qDebug("SDRDaemonChannelSource::calculateDataReadQueueSize: set max queue size to %u blocks", maxSize);
return maxSize;
}
int SDRDaemonChannelSource::webapiSettingsGet(
SWGSDRangel::SWGChannelSettings& response,
QString& errorMessage __attribute__((unused)))
{
response.setDaemonSourceSettings(new SWGSDRangel::SWGDaemonSourceSettings());
response.getDaemonSourceSettings()->init();
webapiFormatChannelSettings(response, m_settings);
return 200;
}
int SDRDaemonChannelSource::webapiSettingsPutPatch(
bool force,
const QStringList& channelSettingsKeys,
SWGSDRangel::SWGChannelSettings& response,
QString& errorMessage __attribute__((unused)))
{
SDRDaemonChannelSourceSettings settings = m_settings;
if (channelSettingsKeys.contains("dataAddress")) {
settings.m_dataAddress = *response.getDaemonSourceSettings()->getDataAddress();
}
if (channelSettingsKeys.contains("dataPort"))
{
int dataPort = response.getDaemonSourceSettings()->getDataPort();
if ((dataPort < 1024) || (dataPort > 65535)) {
settings.m_dataPort = 9090;
} else {
settings.m_dataPort = dataPort;
}
}
MsgConfigureSDRDaemonChannelSource *msg = MsgConfigureSDRDaemonChannelSource::create(settings, force);
m_inputMessageQueue.push(msg);
qDebug("SDRDaemonChannelSource::webapiSettingsPutPatch: forward to GUI: %p", m_guiMessageQueue);
if (m_guiMessageQueue) // forward to GUI if any
{
MsgConfigureSDRDaemonChannelSource *msgToGUI = MsgConfigureSDRDaemonChannelSource::create(settings, force);
m_guiMessageQueue->push(msgToGUI);
}
webapiFormatChannelSettings(response, settings);
return 200;
}
int SDRDaemonChannelSource::webapiReportGet(
SWGSDRangel::SWGChannelReport& response,
QString& errorMessage __attribute__((unused)))
{
response.setDaemonSourceReport(new SWGSDRangel::SWGDaemonSourceReport());
response.getDaemonSourceReport()->init();
webapiFormatChannelReport(response);
return 200;
}
void SDRDaemonChannelSource::webapiFormatChannelSettings(SWGSDRangel::SWGChannelSettings& response, const SDRDaemonChannelSourceSettings& settings)
{
if (response.getDaemonSourceSettings()->getDataAddress()) {
*response.getDaemonSourceSettings()->getDataAddress() = settings.m_dataAddress;
} else {
response.getDaemonSourceSettings()->setDataAddress(new QString(settings.m_dataAddress));
}
response.getDaemonSourceSettings()->setDataPort(settings.m_dataPort);
}
void SDRDaemonChannelSource::webapiFormatChannelReport(SWGSDRangel::SWGChannelReport& response)
{
struct timeval tv;
gettimeofday(&tv, 0);
response.getDaemonSourceReport()->setTvSec(tv.tv_sec);
response.getDaemonSourceReport()->setTvUSec(tv.tv_usec);
response.getDaemonSourceReport()->setQueueSize(m_dataReadQueue.size());
response.getDaemonSourceReport()->setQueueLength(m_dataReadQueue.length());
response.getDaemonSourceReport()->setSamplesCount(m_dataReadQueue.readSampleCount());
response.getDaemonSourceReport()->setCorrectableErrorsCount(m_nbCorrectableErrors);
response.getDaemonSourceReport()->setUncorrectableErrorsCount(m_nbUncorrectableErrors);
}

View File

@ -1,134 +0,0 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2018 Edouard Griffiths, F4EXB. //
// //
// SDRdaemon source channel (Tx) //
// //
// 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 <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#ifndef SDRDAEMON_CHANNEL_SDRDAEMONCHANNELSOURCE_H_
#define SDRDAEMON_CHANNEL_SDRDAEMONCHANNELSOURCE_H_
#include "cm256.h"
#include "dsp/basebandsamplesource.h"
#include "channel/channelsourceapi.h"
#include "channel/sdrdaemonchannelsourcesettings.h"
#include "channel/sdrdaemondataqueue.h"
#include "channel/sdrdaemondatablock.h"
#include "channel/sdrdaemondatareadqueue.h"
class ThreadedBasebandSampleSource;
class UpChannelizer;
class DeviceSinkAPI;
class SDRDaemonChannelSourceThread;
class SDRDaemonDataBlock;
class SDRDaemonChannelSource : public BasebandSampleSource, public ChannelSourceAPI {
Q_OBJECT
public:
class MsgConfigureSDRDaemonChannelSource : public Message {
MESSAGE_CLASS_DECLARATION
public:
const SDRDaemonChannelSourceSettings& getSettings() const { return m_settings; }
bool getForce() const { return m_force; }
static MsgConfigureSDRDaemonChannelSource* create(const SDRDaemonChannelSourceSettings& settings, bool force)
{
return new MsgConfigureSDRDaemonChannelSource(settings, force);
}
private:
SDRDaemonChannelSourceSettings m_settings;
bool m_force;
MsgConfigureSDRDaemonChannelSource(const SDRDaemonChannelSourceSettings& settings, bool force) :
Message(),
m_settings(settings),
m_force(force)
{ }
};
SDRDaemonChannelSource(DeviceSinkAPI *deviceAPI);
~SDRDaemonChannelSource();
virtual void destroy() { delete this; }
virtual void pull(Sample& sample);
virtual void start();
virtual void stop();
virtual bool handleMessage(const Message& cmd);
virtual void getIdentifier(QString& id) { id = objectName(); }
virtual void getTitle(QString& title) { title = "SDRDaemon Source"; }
virtual qint64 getCenterFrequency() const { return 0; }
virtual QByteArray serialize() const;
virtual bool deserialize(const QByteArray& data);
virtual int webapiSettingsGet(
SWGSDRangel::SWGChannelSettings& response,
QString& errorMessage);
virtual int webapiSettingsPutPatch(
bool force,
const QStringList& channelSettingsKeys,
SWGSDRangel::SWGChannelSettings& response,
QString& errorMessage);
virtual int webapiReportGet(
SWGSDRangel::SWGChannelReport& response,
QString& errorMessage);
void setDataLink(const QString& dataAddress, uint16_t dataPort);
static const QString m_channelIdURI;
static const QString m_channelId;
private:
DeviceSinkAPI *m_deviceAPI;
ThreadedBasebandSampleSource* m_threadedChannelizer;
UpChannelizer* m_channelizer;
SDRDaemonDataQueue m_dataQueue;
SDRDaemonChannelSourceThread *m_sourceThread;
CM256 m_cm256;
CM256 *m_cm256p;
bool m_running;
SDRDaemonChannelSourceSettings m_settings;
CM256::cm256_block m_cm256DescriptorBlocks[2*SDRDaemonNbOrginalBlocks]; //!< CM256 decoder descriptors (block addresses and block indexes)
SDRDaemonMetaDataFEC m_currentMeta;
SDRDaemonDataReadQueue m_dataReadQueue;
uint32_t m_nbCorrectableErrors; //!< count of correctable errors in number of blocks
uint32_t m_nbUncorrectableErrors; //!< count of uncorrectable errors in number of blocks
void applySettings(const SDRDaemonChannelSourceSettings& settings, bool force = false);
void handleDataBlock(SDRDaemonDataBlock *dataBlock);
void printMeta(const QString& header, SDRDaemonMetaDataFEC *metaData);
uint32_t calculateDataReadQueueSize(int sampleRate);
void webapiFormatChannelSettings(SWGSDRangel::SWGChannelSettings& response, const SDRDaemonChannelSourceSettings& settings);
void webapiFormatChannelReport(SWGSDRangel::SWGChannelReport& response);
private slots:
void handleData();
};
#endif /* SDRDAEMON_CHANNEL_SDRDAEMONCHANNELSOURCE_H_ */

View File

@ -1,85 +0,0 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2018 Edouard Griffiths, F4EXB. //
// //
// SDRdaemon sink channel (Rx) main settings //
// //
// 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 <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#include "util/simpleserializer.h"
#include "settings/serializable.h"
#include "channel/sdrdaemonchannelsourcesettings.h"
SDRDaemonChannelSourceSettings::SDRDaemonChannelSourceSettings()
{
resetToDefaults();
}
void SDRDaemonChannelSourceSettings::resetToDefaults()
{
m_dataAddress = "127.0.0.1";
m_dataPort = 9090;
}
QByteArray SDRDaemonChannelSourceSettings::serialize() const
{
SimpleSerializer s(1);
s.writeString(1, m_dataAddress);
s.writeU32(2, m_dataPort);
return s.final();
}
bool SDRDaemonChannelSourceSettings::deserialize(const QByteArray& data)
{
SimpleDeserializer d(data);
if(!d.isValid())
{
resetToDefaults();
return false;
}
if(d.getVersion() == 1)
{
uint32_t tmp;
QString strtmp;
d.readString(1, &m_dataAddress, "127.0.0.1");
d.readU32(2, &tmp, 0);
if ((tmp > 1023) && (tmp < 65535)) {
m_dataPort = tmp;
} else {
m_dataPort = 9090;
}
return true;
}
else
{
resetToDefaults();
return false;
}
}

View File

@ -1,43 +0,0 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2018 Edouard Griffiths, F4EXB. //
// //
// SDRdaemon source channel (Tx) main settings //
// //
// 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 <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#ifndef SDRDAEMON_CHANNEL_SDRDAEMONCHANNELSOURCESETTINGS_H_
#define SDRDAEMON_CHANNEL_SDRDAEMONCHANNELSOURCESETTINGS_H_
#include <QByteArray>
class Serializable;
struct SDRDaemonChannelSourceSettings
{
QString m_dataAddress; //!< Listening (local) data address
uint16_t m_dataPort; //!< Listening data port
SDRDaemonChannelSourceSettings();
void resetToDefaults();
QByteArray serialize() const;
bool deserialize(const QByteArray& data);
};
#endif /* SDRDAEMON_CHANNEL_SDRDAEMONCHANNELSOURCESETTINGS_H_ */

View File

@ -1,193 +0,0 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2018 Edouard Griffiths, F4EXB. //
// //
// SDRdaemon source channel (Tx) UDP receiver thread //
// //
// 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 <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#include <algorithm>
#include <QUdpSocket>
#include "channel/sdrdaemondataqueue.h"
#include "channel/sdrdaemondatablock.h"
#include "channel/sdrdaemonchannelsourcethread.h"
#include "cm256.h"
MESSAGE_CLASS_DEFINITION(SDRDaemonChannelSourceThread::MsgStartStop, Message)
MESSAGE_CLASS_DEFINITION(SDRDaemonChannelSourceThread::MsgDataBind, Message)
SDRDaemonChannelSourceThread::SDRDaemonChannelSourceThread(SDRDaemonDataQueue *dataQueue, QObject* parent) :
QThread(parent),
m_running(false),
m_dataQueue(dataQueue),
m_address(QHostAddress::LocalHost),
m_socket(0)
{
std::fill(m_dataBlocks, m_dataBlocks+4, (SDRDaemonDataBlock *) 0);
connect(&m_inputMessageQueue, SIGNAL(messageEnqueued()), this, SLOT(handleInputMessages()), Qt::QueuedConnection);
}
SDRDaemonChannelSourceThread::~SDRDaemonChannelSourceThread()
{
qDebug("SDRDaemonChannelSourceThread::~SDRDaemonChannelSourceThread");
}
void SDRDaemonChannelSourceThread::startStop(bool start)
{
MsgStartStop *msg = MsgStartStop::create(start);
m_inputMessageQueue.push(msg);
}
void SDRDaemonChannelSourceThread::dataBind(const QString& address, uint16_t port)
{
MsgDataBind *msg = MsgDataBind::create(address, port);
m_inputMessageQueue.push(msg);
}
void SDRDaemonChannelSourceThread::startWork()
{
qDebug("SDRDaemonChannelSourceThread::startWork");
m_startWaitMutex.lock();
m_socket = new QUdpSocket(this);
start();
while(!m_running)
m_startWaiter.wait(&m_startWaitMutex, 100);
m_startWaitMutex.unlock();
}
void SDRDaemonChannelSourceThread::stopWork()
{
qDebug("SDRDaemonChannelSourceThread::stopWork");
delete m_socket;
m_socket = 0;
m_running = false;
wait();
}
void SDRDaemonChannelSourceThread::run()
{
qDebug("SDRDaemonChannelSourceThread::run: begin");
m_running = true;
m_startWaiter.wakeAll();
while (m_running)
{
sleep(1); // Do nothing as everything is in the data handler (dequeuer)
}
m_running = false;
qDebug("SDRDaemonChannelSourceThread::run: end");
}
void SDRDaemonChannelSourceThread::handleInputMessages()
{
Message* message;
while ((message = m_inputMessageQueue.pop()) != 0)
{
if (MsgStartStop::match(*message))
{
MsgStartStop* notif = (MsgStartStop*) message;
qDebug("SDRDaemonChannelSourceThread::handleInputMessages: MsgStartStop: %s", notif->getStartStop() ? "start" : "stop");
if (notif->getStartStop()) {
startWork();
} else {
stopWork();
}
delete message;
}
else if (MsgDataBind::match(*message))
{
MsgDataBind* notif = (MsgDataBind*) message;
qDebug("SDRDaemonChannelSourceThread::handleInputMessages: MsgDataBind: %s:%d", qPrintable(notif->getAddress().toString()), notif->getPort());
if (m_socket)
{
disconnect(m_socket, SIGNAL(readyRead()), this, SLOT(readPendingDatagrams()));
m_socket->bind(notif->getAddress(), notif->getPort());
connect(m_socket, SIGNAL(readyRead()), this, SLOT(readPendingDatagrams()));
}
}
}
}
void SDRDaemonChannelSourceThread::readPendingDatagrams()
{
SDRDaemonSuperBlock superBlock;
qint64 size;
while (m_socket->hasPendingDatagrams())
{
QHostAddress sender;
quint16 senderPort = 0;
//qint64 pendingDataSize = m_socket->pendingDatagramSize();
size = m_socket->readDatagram((char *) &superBlock, (long long int) sizeof(SDRDaemonSuperBlock), &sender, &senderPort);
if (size == sizeof(SDRDaemonSuperBlock))
{
unsigned int dataBlockIndex = superBlock.m_header.m_frameIndex % m_nbDataBlocks;
// create the first block for this index
if (m_dataBlocks[dataBlockIndex] == 0) {
m_dataBlocks[dataBlockIndex] = new SDRDaemonDataBlock();
}
if (m_dataBlocks[dataBlockIndex]->m_rxControlBlock.m_frameIndex < 0)
{
// initialize virgin block with the frame index
m_dataBlocks[dataBlockIndex]->m_rxControlBlock.m_frameIndex = superBlock.m_header.m_frameIndex;
}
else
{
// if the frame index is not the same for the same slot it means we are starting a new frame
uint32_t frameIndex = m_dataBlocks[dataBlockIndex]->m_rxControlBlock.m_frameIndex;
if (superBlock.m_header.m_frameIndex != frameIndex)
{
//qDebug("SDRDaemonChannelSourceThread::readPendingDatagrams: push frame %u", frameIndex);
m_dataQueue->push(m_dataBlocks[dataBlockIndex]);
m_dataBlocks[dataBlockIndex] = new SDRDaemonDataBlock();
m_dataBlocks[dataBlockIndex]->m_rxControlBlock.m_frameIndex = superBlock.m_header.m_frameIndex;
}
}
m_dataBlocks[dataBlockIndex]->m_superBlocks[superBlock.m_header.m_blockIndex] = superBlock;
if (superBlock.m_header.m_blockIndex == 0) {
m_dataBlocks[dataBlockIndex]->m_rxControlBlock.m_metaRetrieved = true;
}
if (superBlock.m_header.m_blockIndex < SDRDaemonNbOrginalBlocks) {
m_dataBlocks[dataBlockIndex]->m_rxControlBlock.m_originalCount++;
} else {
m_dataBlocks[dataBlockIndex]->m_rxControlBlock.m_recoveryCount++;
}
m_dataBlocks[dataBlockIndex]->m_rxControlBlock.m_blockCount++;
}
else
{
qWarning("SDRDaemonChannelSourceThread::readPendingDatagrams: wrong super block size not processing");
}
}
}

View File

@ -1,115 +0,0 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2018 Edouard Griffiths, F4EXB. //
// //
// SDRdaemon source channel (Tx) UDP receiver thread //
// //
// 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 <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#ifndef SDRDAEMON_CHANNEL_SDRDAEMONCHANNELSOURCETHREAD_H_
#define SDRDAEMON_CHANNEL_SDRDAEMONCHANNELSOURCETHREAD_H_
#include <QThread>
#include <QMutex>
#include <QWaitCondition>
#include <QHostAddress>
#include "util/message.h"
#include "util/messagequeue.h"
class SDRDaemonDataQueue;
class SDRDaemonDataBlock;
class QUdpSocket;
class SDRDaemonChannelSourceThread : public QThread {
Q_OBJECT
public:
class MsgStartStop : public Message {
MESSAGE_CLASS_DECLARATION
public:
bool getStartStop() const { return m_startStop; }
static MsgStartStop* create(bool startStop) {
return new MsgStartStop(startStop);
}
protected:
bool m_startStop;
MsgStartStop(bool startStop) :
Message(),
m_startStop(startStop)
{ }
};
class MsgDataBind : public Message {
MESSAGE_CLASS_DECLARATION
public:
QHostAddress getAddress() const { return m_address; }
uint16_t getPort() const { return m_port; }
static MsgDataBind* create(const QString& address, uint16_t port) {
return new MsgDataBind(address, port);
}
protected:
QHostAddress m_address;
uint16_t m_port;
MsgDataBind(const QString& address, uint16_t port) :
Message(),
m_port(port)
{
m_address.setAddress(address);
}
};
SDRDaemonChannelSourceThread(SDRDaemonDataQueue *dataQueue, QObject* parent = 0);
~SDRDaemonChannelSourceThread();
void startStop(bool start);
void dataBind(const QString& address, uint16_t port);
private:
QMutex m_startWaitMutex;
QWaitCondition m_startWaiter;
bool m_running;
MessageQueue m_inputMessageQueue;
SDRDaemonDataQueue *m_dataQueue;
QHostAddress m_address;
QUdpSocket *m_socket;
static const uint32_t m_nbDataBlocks = 4; //!< number of data blocks in the ring buffer
SDRDaemonDataBlock *m_dataBlocks[m_nbDataBlocks]; //!< ring buffer of data blocks indexed by frame affinity
void startWork();
void stopWork();
void run();
private slots:
void handleInputMessages();
void readPendingDatagrams();
};
#endif /* SDRDAEMON_CHANNEL_SDRDAEMONCHANNELSOURCETHREAD_H_ */

View File

@ -1,387 +0,0 @@
///////////////////////////////////////////////////////////////////////////////////
// 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 <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#include <QSysInfo>
#include <QResource>
#include <unistd.h>
#include "dsp/dspengine.h"
#include "dsp/dspdevicesourceengine.h"
#include "dsp/dspdevicesinkengine.h"
#include "device/devicesourceapi.h"
#include "device/devicesinkapi.h"
#include "device/deviceenumerator.h"
#include "plugin/pluginmanager.h"
#include "util/message.h"
#include "loggerwithfile.h"
#include "webapi/webapiadapterdaemon.h"
#include "webapi/webapirequestmapper.h"
#include "webapi/webapiserver.h"
#include "channel/sdrdaemonchannelsink.h"
#include "channel/sdrdaemonchannelsource.h"
#include "sdrdaemonparser.h"
#include "sdrdaemonmain.h"
SDRDaemonMain *SDRDaemonMain::m_instance = 0;
SDRDaemonMain::SDRDaemonMain(qtwebapp::LoggerWithFile *logger, const SDRDaemonParser& parser, QObject *parent) :
QObject(parent),
m_logger(logger),
m_settings(),
m_dspEngine(DSPEngine::instance()),
m_lastEngineState(DSPDeviceSourceEngine::StNotStarted),
m_abort(false)
{
qDebug() << "SDRDaemonMain::SDRDaemonMain: start";
m_instance = this;
m_pluginManager = new PluginManager(this);
m_pluginManager->loadPluginsPart(QString("pluginssrv/samplesink"));
m_pluginManager->loadPluginsPart(QString("pluginssrv/samplesource"));
m_pluginManager->loadPluginsFinal();
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("SDRDaemonMain::SDRDaemonMain: registered resource file %s/%s", qPrintable(applicationDirPath), "sdrbase.rcc");
} else {
qWarning("SDRDaemonMain::SDRDaemonMain: 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();
m_tx = parser.getTx();
m_deviceType = parser.getDeviceType();
m_deviceSerial = parser.hasSerial() ? parser.getSerial() : "";
m_deviceSequence = parser.hasSequence() ? parser.getSequence() : -1;
m_deviceSourceEngine = 0;
m_deviceSinkEngine = 0;
m_deviceSourceAPI = 0;
m_deviceSinkAPI = 0;
m_channelSink = 0;
m_channelSource = 0;
if (m_tx)
{
if (addSinkDevice())
{
QString msg(tr("SDRDaemonMain::SDRDaemonMain: set sink %1").arg(m_deviceType));
if (m_deviceSerial.length() > 0) {
msg += tr(" ser: %1").arg(m_deviceSerial);
} else if (m_deviceSequence >= 0) {
msg += tr(" seq: %1").arg(m_deviceSequence);
} else {
msg += " first device";
}
QDebug info = qInfo();
info.noquote();
info << msg;
m_channelSource = new SDRDaemonChannelSource(m_deviceSinkAPI);
m_channelSource->setDataLink(parser.getDataAddress(), parser.getDataPort());
}
else
{
qCritical("SDRDaemonMain::SDRDaemonMain: sink device not found aborting");
m_abort = true;
}
}
else
{
if (addSourceDevice())
{
QString msg(tr("SDRDaemonMain::SDRDaemonMain: set source %1").arg(m_deviceType));
if (m_deviceSerial.length() > 0) {
msg += tr(" ser: %1").arg(m_deviceSerial);
} else if (m_deviceSequence >= 0) {
msg += tr(" seq: %1").arg(m_deviceSequence);
} else {
msg += " first device";
}
QDebug info = qInfo();
info.noquote();
info << msg;
m_channelSink = new SDRDaemonChannelSink(m_deviceSourceAPI);
m_channelSink->setNbBlocksFEC(parser.getNbBlocksFEC());
m_channelSink->setTxDelay(parser.getTxDelay());
m_channelSink->setDataAddress(parser.getDataAddress());
m_channelSink->setDataPort(parser.getDataPort());
}
else
{
qCritical("SDRDaemonMain::SDRDaemonMain: source device not found aborting");
m_abort = true;
}
}
qDebug() << "SDRDaemonMain::SDRDaemonMain: end";
}
SDRDaemonMain::~SDRDaemonMain()
{
removeDevice();
m_apiServer->stop();
m_settings.save();
delete m_apiServer;
delete m_requestMapper;
delete m_apiAdapter;
delete m_pluginManager;
qDebug() << "SDRDaemonMain::~SDRDaemonMain: end";
delete m_logger;
}
void SDRDaemonMain::loadSettings()
{
qDebug() << "SDRDaemonMain::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::addSinkDevice()
{
int deviceIndex = getDeviceIndex();
if (deviceIndex >= 0)
{
DSPDeviceSinkEngine *dspDeviceSinkEngine = m_dspEngine->addDeviceSinkEngine();
dspDeviceSinkEngine->start();
uint dspDeviceSinkEngineUID = dspDeviceSinkEngine->getUID();
char uidCStr[16];
sprintf(uidCStr, "UID:%d", dspDeviceSinkEngineUID);
m_deviceSinkEngine = dspDeviceSinkEngine;
m_deviceSinkAPI = new DeviceSinkAPI(0, dspDeviceSinkEngine);
PluginInterface::SamplingDevice samplingDevice = DeviceEnumerator::instance()->getTxSamplingDevice(deviceIndex);
m_deviceSinkAPI->setSampleSinkSequence(samplingDevice.sequence);
m_deviceSinkAPI->setNbItems(samplingDevice.deviceNbItems);
m_deviceSinkAPI->setItemIndex(samplingDevice.deviceItemIndex);
m_deviceSinkAPI->setHardwareId(samplingDevice.hardwareId);
m_deviceSinkAPI->setSampleSinkId(samplingDevice.id);
m_deviceSinkAPI->setSampleSinkSerial(samplingDevice.serial);
m_deviceSinkAPI->setSampleSinkDisplayName(samplingDevice.displayedName);
m_deviceSinkAPI->setSampleSinkPluginInterface(DeviceEnumerator::instance()->getTxPluginInterface(deviceIndex));
DeviceSampleSink *sink = m_deviceSinkAPI->getPluginInterface()->createSampleSinkPluginInstanceOutput(
m_deviceSinkAPI->getSampleSinkId(), m_deviceSinkAPI);
m_deviceSinkAPI->setSampleSink(sink);
return true;
}
return false;
}
bool SDRDaemonMain::addSourceDevice()
{
int deviceIndex = getDeviceIndex();
if (deviceIndex >= 0)
{
DSPDeviceSourceEngine *dspDeviceSourceEngine = m_dspEngine->addDeviceSourceEngine();
dspDeviceSourceEngine->start();
uint dspDeviceSourceEngineUID = dspDeviceSourceEngine->getUID();
char uidCStr[16];
sprintf(uidCStr, "UID:%d", dspDeviceSourceEngineUID);
m_deviceSourceEngine = dspDeviceSourceEngine;
m_deviceSourceAPI = new DeviceSourceAPI(0, dspDeviceSourceEngine);
PluginInterface::SamplingDevice samplingDevice = DeviceEnumerator::instance()->getRxSamplingDevice(deviceIndex);
m_deviceSourceAPI->setSampleSourceSequence(samplingDevice.sequence);
m_deviceSourceAPI->setNbItems(samplingDevice.deviceNbItems);
m_deviceSourceAPI->setItemIndex(samplingDevice.deviceItemIndex);
m_deviceSourceAPI->setHardwareId(samplingDevice.hardwareId);
m_deviceSourceAPI->setSampleSourceId(samplingDevice.id);
m_deviceSourceAPI->setSampleSourceSerial(samplingDevice.serial);
m_deviceSourceAPI->setSampleSourceDisplayName(samplingDevice.displayedName);
m_deviceSourceAPI->setSampleSourcePluginInterface(DeviceEnumerator::instance()->getRxPluginInterface(deviceIndex));
DeviceSampleSource *source = m_deviceSourceAPI->getPluginInterface()->createSampleSourcePluginInstanceInput(
m_deviceSourceAPI->getSampleSourceId(), m_deviceSourceAPI);
m_deviceSourceAPI->setSampleSource(source);
return true;
}
return false;
}
void SDRDaemonMain::removeDevice()
{
if (m_deviceSourceEngine) // source set
{
m_deviceSourceEngine->stopAcquistion();
// deletes old UI and input object
if (m_channelSink) {
m_channelSink->destroy();
}
m_deviceSourceAPI->resetSampleSourceId();
m_deviceSourceAPI->getPluginInterface()->deleteSampleSourcePluginInstanceInput(
m_deviceSourceAPI->getSampleSource());
m_deviceSourceAPI->clearBuddiesLists(); // clear old API buddies lists
m_deviceSourceEngine->stop();
m_dspEngine->removeLastDeviceSourceEngine();
delete m_deviceSourceAPI;
m_deviceSourceAPI = 0;
}
else if (m_deviceSinkEngine) // sink set
{
m_deviceSinkEngine->stopGeneration();
// deletes old UI and output object
if (m_channelSource) {
m_channelSource->destroy();
}
m_deviceSinkAPI->resetSampleSinkId();
m_deviceSinkAPI->getPluginInterface()->deleteSampleSinkPluginInstanceOutput(
m_deviceSinkAPI->getSampleSink());
m_deviceSinkAPI->clearBuddiesLists(); // clear old API buddies lists
m_deviceSinkEngine->stop();
m_dspEngine->removeLastDeviceSinkEngine();
delete m_deviceSinkAPI;
m_deviceSinkAPI = 0;
}
}
int SDRDaemonMain::getDeviceIndex()
{
int nbSamplingDevices = m_tx ? DeviceEnumerator::instance()->getNbTxSamplingDevices() : DeviceEnumerator::instance()->getNbRxSamplingDevices();
for (int i = 0; i < nbSamplingDevices; i++)
{
PluginInterface::SamplingDevice samplingDevice = m_tx ? DeviceEnumerator::instance()->getTxSamplingDevice(i) : DeviceEnumerator::instance()->getRxSamplingDevice(i);
if (samplingDevice.hardwareId == m_deviceType)
{
if (m_deviceSerial.length() > 0)
{
if (samplingDevice.serial == m_deviceSerial) {
return i;
} else {
continue;
}
}
else if (m_deviceSequence >= 0)
{
if (samplingDevice.sequence == m_deviceSequence) {
return i;
} else {
continue;
}
}
else
{
return i;
}
}
}
return -1; // not found
}
bool SDRDaemonMain::handleMessage(const Message& cmd __attribute__((unused)))
{
return false;
}
void SDRDaemonMain::handleMessages()
{
Message* message;
while ((message = m_inputMessageQueue.pop()) != 0)
{
qDebug("SDRDaemonMain::handleMessages: message: %s", message->getIdentifier());
handleMessage(*message);
delete message;
}
}

View File

@ -1,114 +0,0 @@
///////////////////////////////////////////////////////////////////////////////////
// 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 <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#ifndef SDRDAEMON_SDRDAEMONMAIN_H_
#define SDRDAEMON_SDRDAEMONMAIN_H_
#include <QObject>
#include <QTimer>
#include "sdrdaemonsettings.h"
#include "util/messagequeue.h"
namespace SDRDaemon {
class WebAPIRequestMapper;
class WebAPIServer;
}
namespace qtwebapp {
class LoggerWithFile;
}
class SDRDaemonParser;
class DSPEngine;
class PluginManager;
class Message;
class WebAPIAdapterDaemon;
class DSPDeviceSourceEngine;
class DeviceSourceAPI;
class DSPDeviceSinkEngine;
class DeviceSinkAPI;
class SDRDaemonChannelSink;
class SDRDaemonChannelSource;
class SDRDaemonMain : public QObject {
Q_OBJECT
public:
explicit SDRDaemonMain(qtwebapp::LoggerWithFile *logger, const SDRDaemonParser& parser, QObject *parent = 0);
~SDRDaemonMain();
static SDRDaemonMain *getInstance() { return m_instance; } // Main Core is de facto a singleton so this just returns its reference
MessageQueue* getInputMessageQueue() { return &m_inputMessageQueue; }
const QTimer& getMasterTimer() const { return m_masterTimer; }
const SDRDaemonSettings& getSettings() const { return m_settings; }
bool addSourceDevice();
bool addSinkDevice();
void removeDevice();
bool doAbort() const { return m_abort; }
friend class WebAPIAdapterDaemon;
signals:
void finished();
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;
bool m_tx;
QString m_deviceType;
QString m_deviceSerial;
int m_deviceSequence;
DSPDeviceSourceEngine *m_deviceSourceEngine;
DeviceSourceAPI *m_deviceSourceAPI;
DSPDeviceSinkEngine *m_deviceSinkEngine;
DeviceSinkAPI *m_deviceSinkAPI;
SDRDaemonChannelSink *m_channelSink;
SDRDaemonChannelSource *m_channelSource;
bool m_abort;
void loadSettings();
void setLoggingOptions();
int getDeviceIndex();
bool handleMessage(const Message& cmd);
void addChannelSink();
private slots:
void handleMessages();
};
#endif /* SDRDAEMON_SDRDAEMONMAIN_H_ */

View File

@ -1,262 +0,0 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2018 Edouard Griffiths, F4EXB. //
// //
// SDRdaemon command line parser //
// //
// 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 <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#include "sdrdaemonparser.h"
#include <QCommandLineOption>
#include <QRegExpValidator>
#include <QDebug>
SDRDaemonParser::SDRDaemonParser() :
m_serverAddressOption(QStringList() << "a" << "api-address",
"API server and data (Tx) address.",
"localAddress",
"127.0.0.1"),
m_serverPortOption(QStringList() << "p" << "api-port",
"Web API server port.",
"apiPort",
"9091"),
m_dataAddressOption(QStringList() << "A" << "data-address",
"Remote data address (Rx).",
"remoteAddress",
"127.0.0.1"),
m_dataPortOption(QStringList() << "D" << "data-port",
"UDP stream data port.",
"dataPort",
"9090"),
m_deviceTypeOption(QStringList() << "T" << "device-type",
"Device type.",
"deviceType",
"TestSource"),
m_txOption(QStringList() << "t" << "tx",
"Tx indicator."),
m_serialOption(QStringList() << "s" << "serial",
"Device serial number.",
"serial"),
m_sequenceOption(QStringList() << "i" << "sequence",
"Device sequence index in enumeration for the same device type.",
"sequence"),
m_txDelayOption(QStringList() << "d" << "tx-delay",
"delay between transmission of UDP blocks (ms).",
"txDelay",
"100"),
m_nbBlocksFECOption(QStringList() << "f" << "fec-blocks",
"Number of FEC blocks per frame.",
"nbBlocksFEC",
"8")
{
m_serverAddress = "127.0.0.1";
m_serverPort = 9091;
m_dataAddress = "127.0.0.1";
m_dataPort = 9090;
m_deviceType = "TestSource";
m_tx = false;
m_sequence = 0;
m_txDelay = 100;
m_nbBlocksFEC = 8;
m_hasSequence = false;
m_hasSerial = false;
m_parser.setApplicationDescription("Software Defined Radio RF header server");
m_parser.addHelpOption();
m_parser.addVersionOption();
m_parser.addOption(m_serverAddressOption);
m_parser.addOption(m_serverPortOption);
m_parser.addOption(m_dataAddressOption);
m_parser.addOption(m_dataPortOption);
m_parser.addOption(m_deviceTypeOption);
m_parser.addOption(m_txOption);
m_parser.addOption(m_serialOption);
m_parser.addOption(m_sequenceOption);
m_parser.addOption(m_txDelayOption);
m_parser.addOption(m_nbBlocksFECOption);
}
SDRDaemonParser::~SDRDaemonParser()
{ }
void SDRDaemonParser::parse(const QCoreApplication& app)
{
m_parser.process(app);
int pos;
bool ok;
// server address
QString serverAddress = m_parser.value(m_serverAddressOption);
QString ipRange = "(?:[0-1]?[0-9]?[0-9]|2[0-4][0-9]|25[0-5])";
QRegExp ipRegex ("^" + ipRange
+ "\\." + ipRange
+ "\\." + ipRange
+ "\\." + ipRange + "$");
QRegExpValidator ipValidator(ipRegex);
if (ipValidator.validate(serverAddress, pos) == QValidator::Acceptable)
{
m_serverAddress = serverAddress;
qDebug() << "SDRDaemonParser::parse: server address: " << m_serverAddress;
}
else
{
qWarning() << "SDRDaemonParser::parse: server address invalid. Defaulting to " << m_serverAddress;
}
// server port
QString serverPortStr = m_parser.value(m_serverPortOption);
int serverPort = serverPortStr.toInt(&ok);
if (ok && (serverPort > 1023) && (serverPort < 65536))
{
m_serverPort = serverPort;
qDebug() << "SDRDaemonParser::parse: server port: " << m_serverPort;
}
else
{
qWarning() << "SDRDaemonParser::parse: server port invalid. Defaulting to " << m_serverPort;
}
// data address
QString dataAddress = m_parser.value(m_dataAddressOption);
if (ipValidator.validate(dataAddress, pos) == QValidator::Acceptable)
{
m_dataAddress = dataAddress;
qDebug() << "SDRDaemonParser::parse: data address: " << m_dataAddress;
}
else
{
qWarning() << "SDRDaemonParser::parse: data address invalid. Defaulting to " << m_dataAddress;
}
// data port
QString dataPortStr = m_parser.value(m_dataPortOption);
serverPort = dataPortStr.toInt(&ok);
if (ok && (serverPort > 1023) && (serverPort < 65536))
{
m_dataPort = serverPort;
qDebug() << "SDRDaemonParser::parse: data port: " << m_dataPort;
}
else
{
qWarning() << "SDRDaemonParser::parse: data port invalid. Defaulting to " << m_dataPort;
}
// tx
m_tx = m_parser.isSet(m_txOption);
qDebug() << "SDRDaemonParser::parse: tx: " << m_tx;
// device type
if (m_parser.isSet(m_deviceTypeOption))
{
QString deviceType = m_parser.value(m_deviceTypeOption);
QRegExp deviceTypeRegex("^[A-Z][A-Za-z0-9]+$");
QRegExpValidator deviceTypeValidator(deviceTypeRegex);
if (deviceTypeValidator.validate(deviceType, pos) == QValidator::Acceptable)
{
m_deviceType = deviceType;
qDebug() << "SDRDaemonParser::parse: device type: " << m_deviceType;
}
else
{
m_deviceType = m_tx ? "FileSink" : "TestSource";
qWarning() << "SDRDaemonParser::parse: device type invalid. Defaulting to " << m_deviceType;
}
}
else
{
m_deviceType = m_tx ? "FileSink" : "TestSource";
qInfo() << "SDRDaemonParser::parse: device type not specified. defaulting to " << m_deviceType;
}
// serial
m_hasSerial = m_parser.isSet(m_serialOption);
if (m_hasSerial)
{
m_serial = m_parser.value(m_serialOption);
qDebug() << "SDRDaemonParser::parse: serial: " << m_serial;
}
// sequence
m_hasSequence = m_parser.isSet(m_sequenceOption);
if (m_hasSequence)
{
QString sequenceStr = m_parser.value(m_sequenceOption);
int sequence = sequenceStr.toInt(&ok);
if (ok && (sequence >= 0) && (sequence < 65536)) {
m_sequence = sequence;
qDebug() << "SDRDaemonParser::parse: sequence: " << m_sequence;
} else {
qWarning() << "SDRDaemonParser::parse: sequence invalid. Defaulting to " << m_sequence;
}
}
// Tx delay
if (m_parser.isSet(m_txDelayOption))
{
QString txDelayStr = m_parser.value(m_txDelayOption);
int txDelay = txDelayStr.toInt(&ok);
if (ok && (txDelay >= 0))
{
m_txDelay = txDelay;
qDebug() << "SDRDaemonParser::parse: Tx delay: " << m_txDelay;
}
else
{
qWarning() << "SDRDaemonParser::parse: Tx delay invalid. Defaulting to " << m_txDelay;
}
}
// nb FEC blocks
if (m_parser.isSet(m_nbBlocksFECOption))
{
QString nbBlocksFECStr = m_parser.value(m_nbBlocksFECOption);
int nbBlocksFEC = nbBlocksFECStr.toInt(&ok);
if (ok && (nbBlocksFEC >= 0) && (nbBlocksFEC < 128))
{
m_nbBlocksFEC = nbBlocksFEC;
qDebug() << "SDRDaemonParser::parse: number of FEC blocks: " << m_nbBlocksFEC;
}
else
{
qWarning() << "SDRDaemonParser::parse: number of FEC blocks invalid. Defaulting to " << m_nbBlocksFEC;
}
}
}

View File

@ -1,80 +0,0 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2018 Edouard Griffiths, F4EXB. //
// //
// SDRdaemon command line parser //
// //
// 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 <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#ifndef SDRDAEMON_SDRDAEMONPARSER_H_
#define SDRDAEMON_SDRDAEMONPARSER_H_
#include <QCommandLineParser>
#include <stdint.h>
class SDRDaemonParser
{
public:
SDRDaemonParser();
~SDRDaemonParser();
void parse(const QCoreApplication& app);
const QString& getServerAddress() const { return m_serverAddress; }
uint16_t getServerPort() const { return m_serverPort; }
const QString& getDataAddress() const { return m_dataAddress; }
uint16_t getDataPort() const { return m_dataPort; }
const QString& getDeviceType() const { return m_deviceType; }
bool getTx() const { return m_tx; }
const QString& getSerial() const { return m_serial; }
uint16_t getSequence() const { return m_sequence; }
int getTxDelay() const { return m_txDelay; }
int getNbBlocksFEC() const { return m_nbBlocksFEC; }
bool hasSequence() const { return m_hasSequence; }
bool hasSerial() const { return m_hasSerial; }
private:
QString m_serverAddress; //!< Address of interface the API and UDP data (Tx) listens on
uint16_t m_serverPort; //!< Port the API listens on
QString m_dataAddress; //!< Address of destination of UDP stream (Rx)
uint16_t m_dataPort; //!< Destination port of UDP stream (Rx) or listening port (Tx)
QString m_deviceType; //!< Identifies the type of device
bool m_tx; //!< True for Tx
QString m_serial; //!< Serial number of the device
uint16_t m_sequence; //!< Sequence of the device for the same type of device in enumeration process
int m_txDelay; //!< Initial delay between transmission of UDP blocks in milliseconds
int m_nbBlocksFEC; //!< Number of FEC blocks per frame;
bool m_hasSerial; //!< True if serial was specified
bool m_hasSequence; //!< True if sequence was specified
QCommandLineParser m_parser;
QCommandLineOption m_serverAddressOption;
QCommandLineOption m_serverPortOption;
QCommandLineOption m_dataAddressOption;
QCommandLineOption m_dataPortOption;
QCommandLineOption m_deviceTypeOption;
QCommandLineOption m_txOption;
QCommandLineOption m_serialOption;
QCommandLineOption m_sequenceOption;
QCommandLineOption m_txDelayOption;
QCommandLineOption m_nbBlocksFECOption;
};
#endif /* SDRDAEMON_SDRDAEMONPARSER_H_ */

View File

@ -1,95 +0,0 @@
///////////////////////////////////////////////////////////////////////////////////
// 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 <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#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;
}
}

View File

@ -1,53 +0,0 @@
///////////////////////////////////////////////////////////////////////////////////
// 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 <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#ifndef SDRDAEMON_SDRDAEMONPREFERENCES_H_
#define SDRDAEMON_SDRDAEMONPREFERENCES_H_
#include <QString>
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_ */

View File

@ -1,51 +0,0 @@
///////////////////////////////////////////////////////////////////////////////////
// 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 <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#include <QSettings>
#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();
}

View File

@ -1,54 +0,0 @@
///////////////////////////////////////////////////////////////////////////////////
// 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 <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#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_ */

View File

@ -1,561 +0,0 @@
///////////////////////////////////////////////////////////////////////////////////
// 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 <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#include <QCoreApplication>
#include "SWGDaemonSummaryResponse.h"
#include "SWGLoggingInfo.h"
#include "SWGDeviceSettings.h"
#include "SWGDeviceState.h"
#include "SWGDeviceReport.h"
#include "SWGChannelReport.h"
#include "SWGChannelSettings.h"
#include "SWGErrorResponse.h"
#include "dsp/dsptypes.h"
#include "dsp/dspdevicesourceengine.h"
#include "dsp/dspdevicesinkengine.h"
#include "device/devicesourceapi.h"
#include "device/devicesinkapi.h"
#include "channel/channelsourceapi.h"
#include "channel/channelsinkapi.h"
#include "dsp/devicesamplesink.h"
#include "dsp/devicesamplesource.h"
#include "webapiadapterdaemon.h"
#include "sdrdaemonmain.h"
#include "loggerwithfile.h"
QString WebAPIAdapterDaemon::daemonInstanceSummaryURL = "/sdrdaemon";
QString WebAPIAdapterDaemon::daemonInstanceLoggingURL = "/sdrdaemon/logging";
QString WebAPIAdapterDaemon::daemonChannelSettingsURL = "/sdrdaemon/channel/settings";
QString WebAPIAdapterDaemon::daemonDeviceSettingsURL = "/sdrdaemon/device/settings";
QString WebAPIAdapterDaemon::daemonDeviceReportURL = "/sdrdaemon/device/report";
QString WebAPIAdapterDaemon::daemonChannelReportURL = "/sdrdaemon/channel/report";
QString WebAPIAdapterDaemon::daemonRunURL = "/sdrdaemon/run";
WebAPIAdapterDaemon::WebAPIAdapterDaemon(SDRDaemonMain& sdrDaemonMain) :
m_sdrDaemonMain(sdrDaemonMain)
{
}
WebAPIAdapterDaemon::~WebAPIAdapterDaemon()
{
}
int WebAPIAdapterDaemon::daemonInstanceSummary(
SWGSDRangel::SWGDaemonSummaryResponse& response,
SWGSDRangel::SWGErrorResponse& error __attribute__((unused)))
{
response.init();
*response.getAppname() = QCoreApplication::applicationName();
*response.getVersion() = QCoreApplication::applicationVersion();
*response.getQtVersion() = QString(QT_VERSION_STR);
response.setDspRxBits(SDR_RX_SAMP_SZ);
response.setDspTxBits(SDR_TX_SAMP_SZ);
response.setPid(QCoreApplication::applicationPid());
#if QT_VERSION >= 0x050400
*response.getArchitecture() = QString(QSysInfo::currentCpuArchitecture());
*response.getOs() = QString(QSysInfo::prettyProductName());
#endif
SWGSDRangel::SWGLoggingInfo *logging = response.getLogging();
logging->init();
logging->setDumpToFile(m_sdrDaemonMain.m_logger->getUseFileLogger() ? 1 : 0);
if (logging->getDumpToFile()) {
m_sdrDaemonMain.m_logger->getLogFileName(*logging->getFileName());
m_sdrDaemonMain.m_logger->getFileMinMessageLevelStr(*logging->getFileLevel());
}
m_sdrDaemonMain.m_logger->getConsoleMinMessageLevelStr(*logging->getConsoleLevel());
SWGSDRangel::SWGSamplingDevice *samplingDevice = response.getSamplingDevice();
samplingDevice->setTx(m_sdrDaemonMain.m_tx ? 1 : 0);
samplingDevice->setHwType(new QString(m_sdrDaemonMain.m_deviceType));
samplingDevice->setIndex(0);
if (m_sdrDaemonMain.m_tx)
{
QString state;
m_sdrDaemonMain.m_deviceSinkAPI->getDeviceEngineStateStr(state);
samplingDevice->setState(new QString(state));
samplingDevice->setSerial(new QString(m_sdrDaemonMain.m_deviceSinkAPI->getSampleSinkSerial()));
samplingDevice->setSequence(m_sdrDaemonMain.m_deviceSinkAPI->getSampleSinkSequence());
samplingDevice->setNbStreams(m_sdrDaemonMain.m_deviceSinkAPI->getNbItems());
samplingDevice->setStreamIndex(m_sdrDaemonMain.m_deviceSinkAPI->getItemIndex());
DeviceSampleSink *sampleSink = m_sdrDaemonMain.m_deviceSinkEngine->getSink();
if (sampleSink) {
samplingDevice->setCenterFrequency(sampleSink->getCenterFrequency());
samplingDevice->setBandwidth(sampleSink->getSampleRate());
}
}
else
{
QString state;
m_sdrDaemonMain.m_deviceSourceAPI->getDeviceEngineStateStr(state);
samplingDevice->setState(new QString(state));
samplingDevice->setSerial(new QString(m_sdrDaemonMain.m_deviceSourceAPI->getSampleSourceSerial()));
samplingDevice->setSequence(m_sdrDaemonMain.m_deviceSourceAPI->getSampleSourceSequence());
samplingDevice->setNbStreams(m_sdrDaemonMain.m_deviceSourceAPI->getNbItems());
samplingDevice->setStreamIndex(m_sdrDaemonMain.m_deviceSourceAPI->getItemIndex());
DeviceSampleSource *sampleSource = m_sdrDaemonMain.m_deviceSourceEngine->getSource();
if (sampleSource) {
samplingDevice->setCenterFrequency(sampleSource->getCenterFrequency());
samplingDevice->setBandwidth(sampleSource->getSampleRate());
}
}
return 200;
}
int WebAPIAdapterDaemon::daemonInstanceLoggingGet(
SWGSDRangel::SWGLoggingInfo& response,
SWGSDRangel::SWGErrorResponse& error __attribute__((unused)))
{
response.init();
response.setDumpToFile(m_sdrDaemonMain.m_logger->getUseFileLogger() ? 1 : 0);
if (response.getDumpToFile()) {
m_sdrDaemonMain.m_logger->getLogFileName(*response.getFileName());
m_sdrDaemonMain.m_logger->getFileMinMessageLevelStr(*response.getFileLevel());
}
m_sdrDaemonMain.m_logger->getConsoleMinMessageLevelStr(*response.getConsoleLevel());
return 200;
}
int WebAPIAdapterDaemon::daemonInstanceLoggingPut(
SWGSDRangel::SWGLoggingInfo& query,
SWGSDRangel::SWGLoggingInfo& response,
SWGSDRangel::SWGErrorResponse& error __attribute__((unused)))
{
// response input is the query actually
bool dumpToFile = (query.getDumpToFile() != 0);
QString* consoleLevel = query.getConsoleLevel();
QString* fileLevel = query.getFileLevel();
QString* fileName = query.getFileName();
// perform actions
if (consoleLevel) {
m_sdrDaemonMain.m_settings.setConsoleMinLogLevel(getMsgTypeFromString(*consoleLevel));
}
if (fileLevel) {
m_sdrDaemonMain.m_settings.setFileMinLogLevel(getMsgTypeFromString(*fileLevel));
}
m_sdrDaemonMain.m_settings.setUseLogFile(dumpToFile);
if (fileName) {
m_sdrDaemonMain.m_settings.setLogFileName(*fileName);
}
m_sdrDaemonMain.setLoggingOptions();
// build response
response.init();
getMsgTypeString(m_sdrDaemonMain.m_settings.getConsoleMinLogLevel(), *response.getConsoleLevel());
response.setDumpToFile(m_sdrDaemonMain.m_settings.getUseLogFile() ? 1 : 0);
getMsgTypeString(m_sdrDaemonMain.m_settings.getFileMinLogLevel(), *response.getFileLevel());
*response.getFileName() = m_sdrDaemonMain.m_settings.getLogFileName();
return 200;
}
int WebAPIAdapterDaemon::daemonChannelSettingsGet(
SWGSDRangel::SWGChannelSettings& response,
SWGSDRangel::SWGErrorResponse& error)
{
error.init();
if (m_sdrDaemonMain.m_deviceSourceEngine) // Rx
{
ChannelSinkAPI *channelAPI = m_sdrDaemonMain.m_deviceSourceAPI->getChanelAPIAt(0);
if (channelAPI == 0)
{
*error.getMessage() = QString("There is no channel");
return 500; // a SDRDaemon sink channel should have been created so this is a server error
}
else
{
response.setChannelType(new QString());
channelAPI->getIdentifier(*response.getChannelType());
response.setTx(0);
return channelAPI->webapiSettingsGet(response, *error.getMessage());
}
}
else if (m_sdrDaemonMain.m_deviceSinkEngine) // Tx
{
ChannelSourceAPI *channelAPI = m_sdrDaemonMain.m_deviceSinkAPI->getChanelAPIAt(0);
if (channelAPI == 0)
{
*error.getMessage() = QString("There is no channel");
return 500; // a SDRDaemon source channel should have been created so this is a server error
}
else
{
response.setChannelType(new QString());
channelAPI->getIdentifier(*response.getChannelType());
response.setTx(1);
return channelAPI->webapiSettingsGet(response, *error.getMessage());
}
}
else
{
*error.getMessage() = QString("Device not created error");
return 500;
}
}
int WebAPIAdapterDaemon::daemonChannelSettingsPutPatch(
bool force,
const QStringList& channelSettingsKeys,
SWGSDRangel::SWGChannelSettings& response,
SWGSDRangel::SWGErrorResponse& error)
{
error.init();
if (m_sdrDaemonMain.m_deviceSourceEngine) // Rx
{
ChannelSinkAPI *channelAPI = m_sdrDaemonMain.m_deviceSourceAPI->getChanelAPIAt(0);
if (channelAPI == 0)
{
*error.getMessage() = QString("There is no channel");
return 500;
}
else
{
QString channelType;
channelAPI->getIdentifier(channelType);
if (channelType == *response.getChannelType())
{
return channelAPI->webapiSettingsPutPatch(force, channelSettingsKeys, response, *error.getMessage());
}
else
{
*error.getMessage() = QString("Channel has wrong type. Found %1.").arg(channelType);
return 500;
}
}
}
else if (m_sdrDaemonMain.m_deviceSinkEngine) // Tx
{
ChannelSourceAPI *channelAPI = m_sdrDaemonMain.m_deviceSinkAPI->getChanelAPIAt(0);
if (channelAPI == 0)
{
*error.getMessage() = QString("There is no channel");
return 500;
}
else
{
QString channelType;
channelAPI->getIdentifier(channelType);
if (channelType == *response.getChannelType())
{
return channelAPI->webapiSettingsPutPatch(force, channelSettingsKeys, response, *error.getMessage());
}
else
{
*error.getMessage() = QString("Channel has wrong type. Found %3.").arg(channelType);
return 500;
}
}
}
else
{
*error.getMessage() = QString("DeviceSet error");
return 500;
}
}
int WebAPIAdapterDaemon::daemonDeviceSettingsGet(
SWGSDRangel::SWGDeviceSettings& response __attribute__((unused)),
SWGSDRangel::SWGErrorResponse& error)
{
error.init();
if (m_sdrDaemonMain.m_deviceSourceEngine) // Rx
{
response.setDeviceHwType(new QString(m_sdrDaemonMain.m_deviceSourceAPI->getHardwareId()));
response.setTx(0);
DeviceSampleSource *source = m_sdrDaemonMain.m_deviceSourceAPI->getSampleSource();
return source->webapiSettingsGet(response, *error.getMessage());
}
else if (m_sdrDaemonMain.m_deviceSinkEngine) // Tx
{
response.setDeviceHwType(new QString(m_sdrDaemonMain.m_deviceSinkAPI->getHardwareId()));
response.setTx(1);
DeviceSampleSink *sink = m_sdrDaemonMain.m_deviceSinkAPI->getSampleSink();
return sink->webapiSettingsGet(response, *error.getMessage());
}
else
{
*error.getMessage() = QString("Device error");
return 500;
}
}
int WebAPIAdapterDaemon::daemonDeviceSettingsPutPatch(
bool force,
const QStringList& deviceSettingsKeys,
SWGSDRangel::SWGDeviceSettings& response,
SWGSDRangel::SWGErrorResponse& error)
{
error.init();
if (m_sdrDaemonMain.m_deviceSourceEngine) // Rx
{
if (response.getTx() != 0)
{
*error.getMessage() = QString("Rx device found but Tx device requested");
return 400;
}
if (m_sdrDaemonMain.m_deviceSourceAPI->getHardwareId() != *response.getDeviceHwType())
{
*error.getMessage() = QString("Device mismatch. Found %1 input").arg(m_sdrDaemonMain.m_deviceSourceAPI->getHardwareId());
return 400;
}
else
{
DeviceSampleSource *source = m_sdrDaemonMain.m_deviceSourceAPI->getSampleSource();
return source->webapiSettingsPutPatch(force, deviceSettingsKeys, response, *error.getMessage());
}
}
else if (m_sdrDaemonMain.m_deviceSinkEngine) // Tx
{
if (response.getTx() == 0)
{
*error.getMessage() = QString("Tx device found but Rx device requested");
return 400;
}
else if (m_sdrDaemonMain.m_deviceSinkAPI->getHardwareId() != *response.getDeviceHwType())
{
*error.getMessage() = QString("Device mismatch. Found %1 output").arg(m_sdrDaemonMain.m_deviceSinkAPI->getHardwareId());
return 400;
}
else
{
DeviceSampleSink *sink = m_sdrDaemonMain.m_deviceSinkAPI->getSampleSink();
return sink->webapiSettingsPutPatch(force, deviceSettingsKeys, response, *error.getMessage());
}
}
else
{
*error.getMessage() = QString("DeviceSet error");
return 500;
}
}
int WebAPIAdapterDaemon::daemonRunGet(
SWGSDRangel::SWGDeviceState& response,
SWGSDRangel::SWGErrorResponse& error)
{
error.init();
if (m_sdrDaemonMain.m_deviceSourceEngine) // Rx
{
DeviceSampleSource *source = m_sdrDaemonMain.m_deviceSourceAPI->getSampleSource();
response.init();
return source->webapiRunGet(response, *error.getMessage());
}
else if (m_sdrDaemonMain.m_deviceSinkEngine) // Tx
{
DeviceSampleSink *sink = m_sdrDaemonMain.m_deviceSinkAPI->getSampleSink();
response.init();
return sink->webapiRunGet(response, *error.getMessage());
}
else
{
*error.getMessage() = QString("DeviceSet error");
return 500;
}
}
int WebAPIAdapterDaemon::daemonRunPost(
SWGSDRangel::SWGDeviceState& response,
SWGSDRangel::SWGErrorResponse& error)
{
error.init();
if (m_sdrDaemonMain.m_deviceSourceEngine) // Rx
{
DeviceSampleSource *source = m_sdrDaemonMain.m_deviceSourceAPI->getSampleSource();
response.init();
return source->webapiRun(true, response, *error.getMessage());
}
else if (m_sdrDaemonMain.m_deviceSinkEngine) // Tx
{
DeviceSampleSink *sink = m_sdrDaemonMain.m_deviceSinkAPI->getSampleSink();
response.init();
return sink->webapiRun(true, response, *error.getMessage());
}
else
{
*error.getMessage() = QString("DeviceSet error");
return 500;
}
}
int WebAPIAdapterDaemon::daemonRunDelete(
SWGSDRangel::SWGDeviceState& response,
SWGSDRangel::SWGErrorResponse& error)
{
error.init();
if (m_sdrDaemonMain.m_deviceSourceEngine) // Rx
{
DeviceSampleSource *source = m_sdrDaemonMain.m_deviceSourceAPI->getSampleSource();
response.init();
return source->webapiRun(false, response, *error.getMessage());
}
else if (m_sdrDaemonMain.m_deviceSinkEngine) // Tx
{
DeviceSampleSink *sink = m_sdrDaemonMain.m_deviceSinkAPI->getSampleSink();
response.init();
return sink->webapiRun(false, response, *error.getMessage());
}
else
{
*error.getMessage() = QString("DeviceSet error");
return 500;
}
}
int WebAPIAdapterDaemon::daemonDeviceReportGet(
SWGSDRangel::SWGDeviceReport& response,
SWGSDRangel::SWGErrorResponse& error)
{
error.init();
if (m_sdrDaemonMain.m_deviceSourceEngine) // Rx
{
response.setDeviceHwType(new QString(m_sdrDaemonMain.m_deviceSourceAPI->getHardwareId()));
response.setTx(0);
DeviceSampleSource *source = m_sdrDaemonMain.m_deviceSourceAPI->getSampleSource();
return source->webapiReportGet(response, *error.getMessage());
}
else if (m_sdrDaemonMain.m_deviceSinkEngine) // Tx
{
response.setDeviceHwType(new QString(m_sdrDaemonMain.m_deviceSinkAPI->getHardwareId()));
response.setTx(1);
DeviceSampleSink *sink = m_sdrDaemonMain.m_deviceSinkAPI->getSampleSink();
return sink->webapiReportGet(response, *error.getMessage());
}
else
{
*error.getMessage() = QString("DeviceSet error");
return 500;
}
}
int WebAPIAdapterDaemon::daemonChannelReportGet(
SWGSDRangel::SWGChannelReport& response,
SWGSDRangel::SWGErrorResponse& error)
{
error.init();
if (m_sdrDaemonMain.m_deviceSourceEngine) // Rx
{
ChannelSinkAPI *channelAPI = m_sdrDaemonMain.m_deviceSourceAPI->getChanelAPIAt(0);
if (channelAPI == 0)
{
*error.getMessage() = QString("There is no channel");
return 500; // a SDRDaemon sink channel should have been created so this is a server error
}
else
{
response.setChannelType(new QString());
channelAPI->getIdentifier(*response.getChannelType());
response.setTx(0);
return channelAPI->webapiReportGet(response, *error.getMessage());
}
}
else if (m_sdrDaemonMain.m_deviceSinkEngine) // Tx
{
ChannelSourceAPI *channelAPI = m_sdrDaemonMain.m_deviceSinkAPI->getChanelAPIAt(0);
if (channelAPI == 0)
{
*error.getMessage() = QString("There is no channel");
return 500; // a SDRDaemon source channel should have been created so this is a server error
}
else
{
response.setChannelType(new QString());
channelAPI->getIdentifier(*response.getChannelType());
response.setTx(1);
return channelAPI->webapiReportGet(response, *error.getMessage());
}
}
else
{
*error.getMessage() = QString("Device not created error");
return 500;
}
}
// 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;
}
}

View File

@ -1,116 +0,0 @@
///////////////////////////////////////////////////////////////////////////////////
// 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 <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#ifndef SDRDAEMON_WEBAPI_WEBAPIADAPTERDAEMON_H_
#define SDRDAEMON_WEBAPI_WEBAPIADAPTERDAEMON_H_
#include <QtGlobal>
#include <QStringList>
namespace SWGSDRangel
{
class SWGDaemonSummaryResponse;
class SWGDeviceSet;
class SWGDeviceListItem;
class SWGDeviceSettings;
class SWGDeviceState;
class SWGDeviceReport;
class SWGChannelReport;
class SWGSuccessResponse;
class SWGErrorResponse;
class SWGLoggingInfo;
class SWGChannelSettings;
}
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 daemonChannelSettingsGet(
SWGSDRangel::SWGChannelSettings& response,
SWGSDRangel::SWGErrorResponse& error);
int daemonChannelSettingsPutPatch(
bool force,
const QStringList& channelSettingsKeys,
SWGSDRangel::SWGChannelSettings& response,
SWGSDRangel::SWGErrorResponse& error);
int daemonDeviceSettingsGet(
SWGSDRangel::SWGDeviceSettings& response,
SWGSDRangel::SWGErrorResponse& error);
int daemonDeviceSettingsPutPatch(
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 daemonDeviceReportGet(
SWGSDRangel::SWGDeviceReport& response,
SWGSDRangel::SWGErrorResponse& error);
int daemonChannelReportGet(
SWGSDRangel::SWGChannelReport& response,
SWGSDRangel::SWGErrorResponse& error);
static QString daemonInstanceSummaryURL;
static QString daemonInstanceLoggingURL;
static QString daemonChannelSettingsURL;
static QString daemonDeviceSettingsURL;
static QString daemonDeviceReportURL;
static QString daemonChannelReportURL;
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_ */

File diff suppressed because it is too large Load Diff

View File

@ -1,83 +0,0 @@
///////////////////////////////////////////////////////////////////////////////////
// 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 <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#ifndef SDRDAEMON_WEBAPI_WEBAPIREQUESTMAPPER_H_
#define SDRDAEMON_WEBAPI_WEBAPIREQUESTMAPPER_H_
#include <QJsonParseError>
#include "httprequesthandler.h"
#include "httprequest.h"
#include "httpresponse.h"
#include "staticfilecontroller.h"
#include "export.h"
namespace SWGSDRangel
{
class SWGChannelSettings;
class SWGChannelReport;
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 daemonChannelSettingsService(qtwebapp::HttpRequest& request, qtwebapp::HttpResponse& response);
void daemonDeviceSettingsService(qtwebapp::HttpRequest& request, qtwebapp::HttpResponse& response);
void daemonRunService(qtwebapp::HttpRequest& request, qtwebapp::HttpResponse& response);
void daemonDeviceReportService(qtwebapp::HttpRequest& request, qtwebapp::HttpResponse& response);
void daemonChannelReportService(qtwebapp::HttpRequest& request, qtwebapp::HttpResponse& response);
bool validateChannelSettings(SWGSDRangel::SWGChannelSettings& channelSettings, QJsonObject& jsonObject, QStringList& channelSettingsKeys);
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 resetChannelSettings(SWGSDRangel::SWGChannelSettings& channelSettings);
void resetChannelReport(SWGSDRangel::SWGChannelReport& deviceSettings);
void resetDeviceSettings(SWGSDRangel::SWGDeviceSettings& deviceSettings);
void resetDeviceReport(SWGSDRangel::SWGDeviceReport& deviceReport);
};
} // namespace SDRdaemon
#endif /* SDRDAEMON_WEBAPI_WEBAPIREQUESTMAPPER_H_ */

View File

@ -1,67 +0,0 @@
///////////////////////////////////////////////////////////////////////////////////
// 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 <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#include <QCoreApplication>
#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

View File

@ -1,56 +0,0 @@
///////////////////////////////////////////////////////////////////////////////////
// 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 <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#ifndef SDRDAEMON_WEBAPI_WEBAPISERVER_H_
#define SDRDAEMON_WEBAPI_WEBAPISERVER_H_
#include <QString>
#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_ */