Demod Analyzer implementation with AM modulator and demodulator

This commit is contained in:
f4exb 2020-12-20 01:53:03 +01:00
parent af3f016f0b
commit 321cffc9c7
57 changed files with 3595 additions and 97 deletions

View File

@ -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);

View File

@ -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);

View File

@ -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
#endif // INCLUDE_AMDEMODBASEBAND_H

View File

@ -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,

View File

@ -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<DataFifo*> *dataFifos = MainCore::instance()->getDataPipes().getFifos(m_channel, "demod");
if (dataFifos)
{
QList<DataFifo*>::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<MessageQueue*> *messageQueues = MainCore::instance()->getMessagePipes().getMessageQueues(m_channel, "reportdemod");
if (messageQueues)
{
QList<MessageQueue*>::iterator it = messageQueues->begin();
for (; it != messageQueues->end(); ++it)
{
MainCore::MsgChannelDemodReport *msg = MainCore::MsgChannelDemodReport::create(m_channel, sampleRate);
(*it)->push(msg);
}
}
m_audioSampleRate = sampleRate;
}

View File

@ -18,6 +18,8 @@
#ifndef INCLUDE_AMDEMODSINK_H
#define INCLUDE_AMDEMODSINK_H
#include <QVector>
#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<qint16> m_demodBuffer;
int m_demodBufferFill;
void processOneSample(Complex &ci);
};

View File

@ -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);

View File

@ -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();
}
}

View File

@ -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:
/**

View File

@ -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,

View File

@ -17,6 +17,10 @@
#include <QDebug>
#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<DataFifo*> *dataFifos = MainCore::instance()->getDataPipes().getFifos(m_channel, "demod");
if (dataFifos)
{
QList<DataFifo*>::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<MessageQueue*> *messageQueues = MainCore::instance()->getMessagePipes().getMessageQueues(m_channel, "reportdemod");
if (messageQueues)
{
QList<MessageQueue*>::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);
}

View File

@ -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<qint16> m_demodBuffer;
int m_demodBufferFill;
bool m_demodBufferEnabled;
quint32 m_levelCalcCount;
qreal m_rmsLevel;

View File

@ -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)

View File

@ -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*)));
}
}
}

View File

@ -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,

View File

@ -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})

View File

@ -0,0 +1,346 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>DemodAnalyzerGUI</class>
<widget class="RollupWidget" name="DemodAnalyzerGUI">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>739</width>
<height>778</height>
</rect>
</property>
<property name="minimumSize">
<size>
<width>720</width>
<height>0</height>
</size>
</property>
<property name="font">
<font>
<family>Liberation Sans</family>
<pointsize>9</pointsize>
</font>
</property>
<property name="windowTitle">
<string>Demod Analyzer</string>
</property>
<widget class="QWidget" name="settingsContainer" native="true">
<property name="geometry">
<rect>
<x>0</x>
<y>10</y>
<width>631</width>
<height>41</height>
</rect>
</property>
<property name="windowTitle">
<string>Settings</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<property name="spacing">
<number>3</number>
</property>
<property name="leftMargin">
<number>2</number>
</property>
<property name="topMargin">
<number>2</number>
</property>
<property name="rightMargin">
<number>2</number>
</property>
<property name="bottomMargin">
<number>2</number>
</property>
<item>
<layout class="QHBoxLayout" name="HeaderLayout">
<property name="topMargin">
<number>2</number>
</property>
<item>
<widget class="ButtonSwitch" name="startStop">
<property name="toolTip">
<string>start/stop acquisition</string>
</property>
<property name="text">
<string/>
</property>
<property name="icon">
<iconset resource="../../../sdrgui/resources/res.qrc">
<normaloff>:/play.png</normaloff>
<normalon>:/stop.png</normalon>:/play.png</iconset>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="devicesRefresh">
<property name="maximumSize">
<size>
<width>24</width>
<height>16777215</height>
</size>
</property>
<property name="toolTip">
<string>Refresh indexes of available device sets</string>
</property>
<property name="text">
<string/>
</property>
<property name="icon">
<iconset resource="../../../sdrgui/resources/res.qrc">
<normaloff>:/recycle.png</normaloff>:/recycle.png</iconset>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="channelsLabel">
<property name="text">
<string>Chan</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="channels">
<property name="minimumSize">
<size>
<width>200</width>
<height>0</height>
</size>
</property>
<property name="toolTip">
<string>Channel index</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="channelApply">
<property name="maximumSize">
<size>
<width>24</width>
<height>24</height>
</size>
</property>
<property name="toolTip">
<string>Reinitialization of device data</string>
</property>
<property name="text">
<string/>
</property>
<property name="icon">
<iconset resource="../../../sdrgui/resources/res.qrc">
<normaloff>:/checkmark.png</normaloff>:/checkmark.png</iconset>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="sinkSampleRateText">
<property name="minimumSize">
<size>
<width>80</width>
<height>0</height>
</size>
</property>
<property name="toolTip">
<string>Analyzer (sink) sample rate</string>
</property>
<property name="text">
<string>00000.0 kS/s</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QLabel" name="channelPower">
<property name="minimumSize">
<size>
<width>52</width>
<height>0</height>
</size>
</property>
<property name="toolTip">
<string>Channel power</string>
</property>
<property name="layoutDirection">
<enum>Qt::LeftToRight</enum>
</property>
<property name="text">
<string>-100.0 dB</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<widget class="QWidget" name="spectrumContainer" native="true">
<property name="geometry">
<rect>
<x>0</x>
<y>98</y>
<width>720</width>
<height>284</height>
</rect>
</property>
<property name="minimumSize">
<size>
<width>716</width>
<height>0</height>
</size>
</property>
<property name="windowTitle">
<string>Channel Spectrum</string>
</property>
<layout class="QVBoxLayout" name="verticalLayoutSpectrum">
<property name="spacing">
<number>2</number>
</property>
<property name="leftMargin">
<number>2</number>
</property>
<property name="topMargin">
<number>2</number>
</property>
<property name="rightMargin">
<number>2</number>
</property>
<property name="bottomMargin">
<number>2</number>
</property>
<item>
<widget class="GLSpectrum" name="glSpectrum" native="true">
<property name="minimumSize">
<size>
<width>200</width>
<height>250</height>
</size>
</property>
<property name="font">
<font>
<family>Liberation Mono</family>
<pointsize>8</pointsize>
</font>
</property>
</widget>
</item>
<item>
<widget class="GLSpectrumGUI" name="spectrumGUI" native="true"/>
</item>
</layout>
</widget>
<widget class="QWidget" name="scopeContainer" native="true">
<property name="geometry">
<rect>
<x>0</x>
<y>390</y>
<width>720</width>
<height>334</height>
</rect>
</property>
<property name="minimumSize">
<size>
<width>716</width>
<height>0</height>
</size>
</property>
<property name="windowTitle">
<string>Channel Scope</string>
</property>
<layout class="QVBoxLayout" name="verticalLayoutScope">
<property name="spacing">
<number>2</number>
</property>
<property name="leftMargin">
<number>3</number>
</property>
<property name="topMargin">
<number>3</number>
</property>
<property name="rightMargin">
<number>3</number>
</property>
<property name="bottomMargin">
<number>3</number>
</property>
<item>
<widget class="GLScope" name="glScope" native="true">
<property name="minimumSize">
<size>
<width>200</width>
<height>300</height>
</size>
</property>
<property name="font">
<font>
<family>Liberation Mono</family>
<pointsize>8</pointsize>
</font>
</property>
</widget>
</item>
<item>
<widget class="GLScopeGUI" name="scopeGUI" native="true"/>
</item>
</layout>
</widget>
</widget>
<customwidgets>
<customwidget>
<class>RollupWidget</class>
<extends>QWidget</extends>
<header>gui/rollupwidget.h</header>
<container>1</container>
</customwidget>
<customwidget>
<class>GLSpectrum</class>
<extends>QWidget</extends>
<header>gui/glspectrum.h</header>
<container>1</container>
</customwidget>
<customwidget>
<class>GLSpectrumGUI</class>
<extends>QWidget</extends>
<header>gui/glspectrumgui.h</header>
<container>1</container>
</customwidget>
<customwidget>
<class>ButtonSwitch</class>
<extends>QToolButton</extends>
<header>gui/buttonswitch.h</header>
</customwidget>
<customwidget>
<class>GLScope</class>
<extends>QWidget</extends>
<header>gui/glscope.h</header>
<container>1</container>
</customwidget>
<customwidget>
<class>GLScopeGUI</class>
<extends>QWidget</extends>
<header>gui/glscopegui.h</header>
<container>1</container>
</customwidget>
</customwidgets>
<resources>
<include location="../../../sdrgui/resources/res.qrc"/>
</resources>
<connections/>
</ui>

View File

@ -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 <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#include <QDebug>
#include <QNetworkAccessManager>
#include <QNetworkReply>
#include <QBuffer>
#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<QString> 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<DeviceSet*>& deviceSets = mainCore->getDeviceSets();
std::vector<DeviceSet*>::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<DemodAnalyzerSettings::AvailableChannel>& msgAvailableChannels = msgToGUI->getAvailableChannels();
QHash<ChannelAPI*, DemodAnalyzerSettings::AvailableChannel>::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<QString>& 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;
}
}
}

View File

@ -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 <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#ifndef INCLUDE_FEATURE_DEMODANALYZER_H_
#define INCLUDE_FEATURE_DEMODANALYZER_H_
#include <QThread>
#include <QHash>
#include <QNetworkRequest>
#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<DemodAnalyzerSettings::AvailableChannel>& getAvailableChannels() { return m_availableChannels; }
static MsgReportChannels* create() {
return new MsgReportChannels();
}
private:
QList<DemodAnalyzerSettings::AvailableChannel> 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<ChannelAPI*, DemodAnalyzerSettings::AvailableChannel> 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<QString>& featureSettingsKeys, const DemodAnalyzerSettings& settings, bool force);
private slots:
void networkManagerFinished(QNetworkReply *reply);
void handleChannelMessageQueue(MessageQueue *messageQueues);
};
#endif // INCLUDE_FEATURE_DEMODANALYZER_H_

View File

@ -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 <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#include <QMessageBox>
#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<DemodAnalyzer*>(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<DemodAnalyzerSettings::AvailableChannel>::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);
}
}

View File

@ -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 <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#ifndef INCLUDE_FEATURE_DEMODANALYZERGUI_H_
#define INCLUDE_FEATURE_DEMODANALYZERGUI_H_
#include <QTimer>
#include <QList>
#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<DemodAnalyzerSettings::AvailableChannel> m_availableChannels;
ChannelAPI *m_selectedChannel;
MovingAverageUtil<double, double, 40> 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_

View File

@ -0,0 +1,346 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>DemodAnalyzerGUI</class>
<widget class="RollupWidget" name="DemodAnalyzerGUI">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>739</width>
<height>778</height>
</rect>
</property>
<property name="minimumSize">
<size>
<width>720</width>
<height>0</height>
</size>
</property>
<property name="font">
<font>
<family>Liberation Sans</family>
<pointsize>9</pointsize>
</font>
</property>
<property name="windowTitle">
<string>Demod Analyzer</string>
</property>
<widget class="QWidget" name="settingsContainer" native="true">
<property name="geometry">
<rect>
<x>0</x>
<y>10</y>
<width>631</width>
<height>41</height>
</rect>
</property>
<property name="windowTitle">
<string>Settings</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<property name="spacing">
<number>3</number>
</property>
<property name="leftMargin">
<number>2</number>
</property>
<property name="topMargin">
<number>2</number>
</property>
<property name="rightMargin">
<number>2</number>
</property>
<property name="bottomMargin">
<number>2</number>
</property>
<item>
<layout class="QHBoxLayout" name="HeaderLayout">
<property name="topMargin">
<number>2</number>
</property>
<item>
<widget class="ButtonSwitch" name="startStop">
<property name="toolTip">
<string>start/stop acquisition</string>
</property>
<property name="text">
<string/>
</property>
<property name="icon">
<iconset resource="../../../sdrgui/resources/res.qrc">
<normaloff>:/play.png</normaloff>
<normalon>:/stop.png</normalon>:/play.png</iconset>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="devicesRefresh">
<property name="maximumSize">
<size>
<width>24</width>
<height>16777215</height>
</size>
</property>
<property name="toolTip">
<string>Refresh indexes of available device sets</string>
</property>
<property name="text">
<string/>
</property>
<property name="icon">
<iconset resource="../../../sdrgui/resources/res.qrc">
<normaloff>:/recycle.png</normaloff>:/recycle.png</iconset>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="channelsLabel">
<property name="text">
<string>Chan</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="channels">
<property name="minimumSize">
<size>
<width>200</width>
<height>0</height>
</size>
</property>
<property name="toolTip">
<string>Channel index</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="channelApply">
<property name="maximumSize">
<size>
<width>24</width>
<height>24</height>
</size>
</property>
<property name="toolTip">
<string>Reinitialization of device data</string>
</property>
<property name="text">
<string/>
</property>
<property name="icon">
<iconset resource="../../../sdrgui/resources/res.qrc">
<normaloff>:/checkmark.png</normaloff>:/checkmark.png</iconset>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="sinkSampleRateText">
<property name="minimumSize">
<size>
<width>80</width>
<height>0</height>
</size>
</property>
<property name="toolTip">
<string>Analyzer (sink) sample rate</string>
</property>
<property name="text">
<string>00000.0 kS/s</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QLabel" name="channelPower">
<property name="minimumSize">
<size>
<width>52</width>
<height>0</height>
</size>
</property>
<property name="toolTip">
<string>Channel power</string>
</property>
<property name="layoutDirection">
<enum>Qt::LeftToRight</enum>
</property>
<property name="text">
<string>-100.0 dB</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<widget class="QWidget" name="spectrumContainer" native="true">
<property name="geometry">
<rect>
<x>0</x>
<y>98</y>
<width>720</width>
<height>284</height>
</rect>
</property>
<property name="minimumSize">
<size>
<width>716</width>
<height>0</height>
</size>
</property>
<property name="windowTitle">
<string>Channel Spectrum</string>
</property>
<layout class="QVBoxLayout" name="verticalLayoutSpectrum">
<property name="spacing">
<number>2</number>
</property>
<property name="leftMargin">
<number>2</number>
</property>
<property name="topMargin">
<number>2</number>
</property>
<property name="rightMargin">
<number>2</number>
</property>
<property name="bottomMargin">
<number>2</number>
</property>
<item>
<widget class="GLSpectrum" name="glSpectrum" native="true">
<property name="minimumSize">
<size>
<width>200</width>
<height>250</height>
</size>
</property>
<property name="font">
<font>
<family>Liberation Mono</family>
<pointsize>8</pointsize>
</font>
</property>
</widget>
</item>
<item>
<widget class="GLSpectrumGUI" name="spectrumGUI" native="true"/>
</item>
</layout>
</widget>
<widget class="QWidget" name="scopeContainer" native="true">
<property name="geometry">
<rect>
<x>0</x>
<y>390</y>
<width>720</width>
<height>334</height>
</rect>
</property>
<property name="minimumSize">
<size>
<width>716</width>
<height>0</height>
</size>
</property>
<property name="windowTitle">
<string>Channel Scope</string>
</property>
<layout class="QVBoxLayout" name="verticalLayoutScope">
<property name="spacing">
<number>2</number>
</property>
<property name="leftMargin">
<number>3</number>
</property>
<property name="topMargin">
<number>3</number>
</property>
<property name="rightMargin">
<number>3</number>
</property>
<property name="bottomMargin">
<number>3</number>
</property>
<item>
<widget class="GLScope" name="glScope" native="true">
<property name="minimumSize">
<size>
<width>200</width>
<height>300</height>
</size>
</property>
<property name="font">
<font>
<family>Liberation Mono</family>
<pointsize>8</pointsize>
</font>
</property>
</widget>
</item>
<item>
<widget class="GLScopeGUI" name="scopeGUI" native="true"/>
</item>
</layout>
</widget>
</widget>
<customwidgets>
<customwidget>
<class>RollupWidget</class>
<extends>QWidget</extends>
<header>gui/rollupwidget.h</header>
<container>1</container>
</customwidget>
<customwidget>
<class>GLSpectrum</class>
<extends>QWidget</extends>
<header>gui/glspectrum.h</header>
<container>1</container>
</customwidget>
<customwidget>
<class>GLSpectrumGUI</class>
<extends>QWidget</extends>
<header>gui/glspectrumgui.h</header>
<container>1</container>
</customwidget>
<customwidget>
<class>ButtonSwitch</class>
<extends>QToolButton</extends>
<header>gui/buttonswitch.h</header>
</customwidget>
<customwidget>
<class>GLScope</class>
<extends>QWidget</extends>
<header>gui/glscope.h</header>
<container>1</container>
</customwidget>
<customwidget>
<class>GLScopeGUI</class>
<extends>QWidget</extends>
<header>gui/glscopegui.h</header>
<container>1</container>
</customwidget>
</customwidgets>
<resources>
<include location="../../../sdrgui/resources/res.qrc"/>
</resources>
<connections/>
</ui>

View File

@ -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 <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#include <QtPlugin>
#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();
}

View File

@ -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 <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#ifndef INCLUDE_FEATURE_DEMODANALYZERPLUGIN_H
#define INCLUDE_FEATURE_DEMODANALYZERPLUGIN_H
#include <QObject>
#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

View File

@ -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 <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#include <QColor>
#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;
}
}

View File

@ -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 <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#ifndef INCLUDE_FEATURE_DEMODANALYZERSETTINGS_H_
#define INCLUDE_FEATURE_DEMODANALYZERSETTINGS_H_
#include <QByteArray>
#include <QString>
#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_

View File

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

View File

@ -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 <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#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

View File

@ -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 <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#include <QDebug>
#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<int16_t>::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);
}
}

View File

@ -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 <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#ifndef INCLUDE_DEMODALYZERWORKER_H
#define INCLUDE_DEMODALYZERWORKER_H
#include <QObject>
#include <QMutex>
#include <QByteArray>
#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<double, double, 480> 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

View File

@ -247,7 +247,8 @@ bool VORLocalizer::handleMessage(const Message& cmd)
const ChannelAPI *channel = channelKey.m_key;
m_availableChannels.remove(const_cast<ChannelAPI*>(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;
}

View File

@ -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,

View File

@ -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
}

View File

@ -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();

View File

@ -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()
{

View File

@ -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<Feature*, FeatureSet*> m_featuresMap; //!< Feature to feature set map
PluginManager* m_pluginManager;
MessagePipes m_messagePipes;
DataPipes m_dataPipes;
void debugMaps();
};

View File

@ -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<DataFifo*>* DataPipes::getFifos(const ChannelAPI *source, const QString& type)

View File

@ -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<DataFifo*>* getFifos(const ChannelAPI *source, const QString& type);
private:

View File

@ -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");

View File

@ -47,6 +47,7 @@ public:
void startWork();
void stopWork();
void addDataFifoToDelete(DataFifo *dataFifo);
bool isRunning() const { return m_running; }
private:

View File

@ -48,6 +48,11 @@ public:
m_consumers = consumers;
}
void addElementToDelete(Element *element)
{
m_elementsToDelete.append(element);
}
void processGC()
{
if (m_mutex)

View File

@ -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<Element*>* getElements(const Producer *producer, const QString& type)

View File

@ -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<MessageQueue*>* MessagePipes::getMessageQueues(const ChannelAPI *source, const QString& type)

View File

@ -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<MessageQueue*>* getMessageQueues(const ChannelAPI *source, const QString& type);
private:

View File

@ -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");

View File

@ -46,6 +46,7 @@ public:
void startWork();
void stopWork();
void addMessageQueueToDelete(MessageQueue *messageQueue);
bool isRunning() const { return m_running; }
private:

View File

@ -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:
</div>
<div id="generator">
<div class="content">
Generated 2020-12-08T00:22:13.522+01:00
Generated 2020-12-16T13:53:51.605+01:00
</div>
</div>
</div>

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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:
</div>
<div id="generator">
<div class="content">
Generated 2020-12-08T00:22:13.522+01:00
Generated 2020-12-16T13:53:51.605+01:00
</div>
</div>
</div>

View File

@ -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 <QJsonDocument>
#include <QJsonArray>
#include <QObject>
#include <QDebug>
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;
}
}

View File

@ -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 <QJsonObject>
#include "SWGGLScope.h"
#include "SWGGLSpectrum.h"
#include <QString>
#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_ */

View File

@ -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;
}

View File

@ -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;

View File

@ -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();
}