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 # when building, don't use the install RPATH already
# (but later on when installing) # (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") SET(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/lib")
@ -222,7 +222,6 @@ endif()
add_subdirectory(sdrbase) add_subdirectory(sdrbase)
add_subdirectory(sdrgui) add_subdirectory(sdrgui)
add_subdirectory(sdrsrv) add_subdirectory(sdrsrv)
add_subdirectory(sdrdaemon)
add_subdirectory(sdrbench) add_subdirectory(sdrbench)
add_subdirectory(httpserver) add_subdirectory(httpserver)
add_subdirectory(logging) add_subdirectory(logging)
@ -327,31 +326,6 @@ target_link_libraries(sdrangelbench
target_compile_features(sdrangelbench PRIVATE cxx_generalized_initializers) # cmake >= 3.1.0 target_compile_features(sdrangelbench PRIVATE cxx_generalized_initializers) # cmake >= 3.1.0
target_link_libraries(sdrangelbench Qt5::Multimedia) 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) if (BUILD_DEBIAN)
@ -385,7 +359,6 @@ endif(LIBUSB_FOUND AND UNIX)
install(TARGETS sdrangel DESTINATION bin) install(TARGETS sdrangel DESTINATION bin)
install(TARGETS sdrangelsrv DESTINATION bin) install(TARGETS sdrangelsrv DESTINATION bin)
install(TARGETS sdrangelbench DESTINATION bin) install(TARGETS sdrangelbench DESTINATION bin)
install(TARGETS sdrdaemonsrv DESTINATION bin)
#install(TARGETS sdrbase DESTINATION lib) #install(TARGETS sdrbase DESTINATION lib)
#install files and directories #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( include_directories(
. .
${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_BINARY_DIR}
${CMAKE_SOURCE_DIR}/sdrdaemon
${CM256CC_INCLUDE_DIR} ${CM256CC_INCLUDE_DIR}
${CMAKE_SOURCE_DIR}/swagger/sdrangel/code/qt5/client ${CMAKE_SOURCE_DIR}/swagger/sdrangel/code/qt5/client
) )
#include(${QT_USE_FILE}) #include(${QT_USE_FILE})
@ -47,7 +46,6 @@ target_link_libraries(daemonsink
${QT_LIBRARIES} ${QT_LIBRARIES}
${CM256CC_LIBRARIES} ${CM256CC_LIBRARIES}
sdrbase sdrbase
sdrdaemon
sdrgui sdrgui
swagger swagger
) )

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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