From 321cffc9c7b4270e44ae1900898671a3d9ce4e2e Mon Sep 17 00:00:00 2001 From: f4exb Date: Sun, 20 Dec 2020 01:53:03 +0100 Subject: [PATCH] Demod Analyzer implementation with AM modulator and demodulator --- plugins/channelrx/demodam/amdemod.cpp | 1 + plugins/channelrx/demodam/amdemodbaseband.cpp | 5 + plugins/channelrx/demodam/amdemodbaseband.h | 4 +- plugins/channelrx/demodam/amdemodplugin.cpp | 2 +- plugins/channelrx/demodam/amdemodsink.cpp | 37 ++ plugins/channelrx/demodam/amdemodsink.h | 7 + plugins/channeltx/modam/ammod.cpp | 1 + plugins/channeltx/modam/ammodbaseband.cpp | 7 +- plugins/channeltx/modam/ammodbaseband.h | 2 + plugins/channeltx/modam/ammodplugin.cpp | 2 +- plugins/channeltx/modam/ammodsource.cpp | 41 +- plugins/channeltx/modam/ammodsource.h | 7 + plugins/feature/CMakeLists.txt | 1 + plugins/feature/afc/afc.cpp | 7 +- plugins/feature/afc/afcplugin.cpp | 2 +- plugins/feature/demodanalyzer/CMakeLists.txt | 56 ++ .../feature/demodanalyzer/demodalyzergui.ui | 346 +++++++++++ .../feature/demodanalyzer/demodanalyzer.cpp | 535 ++++++++++++++++++ plugins/feature/demodanalyzer/demodanalyzer.h | 220 +++++++ .../demodanalyzer/demodanalyzergui.cpp | 354 ++++++++++++ .../feature/demodanalyzer/demodanalyzergui.h | 96 ++++ .../feature/demodanalyzer/demodanalyzergui.ui | 346 +++++++++++ .../demodanalyzer/demodanalyzerplugin.cpp | 80 +++ .../demodanalyzer/demodanalyzerplugin.h | 48 ++ .../demodanalyzer/demodanalyzersettings.cpp | 128 +++++ .../demodanalyzer/demodanalyzersettings.h | 67 +++ .../demodanalyzerwebapiadapter.cpp | 51 ++ .../demodanalyzerwebapiadapter.h | 49 ++ .../demodanalyzer/demodanalyzerworker.cpp | 183 ++++++ .../demodanalyzer/demodanalyzerworker.h | 126 +++++ plugins/feature/vorlocalizer/vorlocalizer.cpp | 3 +- .../vorlocalizer/vorlocalizerplugin.cpp | 2 +- sdrbase/dsp/datafifo.cpp | 7 +- sdrbase/dsp/datafifo.h | 1 - sdrbase/maincore.cpp | 1 + sdrbase/maincore.h | 25 + sdrbase/pipes/datapipes.cpp | 6 +- sdrbase/pipes/datapipes.h | 2 +- sdrbase/pipes/datapipesgcworker.cpp | 9 + sdrbase/pipes/datapipesgcworker.h | 1 + sdrbase/pipes/elementpipesgc.h | 5 + sdrbase/pipes/elementpipesregistrations.h | 10 +- sdrbase/pipes/messagepipes.cpp | 6 +- sdrbase/pipes/messagepipes.h | 2 +- sdrbase/pipes/messagepipesgcworker.cpp | 9 + sdrbase/pipes/messagepipesgcworker.h | 1 + sdrbase/resources/webapi/doc/html2/index.html | 54 +- .../doc/swagger/include/DemodAnalyzer.yaml | 29 + .../doc/swagger/include/FeatureSettings.yaml | 10 +- .../api/swagger/include/DemodAnalyzer.yaml | 29 + .../api/swagger/include/FeatureSettings.yaml | 10 +- swagger/sdrangel/code/html2/index.html | 54 +- .../qt5/client/SWGDemodAnalyzerSettings.cpp | 346 +++++++++++ .../qt5/client/SWGDemodAnalyzerSettings.h | 121 ++++ .../code/qt5/client/SWGFeatureSettings.cpp | 107 ++-- .../code/qt5/client/SWGFeatureSettings.h | 27 +- .../code/qt5/client/SWGModelFactory.h | 4 + 57 files changed, 3595 insertions(+), 97 deletions(-) create mode 100644 plugins/feature/demodanalyzer/CMakeLists.txt create mode 100644 plugins/feature/demodanalyzer/demodalyzergui.ui create mode 100644 plugins/feature/demodanalyzer/demodanalyzer.cpp create mode 100644 plugins/feature/demodanalyzer/demodanalyzer.h create mode 100644 plugins/feature/demodanalyzer/demodanalyzergui.cpp create mode 100644 plugins/feature/demodanalyzer/demodanalyzergui.h create mode 100644 plugins/feature/demodanalyzer/demodanalyzergui.ui create mode 100644 plugins/feature/demodanalyzer/demodanalyzerplugin.cpp create mode 100644 plugins/feature/demodanalyzer/demodanalyzerplugin.h create mode 100644 plugins/feature/demodanalyzer/demodanalyzersettings.cpp create mode 100644 plugins/feature/demodanalyzer/demodanalyzersettings.h create mode 100644 plugins/feature/demodanalyzer/demodanalyzerwebapiadapter.cpp create mode 100644 plugins/feature/demodanalyzer/demodanalyzerwebapiadapter.h create mode 100644 plugins/feature/demodanalyzer/demodanalyzerworker.cpp create mode 100644 plugins/feature/demodanalyzer/demodanalyzerworker.h create mode 100644 sdrbase/resources/webapi/doc/swagger/include/DemodAnalyzer.yaml create mode 100644 swagger/sdrangel/api/swagger/include/DemodAnalyzer.yaml create mode 100644 swagger/sdrangel/code/qt5/client/SWGDemodAnalyzerSettings.cpp create mode 100644 swagger/sdrangel/code/qt5/client/SWGDemodAnalyzerSettings.h diff --git a/plugins/channelrx/demodam/amdemod.cpp b/plugins/channelrx/demodam/amdemod.cpp index 593086664..a47d73a9d 100644 --- a/plugins/channelrx/demodam/amdemod.cpp +++ b/plugins/channelrx/demodam/amdemod.cpp @@ -53,6 +53,7 @@ AMDemod::AMDemod(DeviceAPI *deviceAPI) : setObjectName(m_channelId); m_basebandSink = new AMDemodBaseband(); + m_basebandSink->setChannel(this); m_basebandSink->moveToThread(&m_thread); applySettings(m_settings, true); diff --git a/plugins/channelrx/demodam/amdemodbaseband.cpp b/plugins/channelrx/demodam/amdemodbaseband.cpp index 95fc606c4..76088bbd7 100644 --- a/plugins/channelrx/demodam/amdemodbaseband.cpp +++ b/plugins/channelrx/demodam/amdemodbaseband.cpp @@ -79,6 +79,11 @@ void AMDemodBaseband::stopWork() m_running = false; } +void AMDemodBaseband::setChannel(ChannelAPI *channel) +{ + m_sink.setChannel(channel); +} + void AMDemodBaseband::feed(const SampleVector::const_iterator& begin, const SampleVector::const_iterator& end) { m_sampleFifo.write(begin, end); diff --git a/plugins/channelrx/demodam/amdemodbaseband.h b/plugins/channelrx/demodam/amdemodbaseband.h index d3d6b4241..2b360f6fa 100644 --- a/plugins/channelrx/demodam/amdemodbaseband.h +++ b/plugins/channelrx/demodam/amdemodbaseband.h @@ -28,6 +28,7 @@ #include "amdemodsink.h" class DownChannelizer; +class ChannelAPI; class AMDemodBaseband : public QObject { @@ -71,6 +72,7 @@ public: double getMagSq() const { return m_sink.getMagSq(); } bool getPllLocked() const { return m_sink.getPllLocked(); } Real getPllFrequency() const { return m_sink.getPllFrequency(); } + void setChannel(ChannelAPI *channel); bool isRunning() const { return m_running; } private: @@ -90,4 +92,4 @@ private slots: void handleData(); //!< Handle data when samples have to be processed }; -#endif // INCLUDE_AMDEMODBASEBAND_H \ No newline at end of file +#endif // INCLUDE_AMDEMODBASEBAND_H diff --git a/plugins/channelrx/demodam/amdemodplugin.cpp b/plugins/channelrx/demodam/amdemodplugin.cpp index 6ff23d8db..a5d2790dd 100644 --- a/plugins/channelrx/demodam/amdemodplugin.cpp +++ b/plugins/channelrx/demodam/amdemodplugin.cpp @@ -11,7 +11,7 @@ const PluginDescriptor AMDemodPlugin::m_pluginDescriptor = { AMDemod::m_channelId, QStringLiteral("AM Demodulator"), - QStringLiteral("6.3.3"), + QStringLiteral("6.4.0"), QStringLiteral("(c) Edouard Griffiths, F4EXB"), QStringLiteral("https://github.com/f4exb/sdrangel"), true, diff --git a/plugins/channelrx/demodam/amdemodsink.cpp b/plugins/channelrx/demodam/amdemodsink.cpp index 72498b8f5..9f0cd8399 100644 --- a/plugins/channelrx/demodam/amdemodsink.cpp +++ b/plugins/channelrx/demodam/amdemodsink.cpp @@ -21,8 +21,11 @@ #include "audio/audiooutputdevice.h" #include "dsp/fftfilt.h" +#include "dsp/datafifo.h" #include "util/db.h" #include "util/stepfunctions.h" +#include "util/messagequeue.h" +#include "maincore.h" #include "amdemodsink.h" @@ -42,6 +45,8 @@ AMDemodSink::AMDemodSink() : { m_audioBuffer.resize(1<<14); m_audioBufferFill = 0; + m_demodBuffer.resize(1<<12); + m_demodBufferFill = 0; m_magsq = 0.0; @@ -219,6 +224,25 @@ void AMDemodSink::processOneSample(Complex &ci) m_audioBufferFill = 0; } + + m_demodBuffer[m_demodBufferFill] = sample; + ++m_demodBufferFill; + + if (m_demodBufferFill >= m_demodBuffer.size()) + { + QList *dataFifos = MainCore::instance()->getDataPipes().getFifos(m_channel, "demod"); + + if (dataFifos) + { + QList::iterator it = dataFifos->begin(); + + for (; it != dataFifos->end(); ++it) { + (*it)->write((quint8*) &m_demodBuffer[0], m_demodBuffer.size() * sizeof(qint16)); + } + } + + m_demodBufferFill = 0; + } } void AMDemodSink::applyChannelSettings(int channelSampleRate, int channelFrequencyOffset, bool force) @@ -323,5 +347,18 @@ void AMDemodSink::applyAudioSampleRate(int sampleRate) m_syncAMAGC.resize(sampleRate/4, sampleRate/8, 0.1); m_pll.setSampleRate(sampleRate); + QList *messageQueues = MainCore::instance()->getMessagePipes().getMessageQueues(m_channel, "reportdemod"); + + if (messageQueues) + { + QList::iterator it = messageQueues->begin(); + + for (; it != messageQueues->end(); ++it) + { + MainCore::MsgChannelDemodReport *msg = MainCore::MsgChannelDemodReport::create(m_channel, sampleRate); + (*it)->push(msg); + } + } + m_audioSampleRate = sampleRate; } diff --git a/plugins/channelrx/demodam/amdemodsink.h b/plugins/channelrx/demodam/amdemodsink.h index 8e5ee09f7..a2847328c 100644 --- a/plugins/channelrx/demodam/amdemodsink.h +++ b/plugins/channelrx/demodam/amdemodsink.h @@ -18,6 +18,8 @@ #ifndef INCLUDE_AMDEMODSINK_H #define INCLUDE_AMDEMODSINK_H +#include + #include "dsp/channelsamplesink.h" #include "dsp/nco.h" #include "dsp/interpolator.h" @@ -31,6 +33,7 @@ #include "amdemodsettings.h" class fftfilt; +class ChannelAPI; class AMDemodSink : public ChannelSampleSink { public: @@ -49,6 +52,7 @@ public: bool getPllLocked() const { return m_settings.m_pll && m_pll.locked(); } Real getPllFrequency() const { return m_pll.getFreq(); } AudioFifo *getAudioFifo() { return &m_audioFifo; } + void setChannel(ChannelAPI *channel) { m_channel = channel; } void getMagSqLevels(double& avg, double& peak, int& nbSamples) { @@ -87,6 +91,7 @@ private: int m_channelSampleRate; int m_channelFrequencyOffset; AMDemodSettings m_settings; + ChannelAPI *m_channel; int m_audioSampleRate; NCO m_nco; @@ -119,6 +124,8 @@ private: AudioVector m_audioBuffer; AudioFifo m_audioFifo; uint32_t m_audioBufferFill; + QVector m_demodBuffer; + int m_demodBufferFill; void processOneSample(Complex &ci); }; diff --git a/plugins/channeltx/modam/ammod.cpp b/plugins/channeltx/modam/ammod.cpp index 219673bd7..992f283b2 100644 --- a/plugins/channeltx/modam/ammod.cpp +++ b/plugins/channeltx/modam/ammod.cpp @@ -65,6 +65,7 @@ AMMod::AMMod(DeviceAPI *deviceAPI) : m_thread = new QThread(this); m_basebandSource = new AMModBaseband(); m_basebandSource->setInputFileStream(&m_ifstream); + m_basebandSource->setChannel(this); m_basebandSource->moveToThread(m_thread); applySettings(m_settings, true); diff --git a/plugins/channeltx/modam/ammodbaseband.cpp b/plugins/channeltx/modam/ammodbaseband.cpp index 82c1e5052..14d0ba1fe 100644 --- a/plugins/channeltx/modam/ammodbaseband.cpp +++ b/plugins/channeltx/modam/ammodbaseband.cpp @@ -62,6 +62,11 @@ void AMModBaseband::reset() m_sampleFifo.reset(); } +void AMModBaseband::setChannel(ChannelAPI *channel) +{ + m_source.setChannel(channel); +} + void AMModBaseband::pull(const SampleVector::iterator& begin, unsigned int nbSamples) { unsigned int part1Begin, part1End, part2Begin, part2End; @@ -226,4 +231,4 @@ void AMModBaseband::applySettings(const AMModSettings& settings, bool force) int AMModBaseband::getChannelSampleRate() const { return m_channelizer->getChannelSampleRate(); -} \ No newline at end of file +} diff --git a/plugins/channeltx/modam/ammodbaseband.h b/plugins/channeltx/modam/ammodbaseband.h index 5094ac10b..785eedf72 100644 --- a/plugins/channeltx/modam/ammodbaseband.h +++ b/plugins/channeltx/modam/ammodbaseband.h @@ -28,6 +28,7 @@ #include "ammodsource.h" class UpChannelizer; +class ChannelAPI; class AMModBaseband : public QObject { @@ -69,6 +70,7 @@ public: void setInputFileStream(std::ifstream *ifstream) { m_source.setInputFileStream(ifstream); } AudioFifo *getAudioFifo() { return m_source.getAudioFifo(); } AudioFifo *getFeedbackAudioFifo() { return m_source.getFeedbackAudioFifo(); } + void setChannel(ChannelAPI *channel); signals: /** diff --git a/plugins/channeltx/modam/ammodplugin.cpp b/plugins/channeltx/modam/ammodplugin.cpp index f8f2361db..80767fd31 100644 --- a/plugins/channeltx/modam/ammodplugin.cpp +++ b/plugins/channeltx/modam/ammodplugin.cpp @@ -28,7 +28,7 @@ const PluginDescriptor AMModPlugin::m_pluginDescriptor = { AMMod::m_channelId, QStringLiteral("AM Modulator"), - QStringLiteral("6.3.3"), + QStringLiteral("6.4.0"), QStringLiteral("(c) Edouard Griffiths, F4EXB"), QStringLiteral("https://github.com/f4exb/sdrangel"), true, diff --git a/plugins/channeltx/modam/ammodsource.cpp b/plugins/channeltx/modam/ammodsource.cpp index ef7912f92..734eb662f 100644 --- a/plugins/channeltx/modam/ammodsource.cpp +++ b/plugins/channeltx/modam/ammodsource.cpp @@ -17,6 +17,10 @@ #include +#include "dsp/datafifo.h" +#include "util/messagequeue.h" +#include "maincore.h" + #include "ammodsource.h" const int AMModSource::m_levelNbSamples = 480; // every 10ms @@ -37,9 +41,11 @@ AMModSource::AMModSource() : m_audioBufferFill = 0; m_audioReadBuffer.resize(24000); m_audioReadBufferFill = 0; - m_feedbackAudioBuffer.resize(1<<14); m_feedbackAudioBufferFill = 0; + m_demodBuffer.resize(1<<12); + m_demodBufferFill = 0; + m_demodBufferEnabled = false; m_magsq = 0.0; @@ -100,6 +106,25 @@ void AMModSource::pullOne(Sample& sample) sample.m_real = (FixReal) ci.real(); sample.m_imag = (FixReal) ci.imag(); + + m_demodBuffer[m_demodBufferFill] = ci.real() + ci.imag(); + ++m_demodBufferFill; + + if (m_demodBufferFill >= m_demodBuffer.size()) + { + QList *dataFifos = MainCore::instance()->getDataPipes().getFifos(m_channel, "demod"); + + if (dataFifos) + { + QList::iterator it = dataFifos->begin(); + + for (; it != dataFifos->end(); ++it) { + (*it)->write((quint8*) &m_demodBuffer[0], m_demodBuffer.size() * sizeof(qint16)); + } + } + + m_demodBufferFill = 0; + } } void AMModSource::prefetch(unsigned int nbSamples) @@ -289,6 +314,20 @@ void AMModSource::applyAudioSampleRate(int sampleRate) m_toneNco.setFreq(m_settings.m_toneFrequency, sampleRate); m_cwKeyer.setSampleRate(sampleRate); m_cwKeyer.reset(); + + QList *messageQueues = MainCore::instance()->getMessagePipes().getMessageQueues(m_channel, "reportdemod"); + + if (messageQueues) + { + QList::iterator it = messageQueues->begin(); + + for (; it != messageQueues->end(); ++it) + { + MainCore::MsgChannelDemodReport *msg = MainCore::MsgChannelDemodReport::create(m_channel, sampleRate); + (*it)->push(msg); + } + } + m_audioSampleRate = sampleRate; applyFeedbackAudioSampleRate(m_feedbackAudioSampleRate); } diff --git a/plugins/channeltx/modam/ammodsource.h b/plugins/channeltx/modam/ammodsource.h index 3ff5bb14d..56ce84b5b 100644 --- a/plugins/channeltx/modam/ammodsource.h +++ b/plugins/channeltx/modam/ammodsource.h @@ -34,6 +34,8 @@ #include "ammodsettings.h" +class ChannelAPI; + class AMModSource : public QObject, public ChannelSampleSource { Q_OBJECT @@ -48,6 +50,7 @@ public: void setInputFileStream(std::ifstream *ifstream) { m_ifstream = ifstream; } AudioFifo *getAudioFifo() { return &m_audioFifo; } AudioFifo *getFeedbackAudioFifo() { return &m_feedbackAudioFifo; } + void setChannel(ChannelAPI *channel) { m_channel = channel; } void applyAudioSampleRate(int sampleRate); void applyFeedbackAudioSampleRate(int sampleRate); int getAudioSampleRate() const { return m_audioSampleRate; } @@ -67,6 +70,7 @@ private: int m_channelSampleRate; int m_channelFrequencyOffset; AMModSettings m_settings; + ChannelAPI *m_channel; NCO m_carrierNco; NCOF m_toneNco; @@ -96,6 +100,9 @@ private: AudioVector m_feedbackAudioBuffer; uint m_feedbackAudioBufferFill; AudioFifo m_feedbackAudioFifo; + QVector m_demodBuffer; + int m_demodBufferFill; + bool m_demodBufferEnabled; quint32 m_levelCalcCount; qreal m_rmsLevel; diff --git a/plugins/feature/CMakeLists.txt b/plugins/feature/CMakeLists.txt index e2ac16f86..b9a1b553d 100644 --- a/plugins/feature/CMakeLists.txt +++ b/plugins/feature/CMakeLists.txt @@ -9,5 +9,6 @@ if (Qt5Quick_FOUND AND Qt5QuickWidgets_FOUND AND Qt5Positioning_FOUND) endif() add_subdirectory(afc) +add_subdirectory(demodanalyzer) add_subdirectory(rigctlserver) add_subdirectory(simpleptt) diff --git a/plugins/feature/afc/afc.cpp b/plugins/feature/afc/afc.cpp index 7e3fbaf05..7af948f64 100644 --- a/plugins/feature/afc/afc.cpp +++ b/plugins/feature/afc/afc.cpp @@ -584,8 +584,11 @@ void AFC::removeTrackerFeatureReference() { if (m_trackerChannelAPI) { - if (MainCore::instance()->existsChannel(m_trackerChannelAPI)) { - MainCore::instance()->getMessagePipes().unregisterChannelToFeature(m_trackerChannelAPI, this, "settings"); + if (MainCore::instance()->existsChannel(m_trackerChannelAPI)) + { + MessageQueue *messageQueue + = MainCore::instance()->getMessagePipes().unregisterChannelToFeature(m_trackerChannelAPI, this, "settings"); + disconnect(messageQueue, SIGNAL(messageEnqueued()), this, SLOT(handleChannelMessageQueue(MessageQueue*))); } } } diff --git a/plugins/feature/afc/afcplugin.cpp b/plugins/feature/afc/afcplugin.cpp index ee1d1f402..1c6ffad25 100644 --- a/plugins/feature/afc/afcplugin.cpp +++ b/plugins/feature/afc/afcplugin.cpp @@ -29,7 +29,7 @@ const PluginDescriptor AFCPlugin::m_pluginDescriptor = { AFC::m_featureId, QStringLiteral("AFC"), - QStringLiteral("6.3.3"), + QStringLiteral("6.4.0"), QStringLiteral("(c) Edouard Griffiths, F4EXB"), QStringLiteral("https://github.com/f4exb/sdrangel"), true, diff --git a/plugins/feature/demodanalyzer/CMakeLists.txt b/plugins/feature/demodanalyzer/CMakeLists.txt new file mode 100644 index 000000000..b8fd32004 --- /dev/null +++ b/plugins/feature/demodanalyzer/CMakeLists.txt @@ -0,0 +1,56 @@ +project(demodanalyzer) + +set(demodanalyzer_SOURCES + demodanalyzer.cpp + demodanalyzersettings.cpp + demodanalyzerplugin.cpp + demodanalyzerworker.cpp + demodanalyzerwebapiadapter.cpp +) + +set(demodanalyzer_HEADERS + demodanalyzer.h + demodanalyzersettings.h + demodanalyzerplugin.h + demodanalyzerworker.h + demodanalyzerwebapiadapter.h +) + +include_directories( + ${CMAKE_SOURCE_DIR}/swagger/sdrangel/code/qt5/client +) + +if(NOT SERVER_MODE) + set(demodanalyzer_SOURCES + ${demodanalyzer_SOURCES} + demodanalyzergui.cpp + demodanalyzergui.ui + ) + set(demodanalyzer_HEADERS + ${demodanalyzer_HEADERS} + demodanalyzergui.h + ) + + set(TARGET_NAME featuredemodanalyzer) + set(TARGET_LIB "Qt5::Widgets") + set(TARGET_LIB_GUI "sdrgui") + set(INSTALL_FOLDER ${INSTALL_PLUGINS_DIR}) +else() + set(TARGET_NAME featuredemodanalyzersrv) + set(TARGET_LIB "") + set(TARGET_LIB_GUI "") + set(INSTALL_FOLDER ${INSTALL_PLUGINSSRV_DIR}) +endif() + +add_library(${TARGET_NAME} SHARED + ${demodanalyzer_SOURCES} +) + +target_link_libraries(${TARGET_NAME} + Qt5::Core + ${TARGET_LIB} + sdrbase + ${TARGET_LIB_GUI} +) + +install(TARGETS ${TARGET_NAME} DESTINATION ${INSTALL_FOLDER}) diff --git a/plugins/feature/demodanalyzer/demodalyzergui.ui b/plugins/feature/demodanalyzer/demodalyzergui.ui new file mode 100644 index 000000000..b0f3ff01c --- /dev/null +++ b/plugins/feature/demodanalyzer/demodalyzergui.ui @@ -0,0 +1,346 @@ + + + DemodAnalyzerGUI + + + + 0 + 0 + 739 + 778 + + + + + 720 + 0 + + + + + Liberation Sans + 9 + + + + Demod Analyzer + + + + + 0 + 10 + 631 + 41 + + + + Settings + + + + 3 + + + 2 + + + 2 + + + 2 + + + 2 + + + + + 2 + + + + + start/stop acquisition + + + + + + + :/play.png + :/stop.png:/play.png + + + + + + + + 24 + 16777215 + + + + Refresh indexes of available device sets + + + + + + + :/recycle.png:/recycle.png + + + + + + + Chan + + + + + + + + 200 + 0 + + + + Channel index + + + + + + + + 24 + 24 + + + + Reinitialization of device data + + + + + + + :/checkmark.png:/checkmark.png + + + + + + + + 80 + 0 + + + + Analyzer (sink) sample rate + + + 00000.0 kS/s + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 52 + 0 + + + + Channel power + + + Qt::LeftToRight + + + -100.0 dB + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + + + + 0 + 98 + 720 + 284 + + + + + 716 + 0 + + + + Channel Spectrum + + + + 2 + + + 2 + + + 2 + + + 2 + + + 2 + + + + + + 200 + 250 + + + + + Liberation Mono + 8 + + + + + + + + + + + + + 0 + 390 + 720 + 334 + + + + + 716 + 0 + + + + Channel Scope + + + + 2 + + + 3 + + + 3 + + + 3 + + + 3 + + + + + + 200 + 300 + + + + + Liberation Mono + 8 + + + + + + + + + + + + + RollupWidget + QWidget +
gui/rollupwidget.h
+ 1 +
+ + GLSpectrum + QWidget +
gui/glspectrum.h
+ 1 +
+ + GLSpectrumGUI + QWidget +
gui/glspectrumgui.h
+ 1 +
+ + ButtonSwitch + QToolButton +
gui/buttonswitch.h
+
+ + GLScope + QWidget +
gui/glscope.h
+ 1 +
+ + GLScopeGUI + QWidget +
gui/glscopegui.h
+ 1 +
+
+ + + + +
diff --git a/plugins/feature/demodanalyzer/demodanalyzer.cpp b/plugins/feature/demodanalyzer/demodanalyzer.cpp new file mode 100644 index 000000000..ff9cfac9b --- /dev/null +++ b/plugins/feature/demodanalyzer/demodanalyzer.cpp @@ -0,0 +1,535 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2020 Edouard Griffiths, F4EXB // +// // +// 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 // +// (at your option) any later version. // +// // +// This program is distributed in the hope that it will be useful, // +// but WITHOUT ANY WARRANTY; without even the implied warranty of // +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // +// GNU General Public License V3 for more details. // +// // +// You should have received a copy of the GNU General Public License // +// along with this program. If not, see . // +/////////////////////////////////////////////////////////////////////////////////// + +#include +#include +#include +#include + +#include "SWGFeatureSettings.h" +#include "SWGFeatureActions.h" +#include "SWGDeviceState.h" + +#include "dsp/dspengine.h" +#include "dsp/datafifo.h" +#include "dsp/dspdevicesourceengine.h" +#include "dsp/devicesamplesource.h" +#include "device/deviceset.h" +#include "channel/channelapi.h" +#include "maincore.h" + +#include "demodanalyzerworker.h" +#include "demodanalyzer.h" + +MESSAGE_CLASS_DEFINITION(DemodAnalyzer::MsgConfigureDemodAnalyzer, Message) +MESSAGE_CLASS_DEFINITION(DemodAnalyzer::MsgStartStop, Message) +MESSAGE_CLASS_DEFINITION(DemodAnalyzer::MsgRefreshChannels, Message) +MESSAGE_CLASS_DEFINITION(DemodAnalyzer::MsgReportChannels, Message) +MESSAGE_CLASS_DEFINITION(DemodAnalyzer::MsgSelectChannel, Message) +MESSAGE_CLASS_DEFINITION(DemodAnalyzer::MsgReportSampleRate, Message) + +const char* const DemodAnalyzer::m_featureIdURI = "sdrangel.feature.demodanalyzer"; +const char* const DemodAnalyzer::m_featureId = "DemodAnalyzer"; + +DemodAnalyzer::DemodAnalyzer(WebAPIAdapterInterface *webAPIAdapterInterface) : + Feature(m_featureIdURI, webAPIAdapterInterface), + m_spectrumVis(SDR_RX_SCALEF), + m_selectedChannel(nullptr), + m_dataFifo(nullptr) +{ + qDebug("DemodAnalyzer::DemodAnalyzer: webAPIAdapterInterface: %p", webAPIAdapterInterface); + setObjectName(m_featureId); + m_worker = new DemodAnalyzerWorker(); + m_state = StIdle; + m_errorMessage = "DemodAnalyzer error"; +} + +DemodAnalyzer::~DemodAnalyzer() +{ + if (m_worker->isRunning()) { + stop(); + } + + delete m_worker; +} + +void DemodAnalyzer::start() +{ + qDebug("DemodAnalyzer::start"); + + m_worker->setMessageQueueToFeature(getInputMessageQueue()); + m_worker->reset(); + bool ok = m_worker->startWork(); + m_state = ok ? StRunning : StError; + m_thread.start(); + + DemodAnalyzerWorker::MsgConfigureDemodAnalyzerWorker *msg + = DemodAnalyzerWorker::MsgConfigureDemodAnalyzerWorker::create(m_settings, true); + m_worker->getInputMessageQueue()->push(msg); + + if (m_dataFifo) + { + DemodAnalyzerWorker::MsgConnectFifo *msg = DemodAnalyzerWorker::MsgConnectFifo::create(m_dataFifo, true); + m_worker->getInputMessageQueue()->push(msg); + } +} + +void DemodAnalyzer::stop() +{ + qDebug("DemodAnalyzer::stop"); + + if (m_dataFifo) + { + DemodAnalyzerWorker::MsgConnectFifo *msg = DemodAnalyzerWorker::MsgConnectFifo::create(m_dataFifo, false); + m_worker->getInputMessageQueue()->push(msg); + } + + m_worker->stopWork(); + m_state = StIdle; + m_thread.quit(); + m_thread.wait(); +} + +void DemodAnalyzer::setSampleSink(BasebandSampleSink *sink) +{ + m_worker->setSampleSink(sink); +} + +double DemodAnalyzer::getMagSqAvg() const +{ + return m_worker->getMagSqAvg(); +} + +bool DemodAnalyzer::handleMessage(const Message& cmd) +{ + if (MsgConfigureDemodAnalyzer::match(cmd)) + { + MsgConfigureDemodAnalyzer& cfg = (MsgConfigureDemodAnalyzer&) cmd; + qDebug() << "DemodAnalyzer::handleMessage: MsgConfigureDemodAnalyzer"; + applySettings(cfg.getSettings(), cfg.getForce()); + + return true; + } + else if (MsgStartStop::match(cmd)) + { + MsgStartStop& cfg = (MsgStartStop&) cmd; + qDebug() << "DemodAnalyzer::handleMessage: MsgStartStop: start:" << cfg.getStartStop(); + + if (cfg.getStartStop()) { + start(); + } else { + stop(); + } + + return true; + } + else if (MsgRefreshChannels::match(cmd)) + { + qDebug() << "DemodAnalyzer::handleMessage: MsgRefreshChannels"; + updateChannels(); + return true; + } + else if (MsgSelectChannel::match(cmd)) + { + qDebug() << "DemodAnalyzer::handleMessage: MsgSelectChannel"; + MsgSelectChannel& cfg = (MsgSelectChannel&) cmd; + ChannelAPI *selectedChannel = cfg.getChannel(); + setChannel(selectedChannel); + + return true; + } + else if (MainCore::MsgChannelDemodReport::match(cmd)) + { + qDebug() << "DemodAnalyzer::handleMessage: MainCore::MsgChannelDemodReport"; + MainCore::MsgChannelDemodReport& report = (MainCore::MsgChannelDemodReport&) cmd; + + if (report.getChannelAPI() == m_selectedChannel) + { + m_sampleRate = report.getSampleRate(); + + if (m_dataFifo) { + m_dataFifo->setSize(2*m_sampleRate); + } + + if (getMessageQueueToGUI()) + { + MsgReportSampleRate *msg = MsgReportSampleRate::create(m_sampleRate); + getMessageQueueToGUI()->push(msg); + } + } + + return true; + } + else + { + return false; + } +} + +QByteArray DemodAnalyzer::serialize() const +{ + return m_settings.serialize(); +} + +bool DemodAnalyzer::deserialize(const QByteArray& data) +{ + if (m_settings.deserialize(data)) + { + MsgConfigureDemodAnalyzer *msg = MsgConfigureDemodAnalyzer::create(m_settings, true); + m_inputMessageQueue.push(msg); + return true; + } + else + { + m_settings.resetToDefaults(); + MsgConfigureDemodAnalyzer *msg = MsgConfigureDemodAnalyzer::create(m_settings, true); + m_inputMessageQueue.push(msg); + return false; + } +} + +void DemodAnalyzer::applySettings(const DemodAnalyzerSettings& settings, bool force) +{ + qDebug() << "DemodAnalyzer::applySettings:" + << " m_deviceIndex: " << settings.m_deviceIndex + << " m_channelIndex: " << settings.m_channelIndex + << " m_title: " << settings.m_title + << " m_rgbColor: " << settings.m_rgbColor + << " m_useReverseAPI: " << settings.m_useReverseAPI + << " m_reverseAPIAddress: " << settings.m_reverseAPIAddress + << " m_reverseAPIPort: " << settings.m_reverseAPIPort + << " m_reverseAPIFeatureSetIndex: " << settings.m_reverseAPIFeatureSetIndex + << " m_reverseAPIFeatureIndex: " << settings.m_reverseAPIFeatureIndex + << " force: " << force; + + QList reverseAPIKeys; + + if ((m_settings.m_deviceIndex != settings.m_deviceIndex) || force) { + reverseAPIKeys.append("deviceIndex"); + } + if ((m_settings.m_channelIndex != settings.m_channelIndex) || force) { + reverseAPIKeys.append("channelIndex"); + } + if ((m_settings.m_title != settings.m_title) || force) { + reverseAPIKeys.append("title"); + } + if ((m_settings.m_rgbColor != settings.m_rgbColor) || force) { + reverseAPIKeys.append("rgbColor"); + } + + DemodAnalyzerWorker::MsgConfigureDemodAnalyzerWorker *msg = DemodAnalyzerWorker::MsgConfigureDemodAnalyzerWorker::create( + settings, force + ); + m_worker->getInputMessageQueue()->push(msg); + + if (settings.m_useReverseAPI) + { + bool fullUpdate = ((m_settings.m_useReverseAPI != settings.m_useReverseAPI) && settings.m_useReverseAPI) || + (m_settings.m_reverseAPIAddress != settings.m_reverseAPIAddress) || + (m_settings.m_reverseAPIPort != settings.m_reverseAPIPort) || + (m_settings.m_reverseAPIFeatureSetIndex != settings.m_reverseAPIFeatureSetIndex) || + (m_settings.m_reverseAPIFeatureIndex != settings.m_reverseAPIFeatureIndex); + webapiReverseSendSettings(reverseAPIKeys, settings, fullUpdate || force); + } + + m_settings = settings; +} + +void DemodAnalyzer::updateChannels() +{ + MainCore *mainCore = MainCore::instance(); + // MessagePipes& messagePipes = mainCore->getMessagePipes(); + std::vector& deviceSets = mainCore->getDeviceSets(); + std::vector::const_iterator it = deviceSets.begin(); + m_availableChannels.clear(); + + int deviceIndex = 0; + + for (; it != deviceSets.end(); ++it, deviceIndex++) + { + DSPDeviceSourceEngine *deviceSourceEngine = (*it)->m_deviceSourceEngine; + DSPDeviceSinkEngine *deviceSinkEngine = (*it)->m_deviceSinkEngine; + + if (deviceSourceEngine || deviceSinkEngine) + { + // DeviceSampleSource *deviceSource = deviceSourceEngine->getSource(); + // quint64 deviceCenterFrequency = deviceSource->getCenterFrequency(); + // int basebandSampleRate = deviceSource->getSampleRate(); + + for (int chi = 0; chi < (*it)->getNumberOfChannels(); chi++) + { + ChannelAPI *channel = (*it)->getChannelAt(chi); + int i = DemodAnalyzerSettings::m_channelURIs.indexOf(channel->getURI()); + + if (i >= 0) + { + DemodAnalyzerSettings::AvailableChannel availableChannel = + DemodAnalyzerSettings::AvailableChannel{ + deviceSinkEngine != nullptr, + deviceIndex, + chi, + channel, + DemodAnalyzerSettings::m_channelTypes.at(i) + }; + m_availableChannels[channel] = availableChannel; + } + } + } + } + + if (getMessageQueueToGUI()) + { + MsgReportChannels *msgToGUI = MsgReportChannels::create(); + QList& msgAvailableChannels = msgToGUI->getAvailableChannels(); + QHash::iterator it = m_availableChannels.begin(); + + for (; it != m_availableChannels.end(); ++it) { + msgAvailableChannels.push_back(*it); + } + + getMessageQueueToGUI()->push(msgToGUI); + } +} + +void DemodAnalyzer::setChannel(ChannelAPI *selectedChannel) +{ + if ((selectedChannel == m_selectedChannel) || !m_availableChannels.contains(selectedChannel)) { + return; + } + + MainCore *mainCore = MainCore::instance(); + + if (m_selectedChannel) + { + DataFifo *fifo = mainCore->getDataPipes().unregisterChannelToFeature(m_selectedChannel, this, "demod"); + + if ((fifo) && m_worker->isRunning()) + { + DemodAnalyzerWorker::MsgConnectFifo *msg = DemodAnalyzerWorker::MsgConnectFifo::create(fifo, false); + m_worker->getInputMessageQueue()->push(msg); + } + + MessageQueue *messageQueue = mainCore->getMessagePipes().unregisterChannelToFeature(m_selectedChannel, this, "reportdemod"); + disconnect(messageQueue, SIGNAL(messageEnqueued()), this, SLOT(handleChannelMessageQueue(MessageQueue*))); + } + + m_dataFifo = mainCore->getDataPipes().registerChannelToFeature(selectedChannel, this, "demod"); + m_dataFifo->setSize(96000); + + if (m_worker->isRunning()) + { + DemodAnalyzerWorker::MsgConnectFifo *msg = DemodAnalyzerWorker::MsgConnectFifo::create(m_dataFifo, true); + m_worker->getInputMessageQueue()->push(msg); + } + + MessageQueue *messageQueue = mainCore->getMessagePipes().registerChannelToFeature(selectedChannel, this, "reportdemod"); + + QObject::connect( + messageQueue, + &MessageQueue::messageEnqueued, + this, + [=](){ this->handleChannelMessageQueue(messageQueue); }, + Qt::QueuedConnection + ); + + m_selectedChannel = selectedChannel; +} + +int DemodAnalyzer::webapiRun(bool run, + SWGSDRangel::SWGDeviceState& response, + QString& errorMessage) +{ + (void) errorMessage; + getFeatureStateStr(*response.getState()); + MsgStartStop *msg = MsgStartStop::create(run); + getInputMessageQueue()->push(msg); + return 202; +} + +int DemodAnalyzer::webapiSettingsGet( + SWGSDRangel::SWGFeatureSettings& response, + QString& errorMessage) +{ + (void) errorMessage; + response.setDemodAnalyzerSettings(new SWGSDRangel::SWGDemodAnalyzerSettings()); + response.getDemodAnalyzerSettings()->init(); + webapiFormatFeatureSettings(response, m_settings); + return 200; +} + +int DemodAnalyzer::webapiSettingsPutPatch( + bool force, + const QStringList& featureSettingsKeys, + SWGSDRangel::SWGFeatureSettings& response, + QString& errorMessage) +{ + (void) errorMessage; + DemodAnalyzerSettings settings = m_settings; + webapiUpdateFeatureSettings(settings, featureSettingsKeys, response); + + MsgConfigureDemodAnalyzer *msg = MsgConfigureDemodAnalyzer::create(settings, force); + m_inputMessageQueue.push(msg); + + qDebug("DemodAnalyzer::webapiSettingsPutPatch: forward to GUI: %p", m_guiMessageQueue); + if (m_guiMessageQueue) // forward to GUI if any + { + MsgConfigureDemodAnalyzer *msgToGUI = MsgConfigureDemodAnalyzer::create(settings, force); + m_guiMessageQueue->push(msgToGUI); + } + + webapiFormatFeatureSettings(response, settings); + + return 200; +} + +void DemodAnalyzer::webapiFormatFeatureSettings( + SWGSDRangel::SWGFeatureSettings& response, + const DemodAnalyzerSettings& settings) +{ + response.getDemodAnalyzerSettings()->setDeviceIndex(settings.m_deviceIndex); + response.getDemodAnalyzerSettings()->setChannelIndex(settings.m_channelIndex); + + if (response.getDemodAnalyzerSettings()->getTitle()) { + *response.getDemodAnalyzerSettings()->getTitle() = settings.m_title; + } else { + response.getDemodAnalyzerSettings()->setTitle(new QString(settings.m_title)); + } + + response.getDemodAnalyzerSettings()->setRgbColor(settings.m_rgbColor); + response.getDemodAnalyzerSettings()->setUseReverseApi(settings.m_useReverseAPI ? 1 : 0); + + if (response.getDemodAnalyzerSettings()->getReverseApiAddress()) { + *response.getDemodAnalyzerSettings()->getReverseApiAddress() = settings.m_reverseAPIAddress; + } else { + response.getDemodAnalyzerSettings()->setReverseApiAddress(new QString(settings.m_reverseAPIAddress)); + } + + response.getDemodAnalyzerSettings()->setReverseApiPort(settings.m_reverseAPIPort); + response.getDemodAnalyzerSettings()->setReverseApiDeviceIndex(settings.m_reverseAPIFeatureSetIndex); + response.getDemodAnalyzerSettings()->setReverseApiChannelIndex(settings.m_reverseAPIFeatureIndex); +} + +void DemodAnalyzer::webapiUpdateFeatureSettings( + DemodAnalyzerSettings& settings, + const QStringList& featureSettingsKeys, + SWGSDRangel::SWGFeatureSettings& response) +{ + if (featureSettingsKeys.contains("deviceIndex")) { + settings.m_deviceIndex = response.getDemodAnalyzerSettings()->getDeviceIndex(); + } + if (featureSettingsKeys.contains("channelIndex")) { + settings.m_channelIndex = response.getDemodAnalyzerSettings()->getChannelIndex(); + } + if (featureSettingsKeys.contains("title")) { + settings.m_title = *response.getDemodAnalyzerSettings()->getTitle(); + } + if (featureSettingsKeys.contains("rgbColor")) { + settings.m_rgbColor = response.getDemodAnalyzerSettings()->getRgbColor(); + } + if (featureSettingsKeys.contains("useReverseAPI")) { + settings.m_useReverseAPI = response.getDemodAnalyzerSettings()->getUseReverseApi() != 0; + } + if (featureSettingsKeys.contains("reverseAPIAddress")) { + settings.m_reverseAPIAddress = *response.getDemodAnalyzerSettings()->getReverseApiAddress(); + } + if (featureSettingsKeys.contains("reverseAPIPort")) { + settings.m_reverseAPIPort = response.getDemodAnalyzerSettings()->getReverseApiPort(); + } + if (featureSettingsKeys.contains("reverseAPIDeviceIndex")) { + settings.m_reverseAPIFeatureSetIndex = response.getDemodAnalyzerSettings()->getReverseApiDeviceIndex(); + } + if (featureSettingsKeys.contains("reverseAPIChannelIndex")) { + settings.m_reverseAPIFeatureIndex = response.getDemodAnalyzerSettings()->getReverseApiChannelIndex(); + } +} + +void DemodAnalyzer::webapiReverseSendSettings(QList& featureSettingsKeys, const DemodAnalyzerSettings& settings, bool force) +{ + SWGSDRangel::SWGFeatureSettings *swgFeatureSettings = new SWGSDRangel::SWGFeatureSettings(); + // swgFeatureSettings->setOriginatorFeatureIndex(getIndexInDeviceSet()); + // swgFeatureSettings->setOriginatorFeatureSetIndex(getDeviceSetIndex()); + swgFeatureSettings->setFeatureType(new QString("DemodAnalyzer")); + swgFeatureSettings->setDemodAnalyzerSettings(new SWGSDRangel::SWGDemodAnalyzerSettings()); + SWGSDRangel::SWGDemodAnalyzerSettings *swgDemodAnalyzerSettings = swgFeatureSettings->getDemodAnalyzerSettings(); + + // transfer data that has been modified. When force is on transfer all data except reverse API data + + if (featureSettingsKeys.contains("deviceIndex") || force) { + swgDemodAnalyzerSettings->setDeviceIndex(settings.m_deviceIndex); + } + if (featureSettingsKeys.contains("channelIndex") || force) { + swgDemodAnalyzerSettings->setChannelIndex(settings.m_channelIndex); + } + if (featureSettingsKeys.contains("title") || force) { + swgDemodAnalyzerSettings->setTitle(new QString(settings.m_title)); + } + if (featureSettingsKeys.contains("rgbColor") || force) { + swgDemodAnalyzerSettings->setRgbColor(settings.m_rgbColor); + } + + QString channelSettingsURL = QString("http://%1:%2/sdrangel/featureset/%3/feature/%4/settings") + .arg(settings.m_reverseAPIAddress) + .arg(settings.m_reverseAPIPort) + .arg(settings.m_reverseAPIFeatureSetIndex) + .arg(settings.m_reverseAPIFeatureIndex); + m_networkRequest.setUrl(QUrl(channelSettingsURL)); + m_networkRequest.setHeader(QNetworkRequest::ContentTypeHeader, "application/json"); + + QBuffer *buffer = new QBuffer(); + buffer->open((QBuffer::ReadWrite)); + buffer->write(swgFeatureSettings->asJson().toUtf8()); + buffer->seek(0); + + // Always use PATCH to avoid passing reverse API settings + QNetworkReply *reply = m_networkManager->sendCustomRequest(m_networkRequest, "PATCH", buffer); + buffer->setParent(reply); + + delete swgFeatureSettings; +} + +void DemodAnalyzer::networkManagerFinished(QNetworkReply *reply) +{ + QNetworkReply::NetworkError replyError = reply->error(); + + if (replyError) + { + qWarning() << "DemodAnalyzer::networkManagerFinished:" + << " error(" << (int) replyError + << "): " << replyError + << ": " << reply->errorString(); + } + else + { + QString answer = reply->readAll(); + answer.chop(1); // remove last \n + qDebug("DemodAnalyzer::networkManagerFinished: reply:\n%s", answer.toStdString().c_str()); + } + + reply->deleteLater(); +} + +void DemodAnalyzer::handleChannelMessageQueue(MessageQueue* messageQueue) +{ + Message* message; + + while ((message = messageQueue->pop()) != nullptr) + { + if (handleMessage(*message)) { + delete message; + } + } +} diff --git a/plugins/feature/demodanalyzer/demodanalyzer.h b/plugins/feature/demodanalyzer/demodanalyzer.h new file mode 100644 index 000000000..7f92a7a50 --- /dev/null +++ b/plugins/feature/demodanalyzer/demodanalyzer.h @@ -0,0 +1,220 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2020 Edouard Griffiths, F4EXB // +// // +// 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 // +// (at your option) any later version. // +// // +// 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 INCLUDE_FEATURE_DEMODANALYZER_H_ +#define INCLUDE_FEATURE_DEMODANALYZER_H_ + +#include +#include +#include + +#include "feature/feature.h" +#include "util/message.h" +#include "dsp/spectrumvis.h" + +#include "demodanalyzersettings.h" + +class WebAPIAdapterInterface; +class DemodAnalyzerWorker; +class QNetworkAccessManager; +class QNetworkReply; +class DataFifo; + +namespace SWGSDRangel { + class SWGDeviceState; +} + +class DemodAnalyzer : public Feature +{ + Q_OBJECT +public: + class MsgConfigureDemodAnalyzer : public Message { + MESSAGE_CLASS_DECLARATION + + public: + const DemodAnalyzerSettings& getSettings() const { return m_settings; } + bool getForce() const { return m_force; } + + static MsgConfigureDemodAnalyzer* create(const DemodAnalyzerSettings& settings, bool force) { + return new MsgConfigureDemodAnalyzer(settings, force); + } + + private: + DemodAnalyzerSettings m_settings; + bool m_force; + + MsgConfigureDemodAnalyzer(const DemodAnalyzerSettings& settings, bool force) : + Message(), + m_settings(settings), + m_force(force) + { } + }; + + 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 MsgRefreshChannels : public Message { + MESSAGE_CLASS_DECLARATION + + public: + static MsgRefreshChannels* create() { + return new MsgRefreshChannels(); + } + + protected: + MsgRefreshChannels() : + Message() + { } + }; + + class MsgReportChannels : public Message { + MESSAGE_CLASS_DECLARATION + + public: + QList& getAvailableChannels() { return m_availableChannels; } + + static MsgReportChannels* create() { + return new MsgReportChannels(); + } + + private: + QList m_availableChannels; + + MsgReportChannels() : + Message() + {} + }; + + class MsgSelectChannel : public Message { + MESSAGE_CLASS_DECLARATION + + public: + ChannelAPI *getChannel() { return m_channel; } + static MsgSelectChannel* create(ChannelAPI *channel) { + return new MsgSelectChannel(channel); + } + + protected: + ChannelAPI *m_channel; + + MsgSelectChannel(ChannelAPI *channel) : + Message(), + m_channel(channel) + { } + }; + + class MsgReportSampleRate : public Message { + MESSAGE_CLASS_DECLARATION + + public: + int getSampleRate() const { return m_sampleRate; } + + static MsgReportSampleRate* create(int sampleRate) { + return new MsgReportSampleRate(sampleRate); + } + + private: + int m_sampleRate; + + MsgReportSampleRate(int sampleRate) : + Message(), + m_sampleRate(sampleRate) + {} + }; + + DemodAnalyzer(WebAPIAdapterInterface *webAPIAdapterInterface); + virtual ~DemodAnalyzer(); + virtual void destroy() { delete this; } + SpectrumVis *getSpectrumVis() { return &m_spectrumVis; } + void setSampleSink(BasebandSampleSink *sink); + double getMagSqAvg() const; + virtual bool handleMessage(const Message& cmd); + + virtual void getIdentifier(QString& id) const { id = objectName(); } + virtual void getTitle(QString& title) const { title = m_settings.m_title; } + + virtual QByteArray serialize() const; + virtual bool deserialize(const QByteArray& data); + + virtual int webapiRun(bool run, + SWGSDRangel::SWGDeviceState& response, + QString& errorMessage); + + virtual int webapiSettingsGet( + SWGSDRangel::SWGFeatureSettings& response, + QString& errorMessage); + + virtual int webapiSettingsPutPatch( + bool force, + const QStringList& featureSettingsKeys, + SWGSDRangel::SWGFeatureSettings& response, + QString& errorMessage); + + static void webapiFormatFeatureSettings( + SWGSDRangel::SWGFeatureSettings& response, + const DemodAnalyzerSettings& settings); + + static void webapiUpdateFeatureSettings( + DemodAnalyzerSettings& settings, + const QStringList& featureSettingsKeys, + SWGSDRangel::SWGFeatureSettings& response); + + static const char* const m_featureIdURI; + static const char* const m_featureId; + +private: + QThread m_thread; + DemodAnalyzerWorker *m_worker; + DemodAnalyzerSettings m_settings; + SpectrumVis m_spectrumVis; + QHash m_availableChannels; + ChannelAPI *m_selectedChannel; + DataFifo *m_dataFifo; + int m_sampleRate; + + QNetworkAccessManager *m_networkManager; + QNetworkRequest m_networkRequest; + + void start(); + void stop(); + void applySettings(const DemodAnalyzerSettings& settings, bool force = false); + void updateChannels(); + void setChannel(ChannelAPI *selectedChannel); + void webapiReverseSendSettings(QList& featureSettingsKeys, const DemodAnalyzerSettings& settings, bool force); + +private slots: + void networkManagerFinished(QNetworkReply *reply); + void handleChannelMessageQueue(MessageQueue *messageQueues); +}; + +#endif // INCLUDE_FEATURE_DEMODANALYZER_H_ diff --git a/plugins/feature/demodanalyzer/demodanalyzergui.cpp b/plugins/feature/demodanalyzer/demodanalyzergui.cpp new file mode 100644 index 000000000..723103ba7 --- /dev/null +++ b/plugins/feature/demodanalyzer/demodanalyzergui.cpp @@ -0,0 +1,354 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2020 Edouard Griffiths, F4EXB // +// // +// 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 // +// (at your option) any later version. // +// // +// This program is distributed in the hope that it will be useful, // +// but WITHOUT ANY WARRANTY; without even the implied warranty of // +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // +// GNU General Public License V3 for more details. // +// // +// You should have received a copy of the GNU General Public License // +// along with this program. If not, see . // +/////////////////////////////////////////////////////////////////////////////////// + +#include + +#include "feature/featureuiset.h" +#include "dsp/spectrumscopecombovis.h" +#include "dsp/spectrumvis.h" +#include "gui/basicfeaturesettingsdialog.h" +#include "gui/glspectrum.h" +#include "gui/glscope.h" +#include "device/deviceset.h" +#include "util/db.h" +#include "maincore.h" + +#include "ui_demodanalyzergui.h" +#include "demodanalyzer.h" +#include "demodanalyzergui.h" + +DemodAnalyzerGUI* DemodAnalyzerGUI::create(PluginAPI* pluginAPI, FeatureUISet *featureUISet, Feature *feature) +{ + DemodAnalyzerGUI* gui = new DemodAnalyzerGUI(pluginAPI, featureUISet, feature); + return gui; +} + +void DemodAnalyzerGUI::destroy() +{ + delete this; +} + +void DemodAnalyzerGUI::resetToDefaults() +{ + m_settings.resetToDefaults(); + displaySettings(); + applySettings(true); +} + +QByteArray DemodAnalyzerGUI::serialize() const +{ + return m_settings.serialize(); +} + +bool DemodAnalyzerGUI::deserialize(const QByteArray& data) +{ + if (m_settings.deserialize(data)) + { + displaySettings(); + applySettings(true); + return true; + } + else + { + resetToDefaults(); + return false; + } +} + +bool DemodAnalyzerGUI::handleMessage(const Message& message) +{ + if (DemodAnalyzer::MsgConfigureDemodAnalyzer::match(message)) + { + qDebug("DemodAnalyzerGUI::handleMessage: DemodAnalyzer::MsgConfigureDemodAnalyzer"); + const DemodAnalyzer::MsgConfigureDemodAnalyzer& cfg = (DemodAnalyzer::MsgConfigureDemodAnalyzer&) message; + m_settings = cfg.getSettings(); + blockApplySettings(true); + displaySettings(); + blockApplySettings(false); + + return true; + } + else if (DemodAnalyzer::MsgReportChannels::match(message)) + { + qDebug("DemodAnalyzerGUI::handleMessage: DemodAnalyzer::MsgReportChannels"); + DemodAnalyzer::MsgReportChannels& report = (DemodAnalyzer::MsgReportChannels&) message; + m_availableChannels = report.getAvailableChannels(); + updateChannelList(); + + return true; + } + else if (DemodAnalyzer::MsgReportSampleRate::match(message)) + { + DemodAnalyzer::MsgReportSampleRate& report = (DemodAnalyzer::MsgReportSampleRate&) message; + int sampleRate = report.getSampleRate(); + qDebug("DemodAnalyzerGUI::handleMessage: DemodAnalyzer::MsgReportSampleRate: %d", sampleRate); + ui->glSpectrum->setSampleRate(sampleRate); + m_scopeVis->setLiveRate(sampleRate); + displaySampleRate(sampleRate); + + return true; + } + + return false; +} + +void DemodAnalyzerGUI::handleInputMessages() +{ + Message* message; + + while ((message = getInputMessageQueue()->pop())) + { + if (handleMessage(*message)) { + delete message; + } + } +} + +void DemodAnalyzerGUI::onWidgetRolled(QWidget* widget, bool rollDown) +{ + (void) widget; + (void) rollDown; +} + +DemodAnalyzerGUI::DemodAnalyzerGUI(PluginAPI* pluginAPI, FeatureUISet *featureUISet, Feature *feature, QWidget* parent) : + FeatureGUI(parent), + ui(new Ui::DemodAnalyzerGUI), + m_pluginAPI(pluginAPI), + m_featureUISet(featureUISet), + m_doApplySettings(true), + m_lastFeatureState(0), + m_selectedChannel(nullptr) +{ + ui->setupUi(this); + setAttribute(Qt::WA_DeleteOnClose, true); + setChannelWidget(false); + connect(this, SIGNAL(widgetRolled(QWidget*,bool)), this, SLOT(onWidgetRolled(QWidget*,bool))); + m_scopeVis = new ScopeVis(ui->glScope); + + m_demodAnalyzer = reinterpret_cast(feature); + m_demodAnalyzer->setMessageQueueToGUI(&m_inputMessageQueue); + m_spectrumVis = m_demodAnalyzer->getSpectrumVis(); + m_spectrumVis->setGLSpectrum(ui->glSpectrum); + m_spectrumScopeComboVis = new SpectrumScopeComboVis(m_spectrumVis, m_scopeVis); + m_demodAnalyzer->setSampleSink(m_spectrumScopeComboVis); + + m_featureUISet->addRollupWidget(this); + + connect(this, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(onMenuDialogCalled(const QPoint &))); + connect(getInputMessageQueue(), SIGNAL(messageEnqueued()), this, SLOT(handleInputMessages())); + + connect(&m_statusTimer, SIGNAL(timeout()), this, SLOT(updateStatus())); + m_statusTimer.start(1000); + + ui->spectrumGUI->setBuddies(m_spectrumVis, ui->glSpectrum); + ui->scopeGUI->setBuddies(m_scopeVis->getInputMessageQueue(), m_scopeVis, ui->glScope); + ui->glSpectrum->setCenterFrequency(0); + ui->glSpectrum->setSampleRate(48000); + m_scopeVis->setLiveRate(48000); + displaySampleRate(48000); + + ui->glSpectrum->connectTimer(MainCore::instance()->getMasterTimer()); + ui->glScope->connectTimer(MainCore::instance()->getMasterTimer()); + connect(&MainCore::instance()->getMasterTimer(), SIGNAL(timeout()), this, SLOT(tick())); + + ui->spectrumGUI->setBuddies(m_spectrumVis, ui->glSpectrum); + ui->scopeGUI->setBuddies(m_scopeVis->getInputMessageQueue(), m_scopeVis, ui->glScope); + + m_settings.setSpectrumGUI(ui->spectrumGUI); + m_settings.setScopeGUI(ui->scopeGUI); + + displaySettings(); + applySettings(true); +} + +DemodAnalyzerGUI::~DemodAnalyzerGUI() +{ + delete ui; + delete m_spectrumScopeComboVis; + delete m_scopeVis; +} + +void DemodAnalyzerGUI::blockApplySettings(bool block) +{ + m_doApplySettings = !block; +} + +void DemodAnalyzerGUI::displaySettings() +{ + setTitleColor(m_settings.m_rgbColor); + setWindowTitle(m_settings.m_title); + blockApplySettings(true); + blockApplySettings(false); +} + +void DemodAnalyzerGUI::displaySampleRate(int sampleRate) +{ + QString s = QString::number(sampleRate/1000.0, 'f', 1); + ui->sinkSampleRateText->setText(tr("%1 kS/s").arg(s)); +} + +void DemodAnalyzerGUI::updateChannelList() +{ + ui->channels->blockSignals(true); + ui->channels->clear(); + + QList::const_iterator it = m_availableChannels.begin(); + int selectedItem = -1; + + for (int i = 0; it != m_availableChannels.end(); ++it, i++) + { + ui->channels->addItem(tr("%1%2:%3 %4") + .arg(it->m_tx ? "T" : "R") + .arg(it->m_deviceSetIndex) + .arg(it->m_channelIndex) + .arg(it->m_id) + ); + + if (it->m_channelAPI == m_selectedChannel) { + selectedItem = i; + } + } + + ui->channels->blockSignals(false); + + if (m_availableChannels.size() > 0) + { + if (selectedItem >= 0) { + ui->channels->setCurrentIndex(selectedItem); + } else { + ui->channels->setCurrentIndex(0); + } + } +} + +void DemodAnalyzerGUI::leaveEvent(QEvent*) +{ +} + +void DemodAnalyzerGUI::enterEvent(QEvent*) +{ +} + +void DemodAnalyzerGUI::onMenuDialogCalled(const QPoint &p) +{ + if (m_contextMenuType == ContextMenuChannelSettings) + { + BasicFeatureSettingsDialog dialog(this); + dialog.setTitle(m_settings.m_title); + dialog.setColor(m_settings.m_rgbColor); + dialog.setUseReverseAPI(m_settings.m_useReverseAPI); + dialog.setReverseAPIAddress(m_settings.m_reverseAPIAddress); + dialog.setReverseAPIPort(m_settings.m_reverseAPIPort); + dialog.setReverseAPIFeatureSetIndex(m_settings.m_reverseAPIFeatureSetIndex); + dialog.setReverseAPIFeatureIndex(m_settings.m_reverseAPIFeatureIndex); + + dialog.move(p); + dialog.exec(); + + m_settings.m_rgbColor = dialog.getColor().rgb(); + m_settings.m_title = dialog.getTitle(); + m_settings.m_useReverseAPI = dialog.useReverseAPI(); + m_settings.m_reverseAPIAddress = dialog.getReverseAPIAddress(); + m_settings.m_reverseAPIPort = dialog.getReverseAPIPort(); + m_settings.m_reverseAPIFeatureSetIndex = dialog.getReverseAPIFeatureSetIndex(); + m_settings.m_reverseAPIFeatureIndex = dialog.getReverseAPIFeatureIndex(); + + setWindowTitle(m_settings.m_title); + setTitleColor(m_settings.m_rgbColor); + + applySettings(); + } + + resetContextMenuType(); +} + +void DemodAnalyzerGUI::on_startStop_toggled(bool checked) +{ + if (m_doApplySettings) + { + DemodAnalyzer::MsgStartStop *message = DemodAnalyzer::MsgStartStop::create(checked); + m_demodAnalyzer->getInputMessageQueue()->push(message); + } +} + +void DemodAnalyzerGUI::on_devicesRefresh_clicked() +{ + DemodAnalyzer::MsgRefreshChannels *msg = DemodAnalyzer::MsgRefreshChannels::create(); + m_demodAnalyzer->getInputMessageQueue()->push(msg); +} + +void DemodAnalyzerGUI::on_channels_currentIndexChanged(int index) +{ + if ((index >= 0) && (index < m_availableChannels.size())) + { + m_selectedChannel = m_availableChannels[index].m_channelAPI; + DemodAnalyzer::MsgSelectChannel *msg = DemodAnalyzer::MsgSelectChannel::create(m_selectedChannel); + m_demodAnalyzer->getInputMessageQueue()->push(msg); + } +} + +void DemodAnalyzerGUI::on_channelApply_clicked() +{ + if (ui->channels->count() > 0) { + on_channels_currentIndexChanged(ui->channels->currentIndex()); + } +} + +void DemodAnalyzerGUI::tick() +{ + m_channelPowerAvg(m_demodAnalyzer->getMagSqAvg()); + double powDb = CalcDb::dbPower((double) m_channelPowerAvg); + ui->channelPower->setText(tr("%1 dB").arg(powDb, 0, 'f', 1)); +} + +void DemodAnalyzerGUI::updateStatus() +{ + int state = m_demodAnalyzer->getState(); + + if (m_lastFeatureState != state) + { + switch (state) + { + case Feature::StNotStarted: + ui->startStop->setStyleSheet("QToolButton { background:rgb(79,79,79); }"); + break; + case Feature::StIdle: + ui->startStop->setStyleSheet("QToolButton { background-color : blue; }"); + break; + case Feature::StRunning: + ui->startStop->setStyleSheet("QToolButton { background-color : green; }"); + break; + case Feature::StError: + ui->startStop->setStyleSheet("QToolButton { background-color : red; }"); + QMessageBox::information(this, tr("Message"), m_demodAnalyzer->getErrorMessage()); + break; + default: + break; + } + + m_lastFeatureState = state; + } +} + +void DemodAnalyzerGUI::applySettings(bool force) +{ + if (m_doApplySettings) + { + DemodAnalyzer::MsgConfigureDemodAnalyzer* message = DemodAnalyzer::MsgConfigureDemodAnalyzer::create( m_settings, force); + m_demodAnalyzer->getInputMessageQueue()->push(message); + } +} diff --git a/plugins/feature/demodanalyzer/demodanalyzergui.h b/plugins/feature/demodanalyzer/demodanalyzergui.h new file mode 100644 index 000000000..666c92658 --- /dev/null +++ b/plugins/feature/demodanalyzer/demodanalyzergui.h @@ -0,0 +1,96 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2020 Edouard Griffiths, F4EXB // +// // +// 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 // +// (at your option) any later version. // +// // +// 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 INCLUDE_FEATURE_DEMODANALYZERGUI_H_ +#define INCLUDE_FEATURE_DEMODANALYZERGUI_H_ + +#include +#include + +#include "feature/featuregui.h" +#include "util/movingaverage.h" +#include "util/messagequeue.h" +#include "demodanalyzersettings.h" + +class PluginAPI; +class FeatureUISet; +class DemodAnalyzer; +class Feature; +class SpectrumScopeComboVis; +class SpectrumVis; +class ScopeVis; + +namespace Ui { + class DemodAnalyzerGUI; +} + +class DemodAnalyzerGUI : public FeatureGUI { + Q_OBJECT +public: + static DemodAnalyzerGUI* create(PluginAPI* pluginAPI, FeatureUISet *featureUISet, Feature *feature); + virtual void destroy(); + + void resetToDefaults(); + QByteArray serialize() const; + bool deserialize(const QByteArray& data); + virtual MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; } + +private: + Ui::DemodAnalyzerGUI* ui; + PluginAPI* m_pluginAPI; + FeatureUISet* m_featureUISet; + DemodAnalyzerSettings m_settings; + bool m_doApplySettings; + + DemodAnalyzer* m_demodAnalyzer; + SpectrumScopeComboVis* m_spectrumScopeComboVis; + SpectrumVis* m_spectrumVis; + ScopeVis* m_scopeVis; + MessageQueue m_inputMessageQueue; + QTimer m_statusTimer; + int m_lastFeatureState; + QList m_availableChannels; + ChannelAPI *m_selectedChannel; + MovingAverageUtil m_channelPowerAvg; + + explicit DemodAnalyzerGUI(PluginAPI* pluginAPI, FeatureUISet *featureUISet, Feature *feature, QWidget* parent = nullptr); + virtual ~DemodAnalyzerGUI(); + + void blockApplySettings(bool block); + void applySettings(bool force = false); + void displaySettings(); + void displaySampleRate(int sampleRate); + void updateChannelList(); + bool handleMessage(const Message& message); + + void leaveEvent(QEvent*); + void enterEvent(QEvent*); + +private slots: + void onMenuDialogCalled(const QPoint &p); + void onWidgetRolled(QWidget* widget, bool rollDown); + void handleInputMessages(); + void on_startStop_toggled(bool checked); + void on_devicesRefresh_clicked(); + void on_channels_currentIndexChanged(int index); + void on_channelApply_clicked(); + void updateStatus(); + void tick(); +}; + + +#endif // INCLUDE_FEATURE_DEMODANALYZERGUI_H_ diff --git a/plugins/feature/demodanalyzer/demodanalyzergui.ui b/plugins/feature/demodanalyzer/demodanalyzergui.ui new file mode 100644 index 000000000..b0f3ff01c --- /dev/null +++ b/plugins/feature/demodanalyzer/demodanalyzergui.ui @@ -0,0 +1,346 @@ + + + DemodAnalyzerGUI + + + + 0 + 0 + 739 + 778 + + + + + 720 + 0 + + + + + Liberation Sans + 9 + + + + Demod Analyzer + + + + + 0 + 10 + 631 + 41 + + + + Settings + + + + 3 + + + 2 + + + 2 + + + 2 + + + 2 + + + + + 2 + + + + + start/stop acquisition + + + + + + + :/play.png + :/stop.png:/play.png + + + + + + + + 24 + 16777215 + + + + Refresh indexes of available device sets + + + + + + + :/recycle.png:/recycle.png + + + + + + + Chan + + + + + + + + 200 + 0 + + + + Channel index + + + + + + + + 24 + 24 + + + + Reinitialization of device data + + + + + + + :/checkmark.png:/checkmark.png + + + + + + + + 80 + 0 + + + + Analyzer (sink) sample rate + + + 00000.0 kS/s + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 52 + 0 + + + + Channel power + + + Qt::LeftToRight + + + -100.0 dB + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + + + + 0 + 98 + 720 + 284 + + + + + 716 + 0 + + + + Channel Spectrum + + + + 2 + + + 2 + + + 2 + + + 2 + + + 2 + + + + + + 200 + 250 + + + + + Liberation Mono + 8 + + + + + + + + + + + + + 0 + 390 + 720 + 334 + + + + + 716 + 0 + + + + Channel Scope + + + + 2 + + + 3 + + + 3 + + + 3 + + + 3 + + + + + + 200 + 300 + + + + + Liberation Mono + 8 + + + + + + + + + + + + + RollupWidget + QWidget +
gui/rollupwidget.h
+ 1 +
+ + GLSpectrum + QWidget +
gui/glspectrum.h
+ 1 +
+ + GLSpectrumGUI + QWidget +
gui/glspectrumgui.h
+ 1 +
+ + ButtonSwitch + QToolButton +
gui/buttonswitch.h
+
+ + GLScope + QWidget +
gui/glscope.h
+ 1 +
+ + GLScopeGUI + QWidget +
gui/glscopegui.h
+ 1 +
+
+ + + + +
diff --git a/plugins/feature/demodanalyzer/demodanalyzerplugin.cpp b/plugins/feature/demodanalyzer/demodanalyzerplugin.cpp new file mode 100644 index 000000000..a5ccf291a --- /dev/null +++ b/plugins/feature/demodanalyzer/demodanalyzerplugin.cpp @@ -0,0 +1,80 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2020 Edouard Griffiths, F4EXB // +// // +// 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 // +// (at your option) any later version. // +// // +// This program is distributed in the hope that it will be useful, // +// but WITHOUT ANY WARRANTY; without even the implied warranty of // +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // +// GNU General Public License V3 for more details. // +// // +// You should have received a copy of the GNU General Public License // +// along with this program. If not, see . // +/////////////////////////////////////////////////////////////////////////////////// + + +#include +#include "plugin/pluginapi.h" + +#ifndef SERVER_MODE +#include "demodanalyzergui.h" +#endif +#include "demodanalyzer.h" +#include "demodanalyzerplugin.h" +#include "demodanalyzerwebapiadapter.h" + +const PluginDescriptor DemodAnalyzerPlugin::m_pluginDescriptor = { + DemodAnalyzer::m_featureId, + QStringLiteral("Demod Analyzer"), + QStringLiteral("6.4.0"), + QStringLiteral("(c) Edouard Griffiths, F4EXB"), + QStringLiteral("https://github.com/f4exb/sdrangel"), + true, + QStringLiteral("https://github.com/f4exb/sdrangel") +}; + +DemodAnalyzerPlugin::DemodAnalyzerPlugin(QObject* parent) : + QObject(parent), + m_pluginAPI(nullptr) +{ +} + +const PluginDescriptor& DemodAnalyzerPlugin::getPluginDescriptor() const +{ + return m_pluginDescriptor; +} + +void DemodAnalyzerPlugin::initPlugin(PluginAPI* pluginAPI) +{ + m_pluginAPI = pluginAPI; + + // register RigCtl Server feature + m_pluginAPI->registerFeature(DemodAnalyzer::m_featureIdURI, DemodAnalyzer::m_featureId, this); +} + +#ifdef SERVER_MODE +FeatureGUI* DemodAnalyzerPlugin::createFeatureGUI(FeatureUISet *featureUISet, Feature *feature) const +{ + (void) featureUISet; + (void) feature; + return nullptr; +} +#else +FeatureGUI* DemodAnalyzerPlugin::createFeatureGUI(FeatureUISet *featureUISet, Feature *feature) const +{ + return DemodAnalyzerGUI::create(m_pluginAPI, featureUISet, feature); +} +#endif + +Feature* DemodAnalyzerPlugin::createFeature(WebAPIAdapterInterface* webAPIAdapterInterface) const +{ + return new DemodAnalyzer(webAPIAdapterInterface); +} + +FeatureWebAPIAdapter* DemodAnalyzerPlugin::createFeatureWebAPIAdapter() const +{ + return new DemodAnalyzerWebAPIAdapter(); +} diff --git a/plugins/feature/demodanalyzer/demodanalyzerplugin.h b/plugins/feature/demodanalyzer/demodanalyzerplugin.h new file mode 100644 index 000000000..1fb3b2e09 --- /dev/null +++ b/plugins/feature/demodanalyzer/demodanalyzerplugin.h @@ -0,0 +1,48 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2020 Edouard Griffiths, F4EXB // +// // +// 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 // +// (at your option) any later version. // +// // +// 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 INCLUDE_FEATURE_DEMODANALYZERPLUGIN_H +#define INCLUDE_FEATURE_DEMODANALYZERPLUGIN_H + +#include +#include "plugin/plugininterface.h" + +class FeatureGUI; +class WebAPIAdapterInterface; + +class DemodAnalyzerPlugin : public QObject, PluginInterface { + Q_OBJECT + Q_INTERFACES(PluginInterface) + Q_PLUGIN_METADATA(IID "sdrangel.feature.demodanalyzer") + +public: + explicit DemodAnalyzerPlugin(QObject* parent = nullptr); + + const PluginDescriptor& getPluginDescriptor() const; + void initPlugin(PluginAPI* pluginAPI); + + virtual FeatureGUI* createFeatureGUI(FeatureUISet *featureUISet, Feature *feature) const; + virtual Feature* createFeature(WebAPIAdapterInterface *webAPIAdapterInterface) const; + virtual FeatureWebAPIAdapter* createFeatureWebAPIAdapter() const; + +private: + static const PluginDescriptor m_pluginDescriptor; + + PluginAPI* m_pluginAPI; +}; + +#endif // INCLUDE_FEATURE_DEMODANALYZERPLUGIN_H diff --git a/plugins/feature/demodanalyzer/demodanalyzersettings.cpp b/plugins/feature/demodanalyzer/demodanalyzersettings.cpp new file mode 100644 index 000000000..356db8995 --- /dev/null +++ b/plugins/feature/demodanalyzer/demodanalyzersettings.cpp @@ -0,0 +1,128 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2020 Edouard Griffiths, F4EXB // +// // +// 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 // +// (at your option) any later version. // +// // +// This program is distributed in the hope that it will be useful, // +// but WITHOUT ANY WARRANTY; without even the implied warranty of // +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // +// GNU General Public License V3 for more details. // +// // +// You should have received a copy of the GNU General Public License // +// along with this program. If not, see . // +/////////////////////////////////////////////////////////////////////////////////// + +#include + +#include "util/simpleserializer.h" +#include "settings/serializable.h" + +#include "demodanalyzersettings.h" + +const QStringList DemodAnalyzerSettings::m_channelTypes = { + QStringLiteral("AMDemod"), + QStringLiteral("AMMod") +}; + +const QStringList DemodAnalyzerSettings::m_channelURIs = { + QStringLiteral("sdrangel.channel.amdemod"), + QStringLiteral("sdrangel.channeltx.modam") +}; + +DemodAnalyzerSettings::DemodAnalyzerSettings() : + m_spectrumGUI(nullptr), + m_scopeGUI(nullptr) +{ + resetToDefaults(); +} + +void DemodAnalyzerSettings::resetToDefaults() +{ + m_deviceIndex = -1; + m_channelIndex = -1; + m_title = "Demod Analyzer"; + m_rgbColor = QColor(128, 128, 128).rgb(); + m_useReverseAPI = false; + m_reverseAPIAddress = "127.0.0.1"; + m_reverseAPIPort = 8888; + m_reverseAPIFeatureSetIndex = 0; + m_reverseAPIFeatureIndex = 0; +} + +QByteArray DemodAnalyzerSettings::serialize() const +{ + SimpleSerializer s(1); + + s.writeBlob(1, m_spectrumGUI->serialize()); + s.writeBlob(2, m_scopeGUI->serialize()); + s.writeS32(3, m_deviceIndex); + s.writeS32(4, m_channelIndex); + s.writeString(5, m_title); + s.writeU32(6, m_rgbColor); + s.writeBool(7, m_useReverseAPI); + s.writeString(8, m_reverseAPIAddress); + s.writeU32(9, m_reverseAPIPort); + s.writeU32(10, m_reverseAPIFeatureSetIndex); + s.writeU32(11, m_reverseAPIFeatureIndex); + + return s.final(); +} + +bool DemodAnalyzerSettings::deserialize(const QByteArray& data) +{ + SimpleDeserializer d(data); + + if (!d.isValid()) + { + resetToDefaults(); + return false; + } + + if (d.getVersion() == 1) + { + QByteArray bytetmp; + uint32_t utmp; + QString strtmp; + + if (m_spectrumGUI) + { + d.readBlob(1, &bytetmp); + m_spectrumGUI->deserialize(bytetmp); + } + + if (m_scopeGUI) + { + d.readBlob(2, &bytetmp); + m_scopeGUI->deserialize(bytetmp); + } + + d.readS32(3, &m_deviceIndex, -1); + d.readS32(4, &m_channelIndex, -1); + d.readString(5, &m_title, "RigCtl Server"); + d.readU32(6, &m_rgbColor, QColor(128, 128, 128).rgb()); + d.readBool(7, &m_useReverseAPI, false); + d.readString(8, &m_reverseAPIAddress, "127.0.0.1"); + d.readU32(9, &utmp, 0); + + if ((utmp > 1023) && (utmp < 65535)) { + m_reverseAPIPort = utmp; + } else { + m_reverseAPIPort = 8888; + } + + d.readU32(10, &utmp, 0); + m_reverseAPIFeatureSetIndex = utmp > 99 ? 99 : utmp; + d.readU32(11, &utmp, 0); + m_reverseAPIFeatureIndex = utmp > 99 ? 99 : utmp; + + return true; + } + else + { + resetToDefaults(); + return false; + } +} diff --git a/plugins/feature/demodanalyzer/demodanalyzersettings.h b/plugins/feature/demodanalyzer/demodanalyzersettings.h new file mode 100644 index 000000000..0f05522ae --- /dev/null +++ b/plugins/feature/demodanalyzer/demodanalyzersettings.h @@ -0,0 +1,67 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2020 Edouard Griffiths, F4EXB // +// // +// 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 // +// (at your option) any later version. // +// // +// 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 INCLUDE_FEATURE_DEMODANALYZERSETTINGS_H_ +#define INCLUDE_FEATURE_DEMODANALYZERSETTINGS_H_ + +#include +#include + +#include "util/message.h" + +class Serializable; +class ChannelAPI; + +struct DemodAnalyzerSettings +{ + struct AvailableChannel + { + bool m_tx; + int m_deviceSetIndex; + int m_channelIndex; + ChannelAPI *m_channelAPI; + QString m_id; + + AvailableChannel() = default; + AvailableChannel(const AvailableChannel&) = default; + AvailableChannel& operator=(const AvailableChannel&) = default; + }; + + int m_deviceIndex; + int m_channelIndex; + QString m_title; + quint32 m_rgbColor; + bool m_useReverseAPI; + QString m_reverseAPIAddress; + uint16_t m_reverseAPIPort; + uint16_t m_reverseAPIFeatureSetIndex; + uint16_t m_reverseAPIFeatureIndex; + Serializable *m_spectrumGUI; + Serializable *m_scopeGUI; + + DemodAnalyzerSettings(); + void resetToDefaults(); + QByteArray serialize() const; + bool deserialize(const QByteArray& data); + void setSpectrumGUI(Serializable *spectrumGUI) { m_spectrumGUI = spectrumGUI; } + void setScopeGUI(Serializable *scopeGUI) { m_scopeGUI = scopeGUI; } + + static const QStringList m_channelTypes; + static const QStringList m_channelURIs; +}; + +#endif // INCLUDE_FEATURE_DEMODANALYZERSETTINGS_H_ diff --git a/plugins/feature/demodanalyzer/demodanalyzerwebapiadapter.cpp b/plugins/feature/demodanalyzer/demodanalyzerwebapiadapter.cpp new file mode 100644 index 000000000..1e202f418 --- /dev/null +++ b/plugins/feature/demodanalyzer/demodanalyzerwebapiadapter.cpp @@ -0,0 +1,51 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2020 Edouard Griffiths, F4EXB. // +// // +// 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 // +// (at your option) any later version. // +// // +// 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 "SWGFeatureSettings.h" +#include "demodanalyzer.h" +#include "demodanalyzerwebapiadapter.h" + +DemodAnalyzerWebAPIAdapter::DemodAnalyzerWebAPIAdapter() +{} + +DemodAnalyzerWebAPIAdapter::~DemodAnalyzerWebAPIAdapter() +{} + +int DemodAnalyzerWebAPIAdapter::webapiSettingsGet( + SWGSDRangel::SWGFeatureSettings& response, + QString& errorMessage) +{ + (void) errorMessage; + response.setDemodAnalyzerSettings(new SWGSDRangel::SWGDemodAnalyzerSettings()); + response.getDemodAnalyzerSettings()->init(); + DemodAnalyzer::webapiFormatFeatureSettings(response, m_settings); + + return 200; +} + +int DemodAnalyzerWebAPIAdapter::webapiSettingsPutPatch( + bool force, + const QStringList& featureSettingsKeys, + SWGSDRangel::SWGFeatureSettings& response, + QString& errorMessage) +{ + (void) force; // no action + (void) errorMessage; + DemodAnalyzer::webapiUpdateFeatureSettings(m_settings, featureSettingsKeys, response); + + return 200; +} diff --git a/plugins/feature/demodanalyzer/demodanalyzerwebapiadapter.h b/plugins/feature/demodanalyzer/demodanalyzerwebapiadapter.h new file mode 100644 index 000000000..f155388c1 --- /dev/null +++ b/plugins/feature/demodanalyzer/demodanalyzerwebapiadapter.h @@ -0,0 +1,49 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2020 Edouard Griffiths, F4EXB. // +// // +// 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 // +// (at your option) any later version. // +// // +// 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 INCLUDE_DEMODANALYZER_WEBAPIADAPTER_H +#define INCLUDE_DEMODANALYZER_WEBAPIADAPTER_H + +#include "feature/featurewebapiadapter.h" +#include "demodanalyzersettings.h" + +/** + * Standalone API adapter only for the settings + */ +class DemodAnalyzerWebAPIAdapter : public FeatureWebAPIAdapter { +public: + DemodAnalyzerWebAPIAdapter(); + virtual ~DemodAnalyzerWebAPIAdapter(); + + virtual QByteArray serialize() const { return m_settings.serialize(); } + virtual bool deserialize(const QByteArray& data) { return m_settings.deserialize(data); } + + virtual int webapiSettingsGet( + SWGSDRangel::SWGFeatureSettings& response, + QString& errorMessage); + + virtual int webapiSettingsPutPatch( + bool force, + const QStringList& featureSettingsKeys, + SWGSDRangel::SWGFeatureSettings& response, + QString& errorMessage); + +private: + DemodAnalyzerSettings m_settings; +}; + +#endif // INCLUDE_DEMODANALYZER_WEBAPIADAPTER_H diff --git a/plugins/feature/demodanalyzer/demodanalyzerworker.cpp b/plugins/feature/demodanalyzer/demodanalyzerworker.cpp new file mode 100644 index 000000000..49ff187bb --- /dev/null +++ b/plugins/feature/demodanalyzer/demodanalyzerworker.cpp @@ -0,0 +1,183 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2020 Edouard Griffiths, F4EXB // +// // +// 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 // +// (at your option) any later version. // +// // +// This program is distributed in the hope that it will be useful, // +// but WITHOUT ANY WARRANTY; without even the implied warranty of // +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // +// GNU General Public License V3 for more details. // +// // +// You should have received a copy of the GNU General Public License // +// along with this program. If not, see . // +/////////////////////////////////////////////////////////////////////////////////// + +#include + +#include "dsp/basebandsamplesink.h" +#include "dsp/datafifo.h" + +#include "demodanalyzerworker.h" + +MESSAGE_CLASS_DEFINITION(DemodAnalyzerWorker::MsgConfigureDemodAnalyzerWorker, Message) +MESSAGE_CLASS_DEFINITION(DemodAnalyzerWorker::MsgConnectFifo, Message) + +DemodAnalyzerWorker::DemodAnalyzerWorker() : + m_dataFifo(nullptr), + m_msgQueueToFeature(nullptr), + m_sampleBufferSize(0), + m_running(false), + m_mutex(QMutex::Recursive) +{ + qDebug("DemodAnalyzerWorker::DemodAnalyzerWorker"); +} + +DemodAnalyzerWorker::~DemodAnalyzerWorker() +{ + m_inputMessageQueue.clear(); +} + +void DemodAnalyzerWorker::reset() +{ + QMutexLocker mutexLocker(&m_mutex); + m_inputMessageQueue.clear(); +} + +bool DemodAnalyzerWorker::startWork() +{ + QMutexLocker mutexLocker(&m_mutex); + connect(&m_inputMessageQueue, SIGNAL(messageEnqueued()), this, SLOT(handleInputMessages())); + m_running = true; + return m_running; +} + +void DemodAnalyzerWorker::stopWork() +{ + QMutexLocker mutexLocker(&m_mutex); + disconnect(&m_inputMessageQueue, SIGNAL(messageEnqueued()), this, SLOT(handleInputMessages())); + m_running = false; +} + +void DemodAnalyzerWorker::feedPart(const QByteArray::const_iterator& begin, const QByteArray::const_iterator& end) +{ + int countSamples = (end - begin) / sizeof(int16_t); + int16_t *s = (int16_t*) begin; + + if (countSamples > m_sampleBufferSize) + { + m_sampleBuffer.resize(countSamples); + m_sampleBufferSize = countSamples; + } + + for(int i = 0; i < countSamples; i++) + { + double re = s[i] / (double) std::numeric_limits::max(); + m_magsq = re*re; + m_channelPowerAvg(m_magsq); + m_sampleBuffer[i].setReal(re * SDR_RX_SCALEF); + m_sampleBuffer[i].setImag(0); + } + + if (m_sampleSink) { + m_sampleSink->feed(m_sampleBuffer.begin(), m_sampleBuffer.begin() + countSamples, false); + } +} + +void DemodAnalyzerWorker::handleInputMessages() +{ + Message* message; + + while ((message = m_inputMessageQueue.pop()) != nullptr) + { + if (handleMessage(*message)) { + delete message; + } + } +} + +bool DemodAnalyzerWorker::handleMessage(const Message& cmd) +{ + if (MsgConfigureDemodAnalyzerWorker::match(cmd)) + { + QMutexLocker mutexLocker(&m_mutex); + MsgConfigureDemodAnalyzerWorker& cfg = (MsgConfigureDemodAnalyzerWorker&) cmd; + qDebug("DemodAnalyzerWorker::handleMessage: MsgConfigureDemodAnalyzerWorker"); + + applySettings(cfg.getSettings(), cfg.getForce()); + + return true; + } + else if (MsgConnectFifo::match(cmd)) + { + qDebug("DemodAnalyzerWorker::handleMessage: MsgConnectFifo"); + QMutexLocker mutexLocker(&m_mutex); + MsgConnectFifo& msg = (MsgConnectFifo&) cmd; + m_dataFifo = msg.getFifo(); + bool doConnect = msg.getConnect(); + + if (doConnect) { + QObject::connect( + m_dataFifo, + &DataFifo::dataReady, + this, + &DemodAnalyzerWorker::handleData, + Qt::QueuedConnection + ); + } else { + QObject::disconnect( + m_dataFifo, + &DataFifo::dataReady, + this, + &DemodAnalyzerWorker::handleData + ); + } + + return true; + } + else + { + return false; + } +} + +void DemodAnalyzerWorker::applySettings(const DemodAnalyzerSettings& settings, bool force) +{ + qDebug() << "DemodAnalyzerWorker::applySettings:" + << " m_title: " << settings.m_title + << " m_rgbColor: " << settings.m_rgbColor + << " m_deviceIndex: " << settings.m_deviceIndex + << " m_channelIndex: " << settings.m_channelIndex + << " force: " << force; + + m_settings = settings; +} + +void DemodAnalyzerWorker::handleData() +{ + QMutexLocker mutexLocker(&m_mutex); + + while ((m_dataFifo->fill() > 0) && (m_inputMessageQueue.size() == 0)) + { + QByteArray::iterator part1begin; + QByteArray::iterator part1end; + QByteArray::iterator part2begin; + QByteArray::iterator part2end; + + std::size_t count = m_dataFifo->readBegin(m_dataFifo->fill(), &part1begin, &part1end, &part2begin, &part2end); + + // first part of FIFO data + if (part1begin != part1end) { + feedPart(part1begin, part1end); + } + + // second part of FIFO data (used when block wraps around) + if (part2begin != part2end) { + feedPart(part2begin, part2end); + } + + m_dataFifo->readCommit((unsigned int) count); + } +} diff --git a/plugins/feature/demodanalyzer/demodanalyzerworker.h b/plugins/feature/demodanalyzer/demodanalyzerworker.h new file mode 100644 index 000000000..1fdc44c16 --- /dev/null +++ b/plugins/feature/demodanalyzer/demodanalyzerworker.h @@ -0,0 +1,126 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2020 Edouard Griffiths, F4EXB // +// // +// 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 // +// (at your option) any later version. // +// // +// 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 INCLUDE_DEMODALYZERWORKER_H +#define INCLUDE_DEMODALYZERWORKER_H + +#include +#include +#include + +#include "dsp/dsptypes.h" +#include "util/movingaverage.h" +#include "util/message.h" +#include "util/messagequeue.h" + +#include "demodanalyzersettings.h" + +class BasebandSampleSink; +class ChannelAPI; +class Feature; +class DataFifo; + +class DemodAnalyzerWorker : public QObject { + Q_OBJECT +public: + class MsgConfigureDemodAnalyzerWorker : public Message { + MESSAGE_CLASS_DECLARATION + + public: + const DemodAnalyzerSettings& getSettings() const { return m_settings; } + bool getForce() const { return m_force; } + + static MsgConfigureDemodAnalyzerWorker* create(const DemodAnalyzerSettings& settings, bool force) + { + return new MsgConfigureDemodAnalyzerWorker(settings, force); + } + + private: + DemodAnalyzerSettings m_settings; + bool m_force; + + MsgConfigureDemodAnalyzerWorker(const DemodAnalyzerSettings& settings, bool force) : + Message(), + m_settings(settings), + m_force(force) + { } + }; + + class MsgConnectFifo : public Message { + MESSAGE_CLASS_DECLARATION + + public: + DataFifo *getFifo() { return m_fifo; } + bool getConnect() const { return m_connect; } + + static MsgConnectFifo* create(DataFifo *fifo, bool connect) { + return new MsgConnectFifo(fifo, connect); + } + private: + DataFifo *m_fifo; + bool m_connect; + MsgConnectFifo(DataFifo *fifo, bool connect) : + Message(), + m_fifo(fifo), + m_connect(connect) + { } + }; + + DemodAnalyzerWorker(); + ~DemodAnalyzerWorker(); + void reset(); + bool startWork(); + void stopWork(); + bool isRunning() const { return m_running; } + MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; } + void setMessageQueueToFeature(MessageQueue *messageQueue) { m_msgQueueToFeature = messageQueue; } + + void feedPart(const QByteArray::const_iterator& begin, const QByteArray::const_iterator& end); + + void applySampleRate(int sampleRate); + void applySettings(const DemodAnalyzerSettings& settings, bool force = false); + + double getMagSq() const { return m_magsq; } + double getMagSqAvg() const { return (double) m_channelPowerAvg; } + void setSampleSink(BasebandSampleSink* sampleSink) { m_sampleSink = sampleSink; } + + static const unsigned int m_corrFFTLen; + static const unsigned int m_ssbFftLen; + +private: + DataFifo *m_dataFifo; + int m_channelSampleRate; + int m_sinkSampleRate; + MessageQueue m_inputMessageQueue; //!< Queue for asynchronous inbound communication + MessageQueue *m_msgQueueToFeature; //!< Queue to report channel change to main feature object + DemodAnalyzerSettings m_settings; + double m_magsq; + SampleVector m_sampleBuffer; + int m_sampleBufferSize; + MovingAverageUtil m_channelPowerAvg; + BasebandSampleSink* m_sampleSink; + bool m_running; + QMutex m_mutex; + + bool handleMessage(const Message& cmd); + +private slots: + void handleInputMessages(); + void handleData(); //!< Handle data when samples have to be processed +}; + +#endif // INCLUDE_DEMODALYZERWORKER_H diff --git a/plugins/feature/vorlocalizer/vorlocalizer.cpp b/plugins/feature/vorlocalizer/vorlocalizer.cpp index 5ba65fe99..220b5d7b7 100644 --- a/plugins/feature/vorlocalizer/vorlocalizer.cpp +++ b/plugins/feature/vorlocalizer/vorlocalizer.cpp @@ -247,7 +247,8 @@ bool VORLocalizer::handleMessage(const Message& cmd) const ChannelAPI *channel = channelKey.m_key; m_availableChannels.remove(const_cast(channel)); updateChannels(); - MainCore::instance()->getMessagePipes().unregisterChannelToFeature(channel, this, "report"); + MessageQueue *messageQueue = MainCore::instance()->getMessagePipes().unregisterChannelToFeature(channel, this, "report"); + disconnect(messageQueue, SIGNAL(messageEnqueued()), this, SLOT(handleChannelMessageQueue(MessageQueue*))); return true; } diff --git a/plugins/feature/vorlocalizer/vorlocalizerplugin.cpp b/plugins/feature/vorlocalizer/vorlocalizerplugin.cpp index 0761fc85c..e283389cd 100644 --- a/plugins/feature/vorlocalizer/vorlocalizerplugin.cpp +++ b/plugins/feature/vorlocalizer/vorlocalizerplugin.cpp @@ -29,7 +29,7 @@ const PluginDescriptor VORLocalizerPlugin::m_pluginDescriptor = { VORLocalizer::m_featureId, QStringLiteral("VOR Localizer"), - QStringLiteral("6.3.1"), + QStringLiteral("6.4.0"), QStringLiteral("(c) Jon Beniston, M7RCE"), QStringLiteral("https://github.com/f4exb/sdrangel"), true, diff --git a/sdrbase/dsp/datafifo.cpp b/sdrbase/dsp/datafifo.cpp index 50cd2ab30..a572c0161 100644 --- a/sdrbase/dsp/datafifo.cpp +++ b/sdrbase/dsp/datafifo.cpp @@ -77,7 +77,7 @@ bool DataFifo::setSize(int size) { create(size); - return m_data.size() == (unsigned int)size; + return m_data.size() == size; } unsigned int DataFifo::write(const quint8* data, unsigned int count) @@ -280,8 +280,3 @@ unsigned int DataFifo::readCommit(unsigned int count) return count; } - -unsigned int DataFifo::getSizePolicy(unsigned int sampleRate) -{ - return (sampleRate/100)*64; // .64s -} diff --git a/sdrbase/dsp/datafifo.h b/sdrbase/dsp/datafifo.h index 4adf4c3c5..d8ba18139 100644 --- a/sdrbase/dsp/datafifo.h +++ b/sdrbase/dsp/datafifo.h @@ -64,7 +64,6 @@ public: QByteArray::iterator* part1Begin, QByteArray::iterator* part1End, QByteArray::iterator* part2Begin, QByteArray::iterator* part2End); unsigned int readCommit(unsigned int count); - static unsigned int getSizePolicy(unsigned int sampleRate); signals: void dataReady(); diff --git a/sdrbase/maincore.cpp b/sdrbase/maincore.cpp index e8eecc955..87cec9ae3 100644 --- a/sdrbase/maincore.cpp +++ b/sdrbase/maincore.cpp @@ -47,6 +47,7 @@ MESSAGE_CLASS_DEFINITION(MainCore::MsgAddFeature, Message) MESSAGE_CLASS_DEFINITION(MainCore::MsgDeleteFeature, Message) MESSAGE_CLASS_DEFINITION(MainCore::MsgChannelReport, Message) MESSAGE_CLASS_DEFINITION(MainCore::MsgChannelSettings, Message) +MESSAGE_CLASS_DEFINITION(MainCore::MsgChannelDemodReport, Message) MainCore::MainCore() { diff --git a/sdrbase/maincore.h b/sdrbase/maincore.h index cf34f48ad..be6119abf 100644 --- a/sdrbase/maincore.h +++ b/sdrbase/maincore.h @@ -27,6 +27,7 @@ #include "settings/mainsettings.h" #include "util/message.h" #include "pipes/messagepipes.h" +#include "pipes/datapipes.h" class DeviceSet; class FeatureSet; @@ -437,6 +438,28 @@ public: { } }; + class SDRBASE_API MsgChannelDemodReport : public Message { + MESSAGE_CLASS_DECLARATION + + public: + const ChannelAPI *getChannelAPI() const { return m_channelAPI; } + int getSampleRate() const { return m_sampleRate; } + + static MsgChannelDemodReport* create(const ChannelAPI *channelAPI, int sampleRate) { + return new MsgChannelDemodReport(channelAPI, sampleRate); + } + + private: + const ChannelAPI *m_channelAPI; + int m_sampleRate; + + MsgChannelDemodReport(const ChannelAPI *channelAPI, int sampleRate) : + Message(), + m_channelAPI(channelAPI), + m_sampleRate(sampleRate) + { } + }; + class SDRBASE_API MsgChannelSettings : public Message { MESSAGE_CLASS_DECLARATION @@ -508,6 +531,7 @@ public: void clearFeatures(FeatureSet *featureSet); // pipes MessagePipes& getMessagePipes() { return m_messagePipes; } + DataPipes& getDataPipes() { return m_dataPipes; } friend class MainServer; friend class MainWindow; @@ -527,6 +551,7 @@ private: QMap m_featuresMap; //!< Feature to feature set map PluginManager* m_pluginManager; MessagePipes m_messagePipes; + DataPipes m_dataPipes; void debugMaps(); }; diff --git a/sdrbase/pipes/datapipes.cpp b/sdrbase/pipes/datapipes.cpp index e9f6ac0ac..0cd02c407 100644 --- a/sdrbase/pipes/datapipes.cpp +++ b/sdrbase/pipes/datapipes.cpp @@ -44,9 +44,11 @@ DataFifo *DataPipes::registerChannelToFeature(const ChannelAPI *source, Feature return m_registrations.registerProducerToConsumer(source, feature, type); } -void DataPipes::unregisterChannelToFeature(const ChannelAPI *source, Feature *feature, const QString& type) +DataFifo *DataPipes::unregisterChannelToFeature(const ChannelAPI *source, Feature *feature, const QString& type) { - m_registrations.unregisterProducerToConsumer(source, feature, type); + DataFifo *dataFifo = m_registrations.unregisterProducerToConsumer(source, feature, type); + m_gcWorker->addDataFifoToDelete(dataFifo); + return dataFifo; } QList* DataPipes::getFifos(const ChannelAPI *source, const QString& type) diff --git a/sdrbase/pipes/datapipes.h b/sdrbase/pipes/datapipes.h index 30941b22b..9f3fd76b4 100644 --- a/sdrbase/pipes/datapipes.h +++ b/sdrbase/pipes/datapipes.h @@ -44,7 +44,7 @@ public: ~DataPipes(); DataFifo *registerChannelToFeature(const ChannelAPI *source, Feature *feature, const QString& type); - void unregisterChannelToFeature(const ChannelAPI *source, Feature *feature, const QString& type); + DataFifo *unregisterChannelToFeature(const ChannelAPI *source, Feature *feature, const QString& type); QList* getFifos(const ChannelAPI *source, const QString& type); private: diff --git a/sdrbase/pipes/datapipesgcworker.cpp b/sdrbase/pipes/datapipesgcworker.cpp index 28abc6b1e..83b843b34 100644 --- a/sdrbase/pipes/datapipesgcworker.cpp +++ b/sdrbase/pipes/datapipesgcworker.cpp @@ -59,6 +59,15 @@ void DataPipesGCWorker::stopWork() disconnect(&m_gcTimer, SIGNAL(timeout()), this, SLOT(processGC())); } +void DataPipesGCWorker::addDataFifoToDelete(DataFifo *dataFifo) +{ + if (dataFifo) + { + m_gcTimer.start(10000); // restart GC to make sure deletion is postponed + m_dataPipesGC.addElementToDelete(dataFifo); + } +} + void DataPipesGCWorker::processGC() { // qDebug("MessagePipesGCWorker::processGC"); diff --git a/sdrbase/pipes/datapipesgcworker.h b/sdrbase/pipes/datapipesgcworker.h index 714aeae72..6fc5bc3bb 100644 --- a/sdrbase/pipes/datapipesgcworker.h +++ b/sdrbase/pipes/datapipesgcworker.h @@ -47,6 +47,7 @@ public: void startWork(); void stopWork(); + void addDataFifoToDelete(DataFifo *dataFifo); bool isRunning() const { return m_running; } private: diff --git a/sdrbase/pipes/elementpipesgc.h b/sdrbase/pipes/elementpipesgc.h index 7e8948968..6f8cb9490 100644 --- a/sdrbase/pipes/elementpipesgc.h +++ b/sdrbase/pipes/elementpipesgc.h @@ -48,6 +48,11 @@ public: m_consumers = consumers; } + void addElementToDelete(Element *element) + { + m_elementsToDelete.append(element); + } + void processGC() { if (m_mutex) diff --git a/sdrbase/pipes/elementpipesregistrations.h b/sdrbase/pipes/elementpipesregistrations.h index 1b2a9ed3c..7004684d4 100644 --- a/sdrbase/pipes/elementpipesregistrations.h +++ b/sdrbase/pipes/elementpipesregistrations.h @@ -82,8 +82,10 @@ public: return element; } - void unregisterProducerToConsumer(const Producer *producer, Consumer *consumer, const QString& type) + Element *unregisterProducerToConsumer(const Producer *producer, Consumer *consumer, const QString& type) { + Element *element = nullptr; + if (m_typeIds.contains(type)) { int typeId = m_typeIds.value(type); @@ -95,11 +97,13 @@ public: QMutexLocker mlock(&m_mutex); int i = m_consumers[regKey].indexOf(consumer); m_consumers[regKey].removeAt(i); - Element *element = m_elements[regKey][i]; - delete element; + element = m_elements[regKey][i]; + // delete element; // will be deferred to GC m_elements[regKey].removeAt(i); } } + + return element; } QList* getElements(const Producer *producer, const QString& type) diff --git a/sdrbase/pipes/messagepipes.cpp b/sdrbase/pipes/messagepipes.cpp index 377f0831a..9f997d5da 100644 --- a/sdrbase/pipes/messagepipes.cpp +++ b/sdrbase/pipes/messagepipes.cpp @@ -46,9 +46,11 @@ MessageQueue *MessagePipes::registerChannelToFeature(const ChannelAPI *source, F return m_registrations.registerProducerToConsumer(source, feature, type); } -void MessagePipes::unregisterChannelToFeature(const ChannelAPI *source, Feature *feature, const QString& type) +MessageQueue *MessagePipes::unregisterChannelToFeature(const ChannelAPI *source, Feature *feature, const QString& type) { - m_registrations.unregisterProducerToConsumer(source, feature, type); + MessageQueue *messageQueue = m_registrations.unregisterProducerToConsumer(source, feature, type); + m_gcWorker->addMessageQueueToDelete(messageQueue); + return messageQueue; } QList* MessagePipes::getMessageQueues(const ChannelAPI *source, const QString& type) diff --git a/sdrbase/pipes/messagepipes.h b/sdrbase/pipes/messagepipes.h index 5f54d7b6f..7b66f945d 100644 --- a/sdrbase/pipes/messagepipes.h +++ b/sdrbase/pipes/messagepipes.h @@ -44,7 +44,7 @@ public: ~MessagePipes(); MessageQueue *registerChannelToFeature(const ChannelAPI *source, Feature *feature, const QString& type); - void unregisterChannelToFeature(const ChannelAPI *source, Feature *feature, const QString& type); + MessageQueue *unregisterChannelToFeature(const ChannelAPI *source, Feature *feature, const QString& type); QList* getMessageQueues(const ChannelAPI *source, const QString& type); private: diff --git a/sdrbase/pipes/messagepipesgcworker.cpp b/sdrbase/pipes/messagepipesgcworker.cpp index c9dad9f78..53b877022 100644 --- a/sdrbase/pipes/messagepipesgcworker.cpp +++ b/sdrbase/pipes/messagepipesgcworker.cpp @@ -62,6 +62,15 @@ void MessagePipesGCWorker::stopWork() disconnect(&m_gcTimer, SIGNAL(timeout()), this, SLOT(processGC())); } +void MessagePipesGCWorker::addMessageQueueToDelete(MessageQueue *messageQueue) +{ + if (messageQueue) + { + m_gcTimer.start(10000); // restart GC to make sure deletion is postponed + m_messagePipesGC.addElementToDelete(messageQueue); + } +} + void MessagePipesGCWorker::processGC() { // qDebug("MessagePipesGCWorker::processGC"); diff --git a/sdrbase/pipes/messagepipesgcworker.h b/sdrbase/pipes/messagepipesgcworker.h index b692b7af1..0af0ecfde 100644 --- a/sdrbase/pipes/messagepipesgcworker.h +++ b/sdrbase/pipes/messagepipesgcworker.h @@ -46,6 +46,7 @@ public: void startWork(); void stopWork(); + void addMessageQueueToDelete(MessageQueue *messageQueue); bool isRunning() const { return m_running; } private: diff --git a/sdrbase/resources/webapi/doc/html2/index.html b/sdrbase/resources/webapi/doc/html2/index.html index 6fd4a4850..d47d11810 100644 --- a/sdrbase/resources/webapi/doc/html2/index.html +++ b/sdrbase/resources/webapi/doc/html2/index.html @@ -3400,6 +3400,45 @@ margin-bottom: 20px; } }, "description" : "List of DV serial devices available in the system" +}; + defs.DemodAnalyzerSettings = { + "properties" : { + "deviceIndex" : { + "type" : "integer" + }, + "channelIndex" : { + "type" : "integer" + }, + "title" : { + "type" : "string" + }, + "rgbColor" : { + "type" : "integer" + }, + "useReverseAPI" : { + "type" : "integer", + "description" : "Synchronize with reverse API\n * 1 - yes\n * 0 - no\n" + }, + "reverseAPIAddress" : { + "type" : "string" + }, + "reverseAPIPort" : { + "type" : "integer" + }, + "reverseAPIDeviceIndex" : { + "type" : "integer" + }, + "reverseAPIChannelIndex" : { + "type" : "integer" + }, + "spectrumConfig" : { + "$ref" : "#/definitions/GLSpectrum" + }, + "scopeConfig" : { + "$ref" : "#/definitions/GLScope" + } + }, + "description" : "DemodAnalyzer" }; defs.DeviceActions = { "required" : [ "deviceHwType", "direction" ], @@ -4083,18 +4122,21 @@ margin-bottom: 20px; "type" : "integer", "description" : "Optional for reverse API. This is the feature index from where the message comes from." }, - "GS232ControllerSettings" : { - "$ref" : "#/definitions/GS232ControllerSettings" - }, "AFCSettings" : { "$ref" : "#/definitions/AFCSettings" }, - "SimplePTTSettings" : { - "$ref" : "#/definitions/SimplePTTSettings" + "DemodAnalyzerSettings" : { + "$ref" : "#/definitions/DemodAnalyzerSettings" + }, + "GS232ControllerSettings" : { + "$ref" : "#/definitions/GS232ControllerSettings" }, "RigCtlServerSettings" : { "$ref" : "#/definitions/RigCtlServerSettings" }, + "SimplePTTSettings" : { + "$ref" : "#/definitions/SimplePTTSettings" + }, "VORLocalizerSettings" : { "$ref" : "#/definitions/VORLocalizerSettings" } @@ -44878,7 +44920,7 @@ except ApiException as e:
- Generated 2020-12-08T00:22:13.522+01:00 + Generated 2020-12-16T13:53:51.605+01:00
diff --git a/sdrbase/resources/webapi/doc/swagger/include/DemodAnalyzer.yaml b/sdrbase/resources/webapi/doc/swagger/include/DemodAnalyzer.yaml new file mode 100644 index 000000000..7533eb089 --- /dev/null +++ b/sdrbase/resources/webapi/doc/swagger/include/DemodAnalyzer.yaml @@ -0,0 +1,29 @@ +DemodAnalyzerSettings: + description: DemodAnalyzer + properties: + deviceIndex: + type: integer + channelIndex: + type: integer + title: + type: string + rgbColor: + type: integer + useReverseAPI: + type: integer + description: > + Synchronize with reverse API + * 1 - yes + * 0 - no + reverseAPIAddress: + type: string + reverseAPIPort: + type: integer + reverseAPIDeviceIndex: + type: integer + reverseAPIChannelIndex: + type: integer + spectrumConfig: + $ref: "/doc/swagger/include/GLSpectrum.yaml#/GLSpectrum" + scopeConfig: + $ref: "/doc/swagger/include/GLScope.yaml#/GLScope" diff --git a/sdrbase/resources/webapi/doc/swagger/include/FeatureSettings.yaml b/sdrbase/resources/webapi/doc/swagger/include/FeatureSettings.yaml index 675596ffb..d0a0a76ab 100644 --- a/sdrbase/resources/webapi/doc/swagger/include/FeatureSettings.yaml +++ b/sdrbase/resources/webapi/doc/swagger/include/FeatureSettings.yaml @@ -13,13 +13,15 @@ FeatureSettings: originatorFeatureIndex: description: Optional for reverse API. This is the feature index from where the message comes from. type: integer - GS232ControllerSettings: - $ref: "/doc/swagger/include/GS232Controller.yaml#/GS232ControllerSettings" AFCSettings: $ref: "/doc/swagger/include/AFC.yaml#/AFCSettings" - SimplePTTSettings: - $ref: "/doc/swagger/include/SimplePTT.yaml#/SimplePTTSettings" + DemodAnalyzerSettings: + $ref: "/doc/swagger/include/DemodAnalyzer.yaml#/DemodAnalyzerSettings" + GS232ControllerSettings: + $ref: "/doc/swagger/include/GS232Controller.yaml#/GS232ControllerSettings" RigCtlServerSettings: $ref: "/doc/swagger/include/RigCtlServer.yaml#/RigCtlServerSettings" + SimplePTTSettings: + $ref: "/doc/swagger/include/SimplePTT.yaml#/SimplePTTSettings" VORLocalizerSettings: $ref: "/doc/swagger/include/VORLocalizer.yaml#/VORLocalizerSettings" diff --git a/swagger/sdrangel/api/swagger/include/DemodAnalyzer.yaml b/swagger/sdrangel/api/swagger/include/DemodAnalyzer.yaml new file mode 100644 index 000000000..87f773140 --- /dev/null +++ b/swagger/sdrangel/api/swagger/include/DemodAnalyzer.yaml @@ -0,0 +1,29 @@ +DemodAnalyzerSettings: + description: DemodAnalyzer + properties: + deviceIndex: + type: integer + channelIndex: + type: integer + title: + type: string + rgbColor: + type: integer + useReverseAPI: + type: integer + description: > + Synchronize with reverse API + * 1 - yes + * 0 - no + reverseAPIAddress: + type: string + reverseAPIPort: + type: integer + reverseAPIDeviceIndex: + type: integer + reverseAPIChannelIndex: + type: integer + spectrumConfig: + $ref: "http://swgserver:8081/api/swagger/include/GLSpectrum.yaml#/GLSpectrum" + scopeConfig: + $ref: "http://swgserver:8081/api/swagger/include/GLScope.yaml#/GLScope" diff --git a/swagger/sdrangel/api/swagger/include/FeatureSettings.yaml b/swagger/sdrangel/api/swagger/include/FeatureSettings.yaml index ecdc645b7..791577406 100644 --- a/swagger/sdrangel/api/swagger/include/FeatureSettings.yaml +++ b/swagger/sdrangel/api/swagger/include/FeatureSettings.yaml @@ -13,13 +13,15 @@ FeatureSettings: originatorFeatureIndex: description: Optional for reverse API. This is the feature index from where the message comes from. type: integer - GS232ControllerSettings: - $ref: "http://swgserver:8081/api/swagger/include/GS232Controller.yaml#/GS232ControllerSettings" AFCSettings: $ref: "http://swgserver:8081/api/swagger/include/AFC.yaml#/AFCSettings" - SimplePTTSettings: - $ref: "http://swgserver:8081/api/swagger/include/SimplePTT.yaml#/SimplePTTSettings" + DemodAnalyzerSettings: + $ref: "http://swgserver:8081/api/swagger/include/DemodAnalyzer.yaml#/DemodAnalyzerSettings" + GS232ControllerSettings: + $ref: "http://swgserver:8081/api/swagger/include/GS232Controller.yaml#/GS232ControllerSettings" RigCtlServerSettings: $ref: "http://swgserver:8081/api/swagger/include/RigCtlServer.yaml#/RigCtlServerSettings" + SimplePTTSettings: + $ref: "http://swgserver:8081/api/swagger/include/SimplePTT.yaml#/SimplePTTSettings" VORLocalizerSettings: $ref: "http://swgserver:8081/api/swagger/include/VORLocalizer.yaml#/VORLocalizerSettings" diff --git a/swagger/sdrangel/code/html2/index.html b/swagger/sdrangel/code/html2/index.html index 6fd4a4850..d47d11810 100644 --- a/swagger/sdrangel/code/html2/index.html +++ b/swagger/sdrangel/code/html2/index.html @@ -3400,6 +3400,45 @@ margin-bottom: 20px; } }, "description" : "List of DV serial devices available in the system" +}; + defs.DemodAnalyzerSettings = { + "properties" : { + "deviceIndex" : { + "type" : "integer" + }, + "channelIndex" : { + "type" : "integer" + }, + "title" : { + "type" : "string" + }, + "rgbColor" : { + "type" : "integer" + }, + "useReverseAPI" : { + "type" : "integer", + "description" : "Synchronize with reverse API\n * 1 - yes\n * 0 - no\n" + }, + "reverseAPIAddress" : { + "type" : "string" + }, + "reverseAPIPort" : { + "type" : "integer" + }, + "reverseAPIDeviceIndex" : { + "type" : "integer" + }, + "reverseAPIChannelIndex" : { + "type" : "integer" + }, + "spectrumConfig" : { + "$ref" : "#/definitions/GLSpectrum" + }, + "scopeConfig" : { + "$ref" : "#/definitions/GLScope" + } + }, + "description" : "DemodAnalyzer" }; defs.DeviceActions = { "required" : [ "deviceHwType", "direction" ], @@ -4083,18 +4122,21 @@ margin-bottom: 20px; "type" : "integer", "description" : "Optional for reverse API. This is the feature index from where the message comes from." }, - "GS232ControllerSettings" : { - "$ref" : "#/definitions/GS232ControllerSettings" - }, "AFCSettings" : { "$ref" : "#/definitions/AFCSettings" }, - "SimplePTTSettings" : { - "$ref" : "#/definitions/SimplePTTSettings" + "DemodAnalyzerSettings" : { + "$ref" : "#/definitions/DemodAnalyzerSettings" + }, + "GS232ControllerSettings" : { + "$ref" : "#/definitions/GS232ControllerSettings" }, "RigCtlServerSettings" : { "$ref" : "#/definitions/RigCtlServerSettings" }, + "SimplePTTSettings" : { + "$ref" : "#/definitions/SimplePTTSettings" + }, "VORLocalizerSettings" : { "$ref" : "#/definitions/VORLocalizerSettings" } @@ -44878,7 +44920,7 @@ except ApiException as e:
- Generated 2020-12-08T00:22:13.522+01:00 + Generated 2020-12-16T13:53:51.605+01:00
diff --git a/swagger/sdrangel/code/qt5/client/SWGDemodAnalyzerSettings.cpp b/swagger/sdrangel/code/qt5/client/SWGDemodAnalyzerSettings.cpp new file mode 100644 index 000000000..419fb6cd2 --- /dev/null +++ b/swagger/sdrangel/code/qt5/client/SWGDemodAnalyzerSettings.cpp @@ -0,0 +1,346 @@ +/** + * SDRangel + * This is the web REST/JSON API of SDRangel SDR software. SDRangel is an Open Source Qt5/OpenGL 3.0+ (4.3+ in Windows) GUI and server Software Defined Radio and signal analyzer in software. It supports Airspy, BladeRF, HackRF, LimeSDR, PlutoSDR, RTL-SDR, SDRplay RSP1 and FunCube --- Limitations and specifcities: * In SDRangel GUI the first Rx device set cannot be deleted. Conversely the server starts with no device sets and its number of device sets can be reduced to zero by as many calls as necessary to /sdrangel/deviceset with DELETE method. * Preset import and export from/to file is a server only feature. * Device set focus is a GUI only feature. * The following channels are not implemented (status 501 is returned): ATV and DATV demodulators, Channel Analyzer NG, LoRa demodulator * The device settings and report structures contains only the sub-structure corresponding to the device type. The DeviceSettings and DeviceReport structures documented here shows all of them but only one will be or should be present at a time * The channel settings and report structures contains only the sub-structure corresponding to the channel type. The ChannelSettings and ChannelReport structures documented here shows all of them but only one will be or should be present at a time --- + * + * OpenAPI spec version: 6.0.0 + * Contact: f4exb06@gmail.com + * + * NOTE: This class is auto generated by the swagger code generator program. + * https://github.com/swagger-api/swagger-codegen.git + * Do not edit the class manually. + */ + + +#include "SWGDemodAnalyzerSettings.h" + +#include "SWGHelpers.h" + +#include +#include +#include +#include + +namespace SWGSDRangel { + +SWGDemodAnalyzerSettings::SWGDemodAnalyzerSettings(QString* json) { + init(); + this->fromJson(*json); +} + +SWGDemodAnalyzerSettings::SWGDemodAnalyzerSettings() { + device_index = 0; + m_device_index_isSet = false; + channel_index = 0; + m_channel_index_isSet = false; + title = nullptr; + m_title_isSet = false; + rgb_color = 0; + m_rgb_color_isSet = false; + use_reverse_api = 0; + m_use_reverse_api_isSet = false; + reverse_api_address = nullptr; + m_reverse_api_address_isSet = false; + reverse_api_port = 0; + m_reverse_api_port_isSet = false; + reverse_api_device_index = 0; + m_reverse_api_device_index_isSet = false; + reverse_api_channel_index = 0; + m_reverse_api_channel_index_isSet = false; + spectrum_config = nullptr; + m_spectrum_config_isSet = false; + scope_config = nullptr; + m_scope_config_isSet = false; +} + +SWGDemodAnalyzerSettings::~SWGDemodAnalyzerSettings() { + this->cleanup(); +} + +void +SWGDemodAnalyzerSettings::init() { + device_index = 0; + m_device_index_isSet = false; + channel_index = 0; + m_channel_index_isSet = false; + title = new QString(""); + m_title_isSet = false; + rgb_color = 0; + m_rgb_color_isSet = false; + use_reverse_api = 0; + m_use_reverse_api_isSet = false; + reverse_api_address = new QString(""); + m_reverse_api_address_isSet = false; + reverse_api_port = 0; + m_reverse_api_port_isSet = false; + reverse_api_device_index = 0; + m_reverse_api_device_index_isSet = false; + reverse_api_channel_index = 0; + m_reverse_api_channel_index_isSet = false; + spectrum_config = new SWGGLSpectrum(); + m_spectrum_config_isSet = false; + scope_config = new SWGGLScope(); + m_scope_config_isSet = false; +} + +void +SWGDemodAnalyzerSettings::cleanup() { + + + if(title != nullptr) { + delete title; + } + + + if(reverse_api_address != nullptr) { + delete reverse_api_address; + } + + + + if(spectrum_config != nullptr) { + delete spectrum_config; + } + if(scope_config != nullptr) { + delete scope_config; + } +} + +SWGDemodAnalyzerSettings* +SWGDemodAnalyzerSettings::fromJson(QString &json) { + QByteArray array (json.toStdString().c_str()); + QJsonDocument doc = QJsonDocument::fromJson(array); + QJsonObject jsonObject = doc.object(); + this->fromJsonObject(jsonObject); + return this; +} + +void +SWGDemodAnalyzerSettings::fromJsonObject(QJsonObject &pJson) { + ::SWGSDRangel::setValue(&device_index, pJson["deviceIndex"], "qint32", ""); + + ::SWGSDRangel::setValue(&channel_index, pJson["channelIndex"], "qint32", ""); + + ::SWGSDRangel::setValue(&title, pJson["title"], "QString", "QString"); + + ::SWGSDRangel::setValue(&rgb_color, pJson["rgbColor"], "qint32", ""); + + ::SWGSDRangel::setValue(&use_reverse_api, pJson["useReverseAPI"], "qint32", ""); + + ::SWGSDRangel::setValue(&reverse_api_address, pJson["reverseAPIAddress"], "QString", "QString"); + + ::SWGSDRangel::setValue(&reverse_api_port, pJson["reverseAPIPort"], "qint32", ""); + + ::SWGSDRangel::setValue(&reverse_api_device_index, pJson["reverseAPIDeviceIndex"], "qint32", ""); + + ::SWGSDRangel::setValue(&reverse_api_channel_index, pJson["reverseAPIChannelIndex"], "qint32", ""); + + ::SWGSDRangel::setValue(&spectrum_config, pJson["spectrumConfig"], "SWGGLSpectrum", "SWGGLSpectrum"); + + ::SWGSDRangel::setValue(&scope_config, pJson["scopeConfig"], "SWGGLScope", "SWGGLScope"); + +} + +QString +SWGDemodAnalyzerSettings::asJson () +{ + QJsonObject* obj = this->asJsonObject(); + + QJsonDocument doc(*obj); + QByteArray bytes = doc.toJson(); + delete obj; + return QString(bytes); +} + +QJsonObject* +SWGDemodAnalyzerSettings::asJsonObject() { + QJsonObject* obj = new QJsonObject(); + if(m_device_index_isSet){ + obj->insert("deviceIndex", QJsonValue(device_index)); + } + if(m_channel_index_isSet){ + obj->insert("channelIndex", QJsonValue(channel_index)); + } + if(title != nullptr && *title != QString("")){ + toJsonValue(QString("title"), title, obj, QString("QString")); + } + if(m_rgb_color_isSet){ + obj->insert("rgbColor", QJsonValue(rgb_color)); + } + if(m_use_reverse_api_isSet){ + obj->insert("useReverseAPI", QJsonValue(use_reverse_api)); + } + if(reverse_api_address != nullptr && *reverse_api_address != QString("")){ + toJsonValue(QString("reverseAPIAddress"), reverse_api_address, obj, QString("QString")); + } + if(m_reverse_api_port_isSet){ + obj->insert("reverseAPIPort", QJsonValue(reverse_api_port)); + } + if(m_reverse_api_device_index_isSet){ + obj->insert("reverseAPIDeviceIndex", QJsonValue(reverse_api_device_index)); + } + if(m_reverse_api_channel_index_isSet){ + obj->insert("reverseAPIChannelIndex", QJsonValue(reverse_api_channel_index)); + } + if((spectrum_config != nullptr) && (spectrum_config->isSet())){ + toJsonValue(QString("spectrumConfig"), spectrum_config, obj, QString("SWGGLSpectrum")); + } + if((scope_config != nullptr) && (scope_config->isSet())){ + toJsonValue(QString("scopeConfig"), scope_config, obj, QString("SWGGLScope")); + } + + return obj; +} + +qint32 +SWGDemodAnalyzerSettings::getDeviceIndex() { + return device_index; +} +void +SWGDemodAnalyzerSettings::setDeviceIndex(qint32 device_index) { + this->device_index = device_index; + this->m_device_index_isSet = true; +} + +qint32 +SWGDemodAnalyzerSettings::getChannelIndex() { + return channel_index; +} +void +SWGDemodAnalyzerSettings::setChannelIndex(qint32 channel_index) { + this->channel_index = channel_index; + this->m_channel_index_isSet = true; +} + +QString* +SWGDemodAnalyzerSettings::getTitle() { + return title; +} +void +SWGDemodAnalyzerSettings::setTitle(QString* title) { + this->title = title; + this->m_title_isSet = true; +} + +qint32 +SWGDemodAnalyzerSettings::getRgbColor() { + return rgb_color; +} +void +SWGDemodAnalyzerSettings::setRgbColor(qint32 rgb_color) { + this->rgb_color = rgb_color; + this->m_rgb_color_isSet = true; +} + +qint32 +SWGDemodAnalyzerSettings::getUseReverseApi() { + return use_reverse_api; +} +void +SWGDemodAnalyzerSettings::setUseReverseApi(qint32 use_reverse_api) { + this->use_reverse_api = use_reverse_api; + this->m_use_reverse_api_isSet = true; +} + +QString* +SWGDemodAnalyzerSettings::getReverseApiAddress() { + return reverse_api_address; +} +void +SWGDemodAnalyzerSettings::setReverseApiAddress(QString* reverse_api_address) { + this->reverse_api_address = reverse_api_address; + this->m_reverse_api_address_isSet = true; +} + +qint32 +SWGDemodAnalyzerSettings::getReverseApiPort() { + return reverse_api_port; +} +void +SWGDemodAnalyzerSettings::setReverseApiPort(qint32 reverse_api_port) { + this->reverse_api_port = reverse_api_port; + this->m_reverse_api_port_isSet = true; +} + +qint32 +SWGDemodAnalyzerSettings::getReverseApiDeviceIndex() { + return reverse_api_device_index; +} +void +SWGDemodAnalyzerSettings::setReverseApiDeviceIndex(qint32 reverse_api_device_index) { + this->reverse_api_device_index = reverse_api_device_index; + this->m_reverse_api_device_index_isSet = true; +} + +qint32 +SWGDemodAnalyzerSettings::getReverseApiChannelIndex() { + return reverse_api_channel_index; +} +void +SWGDemodAnalyzerSettings::setReverseApiChannelIndex(qint32 reverse_api_channel_index) { + this->reverse_api_channel_index = reverse_api_channel_index; + this->m_reverse_api_channel_index_isSet = true; +} + +SWGGLSpectrum* +SWGDemodAnalyzerSettings::getSpectrumConfig() { + return spectrum_config; +} +void +SWGDemodAnalyzerSettings::setSpectrumConfig(SWGGLSpectrum* spectrum_config) { + this->spectrum_config = spectrum_config; + this->m_spectrum_config_isSet = true; +} + +SWGGLScope* +SWGDemodAnalyzerSettings::getScopeConfig() { + return scope_config; +} +void +SWGDemodAnalyzerSettings::setScopeConfig(SWGGLScope* scope_config) { + this->scope_config = scope_config; + this->m_scope_config_isSet = true; +} + + +bool +SWGDemodAnalyzerSettings::isSet(){ + bool isObjectUpdated = false; + do{ + if(m_device_index_isSet){ + isObjectUpdated = true; break; + } + if(m_channel_index_isSet){ + isObjectUpdated = true; break; + } + if(title && *title != QString("")){ + isObjectUpdated = true; break; + } + if(m_rgb_color_isSet){ + isObjectUpdated = true; break; + } + if(m_use_reverse_api_isSet){ + isObjectUpdated = true; break; + } + if(reverse_api_address && *reverse_api_address != QString("")){ + isObjectUpdated = true; break; + } + if(m_reverse_api_port_isSet){ + isObjectUpdated = true; break; + } + if(m_reverse_api_device_index_isSet){ + isObjectUpdated = true; break; + } + if(m_reverse_api_channel_index_isSet){ + isObjectUpdated = true; break; + } + if(spectrum_config && spectrum_config->isSet()){ + isObjectUpdated = true; break; + } + if(scope_config && scope_config->isSet()){ + isObjectUpdated = true; break; + } + }while(false); + return isObjectUpdated; +} +} + diff --git a/swagger/sdrangel/code/qt5/client/SWGDemodAnalyzerSettings.h b/swagger/sdrangel/code/qt5/client/SWGDemodAnalyzerSettings.h new file mode 100644 index 000000000..557c3cb0b --- /dev/null +++ b/swagger/sdrangel/code/qt5/client/SWGDemodAnalyzerSettings.h @@ -0,0 +1,121 @@ +/** + * SDRangel + * This is the web REST/JSON API of SDRangel SDR software. SDRangel is an Open Source Qt5/OpenGL 3.0+ (4.3+ in Windows) GUI and server Software Defined Radio and signal analyzer in software. It supports Airspy, BladeRF, HackRF, LimeSDR, PlutoSDR, RTL-SDR, SDRplay RSP1 and FunCube --- Limitations and specifcities: * In SDRangel GUI the first Rx device set cannot be deleted. Conversely the server starts with no device sets and its number of device sets can be reduced to zero by as many calls as necessary to /sdrangel/deviceset with DELETE method. * Preset import and export from/to file is a server only feature. * Device set focus is a GUI only feature. * The following channels are not implemented (status 501 is returned): ATV and DATV demodulators, Channel Analyzer NG, LoRa demodulator * The device settings and report structures contains only the sub-structure corresponding to the device type. The DeviceSettings and DeviceReport structures documented here shows all of them but only one will be or should be present at a time * The channel settings and report structures contains only the sub-structure corresponding to the channel type. The ChannelSettings and ChannelReport structures documented here shows all of them but only one will be or should be present at a time --- + * + * OpenAPI spec version: 6.0.0 + * Contact: f4exb06@gmail.com + * + * NOTE: This class is auto generated by the swagger code generator program. + * https://github.com/swagger-api/swagger-codegen.git + * Do not edit the class manually. + */ + +/* + * SWGDemodAnalyzerSettings.h + * + * DemodAnalyzer + */ + +#ifndef SWGDemodAnalyzerSettings_H_ +#define SWGDemodAnalyzerSettings_H_ + +#include + + +#include "SWGGLScope.h" +#include "SWGGLSpectrum.h" +#include + +#include "SWGObject.h" +#include "export.h" + +namespace SWGSDRangel { + +class SWG_API SWGDemodAnalyzerSettings: public SWGObject { +public: + SWGDemodAnalyzerSettings(); + SWGDemodAnalyzerSettings(QString* json); + virtual ~SWGDemodAnalyzerSettings(); + void init(); + void cleanup(); + + virtual QString asJson () override; + virtual QJsonObject* asJsonObject() override; + virtual void fromJsonObject(QJsonObject &json) override; + virtual SWGDemodAnalyzerSettings* fromJson(QString &jsonString) override; + + qint32 getDeviceIndex(); + void setDeviceIndex(qint32 device_index); + + qint32 getChannelIndex(); + void setChannelIndex(qint32 channel_index); + + QString* getTitle(); + void setTitle(QString* title); + + qint32 getRgbColor(); + void setRgbColor(qint32 rgb_color); + + qint32 getUseReverseApi(); + void setUseReverseApi(qint32 use_reverse_api); + + QString* getReverseApiAddress(); + void setReverseApiAddress(QString* reverse_api_address); + + qint32 getReverseApiPort(); + void setReverseApiPort(qint32 reverse_api_port); + + qint32 getReverseApiDeviceIndex(); + void setReverseApiDeviceIndex(qint32 reverse_api_device_index); + + qint32 getReverseApiChannelIndex(); + void setReverseApiChannelIndex(qint32 reverse_api_channel_index); + + SWGGLSpectrum* getSpectrumConfig(); + void setSpectrumConfig(SWGGLSpectrum* spectrum_config); + + SWGGLScope* getScopeConfig(); + void setScopeConfig(SWGGLScope* scope_config); + + + virtual bool isSet() override; + +private: + qint32 device_index; + bool m_device_index_isSet; + + qint32 channel_index; + bool m_channel_index_isSet; + + QString* title; + bool m_title_isSet; + + qint32 rgb_color; + bool m_rgb_color_isSet; + + qint32 use_reverse_api; + bool m_use_reverse_api_isSet; + + QString* reverse_api_address; + bool m_reverse_api_address_isSet; + + qint32 reverse_api_port; + bool m_reverse_api_port_isSet; + + qint32 reverse_api_device_index; + bool m_reverse_api_device_index_isSet; + + qint32 reverse_api_channel_index; + bool m_reverse_api_channel_index_isSet; + + SWGGLSpectrum* spectrum_config; + bool m_spectrum_config_isSet; + + SWGGLScope* scope_config; + bool m_scope_config_isSet; + +}; + +} + +#endif /* SWGDemodAnalyzerSettings_H_ */ diff --git a/swagger/sdrangel/code/qt5/client/SWGFeatureSettings.cpp b/swagger/sdrangel/code/qt5/client/SWGFeatureSettings.cpp index 45c6899c6..f2dae2151 100644 --- a/swagger/sdrangel/code/qt5/client/SWGFeatureSettings.cpp +++ b/swagger/sdrangel/code/qt5/client/SWGFeatureSettings.cpp @@ -34,14 +34,16 @@ SWGFeatureSettings::SWGFeatureSettings() { m_originator_feature_set_index_isSet = false; originator_feature_index = 0; m_originator_feature_index_isSet = false; - gs232_controller_settings = nullptr; - m_gs232_controller_settings_isSet = false; afc_settings = nullptr; m_afc_settings_isSet = false; - simple_ptt_settings = nullptr; - m_simple_ptt_settings_isSet = false; + demod_analyzer_settings = nullptr; + m_demod_analyzer_settings_isSet = false; + gs232_controller_settings = nullptr; + m_gs232_controller_settings_isSet = false; rig_ctl_server_settings = nullptr; m_rig_ctl_server_settings_isSet = false; + simple_ptt_settings = nullptr; + m_simple_ptt_settings_isSet = false; vor_localizer_settings = nullptr; m_vor_localizer_settings_isSet = false; } @@ -58,14 +60,16 @@ SWGFeatureSettings::init() { m_originator_feature_set_index_isSet = false; originator_feature_index = 0; m_originator_feature_index_isSet = false; - gs232_controller_settings = new SWGGS232ControllerSettings(); - m_gs232_controller_settings_isSet = false; afc_settings = new SWGAFCSettings(); m_afc_settings_isSet = false; - simple_ptt_settings = new SWGSimplePTTSettings(); - m_simple_ptt_settings_isSet = false; + demod_analyzer_settings = new SWGDemodAnalyzerSettings(); + m_demod_analyzer_settings_isSet = false; + gs232_controller_settings = new SWGGS232ControllerSettings(); + m_gs232_controller_settings_isSet = false; rig_ctl_server_settings = new SWGRigCtlServerSettings(); m_rig_ctl_server_settings_isSet = false; + simple_ptt_settings = new SWGSimplePTTSettings(); + m_simple_ptt_settings_isSet = false; vor_localizer_settings = new SWGVORLocalizerSettings(); m_vor_localizer_settings_isSet = false; } @@ -77,18 +81,21 @@ SWGFeatureSettings::cleanup() { } - if(gs232_controller_settings != nullptr) { - delete gs232_controller_settings; - } if(afc_settings != nullptr) { delete afc_settings; } - if(simple_ptt_settings != nullptr) { - delete simple_ptt_settings; + if(demod_analyzer_settings != nullptr) { + delete demod_analyzer_settings; + } + if(gs232_controller_settings != nullptr) { + delete gs232_controller_settings; } if(rig_ctl_server_settings != nullptr) { delete rig_ctl_server_settings; } + if(simple_ptt_settings != nullptr) { + delete simple_ptt_settings; + } if(vor_localizer_settings != nullptr) { delete vor_localizer_settings; } @@ -111,14 +118,16 @@ SWGFeatureSettings::fromJsonObject(QJsonObject &pJson) { ::SWGSDRangel::setValue(&originator_feature_index, pJson["originatorFeatureIndex"], "qint32", ""); - ::SWGSDRangel::setValue(&gs232_controller_settings, pJson["GS232ControllerSettings"], "SWGGS232ControllerSettings", "SWGGS232ControllerSettings"); - ::SWGSDRangel::setValue(&afc_settings, pJson["AFCSettings"], "SWGAFCSettings", "SWGAFCSettings"); - ::SWGSDRangel::setValue(&simple_ptt_settings, pJson["SimplePTTSettings"], "SWGSimplePTTSettings", "SWGSimplePTTSettings"); + ::SWGSDRangel::setValue(&demod_analyzer_settings, pJson["DemodAnalyzerSettings"], "SWGDemodAnalyzerSettings", "SWGDemodAnalyzerSettings"); + + ::SWGSDRangel::setValue(&gs232_controller_settings, pJson["GS232ControllerSettings"], "SWGGS232ControllerSettings", "SWGGS232ControllerSettings"); ::SWGSDRangel::setValue(&rig_ctl_server_settings, pJson["RigCtlServerSettings"], "SWGRigCtlServerSettings", "SWGRigCtlServerSettings"); + ::SWGSDRangel::setValue(&simple_ptt_settings, pJson["SimplePTTSettings"], "SWGSimplePTTSettings", "SWGSimplePTTSettings"); + ::SWGSDRangel::setValue(&vor_localizer_settings, pJson["VORLocalizerSettings"], "SWGVORLocalizerSettings", "SWGVORLocalizerSettings"); } @@ -146,18 +155,21 @@ SWGFeatureSettings::asJsonObject() { if(m_originator_feature_index_isSet){ obj->insert("originatorFeatureIndex", QJsonValue(originator_feature_index)); } - if((gs232_controller_settings != nullptr) && (gs232_controller_settings->isSet())){ - toJsonValue(QString("GS232ControllerSettings"), gs232_controller_settings, obj, QString("SWGGS232ControllerSettings")); - } if((afc_settings != nullptr) && (afc_settings->isSet())){ toJsonValue(QString("AFCSettings"), afc_settings, obj, QString("SWGAFCSettings")); } - if((simple_ptt_settings != nullptr) && (simple_ptt_settings->isSet())){ - toJsonValue(QString("SimplePTTSettings"), simple_ptt_settings, obj, QString("SWGSimplePTTSettings")); + if((demod_analyzer_settings != nullptr) && (demod_analyzer_settings->isSet())){ + toJsonValue(QString("DemodAnalyzerSettings"), demod_analyzer_settings, obj, QString("SWGDemodAnalyzerSettings")); + } + if((gs232_controller_settings != nullptr) && (gs232_controller_settings->isSet())){ + toJsonValue(QString("GS232ControllerSettings"), gs232_controller_settings, obj, QString("SWGGS232ControllerSettings")); } if((rig_ctl_server_settings != nullptr) && (rig_ctl_server_settings->isSet())){ toJsonValue(QString("RigCtlServerSettings"), rig_ctl_server_settings, obj, QString("SWGRigCtlServerSettings")); } + if((simple_ptt_settings != nullptr) && (simple_ptt_settings->isSet())){ + toJsonValue(QString("SimplePTTSettings"), simple_ptt_settings, obj, QString("SWGSimplePTTSettings")); + } if((vor_localizer_settings != nullptr) && (vor_localizer_settings->isSet())){ toJsonValue(QString("VORLocalizerSettings"), vor_localizer_settings, obj, QString("SWGVORLocalizerSettings")); } @@ -195,16 +207,6 @@ SWGFeatureSettings::setOriginatorFeatureIndex(qint32 originator_feature_index) { this->m_originator_feature_index_isSet = true; } -SWGGS232ControllerSettings* -SWGFeatureSettings::getGs232ControllerSettings() { - return gs232_controller_settings; -} -void -SWGFeatureSettings::setGs232ControllerSettings(SWGGS232ControllerSettings* gs232_controller_settings) { - this->gs232_controller_settings = gs232_controller_settings; - this->m_gs232_controller_settings_isSet = true; -} - SWGAFCSettings* SWGFeatureSettings::getAfcSettings() { return afc_settings; @@ -215,14 +217,24 @@ SWGFeatureSettings::setAfcSettings(SWGAFCSettings* afc_settings) { this->m_afc_settings_isSet = true; } -SWGSimplePTTSettings* -SWGFeatureSettings::getSimplePttSettings() { - return simple_ptt_settings; +SWGDemodAnalyzerSettings* +SWGFeatureSettings::getDemodAnalyzerSettings() { + return demod_analyzer_settings; } void -SWGFeatureSettings::setSimplePttSettings(SWGSimplePTTSettings* simple_ptt_settings) { - this->simple_ptt_settings = simple_ptt_settings; - this->m_simple_ptt_settings_isSet = true; +SWGFeatureSettings::setDemodAnalyzerSettings(SWGDemodAnalyzerSettings* demod_analyzer_settings) { + this->demod_analyzer_settings = demod_analyzer_settings; + this->m_demod_analyzer_settings_isSet = true; +} + +SWGGS232ControllerSettings* +SWGFeatureSettings::getGs232ControllerSettings() { + return gs232_controller_settings; +} +void +SWGFeatureSettings::setGs232ControllerSettings(SWGGS232ControllerSettings* gs232_controller_settings) { + this->gs232_controller_settings = gs232_controller_settings; + this->m_gs232_controller_settings_isSet = true; } SWGRigCtlServerSettings* @@ -235,6 +247,16 @@ SWGFeatureSettings::setRigCtlServerSettings(SWGRigCtlServerSettings* rig_ctl_ser this->m_rig_ctl_server_settings_isSet = true; } +SWGSimplePTTSettings* +SWGFeatureSettings::getSimplePttSettings() { + return simple_ptt_settings; +} +void +SWGFeatureSettings::setSimplePttSettings(SWGSimplePTTSettings* simple_ptt_settings) { + this->simple_ptt_settings = simple_ptt_settings; + this->m_simple_ptt_settings_isSet = true; +} + SWGVORLocalizerSettings* SWGFeatureSettings::getVorLocalizerSettings() { return vor_localizer_settings; @@ -259,18 +281,21 @@ SWGFeatureSettings::isSet(){ if(m_originator_feature_index_isSet){ isObjectUpdated = true; break; } - if(gs232_controller_settings && gs232_controller_settings->isSet()){ - isObjectUpdated = true; break; - } if(afc_settings && afc_settings->isSet()){ isObjectUpdated = true; break; } - if(simple_ptt_settings && simple_ptt_settings->isSet()){ + if(demod_analyzer_settings && demod_analyzer_settings->isSet()){ + isObjectUpdated = true; break; + } + if(gs232_controller_settings && gs232_controller_settings->isSet()){ isObjectUpdated = true; break; } if(rig_ctl_server_settings && rig_ctl_server_settings->isSet()){ isObjectUpdated = true; break; } + if(simple_ptt_settings && simple_ptt_settings->isSet()){ + isObjectUpdated = true; break; + } if(vor_localizer_settings && vor_localizer_settings->isSet()){ isObjectUpdated = true; break; } diff --git a/swagger/sdrangel/code/qt5/client/SWGFeatureSettings.h b/swagger/sdrangel/code/qt5/client/SWGFeatureSettings.h index de48ba254..9ce7e16d5 100644 --- a/swagger/sdrangel/code/qt5/client/SWGFeatureSettings.h +++ b/swagger/sdrangel/code/qt5/client/SWGFeatureSettings.h @@ -23,6 +23,7 @@ #include "SWGAFCSettings.h" +#include "SWGDemodAnalyzerSettings.h" #include "SWGGS232ControllerSettings.h" #include "SWGRigCtlServerSettings.h" #include "SWGSimplePTTSettings.h" @@ -56,18 +57,21 @@ public: qint32 getOriginatorFeatureIndex(); void setOriginatorFeatureIndex(qint32 originator_feature_index); - SWGGS232ControllerSettings* getGs232ControllerSettings(); - void setGs232ControllerSettings(SWGGS232ControllerSettings* gs232_controller_settings); - SWGAFCSettings* getAfcSettings(); void setAfcSettings(SWGAFCSettings* afc_settings); - SWGSimplePTTSettings* getSimplePttSettings(); - void setSimplePttSettings(SWGSimplePTTSettings* simple_ptt_settings); + SWGDemodAnalyzerSettings* getDemodAnalyzerSettings(); + void setDemodAnalyzerSettings(SWGDemodAnalyzerSettings* demod_analyzer_settings); + + SWGGS232ControllerSettings* getGs232ControllerSettings(); + void setGs232ControllerSettings(SWGGS232ControllerSettings* gs232_controller_settings); SWGRigCtlServerSettings* getRigCtlServerSettings(); void setRigCtlServerSettings(SWGRigCtlServerSettings* rig_ctl_server_settings); + SWGSimplePTTSettings* getSimplePttSettings(); + void setSimplePttSettings(SWGSimplePTTSettings* simple_ptt_settings); + SWGVORLocalizerSettings* getVorLocalizerSettings(); void setVorLocalizerSettings(SWGVORLocalizerSettings* vor_localizer_settings); @@ -84,18 +88,21 @@ private: qint32 originator_feature_index; bool m_originator_feature_index_isSet; - SWGGS232ControllerSettings* gs232_controller_settings; - bool m_gs232_controller_settings_isSet; - SWGAFCSettings* afc_settings; bool m_afc_settings_isSet; - SWGSimplePTTSettings* simple_ptt_settings; - bool m_simple_ptt_settings_isSet; + SWGDemodAnalyzerSettings* demod_analyzer_settings; + bool m_demod_analyzer_settings_isSet; + + SWGGS232ControllerSettings* gs232_controller_settings; + bool m_gs232_controller_settings_isSet; SWGRigCtlServerSettings* rig_ctl_server_settings; bool m_rig_ctl_server_settings_isSet; + SWGSimplePTTSettings* simple_ptt_settings; + bool m_simple_ptt_settings_isSet; + SWGVORLocalizerSettings* vor_localizer_settings; bool m_vor_localizer_settings_isSet; diff --git a/swagger/sdrangel/code/qt5/client/SWGModelFactory.h b/swagger/sdrangel/code/qt5/client/SWGModelFactory.h index a58dd73ee..a14ea8262 100644 --- a/swagger/sdrangel/code/qt5/client/SWGModelFactory.h +++ b/swagger/sdrangel/code/qt5/client/SWGModelFactory.h @@ -72,6 +72,7 @@ #include "SWGDSDDemodSettings.h" #include "SWGDVSerialDevice.h" #include "SWGDVSerialDevices.h" +#include "SWGDemodAnalyzerSettings.h" #include "SWGDeviceActions.h" #include "SWGDeviceConfig.h" #include "SWGDeviceListItem.h" @@ -414,6 +415,9 @@ namespace SWGSDRangel { if(QString("SWGDVSerialDevices").compare(type) == 0) { return new SWGDVSerialDevices(); } + if(QString("SWGDemodAnalyzerSettings").compare(type) == 0) { + return new SWGDemodAnalyzerSettings(); + } if(QString("SWGDeviceActions").compare(type) == 0) { return new SWGDeviceActions(); }