diff --git a/appdaemon/main.cpp b/appdaemon/main.cpp index 937ce5960..e9feb9d2b 100644 --- a/appdaemon/main.cpp +++ b/appdaemon/main.cpp @@ -94,10 +94,17 @@ static int runQtApplication(int argc, char* argv[], qtwebapp::LoggerWithFile *lo SDRDaemonMain m(logger, parser, &a); - // This will cause the application to exit when SDRdaemon is finished - QObject::connect(&m, SIGNAL(finished()), &a, SLOT(quit())); + 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(); + return a.exec(); + } } int main(int argc, char* argv[]) diff --git a/sdrdaemon/CMakeLists.txt b/sdrdaemon/CMakeLists.txt index 0950d9c12..52422863e 100644 --- a/sdrdaemon/CMakeLists.txt +++ b/sdrdaemon/CMakeLists.txt @@ -6,6 +6,7 @@ set(sdrdaemon_SOURCES sdrdaemonsettings.cpp sdrdaemonparser.cpp channel/sdrdaemonchannelsink.cpp + channel/sdrdaemonchannelsource.cpp webapi/webapiadapterdaemon.cpp webapi/webapirequestmapper.cpp webapi/webapiserver.cpp @@ -17,6 +18,7 @@ set(sdrdaemon_HEADERS sdrdaemonsettings.h sdrdaemonparser.h channel/sdrdaemonchannelsink.h + channel/sdrdaemonchannelsource.h webapi/webapiadapterdaemon.h webapi/webapirequestmapper.h webapi/webapiserver.h diff --git a/sdrdaemon/channel/sdrdaemonchannelsink.h b/sdrdaemon/channel/sdrdaemonchannelsink.h index df9b117dd..f92a90da7 100644 --- a/sdrdaemon/channel/sdrdaemonchannelsink.h +++ b/sdrdaemon/channel/sdrdaemonchannelsink.h @@ -58,7 +58,6 @@ private: DownChannelizer* m_channelizer; bool m_running; - }; #endif /* SDRDAEMON_CHANNEL_SDRDAEMONCHANNELSINK_H_ */ diff --git a/sdrdaemon/channel/sdrdaemonchannelsource.cpp b/sdrdaemon/channel/sdrdaemonchannelsource.cpp new file mode 100644 index 000000000..f22886299 --- /dev/null +++ b/sdrdaemon/channel/sdrdaemonchannelsource.cpp @@ -0,0 +1,94 @@ +/////////////////////////////////////////////////////////////////////////////////// +// 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 . // +/////////////////////////////////////////////////////////////////////////////////// + +#include "util/simpleserializer.h" +#include "dsp/threadedbasebandsamplesource.h" +#include "dsp/upchannelizer.h" +#include "device/devicesinkapi.h" +#include "sdrdaemonchannelsource.h" + +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_running(false), + m_samplesCount(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); +} + +SDRDaemonChannelSource::~SDRDaemonChannelSource() +{ + m_deviceAPI->removeChannelAPI(this); + m_deviceAPI->removeThreadedSource(m_threadedChannelizer); + delete m_threadedChannelizer; + delete m_channelizer; +} + +void SDRDaemonChannelSource::pull(Sample& sample) +{ + sample.m_real = 0.0f; + sample.m_imag = 0.0f; + + if (m_samplesCount < 1023) { + m_samplesCount++; + } else { + qDebug("SDRDaemonChannelSource::pull: 1024 samples pulled"); + m_samplesCount = 0; + } +} + +void SDRDaemonChannelSource::start() +{ + qDebug("SDRDaemonChannelSink::start"); + m_running = true; +} + +void SDRDaemonChannelSource::stop() +{ + qDebug("SDRDaemonChannelSink::stop"); + m_running = false; +} + +bool SDRDaemonChannelSource::handleMessage(const Message& cmd __attribute__((unused))) +{ + return false; +} + +QByteArray SDRDaemonChannelSource::serialize() const +{ + SimpleSerializer s(1); + return s.final(); +} + +bool SDRDaemonChannelSource::deserialize(const QByteArray& data __attribute__((unused))) +{ + return false; +} + diff --git a/sdrdaemon/channel/sdrdaemonchannelsource.h b/sdrdaemon/channel/sdrdaemonchannelsource.h new file mode 100644 index 000000000..c5b543199 --- /dev/null +++ b/sdrdaemon/channel/sdrdaemonchannelsource.h @@ -0,0 +1,65 @@ +/////////////////////////////////////////////////////////////////////////////////// +// 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 . // +/////////////////////////////////////////////////////////////////////////////////// + +#ifndef SDRDAEMON_CHANNEL_SDRDAEMONCHANNELSOURCE_H_ +#define SDRDAEMON_CHANNEL_SDRDAEMONCHANNELSOURCE_H_ + +#include "dsp/basebandsamplesource.h" +#include "channel/channelsourceapi.h" + +class ThreadedBasebandSampleSource; +class UpChannelizer; +class DeviceSinkAPI; + +class SDRDaemonChannelSource : public BasebandSampleSource, public ChannelSourceAPI { + Q_OBJECT +public: + 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); + + static const QString m_channelIdURI; + static const QString m_channelId; + +private: + DeviceSinkAPI *m_deviceAPI; + ThreadedBasebandSampleSource* m_threadedChannelizer; + UpChannelizer* m_channelizer; + + bool m_running; + uint32_t m_samplesCount; +}; + + +#endif /* SDRDAEMON_CHANNEL_SDRDAEMONCHANNELSOURCE_H_ */ diff --git a/sdrdaemon/sdrdaemonmain.cpp b/sdrdaemon/sdrdaemonmain.cpp index e7faf6667..ab51d6ecc 100644 --- a/sdrdaemon/sdrdaemonmain.cpp +++ b/sdrdaemon/sdrdaemonmain.cpp @@ -38,6 +38,7 @@ #include "webapi/webapirequestmapper.h" #include "webapi/webapiserver.h" #include "channel/sdrdaemonchannelsink.h" +#include "channel/sdrdaemonchannelsource.h" #include "sdrdaemonparser.h" #include "sdrdaemonmain.h" @@ -48,7 +49,8 @@ SDRDaemonMain::SDRDaemonMain(qtwebapp::LoggerWithFile *logger, const SDRDaemonPa m_logger(logger), m_settings(), m_dspEngine(DSPEngine::instance()), - m_lastEngineState(DSPDeviceSourceEngine::StNotStarted) + m_lastEngineState(DSPDeviceSourceEngine::StNotStarted), + m_abort(false) { qDebug() << "SDRDaemonMain::SDRDaemonMain: start"; @@ -87,6 +89,7 @@ SDRDaemonMain::SDRDaemonMain(qtwebapp::LoggerWithFile *logger, const SDRDaemonPa m_deviceSourceAPI = 0; m_deviceSinkAPI = 0; m_channelSink = 0; + m_channelSource = 0; if (m_tx) { @@ -103,11 +106,12 @@ SDRDaemonMain::SDRDaemonMain(qtwebapp::LoggerWithFile *logger, const SDRDaemonPa QDebug info = qInfo(); info.noquote(); info << msg; + m_channelSource = new SDRDaemonChannelSource(m_deviceSinkAPI); } else { qCritical("SDRDaemonMain::SDRDaemonMain: sink device not found aborting"); - emit finished(); + m_abort = true; } } else @@ -130,7 +134,7 @@ SDRDaemonMain::SDRDaemonMain(qtwebapp::LoggerWithFile *logger, const SDRDaemonPa else { qCritical("SDRDaemonMain::SDRDaemonMain: source device not found aborting"); - emit finished(); + m_abort = true; } } @@ -211,20 +215,20 @@ void SDRDaemonMain::setLoggingOptions() bool SDRDaemonMain::addSinkDevice() { - 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); 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); @@ -246,20 +250,20 @@ bool SDRDaemonMain::addSinkDevice() bool SDRDaemonMain::addSourceDevice() { - 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); 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); @@ -307,6 +311,11 @@ void SDRDaemonMain::removeDevice() 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()); diff --git a/sdrdaemon/sdrdaemonmain.h b/sdrdaemon/sdrdaemonmain.h index 8eb07211a..cc4f987de 100644 --- a/sdrdaemon/sdrdaemonmain.h +++ b/sdrdaemon/sdrdaemonmain.h @@ -48,6 +48,7 @@ class DeviceSourceAPI; class DSPDeviceSinkEngine; class DeviceSinkAPI; class SDRDaemonChannelSink; +class SDRDaemonChannelSource; class SDRDaemonMain : public QObject { Q_OBJECT @@ -65,6 +66,8 @@ public: bool addSinkDevice(); void removeDevice(); + bool doAbort() const { return m_abort; } + friend class WebAPIAdapterDaemon; signals: @@ -94,6 +97,9 @@ private: DSPDeviceSinkEngine *m_deviceSinkEngine; DeviceSinkAPI *m_deviceSinkAPI; SDRDaemonChannelSink *m_channelSink; + SDRDaemonChannelSource *m_channelSource; + + bool m_abort; void loadSettings(); void setLoggingOptions(); diff --git a/sdrdaemon/sdrdaemonparser.cpp b/sdrdaemon/sdrdaemonparser.cpp index a314c8772..d1c7fc07c 100644 --- a/sdrdaemon/sdrdaemonparser.cpp +++ b/sdrdaemon/sdrdaemonparser.cpp @@ -146,22 +146,31 @@ void SDRDaemonParser::parse(const QCoreApplication& app) // device type - 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) + if (m_parser.isSet(m_deviceTypeOption)) { - m_deviceType = deviceType; - qDebug() << "SDRDaemonParser::parse: device type: " << m_deviceType; + 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"; - qWarning() << "SDRDaemonParser::parse: device type invalid. Defaulting to " << m_deviceType; + qInfo() << "SDRDaemonParser::parse: device type not specified. defaulting to " << m_deviceType; } + // serial m_hasSerial = m_parser.isSet(m_serialOption);