mirror of
https://github.com/f4exb/sdrangel.git
synced 2024-09-27 07:16:48 -04:00
Complete removal of SDRDaemon as a distinct binary
This commit is contained in:
parent
4cd9055fe6
commit
6c77f2dfe5
@ -222,7 +222,6 @@ endif()
|
||||
add_subdirectory(sdrbase)
|
||||
add_subdirectory(sdrgui)
|
||||
add_subdirectory(sdrsrv)
|
||||
add_subdirectory(sdrdaemon)
|
||||
add_subdirectory(sdrbench)
|
||||
add_subdirectory(httpserver)
|
||||
add_subdirectory(logging)
|
||||
@ -327,31 +326,6 @@ target_link_libraries(sdrangelbench
|
||||
target_compile_features(sdrangelbench PRIVATE cxx_generalized_initializers) # cmake >= 3.1.0
|
||||
target_link_libraries(sdrangelbench Qt5::Multimedia)
|
||||
|
||||
##############################################################################
|
||||
# SDRdaemon application
|
||||
|
||||
set(sdrdaemonsrv_SOURCES
|
||||
appdaemon/main.cpp
|
||||
)
|
||||
|
||||
add_executable(sdrdaemonsrv
|
||||
${sdrdaemonsrv_SOURCES}
|
||||
)
|
||||
|
||||
target_include_directories(sdrdaemonsrv
|
||||
PUBLIC ${CMAKE_SOURCE_DIR}/sdrdaemon
|
||||
)
|
||||
|
||||
target_link_libraries(sdrdaemonsrv
|
||||
sdrdaemon
|
||||
sdrbase
|
||||
logging
|
||||
${QT_LIBRARIES}
|
||||
)
|
||||
|
||||
target_compile_features(sdrdaemonsrv PRIVATE cxx_generalized_initializers) # cmake >= 3.1.0
|
||||
target_link_libraries(sdrdaemonsrv Qt5::Multimedia)
|
||||
|
||||
##############################################################################
|
||||
|
||||
if (BUILD_DEBIAN)
|
||||
@ -385,7 +359,6 @@ endif(LIBUSB_FOUND AND UNIX)
|
||||
install(TARGETS sdrangel DESTINATION bin)
|
||||
install(TARGETS sdrangelsrv DESTINATION bin)
|
||||
install(TARGETS sdrangelbench DESTINATION bin)
|
||||
install(TARGETS sdrdaemonsrv DESTINATION bin)
|
||||
#install(TARGETS sdrbase DESTINATION lib)
|
||||
|
||||
#install files and directories
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -25,7 +25,6 @@ set(daemonsink_FORMS
|
||||
include_directories(
|
||||
.
|
||||
${CMAKE_CURRENT_BINARY_DIR}
|
||||
${CMAKE_SOURCE_DIR}/sdrdaemon
|
||||
${CM256CC_INCLUDE_DIR}
|
||||
${CMAKE_SOURCE_DIR}/swagger/sdrangel/code/qt5/client
|
||||
)
|
||||
@ -47,7 +46,6 @@ target_link_libraries(daemonsink
|
||||
${QT_LIBRARIES}
|
||||
${CM256CC_LIBRARIES}
|
||||
sdrbase
|
||||
sdrdaemon
|
||||
sdrgui
|
||||
swagger
|
||||
)
|
||||
|
@ -25,7 +25,6 @@ set(daemonsrc_FORMS
|
||||
include_directories(
|
||||
.
|
||||
${CMAKE_CURRENT_BINARY_DIR}
|
||||
${CMAKE_SOURCE_DIR}/sdrdaemon
|
||||
${CM256CC_INCLUDE_DIR}
|
||||
${CMAKE_SOURCE_DIR}/swagger/sdrangel/code/qt5/client
|
||||
)
|
||||
@ -47,7 +46,6 @@ target_link_libraries(daemonsrc
|
||||
${QT_LIBRARIES}
|
||||
${CM256CC_LIBRARIES}
|
||||
sdrbase
|
||||
sdrdaemon
|
||||
sdrgui
|
||||
swagger
|
||||
)
|
||||
|
@ -21,7 +21,6 @@
|
||||
|
||||
#include "channel/sdrdaemondataqueue.h"
|
||||
#include "channel/sdrdaemondatablock.h"
|
||||
#include "channel/sdrdaemonchannelsourcethread.h"
|
||||
|
||||
#include "daemonsrcthread.h"
|
||||
|
||||
|
@ -20,7 +20,6 @@ set(daemonsink_HEADERS
|
||||
include_directories(
|
||||
.
|
||||
${CMAKE_CURRENT_BINARY_DIR}
|
||||
${CMAKE_SOURCE_DIR}/sdrdaemon
|
||||
${CM256CC_INCLUDE_DIR}
|
||||
${CMAKE_SOURCE_DIR}/swagger/sdrangel/code/qt5/client
|
||||
)
|
||||
@ -39,7 +38,6 @@ target_link_libraries(daemonsinksrv
|
||||
${QT_LIBRARIES}
|
||||
${CM256CC_LIBRARIES}
|
||||
sdrbase
|
||||
sdrdaemon
|
||||
swagger
|
||||
)
|
||||
|
||||
|
@ -20,7 +20,6 @@ set(daemonsrc_HEADERS
|
||||
include_directories(
|
||||
.
|
||||
${CMAKE_CURRENT_BINARY_DIR}
|
||||
${CMAKE_SOURCE_DIR}/sdrdaemon
|
||||
${CM256CC_INCLUDE_DIR}
|
||||
${CMAKE_SOURCE_DIR}/swagger/sdrangel/code/qt5/client
|
||||
)
|
||||
@ -39,7 +38,6 @@ target_link_libraries(daemonsrcsrv
|
||||
${QT_LIBRARIES}
|
||||
${CM256CC_LIBRARIES}
|
||||
sdrbase
|
||||
sdrdaemon
|
||||
swagger
|
||||
)
|
||||
|
||||
|
@ -12,6 +12,9 @@ set(sdrbase_SOURCES
|
||||
|
||||
channel/channelsinkapi.cpp
|
||||
channel/channelsourceapi.cpp
|
||||
channel/sdrdaemondataqueue.cpp
|
||||
channel/sdrdaemondatareadqueue.cpp
|
||||
|
||||
commands/command.cpp
|
||||
|
||||
dsp/afsquelch.cpp
|
||||
@ -100,6 +103,10 @@ set(sdrbase_HEADERS
|
||||
|
||||
channel/channelsinkapi.h
|
||||
channel/channelsourceapi.h
|
||||
channel/sdrdaemondataqueue.h
|
||||
channel/sdrdaemondatareadqueue.h
|
||||
channel/sdrdaemondatablock.h
|
||||
|
||||
commands/command.h
|
||||
|
||||
dsp/afsquelch.h
|
||||
|
@ -57,6 +57,8 @@ SOURCES += audio/audiodevicemanager.cpp\
|
||||
audio/audionetsink.cpp\
|
||||
channel/channelsinkapi.cpp\
|
||||
channel/channelsourceapi.cpp\
|
||||
channel/sdrdaemondataqueue.cpp\
|
||||
channel/sdrdaemondatareadqueue.cpp\
|
||||
commands/command.cpp\
|
||||
device/devicesourceapi.cpp\
|
||||
device/devicesinkapi.cpp\
|
||||
@ -132,6 +134,9 @@ HEADERS += audio/audiodevicemanager.h\
|
||||
audio/audionetsink.h\
|
||||
channel/channelsinkapi.h\
|
||||
channel/channelsourceapi.h\
|
||||
channel/sdrdaemondataqueue.h\
|
||||
channel/sdrdaemondatareadqueue.h\
|
||||
channel/sdrdaemondatablock.h\
|
||||
commands/command.h\
|
||||
device/devicesourceapi.h\
|
||||
device/devicesinkapi.h\
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
}
|
@ -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_ */
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -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_ */
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
@ -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();
|
||||
};
|
@ -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);
|
||||
}
|
@ -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_ */
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -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_ */
|
@ -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");
|
||||
}
|
||||
}
|
||||
}
|
@ -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_ */
|
@ -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;
|
||||
}
|
||||
}
|
@ -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_ */
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -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_ */
|
@ -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;
|
||||
}
|
||||
}
|
@ -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_ */
|
@ -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();
|
||||
}
|
@ -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_ */
|
@ -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;
|
||||
}
|
||||
}
|
@ -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
@ -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_ */
|
@ -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
|
@ -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_ */
|
Loading…
Reference in New Issue
Block a user