From 7c7b24de0d1d1fca23c2487a8cb1e72a72917d38 Mon Sep 17 00:00:00 2001 From: f4exb Date: Sat, 23 Sep 2017 10:00:33 +0200 Subject: [PATCH 01/71] Corrected SDRdaemon source handling in the plugin manager --- sdrbase/plugin/pluginmanager.cpp | 34 +++----------------------------- sdrbase/plugin/pluginmanager.h | 2 -- 2 files changed, 3 insertions(+), 33 deletions(-) diff --git a/sdrbase/plugin/pluginmanager.cpp b/sdrbase/plugin/pluginmanager.cpp index 24083218d..d971259f7 100644 --- a/sdrbase/plugin/pluginmanager.cpp +++ b/sdrbase/plugin/pluginmanager.cpp @@ -32,10 +32,8 @@ #include "dsp/dspdevicesourceengine.h" #include "dsp/dspdevicesinkengine.h" -const QString PluginManager::m_sdrDaemonHardwareID = "SDRdaemon"; -const QString PluginManager::m_sdrDaemonDeviceTypeID = "sdrangel.samplesource.sdrdaemon"; -const QString PluginManager::m_sdrDaemonFECHardwareID = "SDRdaemonFEC"; -const QString PluginManager::m_sdrDaemonFECDeviceTypeID = "sdrangel.samplesource.sdrdaemonfec"; +const QString PluginManager::m_sdrDaemonHardwareID = "SDRdaemonSource"; +const QString PluginManager::m_sdrDaemonDeviceTypeID = "sdrangel.samplesource.sdrdaemonsource"; const QString PluginManager::m_fileSourceHardwareID = "FileSource"; const QString PluginManager::m_fileSourceDeviceTypeID = "sdrangel.samplesource.filesource"; const QString PluginManager::m_fileSinkDeviceTypeID = "sdrangel.samplesink.filesink"; @@ -169,10 +167,8 @@ void PluginManager::duplicateLocalSampleSourceDevices(uint deviceUID) } SamplingDevice *sdrDaemonSSD0 = 0; - SamplingDevice *sdrDaemonFECSSD0 = 0; SamplingDevice *fileSourceSSD0 = 0; bool duplicateSDRDaemon = true; - bool duplicateSDRDaemonFEC = true; bool duplicateFileSource = true; for(int i = 0; i < m_sampleSourceDevices.count(); ++i) @@ -186,15 +182,6 @@ void PluginManager::duplicateLocalSampleSourceDevices(uint deviceUID) duplicateSDRDaemon = false; } } - else if (m_sampleSourceDevices[i].m_deviceId == m_sdrDaemonFECDeviceTypeID) // SDRdaemon with FEC - { - if (m_sampleSourceDevices[i].m_deviceSequence == 0) { // reference to device 0 - sdrDaemonFECSSD0 = &m_sampleSourceDevices[i]; - } - else if (m_sampleSourceDevices[i].m_deviceSequence == deviceUID) { // already there - duplicateSDRDaemonFEC = false; - } - } else if (m_sampleSourceDevices[i].m_deviceId == m_fileSourceDeviceTypeID) // File Source { if (m_sampleSourceDevices[i].m_deviceSequence == 0) { // reference to device 0 @@ -211,7 +198,7 @@ void PluginManager::duplicateLocalSampleSourceDevices(uint deviceUID) m_sampleSourceDevices.append( SamplingDevice( sdrDaemonSSD0->m_plugin, - QString("SDRdaemon[%1]").arg(deviceUID), + QString("SDRdaemonSource[%1]").arg(deviceUID), sdrDaemonSSD0->m_hadrwareId, sdrDaemonSSD0->m_deviceId, sdrDaemonSSD0->m_deviceSerial, @@ -220,20 +207,6 @@ void PluginManager::duplicateLocalSampleSourceDevices(uint deviceUID) ); } - if (sdrDaemonFECSSD0 && duplicateSDRDaemonFEC) // append item for a new instance - { - m_sampleSourceDevices.append( - SamplingDevice( - sdrDaemonFECSSD0->m_plugin, - QString("SDRdaemonFEC[%1]").arg(deviceUID), - sdrDaemonFECSSD0->m_hadrwareId, - sdrDaemonFECSSD0->m_deviceId, - sdrDaemonFECSSD0->m_deviceSerial, - deviceUID - ) - ); - } - if (fileSourceSSD0 && duplicateFileSource) // append item for a new instance { m_sampleSourceDevices.append( @@ -294,7 +267,6 @@ void PluginManager::fillSampleSourceSelector(QComboBox* comboBox, uint deviceUID { // For "local" devices show only ones that concern this device set if ((m_sampleSourceDevices[i].m_deviceId == m_sdrDaemonDeviceTypeID) - || (m_sampleSourceDevices[i].m_deviceId == m_sdrDaemonFECDeviceTypeID) || (m_sampleSourceDevices[i].m_deviceId == m_fileSourceDeviceTypeID)) { if (deviceUID != m_sampleSourceDevices[i].m_deviceSequence) { diff --git a/sdrbase/plugin/pluginmanager.h b/sdrbase/plugin/pluginmanager.h index d447a3ee7..d2f5ca9ef 100644 --- a/sdrbase/plugin/pluginmanager.h +++ b/sdrbase/plugin/pluginmanager.h @@ -127,8 +127,6 @@ private: // "Local" sample source device IDs static const QString m_sdrDaemonHardwareID; //!< SDRdaemon hardware ID static const QString m_sdrDaemonDeviceTypeID; //!< SDRdaemon source plugin ID - static const QString m_sdrDaemonFECHardwareID; //!< SDRdaemon with FEC hardware ID - static const QString m_sdrDaemonFECDeviceTypeID; //!< SDRdaemon with FEC source plugin ID static const QString m_fileSourceHardwareID; //!< FileSource source hardware ID static const QString m_fileSourceDeviceTypeID; //!< FileSource source plugin ID From d1b4e2480412bfa3ed18784c4d29ad6230d23d2c Mon Sep 17 00:00:00 2001 From: f4exb Date: Sat, 23 Sep 2017 10:48:29 +0200 Subject: [PATCH 02/71] New button type for transverter frequency translation toggle. Added to RTLSDR GUI --- CMakeLists.txt | 5 + plugins/samplesource/rtlsdr/rtlsdrgui.ui | 15 +++ sdrbase/gui/transverterbutton.cpp | 43 +++++++ sdrbase/gui/transverterbutton.h | 43 +++++++ sdrbase/gui/transverterdialog.cpp | 47 +++++++ sdrbase/gui/transverterdialog.h | 47 +++++++ sdrbase/gui/transverterdialog.ui | 148 +++++++++++++++++++++++ 7 files changed, 348 insertions(+) create mode 100644 sdrbase/gui/transverterbutton.cpp create mode 100644 sdrbase/gui/transverterbutton.h create mode 100644 sdrbase/gui/transverterdialog.cpp create mode 100644 sdrbase/gui/transverterdialog.h create mode 100644 sdrbase/gui/transverterdialog.ui diff --git a/CMakeLists.txt b/CMakeLists.txt index e5675f6e1..f5cc99f2d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -264,6 +264,8 @@ set(sdrbase_SOURCES sdrbase/gui/samplingdevicecontrol.cpp sdrbase/gui/scale.cpp sdrbase/gui/scaleengine.cpp + sdrbase/gui/transverterbutton.cpp + sdrbase/gui/transverterdialog.cpp sdrbase/gui/valuedial.cpp sdrbase/gui/valuedialz.cpp @@ -386,6 +388,8 @@ set(sdrbase_HEADERS sdrbase/gui/samplingdevicecontrol.h sdrbase/gui/scale.h sdrbase/gui/scaleengine.h + sdrbase/gui/transverterbutton.h + sdrbase/gui/transverterdialog.h sdrbase/gui/valuedial.h sdrbase/gui/valuedialz.h @@ -439,6 +443,7 @@ set(sdrbase_FORMS sdrbase/gui/audiodialog.ui sdrbase/gui/samplingdevicecontrol.ui sdrbase/gui/myposdialog.ui + sdrbase/gui/transverterdialog.ui ) set(sdrbase_RESOURCES diff --git a/plugins/samplesource/rtlsdr/rtlsdrgui.ui b/plugins/samplesource/rtlsdr/rtlsdrgui.ui index d56fa26f4..e6e5e23dc 100644 --- a/plugins/samplesource/rtlsdr/rtlsdrgui.ui +++ b/plugins/samplesource/rtlsdr/rtlsdrgui.ui @@ -298,6 +298,16 @@ + + + + Transverter frequency translation toggle + + + X + + + @@ -581,6 +591,11 @@ QToolButton
gui/buttonswitch.h
+ + TransverterButton + QToolButton +
gui/transverterbutton.h
+
diff --git a/sdrbase/gui/transverterbutton.cpp b/sdrbase/gui/transverterbutton.cpp new file mode 100644 index 000000000..33b2eb9d4 --- /dev/null +++ b/sdrbase/gui/transverterbutton.cpp @@ -0,0 +1,43 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2017 F4EXB // +// written by Edouard Griffiths // +// // +// OpenGL interface modernization. // +// See: http://doc.qt.io/qt-5/qopenglshaderprogram.html // +// // +// This program is free software; you can redistribute it and/or modify // +// it under the terms of the GNU General Public License as published by // +// the Free Software Foundation as version 3 of the License, or // +// // +// This program is distributed in the hope that it will be useful, // +// but WITHOUT ANY WARRANTY; without even the implied warranty of // +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // +// GNU General Public License V3 for more details. // +// // +// You should have received a copy of the GNU General Public License // +// along with this program. If not, see . // +/////////////////////////////////////////////////////////////////////////////////// + +#include "transverterdialog.h" +#include "transverterbutton.h" + +TransverterButton::TransverterButton(QWidget* parent) : + ButtonSwitch(parent), + m_deltaFrequency(0) +{ + connect(this, SIGNAL(toggled(bool)), this, SLOT(onToggled(bool))); +} + +void TransverterButton::onToggled(bool checked) +{ + if (checked) { + TransverterDialog transverterDialog(&m_deltaFrequency, this); + transverterDialog.exec(); + setToolTip(tr("Transverter frequency translation toggle. Delta frequency %1 kHz").arg(m_deltaFrequency)); + } +} + +void TransverterButton::doToggle(bool checked) +{ + onToggled(checked); +} diff --git a/sdrbase/gui/transverterbutton.h b/sdrbase/gui/transverterbutton.h new file mode 100644 index 000000000..d6a490064 --- /dev/null +++ b/sdrbase/gui/transverterbutton.h @@ -0,0 +1,43 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2017 F4EXB // +// written by Edouard Griffiths // +// // +// OpenGL interface modernization. // +// See: http://doc.qt.io/qt-5/qopenglshaderprogram.html // +// // +// This program is free software; you can redistribute it and/or modify // +// it under the terms of the GNU General Public License as published by // +// the Free Software Foundation as version 3 of the License, or // +// // +// This program is distributed in the hope that it will be useful, // +// but WITHOUT ANY WARRANTY; without even the implied warranty of // +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // +// GNU General Public License V3 for more details. // +// // +// You should have received a copy of the GNU General Public License // +// along with this program. If not, see . // +/////////////////////////////////////////////////////////////////////////////////// + +#ifndef SDRBASE_GUI_TRANSVERTERBUTTON_H_ +#define SDRBASE_GUI_TRANSVERTERBUTTON_H_ + +#include "buttonswitch.h" + +class TransverterButton : public ButtonSwitch { + Q_OBJECT + +public: + TransverterButton(QWidget* parent = 0); + void doToggle(bool checked); + qint64 getDeltaFrequency() const { return m_deltaFrequency; } + void setDeltaFrequency(qint64 deltaFrequency) { m_deltaFrequency = deltaFrequency; } + +private slots: + void onToggled(bool checked); + +private: + qint64 m_deltaFrequency; +}; + + +#endif /* SDRBASE_GUI_TRANSVERTERBUTTON_H_ */ diff --git a/sdrbase/gui/transverterdialog.cpp b/sdrbase/gui/transverterdialog.cpp new file mode 100644 index 000000000..c6e3e557e --- /dev/null +++ b/sdrbase/gui/transverterdialog.cpp @@ -0,0 +1,47 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2017 F4EXB // +// written by Edouard Griffiths // +// // +// OpenGL interface modernization. // +// See: http://doc.qt.io/qt-5/qopenglshaderprogram.html // +// // +// This program is free software; you can redistribute it and/or modify // +// it under the terms of the GNU General Public License as published by // +// the Free Software Foundation as version 3 of the License, or // +// // +// This program is distributed in the hope that it will be useful, // +// but WITHOUT ANY WARRANTY; without even the implied warranty of // +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // +// GNU General Public License V3 for more details. // +// // +// You should have received a copy of the GNU General Public License // +// along with this program. If not, see . // +/////////////////////////////////////////////////////////////////////////////////// + +#include "transverterdialog.h" + +#include "ui_transverterdialog.h" + + +TransverterDialog::TransverterDialog(qint64 *deltaFrequency, QWidget* parent) : + QDialog(parent), + ui(new Ui::TransverterDialog), + m_deltaFrequency(deltaFrequency) +{ + ui->setupUi(this); + ui->deltaFrequencyLabel->setText(QString("%1f").arg(QChar(0x94, 0x03))); + ui->deltaFrequency->setColorMapper(ColorMapper(ColorMapper::GrayGold)); + ui->deltaFrequency->setValueRange(false, 7, -9999999, 9999999); + ui->deltaFrequency->setValue(*m_deltaFrequency); +} + +TransverterDialog::~TransverterDialog() +{ + delete ui; +} + +void TransverterDialog::accept() +{ + *m_deltaFrequency = ui->deltaFrequency->getValueNew(); + QDialog::accept(); +} diff --git a/sdrbase/gui/transverterdialog.h b/sdrbase/gui/transverterdialog.h new file mode 100644 index 000000000..58edcc063 --- /dev/null +++ b/sdrbase/gui/transverterdialog.h @@ -0,0 +1,47 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2017 F4EXB // +// written by Edouard Griffiths // +// // +// OpenGL interface modernization. // +// See: http://doc.qt.io/qt-5/qopenglshaderprogram.html // +// // +// This program is free software; you can redistribute it and/or modify // +// it under the terms of the GNU General Public License as published by // +// the Free Software Foundation as version 3 of the License, or // +// // +// This program is distributed in the hope that it will be useful, // +// but WITHOUT ANY WARRANTY; without even the implied warranty of // +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // +// GNU General Public License V3 for more details. // +// // +// You should have received a copy of the GNU General Public License // +// along with this program. If not, see . // +/////////////////////////////////////////////////////////////////////////////////// + +#ifndef SDRBASE_GUI_TRANSVERTERDIALOG_H_ +#define SDRBASE_GUI_TRANSVERTERDIALOG_H_ + +#include + +namespace Ui { + class TransverterDialog; +} + +class TransverterDialog : public QDialog { + Q_OBJECT + +public: + explicit TransverterDialog(qint64 *deltaFrequency, QWidget* parent = 0); + ~TransverterDialog(); + +private: + Ui::TransverterDialog* ui; + qint64 *m_deltaFrequency; + +private slots: + void accept(); +}; + + + +#endif /* SDRBASE_GUI_TRANSVERTERDIALOG_H_ */ diff --git a/sdrbase/gui/transverterdialog.ui b/sdrbase/gui/transverterdialog.ui new file mode 100644 index 000000000..775311359 --- /dev/null +++ b/sdrbase/gui/transverterdialog.ui @@ -0,0 +1,148 @@ + + + TransverterDialog + + + + 0 + 0 + 324 + 81 + + + + + Sans Serif + 9 + + + + Delta Frequency + + + + + + + + + + Df + + + + + + + + 0 + 0 + + + + + 32 + 16 + + + + + DejaVu Sans Mono + 12 + + + + PointingHandCursor + + + Qt::StrongFocus + + + Transverter delta frequency (kHz) + + deltaFrequencyUnits + + + + + + kHz + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + + ValueDialZ + QWidget +
gui/valuedialz.h
+ 1 +
+
+ + buttonBox + + + + + buttonBox + accepted() + TransverterDialog + accept() + + + 257 + 194 + + + 157 + 203 + + + + + buttonBox + rejected() + TransverterDialog + reject() + + + 314 + 194 + + + 286 + 203 + + + + +
From da8857e0e16f50bfeb533a8c0761450e83d041e8 Mon Sep 17 00:00:00 2001 From: f4exb Date: Sat, 23 Sep 2017 17:19:58 +0200 Subject: [PATCH 03/71] Windows build fixes --- app/app.pro | 1 + plugins/channelrx/demodbfm/rdsdemod.cpp | 6 +++++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/app/app.pro b/app/app.pro index 3f1f6e185..bdd7bf26e 100644 --- a/app/app.pro +++ b/app/app.pro @@ -6,6 +6,7 @@ QT += core gui multimedia opengl greaterThan(QT_MAJOR_VERSION, 4): QT += widgets +QMAKE_CXXFLAGS += -std=c++11 TEMPLATE = app TARGET = sdrangel diff --git a/plugins/channelrx/demodbfm/rdsdemod.cpp b/plugins/channelrx/demodbfm/rdsdemod.cpp index 97c1a21bb..32292f32b 100644 --- a/plugins/channelrx/demodbfm/rdsdemod.cpp +++ b/plugins/channelrx/demodbfm/rdsdemod.cpp @@ -22,6 +22,10 @@ #include #include +#undef M_PI +#define M_PI 3.14159265358979323846 +#undef M_PI_2 +#define M_PI_2 1.57079632679489661923 const Real RDSDemod::m_pllBeta = 50; const Real RDSDemod::m_fsc = 1187.5; @@ -77,7 +81,7 @@ bool RDSDemod::process(Real demod, bool& bit) m_parms.clock_offset = 0; }*/ - m_parms.subcarr_phi += (2 * M_PI * m_fsc) / (Real) m_srate; + m_parms.subcarr_phi += (2 * M_PI * m_fsc) / (Real) m_srate; m_parms.clock_phi = m_parms.subcarr_phi + m_parms.clock_offset; // Clock phase recovery From 43a1e0e14bba1f232aaab29d0d02ba0be5d333d2 Mon Sep 17 00:00:00 2001 From: f4exb Date: Sat, 23 Sep 2017 19:15:56 +0200 Subject: [PATCH 04/71] Transverter frequency shift logic. Implemented it for RTLSDR --- plugins/samplesource/rtlsdr/rtlsdrgui.cpp | 41 +++++++++++++---- plugins/samplesource/rtlsdr/rtlsdrgui.h | 2 + plugins/samplesource/rtlsdr/rtlsdrgui.ui | 2 +- plugins/samplesource/rtlsdr/rtlsdrinput.cpp | 45 +++++++++++++++---- plugins/samplesource/rtlsdr/rtlsdrinput.h | 9 ++++ plugins/samplesource/rtlsdr/rtlsdrplugin.cpp | 2 +- .../samplesource/rtlsdr/rtlsdrsettings.cpp | 9 ++++ plugins/samplesource/rtlsdr/rtlsdrsettings.h | 3 ++ sdrbase/gui/transverterbutton.cpp | 2 +- sdrbase/gui/transverterdialog.cpp | 4 +- 10 files changed, 97 insertions(+), 22 deletions(-) diff --git a/plugins/samplesource/rtlsdr/rtlsdrgui.cpp b/plugins/samplesource/rtlsdr/rtlsdrgui.cpp index 6c2b84309..574d40b40 100644 --- a/plugins/samplesource/rtlsdr/rtlsdrgui.cpp +++ b/plugins/samplesource/rtlsdr/rtlsdrgui.cpp @@ -28,6 +28,7 @@ #include "dsp/dspengine.h" #include "dsp/dspcommands.h" + RTLSDRGui::RTLSDRGui(DeviceSourceAPI *deviceAPI, QWidget* parent) : QWidget(parent), ui(new Ui::RTLSDRGui), @@ -40,10 +41,10 @@ RTLSDRGui::RTLSDRGui(DeviceSourceAPI *deviceAPI, QWidget* parent) : ui->setupUi(this); ui->centerFrequency->setColorMapper(ColorMapper(ColorMapper::GrayGold)); - ui->centerFrequency->setValueRange(7, 24000U, 1900000U); + updateFrequencyLimits(); ui->sampleRate->setColorMapper(ColorMapper(ColorMapper::GrayGreenYellow)); - ui->sampleRate->setValueRange(7, 950000U, 2400000U); + ui->sampleRate->setValueRange(7, RTLSDRInput::sampleRateHighRangeMin, RTLSDRInput::sampleRateHighRangeMax); connect(&m_updateTimer, SIGNAL(timeout()), this, SLOT(updateHardware())); connect(&m_statusTimer, SIGNAL(timeout()), this, SLOT(updateStatus())); @@ -175,6 +176,18 @@ void RTLSDRGui::updateSampleRateAndFrequency() ui->deviceRateText->setText(tr("%1k").arg(QString::number(m_sampleRate / 1000.0f, 'g', 5))); } +void RTLSDRGui::updateFrequencyLimits() +{ + // values in kHz + qint64 minLimit = (m_settings.m_noModMode ? RTLSDRInput::frequencyLowRangeMin : RTLSDRInput::frequencyHighRangeMin) + m_settings.m_transverterDeltaFrequency/1000; + qint64 maxLimit = (m_settings.m_noModMode ? RTLSDRInput::frequencyLowRangeMax : RTLSDRInput::frequencyHighRangeMax) + m_settings.m_transverterDeltaFrequency/1000; + + minLimit = minLimit < 0 ? 0 : minLimit > 9999999 ? 9999999 : minLimit; + maxLimit = maxLimit < 0 ? 0 : maxLimit > 9999999 ? 9999999 : maxLimit; + + ui->centerFrequency->setValueRange(7, minLimit, maxLimit); +} + void RTLSDRGui::displayGains() { if (m_gains.size() > 0) @@ -214,6 +227,9 @@ void RTLSDRGui::displaySettings() ui->ppmText->setText(tr("%1").arg(m_settings.m_loPpmCorrection)); ui->decim->setCurrentIndex(m_settings.m_log2Decim); ui->fcPos->setCurrentIndex((int) m_settings.m_fcPos); + ui->checkBox->setChecked(m_settings.m_noModMode); + ui->transverter->setDeltaFrequency(m_settings.m_transverterDeltaFrequency); + ui->transverter->setChecked(m_settings.m_transverterMode); } void RTLSDRGui::sendSettings() @@ -316,6 +332,14 @@ void RTLSDRGui::on_record_toggled(bool checked) m_sampleSource->getInputMessageQueue()->push(message); } +void RTLSDRGui::on_transverter_toggled(bool checked) +{ + m_settings.m_transverterMode = checked; + m_settings.m_transverterDeltaFrequency = checked ? ui->transverter->getDeltaFrequency() : 0; + updateFrequencyLimits(); + sendSettings(); +} + void RTLSDRGui::updateHardware() { RTLSDRInput::MsgConfigureRTLSDR* message = RTLSDRInput::MsgConfigureRTLSDR::create(m_settings); @@ -356,18 +380,17 @@ void RTLSDRGui::on_checkBox_stateChanged(int state) { if (state == Qt::Checked) { - // Direct Modes: 0: off, 1: I, 2: Q, 3: NoMod. - ((RTLSDRInput*)m_sampleSource)->set_ds_mode(3); ui->gain->setEnabled(false); - ui->centerFrequency->setValueRange(7, 1000U, 275000U); + m_settings.m_noModMode = true; + updateFrequencyLimits(); ui->centerFrequency->setValue(7000); m_settings.m_centerFrequency = 7000 * 1000; } else { - ((RTLSDRInput*)m_sampleSource)->set_ds_mode(0); ui->gain->setEnabled(true); - ui->centerFrequency->setValueRange(7, 28500U, 1700000U); + m_settings.m_noModMode = false; + updateFrequencyLimits(); ui->centerFrequency->setValue(434000); ui->gain->setValue(0); m_settings.m_centerFrequency = 435000 * 1000; @@ -391,9 +414,9 @@ void RTLSDRGui::on_sampleRate_changed(quint64 value) void RTLSDRGui::on_lowSampleRate_toggled(bool checked) { if (checked) { - ui->sampleRate->setValueRange(7, 230000U, 300000U); + ui->sampleRate->setValueRange(7, RTLSDRInput::sampleRateLowRangeMin, RTLSDRInput::sampleRateLowRangeMax); } else { - ui->sampleRate->setValueRange(7, 950000U, 2400000U); + ui->sampleRate->setValueRange(7, RTLSDRInput::sampleRateHighRangeMin, RTLSDRInput::sampleRateHighRangeMax); } m_settings.m_devSampleRate = ui->sampleRate->getValueNew(); diff --git a/plugins/samplesource/rtlsdr/rtlsdrgui.h b/plugins/samplesource/rtlsdr/rtlsdrgui.h index 5b8b002ee..d3f4da031 100644 --- a/plugins/samplesource/rtlsdr/rtlsdrgui.h +++ b/plugins/samplesource/rtlsdr/rtlsdrgui.h @@ -69,6 +69,7 @@ private: void displaySettings(); void sendSettings(); void updateSampleRateAndFrequency(); + void updateFrequencyLimits(); private slots: void handleInputMessages(); @@ -86,6 +87,7 @@ private slots: void on_agc_stateChanged(int state); void on_startStop_toggled(bool checked); void on_record_toggled(bool checked); + void on_transverter_toggled(bool checked); void updateHardware(); void updateStatus(); }; diff --git a/plugins/samplesource/rtlsdr/rtlsdrgui.ui b/plugins/samplesource/rtlsdr/rtlsdrgui.ui index e6e5e23dc..b8937a0d6 100644 --- a/plugins/samplesource/rtlsdr/rtlsdrgui.ui +++ b/plugins/samplesource/rtlsdr/rtlsdrgui.ui @@ -299,7 +299,7 @@
- + Transverter frequency translation toggle diff --git a/plugins/samplesource/rtlsdr/rtlsdrinput.cpp b/plugins/samplesource/rtlsdr/rtlsdrinput.cpp index 147b06904..0eebfe1cb 100644 --- a/plugins/samplesource/rtlsdr/rtlsdrinput.cpp +++ b/plugins/samplesource/rtlsdr/rtlsdrinput.cpp @@ -32,6 +32,15 @@ MESSAGE_CLASS_DEFINITION(RTLSDRInput::MsgConfigureRTLSDR, Message) MESSAGE_CLASS_DEFINITION(RTLSDRInput::MsgReportRTLSDR, Message) MESSAGE_CLASS_DEFINITION(RTLSDRInput::MsgFileRecord, Message) +const quint64 RTLSDRInput::frequencyLowRangeMin = 1000UL; +const quint64 RTLSDRInput::frequencyLowRangeMax = 275000UL; +const quint64 RTLSDRInput::frequencyHighRangeMin = 24000UL; +const quint64 RTLSDRInput::frequencyHighRangeMax = 1900000UL; +const int RTLSDRInput::sampleRateLowRangeMin = 230000U; +const int RTLSDRInput::sampleRateLowRangeMax = 300000U; +const int RTLSDRInput::sampleRateHighRangeMin = 950000U; +const int RTLSDRInput::sampleRateHighRangeMax = 2400000U; + RTLSDRInput::RTLSDRInput(DeviceSourceAPI *deviceAPI) : m_deviceAPI(deviceAPI), m_settings(), @@ -354,35 +363,43 @@ bool RTLSDRInput::applySettings(const RTLSDRSettings& settings, bool force) } } - qint64 deviceCenterFrequency = m_settings.m_centerFrequency; - qint64 f_img = deviceCenterFrequency; - quint32 devSampleRate =m_settings.m_devSampleRate; - if (force || (m_settings.m_centerFrequency != settings.m_centerFrequency) - || (m_settings.m_fcPos != settings.m_fcPos)) + || (m_settings.m_fcPos != settings.m_fcPos) + || (m_settings.m_transverterMode != settings.m_transverterMode) + || (m_settings.m_transverterDeltaFrequency != settings.m_transverterDeltaFrequency)) { m_settings.m_centerFrequency = settings.m_centerFrequency; + m_settings.m_transverterMode = settings.m_transverterMode; + m_settings.m_transverterDeltaFrequency = settings.m_transverterDeltaFrequency; + qint64 deviceCenterFrequency = m_settings.m_centerFrequency; + + deviceCenterFrequency -= m_settings.m_transverterMode ? m_settings.m_transverterDeltaFrequency : 0; + + qint64 f_img = deviceCenterFrequency; + quint32 devSampleRate = m_settings.m_devSampleRate; + forwardChange = true; if ((m_settings.m_log2Decim == 0) || (settings.m_fcPos == RTLSDRSettings::FC_POS_CENTER)) { - deviceCenterFrequency = m_settings.m_centerFrequency; f_img = deviceCenterFrequency; } else { if (settings.m_fcPos == RTLSDRSettings::FC_POS_INFRA) { - deviceCenterFrequency = m_settings.m_centerFrequency + (devSampleRate / 4); + deviceCenterFrequency += (devSampleRate / 4); f_img = deviceCenterFrequency + devSampleRate/2; } else if (settings.m_fcPos == RTLSDRSettings::FC_POS_SUPRA) { - deviceCenterFrequency = m_settings.m_centerFrequency - (devSampleRate / 4); + deviceCenterFrequency -= (devSampleRate / 4); f_img = deviceCenterFrequency - devSampleRate/2; } } + deviceCenterFrequency = deviceCenterFrequency < 0 ? 0 : deviceCenterFrequency; + if (m_dev != 0) { if (rtlsdr_set_center_freq( m_dev, deviceCenterFrequency ) != 0) @@ -411,6 +428,18 @@ bool RTLSDRInput::applySettings(const RTLSDRSettings& settings, bool force) } } + if ((m_settings.m_noModMode != settings.m_noModMode) || force) + { + m_settings.m_noModMode = settings.m_noModMode; + + // Direct Modes: 0: off, 1: I, 2: Q, 3: NoMod. + if (m_settings.m_noModMode) { + set_ds_mode(3); + } else { + set_ds_mode(0); + } + } + if (forwardChange) { int sampleRate = m_settings.m_devSampleRate/(1<& getGains() const { return m_gains; } void set_ds_mode(int on); + static const quint64 frequencyLowRangeMin; + static const quint64 frequencyLowRangeMax; + static const quint64 frequencyHighRangeMin; + static const quint64 frequencyHighRangeMax; + static const int sampleRateLowRangeMin; + static const int sampleRateLowRangeMax; + static const int sampleRateHighRangeMin; + static const int sampleRateHighRangeMax; + private: DeviceSourceAPI *m_deviceAPI; FileRecord *m_fileSink; //!< File sink to record device I/Q output diff --git a/plugins/samplesource/rtlsdr/rtlsdrplugin.cpp b/plugins/samplesource/rtlsdr/rtlsdrplugin.cpp index b168512fd..757766330 100644 --- a/plugins/samplesource/rtlsdr/rtlsdrplugin.cpp +++ b/plugins/samplesource/rtlsdr/rtlsdrplugin.cpp @@ -11,7 +11,7 @@ const PluginDescriptor RTLSDRPlugin::m_pluginDescriptor = { QString("RTL-SDR Input"), - QString("3.7.2"), + QString("3.7.3"), QString("(c) Edouard Griffiths, F4EXB"), QString("https://github.com/f4exb/sdrangel"), true, diff --git a/plugins/samplesource/rtlsdr/rtlsdrsettings.cpp b/plugins/samplesource/rtlsdr/rtlsdrsettings.cpp index edf29351d..703306865 100644 --- a/plugins/samplesource/rtlsdr/rtlsdrsettings.cpp +++ b/plugins/samplesource/rtlsdr/rtlsdrsettings.cpp @@ -35,6 +35,9 @@ void RTLSDRSettings::resetToDefaults() m_dcBlock = false; m_iqImbalance = false; m_agc = false; + m_noModMode = false; + m_transverterMode = false; + m_transverterDeltaFrequency = 0; } QByteArray RTLSDRSettings::serialize() const @@ -50,6 +53,9 @@ QByteArray RTLSDRSettings::serialize() const s.writeS32(8, m_devSampleRate); s.writeBool(9, m_lowSampleRate); s.writeBool(10, m_agc); + s.writeBool(11, m_noModMode); + s.writeBool(12, m_transverterMode); + s.writeS64(13, m_transverterDeltaFrequency); return s.final(); } @@ -78,6 +84,9 @@ bool RTLSDRSettings::deserialize(const QByteArray& data) d.readS32(8, &m_devSampleRate, 1024*1000); d.readBool(9, &m_lowSampleRate, false); d.readBool(10, &m_agc, false); + d.readBool(11, &m_noModMode, false); + d.readBool(12, &m_transverterMode, false); + d.readS64(13, &m_transverterDeltaFrequency, 0); return true; } diff --git a/plugins/samplesource/rtlsdr/rtlsdrsettings.h b/plugins/samplesource/rtlsdr/rtlsdrsettings.h index ff257de71..d9c9a2476 100644 --- a/plugins/samplesource/rtlsdr/rtlsdrsettings.h +++ b/plugins/samplesource/rtlsdr/rtlsdrsettings.h @@ -34,6 +34,9 @@ struct RTLSDRSettings { bool m_dcBlock; bool m_iqImbalance; bool m_agc; + bool m_noModMode; + bool m_transverterMode; + qint64 m_transverterDeltaFrequency; RTLSDRSettings(); void resetToDefaults(); diff --git a/sdrbase/gui/transverterbutton.cpp b/sdrbase/gui/transverterbutton.cpp index 33b2eb9d4..ddfd366f2 100644 --- a/sdrbase/gui/transverterbutton.cpp +++ b/sdrbase/gui/transverterbutton.cpp @@ -33,7 +33,7 @@ void TransverterButton::onToggled(bool checked) if (checked) { TransverterDialog transverterDialog(&m_deltaFrequency, this); transverterDialog.exec(); - setToolTip(tr("Transverter frequency translation toggle. Delta frequency %1 kHz").arg(m_deltaFrequency)); + setToolTip(tr("Transverter frequency translation toggle. Delta frequency %1 kHz").arg(m_deltaFrequency/1000)); } } diff --git a/sdrbase/gui/transverterdialog.cpp b/sdrbase/gui/transverterdialog.cpp index c6e3e557e..d6ac37108 100644 --- a/sdrbase/gui/transverterdialog.cpp +++ b/sdrbase/gui/transverterdialog.cpp @@ -32,7 +32,7 @@ TransverterDialog::TransverterDialog(qint64 *deltaFrequency, QWidget* parent) : ui->deltaFrequencyLabel->setText(QString("%1f").arg(QChar(0x94, 0x03))); ui->deltaFrequency->setColorMapper(ColorMapper(ColorMapper::GrayGold)); ui->deltaFrequency->setValueRange(false, 7, -9999999, 9999999); - ui->deltaFrequency->setValue(*m_deltaFrequency); + ui->deltaFrequency->setValue(*m_deltaFrequency/1000); } TransverterDialog::~TransverterDialog() @@ -42,6 +42,6 @@ TransverterDialog::~TransverterDialog() void TransverterDialog::accept() { - *m_deltaFrequency = ui->deltaFrequency->getValueNew(); + *m_deltaFrequency = ui->deltaFrequency->getValueNew()*1000; QDialog::accept(); } From fcb0d99af59e474530a8731a32e958ebfabf4644 Mon Sep 17 00:00:00 2001 From: f4exb Date: Sat, 23 Sep 2017 21:59:39 +0200 Subject: [PATCH 05/71] RTLSDR: update center frequency after transverter toggle --- plugins/samplesource/rtlsdr/rtlsdrgui.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/plugins/samplesource/rtlsdr/rtlsdrgui.cpp b/plugins/samplesource/rtlsdr/rtlsdrgui.cpp index 574d40b40..7979bd40d 100644 --- a/plugins/samplesource/rtlsdr/rtlsdrgui.cpp +++ b/plugins/samplesource/rtlsdr/rtlsdrgui.cpp @@ -337,6 +337,7 @@ void RTLSDRGui::on_transverter_toggled(bool checked) m_settings.m_transverterMode = checked; m_settings.m_transverterDeltaFrequency = checked ? ui->transverter->getDeltaFrequency() : 0; updateFrequencyLimits(); + m_settings.m_centerFrequency = ui->centerFrequency->getValueNew()*1000; sendSettings(); } From 84c6488310f67643196c6b81dc9b82863a80fdf2 Mon Sep 17 00:00:00 2001 From: f4exb Date: Sat, 23 Sep 2017 22:11:52 +0200 Subject: [PATCH 06/71] ValueDialZ: fixed display of int64 larger than max of int32 in absolute value --- sdrbase/gui/valuedialz.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sdrbase/gui/valuedialz.cpp b/sdrbase/gui/valuedialz.cpp index 23aa5d56e..53b3f134e 100644 --- a/sdrbase/gui/valuedialz.cpp +++ b/sdrbase/gui/valuedialz.cpp @@ -185,7 +185,8 @@ QChar ValueDialZ::digitNeigh(QChar c, bool dir) QString ValueDialZ::formatText(qint64 value) { - QString str = QString("%1%2").arg(m_positiveOnly ? "" : value < 0 ? "-" : "+").arg(abs(value), m_numDigits, 10, QChar('0')); + qDebug("ValueDialZ::formatText: value: %lld", value); + QString str = QString("%1%2").arg(m_positiveOnly ? "" : value < 0 ? "-" : "+").arg(value < 0 ? -value : value, m_numDigits, 10, QChar('0')); for(int i = 0; i < m_numDecimalPoints; i++) { From 25272f21d09f035e113c18c4697b565758d002e6 Mon Sep 17 00:00:00 2001 From: f4exb Date: Sat, 23 Sep 2017 22:38:37 +0200 Subject: [PATCH 07/71] Transverter button: set in Hz units --- sdrbase/gui/transverterbutton.cpp | 2 +- sdrbase/gui/transverterdialog.cpp | 6 +++--- sdrbase/gui/transverterdialog.ui | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/sdrbase/gui/transverterbutton.cpp b/sdrbase/gui/transverterbutton.cpp index ddfd366f2..eede250c8 100644 --- a/sdrbase/gui/transverterbutton.cpp +++ b/sdrbase/gui/transverterbutton.cpp @@ -33,7 +33,7 @@ void TransverterButton::onToggled(bool checked) if (checked) { TransverterDialog transverterDialog(&m_deltaFrequency, this); transverterDialog.exec(); - setToolTip(tr("Transverter frequency translation toggle. Delta frequency %1 kHz").arg(m_deltaFrequency/1000)); + setToolTip(tr("Transverter frequency translation toggle. Delta frequency %1 MHz").arg(m_deltaFrequency/1000000.0)); } } diff --git a/sdrbase/gui/transverterdialog.cpp b/sdrbase/gui/transverterdialog.cpp index d6ac37108..ed049f659 100644 --- a/sdrbase/gui/transverterdialog.cpp +++ b/sdrbase/gui/transverterdialog.cpp @@ -31,8 +31,8 @@ TransverterDialog::TransverterDialog(qint64 *deltaFrequency, QWidget* parent) : ui->setupUi(this); ui->deltaFrequencyLabel->setText(QString("%1f").arg(QChar(0x94, 0x03))); ui->deltaFrequency->setColorMapper(ColorMapper(ColorMapper::GrayGold)); - ui->deltaFrequency->setValueRange(false, 7, -9999999, 9999999); - ui->deltaFrequency->setValue(*m_deltaFrequency/1000); + ui->deltaFrequency->setValueRange(false, 10, -9999999999L, 9999999999L); + ui->deltaFrequency->setValue(*m_deltaFrequency); } TransverterDialog::~TransverterDialog() @@ -42,6 +42,6 @@ TransverterDialog::~TransverterDialog() void TransverterDialog::accept() { - *m_deltaFrequency = ui->deltaFrequency->getValueNew()*1000; + *m_deltaFrequency = ui->deltaFrequency->getValueNew(); QDialog::accept(); } diff --git a/sdrbase/gui/transverterdialog.ui b/sdrbase/gui/transverterdialog.ui index 775311359..8b3522215 100644 --- a/sdrbase/gui/transverterdialog.ui +++ b/sdrbase/gui/transverterdialog.ui @@ -58,7 +58,7 @@ Qt::StrongFocus - Transverter delta frequency (kHz) + Transverter delta frequency (Hz) deltaFrequencyUnits @@ -66,7 +66,7 @@ - kHz + Hz From 87a60ff22001ebf99cebe3abf09740545f075030 Mon Sep 17 00:00:00 2001 From: f4exb Date: Sun, 24 Sep 2017 02:08:08 +0200 Subject: [PATCH 08/71] RTLSDR tranverter mode interim state (1) --- plugins/samplesource/rtlsdr/rtlsdrgui.cpp | 18 ++++++++--------- plugins/samplesource/rtlsdr/rtlsdrgui.h | 3 +-- plugins/samplesource/rtlsdr/rtlsdrgui.ui | 9 +++++++++ sdrbase/gui/transverterbutton.cpp | 24 ++++++++++------------- sdrbase/gui/transverterbutton.h | 10 ++++++---- sdrbase/gui/transverterdialog.cpp | 11 +++++++---- sdrbase/gui/transverterdialog.h | 5 +++-- sdrbase/gui/transverterdialog.ui | 24 +++++++++++++++++++++-- 8 files changed, 67 insertions(+), 37 deletions(-) diff --git a/plugins/samplesource/rtlsdr/rtlsdrgui.cpp b/plugins/samplesource/rtlsdr/rtlsdrgui.cpp index 7979bd40d..b0f13f0c7 100644 --- a/plugins/samplesource/rtlsdr/rtlsdrgui.cpp +++ b/plugins/samplesource/rtlsdr/rtlsdrgui.cpp @@ -179,12 +179,15 @@ void RTLSDRGui::updateSampleRateAndFrequency() void RTLSDRGui::updateFrequencyLimits() { // values in kHz - qint64 minLimit = (m_settings.m_noModMode ? RTLSDRInput::frequencyLowRangeMin : RTLSDRInput::frequencyHighRangeMin) + m_settings.m_transverterDeltaFrequency/1000; - qint64 maxLimit = (m_settings.m_noModMode ? RTLSDRInput::frequencyLowRangeMax : RTLSDRInput::frequencyHighRangeMax) + m_settings.m_transverterDeltaFrequency/1000; + qint64 deltaFrequency = m_settings.m_transverterMode ? m_settings.m_transverterDeltaFrequency/1000 : 0; + qint64 minLimit = (m_settings.m_noModMode ? RTLSDRInput::frequencyLowRangeMin : RTLSDRInput::frequencyHighRangeMin) + deltaFrequency; + qint64 maxLimit = (m_settings.m_noModMode ? RTLSDRInput::frequencyLowRangeMax : RTLSDRInput::frequencyHighRangeMax) + deltaFrequency; minLimit = minLimit < 0 ? 0 : minLimit > 9999999 ? 9999999 : minLimit; maxLimit = maxLimit < 0 ? 0 : maxLimit > 9999999 ? 9999999 : maxLimit; + qDebug("RTLSDRGui::updateFrequencyLimits: delta: %lld min: %lld max: %lld", deltaFrequency, minLimit, maxLimit); + ui->centerFrequency->setValueRange(7, minLimit, maxLimit); } @@ -299,10 +302,6 @@ void RTLSDRGui::on_gain_valueChanged(int value) sendSettings(); } -void RTLSDRGui::on_sampleRate_currentIndexChanged(int index __attribute__((unused))) -{ -} - void RTLSDRGui::on_startStop_toggled(bool checked) { if (checked) @@ -332,10 +331,11 @@ void RTLSDRGui::on_record_toggled(bool checked) m_sampleSource->getInputMessageQueue()->push(message); } -void RTLSDRGui::on_transverter_toggled(bool checked) +void RTLSDRGui::on_transverter_clicked() { - m_settings.m_transverterMode = checked; - m_settings.m_transverterDeltaFrequency = checked ? ui->transverter->getDeltaFrequency() : 0; + m_settings.m_transverterMode = ui->transverter->getDeltaFrequencyAcive(); + m_settings.m_transverterDeltaFrequency = ui->transverter->getDeltaFrequency(); + qDebug("RTLSDRGui::on_transverter_clicked: %lld Hz %s", m_settings.m_transverterDeltaFrequency, m_settings.m_transverterMode ? "on" : "off"); updateFrequencyLimits(); m_settings.m_centerFrequency = ui->centerFrequency->getValueNew()*1000; sendSettings(); diff --git a/plugins/samplesource/rtlsdr/rtlsdrgui.h b/plugins/samplesource/rtlsdr/rtlsdrgui.h index d3f4da031..6d4004b34 100644 --- a/plugins/samplesource/rtlsdr/rtlsdrgui.h +++ b/plugins/samplesource/rtlsdr/rtlsdrgui.h @@ -82,12 +82,11 @@ private slots: void on_fcPos_currentIndexChanged(int index); void on_ppm_valueChanged(int value); void on_gain_valueChanged(int value); - void on_sampleRate_currentIndexChanged(int index); void on_checkBox_stateChanged(int state); void on_agc_stateChanged(int state); void on_startStop_toggled(bool checked); void on_record_toggled(bool checked); - void on_transverter_toggled(bool checked); + void on_transverter_clicked(); void updateHardware(); void updateStatus(); }; diff --git a/plugins/samplesource/rtlsdr/rtlsdrgui.ui b/plugins/samplesource/rtlsdr/rtlsdrgui.ui index b8937a0d6..a6126a86f 100644 --- a/plugins/samplesource/rtlsdr/rtlsdrgui.ui +++ b/plugins/samplesource/rtlsdr/rtlsdrgui.ui @@ -300,12 +300,21 @@ + + + 24 + 24 + + Transverter frequency translation toggle X + + false + diff --git a/sdrbase/gui/transverterbutton.cpp b/sdrbase/gui/transverterbutton.cpp index eede250c8..e605d95c8 100644 --- a/sdrbase/gui/transverterbutton.cpp +++ b/sdrbase/gui/transverterbutton.cpp @@ -22,22 +22,18 @@ #include "transverterbutton.h" TransverterButton::TransverterButton(QWidget* parent) : - ButtonSwitch(parent), - m_deltaFrequency(0) + QPushButton(parent), + m_deltaFrequency(0), + m_deltaFrequencyActive(false) { - connect(this, SIGNAL(toggled(bool)), this, SLOT(onToggled(bool))); + connect(this, SIGNAL(clicked(bool)), this, SLOT(onClicked(bool))); } -void TransverterButton::onToggled(bool checked) +void TransverterButton::onClicked() { - if (checked) { - TransverterDialog transverterDialog(&m_deltaFrequency, this); - transverterDialog.exec(); - setToolTip(tr("Transverter frequency translation toggle. Delta frequency %1 MHz").arg(m_deltaFrequency/1000000.0)); - } -} - -void TransverterButton::doToggle(bool checked) -{ - onToggled(checked); + TransverterDialog transverterDialog(m_deltaFrequency, m_deltaFrequencyActive, this); + transverterDialog.exec(); + setToolTip(tr("Transverter frequency translation dialog. Delta frequency %1 MHz %2") + .arg(m_deltaFrequency/1000000.0) + .arg(m_deltaFrequencyActive ? "enabled" : "disabled")); } diff --git a/sdrbase/gui/transverterbutton.h b/sdrbase/gui/transverterbutton.h index d6a490064..d738f9f3d 100644 --- a/sdrbase/gui/transverterbutton.h +++ b/sdrbase/gui/transverterbutton.h @@ -21,22 +21,24 @@ #ifndef SDRBASE_GUI_TRANSVERTERBUTTON_H_ #define SDRBASE_GUI_TRANSVERTERBUTTON_H_ -#include "buttonswitch.h" +#include -class TransverterButton : public ButtonSwitch { +class TransverterButton : public QPushButton { Q_OBJECT public: TransverterButton(QWidget* parent = 0); - void doToggle(bool checked); qint64 getDeltaFrequency() const { return m_deltaFrequency; } void setDeltaFrequency(qint64 deltaFrequency) { m_deltaFrequency = deltaFrequency; } + bool getDeltaFrequencyAcive() const { return m_deltaFrequencyActive; } + void setDeltaFrequencyActive(bool active) { m_deltaFrequencyActive = active; } private slots: - void onToggled(bool checked); + void onClicked(); private: qint64 m_deltaFrequency; + bool m_deltaFrequencyActive; }; diff --git a/sdrbase/gui/transverterdialog.cpp b/sdrbase/gui/transverterdialog.cpp index ed049f659..d75e33a2f 100644 --- a/sdrbase/gui/transverterdialog.cpp +++ b/sdrbase/gui/transverterdialog.cpp @@ -23,16 +23,18 @@ #include "ui_transverterdialog.h" -TransverterDialog::TransverterDialog(qint64 *deltaFrequency, QWidget* parent) : +TransverterDialog::TransverterDialog(qint64& deltaFrequency, bool& deltaFrequencyActive, QWidget* parent) : QDialog(parent), ui(new Ui::TransverterDialog), - m_deltaFrequency(deltaFrequency) + m_deltaFrequency(deltaFrequency), + m_deltaFrequencyActive(deltaFrequencyActive) { ui->setupUi(this); ui->deltaFrequencyLabel->setText(QString("%1f").arg(QChar(0x94, 0x03))); ui->deltaFrequency->setColorMapper(ColorMapper(ColorMapper::GrayGold)); ui->deltaFrequency->setValueRange(false, 10, -9999999999L, 9999999999L); - ui->deltaFrequency->setValue(*m_deltaFrequency); + ui->deltaFrequency->setValue(m_deltaFrequency); + ui->deltaFrequencyActive->setChecked(m_deltaFrequencyActive); } TransverterDialog::~TransverterDialog() @@ -42,6 +44,7 @@ TransverterDialog::~TransverterDialog() void TransverterDialog::accept() { - *m_deltaFrequency = ui->deltaFrequency->getValueNew(); + m_deltaFrequency = ui->deltaFrequency->getValueNew(); + m_deltaFrequencyActive = ui->deltaFrequencyActive->isChecked(); QDialog::accept(); } diff --git a/sdrbase/gui/transverterdialog.h b/sdrbase/gui/transverterdialog.h index 58edcc063..581617482 100644 --- a/sdrbase/gui/transverterdialog.h +++ b/sdrbase/gui/transverterdialog.h @@ -31,12 +31,13 @@ class TransverterDialog : public QDialog { Q_OBJECT public: - explicit TransverterDialog(qint64 *deltaFrequency, QWidget* parent = 0); + explicit TransverterDialog(qint64& deltaFrequency, bool& deltaFrequencyActive, QWidget* parent = 0); ~TransverterDialog(); private: Ui::TransverterDialog* ui; - qint64 *m_deltaFrequency; + qint64& m_deltaFrequency; + bool& m_deltaFrequencyActive; private slots: void accept(); diff --git a/sdrbase/gui/transverterdialog.ui b/sdrbase/gui/transverterdialog.ui index 8b3522215..c657b3994 100644 --- a/sdrbase/gui/transverterdialog.ui +++ b/sdrbase/gui/transverterdialog.ui @@ -60,7 +60,6 @@ Transverter delta frequency (Hz) - deltaFrequencyUnits @@ -83,6 +82,20 @@ + + + + Enable or disable frequency translation + + + + + + + :/checkmark.png:/checkmark.png + + + @@ -106,11 +119,18 @@
gui/valuedialz.h
1 + + ButtonSwitch + QToolButton +
gui/buttonswitch.h
+
buttonBox - + + + buttonBox From 82509e5785ce401f1e916430980b73b870e472d9 Mon Sep 17 00:00:00 2001 From: f4exb Date: Sun, 24 Sep 2017 02:44:20 +0200 Subject: [PATCH 09/71] RTLSDR tranverter mode interim state (2) --- plugins/samplesource/rtlsdr/rtlsdrgui.cpp | 5 +++-- sdrbase/gui/transverterbutton.cpp | 7 ++++++- sdrbase/gui/transverterbutton.h | 16 ++++++++++++++-- 3 files changed, 23 insertions(+), 5 deletions(-) diff --git a/plugins/samplesource/rtlsdr/rtlsdrgui.cpp b/plugins/samplesource/rtlsdr/rtlsdrgui.cpp index b0f13f0c7..059b53589 100644 --- a/plugins/samplesource/rtlsdr/rtlsdrgui.cpp +++ b/plugins/samplesource/rtlsdr/rtlsdrgui.cpp @@ -222,6 +222,9 @@ void RTLSDRGui::displayGains() void RTLSDRGui::displaySettings() { + ui->transverter->setDeltaFrequency(m_settings.m_transverterDeltaFrequency); + ui->transverter->setDeltaFrequencyActive(m_settings.m_transverterMode); + updateFrequencyLimits(); ui->centerFrequency->setValue(m_settings.m_centerFrequency / 1000); ui->sampleRate->setValue(m_settings.m_devSampleRate); ui->dcOffset->setChecked(m_settings.m_dcBlock); @@ -231,8 +234,6 @@ void RTLSDRGui::displaySettings() ui->decim->setCurrentIndex(m_settings.m_log2Decim); ui->fcPos->setCurrentIndex((int) m_settings.m_fcPos); ui->checkBox->setChecked(m_settings.m_noModMode); - ui->transverter->setDeltaFrequency(m_settings.m_transverterDeltaFrequency); - ui->transverter->setChecked(m_settings.m_transverterMode); } void RTLSDRGui::sendSettings() diff --git a/sdrbase/gui/transverterbutton.cpp b/sdrbase/gui/transverterbutton.cpp index e605d95c8..99f1d3c2a 100644 --- a/sdrbase/gui/transverterbutton.cpp +++ b/sdrbase/gui/transverterbutton.cpp @@ -26,13 +26,18 @@ TransverterButton::TransverterButton(QWidget* parent) : m_deltaFrequency(0), m_deltaFrequencyActive(false) { - connect(this, SIGNAL(clicked(bool)), this, SLOT(onClicked(bool))); + connect(this, SIGNAL(clicked()), this, SLOT(onClicked())); } void TransverterButton::onClicked() { TransverterDialog transverterDialog(m_deltaFrequency, m_deltaFrequencyActive, this); transverterDialog.exec(); + updateState(); +} + +void TransverterButton::updateState() +{ setToolTip(tr("Transverter frequency translation dialog. Delta frequency %1 MHz %2") .arg(m_deltaFrequency/1000000.0) .arg(m_deltaFrequencyActive ? "enabled" : "disabled")); diff --git a/sdrbase/gui/transverterbutton.h b/sdrbase/gui/transverterbutton.h index d738f9f3d..b526fb02c 100644 --- a/sdrbase/gui/transverterbutton.h +++ b/sdrbase/gui/transverterbutton.h @@ -29,9 +29,19 @@ class TransverterButton : public QPushButton { public: TransverterButton(QWidget* parent = 0); qint64 getDeltaFrequency() const { return m_deltaFrequency; } - void setDeltaFrequency(qint64 deltaFrequency) { m_deltaFrequency = deltaFrequency; } bool getDeltaFrequencyAcive() const { return m_deltaFrequencyActive; } - void setDeltaFrequencyActive(bool active) { m_deltaFrequencyActive = active; } + + void setDeltaFrequency(qint64 deltaFrequency) + { + m_deltaFrequency = deltaFrequency; + updateState(); + } + + void setDeltaFrequencyActive(bool active) + { + m_deltaFrequencyActive = active; + updateState(); + } private slots: void onClicked(); @@ -39,6 +49,8 @@ private slots: private: qint64 m_deltaFrequency; bool m_deltaFrequencyActive; + + void updateState(); }; From 67e93f6d4029d295d046b9b20f6350549778ff19 Mon Sep 17 00:00:00 2001 From: f4exb Date: Sun, 24 Sep 2017 03:12:27 +0200 Subject: [PATCH 10/71] RTLSDR tranverter mode implemented --- plugins/samplesource/rtlsdr/rtlsdrgui.cpp | 1 + plugins/samplesource/rtlsdr/rtlsdrgui.ui | 2 +- sdrbase/gui/transverterbutton.cpp | 11 +++++++++++ 3 files changed, 13 insertions(+), 1 deletion(-) diff --git a/plugins/samplesource/rtlsdr/rtlsdrgui.cpp b/plugins/samplesource/rtlsdr/rtlsdrgui.cpp index 059b53589..9e23c9e0d 100644 --- a/plugins/samplesource/rtlsdr/rtlsdrgui.cpp +++ b/plugins/samplesource/rtlsdr/rtlsdrgui.cpp @@ -234,6 +234,7 @@ void RTLSDRGui::displaySettings() ui->decim->setCurrentIndex(m_settings.m_log2Decim); ui->fcPos->setCurrentIndex((int) m_settings.m_fcPos); ui->checkBox->setChecked(m_settings.m_noModMode); + ui->agc->setChecked(m_settings.m_agc); } void RTLSDRGui::sendSettings() diff --git a/plugins/samplesource/rtlsdr/rtlsdrgui.ui b/plugins/samplesource/rtlsdr/rtlsdrgui.ui index a6126a86f..7f294acca 100644 --- a/plugins/samplesource/rtlsdr/rtlsdrgui.ui +++ b/plugins/samplesource/rtlsdr/rtlsdrgui.ui @@ -307,7 +307,7 @@ - Transverter frequency translation toggle + Transverter frequency translation dialog X diff --git a/sdrbase/gui/transverterbutton.cpp b/sdrbase/gui/transverterbutton.cpp index 99f1d3c2a..8f1edd1b1 100644 --- a/sdrbase/gui/transverterbutton.cpp +++ b/sdrbase/gui/transverterbutton.cpp @@ -26,6 +26,7 @@ TransverterButton::TransverterButton(QWidget* parent) : m_deltaFrequency(0), m_deltaFrequencyActive(false) { + setObjectName("TransverterButton"); connect(this, SIGNAL(clicked()), this, SLOT(onClicked())); } @@ -41,4 +42,14 @@ void TransverterButton::updateState() setToolTip(tr("Transverter frequency translation dialog. Delta frequency %1 MHz %2") .arg(m_deltaFrequency/1000000.0) .arg(m_deltaFrequencyActive ? "enabled" : "disabled")); + + if(m_deltaFrequencyActive) + { + setStyleSheet("TransverterButton { background:rgb(128, 70, 0); }"); + } + else + { + setStyleSheet("TransverterButton { background:rgb(48, 48, 48); }"); + } + } From 23c13f5fc2ca43ff5ea43e208c23d719e40efacc Mon Sep 17 00:00:00 2001 From: f4exb Date: Sun, 24 Sep 2017 03:18:12 +0200 Subject: [PATCH 11/71] Bumped version to 3.7.3 --- debian/changelog | 6 ++++++ sdrbase/gui/aboutdialog.ui | 2 +- sdrbase/mainwindow.cpp | 4 ++-- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/debian/changelog b/debian/changelog index a9cc4675b..2d7388aa9 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,9 @@ +sdrangel (3.7.3-1) unstable; urgency=medium + + * RTLSDR: Button and dialog to set frequency translation for transverter operation + + -- Edouard Griffiths, F4EXB Sat, 01 Oct 2017 05:14:18 +0200 + sdrangel (3.7.2-1) unstable; urgency=medium * PlutoSDR: Remove from device enumeration if device is not accessible diff --git a/sdrbase/gui/aboutdialog.ui b/sdrbase/gui/aboutdialog.ui index fa0e4dc2e..d713dea7f 100644 --- a/sdrbase/gui/aboutdialog.ui +++ b/sdrbase/gui/aboutdialog.ui @@ -84,7 +84,7 @@ - <html><head/><body><p>Version 3.7.2 - Copyright (C) 2015-2017 Edouard Griffiths, F4EXB. </p><p>Code at <a href="https://github.com/f4exb/sdrangel"><span style=" text-decoration: underline; color:#0000ff;">https://github.com/f4exb/sdrangel</span></a></p><p>Many thanks to the original developers:</p><p>The osmocom developer team - especially horizon, Hoernchen &amp; tnt.</p><p>Christian Daniel from maintech GmbH.</p><p>John Greb (hexameron) for the contributions in <a href="https://github.com/hexameron/rtl-sdrangelove"><span style=" text-decoration: underline; color:#0000ff;">RTL-SDRangelove</span></a></p><p>The following rules apply to the SDRangel main application and libsdrbase:<br/>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; either version 2 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. You should have received a copy of the GNU General Public License along with this program. If not, see <a href="http://www.gnu.org/licenses/"><span style=" text-decoration: underline; color:#0000ff;">http://www.gnu.org/licenses/</span></a>.</p><p>For the license of installed plugins, look into the plugin list.</p></body></html> + <html><head/><body><p>Version 3.7.3 - Copyright (C) 2015-2017 Edouard Griffiths, F4EXB. </p><p>Code at <a href="https://github.com/f4exb/sdrangel"><span style=" text-decoration: underline; color:#0000ff;">https://github.com/f4exb/sdrangel</span></a></p><p>Many thanks to the original developers:</p><p>The osmocom developer team - especially horizon, Hoernchen &amp; tnt.</p><p>Christian Daniel from maintech GmbH.</p><p>John Greb (hexameron) for the contributions in <a href="https://github.com/hexameron/rtl-sdrangelove"><span style=" text-decoration: underline; color:#0000ff;">RTL-SDRangelove</span></a></p><p>The following rules apply to the SDRangel main application and libsdrbase:<br/>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; either version 2 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. You should have received a copy of the GNU General Public License along with this program. If not, see <a href="http://www.gnu.org/licenses/"><span style=" text-decoration: underline; color:#0000ff;">http://www.gnu.org/licenses/</span></a>.</p><p>For the license of installed plugins, look into the plugin list.</p></body></html> true diff --git a/sdrbase/mainwindow.cpp b/sdrbase/mainwindow.cpp index 66e3b3ff1..078941719 100644 --- a/sdrbase/mainwindow.cpp +++ b/sdrbase/mainwindow.cpp @@ -501,9 +501,9 @@ void MainWindow::createStatusBar() { QString qtVersionStr = QString("Qt %1 ").arg(QT_VERSION_STR); #if QT_VERSION >= 0x050400 - m_showSystemWidget = new QLabel("SDRangel v3.7.2 " + qtVersionStr + QSysInfo::prettyProductName(), this); + m_showSystemWidget = new QLabel("SDRangel v3.7.3 " + qtVersionStr + QSysInfo::prettyProductName(), this); #else - m_showSystemWidget = new QLabel("SDRangel v3.7.2 " + qtVersionStr, this); + m_showSystemWidget = new QLabel("SDRangel v3.7.3 " + qtVersionStr, this); #endif statusBar()->addPermanentWidget(m_showSystemWidget); From f416e6242ca9585a7105733d97b9d2349e5ad2af Mon Sep 17 00:00:00 2001 From: f4exb Date: Sun, 24 Sep 2017 11:04:26 +0200 Subject: [PATCH 12/71] RTLSDR transverter mode options documentation --- doc/img/RTLSDR_plugin.png | Bin 25265 -> 25909 bytes doc/img/RTLSDR_plugin_xvrt.png | Bin 0 -> 10385 bytes plugins/samplesource/rtlsdr/readme.md | 28 ++++++++++++++++++++++++++ 3 files changed, 28 insertions(+) create mode 100644 doc/img/RTLSDR_plugin_xvrt.png diff --git a/doc/img/RTLSDR_plugin.png b/doc/img/RTLSDR_plugin.png index 1a99604de7202aa92a09f1e6de49a9920e22d059..6a9d91065b5e63ac98a87f32f65acaa723bbef14 100644 GIT binary patch literal 25909 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 B_`m=F literal 25265 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ⅅP+?qe$Z$lTZx6H$-CL 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 diff --git a/doc/img/RTLSDR_plugin_xvrt.png b/doc/img/RTLSDR_plugin_xvrt.png new file mode 100644 index 0000000000000000000000000000000000000000..caba799124c6beb21e2bbb7bb08102e70c81ea95 GIT binary patch literal 10385 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 literal 0 HcmV?d00001 diff --git a/plugins/samplesource/rtlsdr/readme.md b/plugins/samplesource/rtlsdr/readme.md index c086f574a..b4de39635 100644 --- a/plugins/samplesource/rtlsdr/readme.md +++ b/plugins/samplesource/rtlsdr/readme.md @@ -57,6 +57,34 @@ Possible values are: - **Inf**: the decimation operation takes place around the center of the lower half of the BladeRF Rx passband. - **Sup**: the decimation operation takes place around the center of the upper half of the BladeRF Rx passband. +

4a: Transverter mode open dialog

+ +This button opens a dialog to set the transverter mode frequency translation options: + +![SDR Daemon source input stream trasverter dialog](../../../doc/img/RTLSDR_plugin_xvrt.png) + +Note that if you mouse over the button a tooltip appears that displays the translating frequency and if translation is enabled or disabled. When the frequency translation is enabled the button is lit. + +

4a.1: Translating frequency

+ +You can set the translating frequency in Hz with this dial. Use the wheels to adjust the sample rate. Left click on a digit sets the cursor position at this digit. Right click on a digit sets all digits on the right to zero. This effectively floors value at the digit position. Wheels are moved with the mousewheel while pointing at the wheel or by selecting the wheel with the left mouse click and using the keyboard arroews. Pressing shift simultanoeusly moves digit by 5 and pressing control moves it by 2. + +The frequency set in the device is the frequency on the main dial (1) minus this frequency. Thus it is positive for down converters and negative for up converters. + +For example with the DX Patrol that has a mixer at 120 MHz for HF operation you would set the value to -120,000,000 Hz so that if the main dial frequency is set at 7,130 kHz the RTLSDR of the DX Patrol will be set to 127.130 MHz. + +If you use a down converter to receive the 6 cm band narrowband center frequency of 5670 MHz at 432 MHz you would set the translating frequency to 5760 - 432 = 5328 MHz thus dial +5,328,000,000 Hz. + +For bands even higher in the frequency spectrum the GHz digits are not really significant so you can have them set at 1 GHz. Thus to receive the 10368 MHz frequency at 432 MHz you would set the translating frequency to 1368 - 432 = 936 MHz. Note that in this case the frequency of the LO used in the mixer of the transverter is set at 9936 MHz. + +

4a.2: Translating frequency enable/disable

+ +Use this toggle button to activate or deactivate the frequency translation + +

4a.3: Confirmation buttons

+ +Use these buttons to confirm ("OK") or dismiss ("Cancel") your changes. +

5: Toggle low/high sample rate range

When button is on the sample rate can vary from 230 kS/s to 300 kS/s From 3a6d6f63b1cf2f07d82245cf9b42254e99312132 Mon Sep 17 00:00:00 2001 From: f4exb Date: Sun, 24 Sep 2017 12:11:15 +0200 Subject: [PATCH 13/71] RTLSDR: changed base class of TransverterButton promoted widget to QPushButton --- plugins/samplesource/rtlsdr/rtlsdrgui.ui | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/samplesource/rtlsdr/rtlsdrgui.ui b/plugins/samplesource/rtlsdr/rtlsdrgui.ui index 7f294acca..c09070110 100644 --- a/plugins/samplesource/rtlsdr/rtlsdrgui.ui +++ b/plugins/samplesource/rtlsdr/rtlsdrgui.ui @@ -602,7 +602,7 @@ TransverterButton - QToolButton + QPushButton
gui/transverterbutton.h
From 24413bfb7d2bde4c54e8a28dccc8e45a17be79d4 Mon Sep 17 00:00:00 2001 From: f4exb Date: Sun, 24 Sep 2017 13:03:08 +0200 Subject: [PATCH 14/71] PlutoSDR input: implemented transverter feature --- .../plutosdrinput/plutosdrinput.cpp | 65 +++++++++++++++---- .../plutosdrinput/plutosdrinputgui.cpp | 34 +++++++++- .../plutosdrinput/plutosdrinputgui.h | 2 + .../plutosdrinput/plutosdrinputgui.ui | 21 ++++++ .../plutosdrinput/plutosdrinputplugin.cpp | 2 +- .../plutosdrinput/plutosdrinputsettings.cpp | 6 ++ .../plutosdrinput/plutosdrinputsettings.h | 2 + 7 files changed, 115 insertions(+), 17 deletions(-) diff --git a/plugins/samplesource/plutosdrinput/plutosdrinput.cpp b/plugins/samplesource/plutosdrinput/plutosdrinput.cpp index c5593b426..3d6b26651 100644 --- a/plugins/samplesource/plutosdrinput/plutosdrinput.cpp +++ b/plugins/samplesource/plutosdrinput/plutosdrinput.cpp @@ -367,15 +367,6 @@ bool PlutoSDRInput::applySettings(const PlutoSDRInputSettings& settings, bool fo forwardChangeOwnDSP = true; } - if ((m_settings.m_fcPos != settings.m_fcPos) || force) - { - if (m_plutoSDRInputThread != 0) - { - m_plutoSDRInputThread->setFcPos(settings.m_fcPos); - qDebug() << "PlutoSDRInput::applySettings: set fcPos to " << settings.m_fcPos; - } - } - if ((m_settings.m_LOppmTenths != settings.m_LOppmTenths) || force) { plutoBox->setLOPPMTenths(settings.m_LOppmTenths); @@ -385,11 +376,59 @@ bool PlutoSDRInput::applySettings(const PlutoSDRInputSettings& settings, bool fo std::vector params; bool paramsToSet = false; - if ((m_settings.m_centerFrequency != settings.m_centerFrequency) || force) + if (force || (m_settings.m_centerFrequency != settings.m_centerFrequency) + || (m_settings.m_fcPos != settings.m_fcPos) + || (m_settings.m_transverterMode != settings.m_transverterMode) + || (m_settings.m_transverterDeltaFrequency != settings.m_transverterDeltaFrequency)) { - params.push_back(QString(tr("out_altvoltage0_RX_LO_frequency=%1").arg(settings.m_centerFrequency)).toStdString()); - paramsToSet = true; - forwardChangeOwnDSP = true; + qint64 deviceCenterFrequency = settings.m_centerFrequency; + deviceCenterFrequency -= settings.m_transverterMode ? settings.m_transverterDeltaFrequency : 0; + qint64 f_img = deviceCenterFrequency; + quint32 devSampleRate = settings.m_devSampleRate; + + if ((m_settings.m_log2Decim == 0) || (settings.m_fcPos == PlutoSDRInputSettings::FC_POS_CENTER)) + { + f_img = deviceCenterFrequency; + } + else + { + if (settings.m_fcPos == PlutoSDRInputSettings::FC_POS_INFRA) + { + deviceCenterFrequency += (devSampleRate / 4); + f_img = deviceCenterFrequency + devSampleRate/2; + } + else if (settings.m_fcPos == PlutoSDRInputSettings::FC_POS_SUPRA) + { + deviceCenterFrequency -= (devSampleRate / 4); + f_img = deviceCenterFrequency - devSampleRate/2; + } + } + + deviceCenterFrequency = deviceCenterFrequency < 0 ? 0 : deviceCenterFrequency; + + if (force || (m_settings.m_centerFrequency != settings.m_centerFrequency) + || (m_settings.m_transverterMode != settings.m_transverterMode) + || (m_settings.m_transverterDeltaFrequency != settings.m_transverterDeltaFrequency)) + { + params.push_back(QString(tr("out_altvoltage0_RX_LO_frequency=%1").arg(deviceCenterFrequency)).toStdString()); + paramsToSet = true; + forwardChangeOwnDSP = true; + } + + if ((m_settings.m_fcPos != settings.m_fcPos) || force) + { + if (m_plutoSDRInputThread != 0) + { + m_plutoSDRInputThread->setFcPos(settings.m_fcPos); + qDebug() << "PlutoSDRInput::applySettings: set fcPos to " << settings.m_fcPos; + } + } + + qDebug() << "PlutoSDRInput::applySettings: center freq: " << settings.m_centerFrequency << " Hz" + << " device center freq: " << deviceCenterFrequency << " Hz" + << " device sample rate: " << devSampleRate << "S/s" + << " Actual sample rate: " << devSampleRate/(1<setupUi(this); ui->centerFrequency->setColorMapper(ColorMapper(ColorMapper::GrayGold)); - ui->centerFrequency->setValueRange(7, DevicePlutoSDR::loLowLimitFreq/1000, DevicePlutoSDR::loHighLimitFreq/1000); + updateFrequencyLimits(); ui->sampleRate->setColorMapper(ColorMapper(ColorMapper::GrayGreenYellow)); ui->sampleRate->setValueRange(8, DevicePlutoSDR::srLowLimitFreq, DevicePlutoSDR::srHighLimitFreq); @@ -275,8 +275,21 @@ void PlutoSDRInputGui::on_antenna_currentIndexChanged(int index) sendSettings(); } +void PlutoSDRInputGui::on_transverter_clicked() +{ + m_settings.m_transverterMode = ui->transverter->getDeltaFrequencyAcive(); + m_settings.m_transverterDeltaFrequency = ui->transverter->getDeltaFrequency(); + qDebug("PlutoSDRInputGui::on_transverter_clicked: %lld Hz %s", m_settings.m_transverterDeltaFrequency, m_settings.m_transverterMode ? "on" : "off"); + updateFrequencyLimits(); + m_settings.m_centerFrequency = ui->centerFrequency->getValueNew()*1000; + sendSettings(); +} + void PlutoSDRInputGui::displaySettings() { + ui->transverter->setDeltaFrequency(m_settings.m_transverterDeltaFrequency); + ui->transverter->setDeltaFrequencyActive(m_settings.m_transverterMode); + updateFrequencyLimits(); ui->centerFrequency->setValue(m_settings.m_centerFrequency / 1000); ui->sampleRate->setValue(m_settings.m_devSampleRate); @@ -402,20 +415,35 @@ void PlutoSDRInputGui::setSampleRateLimits() ui->sampleRate->setValue(m_settings.m_devSampleRate); } +void PlutoSDRInputGui::updateFrequencyLimits() +{ + // values in kHz + qint64 deltaFrequency = m_settings.m_transverterMode ? m_settings.m_transverterDeltaFrequency/1000 : 0; + qint64 minLimit = DevicePlutoSDR::loLowLimitFreq/1000 + deltaFrequency; + qint64 maxLimit = DevicePlutoSDR::loHighLimitFreq/1000 + deltaFrequency; + + minLimit = minLimit < 0 ? 0 : minLimit > 9999999 ? 9999999 : minLimit; + maxLimit = maxLimit < 0 ? 0 : maxLimit > 9999999 ? 9999999 : maxLimit; + + qDebug("PlutoSDRInputGui::updateFrequencyLimits: delta: %lld min: %lld max: %lld", deltaFrequency, minLimit, maxLimit); + + ui->centerFrequency->setValueRange(7, minLimit, maxLimit); +} + void PlutoSDRInputGui::handleInputMessages() { Message* message; while ((message = m_inputMessageQueue.pop()) != 0) { - qDebug("LimeSDRInputGUI::handleInputMessages: message: %s", message->getIdentifier()); + qDebug("PlutoSDRInputGui::handleInputMessages: message: %s", message->getIdentifier()); if (DSPSignalNotification::match(*message)) { DSPSignalNotification* notif = (DSPSignalNotification*) message; m_sampleRate = notif->getSampleRate(); m_deviceCenterFrequency = notif->getCenterFrequency(); - qDebug("LimeSDRInputGUI::handleInputMessages: DSPSignalNotification: SampleRate: %d, CenterFrequency: %llu", notif->getSampleRate(), notif->getCenterFrequency()); + qDebug("PlutoSDRInputGui::handleInputMessages: DSPSignalNotification: SampleRate: %d, CenterFrequency: %llu", notif->getSampleRate(), notif->getCenterFrequency()); updateSampleRateAndFrequency(); setFIRBWLimits(); diff --git a/plugins/samplesource/plutosdrinput/plutosdrinputgui.h b/plugins/samplesource/plutosdrinput/plutosdrinputgui.h index 20c62ac04..8d74db570 100644 --- a/plugins/samplesource/plutosdrinput/plutosdrinputgui.h +++ b/plugins/samplesource/plutosdrinput/plutosdrinputgui.h @@ -72,6 +72,7 @@ private: void updateSampleRateAndFrequency(); void setFIRBWLimits(); void setSampleRateLimits(); + void updateFrequencyLimits(); private slots: void on_startStop_toggled(bool checked); @@ -91,6 +92,7 @@ private slots: void on_gainMode_currentIndexChanged(int index); void on_gain_valueChanged(int value); void on_antenna_currentIndexChanged(int index); + void on_transverter_clicked(); void updateHardware(); void updateStatus(); void handleInputMessages(); diff --git a/plugins/samplesource/plutosdrinput/plutosdrinputgui.ui b/plugins/samplesource/plutosdrinput/plutosdrinputgui.ui index f858acfcc..2ea09a0ec 100644 --- a/plugins/samplesource/plutosdrinput/plutosdrinputgui.ui +++ b/plugins/samplesource/plutosdrinput/plutosdrinputgui.ui @@ -275,6 +275,22 @@
+ + + + + 24 + 24 + + + + Transverter frequency translation dialog + + + X + + + @@ -937,6 +953,11 @@ QToolButton
gui/buttonswitch.h
+ + TransverterButton + QPushButton +
gui/transverterbutton.h
+
diff --git a/plugins/samplesource/plutosdrinput/plutosdrinputplugin.cpp b/plugins/samplesource/plutosdrinput/plutosdrinputplugin.cpp index e5a6a43d3..ab365852a 100644 --- a/plugins/samplesource/plutosdrinput/plutosdrinputplugin.cpp +++ b/plugins/samplesource/plutosdrinput/plutosdrinputplugin.cpp @@ -28,7 +28,7 @@ class DeviceSourceAPI; const PluginDescriptor PlutoSDRInputPlugin::m_pluginDescriptor = { QString("PlutoSDR Input"), - QString("3.7.2"), + QString("3.7.3"), QString("(c) Edouard Griffiths, F4EXB"), QString("https://github.com/f4exb/sdrangel"), true, diff --git a/plugins/samplesource/plutosdrinput/plutosdrinputsettings.cpp b/plugins/samplesource/plutosdrinput/plutosdrinputsettings.cpp index b0d4f5e08..ac5f7cb33 100644 --- a/plugins/samplesource/plutosdrinput/plutosdrinputsettings.cpp +++ b/plugins/samplesource/plutosdrinput/plutosdrinputsettings.cpp @@ -41,6 +41,8 @@ void PlutoSDRInputSettings::resetToDefaults() m_gain = 40; m_antennaPath = RFPATH_A_BAL; m_gainMode = GAIN_MANUAL; + m_transverterMode = false; + m_transverterDeltaFrequency = 0; } QByteArray PlutoSDRInputSettings::serialize() const @@ -61,6 +63,8 @@ QByteArray PlutoSDRInputSettings::serialize() const s.writeU32(13, m_gain); s.writeS32(14, (int) m_antennaPath); s.writeS32(15, (int) m_gainMode); + s.writeBool(16, m_transverterMode); + s.writeS64(17, m_transverterDeltaFrequency); return s.final(); } @@ -114,6 +118,8 @@ bool PlutoSDRInputSettings::deserialize(const QByteArray& data) } else { m_gainMode = GAIN_MANUAL; } + d.readBool(16, &m_transverterMode, false); + d.readS64(17, &m_transverterDeltaFrequency, 0); return true; } diff --git a/plugins/samplesource/plutosdrinput/plutosdrinputsettings.h b/plugins/samplesource/plutosdrinput/plutosdrinputsettings.h index 1003329e9..19d4793b2 100644 --- a/plugins/samplesource/plutosdrinput/plutosdrinputsettings.h +++ b/plugins/samplesource/plutosdrinput/plutosdrinputsettings.h @@ -71,6 +71,8 @@ struct PlutoSDRInputSettings { quint32 m_gain; //!< "hardware" gain RFPath m_antennaPath; GainMode m_gainMode; + bool m_transverterMode; + qint64 m_transverterDeltaFrequency; PlutoSDRInputSettings(); From 99e96f10993f4f1846101ca89ea73b1ed48351f1 Mon Sep 17 00:00:00 2001 From: f4exb Date: Sun, 24 Sep 2017 14:32:49 +0200 Subject: [PATCH 15/71] PlutoSDR input: transverter feature documentation --- doc/img/PlutoSDRInput_plugin.png | Bin 31659 -> 32353 bytes plugins/samplesource/plutosdrinput/readme.md | 30 +++++++++++++++++++ plugins/samplesource/rtlsdr/readme.md | 2 ++ 3 files changed, 32 insertions(+) diff --git a/doc/img/PlutoSDRInput_plugin.png b/doc/img/PlutoSDRInput_plugin.png index bd147c3b9dbbc5f49642f0b35e0e4469c133af5e..72de0453ae729227b5a109dcb1219459063031c9 100644 GIT binary patch literal 32353 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 YRrkuIb`dxg9t}-g`0eXlA)OEZ7ad4c{{R30 literal 31659 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

T^Ii0q2-} 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 PYGcSrDN7bhm4a: Transverter mode open dialog + +This button opens a dialog to set the transverter mode frequency translation options: + +![SDR Daemon source input stream trasverter dialog](../../../doc/img/RTLSDR_plugin_xvrt.png) + +Note that if you mouse over the button a tooltip appears that displays the translating frequency and if translation is enabled or disabled. When the frequency translation is enabled the button is lit. + +

4a.1: Translating frequency

+ +You can set the translating frequency in Hz with this dial. Use the wheels to adjust the sample rate. Left click on a digit sets the cursor position at this digit. Right click on a digit sets all digits on the right to zero. This effectively floors value at the digit position. Wheels are moved with the mousewheel while pointing at the wheel or by selecting the wheel with the left mouse click and using the keyboard arroews. Pressing shift simultanoeusly moves digit by 5 and pressing control moves it by 2. + +The frequency set in the device is the frequency on the main dial (1) minus this frequency. Thus it is positive for down converters and negative for up converters. + +For example with the DX Patrol that has a mixer at 120 MHz for HF operation you would set the value to -120,000,000 Hz so that if the main dial frequency is set at 7,130 kHz the RTLSDR of the DX Patrol will be set to 127.130 MHz. + +If you use a down converter to receive the 6 cm band narrowband center frequency of 5670 MHz at 432 MHz you would set the translating frequency to 5760 - 432 = 5328 MHz thus dial +5,328,000,000 Hz. + +For bands even higher in the frequency spectrum the GHz digits are not really significant so you can have them set at 1 GHz. Thus to receive the 10368 MHz frequency at 432 MHz you would set the translating frequency to 1368 - 432 = 936 MHz. Note that in this case the frequency of the LO used in the mixer of the transverter is set at 9936 MHz. + +The Hz precision allows a fine tuning of the transverter LO offset + +

4a.2: Translating frequency enable/disable

+ +Use this toggle button to activate or deactivate the frequency translation + +

4a.3: Confirmation buttons

+ +Use these buttons to confirm ("OK") or dismiss ("Cancel") your changes. +

5: Software decimation factor

The I/Q stream from the PlutoSDR is doensampled by a power of two by software inside the plugin before being sent to the passband. Possible values are increasing powers of two: 1 (no decimation), 2, 4, 8, 16, 32, 64. diff --git a/plugins/samplesource/rtlsdr/readme.md b/plugins/samplesource/rtlsdr/readme.md index b4de39635..d89e58e88 100644 --- a/plugins/samplesource/rtlsdr/readme.md +++ b/plugins/samplesource/rtlsdr/readme.md @@ -77,6 +77,8 @@ If you use a down converter to receive the 6 cm band narrowband center frequency For bands even higher in the frequency spectrum the GHz digits are not really significant so you can have them set at 1 GHz. Thus to receive the 10368 MHz frequency at 432 MHz you would set the translating frequency to 1368 - 432 = 936 MHz. Note that in this case the frequency of the LO used in the mixer of the transverter is set at 9936 MHz. +The Hz precision allows a fine tuning of the transverter LO offset +

4a.2: Translating frequency enable/disable

Use this toggle button to activate or deactivate the frequency translation From 37d44038f42728e3f5dcdbd8e9f763e5dcedc380 Mon Sep 17 00:00:00 2001 From: f4exb Date: Mon, 25 Sep 2017 19:11:13 +0200 Subject: [PATCH 16/71] PlutoSDR output: implemented transverter feature --- doc/img/PlutoSDROutput_plugin.png | Bin 26847 -> 27936 bytes .../plutosdroutput/plutosdroutput.cpp | 16 ++++++++-- .../plutosdroutput/plutosdroutputgui.cpp | 30 +++++++++++++++++- .../plutosdroutput/plutosdroutputgui.h | 2 ++ .../plutosdroutput/plutosdroutputgui.ui | 21 ++++++++++++ .../plutosdroutput/plutosdroutputsettings.cpp | 6 ++++ .../plutosdroutput/plutosdroutputsettings.h | 2 ++ plugins/samplesink/plutosdroutput/readme.md | 30 ++++++++++++++++++ plugins/samplesource/plutosdrinput/readme.md | 2 +- 9 files changed, 105 insertions(+), 4 deletions(-) diff --git a/doc/img/PlutoSDROutput_plugin.png b/doc/img/PlutoSDROutput_plugin.png index 9bfebf06cc7e60af376433c5877c49b7c337de78..d728b849f4e78371b6f4928995d0d169de7db61a 100644 GIT binary patch literal 27936 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%0ARe!$@*jVUet7dZAOe3(jg+5 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 literal 26847 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þwXyS?&&p(c=bzheOwOj<-Z>AgUueLuS#fUjA?Wx1&DXR_yA{ zA5BL`%_nOV@1#fXqf6`Tbjqr9)<*3GyR6XtoC>`Be5nsQdnu_@?@7%OV>_QguFzel zuqKSA!xs`)cl_ci^D7st7V9<+ybTV%#{(Zx_^jtfYm1b(E(*zZ0G}j(zZQz9!LZEE z?naB++uK8VTXiG)>HH5OBBJ{_10uS!7_3VF7y+3_Vy9766r#9%oVOn|`CFWRY4>=t z>1AjAhFEQNS?tQw;FMq{#x=fjhu zMLL{bJ3lU0#`+XBV(Rt$$=WIZ^)Wqnygk=)B36hc{EfVCa!F^PG$y8xAthy8_S#)r zg%OWGcCKuq2cZ+UZr?3*m5J`-8Hi%Ilg2qweYmqd){3;HRHXQ2G^CcXn)@VeBHpU|+L^%b}Gw2N>>!L8paB^XpTAMD+bbz$_sq z7!ZWdex8=WYff5P`q@xkLfi^+}a&ZQhZ?O1NwzW5|>`-z3TzKXLaZjL+- z`ST3*QkRqe*G%r_Q(WI9LHgiOkl8oI67sJ}Z-?xW&}MX*H(8Y$9{)NUvMN=5VwI9R zF0E5JQW#!7nj2!wabBv64rbT8rp4iT?yp3=a=Fvl_bBS?QxmkAx3_v{+|_TAl8UJn z%@VmJbn2g2_@iuPy>obhFRBAof_<70fi5!gxjCOWDDU{Ge{@dz!wBTqfm zXlKot9PXm8NTQep=qO`i>6;8`go1DB{gP2Mv#;lmlu36p{#M;8y9xSym{tUrl$1PD=GN*jlp7L^dDVXscpd%R&@QsiB@Jgx zisI>-uiom}5TSX*OYE)H3fEpQCFo75at`w@?|XAGeDxLzcRJGVCY{zTa&EtKrIWvG ziB@fpigTC|Tl%@39rxtP5+%yly-vwYRK{xgO7eWpxnOR4!PfcJ?(;u?+|N$dUc?NP zi{RkkbS8?&Uz9k+0H_u$J?)HTG6<-G?*~XXwC2uz6F+O6I;=neP{I?KfH&Ii#xG>Z z%eu!|0GV@9{P3>MxpVB1Z}$$v>|8~l%m?~z|7sqI>=u<()74kp1c?v-I8kNtjsfZU@C(1 z@LPLEikC^drod-qx*KCB+dIknMNaM3`ofxAW93?8=O+p%i4m{2p%Rkb160-zN8Hc7 zUy-0h%GDPn=@pIqE}x(5+oxHqaJVK37S)x~FGj}1v;zC}90qgnrfeo_j#lUbC|JnI z$Qq9KV%$lTvdMDH( zIKR=}L~9!vM{=}s4TGp}JxzLb`Fjen=6gRDTL+hGBe6wgg{Qpc(voxiqe91rr*KZ3 zR*5A}`J!0O_e}>&)=%AX{cat&JWBQ>K_$8o24@?Tl5p#d9IAe7o)}GBjA3<_(DNP8 zeD=yfH66ynpj?eiJ?2E&}L;MTg!v}7XLI_)oDrA5Iu`__s*$Y zZ-l3Y;e2s!j>q`xh1Q+e*lhQh=YRHw7|w@W0u_zMH3V8n8D@Yxb^9(>?Kt~Lz;1jv zrK1bxQp2S=juR?oW@a^~+Z{vWfdUeDVyo@DXOnw$=tWbRZ+%OOy~-@cC(?0trra3* zh`fO0qBgKvqv7oK;=V=9B;2L1UUSJ_^{ZnsY29{C3(NuuZ`It^7ynmLY=%f zbRK85d7U+)LDlc(F43AYWk@w?NtR8&&L8b){^)1R%!$b@`N8bVGgro?Ag6fmQ(Xi6 zmZB#%kGUIM2K-z#wB<%R%rwvrb)`umrp`ed)0VDQ?IMGVkCx1X!rjXsY_3P+`(Ln0 zXl@y{4_{|5yc5ikUw-VkvU{t_b?q$|Q_Tx|1B+tg+Z^-iE4N17^JokBc#Nz?Rpi<= zQDqvO{#N`RwTa-m5E2sV{`Lft3*P3cxE$i?O8f(==>3YaH=E6V43|uND}sunNmZOe zYHqTs#C|&8HWA>Kd~EAOsT<{Is9V6PUdF!#YJ|9W0!Y>%c)-RYqocz=etcP!+H10+ zuEwxRQGo3k*-){=x$TX&9~O^B6=UXHSu%{Otht`)=O=%0+`O@1)CPJd9=@6nX@b5z z+1MVk8X0_$+GE6X1xN+!-W{9O-WBznfy{pP&@44Y*WBe5wE@^r?SsiS^6c;F z+m0I1?h>5ub4U3H!Y9%c<*JO{T(IGEW5wLKcj9m$*8k^$jQx^}un~t{4ldc%h5H9w zKK^f?&*p1Hc$7ufN-hr43bClob_g&nDX^$yQ4%lzdRu18cW61F-6`Ni^nqSPx8a-E ztVXNnhQXx^hZ+g<0yYxwMr@odz4iD$i!`hBGPa~@QuZpcH}lgLR7Zfka3HoT&eJVr z#OnE2J2#pGOH;<-^JSVik1E$fRNsKQBH=7L z^GWsAn&AC<>j$D|C$_l4FW&05S{IMV{^*YgU-8n&*mg?o%W4YF&nJ^E5yROJS}yUx z#;sVa3vUp@e(4zVYHG1;(>b=&wQK74NO9NkSo$BH$lTwISNTco?R@_kJKg_$OTt&N zlUJ@4TlO(Q*qc@oaPU=h3sQXA?{D+$vPBZ~(9;QsfAXQ9RE-JMCLKKgaCfUfMzM*v z;T=ZXn@j#-ey+|Es+wLYb1m)C_>P=m)u)7v{$#zcY`xpnG&a!+@2qFssipA=h8Ij^ zHB4lqzTeJUpE^xrIr)v5^VAfJh!JxPL)=7I@_F{@Cr+m8;_v-FFvXE^O(iAz`?g@l zcpJ*iNrj5CYQYxFNr!VAi|2-H?pQM$8Bi6_;04Hf{V+>%_u(Ng2%cjwYhi77QXH&} zsr*ofd2D{oez2iqNGQyY>gyYk+CdjBVv&=YdW9)#1s@*?jK;=B67~%Wvq~?n6Ml0Q z^Eskm`ywX2ddluaHu-C!i}c$eMJ2~- zY3-vf%+8xOfj3PGtWJMYn*H2wi}7d9mzky+3bMQli||$>o;Lqy-)!uPbn|~0%&iQ) z5--CGS+k4N-TUw+@n)V#EV6wP%;AGZ7833I*@0i}4cu9y8-(uXkZOC6T}@Ls#?uVm z-{!OGi~3+pbjzON;bH=Jhr$T`PHm9j>A0#QU8-E`AK|dx5^*VP&wih-RdLQ?Tlz6S z&!izxMyt|)O=7T+*`oHXC#f%AhWSt7hz(nmlShFAH%)nGYj)3! z?>eiOy?#G+x5wyuh6AU!#*G?~nSdCs051aYnsTY5kZ8+OK z^!FjRBq~jcmKf~E9BT&$y9eNf0qB2cWLimE4(e~)F79zNr3cty!$;kE(o*vKM-qW~I%+@71*nx50{k8k2R zu-MTs)S+Iw8{@uhknNQbBk{ZQIU(2hVGgQ}Zgx1mip1T)n}0Pb?`IB&7~j=&&bP{L z6$_%3c^CO+@x2Nu4VTtNjp?#d^qxbPJ~ArGxKJAoMk(0}4iY_5RCE_mq}I9b5z9Z5 zv8jV_g1($BHYh@*0l?*(P*Nx~{Z5{7faoQFjdTF3FkI=(3bldzP@X!}L6&cFa&jT9 zkmQ;$dF{^A3!v1Q!_*z-W^W4$-cFEnU%%d9DOT;a_Vj3bzSO6DA-$$VPP;(y^%p4u zO`K>fW}LC#C*L9s6JPMzHiud_K25LKA@fP9dw<{e_~Wk(dug+Rjr^i)FDAutS?_2$ z@HG$t4ZyF%g?Rf|u@^;p+`k|?z#Jf<-(%%}sp>dh3lV;85!aPwn8SfmU<6C0an~UO zrFr0;4?$b)EVCUOuJ@HhVhaH3lFk_ru=;dO7)O3cdgDCHyCNy1VK)E%uJ>meEX*dO zDVIZ2(M*laQL)Q;`TF~EL3Vy!9aE>OL!_&(23N-`oo{h-yZbLiP3sDqqBS{SaE9(p zA2faWXcbEZ_v=1El*M44fjpF2qYl0{H6hssh&}O9=4!H9h7ytsQ|dDbs(mG-IU;{( zgq_l6_x9JuiV;ya->@rFHMQ;g_i4}pEc^MY7ZW|N@I50#5-N<1jXUFbTWvM~3KSK93HL1;uD-BOf>QB~1G3=_AS-iZx6DG%MUKIE3z+=k;3Zky$4_N&1 z(dN|n!152t0)aXpX~VCxeL={qcpnfjb$XO7*uD%^WJA zV_-MPV+-V&-A+99=@6ZDA=Y^#3zl8oX>HdLAz_&%+i2<*G?lO4jPv6*7p-+m{zZua zOq6U<<@@8?5fFZH$E0Nw*d%bDm0>gj0pP>XP^F@6r6DK(x;fn>>@{3#$CTHvt7?VT^6u)>iDGv;9zAJtvG55qb*9+U zVQFe=g2Yj!ri`>Sp|`FF^Ll`oz^S($=Qz!NDO$~|?w<6Z7mJ1Us@9lx=Ce7z%VU@) zsV>~~llb>f8jJ0lDC}j4%9QwMNkAKh=0&b%PAZP)JP$1Ckt9_83Wt|~Ic{sO(Xvyt}4tWGx{K9UyyH(Jz2M$_keqUVMlaJ7!cxV($p2npcQc* zg)5&&u0h9P+d|hvB51-($2Ptmw|Fa&{)GCHWL_id2IboZQd45R0LBWA$M^3f*PqFR zcPaK;#N{qcuyb;{)@VL?GIM2cA_i=73(-MU46xE?VNQntT#)e53xWJ^sUm%G#P74ZM240W_;Cz}C9o+)B zWE(^@At6{$f^YvyO-43V(x8b?Lc%O6I+n$s`0=BvS%u?liz9@ifB_pSwv7+#>4leg zR~xKskEl}wTIwXl4kRbFgVq>$7U-!iOYWsN-4OS|R=i4A@KCjhEwCy@^vBbbj(z6m zQS)*|rG8NJ+MbU=i6ma6<;yheFxAna!2qU)l8Op*YGY&L%3wmw21I8$LJrsFQfjD( zZW@T!NbE0yH^QxR1VbL)Vvj(Q#(=aSNRg?MkGy$ys{k5;BU&0_0W@}Vb2AwQh1#OS z8kE)H>p2B+wo~Bh?`6k)HKzTH6uI= z&bLnhdqmb-oDmS41$Fz3>3q-+TMO2!yp$p77h)s8lcI-`S;C|!)H9qHI*sSrK0?(P zu_+<#0!s>>;exoZEVZ?R^1c0iP%`hpoglw*r43#$G%#l%AlQ#uf$2cDgmQyAR>e=vh!77EJ4Z)H z$XQ`a*;h>CLIu(iEdGm%oG;MN6Wi(Jg<4(x zLtnwJFYFhd863o2op@*?5Dz0MGRO?LU4oe`m}Fa!*8y}nk^+*M$%c$c%Pw#ggsN;; zs^9Sc2eZwvi-V&Kh~m(40$(w?Z&@3Hlhw3(;KCCkd0Wch@X`s|U6?|^NpSF+Iy!<% zO8B6#+6mnD%rKS@A|tG1WguT)Vd2X57v)sI&H#YUCm($qN&A76yCN94*_$-z=W~Zv zk+d;ov8@LYSLZaYy&2eTQlE4 zcZ0x!cIaNhIXaEad%|Yn&KFts&2xw%xgj`2)EGQ2ODaf!8%&Q5;kzCy?pZb~YYs_U zFvvkBH5a632*Azg>{Nhnatp*5e41yQvE3L}?i)Ghn4^*|AjSQK(Q)pQ#q~~KkPD}O zOG4|~=v0RpKkE0nRe5oa*RAGbVm;%pPhvNptZiVfQ4EQ!rvu9d8QfFQA2bJ%Vs2h| zBO}|(Dx}LCS}h>tzk&f2AbPmE;faas&pvu=Qzfi$ly1DHZ05?m+hvg4XU$CMv#K%s zaG-Wn?`JUI%tYg>Cl*b*q%F=?fo_&OiRijkMx+|>&v*0&o~MIPc!zztHo0(EIO!c? zZP&F)7jZ~(QZ3KPiFNnWU6fZ=t*oQCyTfqs+Mv4BI|2^9&~Y)2pNq)PY(p3|{LAh0 zinY?}PR?xssuO){y7i}+#J-e1`3w4^UqTz@L;2^|R&;5;JduN0hN$~G)7`t_h~ybo zyG=hF=s<#x??A7ipPX#)?dzU`4!e`!p@-?j<;`oRlLc!GMbDq1)R93p6I_J`|91lxHK_%xd8nD>K)w|^JHGOTM*weWy#Cgb`xxWK!$#F zU%3a9Oe0x_>AlXq@;HGLK)e2 z(z5dlvlfCc9bU5cVagn7_1QFvmQi@Pj7KGn&zOdz_u8b|GHKY*r;D0AERl)g9zLTO zztPQ-huhYKjN_UaLyyO2Jlj-{$qS_MrybkXqOLsATPVtzRHYU!*T>R?e;vW7G4NE7 z2>%1GY=Z!=aGM-HqkkB6E}8W6rS=Lm&Ke1|muFm$OG%1~W_^8s&TE?U_|8L@^3Q}N zPdQbecB(wtO~5sIJH986Y|TF+Afsc2PyaBfokLvhGjUNeY0*?)&WG{6$w-Ee@->ee zptR(`V|I(}k4ErW!KZ)>D^k5C8k}$M4I`7(O*l2CsI0zp)y_Y6FT3%`ua8@(Zu<_kRMd^Gxj_i3^8B#V8!PmD$-vXy{GJrm~Fmy{yJ z_3MACd}3Ox{ky|VRaba7o$7uwqjg@|HG`cq9(tmGLxN;;_5?hV}{@*jqyK$nF zFJ5#Jx#Z8V2&L?;d`76Vz|WDZPKG=J|NGOwoBCg${=GE+ z`Q3j%{d-sc^Sl3k`gfE69>(88`_B&j|Hr5Q?(lzp`tRZVzwhw>o`2@bIkw6dIt+4x TGk5r}h%n?HDm}=PHhT46%6mOr diff --git a/plugins/samplesink/plutosdroutput/plutosdroutput.cpp b/plugins/samplesink/plutosdroutput/plutosdroutput.cpp index 39459fff3..e979fe627 100644 --- a/plugins/samplesink/plutosdroutput/plutosdroutput.cpp +++ b/plugins/samplesink/plutosdroutput/plutosdroutput.cpp @@ -343,11 +343,23 @@ bool PlutoSDROutput::applySettings(const PlutoSDROutputSettings& settings, bool std::vector params; bool paramsToSet = false; - if ((m_settings.m_centerFrequency != settings.m_centerFrequency) || force) + if (force || (m_settings.m_centerFrequency != settings.m_centerFrequency) + || (m_settings.m_transverterMode != settings.m_transverterMode) + || (m_settings.m_transverterDeltaFrequency != settings.m_transverterDeltaFrequency)) + { - params.push_back(QString(tr("out_altvoltage1_TX_LO_frequency=%1").arg(settings.m_centerFrequency)).toStdString()); + qint64 deviceCenterFrequency = settings.m_centerFrequency; + deviceCenterFrequency -= settings.m_transverterMode ? settings.m_transverterDeltaFrequency : 0; + deviceCenterFrequency = deviceCenterFrequency < 0 ? 0 : deviceCenterFrequency; + + + params.push_back(QString(tr("out_altvoltage1_TX_LO_frequency=%1").arg(deviceCenterFrequency)).toStdString()); paramsToSet = true; forwardChangeOwnDSP = true; + + qDebug() << "PlutoSDROutput::applySettings: center freq: " << settings.m_centerFrequency << " Hz" + << " device center freq: " << deviceCenterFrequency << " Hz"; + } if ((m_settings.m_lpfBW != settings.m_lpfBW) || force) diff --git a/plugins/samplesink/plutosdroutput/plutosdroutputgui.cpp b/plugins/samplesink/plutosdroutput/plutosdroutputgui.cpp index 8d4a48521..893c2055e 100644 --- a/plugins/samplesink/plutosdroutput/plutosdroutputgui.cpp +++ b/plugins/samplesink/plutosdroutput/plutosdroutputgui.cpp @@ -44,7 +44,7 @@ PlutoSDROutputGUI::PlutoSDROutputGUI(DeviceSinkAPI *deviceAPI, QWidget* parent) ui->setupUi(this); ui->centerFrequency->setColorMapper(ColorMapper(ColorMapper::GrayGold)); - ui->centerFrequency->setValueRange(7, DevicePlutoSDR::loLowLimitFreq/1000, DevicePlutoSDR::loHighLimitFreq/1000); + updateFrequencyLimits(); ui->sampleRate->setColorMapper(ColorMapper(ColorMapper::GrayGreenYellow)); ui->sampleRate->setValueRange(8, DevicePlutoSDR::srLowLimitFreq, DevicePlutoSDR::srHighLimitFreq); @@ -238,8 +238,21 @@ void PlutoSDROutputGUI::on_antenna_currentIndexChanged(int index) sendSettings(); } +void PlutoSDROutputGUI::on_transverter_clicked() +{ + m_settings.m_transverterMode = ui->transverter->getDeltaFrequencyAcive(); + m_settings.m_transverterDeltaFrequency = ui->transverter->getDeltaFrequency(); + qDebug("PlutoSDROutputGUI::on_transverter_clicked: %lld Hz %s", m_settings.m_transverterDeltaFrequency, m_settings.m_transverterMode ? "on" : "off"); + updateFrequencyLimits(); + m_settings.m_centerFrequency = ui->centerFrequency->getValueNew()*1000; + sendSettings(); +} + void PlutoSDROutputGUI::displaySettings() { + ui->transverter->setDeltaFrequency(m_settings.m_transverterDeltaFrequency); + ui->transverter->setDeltaFrequencyActive(m_settings.m_transverterMode); + updateFrequencyLimits(); ui->centerFrequency->setValue(m_settings.m_centerFrequency / 1000); ui->sampleRate->setValue(m_settings.m_devSampleRate); @@ -362,6 +375,21 @@ void PlutoSDROutputGUI::setSampleRateLimits() ui->sampleRate->setValue(m_settings.m_devSampleRate); } +void PlutoSDROutputGUI::updateFrequencyLimits() +{ + // values in kHz + qint64 deltaFrequency = m_settings.m_transverterMode ? m_settings.m_transverterDeltaFrequency/1000 : 0; + qint64 minLimit = DevicePlutoSDR::loLowLimitFreq/1000 + deltaFrequency; + qint64 maxLimit = DevicePlutoSDR::loHighLimitFreq/1000 + deltaFrequency; + + minLimit = minLimit < 0 ? 0 : minLimit > 9999999 ? 9999999 : minLimit; + maxLimit = maxLimit < 0 ? 0 : maxLimit > 9999999 ? 9999999 : maxLimit; + + qDebug("PlutoSDRInputGui::updateFrequencyLimits: delta: %lld min: %lld max: %lld", deltaFrequency, minLimit, maxLimit); + + ui->centerFrequency->setValueRange(7, minLimit, maxLimit); +} + void PlutoSDROutputGUI::handleInputMessages() { Message* message; diff --git a/plugins/samplesink/plutosdroutput/plutosdroutputgui.h b/plugins/samplesink/plutosdroutput/plutosdroutputgui.h index 570a9e93e..235624f04 100644 --- a/plugins/samplesink/plutosdroutput/plutosdroutputgui.h +++ b/plugins/samplesink/plutosdroutput/plutosdroutputgui.h @@ -72,6 +72,7 @@ private: void updateSampleRateAndFrequency(); void setFIRBWLimits(); void setSampleRateLimits(); + void updateFrequencyLimits(); private slots: void on_startStop_toggled(bool checked); @@ -86,6 +87,7 @@ private slots: void on_lpFIRGain_currentIndexChanged(int index); void on_att_valueChanged(int value); void on_antenna_currentIndexChanged(int index); + void on_transverter_clicked(); void updateHardware(); void updateStatus(); void handleInputMessages(); diff --git a/plugins/samplesink/plutosdroutput/plutosdroutputgui.ui b/plugins/samplesink/plutosdroutput/plutosdroutputgui.ui index a8c7e7183..ea61bf9c4 100644 --- a/plugins/samplesink/plutosdroutput/plutosdroutputgui.ui +++ b/plugins/samplesink/plutosdroutput/plutosdroutputgui.ui @@ -240,6 +240,22 @@
+ + + + + 24 + 24 + + + + Transverter frequency translation dialog + + + X + + + @@ -766,6 +782,11 @@ QToolButton
gui/buttonswitch.h
+ + TransverterButton + QPushButton +
gui/transverterbutton.h
+
diff --git a/plugins/samplesink/plutosdroutput/plutosdroutputsettings.cpp b/plugins/samplesink/plutosdroutput/plutosdroutputsettings.cpp index 631da14d6..21ef340c4 100644 --- a/plugins/samplesink/plutosdroutput/plutosdroutputsettings.cpp +++ b/plugins/samplesink/plutosdroutput/plutosdroutputsettings.cpp @@ -36,6 +36,8 @@ void PlutoSDROutputSettings::resetToDefaults() m_lpfFIRlog2Interp = 0; m_att = -50; m_antennaPath = RFPATH_A; + m_transverterMode = false; + m_transverterDeltaFrequency = 0; } QByteArray PlutoSDROutputSettings::serialize() const @@ -52,6 +54,8 @@ QByteArray PlutoSDROutputSettings::serialize() const s.writeU64(12, m_devSampleRate); s.writeS32(13, m_att); s.writeS32(14, (int) m_antennaPath); + s.writeBool(15, m_transverterMode); + s.writeS64(16, m_transverterDeltaFrequency); return s.final(); } @@ -91,6 +95,8 @@ bool PlutoSDROutputSettings::deserialize(const QByteArray& data) } else { m_antennaPath = RFPATH_A; } + d.readBool(15, &m_transverterMode, false); + d.readS64(16, &m_transverterDeltaFrequency, 0); return true; } diff --git a/plugins/samplesink/plutosdroutput/plutosdroutputsettings.h b/plugins/samplesink/plutosdroutput/plutosdroutputsettings.h index a3ad223b3..672dbd4fd 100644 --- a/plugins/samplesink/plutosdroutput/plutosdroutputsettings.h +++ b/plugins/samplesink/plutosdroutput/plutosdroutputsettings.h @@ -42,6 +42,8 @@ struct PlutoSDROutputSettings { quint32 m_lpfBW; //!< analog lowpass filter bandwidth (Hz) qint32 m_att; //!< "hardware" attenuation in dB fourths RFPath m_antennaPath; + bool m_transverterMode; + qint64 m_transverterDeltaFrequency; PlutoSDROutputSettings(); diff --git a/plugins/samplesink/plutosdroutput/readme.md b/plugins/samplesink/plutosdroutput/readme.md index 5ed3f9ef1..b8724eb6a 100644 --- a/plugins/samplesink/plutosdroutput/readme.md +++ b/plugins/samplesink/plutosdroutput/readme.md @@ -59,6 +59,36 @@ Baseband I/Q sample rate in kS/s. This is the host to device sample rate (5) div Use this slider to adjust LO correction in ppm. It can be varied from -20.0 to 20.0 in 0.1 steps and is applied in hardware. This applies to the oscillator that controls both the Tx and Rx frequency therefore it is also changed on the Rx plugin if it is active. +

2a: Transverter mode open dialog

+ +This button opens a dialog to set the transverter mode frequency translation options: + +![SDR Daemon source input stream trasverter dialog](../../../doc/img/RTLSDR_plugin_xvrt.png) + +Note that if you mouse over the button a tooltip appears that displays the translating frequency and if translation is enabled or disabled. When the frequency translation is enabled the button is lit. + +

2a.1: Translating frequency

+ +You can set the translating frequency in Hz with this dial. Use the wheels to adjust the sample rate. Left click on a digit sets the cursor position at this digit. Right click on a digit sets all digits on the right to zero. This effectively floors value at the digit position. Wheels are moved with the mousewheel while pointing at the wheel or by selecting the wheel with the left mouse click and using the keyboard arroews. Pressing shift simultanoeusly moves digit by 5 and pressing control moves it by 2. + +The frequency set in the device is the frequency on the main dial (1) minus this frequency. Thus it is positive for up converters and negative for down converters. + +For example with a mixer at 120 MHz for HF operation you would set the value to -120,000,000 Hz so that if the main dial frequency is set to 7,130 kHz the PuotSDR will be set to 127.130 MHz. + +If you use an up converter to transmit at the 6 cm band narrowband center frequency of 5670 MHz aith the PlutoSDR set at 432 MHz you would set the translating frequency to 5760 - 432 = 5328 MHz thus dial +5,328,000,000 Hz. + +For bands even higher in the frequency spectrum the GHz digits are not really significant so you can have them set at 1 GHz. Thus to transmit at the 10368 MHz frequency with 432 MHz for the PlutoSDR you would set the translating frequency to 1368 - 432 = 936 MHz. Note that in this case the frequency of the LO used in the mixer of the transverter is set at 9936 MHz. + +The Hz precision allows a fine tuning of the transverter LO offset + +

2a.2: Translating frequency enable/disable

+ +Use this toggle button to activate or deactivate the frequency translation + +

2a.3: Confirmation buttons

+ +Use these buttons to confirm ("OK") or dismiss ("Cancel") your changes. +

3: Software interpolation factor

The I/Q stream to the PlutoSDR is upsampled by a power of two by software inside the plugin from the signal coming from the passband. Possible values are increasing powers of two: 1 (no interpolation), 2, 4, 8, 16, 32. diff --git a/plugins/samplesource/plutosdrinput/readme.md b/plugins/samplesource/plutosdrinput/readme.md index 291f41874..351e7bceb 100644 --- a/plugins/samplesource/plutosdrinput/readme.md +++ b/plugins/samplesource/plutosdrinput/readme.md @@ -86,7 +86,7 @@ You can set the translating frequency in Hz with this dial. Use the wheels to ad The frequency set in the device is the frequency on the main dial (1) minus this frequency. Thus it is positive for down converters and negative for up converters. -For example with the DX Patrol that has a mixer at 120 MHz for HF operation you would set the value to -120,000,000 Hz so that if the main dial frequency is set at 7,130 kHz the RTLSDR of the DX Patrol will be set to 127.130 MHz. +For example a mixer at 120 MHz for HF operation you would set the value to -120,000,000 Hz so that if the main dial frequency is set at 7,130 kHz the PlutoSDR will be set to 127.130 MHz. If you use a down converter to receive the 6 cm band narrowband center frequency of 5670 MHz at 432 MHz you would set the translating frequency to 5760 - 432 = 5328 MHz thus dial +5,328,000,000 Hz. From d9d1b8bfec0adaa2196383dbcfd7105a704f60d7 Mon Sep 17 00:00:00 2001 From: f4exb Date: Mon, 25 Sep 2017 20:16:25 +0200 Subject: [PATCH 17/71] FunCube Pro input: implemented transverter feature --- fcdpp.rules => fcd.rules | 3 +- fcdlib/fcdtraits.cpp | 8 ++++- fcdlib/fcdtraits.h | 6 ++++ .../plutosdroutput/plutosdroutputplugin.cpp | 2 +- plugins/samplesource/fcdpro/fcdprogui.cpp | 31 ++++++++++++++++++- plugins/samplesource/fcdpro/fcdprogui.h | 2 ++ plugins/samplesource/fcdpro/fcdprogui.ui | 31 ++++++++++++++++--- plugins/samplesource/fcdpro/fcdproinput.cpp | 23 +++++++++----- .../samplesource/fcdpro/fcdprosettings.cpp | 6 ++++ plugins/samplesource/fcdpro/fcdprosettings.h | 2 ++ 10 files changed, 97 insertions(+), 17 deletions(-) rename fcdpp.rules => fcd.rules (56%) diff --git a/fcdpp.rules b/fcd.rules similarity index 56% rename from fcdpp.rules rename to fcd.rules index ccadc1461..3dace445c 100644 --- a/fcdpp.rules +++ b/fcd.rules @@ -1,5 +1,6 @@ # Udev rules for the Funcube Dongle Pro+ (0xfb31) # HIDAPI/libusb: -SUBSYSTEMS=="usb", ATTRS{idVendor}=="04d8", ATTRS{idProduct}=="fb31", GROUP:="audio", MODE:="0666" +SUBSYSTEMS=="usb", ATTRS{idVendor}=="04d8", ATTRS{idProduct}=="fb56", MODE:="0666" +SUBSYSTEMS=="usb", ATTRS{idVendor}=="04d8", ATTRS{idProduct}=="fb31", MODE:="0666" diff --git a/fcdlib/fcdtraits.cpp b/fcdlib/fcdtraits.cpp index a119628fa..eb7342d1f 100644 --- a/fcdlib/fcdtraits.cpp +++ b/fcdlib/fcdtraits.cpp @@ -22,5 +22,11 @@ const char *fcd_traits::displayedName = "FunCube Dongle Pro+"; const char *fcd_traits::pluginDisplayedName = "FunCube Pro Input"; const char *fcd_traits::pluginDisplayedName = "FunCube Pro+ Input"; -const char *fcd_traits::pluginVersion = "3.5.0"; +const char *fcd_traits::pluginVersion = "3.7.3"; const char *fcd_traits::pluginVersion = "3.5.0"; + +const int64_t fcd_traits::loLowLimitFreq = 64000000L; +const int64_t fcd_traits::loLowLimitFreq = 64000000L; + +const int64_t fcd_traits::loHighLimitFreq = 1700000000L; +const int64_t fcd_traits::loHighLimitFreq = 1700000000L; diff --git a/fcdlib/fcdtraits.h b/fcdlib/fcdtraits.h index 8d6cc9db0..a649edc39 100644 --- a/fcdlib/fcdtraits.h +++ b/fcdlib/fcdtraits.h @@ -30,6 +30,8 @@ struct fcd_traits static const char *displayedName; static const char *pluginDisplayedName; static const char *pluginVersion; + static const int64_t loLowLimitFreq; + static const int64_t loHighLimitFreq; }; template<> @@ -46,6 +48,8 @@ struct fcd_traits static const char *displayedName; static const char *pluginDisplayedName; static const char *pluginVersion; + static const int64_t loLowLimitFreq; + static const int64_t loHighLimitFreq; }; template<> @@ -62,6 +66,8 @@ struct fcd_traits static const char *displayedName; static const char *pluginDisplayedName; static const char *pluginVersion; + static const int64_t loLowLimitFreq; + static const int64_t loHighLimitFreq; }; template const char *fcd_traits::alsaDeviceName = ""; diff --git a/plugins/samplesink/plutosdroutput/plutosdroutputplugin.cpp b/plugins/samplesink/plutosdroutput/plutosdroutputplugin.cpp index 1c5b9c479..4b4372349 100644 --- a/plugins/samplesink/plutosdroutput/plutosdroutputplugin.cpp +++ b/plugins/samplesink/plutosdroutput/plutosdroutputplugin.cpp @@ -28,7 +28,7 @@ class DeviceSourceAPI; const PluginDescriptor PlutoSDROutputPlugin::m_pluginDescriptor = { QString("PlutoSDR Output"), - QString("3.7.2"), + QString("3.7.3"), QString("(c) Edouard Griffiths, F4EXB"), QString("https://github.com/f4exb/sdrangel"), true, diff --git a/plugins/samplesource/fcdpro/fcdprogui.cpp b/plugins/samplesource/fcdpro/fcdprogui.cpp index 0ffb02b08..e07dd8304 100644 --- a/plugins/samplesource/fcdpro/fcdprogui.cpp +++ b/plugins/samplesource/fcdpro/fcdprogui.cpp @@ -25,6 +25,7 @@ #include #include "fcdproconst.h" +#include "fcdtraits.h" FCDProGui::FCDProGui(DeviceSourceAPI *deviceAPI, QWidget* parent) : QWidget(parent), @@ -38,7 +39,7 @@ FCDProGui::FCDProGui(DeviceSourceAPI *deviceAPI, QWidget* parent) : ui->setupUi(this); ui->centerFrequency->setColorMapper(ColorMapper(ColorMapper::GrayGold)); - ui->centerFrequency->setValueRange(7, 64000U, 1700000U); + updateFrequencyLimits(); ui->lnaGain->clear(); for (int i = 0; i < FCDProConstants::fcdpro_lna_gain_nb_values(); i++) @@ -237,8 +238,26 @@ void FCDProGui::updateSampleRateAndFrequency() ui->deviceRateText->setText(tr("%1k").arg((float)m_sampleRate / 1000)); } +void FCDProGui::updateFrequencyLimits() +{ + // values in kHz + qint64 deltaFrequency = m_settings.m_transverterMode ? m_settings.m_transverterDeltaFrequency/1000 : 0; + qint64 minLimit = fcd_traits::loLowLimitFreq/1000 + deltaFrequency; + qint64 maxLimit = fcd_traits::loHighLimitFreq/1000 + deltaFrequency; + + minLimit = minLimit < 0 ? 0 : minLimit > 9999999 ? 9999999 : minLimit; + maxLimit = maxLimit < 0 ? 0 : maxLimit > 9999999 ? 9999999 : maxLimit; + + qDebug("FCDProGui::updateFrequencyLimits: delta: %lld min: %lld max: %lld", deltaFrequency, minLimit, maxLimit); + + ui->centerFrequency->setValueRange(7, minLimit, maxLimit); +} + void FCDProGui::displaySettings() { + ui->transverter->setDeltaFrequency(m_settings.m_transverterDeltaFrequency); + ui->transverter->setDeltaFrequencyActive(m_settings.m_transverterMode); + updateFrequencyLimits(); ui->centerFrequency->setValue(m_settings.m_centerFrequency / 1000); ui->ppm->setValue(m_settings.m_LOppmTenths); ui->ppmText->setText(QString("%1").arg(QString::number(m_settings.m_LOppmTenths/10.0, 'f', 1))); @@ -440,6 +459,16 @@ void FCDProGui::on_record_toggled(bool checked) m_sampleSource->getInputMessageQueue()->push(message); } +void FCDProGui::on_transverter_clicked() +{ + m_settings.m_transverterMode = ui->transverter->getDeltaFrequencyAcive(); + m_settings.m_transverterDeltaFrequency = ui->transverter->getDeltaFrequency(); + qDebug("FCDProGui::on_transverter_clicked: %lld Hz %s", m_settings.m_transverterDeltaFrequency, m_settings.m_transverterMode ? "on" : "off"); + updateFrequencyLimits(); + m_settings.m_centerFrequency = ui->centerFrequency->getValueNew()*1000; + sendSettings(); +} + void FCDProGui::updateStatus() { int state = m_deviceAPI->state(); diff --git a/plugins/samplesource/fcdpro/fcdprogui.h b/plugins/samplesource/fcdpro/fcdprogui.h index 8d93580f3..03491152e 100644 --- a/plugins/samplesource/fcdpro/fcdprogui.h +++ b/plugins/samplesource/fcdpro/fcdprogui.h @@ -68,6 +68,7 @@ private: void displaySettings(); void sendSettings(); void updateSampleRateAndFrequency(); + void updateFrequencyLimits(); private slots: void handleInputMessages(); @@ -95,6 +96,7 @@ private slots: void on_setDefaults_clicked(bool checked); void on_startStop_toggled(bool checked); void on_record_toggled(bool checked); + void on_transverter_clicked(); void updateHardware(); void updateStatus(); }; diff --git a/plugins/samplesource/fcdpro/fcdprogui.ui b/plugins/samplesource/fcdpro/fcdprogui.ui index 0ad31ead9..f368fea64 100644 --- a/plugins/samplesource/fcdpro/fcdprogui.ui +++ b/plugins/samplesource/fcdpro/fcdprogui.ui @@ -6,20 +6,20 @@ 0 0 - 270 - 335 + 320 + 350 - + 0 0 - 270 - 335 + 320 + 350 @@ -238,6 +238,22 @@
+ + + + + 24 + 24 + + + + Transverter frequency translation dialog + + + X + + + @@ -484,6 +500,11 @@ QToolButton
gui/buttonswitch.h
+ + TransverterButton + QPushButton +
gui/transverterbutton.h
+
diff --git a/plugins/samplesource/fcdpro/fcdproinput.cpp b/plugins/samplesource/fcdpro/fcdproinput.cpp index 2a374dae7..764ce22e7 100644 --- a/plugins/samplesource/fcdpro/fcdproinput.cpp +++ b/plugins/samplesource/fcdpro/fcdproinput.cpp @@ -201,16 +201,23 @@ void FCDProInput::applySettings(const FCDProSettings& settings, bool force) { bool signalChange = false; - if ((m_settings.m_centerFrequency != settings.m_centerFrequency) || force) + if (force || (m_settings.m_centerFrequency != settings.m_centerFrequency) + || (m_settings.m_transverterMode != settings.m_transverterMode) + || (m_settings.m_transverterDeltaFrequency != settings.m_transverterDeltaFrequency)) { - qDebug() << "FCDProInput::applySettings: fc: " << settings.m_centerFrequency; + qint64 deviceCenterFrequency = settings.m_centerFrequency; + deviceCenterFrequency -= settings.m_transverterMode ? settings.m_transverterDeltaFrequency : 0; + deviceCenterFrequency = deviceCenterFrequency < 0 ? 0 : deviceCenterFrequency; + + if (m_dev != 0) + { + set_center_freq((double) deviceCenterFrequency); + } + + qDebug() << "FCDProInput::applySettings: center freq: " << settings.m_centerFrequency << " Hz" + << " device center freq: " << deviceCenterFrequency << " Hz"; + m_settings.m_centerFrequency = settings.m_centerFrequency; - - if (m_dev != 0) - { - set_center_freq((double) m_settings.m_centerFrequency); - } - signalChange = true; } diff --git a/plugins/samplesource/fcdpro/fcdprosettings.cpp b/plugins/samplesource/fcdpro/fcdprosettings.cpp index 6ef1873a5..88f19bc73 100644 --- a/plugins/samplesource/fcdpro/fcdprosettings.cpp +++ b/plugins/samplesource/fcdpro/fcdprosettings.cpp @@ -45,6 +45,8 @@ void FCDProSettings::resetToDefaults() m_ifFilterIndex = 0; m_gain5Index = 0; m_gain6Index = 0; + m_transverterMode = false; + m_transverterDeltaFrequency = 0; } QByteArray FCDProSettings::serialize() const @@ -70,6 +72,8 @@ QByteArray FCDProSettings::serialize() const s.writeS32(17, m_ifFilterIndex); s.writeS32(18, m_gain5Index); s.writeS32(19, m_gain6Index); + s.writeBool(20, m_transverterMode); + s.writeS64(21, m_transverterDeltaFrequency); return s.final(); } @@ -105,6 +109,8 @@ bool FCDProSettings::deserialize(const QByteArray& data) d.readS32(17, &m_ifFilterIndex, 0); d.readS32(18, &m_gain5Index, 0); d.readS32(19, &m_gain6Index, 0); + d.readBool(20, &m_transverterMode, false); + d.readS64(21, &m_transverterDeltaFrequency, 0); return true; } diff --git a/plugins/samplesource/fcdpro/fcdprosettings.h b/plugins/samplesource/fcdpro/fcdprosettings.h index aaa3ff384..59f4e3860 100644 --- a/plugins/samplesource/fcdpro/fcdprosettings.h +++ b/plugins/samplesource/fcdpro/fcdprosettings.h @@ -38,6 +38,8 @@ struct FCDProSettings { qint32 m_gain6Index; bool m_dcBlock; bool m_iqCorrection; + bool m_transverterMode; + qint64 m_transverterDeltaFrequency; FCDProSettings(); void resetToDefaults(); From 97fa96979acc909da6efd2d951ddf8b48341a47b Mon Sep 17 00:00:00 2001 From: f4exb Date: Mon, 25 Sep 2017 20:39:14 +0200 Subject: [PATCH 18/71] FunCube Pro+ input: implemented transverter feature --- fcdlib/fcdtraits.cpp | 4 +-- .../samplesource/fcdproplus/fcdproplusgui.cpp | 31 ++++++++++++++++++- .../samplesource/fcdproplus/fcdproplusgui.h | 2 ++ .../samplesource/fcdproplus/fcdproplusgui.ui | 21 +++++++++++++ .../fcdproplus/fcdproplusinput.cpp | 23 +++++++++----- .../fcdproplus/fcdproplussettings.cpp | 6 ++++ .../fcdproplus/fcdproplussettings.h | 2 ++ 7 files changed, 78 insertions(+), 11 deletions(-) diff --git a/fcdlib/fcdtraits.cpp b/fcdlib/fcdtraits.cpp index eb7342d1f..638727513 100644 --- a/fcdlib/fcdtraits.cpp +++ b/fcdlib/fcdtraits.cpp @@ -26,7 +26,7 @@ const char *fcd_traits::pluginVersion = "3.7.3"; const char *fcd_traits::pluginVersion = "3.5.0"; const int64_t fcd_traits::loLowLimitFreq = 64000000L; -const int64_t fcd_traits::loLowLimitFreq = 64000000L; +const int64_t fcd_traits::loLowLimitFreq = 150000L; const int64_t fcd_traits::loHighLimitFreq = 1700000000L; -const int64_t fcd_traits::loHighLimitFreq = 1700000000L; +const int64_t fcd_traits::loHighLimitFreq = 2000000000L; diff --git a/plugins/samplesource/fcdproplus/fcdproplusgui.cpp b/plugins/samplesource/fcdproplus/fcdproplusgui.cpp index 1d2c56798..01221162b 100644 --- a/plugins/samplesource/fcdproplus/fcdproplusgui.cpp +++ b/plugins/samplesource/fcdproplus/fcdproplusgui.cpp @@ -26,6 +26,7 @@ #include #include "fcdproplusconst.h" +#include "fcdtraits.h" FCDProPlusGui::FCDProPlusGui(DeviceSourceAPI *deviceAPI, QWidget* parent) : QWidget(parent), @@ -40,7 +41,7 @@ FCDProPlusGui::FCDProPlusGui(DeviceSourceAPI *deviceAPI, QWidget* parent) : ui->setupUi(this); ui->centerFrequency->setColorMapper(ColorMapper(ColorMapper::GrayGold)); - ui->centerFrequency->setValueRange(7, 150U, 2000000U); + updateFrequencyLimits(); ui->filterIF->clear(); for (int i = 0; i < FCDProPlusConstants::fcdproplus_if_filter_nb_values(); i++) @@ -155,8 +156,26 @@ void FCDProPlusGui::updateSampleRateAndFrequency() ui->deviceRateText->setText(tr("%1k").arg((float)m_sampleRate / 1000)); } +void FCDProPlusGui::updateFrequencyLimits() +{ + // values in kHz + qint64 deltaFrequency = m_settings.m_transverterMode ? m_settings.m_transverterDeltaFrequency/1000 : 0; + qint64 minLimit = fcd_traits::loLowLimitFreq/1000 + deltaFrequency; + qint64 maxLimit = fcd_traits::loHighLimitFreq/1000 + deltaFrequency; + + minLimit = minLimit < 0 ? 0 : minLimit > 9999999 ? 9999999 : minLimit; + maxLimit = maxLimit < 0 ? 0 : maxLimit > 9999999 ? 9999999 : maxLimit; + + qDebug("FCDProPlusGui::updateFrequencyLimits: delta: %lld min: %lld max: %lld", deltaFrequency, minLimit, maxLimit); + + ui->centerFrequency->setValueRange(7, minLimit, maxLimit); +} + void FCDProPlusGui::displaySettings() { + ui->transverter->setDeltaFrequency(m_settings.m_transverterDeltaFrequency); + ui->transverter->setDeltaFrequencyActive(m_settings.m_transverterMode); + updateFrequencyLimits(); ui->centerFrequency->setValue(m_settings.m_centerFrequency / 1000); ui->dcOffset->setChecked(m_settings.m_dcBlock); ui->iqImbalance->setChecked(m_settings.m_iqImbalance); @@ -303,3 +322,13 @@ void FCDProPlusGui::on_record_toggled(bool checked) FCDProPlusInput::MsgFileRecord* message = FCDProPlusInput::MsgFileRecord::create(checked); m_sampleSource->getInputMessageQueue()->push(message); } + +void FCDProPlusGui::on_transverter_clicked() +{ + m_settings.m_transverterMode = ui->transverter->getDeltaFrequencyAcive(); + m_settings.m_transverterDeltaFrequency = ui->transverter->getDeltaFrequency(); + qDebug("FCDProPlusGui::on_transverter_clicked: %lld Hz %s", m_settings.m_transverterDeltaFrequency, m_settings.m_transverterMode ? "on" : "off"); + updateFrequencyLimits(); + m_settings.m_centerFrequency = ui->centerFrequency->getValueNew()*1000; + sendSettings(); +} diff --git a/plugins/samplesource/fcdproplus/fcdproplusgui.h b/plugins/samplesource/fcdproplus/fcdproplusgui.h index 8628df0af..4dbd77ad9 100644 --- a/plugins/samplesource/fcdproplus/fcdproplusgui.h +++ b/plugins/samplesource/fcdproplus/fcdproplusgui.h @@ -67,6 +67,7 @@ private: void displaySettings(); void sendSettings(); void updateSampleRateAndFrequency(); + void updateFrequencyLimits(); private slots: void handleInputMessages(); @@ -82,6 +83,7 @@ private slots: void on_ppm_valueChanged(int value); void on_startStop_toggled(bool checked); void on_record_toggled(bool checked); + void on_transverter_clicked(); void updateHardware(); void updateStatus(); }; diff --git a/plugins/samplesource/fcdproplus/fcdproplusgui.ui b/plugins/samplesource/fcdproplus/fcdproplusgui.ui index cc0720819..270db02c2 100644 --- a/plugins/samplesource/fcdproplus/fcdproplusgui.ui +++ b/plugins/samplesource/fcdproplus/fcdproplusgui.ui @@ -238,6 +238,22 @@
+ + + + + 24 + 24 + + + + Transverter frequency translation dialog + + + X + + + @@ -391,6 +407,11 @@ QToolButton
gui/buttonswitch.h
+ + TransverterButton + QPushButton +
gui/transverterbutton.h
+
diff --git a/plugins/samplesource/fcdproplus/fcdproplusinput.cpp b/plugins/samplesource/fcdproplus/fcdproplusinput.cpp index d17641487..e860f88fe 100644 --- a/plugins/samplesource/fcdproplus/fcdproplusinput.cpp +++ b/plugins/samplesource/fcdproplus/fcdproplusinput.cpp @@ -195,17 +195,24 @@ void FCDProPlusInput::applySettings(const FCDProPlusSettings& settings, bool for { bool signalChange = false; - if ((m_settings.m_centerFrequency != settings.m_centerFrequency) || force) + if (force || (m_settings.m_centerFrequency != settings.m_centerFrequency) + || (m_settings.m_transverterMode != settings.m_transverterMode) + || (m_settings.m_transverterDeltaFrequency != settings.m_transverterDeltaFrequency)) { - qDebug() << "FCDProPlusInput::applySettings: fc: " << settings.m_centerFrequency; - m_settings.m_centerFrequency = settings.m_centerFrequency; + qint64 deviceCenterFrequency = settings.m_centerFrequency; + deviceCenterFrequency -= settings.m_transverterMode ? settings.m_transverterDeltaFrequency : 0; + deviceCenterFrequency = deviceCenterFrequency < 0 ? 0 : deviceCenterFrequency; - if (m_dev != 0) - { - set_center_freq((double) m_settings.m_centerFrequency); - } + if (m_dev != 0) + { + set_center_freq((double) deviceCenterFrequency); + } - signalChange = true; + qDebug() << "FCDProPlusInput::applySettings: center freq: " << settings.m_centerFrequency << " Hz" + << " device center freq: " << deviceCenterFrequency << " Hz"; + + m_settings.m_centerFrequency = settings.m_centerFrequency; + signalChange = true; } if ((m_settings.m_lnaGain != settings.m_lnaGain) || force) diff --git a/plugins/samplesource/fcdproplus/fcdproplussettings.cpp b/plugins/samplesource/fcdproplus/fcdproplussettings.cpp index ad557d39d..0751c78ac 100644 --- a/plugins/samplesource/fcdproplus/fcdproplussettings.cpp +++ b/plugins/samplesource/fcdproplus/fcdproplussettings.cpp @@ -35,6 +35,8 @@ void FCDProPlusSettings::resetToDefaults() m_LOppmTenths = 0; m_dcBlock = false; m_iqImbalance = false; + m_transverterMode = false; + m_transverterDeltaFrequency = 0; } QByteArray FCDProPlusSettings::serialize() const @@ -50,6 +52,8 @@ QByteArray FCDProPlusSettings::serialize() const s.writeBool(7, m_iqImbalance); s.writeS32(8, m_LOppmTenths); s.writeU32(9, m_ifGain); + s.writeBool(10, m_transverterMode); + s.writeS64(11, m_transverterDeltaFrequency); return s.final(); } @@ -75,6 +79,8 @@ bool FCDProPlusSettings::deserialize(const QByteArray& data) d.readBool(7, &m_iqImbalance, false); d.readS32(8, &m_LOppmTenths, 0); d.readU32(9, &m_ifGain, 0); + d.readBool(10, &m_transverterMode, false); + d.readS64(11, &m_transverterDeltaFrequency, 0); return true; } diff --git a/plugins/samplesource/fcdproplus/fcdproplussettings.h b/plugins/samplesource/fcdproplus/fcdproplussettings.h index fc4373a05..b0978fb17 100644 --- a/plugins/samplesource/fcdproplus/fcdproplussettings.h +++ b/plugins/samplesource/fcdproplus/fcdproplussettings.h @@ -29,6 +29,8 @@ struct FCDProPlusSettings { qint32 m_LOppmTenths; bool m_dcBlock; bool m_iqImbalance; + bool m_transverterMode; + qint64 m_transverterDeltaFrequency; FCDProPlusSettings(); void resetToDefaults(); From 84d5b4f1ee2647551aef69ca47c0553e24780de8 Mon Sep 17 00:00:00 2001 From: f4exb Date: Mon, 25 Sep 2017 23:07:29 +0200 Subject: [PATCH 19/71] Airspy input: implemented transverter feature --- plugins/samplesource/airspy/airspygui.cpp | 41 +++++++++++++------ plugins/samplesource/airspy/airspygui.h | 2 + plugins/samplesource/airspy/airspygui.ui | 21 ++++++++++ plugins/samplesource/airspy/airspyinput.cpp | 29 ++++++++----- plugins/samplesource/airspy/airspyinput.h | 23 ++--------- .../samplesource/airspy/airspysettings.cpp | 6 +++ plugins/samplesource/airspy/airspysettings.h | 2 + plugins/samplesource/rtlsdr/rtlsdrinput.cpp | 5 +-- 8 files changed, 83 insertions(+), 46 deletions(-) diff --git a/plugins/samplesource/airspy/airspygui.cpp b/plugins/samplesource/airspy/airspygui.cpp index 81b38db59..bb7756dc2 100644 --- a/plugins/samplesource/airspy/airspygui.cpp +++ b/plugins/samplesource/airspy/airspygui.cpp @@ -42,7 +42,7 @@ AirspyGui::AirspyGui(DeviceSourceAPI *deviceAPI, QWidget* parent) : ui->setupUi(this); ui->centerFrequency->setColorMapper(ColorMapper(ColorMapper::GrayGold)); - ui->centerFrequency->setValueRange(7, 24000U, 1900000U); + updateFrequencyLimits(); connect(&m_updateTimer, SIGNAL(timeout()), this, SLOT(updateHardware())); connect(&m_statusTimer, SIGNAL(timeout()), this, SLOT(updateStatus())); @@ -114,17 +114,6 @@ bool AirspyGui::deserialize(const QByteArray& data) bool AirspyGui::handleMessage(const Message& message __attribute__((unused))) { return false; -// if (AirspyInput::MsgReportAirspy::match(message)) -// { -// qDebug() << "AirspyGui::handleMessage: MsgReportAirspy"; -// m_rates = ((AirspyInput::MsgReportAirspy&) message).getSampleRates(); -// displaySampleRates(); -// return true; -// } -// else -// { -// return false; -// } } void AirspyGui::handleInputMessages() @@ -162,8 +151,26 @@ void AirspyGui::updateSampleRateAndFrequency() ui->deviceRateText->setText(tr("%1k").arg((float)m_sampleRate / 1000)); } +void AirspyGui::updateFrequencyLimits() +{ + // values in kHz + qint64 deltaFrequency = m_settings.m_transverterMode ? m_settings.m_transverterDeltaFrequency/1000 : 0; + qint64 minLimit = AirspyInput::loLowLimitFreq/1000 + deltaFrequency; + qint64 maxLimit = AirspyInput::loHighLimitFreq/1000 + deltaFrequency; + + minLimit = minLimit < 0 ? 0 : minLimit > 9999999 ? 9999999 : minLimit; + maxLimit = maxLimit < 0 ? 0 : maxLimit > 9999999 ? 9999999 : maxLimit; + + qDebug("AirspyGui::updateFrequencyLimits: delta: %lld min: %lld max: %lld", deltaFrequency, minLimit, maxLimit); + + ui->centerFrequency->setValueRange(7, minLimit, maxLimit); +} + void AirspyGui::displaySettings() { + ui->transverter->setDeltaFrequency(m_settings.m_transverterDeltaFrequency); + ui->transverter->setDeltaFrequencyActive(m_settings.m_transverterMode); + updateFrequencyLimits(); ui->centerFrequency->setValue(m_settings.m_centerFrequency / 1000); ui->LOppm->setValue(m_settings.m_LOppmTenths); @@ -355,6 +362,16 @@ void AirspyGui::on_record_toggled(bool checked) m_sampleSource->getInputMessageQueue()->push(message); } +void AirspyGui::on_transverter_clicked() +{ + m_settings.m_transverterMode = ui->transverter->getDeltaFrequencyAcive(); + m_settings.m_transverterDeltaFrequency = ui->transverter->getDeltaFrequency(); + qDebug("AirspyGui::on_transverter_clicked: %lld Hz %s", m_settings.m_transverterDeltaFrequency, m_settings.m_transverterMode ? "on" : "off"); + updateFrequencyLimits(); + m_settings.m_centerFrequency = ui->centerFrequency->getValueNew()*1000; + sendSettings(); +} + void AirspyGui::updateHardware() { qDebug() << "AirspyGui::updateHardware"; diff --git a/plugins/samplesource/airspy/airspygui.h b/plugins/samplesource/airspy/airspygui.h index 145caca75..66bdc10d0 100644 --- a/plugins/samplesource/airspy/airspygui.h +++ b/plugins/samplesource/airspy/airspygui.h @@ -72,6 +72,7 @@ private: void displaySampleRates(); void sendSettings(); void updateSampleRateAndFrequency(); + void updateFrequencyLimits(); private slots: void on_centerFrequency_changed(quint64 value); @@ -89,6 +90,7 @@ private slots: void on_mixAGC_stateChanged(int state); void on_startStop_toggled(bool checked); void on_record_toggled(bool checked); + void on_transverter_clicked(); void updateHardware(); void updateStatus(); void handleInputMessages(); diff --git a/plugins/samplesource/airspy/airspygui.ui b/plugins/samplesource/airspy/airspygui.ui index 29095605b..f26919185 100644 --- a/plugins/samplesource/airspy/airspygui.ui +++ b/plugins/samplesource/airspy/airspygui.ui @@ -267,6 +267,22 @@
+ + + + + 24 + 24 + + + + Transverter frequency translation dialog + + + X + + + @@ -645,6 +661,11 @@ QToolButton
gui/buttonswitch.h
+ + TransverterButton + QPushButton +
gui/transverterbutton.h
+
diff --git a/plugins/samplesource/airspy/airspyinput.cpp b/plugins/samplesource/airspy/airspyinput.cpp index 8c7e4865f..fdea8467e 100644 --- a/plugins/samplesource/airspy/airspyinput.cpp +++ b/plugins/samplesource/airspy/airspyinput.cpp @@ -30,7 +30,9 @@ MESSAGE_CLASS_DEFINITION(AirspyInput::MsgConfigureAirspy, Message) MESSAGE_CLASS_DEFINITION(AirspyInput::MsgFileRecord, Message) -//MESSAGE_CLASS_DEFINITION(AirspyInput::MsgReportAirspy, Message) + +const qint64 AirspyInput::loLowLimitFreq = 24000000L; +const qint64 AirspyInput::loHighLimitFreq = 1900000000L; AirspyInput::AirspyInput(DeviceSourceAPI *deviceAPI) : m_deviceAPI(deviceAPI), @@ -332,15 +334,22 @@ bool AirspyInput::applySettings(const AirspySettings& settings, bool force) } } - qint64 deviceCenterFrequency = m_settings.m_centerFrequency; - qint64 f_img = deviceCenterFrequency; - quint32 devSampleRate = m_sampleRates[m_settings.m_devSampleRateIndex]; - - if (force || (m_settings.m_centerFrequency != settings.m_centerFrequency) || - (m_settings.m_LOppmTenths != settings.m_LOppmTenths) || - (m_settings.m_fcPos != settings.m_fcPos)) + if (force || (m_settings.m_centerFrequency != settings.m_centerFrequency) + || (m_settings.m_LOppmTenths != settings.m_LOppmTenths) + || (m_settings.m_fcPos != settings.m_fcPos) + || (m_settings.m_transverterMode != settings.m_transverterMode) + || (m_settings.m_transverterDeltaFrequency != settings.m_transverterDeltaFrequency)) { - m_settings.m_centerFrequency = settings.m_centerFrequency; + m_settings.m_centerFrequency = settings.m_centerFrequency; + m_settings.m_transverterMode = settings.m_transverterMode; + m_settings.m_transverterDeltaFrequency = settings.m_transverterDeltaFrequency; + + qint64 deviceCenterFrequency = m_settings.m_centerFrequency; + deviceCenterFrequency -= m_settings.m_transverterMode ? m_settings.m_transverterDeltaFrequency : 0; + deviceCenterFrequency = deviceCenterFrequency < 0 ? 0 : deviceCenterFrequency; + qint64 f_img = deviceCenterFrequency; + quint32 devSampleRate = m_sampleRates[m_settings.m_devSampleRateIndex]; + m_settings.m_LOppmTenths = settings.m_LOppmTenths; if ((m_settings.m_log2Decim == 0) || (settings.m_fcPos == AirspySettings::FC_POS_CENTER)) @@ -503,7 +512,7 @@ bool AirspyInput::applySettings(const AirspySettings& settings, bool force) if (forwardChange) { - int sampleRate = devSampleRate/(1<handleMessage(*notif); // forward to file sink m_deviceAPI->getDeviceEngineInputMessageQueue()->push(notif); diff --git a/plugins/samplesource/airspy/airspyinput.h b/plugins/samplesource/airspy/airspyinput.h index d8af4f729..9981367b5 100644 --- a/plugins/samplesource/airspy/airspyinput.h +++ b/plugins/samplesource/airspy/airspyinput.h @@ -68,26 +68,6 @@ public: { } }; -// class MsgReportAirspy : public Message { -// MESSAGE_CLASS_DECLARATION -// -// public: -// const std::vector& getSampleRates() const { return m_sampleRates; } -// -// static MsgReportAirspy* create(const std::vector& sampleRates) -// { -// return new MsgReportAirspy(sampleRates); -// } -// -// protected: -// std::vector m_sampleRates; -// -// MsgReportAirspy(const std::vector& sampleRates) : -// Message(), -// m_sampleRates(sampleRates) -// { } -// }; - AirspyInput(DeviceSourceAPI *deviceAPI); virtual ~AirspyInput(); virtual void destroy(); @@ -102,6 +82,9 @@ public: virtual bool handleMessage(const Message& message); + static const qint64 loLowLimitFreq; + static const qint64 loHighLimitFreq; + private: bool openDevice(); void closeDevice(); diff --git a/plugins/samplesource/airspy/airspysettings.cpp b/plugins/samplesource/airspy/airspysettings.cpp index dca1edc7b..ef8dbb1a0 100644 --- a/plugins/samplesource/airspy/airspysettings.cpp +++ b/plugins/samplesource/airspy/airspysettings.cpp @@ -38,6 +38,8 @@ void AirspySettings::resetToDefaults() m_biasT = false; m_dcBlock = false; m_iqCorrection = false; + m_transverterMode = false; + m_transverterDeltaFrequency = 0; } QByteArray AirspySettings::serialize() const @@ -56,6 +58,8 @@ QByteArray AirspySettings::serialize() const s.writeBool(10, m_iqCorrection); s.writeBool(11, m_lnaAGC); s.writeBool(12, m_mixerAGC); + s.writeBool(13, m_transverterMode); + s.writeS64(14, m_transverterDeltaFrequency); return s.final(); } @@ -87,6 +91,8 @@ bool AirspySettings::deserialize(const QByteArray& data) d.readBool(10, &m_iqCorrection, false); d.readBool(11, &m_lnaAGC, false); d.readBool(12, &m_mixerAGC, false); + d.readBool(13, &m_transverterMode, false); + d.readS64(14, &m_transverterDeltaFrequency, 0); return true; } diff --git a/plugins/samplesource/airspy/airspysettings.h b/plugins/samplesource/airspy/airspysettings.h index 6cbf16aec..4e42fe061 100644 --- a/plugins/samplesource/airspy/airspysettings.h +++ b/plugins/samplesource/airspy/airspysettings.h @@ -37,6 +37,8 @@ struct AirspySettings { bool m_biasT; bool m_dcBlock; bool m_iqCorrection; + bool m_transverterMode; + qint64 m_transverterDeltaFrequency; AirspySettings(); void resetToDefaults(); diff --git a/plugins/samplesource/rtlsdr/rtlsdrinput.cpp b/plugins/samplesource/rtlsdr/rtlsdrinput.cpp index 0eebfe1cb..533f9f2c0 100644 --- a/plugins/samplesource/rtlsdr/rtlsdrinput.cpp +++ b/plugins/samplesource/rtlsdr/rtlsdrinput.cpp @@ -372,9 +372,8 @@ bool RTLSDRInput::applySettings(const RTLSDRSettings& settings, bool force) m_settings.m_transverterMode = settings.m_transverterMode; m_settings.m_transverterDeltaFrequency = settings.m_transverterDeltaFrequency; qint64 deviceCenterFrequency = m_settings.m_centerFrequency; - deviceCenterFrequency -= m_settings.m_transverterMode ? m_settings.m_transverterDeltaFrequency : 0; - + deviceCenterFrequency = deviceCenterFrequency < 0 ? 0 : deviceCenterFrequency; qint64 f_img = deviceCenterFrequency; quint32 devSampleRate = m_settings.m_devSampleRate; @@ -398,8 +397,6 @@ bool RTLSDRInput::applySettings(const RTLSDRSettings& settings, bool force) } } - deviceCenterFrequency = deviceCenterFrequency < 0 ? 0 : deviceCenterFrequency; - if (m_dev != 0) { if (rtlsdr_set_center_freq( m_dev, deviceCenterFrequency ) != 0) From efdfc797ff5c93fa5332842b795af4fe7d041b61 Mon Sep 17 00:00:00 2001 From: f4exb Date: Mon, 25 Sep 2017 23:16:29 +0200 Subject: [PATCH 20/71] Airspy input: fixed transverter feature --- plugins/samplesource/airspy/airspyinput.cpp | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/plugins/samplesource/airspy/airspyinput.cpp b/plugins/samplesource/airspy/airspyinput.cpp index fdea8467e..02410cdbd 100644 --- a/plugins/samplesource/airspy/airspyinput.cpp +++ b/plugins/samplesource/airspy/airspyinput.cpp @@ -343,6 +343,7 @@ bool AirspyInput::applySettings(const AirspySettings& settings, bool force) m_settings.m_centerFrequency = settings.m_centerFrequency; m_settings.m_transverterMode = settings.m_transverterMode; m_settings.m_transverterDeltaFrequency = settings.m_transverterDeltaFrequency; + m_settings.m_LOppmTenths = settings.m_LOppmTenths; qint64 deviceCenterFrequency = m_settings.m_centerFrequency; deviceCenterFrequency -= m_settings.m_transverterMode ? m_settings.m_transverterDeltaFrequency : 0; @@ -350,23 +351,20 @@ bool AirspyInput::applySettings(const AirspySettings& settings, bool force) qint64 f_img = deviceCenterFrequency; quint32 devSampleRate = m_sampleRates[m_settings.m_devSampleRateIndex]; - m_settings.m_LOppmTenths = settings.m_LOppmTenths; - if ((m_settings.m_log2Decim == 0) || (settings.m_fcPos == AirspySettings::FC_POS_CENTER)) { - deviceCenterFrequency = m_settings.m_centerFrequency; f_img = deviceCenterFrequency; } else { if (settings.m_fcPos == AirspySettings::FC_POS_INFRA) { - deviceCenterFrequency = m_settings.m_centerFrequency + (devSampleRate / 4); + deviceCenterFrequency += (devSampleRate / 4); f_img = deviceCenterFrequency + devSampleRate/2; } else if (settings.m_fcPos == AirspySettings::FC_POS_SUPRA) { - deviceCenterFrequency = m_settings.m_centerFrequency - (devSampleRate / 4); + deviceCenterFrequency -= (devSampleRate / 4); f_img = deviceCenterFrequency - devSampleRate/2; } } From f270eff41d7a9d6799aacfd2ca9987ed988599d9 Mon Sep 17 00:00:00 2001 From: f4exb Date: Mon, 25 Sep 2017 23:21:02 +0200 Subject: [PATCH 21/71] Updated affected plugins versions --- debian/changelog | 3 ++- fcdlib/fcdtraits.cpp | 2 +- plugins/samplesource/airspy/airspyplugin.cpp | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/debian/changelog b/debian/changelog index 2d7388aa9..be06903b1 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,6 +1,7 @@ sdrangel (3.7.3-1) unstable; urgency=medium - * RTLSDR: Button and dialog to set frequency translation for transverter operation + * For Airspy, Funcube Pro and Pro+, PlutoSDR Rx and Tx, RTLSDR: + * Button and dialog to set frequency translation for transverter operation -- Edouard Griffiths, F4EXB Sat, 01 Oct 2017 05:14:18 +0200 diff --git a/fcdlib/fcdtraits.cpp b/fcdlib/fcdtraits.cpp index 638727513..980f9400d 100644 --- a/fcdlib/fcdtraits.cpp +++ b/fcdlib/fcdtraits.cpp @@ -23,7 +23,7 @@ const char *fcd_traits::pluginDisplayedName = "FunCube Pro Input"; const char *fcd_traits::pluginDisplayedName = "FunCube Pro+ Input"; const char *fcd_traits::pluginVersion = "3.7.3"; -const char *fcd_traits::pluginVersion = "3.5.0"; +const char *fcd_traits::pluginVersion = "3.7.3"; const int64_t fcd_traits::loLowLimitFreq = 64000000L; const int64_t fcd_traits::loLowLimitFreq = 150000L; diff --git a/plugins/samplesource/airspy/airspyplugin.cpp b/plugins/samplesource/airspy/airspyplugin.cpp index 64e097e4d..f13854a10 100644 --- a/plugins/samplesource/airspy/airspyplugin.cpp +++ b/plugins/samplesource/airspy/airspyplugin.cpp @@ -27,7 +27,7 @@ const PluginDescriptor AirspyPlugin::m_pluginDescriptor = { QString("Airspy Input"), - QString("3.5.0"), + QString("3.7.3"), QString("(c) Edouard Griffiths, F4EXB"), QString("https://github.com/f4exb/sdrangel"), true, From 0b6eb2129abe65935866f484d77ddb8f33541248 Mon Sep 17 00:00:00 2001 From: f4exb Date: Tue, 26 Sep 2017 00:22:08 +0200 Subject: [PATCH 22/71] Reset PluginInstanceGUI to its original name --- plugins/channelrx/chanalyzer/chanalyzergui.h | 4 ++-- .../channelrx/chanalyzer/chanalyzerplugin.cpp | 2 +- plugins/channelrx/chanalyzer/chanalyzerplugin.h | 2 +- plugins/channelrx/chanalyzerng/chanalyzernggui.h | 4 ++-- .../chanalyzerng/chanalyzerngplugin.cpp | 2 +- .../channelrx/chanalyzerng/chanalyzerngplugin.h | 2 +- plugins/channelrx/demodam/amdemodgui.h | 4 ++-- plugins/channelrx/demodam/amdemodplugin.cpp | 2 +- plugins/channelrx/demodam/amdemodplugin.h | 2 +- plugins/channelrx/demodatv/atvdemodgui.h | 4 ++-- plugins/channelrx/demodatv/atvdemodplugin.cpp | 2 +- plugins/channelrx/demodatv/atvdemodplugin.h | 2 +- plugins/channelrx/demodbfm/bfmdemodgui.h | 4 ++-- plugins/channelrx/demodbfm/bfmplugin.cpp | 2 +- plugins/channelrx/demodbfm/bfmplugin.h | 2 +- plugins/channelrx/demoddsd/dsddemodgui.h | 4 ++-- plugins/channelrx/demoddsd/dsddemodplugin.cpp | 2 +- plugins/channelrx/demoddsd/dsddemodplugin.h | 2 +- plugins/channelrx/demodlora/lorademodgui.h | 4 ++-- plugins/channelrx/demodlora/loraplugin.cpp | 2 +- plugins/channelrx/demodlora/loraplugin.h | 2 +- plugins/channelrx/demodnfm/nfmdemodgui.h | 4 ++-- plugins/channelrx/demodnfm/nfmplugin.cpp | 2 +- plugins/channelrx/demodnfm/nfmplugin.h | 2 +- plugins/channelrx/demodssb/ssbdemodgui.h | 4 ++-- plugins/channelrx/demodssb/ssbplugin.cpp | 2 +- plugins/channelrx/demodssb/ssbplugin.h | 2 +- plugins/channelrx/demodwfm/wfmdemodgui.h | 4 ++-- plugins/channelrx/demodwfm/wfmplugin.cpp | 2 +- plugins/channelrx/demodwfm/wfmplugin.h | 2 +- plugins/channelrx/tcpsrc/tcpsrcgui.h | 4 ++-- plugins/channelrx/tcpsrc/tcpsrcplugin.cpp | 2 +- plugins/channelrx/tcpsrc/tcpsrcplugin.h | 2 +- plugins/channelrx/udpsrc/udpsrcgui.h | 4 ++-- plugins/channelrx/udpsrc/udpsrcplugin.cpp | 2 +- plugins/channelrx/udpsrc/udpsrcplugin.h | 2 +- plugins/channeltx/modam/ammodgui.h | 4 ++-- plugins/channeltx/modam/ammodplugin.cpp | 2 +- plugins/channeltx/modam/ammodplugin.h | 2 +- plugins/channeltx/modatv/atvmodgui.h | 4 ++-- plugins/channeltx/modatv/atvmodplugin.cpp | 2 +- plugins/channeltx/modatv/atvmodplugin.h | 2 +- plugins/channeltx/modnfm/nfmmodgui.h | 4 ++-- plugins/channeltx/modnfm/nfmmodplugin.cpp | 2 +- plugins/channeltx/modnfm/nfmmodplugin.h | 2 +- plugins/channeltx/modssb/ssbmodgui.h | 4 ++-- plugins/channeltx/modssb/ssbmodplugin.cpp | 2 +- plugins/channeltx/modssb/ssbmodplugin.h | 2 +- plugins/channeltx/modwfm/wfmmodgui.h | 4 ++-- plugins/channeltx/modwfm/wfmmodplugin.cpp | 2 +- plugins/channeltx/modwfm/wfmmodplugin.h | 2 +- plugins/channeltx/udpsink/udpsinkgui.h | 4 ++-- plugins/channeltx/udpsink/udpsinkplugin.cpp | 2 +- plugins/channeltx/udpsink/udpsinkplugin.h | 2 +- .../samplesink/bladerfoutput/bladerfoutputgui.h | 4 ++-- .../bladerfoutput/bladerfoutputplugin.cpp | 2 +- .../bladerfoutput/bladerfoutputplugin.h | 2 +- plugins/samplesink/filesink/filesinkgui.h | 4 ++-- plugins/samplesink/filesink/filesinkplugin.cpp | 2 +- plugins/samplesink/filesink/filesinkplugin.h | 2 +- .../samplesink/hackrfoutput/hackrfoutputgui.h | 4 ++-- .../hackrfoutput/hackrfoutputplugin.cpp | 2 +- .../samplesink/hackrfoutput/hackrfoutputplugin.h | 2 +- .../samplesink/limesdroutput/limesdroutputgui.h | 4 ++-- .../limesdroutput/limesdroutputplugin.cpp | 2 +- .../limesdroutput/limesdroutputplugin.h | 2 +- .../plutosdroutput/plutosdroutputgui.h | 4 ++-- .../plutosdroutput/plutosdroutputplugin.cpp | 2 +- .../plutosdroutput/plutosdroutputplugin.h | 2 +- .../samplesink/sdrdaemonsink/sdrdaemonsinkgui.h | 4 ++-- .../sdrdaemonsink/sdrdaemonsinkplugin.cpp | 2 +- .../sdrdaemonsink/sdrdaemonsinkplugin.h | 2 +- plugins/samplesource/airspy/airspygui.h | 4 ++-- plugins/samplesource/airspy/airspyplugin.cpp | 2 +- plugins/samplesource/airspy/airspyplugin.h | 2 +- .../samplesource/bladerfinput/bladerfinputgui.h | 4 ++-- .../bladerfinput/bladerfinputplugin.cpp | 2 +- .../bladerfinput/bladerfinputplugin.h | 2 +- plugins/samplesource/fcdpro/fcdprogui.h | 4 ++-- plugins/samplesource/fcdpro/fcdproplugin.cpp | 2 +- plugins/samplesource/fcdpro/fcdproplugin.h | 2 +- plugins/samplesource/fcdproplus/fcdproplusgui.h | 4 ++-- .../samplesource/fcdproplus/fcdproplusplugin.cpp | 2 +- .../samplesource/fcdproplus/fcdproplusplugin.h | 2 +- plugins/samplesource/filesource/filesourcegui.h | 4 ++-- .../samplesource/filesource/filesourceplugin.cpp | 2 +- .../samplesource/filesource/filesourceplugin.h | 2 +- .../samplesource/hackrfinput/hackrfinputgui.h | 4 ++-- .../hackrfinput/hackrfinputplugin.cpp | 2 +- .../samplesource/hackrfinput/hackrfinputplugin.h | 2 +- .../samplesource/limesdrinput/limesdrinputgui.h | 4 ++-- .../limesdrinput/limesdrinputplugin.cpp | 2 +- .../limesdrinput/limesdrinputplugin.h | 2 +- .../plutosdrinput/plutosdrinputgui.h | 4 ++-- .../plutosdrinput/plutosdrinputplugin.cpp | 2 +- .../plutosdrinput/plutosdrinputplugin.h | 2 +- plugins/samplesource/rtlsdr/rtlsdrgui.h | 4 ++-- plugins/samplesource/rtlsdr/rtlsdrplugin.cpp | 2 +- plugins/samplesource/rtlsdr/rtlsdrplugin.h | 2 +- .../sdrdaemonsource/sdrdaemonsourcegui.h | 4 ++-- .../sdrdaemonsource/sdrdaemonsourceplugin.cpp | 2 +- .../sdrdaemonsource/sdrdaemonsourceplugin.h | 2 +- plugins/samplesource/sdrplay/sdrplaygui.h | 4 ++-- plugins/samplesource/sdrplay/sdrplayplugin.cpp | 2 +- plugins/samplesource/sdrplay/sdrplayplugin.h | 2 +- sdrbase/device/devicesinkapi.cpp | 8 ++++---- sdrbase/device/devicesinkapi.h | 16 ++++++++-------- sdrbase/device/devicesourceapi.cpp | 8 ++++---- sdrbase/device/devicesourceapi.h | 16 ++++++++-------- sdrbase/mainwindow.cpp | 14 +++++++------- sdrbase/mainwindow.h | 2 +- sdrbase/plugin/pluginapi.h | 2 +- .../{plugininstanceui.h => plugininstancegui.h} | 6 +++--- sdrbase/plugin/plugininterface.cpp | 6 +++--- sdrbase/plugin/plugininterface.h | 14 +++++++------- sdrbase/plugin/pluginmanager.cpp | 2 +- 116 files changed, 187 insertions(+), 187 deletions(-) rename sdrbase/plugin/{plugininstanceui.h => plugininstancegui.h} (87%) diff --git a/plugins/channelrx/chanalyzer/chanalyzergui.h b/plugins/channelrx/chanalyzer/chanalyzergui.h index 24b352dba..36d00b8ce 100644 --- a/plugins/channelrx/chanalyzer/chanalyzergui.h +++ b/plugins/channelrx/chanalyzer/chanalyzergui.h @@ -17,10 +17,10 @@ #ifndef INCLUDE_CHANNELANALYZERGUI_H #define INCLUDE_CHANNELANALYZERGUI_H +#include #include "gui/rollupwidget.h" #include "dsp/channelmarker.h" #include "dsp/movingaverage.h" -#include "plugin/plugininstanceui.h" #include "util/messagequeue.h" class PluginAPI; @@ -37,7 +37,7 @@ namespace Ui { class ChannelAnalyzerGUI; } -class ChannelAnalyzerGUI : public RollupWidget, public PluginInstanceUI { +class ChannelAnalyzerGUI : public RollupWidget, public PluginInstanceGUI { Q_OBJECT public: diff --git a/plugins/channelrx/chanalyzer/chanalyzerplugin.cpp b/plugins/channelrx/chanalyzer/chanalyzerplugin.cpp index da6b09167..428ccd78c 100644 --- a/plugins/channelrx/chanalyzer/chanalyzerplugin.cpp +++ b/plugins/channelrx/chanalyzer/chanalyzerplugin.cpp @@ -33,7 +33,7 @@ void ChannelAnalyzerPlugin::initPlugin(PluginAPI* pluginAPI) m_pluginAPI->registerRxChannel(ChannelAnalyzerGUI::m_channelID, this); } -PluginInstanceUI* ChannelAnalyzerPlugin::createRxChannel(const QString& channelName, DeviceSourceAPI *deviceAPI) +PluginInstanceGUI* ChannelAnalyzerPlugin::createRxChannel(const QString& channelName, DeviceSourceAPI *deviceAPI) { if(channelName == ChannelAnalyzerGUI::m_channelID) { diff --git a/plugins/channelrx/chanalyzer/chanalyzerplugin.h b/plugins/channelrx/chanalyzer/chanalyzerplugin.h index 02ad6ddaa..aa42c8edb 100644 --- a/plugins/channelrx/chanalyzer/chanalyzerplugin.h +++ b/plugins/channelrx/chanalyzer/chanalyzerplugin.h @@ -17,7 +17,7 @@ public: const PluginDescriptor& getPluginDescriptor() const; void initPlugin(PluginAPI* pluginAPI); - PluginInstanceUI* createRxChannel(const QString& channelName, DeviceSourceAPI *deviceAPI); + PluginInstanceGUI* createRxChannel(const QString& channelName, DeviceSourceAPI *deviceAPI); private: static const PluginDescriptor m_pluginDescriptor; diff --git a/plugins/channelrx/chanalyzerng/chanalyzernggui.h b/plugins/channelrx/chanalyzerng/chanalyzernggui.h index d9797c0d1..1fc764357 100644 --- a/plugins/channelrx/chanalyzerng/chanalyzernggui.h +++ b/plugins/channelrx/chanalyzerng/chanalyzernggui.h @@ -17,10 +17,10 @@ #ifndef INCLUDE_CHANNELANALYZERNGGUI_H #define INCLUDE_CHANNELANALYZERNGGUI_H +#include #include "gui/rollupwidget.h" #include "dsp/channelmarker.h" #include "dsp/movingaverage.h" -#include "plugin/plugininstanceui.h" #include "util/messagequeue.h" class PluginAPI; @@ -37,7 +37,7 @@ namespace Ui { class ChannelAnalyzerNGGUI; } -class ChannelAnalyzerNGGUI : public RollupWidget, public PluginInstanceUI { +class ChannelAnalyzerNGGUI : public RollupWidget, public PluginInstanceGUI { Q_OBJECT public: diff --git a/plugins/channelrx/chanalyzerng/chanalyzerngplugin.cpp b/plugins/channelrx/chanalyzerng/chanalyzerngplugin.cpp index d6ad4176c..1ddff0440 100644 --- a/plugins/channelrx/chanalyzerng/chanalyzerngplugin.cpp +++ b/plugins/channelrx/chanalyzerng/chanalyzerngplugin.cpp @@ -48,7 +48,7 @@ void ChannelAnalyzerNGPlugin::initPlugin(PluginAPI* pluginAPI) m_pluginAPI->registerRxChannel(ChannelAnalyzerNGGUI::m_channelID, this); } -PluginInstanceUI* ChannelAnalyzerNGPlugin::createRxChannel(const QString& channelName, DeviceSourceAPI *deviceAPI) +PluginInstanceGUI* ChannelAnalyzerNGPlugin::createRxChannel(const QString& channelName, DeviceSourceAPI *deviceAPI) { if(channelName == ChannelAnalyzerNGGUI::m_channelID) { diff --git a/plugins/channelrx/chanalyzerng/chanalyzerngplugin.h b/plugins/channelrx/chanalyzerng/chanalyzerngplugin.h index c3536677e..2f4597254 100644 --- a/plugins/channelrx/chanalyzerng/chanalyzerngplugin.h +++ b/plugins/channelrx/chanalyzerng/chanalyzerngplugin.h @@ -34,7 +34,7 @@ public: const PluginDescriptor& getPluginDescriptor() const; void initPlugin(PluginAPI* pluginAPI); - PluginInstanceUI* createRxChannel(const QString& channelName, DeviceSourceAPI *deviceAPI); + PluginInstanceGUI* createRxChannel(const QString& channelName, DeviceSourceAPI *deviceAPI); private: static const PluginDescriptor m_pluginDescriptor; diff --git a/plugins/channelrx/demodam/amdemodgui.h b/plugins/channelrx/demodam/amdemodgui.h index 1133d8bf4..de9c20d6e 100644 --- a/plugins/channelrx/demodam/amdemodgui.h +++ b/plugins/channelrx/demodam/amdemodgui.h @@ -1,10 +1,10 @@ #ifndef INCLUDE_AMDEMODGUI_H #define INCLUDE_AMDEMODGUI_H +#include #include "gui/rollupwidget.h" #include "dsp/channelmarker.h" #include "dsp/movingaverage.h" -#include "plugin/plugininstanceui.h" #include "util/messagequeue.h" class PluginAPI; @@ -18,7 +18,7 @@ namespace Ui { class AMDemodGUI; } -class AMDemodGUI : public RollupWidget, public PluginInstanceUI { +class AMDemodGUI : public RollupWidget, public PluginInstanceGUI { Q_OBJECT public: diff --git a/plugins/channelrx/demodam/amdemodplugin.cpp b/plugins/channelrx/demodam/amdemodplugin.cpp index 1384d25d1..265bd921b 100644 --- a/plugins/channelrx/demodam/amdemodplugin.cpp +++ b/plugins/channelrx/demodam/amdemodplugin.cpp @@ -33,7 +33,7 @@ void AMDemodPlugin::initPlugin(PluginAPI* pluginAPI) m_pluginAPI->registerRxChannel(AMDemodGUI::m_channelID, this); } -PluginInstanceUI* AMDemodPlugin::createRxChannel(const QString& channelName, DeviceSourceAPI *deviceAPI) +PluginInstanceGUI* AMDemodPlugin::createRxChannel(const QString& channelName, DeviceSourceAPI *deviceAPI) { if(channelName == AMDemodGUI::m_channelID) { diff --git a/plugins/channelrx/demodam/amdemodplugin.h b/plugins/channelrx/demodam/amdemodplugin.h index adc15d026..903c6d7c4 100644 --- a/plugins/channelrx/demodam/amdemodplugin.h +++ b/plugins/channelrx/demodam/amdemodplugin.h @@ -33,7 +33,7 @@ public: const PluginDescriptor& getPluginDescriptor() const; void initPlugin(PluginAPI* pluginAPI); - PluginInstanceUI* createRxChannel(const QString& channelName, DeviceSourceAPI *deviceAPI); + PluginInstanceGUI* createRxChannel(const QString& channelName, DeviceSourceAPI *deviceAPI); private: static const PluginDescriptor m_pluginDescriptor; diff --git a/plugins/channelrx/demodatv/atvdemodgui.h b/plugins/channelrx/demodatv/atvdemodgui.h index 720a5f19f..7f6764acc 100644 --- a/plugins/channelrx/demodatv/atvdemodgui.h +++ b/plugins/channelrx/demodatv/atvdemodgui.h @@ -18,10 +18,10 @@ #ifndef INCLUDE_ATVDEMODGUI_H #define INCLUDE_ATVDEMODGUI_H +#include #include "gui/rollupwidget.h" #include "dsp/channelmarker.h" #include "dsp/movingaverage.h" -#include "plugin/plugininstanceui.h" #include "util/messagequeue.h" class PluginAPI; @@ -37,7 +37,7 @@ namespace Ui class ATVDemodGUI; } -class ATVDemodGUI : public RollupWidget, public PluginInstanceUI +class ATVDemodGUI : public RollupWidget, public PluginInstanceGUI { Q_OBJECT diff --git a/plugins/channelrx/demodatv/atvdemodplugin.cpp b/plugins/channelrx/demodatv/atvdemodplugin.cpp index 8aecf1499..c42bb89d4 100644 --- a/plugins/channelrx/demodatv/atvdemodplugin.cpp +++ b/plugins/channelrx/demodatv/atvdemodplugin.cpp @@ -53,7 +53,7 @@ void ATVDemodPlugin::initPlugin(PluginAPI* ptrPluginAPI) m_ptrPluginAPI->registerRxChannel(ATVDemodGUI::m_strChannelID, this); } -PluginInstanceUI* ATVDemodPlugin::createRxChannel(const QString& strChannelName, DeviceSourceAPI *ptrDeviceAPI) +PluginInstanceGUI* ATVDemodPlugin::createRxChannel(const QString& strChannelName, DeviceSourceAPI *ptrDeviceAPI) { if(strChannelName == ATVDemodGUI::m_strChannelID) { diff --git a/plugins/channelrx/demodatv/atvdemodplugin.h b/plugins/channelrx/demodatv/atvdemodplugin.h index e26d77610..93f0e11d5 100644 --- a/plugins/channelrx/demodatv/atvdemodplugin.h +++ b/plugins/channelrx/demodatv/atvdemodplugin.h @@ -35,7 +35,7 @@ public: const PluginDescriptor& getPluginDescriptor() const; void initPlugin(PluginAPI* ptrPluginAPI); - PluginInstanceUI* createRxChannel(const QString& strChannelName, DeviceSourceAPI *ptrDeviceAPI); + PluginInstanceGUI* createRxChannel(const QString& strChannelName, DeviceSourceAPI *ptrDeviceAPI); private: static const PluginDescriptor m_ptrPluginDescriptor; diff --git a/plugins/channelrx/demodbfm/bfmdemodgui.h b/plugins/channelrx/demodbfm/bfmdemodgui.h index cf3c2d875..126d80e6d 100644 --- a/plugins/channelrx/demodbfm/bfmdemodgui.h +++ b/plugins/channelrx/demodbfm/bfmdemodgui.h @@ -18,10 +18,10 @@ #ifndef INCLUDE_BFMDEMODGUI_H #define INCLUDE_BFMDEMODGUI_H +#include #include "gui/rollupwidget.h" #include "dsp/channelmarker.h" #include "dsp/movingaverage.h" -#include "plugin/plugininstanceui.h" #include "util/messagequeue.h" #include "rdsparser.h" @@ -38,7 +38,7 @@ namespace Ui { class BFMDemodGUI; } -class BFMDemodGUI : public RollupWidget, public PluginInstanceUI { +class BFMDemodGUI : public RollupWidget, public PluginInstanceGUI { Q_OBJECT public: diff --git a/plugins/channelrx/demodbfm/bfmplugin.cpp b/plugins/channelrx/demodbfm/bfmplugin.cpp index 6eb20bfd3..153984c0c 100644 --- a/plugins/channelrx/demodbfm/bfmplugin.cpp +++ b/plugins/channelrx/demodbfm/bfmplugin.cpp @@ -50,7 +50,7 @@ void BFMPlugin::initPlugin(PluginAPI* pluginAPI) m_pluginAPI->registerRxChannel(BFMDemodGUI::m_channelID, this); } -PluginInstanceUI* BFMPlugin::createRxChannel(const QString& channelName, DeviceSourceAPI *deviceAPI) +PluginInstanceGUI* BFMPlugin::createRxChannel(const QString& channelName, DeviceSourceAPI *deviceAPI) { if(channelName == BFMDemodGUI::m_channelID) { diff --git a/plugins/channelrx/demodbfm/bfmplugin.h b/plugins/channelrx/demodbfm/bfmplugin.h index 0b5fdb8e7..6879eb197 100644 --- a/plugins/channelrx/demodbfm/bfmplugin.h +++ b/plugins/channelrx/demodbfm/bfmplugin.h @@ -34,7 +34,7 @@ public: const PluginDescriptor& getPluginDescriptor() const; void initPlugin(PluginAPI* pluginAPI); - PluginInstanceUI* createRxChannel(const QString& channelName, DeviceSourceAPI *deviceAPI); + PluginInstanceGUI* createRxChannel(const QString& channelName, DeviceSourceAPI *deviceAPI); private: static const PluginDescriptor m_pluginDescriptor; diff --git a/plugins/channelrx/demoddsd/dsddemodgui.h b/plugins/channelrx/demoddsd/dsddemodgui.h index 390a835ed..0b36ae0ad 100644 --- a/plugins/channelrx/demoddsd/dsddemodgui.h +++ b/plugins/channelrx/demoddsd/dsddemodgui.h @@ -18,13 +18,13 @@ #ifndef INCLUDE_DSDDEMODGUI_H #define INCLUDE_DSDDEMODGUI_H +#include #include #include "gui/rollupwidget.h" #include "dsp/dsptypes.h" #include "dsp/channelmarker.h" #include "dsp/movingaverage.h" -#include "plugin/plugininstanceui.h" #include "util/messagequeue.h" class PluginAPI; @@ -39,7 +39,7 @@ namespace Ui { class DSDDemodGUI; } -class DSDDemodGUI : public RollupWidget, public PluginInstanceUI { +class DSDDemodGUI : public RollupWidget, public PluginInstanceGUI { Q_OBJECT public: diff --git a/plugins/channelrx/demoddsd/dsddemodplugin.cpp b/plugins/channelrx/demoddsd/dsddemodplugin.cpp index a3d1c9c4b..f6a84a23f 100644 --- a/plugins/channelrx/demoddsd/dsddemodplugin.cpp +++ b/plugins/channelrx/demoddsd/dsddemodplugin.cpp @@ -50,7 +50,7 @@ void DSDDemodPlugin::initPlugin(PluginAPI* pluginAPI) m_pluginAPI->registerRxChannel(DSDDemodGUI::m_channelID, this); } -PluginInstanceUI* DSDDemodPlugin::createRxChannel(const QString& channelName, DeviceSourceAPI *deviceAPI) +PluginInstanceGUI* DSDDemodPlugin::createRxChannel(const QString& channelName, DeviceSourceAPI *deviceAPI) { if(channelName == DSDDemodGUI::m_channelID) { diff --git a/plugins/channelrx/demoddsd/dsddemodplugin.h b/plugins/channelrx/demoddsd/dsddemodplugin.h index 835a85508..ee80b5033 100644 --- a/plugins/channelrx/demoddsd/dsddemodplugin.h +++ b/plugins/channelrx/demoddsd/dsddemodplugin.h @@ -34,7 +34,7 @@ public: const PluginDescriptor& getPluginDescriptor() const; void initPlugin(PluginAPI* pluginAPI); - PluginInstanceUI* createRxChannel(const QString& channelName, DeviceSourceAPI *deviceAPI); + PluginInstanceGUI* createRxChannel(const QString& channelName, DeviceSourceAPI *deviceAPI); private: static const PluginDescriptor m_pluginDescriptor; diff --git a/plugins/channelrx/demodlora/lorademodgui.h b/plugins/channelrx/demodlora/lorademodgui.h index 43884380c..a48c4e221 100644 --- a/plugins/channelrx/demodlora/lorademodgui.h +++ b/plugins/channelrx/demodlora/lorademodgui.h @@ -1,9 +1,9 @@ #ifndef INCLUDE_LoRaDEMODGUI_H #define INCLUDE_LoRaDEMODGUI_H +#include #include "gui/rollupwidget.h" #include "dsp/channelmarker.h" -#include "plugin/plugininstanceui.h" #include "util/messagequeue.h" #define BANDWIDTHSTRING {7813,15625,20833,31250,62500} @@ -19,7 +19,7 @@ namespace Ui { class LoRaDemodGUI; } -class LoRaDemodGUI : public RollupWidget, public PluginInstanceUI { +class LoRaDemodGUI : public RollupWidget, public PluginInstanceGUI { Q_OBJECT public: diff --git a/plugins/channelrx/demodlora/loraplugin.cpp b/plugins/channelrx/demodlora/loraplugin.cpp index 2f93c2ffb..0d877a716 100644 --- a/plugins/channelrx/demodlora/loraplugin.cpp +++ b/plugins/channelrx/demodlora/loraplugin.cpp @@ -33,7 +33,7 @@ void LoRaPlugin::initPlugin(PluginAPI* pluginAPI) m_pluginAPI->registerRxChannel(LoRaDemodGUI::m_channelID, this); } -PluginInstanceUI* LoRaPlugin::createRxChannel(const QString& channelName, DeviceSourceAPI *deviceAPI) +PluginInstanceGUI* LoRaPlugin::createRxChannel(const QString& channelName, DeviceSourceAPI *deviceAPI) { if(channelName == LoRaDemodGUI::m_channelID) { diff --git a/plugins/channelrx/demodlora/loraplugin.h b/plugins/channelrx/demodlora/loraplugin.h index 5fa25822d..412419c10 100644 --- a/plugins/channelrx/demodlora/loraplugin.h +++ b/plugins/channelrx/demodlora/loraplugin.h @@ -17,7 +17,7 @@ public: const PluginDescriptor& getPluginDescriptor() const; void initPlugin(PluginAPI* pluginAPI); - PluginInstanceUI* createRxChannel(const QString& channelName, DeviceSourceAPI *deviceAPI); + PluginInstanceGUI* createRxChannel(const QString& channelName, DeviceSourceAPI *deviceAPI); private: static const PluginDescriptor m_pluginDescriptor; diff --git a/plugins/channelrx/demodnfm/nfmdemodgui.h b/plugins/channelrx/demodnfm/nfmdemodgui.h index e986b143b..7b8cbd5f5 100644 --- a/plugins/channelrx/demodnfm/nfmdemodgui.h +++ b/plugins/channelrx/demodnfm/nfmdemodgui.h @@ -1,11 +1,11 @@ #ifndef INCLUDE_NFMDEMODGUI_H #define INCLUDE_NFMDEMODGUI_H +#include #include "gui/rollupwidget.h" #include "dsp/dsptypes.h" #include "dsp/channelmarker.h" #include "dsp/movingaverage.h" -#include "plugin/plugininstanceui.h" #include "util/messagequeue.h" class PluginAPI; @@ -19,7 +19,7 @@ namespace Ui { class NFMDemodGUI; } -class NFMDemodGUI : public RollupWidget, public PluginInstanceUI { +class NFMDemodGUI : public RollupWidget, public PluginInstanceGUI { Q_OBJECT public: diff --git a/plugins/channelrx/demodnfm/nfmplugin.cpp b/plugins/channelrx/demodnfm/nfmplugin.cpp index f0f218f1b..c66b64a14 100644 --- a/plugins/channelrx/demodnfm/nfmplugin.cpp +++ b/plugins/channelrx/demodnfm/nfmplugin.cpp @@ -33,7 +33,7 @@ void NFMPlugin::initPlugin(PluginAPI* pluginAPI) m_pluginAPI->registerRxChannel(NFMDemodGUI::m_channelID, this); } -PluginInstanceUI* NFMPlugin::createRxChannel(const QString& channelName, DeviceSourceAPI *deviceAPI) +PluginInstanceGUI* NFMPlugin::createRxChannel(const QString& channelName, DeviceSourceAPI *deviceAPI) { if(channelName == NFMDemodGUI::m_channelID) { NFMDemodGUI* gui = NFMDemodGUI::create(m_pluginAPI, deviceAPI); diff --git a/plugins/channelrx/demodnfm/nfmplugin.h b/plugins/channelrx/demodnfm/nfmplugin.h index ff2e822ce..10eb6b131 100644 --- a/plugins/channelrx/demodnfm/nfmplugin.h +++ b/plugins/channelrx/demodnfm/nfmplugin.h @@ -17,7 +17,7 @@ public: const PluginDescriptor& getPluginDescriptor() const; void initPlugin(PluginAPI* pluginAPI); - PluginInstanceUI* createRxChannel(const QString& channelName, DeviceSourceAPI *deviceAPI); + PluginInstanceGUI* createRxChannel(const QString& channelName, DeviceSourceAPI *deviceAPI); private: static const PluginDescriptor m_pluginDescriptor; diff --git a/plugins/channelrx/demodssb/ssbdemodgui.h b/plugins/channelrx/demodssb/ssbdemodgui.h index 0be23c5be..e59bf74c2 100644 --- a/plugins/channelrx/demodssb/ssbdemodgui.h +++ b/plugins/channelrx/demodssb/ssbdemodgui.h @@ -1,10 +1,10 @@ #ifndef INCLUDE_SSBDEMODGUI_H #define INCLUDE_SSBDEMODGUI_H +#include #include "gui/rollupwidget.h" #include "dsp/channelmarker.h" #include "dsp/movingaverage.h" -#include "plugin/plugininstanceui.h" #include "util/messagequeue.h" class PluginAPI; @@ -20,7 +20,7 @@ namespace Ui { class SSBDemodGUI; } -class SSBDemodGUI : public RollupWidget, public PluginInstanceUI { +class SSBDemodGUI : public RollupWidget, public PluginInstanceGUI { Q_OBJECT public: diff --git a/plugins/channelrx/demodssb/ssbplugin.cpp b/plugins/channelrx/demodssb/ssbplugin.cpp index a7931ccee..1b9218a23 100644 --- a/plugins/channelrx/demodssb/ssbplugin.cpp +++ b/plugins/channelrx/demodssb/ssbplugin.cpp @@ -33,7 +33,7 @@ void SSBPlugin::initPlugin(PluginAPI* pluginAPI) m_pluginAPI->registerRxChannel(SSBDemodGUI::m_channelID, this); } -PluginInstanceUI* SSBPlugin::createRxChannel(const QString& channelName, DeviceSourceAPI *deviceAPI) +PluginInstanceGUI* SSBPlugin::createRxChannel(const QString& channelName, DeviceSourceAPI *deviceAPI) { if(channelName == SSBDemodGUI::m_channelID) { diff --git a/plugins/channelrx/demodssb/ssbplugin.h b/plugins/channelrx/demodssb/ssbplugin.h index 5901a3671..e87d6c03e 100644 --- a/plugins/channelrx/demodssb/ssbplugin.h +++ b/plugins/channelrx/demodssb/ssbplugin.h @@ -17,7 +17,7 @@ public: const PluginDescriptor& getPluginDescriptor() const; void initPlugin(PluginAPI* pluginAPI); - PluginInstanceUI* createRxChannel(const QString& channelName, DeviceSourceAPI *deviceAPI); + PluginInstanceGUI* createRxChannel(const QString& channelName, DeviceSourceAPI *deviceAPI); private: static const PluginDescriptor m_pluginDescriptor; diff --git a/plugins/channelrx/demodwfm/wfmdemodgui.h b/plugins/channelrx/demodwfm/wfmdemodgui.h index 630fdc1cc..b322d702f 100644 --- a/plugins/channelrx/demodwfm/wfmdemodgui.h +++ b/plugins/channelrx/demodwfm/wfmdemodgui.h @@ -1,10 +1,10 @@ #ifndef INCLUDE_WFMDEMODGUI_H #define INCLUDE_WFMDEMODGUI_H +#include #include "gui/rollupwidget.h" #include "dsp/channelmarker.h" #include "dsp/movingaverage.h" -#include "plugin/plugininstanceui.h" #include "util/messagequeue.h" class PluginAPI; @@ -18,7 +18,7 @@ namespace Ui { class WFMDemodGUI; } -class WFMDemodGUI : public RollupWidget, public PluginInstanceUI { +class WFMDemodGUI : public RollupWidget, public PluginInstanceGUI { Q_OBJECT public: diff --git a/plugins/channelrx/demodwfm/wfmplugin.cpp b/plugins/channelrx/demodwfm/wfmplugin.cpp index bb620ff0f..9cf3fe06f 100644 --- a/plugins/channelrx/demodwfm/wfmplugin.cpp +++ b/plugins/channelrx/demodwfm/wfmplugin.cpp @@ -33,7 +33,7 @@ void WFMPlugin::initPlugin(PluginAPI* pluginAPI) m_pluginAPI->registerRxChannel(WFMDemodGUI::m_channelID, this); } -PluginInstanceUI* WFMPlugin::createRxChannel(const QString& channelName, DeviceSourceAPI *deviceAPI) +PluginInstanceGUI* WFMPlugin::createRxChannel(const QString& channelName, DeviceSourceAPI *deviceAPI) { if(channelName == WFMDemodGUI::m_channelID) { diff --git a/plugins/channelrx/demodwfm/wfmplugin.h b/plugins/channelrx/demodwfm/wfmplugin.h index 84a06fe18..51cfc52ef 100644 --- a/plugins/channelrx/demodwfm/wfmplugin.h +++ b/plugins/channelrx/demodwfm/wfmplugin.h @@ -17,7 +17,7 @@ public: const PluginDescriptor& getPluginDescriptor() const; void initPlugin(PluginAPI* pluginAPI); - PluginInstanceUI* createRxChannel(const QString& channelName, DeviceSourceAPI *deviceAPI); + PluginInstanceGUI* createRxChannel(const QString& channelName, DeviceSourceAPI *deviceAPI); private: static const PluginDescriptor m_pluginDescriptor; diff --git a/plugins/channelrx/tcpsrc/tcpsrcgui.h b/plugins/channelrx/tcpsrc/tcpsrcgui.h index 5986380ef..01e431374 100644 --- a/plugins/channelrx/tcpsrc/tcpsrcgui.h +++ b/plugins/channelrx/tcpsrc/tcpsrcgui.h @@ -1,12 +1,12 @@ #ifndef INCLUDE_TCPSRCGUI_H #define INCLUDE_TCPSRCGUI_H +#include #include #include "gui/rollupwidget.h" #include "dsp/channelmarker.h" #include "dsp/movingaverage.h" -#include "plugin/plugininstanceui.h" #include "util/messagequeue.h" #include "tcpsrc.h" @@ -22,7 +22,7 @@ namespace Ui { class TCPSrcGUI; } -class TCPSrcGUI : public RollupWidget, public PluginInstanceUI { +class TCPSrcGUI : public RollupWidget, public PluginInstanceGUI { Q_OBJECT public: diff --git a/plugins/channelrx/tcpsrc/tcpsrcplugin.cpp b/plugins/channelrx/tcpsrc/tcpsrcplugin.cpp index 8c5d2b6fe..fc80ff9d0 100644 --- a/plugins/channelrx/tcpsrc/tcpsrcplugin.cpp +++ b/plugins/channelrx/tcpsrc/tcpsrcplugin.cpp @@ -33,7 +33,7 @@ void TCPSrcPlugin::initPlugin(PluginAPI* pluginAPI) m_pluginAPI->registerRxChannel(TCPSrcGUI::m_channelID, this); } -PluginInstanceUI* TCPSrcPlugin::createRxChannel(const QString& channelName, DeviceSourceAPI *deviceAPI) +PluginInstanceGUI* TCPSrcPlugin::createRxChannel(const QString& channelName, DeviceSourceAPI *deviceAPI) { if(channelName == TCPSrcGUI::m_channelID) { diff --git a/plugins/channelrx/tcpsrc/tcpsrcplugin.h b/plugins/channelrx/tcpsrc/tcpsrcplugin.h index 19224b73a..a48356ba4 100644 --- a/plugins/channelrx/tcpsrc/tcpsrcplugin.h +++ b/plugins/channelrx/tcpsrc/tcpsrcplugin.h @@ -17,7 +17,7 @@ public: const PluginDescriptor& getPluginDescriptor() const; void initPlugin(PluginAPI* pluginAPI); - PluginInstanceUI* createRxChannel(const QString& channelName, DeviceSourceAPI *deviceAPI); + PluginInstanceGUI* createRxChannel(const QString& channelName, DeviceSourceAPI *deviceAPI); private: static const PluginDescriptor m_pluginDescriptor; diff --git a/plugins/channelrx/udpsrc/udpsrcgui.h b/plugins/channelrx/udpsrc/udpsrcgui.h index 2c3973091..55e51243c 100644 --- a/plugins/channelrx/udpsrc/udpsrcgui.h +++ b/plugins/channelrx/udpsrc/udpsrcgui.h @@ -18,11 +18,11 @@ #ifndef INCLUDE_UDPSRCGUI_H #define INCLUDE_UDPSRCGUI_H +#include #include #include "gui/rollupwidget.h" #include "dsp/channelmarker.h" #include "dsp/movingaverage.h" -#include "plugin/plugininstanceui.h" #include "util/messagequeue.h" #include "udpsrc.h" @@ -38,7 +38,7 @@ namespace Ui { class UDPSrcGUI; } -class UDPSrcGUI : public RollupWidget, public PluginInstanceUI { +class UDPSrcGUI : public RollupWidget, public PluginInstanceGUI { Q_OBJECT public: diff --git a/plugins/channelrx/udpsrc/udpsrcplugin.cpp b/plugins/channelrx/udpsrc/udpsrcplugin.cpp index 1940602f5..f8b5f0cbe 100644 --- a/plugins/channelrx/udpsrc/udpsrcplugin.cpp +++ b/plugins/channelrx/udpsrc/udpsrcplugin.cpp @@ -50,7 +50,7 @@ void UDPSrcPlugin::initPlugin(PluginAPI* pluginAPI) m_pluginAPI->registerRxChannel(UDPSrcGUI::m_channelID, this); } -PluginInstanceUI* UDPSrcPlugin::createRxChannel(const QString& channelName, DeviceSourceAPI *deviceAPI) +PluginInstanceGUI* UDPSrcPlugin::createRxChannel(const QString& channelName, DeviceSourceAPI *deviceAPI) { if(channelName == UDPSrcGUI::m_channelID) { diff --git a/plugins/channelrx/udpsrc/udpsrcplugin.h b/plugins/channelrx/udpsrc/udpsrcplugin.h index 39707665b..798ecbd9c 100644 --- a/plugins/channelrx/udpsrc/udpsrcplugin.h +++ b/plugins/channelrx/udpsrc/udpsrcplugin.h @@ -34,7 +34,7 @@ public: const PluginDescriptor& getPluginDescriptor() const; void initPlugin(PluginAPI* pluginAPI); - PluginInstanceUI* createRxChannel(const QString& channelName, DeviceSourceAPI *deviceAPI); + PluginInstanceGUI* createRxChannel(const QString& channelName, DeviceSourceAPI *deviceAPI); private: static const PluginDescriptor m_pluginDescriptor; diff --git a/plugins/channeltx/modam/ammodgui.h b/plugins/channeltx/modam/ammodgui.h index 6c2c523c2..25ca8e315 100644 --- a/plugins/channeltx/modam/ammodgui.h +++ b/plugins/channeltx/modam/ammodgui.h @@ -17,10 +17,10 @@ #ifndef PLUGINS_CHANNELTX_MODAM_AMMODGUI_H_ #define PLUGINS_CHANNELTX_MODAM_AMMODGUI_H_ +#include #include "gui/rollupwidget.h" #include "dsp/channelmarker.h" #include "dsp/movingaverage.h" -#include "plugin/plugininstanceui.h" #include "util/messagequeue.h" #include "ammod.h" @@ -36,7 +36,7 @@ namespace Ui { class AMModGUI; } -class AMModGUI : public RollupWidget, public PluginInstanceUI { +class AMModGUI : public RollupWidget, public PluginInstanceGUI { Q_OBJECT public: diff --git a/plugins/channeltx/modam/ammodplugin.cpp b/plugins/channeltx/modam/ammodplugin.cpp index 96b269ed8..2846d34c6 100644 --- a/plugins/channeltx/modam/ammodplugin.cpp +++ b/plugins/channeltx/modam/ammodplugin.cpp @@ -49,7 +49,7 @@ void AMModPlugin::initPlugin(PluginAPI* pluginAPI) m_pluginAPI->registerTxChannel(AMModGUI::m_channelID, this); } -PluginInstanceUI* AMModPlugin::createTxChannel(const QString& channelName, DeviceSinkAPI *deviceAPI) +PluginInstanceGUI* AMModPlugin::createTxChannel(const QString& channelName, DeviceSinkAPI *deviceAPI) { if(channelName == AMModGUI::m_channelID) { diff --git a/plugins/channeltx/modam/ammodplugin.h b/plugins/channeltx/modam/ammodplugin.h index 9a87c0012..ce74622b7 100644 --- a/plugins/channeltx/modam/ammodplugin.h +++ b/plugins/channeltx/modam/ammodplugin.h @@ -33,7 +33,7 @@ public: const PluginDescriptor& getPluginDescriptor() const; void initPlugin(PluginAPI* pluginAPI); - PluginInstanceUI* createTxChannel(const QString& channelName, DeviceSinkAPI *deviceAPI); + PluginInstanceGUI* createTxChannel(const QString& channelName, DeviceSinkAPI *deviceAPI); private: static const PluginDescriptor m_pluginDescriptor; diff --git a/plugins/channeltx/modatv/atvmodgui.h b/plugins/channeltx/modatv/atvmodgui.h index 66cd4c38d..febd1730e 100644 --- a/plugins/channeltx/modatv/atvmodgui.h +++ b/plugins/channeltx/modatv/atvmodgui.h @@ -17,10 +17,10 @@ #ifndef PLUGINS_CHANNELTX_MODTV_ATVMODGUI_H_ #define PLUGINS_CHANNELTX_MODTV_ATVMODGUI_H_ +#include #include "gui/rollupwidget.h" #include "dsp/channelmarker.h" #include "dsp/movingaverage.h" -#include "plugin/plugininstanceui.h" #include "util/messagequeue.h" #include "atvmod.h" @@ -37,7 +37,7 @@ namespace Ui { class ATVModGUI; } -class ATVModGUI : public RollupWidget, public PluginInstanceUI { +class ATVModGUI : public RollupWidget, public PluginInstanceGUI { Q_OBJECT public: diff --git a/plugins/channeltx/modatv/atvmodplugin.cpp b/plugins/channeltx/modatv/atvmodplugin.cpp index 5e5e4156e..33482b2c0 100644 --- a/plugins/channeltx/modatv/atvmodplugin.cpp +++ b/plugins/channeltx/modatv/atvmodplugin.cpp @@ -49,7 +49,7 @@ void ATVModPlugin::initPlugin(PluginAPI* pluginAPI) m_pluginAPI->registerTxChannel(ATVModGUI::m_channelID, this); } -PluginInstanceUI* ATVModPlugin::createTxChannel(const QString& channelName, DeviceSinkAPI *deviceAPI) +PluginInstanceGUI* ATVModPlugin::createTxChannel(const QString& channelName, DeviceSinkAPI *deviceAPI) { if(channelName == ATVModGUI::m_channelID) { diff --git a/plugins/channeltx/modatv/atvmodplugin.h b/plugins/channeltx/modatv/atvmodplugin.h index de2c6ec57..6061dbd26 100644 --- a/plugins/channeltx/modatv/atvmodplugin.h +++ b/plugins/channeltx/modatv/atvmodplugin.h @@ -33,7 +33,7 @@ public: const PluginDescriptor& getPluginDescriptor() const; void initPlugin(PluginAPI* pluginAPI); - PluginInstanceUI* createTxChannel(const QString& channelName, DeviceSinkAPI *deviceAPI); + PluginInstanceGUI* createTxChannel(const QString& channelName, DeviceSinkAPI *deviceAPI); private: static const PluginDescriptor m_pluginDescriptor; diff --git a/plugins/channeltx/modnfm/nfmmodgui.h b/plugins/channeltx/modnfm/nfmmodgui.h index 8e9759e50..7cb026320 100644 --- a/plugins/channeltx/modnfm/nfmmodgui.h +++ b/plugins/channeltx/modnfm/nfmmodgui.h @@ -17,10 +17,10 @@ #ifndef PLUGINS_CHANNELTX_MODNFM_NFMMODGUI_H_ #define PLUGINS_CHANNELTX_MODNFM_NFMMODGUI_H_ +#include #include "gui/rollupwidget.h" #include "dsp/channelmarker.h" #include "dsp/movingaverage.h" -#include "plugin/plugininstanceui.h" #include "util/messagequeue.h" #include "nfmmod.h" @@ -36,7 +36,7 @@ namespace Ui { class NFMModGUI; } -class NFMModGUI : public RollupWidget, public PluginInstanceUI { +class NFMModGUI : public RollupWidget, public PluginInstanceGUI { Q_OBJECT public: diff --git a/plugins/channeltx/modnfm/nfmmodplugin.cpp b/plugins/channeltx/modnfm/nfmmodplugin.cpp index 2f876202f..a1a787825 100644 --- a/plugins/channeltx/modnfm/nfmmodplugin.cpp +++ b/plugins/channeltx/modnfm/nfmmodplugin.cpp @@ -49,7 +49,7 @@ void NFMModPlugin::initPlugin(PluginAPI* pluginAPI) m_pluginAPI->registerTxChannel(NFMModGUI::m_channelID, this); } -PluginInstanceUI* NFMModPlugin::createTxChannel(const QString& channelName, DeviceSinkAPI *deviceAPI) +PluginInstanceGUI* NFMModPlugin::createTxChannel(const QString& channelName, DeviceSinkAPI *deviceAPI) { if(channelName == NFMModGUI::m_channelID) { diff --git a/plugins/channeltx/modnfm/nfmmodplugin.h b/plugins/channeltx/modnfm/nfmmodplugin.h index 6fa9d098d..8c35aba10 100644 --- a/plugins/channeltx/modnfm/nfmmodplugin.h +++ b/plugins/channeltx/modnfm/nfmmodplugin.h @@ -33,7 +33,7 @@ public: const PluginDescriptor& getPluginDescriptor() const; void initPlugin(PluginAPI* pluginAPI); - PluginInstanceUI* createTxChannel(const QString& channelName, DeviceSinkAPI *deviceAPI); + PluginInstanceGUI* createTxChannel(const QString& channelName, DeviceSinkAPI *deviceAPI); private: static const PluginDescriptor m_pluginDescriptor; diff --git a/plugins/channeltx/modssb/ssbmodgui.h b/plugins/channeltx/modssb/ssbmodgui.h index 098a7e079..eceb0642b 100644 --- a/plugins/channeltx/modssb/ssbmodgui.h +++ b/plugins/channeltx/modssb/ssbmodgui.h @@ -17,10 +17,10 @@ #ifndef PLUGINS_CHANNELTX_MODSSB_SSBMODGUI_H_ #define PLUGINS_CHANNELTX_MODSSB_SSBMODGUI_H_ +#include #include "gui/rollupwidget.h" #include "dsp/channelmarker.h" #include "dsp/movingaverage.h" -#include "plugin/plugininstanceui.h" #include "util/messagequeue.h" #include "ssbmod.h" @@ -37,7 +37,7 @@ namespace Ui { class SSBModGUI; } -class SSBModGUI : public RollupWidget, public PluginInstanceUI { +class SSBModGUI : public RollupWidget, public PluginInstanceGUI { Q_OBJECT public: diff --git a/plugins/channeltx/modssb/ssbmodplugin.cpp b/plugins/channeltx/modssb/ssbmodplugin.cpp index e616cd916..e3a2b6494 100644 --- a/plugins/channeltx/modssb/ssbmodplugin.cpp +++ b/plugins/channeltx/modssb/ssbmodplugin.cpp @@ -49,7 +49,7 @@ void SSBModPlugin::initPlugin(PluginAPI* pluginAPI) m_pluginAPI->registerTxChannel(SSBModGUI::m_channelID, this); } -PluginInstanceUI* SSBModPlugin::createTxChannel(const QString& channelName, DeviceSinkAPI *deviceAPI) +PluginInstanceGUI* SSBModPlugin::createTxChannel(const QString& channelName, DeviceSinkAPI *deviceAPI) { if(channelName == SSBModGUI::m_channelID) { diff --git a/plugins/channeltx/modssb/ssbmodplugin.h b/plugins/channeltx/modssb/ssbmodplugin.h index 3b58e24ab..3c8ef8c98 100644 --- a/plugins/channeltx/modssb/ssbmodplugin.h +++ b/plugins/channeltx/modssb/ssbmodplugin.h @@ -33,7 +33,7 @@ public: const PluginDescriptor& getPluginDescriptor() const; void initPlugin(PluginAPI* pluginAPI); - PluginInstanceUI* createTxChannel(const QString& channelName, DeviceSinkAPI *deviceAPI); + PluginInstanceGUI* createTxChannel(const QString& channelName, DeviceSinkAPI *deviceAPI); private: static const PluginDescriptor m_pluginDescriptor; diff --git a/plugins/channeltx/modwfm/wfmmodgui.h b/plugins/channeltx/modwfm/wfmmodgui.h index 8add57c38..a929135db 100644 --- a/plugins/channeltx/modwfm/wfmmodgui.h +++ b/plugins/channeltx/modwfm/wfmmodgui.h @@ -17,10 +17,10 @@ #ifndef PLUGINS_CHANNELTX_MODWFM_WFMMODGUI_H_ #define PLUGINS_CHANNELTX_MODWFM_WFMMODGUI_H_ +#include #include "gui/rollupwidget.h" #include "dsp/channelmarker.h" #include "dsp/movingaverage.h" -#include "plugin/plugininstanceui.h" #include "util/messagequeue.h" #include "wfmmod.h" @@ -36,7 +36,7 @@ namespace Ui { class WFMModGUI; } -class WFMModGUI : public RollupWidget, public PluginInstanceUI { +class WFMModGUI : public RollupWidget, public PluginInstanceGUI { Q_OBJECT public: diff --git a/plugins/channeltx/modwfm/wfmmodplugin.cpp b/plugins/channeltx/modwfm/wfmmodplugin.cpp index 0b08dd2ef..e18c82a4d 100644 --- a/plugins/channeltx/modwfm/wfmmodplugin.cpp +++ b/plugins/channeltx/modwfm/wfmmodplugin.cpp @@ -49,7 +49,7 @@ void WFMModPlugin::initPlugin(PluginAPI* pluginAPI) m_pluginAPI->registerTxChannel(WFMModGUI::m_channelID, this); } -PluginInstanceUI* WFMModPlugin::createTxChannel(const QString& channelName, DeviceSinkAPI *deviceAPI) +PluginInstanceGUI* WFMModPlugin::createTxChannel(const QString& channelName, DeviceSinkAPI *deviceAPI) { if(channelName == WFMModGUI::m_channelID) { diff --git a/plugins/channeltx/modwfm/wfmmodplugin.h b/plugins/channeltx/modwfm/wfmmodplugin.h index 48616d21d..e4b67ba1c 100644 --- a/plugins/channeltx/modwfm/wfmmodplugin.h +++ b/plugins/channeltx/modwfm/wfmmodplugin.h @@ -33,7 +33,7 @@ public: const PluginDescriptor& getPluginDescriptor() const; void initPlugin(PluginAPI* pluginAPI); - PluginInstanceUI* createTxChannel(const QString& channelName, DeviceSinkAPI *deviceAPI); + PluginInstanceGUI* createTxChannel(const QString& channelName, DeviceSinkAPI *deviceAPI); private: static const PluginDescriptor m_pluginDescriptor; diff --git a/plugins/channeltx/udpsink/udpsinkgui.h b/plugins/channeltx/udpsink/udpsinkgui.h index f4291ca0f..a6abfb8b5 100644 --- a/plugins/channeltx/udpsink/udpsinkgui.h +++ b/plugins/channeltx/udpsink/udpsinkgui.h @@ -17,11 +17,11 @@ #ifndef PLUGINS_CHANNELTX_UDPSINK_UDPSINKGUI_H_ #define PLUGINS_CHANNELTX_UDPSINK_UDPSINKGUI_H_ +#include #include #include "gui/rollupwidget.h" #include "dsp/channelmarker.h" -#include "plugin/plugininstanceui.h" #include "util/messagequeue.h" #include "udpsink.h" @@ -37,7 +37,7 @@ namespace Ui { class UDPSinkGUI; } -class UDPSinkGUI : public RollupWidget, public PluginInstanceUI { +class UDPSinkGUI : public RollupWidget, public PluginInstanceGUI { Q_OBJECT public: diff --git a/plugins/channeltx/udpsink/udpsinkplugin.cpp b/plugins/channeltx/udpsink/udpsinkplugin.cpp index 88b7ff3d8..46d829c84 100644 --- a/plugins/channeltx/udpsink/udpsinkplugin.cpp +++ b/plugins/channeltx/udpsink/udpsinkplugin.cpp @@ -50,7 +50,7 @@ void UDPSinkPlugin::initPlugin(PluginAPI* pluginAPI) m_pluginAPI->registerTxChannel(UDPSinkGUI::m_channelID, this); } -PluginInstanceUI* UDPSinkPlugin::createTxChannel(const QString& channelName, DeviceSinkAPI *deviceAPI) +PluginInstanceGUI* UDPSinkPlugin::createTxChannel(const QString& channelName, DeviceSinkAPI *deviceAPI) { if(channelName == UDPSinkGUI::m_channelID) { diff --git a/plugins/channeltx/udpsink/udpsinkplugin.h b/plugins/channeltx/udpsink/udpsinkplugin.h index e56d94318..7574f2951 100644 --- a/plugins/channeltx/udpsink/udpsinkplugin.h +++ b/plugins/channeltx/udpsink/udpsinkplugin.h @@ -34,7 +34,7 @@ public: const PluginDescriptor& getPluginDescriptor() const; void initPlugin(PluginAPI* pluginAPI); - PluginInstanceUI* createTxChannel(const QString& channelName, DeviceSinkAPI *deviceAPI); + PluginInstanceGUI* createTxChannel(const QString& channelName, DeviceSinkAPI *deviceAPI); private: static const PluginDescriptor m_pluginDescriptor; diff --git a/plugins/samplesink/bladerfoutput/bladerfoutputgui.h b/plugins/samplesink/bladerfoutput/bladerfoutputgui.h index 9865f8784..e275d3b30 100644 --- a/plugins/samplesink/bladerfoutput/bladerfoutputgui.h +++ b/plugins/samplesink/bladerfoutput/bladerfoutputgui.h @@ -17,10 +17,10 @@ #ifndef INCLUDE_BLADERFOUTPUTGUI_H #define INCLUDE_BLADERFOUTPUTGUI_H +#include #include #include -#include "plugin/plugininstanceui.h" #include "util/messagequeue.h" #include "bladerfoutput.h" @@ -32,7 +32,7 @@ namespace Ui { class BladerfOutputGui; } -class BladerfOutputGui : public QWidget, public PluginInstanceUI { +class BladerfOutputGui : public QWidget, public PluginInstanceGUI { Q_OBJECT public: diff --git a/plugins/samplesink/bladerfoutput/bladerfoutputplugin.cpp b/plugins/samplesink/bladerfoutput/bladerfoutputplugin.cpp index 7af7a8ec0..6ea15cc63 100644 --- a/plugins/samplesink/bladerfoutput/bladerfoutputplugin.cpp +++ b/plugins/samplesink/bladerfoutput/bladerfoutputplugin.cpp @@ -77,7 +77,7 @@ PluginInterface::SamplingDevices BladerfOutputPlugin::enumSampleSinks() return result; } -PluginInstanceUI* BladerfOutputPlugin::createSampleSinkPluginInstanceGUI(const QString& sinkId,QWidget **widget, DeviceSinkAPI *deviceAPI) +PluginInstanceGUI* BladerfOutputPlugin::createSampleSinkPluginInstanceGUI(const QString& sinkId,QWidget **widget, DeviceSinkAPI *deviceAPI) { if(sinkId == m_deviceTypeID) { diff --git a/plugins/samplesink/bladerfoutput/bladerfoutputplugin.h b/plugins/samplesink/bladerfoutput/bladerfoutputplugin.h index 3126667cc..62fd5755d 100644 --- a/plugins/samplesink/bladerfoutput/bladerfoutputplugin.h +++ b/plugins/samplesink/bladerfoutput/bladerfoutputplugin.h @@ -36,7 +36,7 @@ public: void initPlugin(PluginAPI* pluginAPI); virtual SamplingDevices enumSampleSinks(); - virtual PluginInstanceUI* createSampleSinkPluginInstanceGUI(const QString& sinkId, QWidget **widget, DeviceSinkAPI *deviceAPI); + virtual PluginInstanceGUI* createSampleSinkPluginInstanceGUI(const QString& sinkId, QWidget **widget, DeviceSinkAPI *deviceAPI); virtual DeviceSampleSink* createSampleSinkPluginInstanceOutput(const QString& sinkId, DeviceSinkAPI *deviceAPI); static const QString m_hardwareID; diff --git a/plugins/samplesink/filesink/filesinkgui.h b/plugins/samplesink/filesink/filesinkgui.h index 7153834b1..2c45b9dda 100644 --- a/plugins/samplesink/filesink/filesinkgui.h +++ b/plugins/samplesink/filesink/filesinkgui.h @@ -17,10 +17,10 @@ #ifndef INCLUDE_FILESINKGUI_H #define INCLUDE_FILESINKGUI_H +#include #include #include -#include "plugin/plugininstanceui.h" #include "util/messagequeue.h" #include "filesinkoutput.h" @@ -34,7 +34,7 @@ namespace Ui { class FileSinkGui; } -class FileSinkGui : public QWidget, public PluginInstanceUI { +class FileSinkGui : public QWidget, public PluginInstanceGUI { Q_OBJECT public: diff --git a/plugins/samplesink/filesink/filesinkplugin.cpp b/plugins/samplesink/filesink/filesinkplugin.cpp index b70155a6e..e2497ae1e 100644 --- a/plugins/samplesink/filesink/filesinkplugin.cpp +++ b/plugins/samplesink/filesink/filesinkplugin.cpp @@ -69,7 +69,7 @@ PluginInterface::SamplingDevices FileSinkPlugin::enumSampleSinks() return result; } -PluginInstanceUI* FileSinkPlugin::createSampleSinkPluginInstanceGUI(const QString& sinkId, QWidget **widget, DeviceSinkAPI *deviceAPI) +PluginInstanceGUI* FileSinkPlugin::createSampleSinkPluginInstanceGUI(const QString& sinkId, QWidget **widget, DeviceSinkAPI *deviceAPI) { if(sinkId == m_deviceTypeID) { diff --git a/plugins/samplesink/filesink/filesinkplugin.h b/plugins/samplesink/filesink/filesinkplugin.h index 5beea7402..fcc706167 100644 --- a/plugins/samplesink/filesink/filesinkplugin.h +++ b/plugins/samplesink/filesink/filesinkplugin.h @@ -37,7 +37,7 @@ public: void initPlugin(PluginAPI* pluginAPI); virtual SamplingDevices enumSampleSinks(); - virtual PluginInstanceUI* createSampleSinkPluginInstanceGUI(const QString& sinkId, QWidget **widget, DeviceSinkAPI *deviceAPI); + virtual PluginInstanceGUI* createSampleSinkPluginInstanceGUI(const QString& sinkId, QWidget **widget, DeviceSinkAPI *deviceAPI); virtual DeviceSampleSink* createSampleSinkPluginInstanceOutput(const QString& sinkId, DeviceSinkAPI *deviceAPI); static const QString m_hardwareID; diff --git a/plugins/samplesink/hackrfoutput/hackrfoutputgui.h b/plugins/samplesink/hackrfoutput/hackrfoutputgui.h index 5c62c7e25..b5ced5931 100644 --- a/plugins/samplesink/hackrfoutput/hackrfoutputgui.h +++ b/plugins/samplesink/hackrfoutput/hackrfoutputgui.h @@ -17,10 +17,10 @@ #ifndef INCLUDE_HACKRFOUTPUTGUI_H #define INCLUDE_HACKRFOUTPUTGUI_H +#include #include #include -#include "plugin/plugininstanceui.h" #include "util/messagequeue.h" #include "hackrfoutput.h" @@ -34,7 +34,7 @@ namespace Ui { class HackRFOutputGui; } -class HackRFOutputGui : public QWidget, public PluginInstanceUI { +class HackRFOutputGui : public QWidget, public PluginInstanceGUI { Q_OBJECT public: diff --git a/plugins/samplesink/hackrfoutput/hackrfoutputplugin.cpp b/plugins/samplesink/hackrfoutput/hackrfoutputplugin.cpp index f90a8a60e..a65a24218 100644 --- a/plugins/samplesink/hackrfoutput/hackrfoutputplugin.cpp +++ b/plugins/samplesink/hackrfoutput/hackrfoutputplugin.cpp @@ -116,7 +116,7 @@ PluginInterface::SamplingDevices HackRFOutputPlugin::enumSampleSinks() return result; } -PluginInstanceUI* HackRFOutputPlugin::createSampleSinkPluginInstanceGUI(const QString& sinkId, QWidget **widget, DeviceSinkAPI *deviceAPI) +PluginInstanceGUI* HackRFOutputPlugin::createSampleSinkPluginInstanceGUI(const QString& sinkId, QWidget **widget, DeviceSinkAPI *deviceAPI) { if(sinkId == m_deviceTypeID) { diff --git a/plugins/samplesink/hackrfoutput/hackrfoutputplugin.h b/plugins/samplesink/hackrfoutput/hackrfoutputplugin.h index 3bc320a12..6ba7809b2 100644 --- a/plugins/samplesink/hackrfoutput/hackrfoutputplugin.h +++ b/plugins/samplesink/hackrfoutput/hackrfoutputplugin.h @@ -36,7 +36,7 @@ public: void initPlugin(PluginAPI* pluginAPI); virtual SamplingDevices enumSampleSinks(); - virtual PluginInstanceUI* createSampleSinkPluginInstanceGUI(const QString& sinkId, QWidget **widget, DeviceSinkAPI *deviceAPI); + virtual PluginInstanceGUI* createSampleSinkPluginInstanceGUI(const QString& sinkId, QWidget **widget, DeviceSinkAPI *deviceAPI); virtual DeviceSampleSink* createSampleSinkPluginInstanceOutput(const QString& sinkId, DeviceSinkAPI *deviceAPI); static const QString m_hardwareID; diff --git a/plugins/samplesink/limesdroutput/limesdroutputgui.h b/plugins/samplesink/limesdroutput/limesdroutputgui.h index 219831fa0..55ebd4d91 100644 --- a/plugins/samplesink/limesdroutput/limesdroutputgui.h +++ b/plugins/samplesink/limesdroutput/limesdroutputgui.h @@ -17,10 +17,10 @@ #ifndef PLUGINS_SAMPLESOURCE_LIMESDROUTPUT_LIMESDROUTPUTGUI_H_ #define PLUGINS_SAMPLESOURCE_LIMESDROUTPUT_LIMESDROUTPUTGUI_H_ +#include #include #include -#include "plugin/plugininstanceui.h" #include "util/messagequeue.h" #include "limesdroutput.h" @@ -32,7 +32,7 @@ namespace Ui { class LimeSDROutputGUI; } -class LimeSDROutputGUI : public QWidget, public PluginInstanceUI { +class LimeSDROutputGUI : public QWidget, public PluginInstanceGUI { Q_OBJECT public: diff --git a/plugins/samplesink/limesdroutput/limesdroutputplugin.cpp b/plugins/samplesink/limesdroutput/limesdroutputplugin.cpp index 1bff816a6..14cbff296 100644 --- a/plugins/samplesink/limesdroutput/limesdroutputplugin.cpp +++ b/plugins/samplesink/limesdroutput/limesdroutputplugin.cpp @@ -96,7 +96,7 @@ PluginInterface::SamplingDevices LimeSDROutputPlugin::enumSampleSinks() return result; } -PluginInstanceUI* LimeSDROutputPlugin::createSampleSinkPluginInstanceGUI(const QString& sinkId,QWidget **widget, DeviceSinkAPI *deviceAPI) +PluginInstanceGUI* LimeSDROutputPlugin::createSampleSinkPluginInstanceGUI(const QString& sinkId,QWidget **widget, DeviceSinkAPI *deviceAPI) { if(sinkId == m_deviceTypeID) { diff --git a/plugins/samplesink/limesdroutput/limesdroutputplugin.h b/plugins/samplesink/limesdroutput/limesdroutputplugin.h index 0fbbc40f5..bf012aa38 100644 --- a/plugins/samplesink/limesdroutput/limesdroutputplugin.h +++ b/plugins/samplesink/limesdroutput/limesdroutputplugin.h @@ -36,7 +36,7 @@ public: void initPlugin(PluginAPI* pluginAPI); virtual SamplingDevices enumSampleSinks(); - virtual PluginInstanceUI* createSampleSinkPluginInstanceGUI(const QString& sinkId, QWidget **widget, DeviceSinkAPI *deviceAPI); + virtual PluginInstanceGUI* createSampleSinkPluginInstanceGUI(const QString& sinkId, QWidget **widget, DeviceSinkAPI *deviceAPI); virtual DeviceSampleSink* createSampleSinkPluginInstanceOutput(const QString& sinkId, DeviceSinkAPI *deviceAPI); static const QString m_hardwareID; diff --git a/plugins/samplesink/plutosdroutput/plutosdroutputgui.h b/plugins/samplesink/plutosdroutput/plutosdroutputgui.h index 235624f04..ece73df40 100644 --- a/plugins/samplesink/plutosdroutput/plutosdroutputgui.h +++ b/plugins/samplesink/plutosdroutput/plutosdroutputgui.h @@ -17,11 +17,11 @@ #ifndef PLUGINS_SAMPLESOURCE_PLUTOSDROUTPUT_PLUTOSDROUTPUTGUI_H_ #define PLUGINS_SAMPLESOURCE_PLUTOSDROUTPUT_PLUTOSDROUTPUTGUI_H_ +#include #include #include #include -#include "plugin/plugininstanceui.h" #include "util/messagequeue.h" #include "plutosdroutputsettings.h" @@ -33,7 +33,7 @@ namespace Ui { class PlutoSDROutputGUI; } -class PlutoSDROutputGUI : public QWidget, public PluginInstanceUI { +class PlutoSDROutputGUI : public QWidget, public PluginInstanceGUI { Q_OBJECT public: diff --git a/plugins/samplesink/plutosdroutput/plutosdroutputplugin.cpp b/plugins/samplesink/plutosdroutput/plutosdroutputplugin.cpp index 4b4372349..c8d5bc761 100644 --- a/plugins/samplesink/plutosdroutput/plutosdroutputplugin.cpp +++ b/plugins/samplesink/plutosdroutput/plutosdroutputplugin.cpp @@ -81,7 +81,7 @@ PluginInterface::SamplingDevices PlutoSDROutputPlugin::enumSampleSinks() return result; } -PluginInstanceUI* PlutoSDROutputPlugin::createSampleSinkPluginInstanceGUI(const QString& sinkId, QWidget **widget, DeviceSinkAPI *deviceAPI) +PluginInstanceGUI* PlutoSDROutputPlugin::createSampleSinkPluginInstanceGUI(const QString& sinkId, QWidget **widget, DeviceSinkAPI *deviceAPI) { if(sinkId == m_deviceTypeID) { diff --git a/plugins/samplesink/plutosdroutput/plutosdroutputplugin.h b/plugins/samplesink/plutosdroutput/plutosdroutputplugin.h index 2e0880fc8..730a28473 100644 --- a/plugins/samplesink/plutosdroutput/plutosdroutputplugin.h +++ b/plugins/samplesink/plutosdroutput/plutosdroutputplugin.h @@ -36,7 +36,7 @@ public: void initPlugin(PluginAPI* pluginAPI); virtual SamplingDevices enumSampleSinks(); - virtual PluginInstanceUI* createSampleSinkPluginInstanceGUI(const QString& sinkId, QWidget **widget, DeviceSinkAPI *deviceAPI); + virtual PluginInstanceGUI* createSampleSinkPluginInstanceGUI(const QString& sinkId, QWidget **widget, DeviceSinkAPI *deviceAPI); virtual DeviceSampleSink* createSampleSinkPluginInstanceOutput(const QString& sinkId, DeviceSinkAPI *deviceAPI); static const QString m_hardwareID; diff --git a/plugins/samplesink/sdrdaemonsink/sdrdaemonsinkgui.h b/plugins/samplesink/sdrdaemonsink/sdrdaemonsinkgui.h index dd5bef6d0..91f51ca7d 100644 --- a/plugins/samplesink/sdrdaemonsink/sdrdaemonsinkgui.h +++ b/plugins/samplesink/sdrdaemonsink/sdrdaemonsinkgui.h @@ -17,11 +17,11 @@ #ifndef INCLUDE_SDRDAEMONSINKGUI_H #define INCLUDE_SDRDAEMONSINKGUI_H +#include #include #include #include -#include "plugin/plugininstanceui.h" #include "util/messagequeue.h" #include "sdrdaemonsinksettings.h" @@ -35,7 +35,7 @@ namespace Ui { class SDRdaemonSinkGui; } -class SDRdaemonSinkGui : public QWidget, public PluginInstanceUI { +class SDRdaemonSinkGui : public QWidget, public PluginInstanceGUI { Q_OBJECT public: diff --git a/plugins/samplesink/sdrdaemonsink/sdrdaemonsinkplugin.cpp b/plugins/samplesink/sdrdaemonsink/sdrdaemonsinkplugin.cpp index 58526827d..53f56c003 100644 --- a/plugins/samplesink/sdrdaemonsink/sdrdaemonsinkplugin.cpp +++ b/plugins/samplesink/sdrdaemonsink/sdrdaemonsinkplugin.cpp @@ -70,7 +70,7 @@ PluginInterface::SamplingDevices SDRdaemonSinkPlugin::enumSampleSinks() return result; } -PluginInstanceUI* SDRdaemonSinkPlugin::createSampleSinkPluginInstanceGUI(const QString& sinkId, QWidget **widget, DeviceSinkAPI *deviceAPI) +PluginInstanceGUI* SDRdaemonSinkPlugin::createSampleSinkPluginInstanceGUI(const QString& sinkId, QWidget **widget, DeviceSinkAPI *deviceAPI) { if(sinkId == m_deviceTypeID) { diff --git a/plugins/samplesink/sdrdaemonsink/sdrdaemonsinkplugin.h b/plugins/samplesink/sdrdaemonsink/sdrdaemonsinkplugin.h index 07c3dbfba..2980b19e9 100644 --- a/plugins/samplesink/sdrdaemonsink/sdrdaemonsinkplugin.h +++ b/plugins/samplesink/sdrdaemonsink/sdrdaemonsinkplugin.h @@ -37,7 +37,7 @@ public: void initPlugin(PluginAPI* pluginAPI); virtual SamplingDevices enumSampleSinks(); - virtual PluginInstanceUI* createSampleSinkPluginInstanceGUI(const QString& sinkId, QWidget **widget, DeviceSinkAPI *deviceAPI); + virtual PluginInstanceGUI* createSampleSinkPluginInstanceGUI(const QString& sinkId, QWidget **widget, DeviceSinkAPI *deviceAPI); virtual DeviceSampleSink* createSampleSinkPluginInstanceOutput(const QString& sinkId, DeviceSinkAPI *deviceAPI); static const QString m_hardwareID; diff --git a/plugins/samplesource/airspy/airspygui.h b/plugins/samplesource/airspy/airspygui.h index 66bdc10d0..c507a6dd7 100644 --- a/plugins/samplesource/airspy/airspygui.h +++ b/plugins/samplesource/airspy/airspygui.h @@ -17,10 +17,10 @@ #ifndef INCLUDE_AIRSPYGUI_H #define INCLUDE_AIRSPYGUI_H +#include #include #include -#include "plugin/plugininstanceui.h" #include "util/messagequeue.h" #include "airspyinput.h" @@ -33,7 +33,7 @@ namespace Ui { class AirspySampleRates; } -class AirspyGui : public QWidget, public PluginInstanceUI { +class AirspyGui : public QWidget, public PluginInstanceGUI { Q_OBJECT public: diff --git a/plugins/samplesource/airspy/airspyplugin.cpp b/plugins/samplesource/airspy/airspyplugin.cpp index f13854a10..13d856eb2 100644 --- a/plugins/samplesource/airspy/airspyplugin.cpp +++ b/plugins/samplesource/airspy/airspyplugin.cpp @@ -119,7 +119,7 @@ PluginInterface::SamplingDevices AirspyPlugin::enumSampleSources() return result; } -PluginInstanceUI* AirspyPlugin::createSampleSourcePluginInstanceGUI(const QString& sourceId, QWidget **widget, DeviceSourceAPI *deviceAPI) +PluginInstanceGUI* AirspyPlugin::createSampleSourcePluginInstanceGUI(const QString& sourceId, QWidget **widget, DeviceSourceAPI *deviceAPI) { if (sourceId == m_deviceTypeID) { diff --git a/plugins/samplesource/airspy/airspyplugin.h b/plugins/samplesource/airspy/airspyplugin.h index 0a3f6ffe2..0406ffd68 100644 --- a/plugins/samplesource/airspy/airspyplugin.h +++ b/plugins/samplesource/airspy/airspyplugin.h @@ -36,7 +36,7 @@ public: void initPlugin(PluginAPI* pluginAPI); virtual SamplingDevices enumSampleSources(); - virtual PluginInstanceUI* createSampleSourcePluginInstanceGUI(const QString& sourceId, QWidget **widget, DeviceSourceAPI *deviceAPI); + virtual PluginInstanceGUI* createSampleSourcePluginInstanceGUI(const QString& sourceId, QWidget **widget, DeviceSourceAPI *deviceAPI); virtual DeviceSampleSource* createSampleSourcePluginInstanceInput(const QString& sourceId, DeviceSourceAPI *deviceAPI); static const QString m_hardwareID; diff --git a/plugins/samplesource/bladerfinput/bladerfinputgui.h b/plugins/samplesource/bladerfinput/bladerfinputgui.h index 234e29197..0d75c6ab9 100644 --- a/plugins/samplesource/bladerfinput/bladerfinputgui.h +++ b/plugins/samplesource/bladerfinput/bladerfinputgui.h @@ -17,10 +17,10 @@ #ifndef INCLUDE_BLADERFINPUTGUI_H #define INCLUDE_BLADERFINPUTGUI_H +#include #include #include -#include "plugin/plugininstanceui.h" #include "util/messagequeue.h" #include "bladerfinput.h" @@ -31,7 +31,7 @@ namespace Ui { class BladerfInputGui; } -class BladerfInputGui : public QWidget, public PluginInstanceUI { +class BladerfInputGui : public QWidget, public PluginInstanceGUI { Q_OBJECT public: diff --git a/plugins/samplesource/bladerfinput/bladerfinputplugin.cpp b/plugins/samplesource/bladerfinput/bladerfinputplugin.cpp index c73877ef7..ae7ba37fc 100644 --- a/plugins/samplesource/bladerfinput/bladerfinputplugin.cpp +++ b/plugins/samplesource/bladerfinput/bladerfinputplugin.cpp @@ -78,7 +78,7 @@ PluginInterface::SamplingDevices BlderfInputPlugin::enumSampleSources() return result; } -PluginInstanceUI* BlderfInputPlugin::createSampleSourcePluginInstanceGUI(const QString& sourceId,QWidget **widget, DeviceSourceAPI *deviceAPI) +PluginInstanceGUI* BlderfInputPlugin::createSampleSourcePluginInstanceGUI(const QString& sourceId,QWidget **widget, DeviceSourceAPI *deviceAPI) { if(sourceId == m_deviceTypeID) { diff --git a/plugins/samplesource/bladerfinput/bladerfinputplugin.h b/plugins/samplesource/bladerfinput/bladerfinputplugin.h index a13e93bc9..e21998654 100644 --- a/plugins/samplesource/bladerfinput/bladerfinputplugin.h +++ b/plugins/samplesource/bladerfinput/bladerfinputplugin.h @@ -37,7 +37,7 @@ public: void initPlugin(PluginAPI* pluginAPI); virtual SamplingDevices enumSampleSources(); - virtual PluginInstanceUI* createSampleSourcePluginInstanceGUI(const QString& sourceId, QWidget **widget, DeviceSourceAPI *deviceAPI); + virtual PluginInstanceGUI* createSampleSourcePluginInstanceGUI(const QString& sourceId, QWidget **widget, DeviceSourceAPI *deviceAPI); virtual DeviceSampleSource* createSampleSourcePluginInstanceInput(const QString& sourceId, DeviceSourceAPI *deviceAPI); static const QString m_hardwareID; diff --git a/plugins/samplesource/fcdpro/fcdprogui.h b/plugins/samplesource/fcdpro/fcdprogui.h index 03491152e..d9c1a1742 100644 --- a/plugins/samplesource/fcdpro/fcdprogui.h +++ b/plugins/samplesource/fcdpro/fcdprogui.h @@ -17,10 +17,10 @@ #ifndef INCLUDE_FCDPROGUI_H #define INCLUDE_FCDPROGUI_H +#include #include #include -#include "plugin/plugininstanceui.h" #include "util/messagequeue.h" #include "fcdproinput.h" @@ -32,7 +32,7 @@ namespace Ui { class FCDProGui; } -class FCDProGui : public QWidget, public PluginInstanceUI { +class FCDProGui : public QWidget, public PluginInstanceGUI { Q_OBJECT public: diff --git a/plugins/samplesource/fcdpro/fcdproplugin.cpp b/plugins/samplesource/fcdpro/fcdproplugin.cpp index 268f28841..f6d0bfdee 100644 --- a/plugins/samplesource/fcdpro/fcdproplugin.cpp +++ b/plugins/samplesource/fcdpro/fcdproplugin.cpp @@ -74,7 +74,7 @@ PluginInterface::SamplingDevices FCDProPlugin::enumSampleSources() return result; } -PluginInstanceUI* FCDProPlugin::createSampleSourcePluginInstanceGUI(const QString& sourceId, QWidget **widget, DeviceSourceAPI *deviceAPI) +PluginInstanceGUI* FCDProPlugin::createSampleSourcePluginInstanceGUI(const QString& sourceId, QWidget **widget, DeviceSourceAPI *deviceAPI) { if(sourceId == fcd_traits::interfaceIID) { diff --git a/plugins/samplesource/fcdpro/fcdproplugin.h b/plugins/samplesource/fcdpro/fcdproplugin.h index fe55f5aa3..4005bc47e 100644 --- a/plugins/samplesource/fcdpro/fcdproplugin.h +++ b/plugins/samplesource/fcdpro/fcdproplugin.h @@ -20,7 +20,7 @@ public: void initPlugin(PluginAPI* pluginAPI); virtual SamplingDevices enumSampleSources(); - virtual PluginInstanceUI* createSampleSourcePluginInstanceGUI(const QString& sourceId, QWidget **widget, DeviceSourceAPI *deviceAPI); + virtual PluginInstanceGUI* createSampleSourcePluginInstanceGUI(const QString& sourceId, QWidget **widget, DeviceSourceAPI *deviceAPI); virtual DeviceSampleSource* createSampleSourcePluginInstanceInput(const QString& sourceId, DeviceSourceAPI *deviceAPI); private: diff --git a/plugins/samplesource/fcdproplus/fcdproplusgui.h b/plugins/samplesource/fcdproplus/fcdproplusgui.h index 4dbd77ad9..586170bb6 100644 --- a/plugins/samplesource/fcdproplus/fcdproplusgui.h +++ b/plugins/samplesource/fcdproplus/fcdproplusgui.h @@ -17,10 +17,10 @@ #ifndef INCLUDE_FCDGUI_H #define INCLUDE_FCDGUI_H +#include #include #include -#include "plugin/plugininstanceui.h" #include "util/messagequeue.h" #include "fcdproplusinput.h" @@ -31,7 +31,7 @@ namespace Ui { class FCDProPlusGui; } -class FCDProPlusGui : public QWidget, public PluginInstanceUI { +class FCDProPlusGui : public QWidget, public PluginInstanceGUI { Q_OBJECT public: diff --git a/plugins/samplesource/fcdproplus/fcdproplusplugin.cpp b/plugins/samplesource/fcdproplus/fcdproplusplugin.cpp index ab5958e56..14159c0b7 100644 --- a/plugins/samplesource/fcdproplus/fcdproplusplugin.cpp +++ b/plugins/samplesource/fcdproplus/fcdproplusplugin.cpp @@ -76,7 +76,7 @@ PluginInterface::SamplingDevices FCDProPlusPlugin::enumSampleSources() return result; } -PluginInstanceUI* FCDProPlusPlugin::createSampleSourcePluginInstanceGUI(const QString& sourceId, QWidget **widget, DeviceSourceAPI *deviceAPI) +PluginInstanceGUI* FCDProPlusPlugin::createSampleSourcePluginInstanceGUI(const QString& sourceId, QWidget **widget, DeviceSourceAPI *deviceAPI) { if(sourceId == fcd_traits::interfaceIID) { diff --git a/plugins/samplesource/fcdproplus/fcdproplusplugin.h b/plugins/samplesource/fcdproplus/fcdproplusplugin.h index ecad2455a..c122e8b9b 100644 --- a/plugins/samplesource/fcdproplus/fcdproplusplugin.h +++ b/plugins/samplesource/fcdproplus/fcdproplusplugin.h @@ -20,7 +20,7 @@ public: void initPlugin(PluginAPI* pluginAPI); virtual SamplingDevices enumSampleSources(); - virtual PluginInstanceUI* createSampleSourcePluginInstanceGUI(const QString& sourceId, QWidget **widget, DeviceSourceAPI *deviceAPI); + virtual PluginInstanceGUI* createSampleSourcePluginInstanceGUI(const QString& sourceId, QWidget **widget, DeviceSourceAPI *deviceAPI); virtual DeviceSampleSource* createSampleSourcePluginInstanceInput(const QString& sourceId, DeviceSourceAPI *deviceAPI); static const QString m_deviceTypeID; diff --git a/plugins/samplesource/filesource/filesourcegui.h b/plugins/samplesource/filesource/filesourcegui.h index 5b706ecd8..bef589100 100644 --- a/plugins/samplesource/filesource/filesourcegui.h +++ b/plugins/samplesource/filesource/filesourcegui.h @@ -17,10 +17,10 @@ #ifndef INCLUDE_FILESOURCEGUI_H #define INCLUDE_FILESOURCEGUI_H +#include #include #include -#include "plugin/plugininstanceui.h" #include "util/messagequeue.h" #include "filesourceinput.h" @@ -31,7 +31,7 @@ namespace Ui { class FileSourceGui; } -class FileSourceGui : public QWidget, public PluginInstanceUI { +class FileSourceGui : public QWidget, public PluginInstanceGUI { Q_OBJECT public: diff --git a/plugins/samplesource/filesource/filesourceplugin.cpp b/plugins/samplesource/filesource/filesourceplugin.cpp index 1f7df67dc..04ed32ba6 100644 --- a/plugins/samplesource/filesource/filesourceplugin.cpp +++ b/plugins/samplesource/filesource/filesourceplugin.cpp @@ -69,7 +69,7 @@ PluginInterface::SamplingDevices FileSourcePlugin::enumSampleSources() return result; } -PluginInstanceUI* FileSourcePlugin::createSampleSourcePluginInstanceGUI(const QString& sourceId, QWidget **widget, DeviceSourceAPI *deviceAPI) +PluginInstanceGUI* FileSourcePlugin::createSampleSourcePluginInstanceGUI(const QString& sourceId, QWidget **widget, DeviceSourceAPI *deviceAPI) { if(sourceId == m_deviceTypeID) { diff --git a/plugins/samplesource/filesource/filesourceplugin.h b/plugins/samplesource/filesource/filesourceplugin.h index 4e7a47a45..04fb820ad 100644 --- a/plugins/samplesource/filesource/filesourceplugin.h +++ b/plugins/samplesource/filesource/filesourceplugin.h @@ -36,7 +36,7 @@ public: void initPlugin(PluginAPI* pluginAPI); virtual SamplingDevices enumSampleSources(); - virtual PluginInstanceUI* createSampleSourcePluginInstanceGUI(const QString& sourceId, QWidget **widget, DeviceSourceAPI *deviceAPI); + virtual PluginInstanceGUI* createSampleSourcePluginInstanceGUI(const QString& sourceId, QWidget **widget, DeviceSourceAPI *deviceAPI); virtual DeviceSampleSource* createSampleSourcePluginInstanceInput(const QString& sourceId, DeviceSourceAPI *deviceAPI); static const QString m_hardwareID; diff --git a/plugins/samplesource/hackrfinput/hackrfinputgui.h b/plugins/samplesource/hackrfinput/hackrfinputgui.h index 6370ee2e7..5f78a2f34 100644 --- a/plugins/samplesource/hackrfinput/hackrfinputgui.h +++ b/plugins/samplesource/hackrfinput/hackrfinputgui.h @@ -17,10 +17,10 @@ #ifndef INCLUDE_HACKRFINPUTGUI_H #define INCLUDE_HACKRFINPUTGUI_H +#include #include #include -#include "plugin/plugininstanceui.h" #include "util/messagequeue.h" #include "hackrfinput.h" @@ -33,7 +33,7 @@ namespace Ui { class HackRFInputGui; } -class HackRFInputGui : public QWidget, public PluginInstanceUI { +class HackRFInputGui : public QWidget, public PluginInstanceGUI { Q_OBJECT public: diff --git a/plugins/samplesource/hackrfinput/hackrfinputplugin.cpp b/plugins/samplesource/hackrfinput/hackrfinputplugin.cpp index eb9901d07..833722be8 100644 --- a/plugins/samplesource/hackrfinput/hackrfinputplugin.cpp +++ b/plugins/samplesource/hackrfinput/hackrfinputplugin.cpp @@ -117,7 +117,7 @@ PluginInterface::SamplingDevices HackRFInputPlugin::enumSampleSources() return result; } -PluginInstanceUI* HackRFInputPlugin::createSampleSourcePluginInstanceGUI(const QString& sourceId, QWidget **widget, DeviceSourceAPI *deviceAPI) +PluginInstanceGUI* HackRFInputPlugin::createSampleSourcePluginInstanceGUI(const QString& sourceId, QWidget **widget, DeviceSourceAPI *deviceAPI) { if(sourceId == m_deviceTypeID) { diff --git a/plugins/samplesource/hackrfinput/hackrfinputplugin.h b/plugins/samplesource/hackrfinput/hackrfinputplugin.h index c5c7f1c2e..c779cb880 100644 --- a/plugins/samplesource/hackrfinput/hackrfinputplugin.h +++ b/plugins/samplesource/hackrfinput/hackrfinputplugin.h @@ -36,7 +36,7 @@ public: void initPlugin(PluginAPI* pluginAPI); virtual SamplingDevices enumSampleSources(); - virtual PluginInstanceUI* createSampleSourcePluginInstanceGUI(const QString& sourceId, QWidget **widget, DeviceSourceAPI *deviceAPI); + virtual PluginInstanceGUI* createSampleSourcePluginInstanceGUI(const QString& sourceId, QWidget **widget, DeviceSourceAPI *deviceAPI); virtual DeviceSampleSource* createSampleSourcePluginInstanceInput(const QString& sourceId, DeviceSourceAPI *deviceAPI); static const QString m_hardwareID; diff --git a/plugins/samplesource/limesdrinput/limesdrinputgui.h b/plugins/samplesource/limesdrinput/limesdrinputgui.h index 5b8d20f0c..7484f03db 100644 --- a/plugins/samplesource/limesdrinput/limesdrinputgui.h +++ b/plugins/samplesource/limesdrinput/limesdrinputgui.h @@ -17,10 +17,10 @@ #ifndef PLUGINS_SAMPLESOURCE_LIMESDRINPUT_LIMESDRINPUTGUI_H_ #define PLUGINS_SAMPLESOURCE_LIMESDRINPUT_LIMESDRINPUTGUI_H_ +#include #include #include -#include "plugin/plugininstanceui.h" #include "util/messagequeue.h" #include "limesdrinput.h" @@ -31,7 +31,7 @@ namespace Ui { class LimeSDRInputGUI; } -class LimeSDRInputGUI : public QWidget, public PluginInstanceUI { +class LimeSDRInputGUI : public QWidget, public PluginInstanceGUI { Q_OBJECT public: diff --git a/plugins/samplesource/limesdrinput/limesdrinputplugin.cpp b/plugins/samplesource/limesdrinput/limesdrinputplugin.cpp index 17f576753..f3dd6ef78 100644 --- a/plugins/samplesource/limesdrinput/limesdrinputplugin.cpp +++ b/plugins/samplesource/limesdrinput/limesdrinputplugin.cpp @@ -97,7 +97,7 @@ PluginInterface::SamplingDevices LimeSDRInputPlugin::enumSampleSources() return result; } -PluginInstanceUI* LimeSDRInputPlugin::createSampleSourcePluginInstanceGUI(const QString& sourceId,QWidget **widget, DeviceSourceAPI *deviceAPI) +PluginInstanceGUI* LimeSDRInputPlugin::createSampleSourcePluginInstanceGUI(const QString& sourceId,QWidget **widget, DeviceSourceAPI *deviceAPI) { if(sourceId == m_deviceTypeID) { diff --git a/plugins/samplesource/limesdrinput/limesdrinputplugin.h b/plugins/samplesource/limesdrinput/limesdrinputplugin.h index a366d5803..ee1dc218f 100644 --- a/plugins/samplesource/limesdrinput/limesdrinputplugin.h +++ b/plugins/samplesource/limesdrinput/limesdrinputplugin.h @@ -36,7 +36,7 @@ public: void initPlugin(PluginAPI* pluginAPI); virtual SamplingDevices enumSampleSources(); - virtual PluginInstanceUI* createSampleSourcePluginInstanceGUI(const QString& sourceId, QWidget **widget, DeviceSourceAPI *deviceAPI); + virtual PluginInstanceGUI* createSampleSourcePluginInstanceGUI(const QString& sourceId, QWidget **widget, DeviceSourceAPI *deviceAPI); virtual DeviceSampleSource* createSampleSourcePluginInstanceInput(const QString& sourceId, DeviceSourceAPI *deviceAPI); static const QString m_hardwareID; diff --git a/plugins/samplesource/plutosdrinput/plutosdrinputgui.h b/plugins/samplesource/plutosdrinput/plutosdrinputgui.h index 8d74db570..e8b22eab5 100644 --- a/plugins/samplesource/plutosdrinput/plutosdrinputgui.h +++ b/plugins/samplesource/plutosdrinput/plutosdrinputgui.h @@ -17,11 +17,11 @@ #ifndef PLUGINS_SAMPLESOURCE_PLUTOSDRINPUT_PLUTOSDRINPUTGUI_H_ #define PLUGINS_SAMPLESOURCE_PLUTOSDRINPUT_PLUTOSDRINPUTGUI_H_ +#include #include #include #include -#include "plugin/plugininstanceui.h" #include "util/messagequeue.h" #include "plutosdrinputsettings.h" @@ -33,7 +33,7 @@ namespace Ui { class PlutoSDRInputGUI; } -class PlutoSDRInputGui : public QWidget, public PluginInstanceUI { +class PlutoSDRInputGui : public QWidget, public PluginInstanceGUI { Q_OBJECT public: diff --git a/plugins/samplesource/plutosdrinput/plutosdrinputplugin.cpp b/plugins/samplesource/plutosdrinput/plutosdrinputplugin.cpp index ab365852a..8dcdf86ff 100644 --- a/plugins/samplesource/plutosdrinput/plutosdrinputplugin.cpp +++ b/plugins/samplesource/plutosdrinput/plutosdrinputplugin.cpp @@ -81,7 +81,7 @@ PluginInterface::SamplingDevices PlutoSDRInputPlugin::enumSampleSources() return result; } -PluginInstanceUI* PlutoSDRInputPlugin::createSampleSourcePluginInstanceGUI(const QString& sourceId, QWidget **widget, DeviceSourceAPI *deviceAPI) +PluginInstanceGUI* PlutoSDRInputPlugin::createSampleSourcePluginInstanceGUI(const QString& sourceId, QWidget **widget, DeviceSourceAPI *deviceAPI) { if(sourceId == m_deviceTypeID) { diff --git a/plugins/samplesource/plutosdrinput/plutosdrinputplugin.h b/plugins/samplesource/plutosdrinput/plutosdrinputplugin.h index 2c3b959d1..a4feaf21f 100644 --- a/plugins/samplesource/plutosdrinput/plutosdrinputplugin.h +++ b/plugins/samplesource/plutosdrinput/plutosdrinputplugin.h @@ -36,7 +36,7 @@ public: void initPlugin(PluginAPI* pluginAPI); virtual SamplingDevices enumSampleSources(); - virtual PluginInstanceUI* createSampleSourcePluginInstanceGUI(const QString& sourceId, QWidget **widget, DeviceSourceAPI *deviceAPI); + virtual PluginInstanceGUI* createSampleSourcePluginInstanceGUI(const QString& sourceId, QWidget **widget, DeviceSourceAPI *deviceAPI); virtual DeviceSampleSource* createSampleSourcePluginInstanceInput(const QString& sourceId, DeviceSourceAPI *deviceAPI); static const QString m_hardwareID; diff --git a/plugins/samplesource/rtlsdr/rtlsdrgui.h b/plugins/samplesource/rtlsdr/rtlsdrgui.h index 6d4004b34..168a295f5 100644 --- a/plugins/samplesource/rtlsdr/rtlsdrgui.h +++ b/plugins/samplesource/rtlsdr/rtlsdrgui.h @@ -17,10 +17,10 @@ #ifndef INCLUDE_RTLSDRGUI_H #define INCLUDE_RTLSDRGUI_H +#include #include #include -#include "plugin/plugininstanceui.h" #include "util/messagequeue.h" #include "rtlsdrinput.h" @@ -32,7 +32,7 @@ namespace Ui { class RTLSDRSampleRates; } -class RTLSDRGui : public QWidget, public PluginInstanceUI { +class RTLSDRGui : public QWidget, public PluginInstanceGUI { Q_OBJECT public: diff --git a/plugins/samplesource/rtlsdr/rtlsdrplugin.cpp b/plugins/samplesource/rtlsdr/rtlsdrplugin.cpp index 757766330..7b84b270c 100644 --- a/plugins/samplesource/rtlsdr/rtlsdrplugin.cpp +++ b/plugins/samplesource/rtlsdr/rtlsdrplugin.cpp @@ -62,7 +62,7 @@ PluginInterface::SamplingDevices RTLSDRPlugin::enumSampleSources() return result; } -PluginInstanceUI* RTLSDRPlugin::createSampleSourcePluginInstanceGUI(const QString& sourceId, QWidget **widget, DeviceSourceAPI *deviceAPI) +PluginInstanceGUI* RTLSDRPlugin::createSampleSourcePluginInstanceGUI(const QString& sourceId, QWidget **widget, DeviceSourceAPI *deviceAPI) { if(sourceId == m_deviceTypeID) { RTLSDRGui* gui = new RTLSDRGui(deviceAPI); diff --git a/plugins/samplesource/rtlsdr/rtlsdrplugin.h b/plugins/samplesource/rtlsdr/rtlsdrplugin.h index 505bdd8de..72cee65ec 100644 --- a/plugins/samplesource/rtlsdr/rtlsdrplugin.h +++ b/plugins/samplesource/rtlsdr/rtlsdrplugin.h @@ -20,7 +20,7 @@ public: void initPlugin(PluginAPI* pluginAPI); virtual SamplingDevices enumSampleSources(); - virtual PluginInstanceUI* createSampleSourcePluginInstanceGUI(const QString& sourceId, QWidget **widget, DeviceSourceAPI *deviceAPI); + virtual PluginInstanceGUI* createSampleSourcePluginInstanceGUI(const QString& sourceId, QWidget **widget, DeviceSourceAPI *deviceAPI); virtual DeviceSampleSource* createSampleSourcePluginInstanceInput(const QString& sourceId, DeviceSourceAPI *deviceAPI); static const QString m_hardwareID; diff --git a/plugins/samplesource/sdrdaemonsource/sdrdaemonsourcegui.h b/plugins/samplesource/sdrdaemonsource/sdrdaemonsourcegui.h index 44cbaf9c4..dbc71a083 100644 --- a/plugins/samplesource/sdrdaemonsource/sdrdaemonsourcegui.h +++ b/plugins/samplesource/sdrdaemonsource/sdrdaemonsourcegui.h @@ -17,11 +17,11 @@ #ifndef INCLUDE_SDRDAEMONSOURCEGUI_H #define INCLUDE_SDRDAEMONSOURCEGUI_H +#include #include #include #include -#include "plugin/plugininstanceui.h" #include "util/messagequeue.h" #include "sdrdaemonsourceinput.h" @@ -32,7 +32,7 @@ namespace Ui { class SDRdaemonSourceGui; } -class SDRdaemonSourceGui : public QWidget, public PluginInstanceUI { +class SDRdaemonSourceGui : public QWidget, public PluginInstanceGUI { Q_OBJECT public: diff --git a/plugins/samplesource/sdrdaemonsource/sdrdaemonsourceplugin.cpp b/plugins/samplesource/sdrdaemonsource/sdrdaemonsourceplugin.cpp index 82caeab55..0f4417cef 100644 --- a/plugins/samplesource/sdrdaemonsource/sdrdaemonsourceplugin.cpp +++ b/plugins/samplesource/sdrdaemonsource/sdrdaemonsourceplugin.cpp @@ -70,7 +70,7 @@ PluginInterface::SamplingDevices SDRdaemonSourcePlugin::enumSampleSources() return result; } -PluginInstanceUI* SDRdaemonSourcePlugin::createSampleSourcePluginInstanceGUI(const QString& sourceId, QWidget **widget, DeviceSourceAPI *deviceAPI) +PluginInstanceGUI* SDRdaemonSourcePlugin::createSampleSourcePluginInstanceGUI(const QString& sourceId, QWidget **widget, DeviceSourceAPI *deviceAPI) { if(sourceId == m_deviceTypeID) { diff --git a/plugins/samplesource/sdrdaemonsource/sdrdaemonsourceplugin.h b/plugins/samplesource/sdrdaemonsource/sdrdaemonsourceplugin.h index d33d1ecb6..1c154d112 100644 --- a/plugins/samplesource/sdrdaemonsource/sdrdaemonsourceplugin.h +++ b/plugins/samplesource/sdrdaemonsource/sdrdaemonsourceplugin.h @@ -36,7 +36,7 @@ public: void initPlugin(PluginAPI* pluginAPI); virtual SamplingDevices enumSampleSources(); - virtual PluginInstanceUI* createSampleSourcePluginInstanceGUI(const QString& sourceId, QWidget **widget, DeviceSourceAPI *deviceAPI); + virtual PluginInstanceGUI* createSampleSourcePluginInstanceGUI(const QString& sourceId, QWidget **widget, DeviceSourceAPI *deviceAPI); virtual DeviceSampleSource* createSampleSourcePluginInstanceInput(const QString& sourceId, DeviceSourceAPI *deviceAPI); static const QString m_hardwareID; diff --git a/plugins/samplesource/sdrplay/sdrplaygui.h b/plugins/samplesource/sdrplay/sdrplaygui.h index 2824dfaae..8310c01a8 100644 --- a/plugins/samplesource/sdrplay/sdrplaygui.h +++ b/plugins/samplesource/sdrplay/sdrplaygui.h @@ -17,11 +17,11 @@ #ifndef PLUGINS_SAMPLESOURCE_SDRPLAY_SDRPLAYGUI_H_ #define PLUGINS_SAMPLESOURCE_SDRPLAY_SDRPLAYGUI_H_ +#include #include #include #include -#include "plugin/plugininstanceui.h" #include "util/messagequeue.h" #include "sdrplayinput.h" @@ -34,7 +34,7 @@ namespace Ui { class SDRPlayGui; } -class SDRPlayGui : public QWidget, public PluginInstanceUI { +class SDRPlayGui : public QWidget, public PluginInstanceGUI { Q_OBJECT public: diff --git a/plugins/samplesource/sdrplay/sdrplayplugin.cpp b/plugins/samplesource/sdrplay/sdrplayplugin.cpp index bcf0cb2f1..99553ad4b 100644 --- a/plugins/samplesource/sdrplay/sdrplayplugin.cpp +++ b/plugins/samplesource/sdrplay/sdrplayplugin.cpp @@ -83,7 +83,7 @@ PluginInterface::SamplingDevices SDRPlayPlugin::enumSampleSources() return result; } -PluginInstanceUI* SDRPlayPlugin::createSampleSourcePluginInstanceGUI(const QString& sourceId,QWidget **widget, DeviceSourceAPI *deviceAPI) +PluginInstanceGUI* SDRPlayPlugin::createSampleSourcePluginInstanceGUI(const QString& sourceId,QWidget **widget, DeviceSourceAPI *deviceAPI) { if(sourceId == m_deviceTypeID) { diff --git a/plugins/samplesource/sdrplay/sdrplayplugin.h b/plugins/samplesource/sdrplay/sdrplayplugin.h index 6015527e0..12417334d 100644 --- a/plugins/samplesource/sdrplay/sdrplayplugin.h +++ b/plugins/samplesource/sdrplay/sdrplayplugin.h @@ -36,7 +36,7 @@ public: void initPlugin(PluginAPI* pluginAPI); virtual SamplingDevices enumSampleSources(); - virtual PluginInstanceUI* createSampleSourcePluginInstanceGUI(const QString& sourceId, QWidget **widget, DeviceSourceAPI *deviceAPI); + virtual PluginInstanceGUI* createSampleSourcePluginInstanceGUI(const QString& sourceId, QWidget **widget, DeviceSourceAPI *deviceAPI); virtual DeviceSampleSource* createSampleSourcePluginInstanceInput(const QString& sourceId, DeviceSourceAPI *deviceAPI); static const QString m_hardwareID; diff --git a/sdrbase/device/devicesinkapi.cpp b/sdrbase/device/devicesinkapi.cpp index f7fc083bd..e634c5d68 100644 --- a/sdrbase/device/devicesinkapi.cpp +++ b/sdrbase/device/devicesinkapi.cpp @@ -14,7 +14,7 @@ // along with this program. If not, see . // /////////////////////////////////////////////////////////////////////////////////// -#include +#include #include "device/devicesinkapi.h" #include "device/devicesourceapi.h" #include "dsp/devicesamplesink.h" @@ -194,18 +194,18 @@ void DeviceSinkAPI::setSampleSinkPluginInterface(PluginInterface *iface) m_pluginInterface = iface; } -void DeviceSinkAPI::setSampleSinkPluginInstanceUI(PluginInstanceUI *gui) +void DeviceSinkAPI::setSampleSinkPluginInstanceUI(PluginInstanceGUI *gui) { m_sampleSinkPluginInstanceUI = gui; } -void DeviceSinkAPI::registerChannelInstance(const QString& channelName, PluginInstanceUI* pluginGUI) +void DeviceSinkAPI::registerChannelInstance(const QString& channelName, PluginInstanceGUI* pluginGUI) { m_channelInstanceRegistrations.append(ChannelInstanceRegistration(channelName, pluginGUI)); renameChannelInstances(); } -void DeviceSinkAPI::removeChannelInstance(PluginInstanceUI* pluginGUI) +void DeviceSinkAPI::removeChannelInstance(PluginInstanceGUI* pluginGUI) { for(ChannelInstanceRegistrations::iterator it = m_channelInstanceRegistrations.begin(); it != m_channelInstanceRegistrations.end(); ++it) { diff --git a/sdrbase/device/devicesinkapi.h b/sdrbase/device/devicesinkapi.h index 3f2be5c8d..45c67ec97 100644 --- a/sdrbase/device/devicesinkapi.h +++ b/sdrbase/device/devicesinkapi.h @@ -32,7 +32,7 @@ class DeviceSampleSink; class MessageQueue; class ChannelMarker; class QWidget; -class PluginInstanceUI; +class PluginInstanceGUI; class PluginAPI; class PluginInterface; class Preset; @@ -74,7 +74,7 @@ public: void setSampleSinkDisplayName(const QString& serial); void setSampleSinkSequence(int sequence); void setSampleSinkPluginInterface(PluginInterface *iface); - void setSampleSinkPluginInstanceUI(PluginInstanceUI *gui); + void setSampleSinkPluginInstanceUI(PluginInstanceGUI *gui); const QString& getHardwareId() const { return m_hardwareId; } const QString& getSampleSinkId() const { return m_sampleSinkId; } @@ -82,10 +82,10 @@ public: const QString& getSampleSinkDisplayName() const { return m_sampleSinkDisplayName; } PluginInterface *getPluginInterface() { return m_pluginInterface; } uint32_t getSampleSinkSequence() const { return m_sampleSinkSequence; } - PluginInstanceUI *getSampleSinkPluginInstanceGUI() { return m_sampleSinkPluginInstanceUI; } + PluginInstanceGUI *getSampleSinkPluginInstanceGUI() { return m_sampleSinkPluginInstanceUI; } - void registerChannelInstance(const QString& channelName, PluginInstanceUI* pluginGUI); - void removeChannelInstance(PluginInstanceUI* pluginGUI); + void registerChannelInstance(const QString& channelName, PluginInstanceGUI* pluginGUI); + void removeChannelInstance(PluginInstanceGUI* pluginGUI); void freeChannels(); @@ -115,14 +115,14 @@ protected: struct ChannelInstanceRegistration { QString m_channelName; - PluginInstanceUI* m_gui; + PluginInstanceGUI* m_gui; ChannelInstanceRegistration() : m_channelName(), m_gui(0) { } - ChannelInstanceRegistration(const QString& channelName, PluginInstanceUI* pluginGUI) : + ChannelInstanceRegistration(const QString& channelName, PluginInstanceGUI* pluginGUI) : m_channelName(channelName), m_gui(pluginGUI) { } @@ -153,7 +153,7 @@ protected: QString m_sampleSinkDisplayName; uint32_t m_sampleSinkSequence; PluginInterface* m_pluginInterface; - PluginInstanceUI* m_sampleSinkPluginInstanceUI; + PluginInstanceGUI* m_sampleSinkPluginInstanceUI; ChannelInstanceRegistrations m_channelInstanceRegistrations; diff --git a/sdrbase/device/devicesourceapi.cpp b/sdrbase/device/devicesourceapi.cpp index 2251941fe..17afc8233 100644 --- a/sdrbase/device/devicesourceapi.cpp +++ b/sdrbase/device/devicesourceapi.cpp @@ -14,7 +14,7 @@ // along with this program. If not, see . // /////////////////////////////////////////////////////////////////////////////////// -#include +#include #include "device/devicesourceapi.h" #include "device/devicesinkapi.h" #include "dsp/devicesamplesource.h" @@ -186,18 +186,18 @@ void DeviceSourceAPI::setSampleSourcePluginInterface(PluginInterface *iface) m_pluginInterface = iface; } -void DeviceSourceAPI::setSampleSourcePluginInstanceGUI(PluginInstanceUI *gui) +void DeviceSourceAPI::setSampleSourcePluginInstanceGUI(PluginInstanceGUI *gui) { m_sampleSourcePluginInstanceUI = gui; } -void DeviceSourceAPI::registerChannelInstance(const QString& channelName, PluginInstanceUI* pluginGUI) +void DeviceSourceAPI::registerChannelInstance(const QString& channelName, PluginInstanceGUI* pluginGUI) { m_channelInstanceRegistrations.append(ChannelInstanceRegistration(channelName, pluginGUI)); renameChannelInstances(); } -void DeviceSourceAPI::removeChannelInstance(PluginInstanceUI* pluginGUI) +void DeviceSourceAPI::removeChannelInstance(PluginInstanceGUI* pluginGUI) { for(ChannelInstanceRegistrations::iterator it = m_channelInstanceRegistrations.begin(); it != m_channelInstanceRegistrations.end(); ++it) { diff --git a/sdrbase/device/devicesourceapi.h b/sdrbase/device/devicesourceapi.h index b169b96de..3e9e9c6f8 100644 --- a/sdrbase/device/devicesourceapi.h +++ b/sdrbase/device/devicesourceapi.h @@ -34,7 +34,7 @@ class DeviceSampleSource; class MessageQueue; class ChannelMarker; class QWidget; -class PluginInstanceUI; +class PluginInstanceGUI; class PluginAPI; class PluginInterface; class Preset; @@ -75,7 +75,7 @@ public: void setSampleSourceDisplayName(const QString& serial); void setSampleSourceSequence(int sequence); void setSampleSourcePluginInterface(PluginInterface *iface); - void setSampleSourcePluginInstanceGUI(PluginInstanceUI *gui); + void setSampleSourcePluginInstanceGUI(PluginInstanceGUI *gui); const QString& getHardwareId() const { return m_hardwareId; } const QString& getSampleSourceId() const { return m_sampleSourceId; } @@ -83,10 +83,10 @@ public: const QString& getSampleSourceDisplayName() const { return m_sampleSourceDisplayName; } PluginInterface *getPluginInterface() { return m_pluginInterface; } uint32_t getSampleSourceSequence() const { return m_sampleSourceSequence; } - PluginInstanceUI *getSampleSourcePluginInstanceGUI() { return m_sampleSourcePluginInstanceUI; } + PluginInstanceGUI *getSampleSourcePluginInstanceGUI() { return m_sampleSourcePluginInstanceUI; } - void registerChannelInstance(const QString& channelName, PluginInstanceUI* pluginGUI); - void removeChannelInstance(PluginInstanceUI* pluginGUI); + void registerChannelInstance(const QString& channelName, PluginInstanceGUI* pluginGUI); + void removeChannelInstance(PluginInstanceGUI* pluginGUI); void freeChannels(); @@ -116,14 +116,14 @@ protected: struct ChannelInstanceRegistration { QString m_channelName; - PluginInstanceUI* m_gui; + PluginInstanceGUI* m_gui; ChannelInstanceRegistration() : m_channelName(), m_gui(NULL) { } - ChannelInstanceRegistration(const QString& channelName, PluginInstanceUI* pluginGUI) : + ChannelInstanceRegistration(const QString& channelName, PluginInstanceGUI* pluginGUI) : m_channelName(channelName), m_gui(pluginGUI) { } @@ -154,7 +154,7 @@ protected: QString m_sampleSourceDisplayName; uint32_t m_sampleSourceSequence; PluginInterface* m_pluginInterface; - PluginInstanceUI* m_sampleSourcePluginInstanceUI; + PluginInstanceGUI* m_sampleSourcePluginInstanceUI; ChannelInstanceRegistrations m_channelInstanceRegistrations; diff --git a/sdrbase/mainwindow.cpp b/sdrbase/mainwindow.cpp index 078941719..ec2896270 100644 --- a/sdrbase/mainwindow.cpp +++ b/sdrbase/mainwindow.cpp @@ -15,8 +15,8 @@ // along with this program. If not, see . // /////////////////////////////////////////////////////////////////////////////////// -#include -#include +#include +#include #include #include #include @@ -146,7 +146,7 @@ MainWindow::MainWindow(QWidget* parent) : m_deviceUIs.back()->m_deviceSourceAPI->getSampleSourceId(), m_deviceUIs.back()->m_deviceSourceAPI); m_deviceUIs.back()->m_deviceSourceAPI->setSampleSource(source); QWidget *gui; - PluginInstanceUI *pluginGUI = m_deviceUIs.back()->m_deviceSourceAPI->getPluginInterface()->createSampleSourcePluginInstanceGUI( + PluginInstanceGUI *pluginGUI = m_deviceUIs.back()->m_deviceSourceAPI->getPluginInterface()->createSampleSourcePluginInstanceGUI( m_deviceUIs.back()->m_deviceSourceAPI->getSampleSourceId(), &gui, m_deviceUIs.back()->m_deviceSourceAPI); m_deviceUIs.back()->m_deviceSourceAPI->getSampleSource()->setMessageQueueToGUI(pluginGUI->getInputMessageQueue()); m_deviceUIs.back()->m_deviceSourceAPI->setSampleSourcePluginInstanceGUI(pluginGUI); @@ -230,7 +230,7 @@ void MainWindow::addSourceDevice() m_deviceUIs.back()->m_deviceSourceAPI->getSampleSourceId(), m_deviceUIs.back()->m_deviceSourceAPI); m_deviceUIs.back()->m_deviceSourceAPI->setSampleSource(source); QWidget *gui; - PluginInstanceUI *pluginGUI = m_deviceUIs.back()->m_deviceSourceAPI->getPluginInterface()->createSampleSourcePluginInstanceGUI( + PluginInstanceGUI *pluginGUI = m_deviceUIs.back()->m_deviceSourceAPI->getPluginInterface()->createSampleSourcePluginInstanceGUI( m_deviceUIs.back()->m_deviceSourceAPI->getSampleSourceId(), &gui, m_deviceUIs.back()->m_deviceSourceAPI); m_deviceUIs.back()->m_deviceSourceAPI->getSampleSource()->setMessageQueueToGUI(pluginGUI->getInputMessageQueue()); m_deviceUIs.back()->m_deviceSourceAPI->setSampleSourcePluginInstanceGUI(pluginGUI); @@ -286,7 +286,7 @@ void MainWindow::addSinkDevice() m_deviceUIs.back()->m_deviceSinkAPI->getSampleSinkId(), m_deviceUIs.back()->m_deviceSinkAPI); m_deviceUIs.back()->m_deviceSinkAPI->setSampleSink(sink); QWidget *gui; - PluginInstanceUI *pluginUI = m_deviceUIs.back()->m_deviceSinkAPI->getPluginInterface()->createSampleSinkPluginInstanceGUI( + PluginInstanceGUI *pluginUI = m_deviceUIs.back()->m_deviceSinkAPI->getPluginInterface()->createSampleSinkPluginInstanceGUI( m_deviceUIs.back()->m_deviceSinkAPI->getSampleSinkId(), &gui, m_deviceUIs.back()->m_deviceSinkAPI); m_deviceUIs.back()->m_deviceSinkAPI->getSampleSink()->setMessageQueueToGUI(pluginUI->getInputMessageQueue()); m_deviceUIs.back()->m_deviceSinkAPI->setSampleSinkPluginInstanceUI(pluginUI); @@ -895,7 +895,7 @@ void MainWindow::on_sampleSource_confirmClicked(bool checked __attribute__((unus deviceUI->m_deviceSourceAPI->getSampleSourceId(), deviceUI->m_deviceSourceAPI); deviceUI->m_deviceSourceAPI->setSampleSource(source); QWidget *gui; - PluginInstanceUI *pluginUI = deviceUI->m_deviceSourceAPI->getPluginInterface()->createSampleSourcePluginInstanceGUI( + PluginInstanceGUI *pluginUI = deviceUI->m_deviceSourceAPI->getPluginInterface()->createSampleSourcePluginInstanceGUI( deviceUI->m_deviceSourceAPI->getSampleSourceId(), &gui, deviceUI->m_deviceSourceAPI); deviceUI->m_deviceSourceAPI->getSampleSource()->setMessageQueueToGUI(pluginUI->getInputMessageQueue()); deviceUI->m_deviceSourceAPI->setSampleSourcePluginInstanceGUI(pluginUI); @@ -974,7 +974,7 @@ void MainWindow::on_sampleSink_confirmClicked(bool checked __attribute__((unused deviceUI->m_deviceSinkAPI->getSampleSinkId(), deviceUI->m_deviceSinkAPI); deviceUI->m_deviceSinkAPI->setSampleSink(sink); QWidget *gui; - PluginInstanceUI *pluginUI = deviceUI->m_deviceSinkAPI->getPluginInterface()->createSampleSinkPluginInstanceGUI( + PluginInstanceGUI *pluginUI = deviceUI->m_deviceSinkAPI->getPluginInterface()->createSampleSinkPluginInstanceGUI( deviceUI->m_deviceSinkAPI->getSampleSinkId(), &gui, deviceUI->m_deviceSinkAPI); deviceUI->m_deviceSinkAPI->getSampleSink()->setMessageQueueToGUI(pluginUI->getInputMessageQueue()); deviceUI->m_deviceSinkAPI->setSampleSinkPluginInstanceUI(pluginUI); diff --git a/sdrbase/mainwindow.h b/sdrbase/mainwindow.h index c575ba6dd..3137730b2 100644 --- a/sdrbase/mainwindow.h +++ b/sdrbase/mainwindow.h @@ -41,7 +41,7 @@ class GLSpectrum; class GLSpectrumGUI; class ChannelWindow; class PluginAPI; -class PluginInstanceUI; +class PluginInstanceGUI; class ChannelMarker; class PluginManager; class DeviceSourceAPI; diff --git a/sdrbase/plugin/pluginapi.h b/sdrbase/plugin/pluginapi.h index ebc2d91e6..b0b5d4bcb 100644 --- a/sdrbase/plugin/pluginapi.h +++ b/sdrbase/plugin/pluginapi.h @@ -12,7 +12,7 @@ class PluginManager; class PluginInterface; class MainWindow; class MessageQueue; -class PluginInstanceUI; +class PluginInstanceGUI; class SDRANGEL_API PluginAPI : public QObject { Q_OBJECT diff --git a/sdrbase/plugin/plugininstanceui.h b/sdrbase/plugin/plugininstancegui.h similarity index 87% rename from sdrbase/plugin/plugininstanceui.h rename to sdrbase/plugin/plugininstancegui.h index 3a6a302c3..8871c1ec4 100644 --- a/sdrbase/plugin/plugininstanceui.h +++ b/sdrbase/plugin/plugininstancegui.h @@ -10,10 +10,10 @@ class Message; class MessageQueue; -class SDRANGEL_API PluginInstanceUI { +class SDRANGEL_API PluginInstanceGUI { public: - PluginInstanceUI() { }; - virtual ~PluginInstanceUI() { }; + PluginInstanceGUI() { }; + virtual ~PluginInstanceGUI() { }; virtual void destroy() = 0; diff --git a/sdrbase/plugin/plugininterface.cpp b/sdrbase/plugin/plugininterface.cpp index 38cb20750..7db1c63ed 100644 --- a/sdrbase/plugin/plugininterface.cpp +++ b/sdrbase/plugin/plugininterface.cpp @@ -1,10 +1,10 @@ +#include #include "dsp/devicesamplesource.h" #include "dsp/devicesamplesink.h" #include "plugin/plugininterface.h" -#include "plugininstanceui.h" -void PluginInterface::deleteSampleSourcePluginInstanceGUI(PluginInstanceUI *ui) +void PluginInterface::deleteSampleSourcePluginInstanceGUI(PluginInstanceGUI *ui) { ui->destroy(); } @@ -14,7 +14,7 @@ void PluginInterface::deleteSampleSourcePluginInstanceInput(DeviceSampleSource * source->destroy(); } -void PluginInterface::deleteSampleSinkPluginInstanceGUI(PluginInstanceUI *ui) +void PluginInterface::deleteSampleSinkPluginInstanceGUI(PluginInstanceGUI *ui) { ui->destroy(); } diff --git a/sdrbase/plugin/plugininterface.h b/sdrbase/plugin/plugininterface.h index 067cd1b15..612cbb05e 100644 --- a/sdrbase/plugin/plugininterface.h +++ b/sdrbase/plugin/plugininterface.h @@ -17,7 +17,7 @@ struct PluginDescriptor { class PluginAPI; class DeviceSourceAPI; class DeviceSinkAPI; -class PluginInstanceUI; +class PluginInstanceGUI; class QWidget; class DeviceSampleSource; class DeviceSampleSink; @@ -52,23 +52,23 @@ public: virtual void initPlugin(PluginAPI* pluginAPI) = 0; // channel Rx plugins - virtual PluginInstanceUI* createRxChannel(const QString& channelName __attribute__((unused)), DeviceSourceAPI *deviceAPI __attribute__((unused)) ) { return 0; } + virtual PluginInstanceGUI* createRxChannel(const QString& channelName __attribute__((unused)), DeviceSourceAPI *deviceAPI __attribute__((unused)) ) { return 0; } // channel Tx plugins - virtual PluginInstanceUI* createTxChannel(const QString& channelName __attribute__((unused)), DeviceSinkAPI *deviceAPI __attribute__((unused)) ) { return 0; } + virtual PluginInstanceGUI* createTxChannel(const QString& channelName __attribute__((unused)), DeviceSinkAPI *deviceAPI __attribute__((unused)) ) { return 0; } // device source plugins only virtual SamplingDevices enumSampleSources() { return SamplingDevices(); } - virtual PluginInstanceUI* createSampleSourcePluginInstanceGUI(const QString& sourceId __attribute__((unused)), QWidget **widget __attribute__((unused)), DeviceSourceAPI *deviceAPI __attribute__((unused))) { return 0; } + virtual PluginInstanceGUI* createSampleSourcePluginInstanceGUI(const QString& sourceId __attribute__((unused)), QWidget **widget __attribute__((unused)), DeviceSourceAPI *deviceAPI __attribute__((unused))) { return 0; } virtual DeviceSampleSource* createSampleSourcePluginInstanceInput(const QString& sourceId __attribute__((unused)), DeviceSourceAPI *deviceAPI __attribute__((unused))) { return 0; } // creates the input "core" - virtual void deleteSampleSourcePluginInstanceGUI(PluginInstanceUI *ui); + virtual void deleteSampleSourcePluginInstanceGUI(PluginInstanceGUI *ui); virtual void deleteSampleSourcePluginInstanceInput(DeviceSampleSource *source); // device sink plugins only virtual SamplingDevices enumSampleSinks() { return SamplingDevices(); } - virtual PluginInstanceUI* createSampleSinkPluginInstanceGUI(const QString& sinkId __attribute__((unused)), QWidget **widget __attribute__((unused)), DeviceSinkAPI *deviceAPI __attribute__((unused))) { return 0; } + virtual PluginInstanceGUI* createSampleSinkPluginInstanceGUI(const QString& sinkId __attribute__((unused)), QWidget **widget __attribute__((unused)), DeviceSinkAPI *deviceAPI __attribute__((unused))) { return 0; } virtual DeviceSampleSink* createSampleSinkPluginInstanceOutput(const QString& sinkId __attribute__((unused)), DeviceSinkAPI *deviceAPI __attribute__((unused))) { return 0; } // creates the output "core" - virtual void deleteSampleSinkPluginInstanceGUI(PluginInstanceUI *ui); + virtual void deleteSampleSinkPluginInstanceGUI(PluginInstanceGUI *ui); virtual void deleteSampleSinkPluginInstanceOutput(DeviceSampleSink *sink); }; diff --git a/sdrbase/plugin/pluginmanager.cpp b/sdrbase/plugin/pluginmanager.cpp index d971259f7..a318152a2 100644 --- a/sdrbase/plugin/pluginmanager.cpp +++ b/sdrbase/plugin/pluginmanager.cpp @@ -14,7 +14,7 @@ // along with this program. If not, see . // /////////////////////////////////////////////////////////////////////////////////// -#include +#include #include "device/devicesourceapi.h" #include "device/devicesinkapi.h" #include From f2ae52228dcb2563a8a4f3bf7277959ce48dac01 Mon Sep 17 00:00:00 2001 From: f4exb Date: Tue, 26 Sep 2017 16:46:19 +0200 Subject: [PATCH 23/71] Reset PluginInstanceGUI to its original name: fixed cmake file --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index f5cc99f2d..e24226041 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -397,7 +397,7 @@ set(sdrbase_HEADERS sdrbase/dsp/devicesamplesink.h sdrbase/plugin/pluginapi.h - sdrbase/plugin/plugininstanceui.h + sdrbase/plugin/plugininstancegui.h sdrbase/plugin/plugininterface.h sdrbase/plugin/pluginmanager.h From 42533f2fa369a3ce6fb896e6664a3e8104bd2623 Mon Sep 17 00:00:00 2001 From: f4exb Date: Tue, 26 Sep 2017 16:49:17 +0200 Subject: [PATCH 24/71] Fixed Windows build --- sdrbase/sdrbase.pro | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/sdrbase/sdrbase.pro b/sdrbase/sdrbase.pro index bed3eb47b..cadd268f6 100644 --- a/sdrbase/sdrbase.pro +++ b/sdrbase/sdrbase.pro @@ -119,6 +119,8 @@ SOURCES += mainwindow.cpp\ gui/mypositiondialog.cpp\ gui/scale.cpp\ gui/scaleengine.cpp\ + gui/transverterbutton.cpp\ + gui/transverterdialog.cpp\ gui/valuedial.cpp\ gui/valuedialz.cpp\ dsp/devicesamplesource.cpp\ @@ -228,12 +230,14 @@ HEADERS += mainwindow.h\ gui/mypositiondialog.h\ gui/scale.h\ gui/scaleengine.h\ + gui/transverterbutton.h\ + gui/transverterdialog.h\ gui/valuedial.h\ gui/valuedialz.h\ dsp/devicesamplesource.h\ dsp/devicesamplesink.h\ plugin/pluginapi.h\ - plugin/plugininstanceui.h\ + plugin/plugininstancegui.h\ plugin/plugininterface.h\ plugin/pluginmanager.h\ settings/preferences.h\ @@ -263,6 +267,7 @@ FORMS += mainwindow.ui\ gui/samplingdevicecontrol.ui\ gui/myposdialog.ui\ gui/glspectrumgui.ui\ + gui/transverterdialog.ui\ mainwindow.ui RESOURCES = resources/res.qrc From 69a94c6004356b4316b1a5c7e5790806237a28a3 Mon Sep 17 00:00:00 2001 From: f4exb Date: Tue, 26 Sep 2017 23:19:49 +0200 Subject: [PATCH 25/71] AM demod: use AM settings class and associated applySettings method --- plugins/channelrx/demodam/CMakeLists.txt | 2 + plugins/channelrx/demodam/amdemod.cpp | 177 +++++++++++------- plugins/channelrx/demodam/amdemod.h | 80 ++++---- plugins/channelrx/demodam/amdemodsettings.cpp | 87 +++++++++ plugins/channelrx/demodam/amdemodsettings.h | 45 +++++ 5 files changed, 285 insertions(+), 106 deletions(-) create mode 100644 plugins/channelrx/demodam/amdemodsettings.cpp create mode 100644 plugins/channelrx/demodam/amdemodsettings.h diff --git a/plugins/channelrx/demodam/CMakeLists.txt b/plugins/channelrx/demodam/CMakeLists.txt index 0c6721c3b..cbbd3ae9c 100644 --- a/plugins/channelrx/demodam/CMakeLists.txt +++ b/plugins/channelrx/demodam/CMakeLists.txt @@ -3,12 +3,14 @@ project(am) set(am_SOURCES amdemod.cpp amdemodgui.cpp + amdemodsettings.cpp amdemodplugin.cpp ) set(am_HEADERS amdemod.h amdemodgui.h + amdemodsettings.h amdemodplugin.h ) diff --git a/plugins/channelrx/demodam/amdemod.cpp b/plugins/channelrx/demodam/amdemod.cpp index f4c1f7e60..9ef6b2d57 100644 --- a/plugins/channelrx/demodam/amdemod.cpp +++ b/plugins/channelrx/demodam/amdemod.cpp @@ -43,14 +43,12 @@ AMDemod::AMDemod() : { setObjectName("AMDemod"); - m_config.m_inputSampleRate = 96000; - m_config.m_inputFrequencyOffset = 0; - m_config.m_rfBandwidth = 5000; - m_config.m_squelch = -40.0; - m_config.m_volume = 2.0; - m_config.m_audioSampleRate = DSPEngine::instance()->getAudioSampleRate(); - - apply(); +// m_config.m_inputSampleRate = 96000; +// m_config.m_inputFrequencyOffset = 0; +// m_config.m_rfBandwidth = 5000; +// m_config.m_squelch = -40.0; +// m_config.m_volume = 2.0; +// m_config.m_audioSampleRate = DSPEngine::instance()->getAudioSampleRate(); m_audioBuffer.resize(1<<14); m_audioBufferFill = 0; @@ -60,7 +58,9 @@ AMDemod::AMDemod() : m_magsq = 0.0; DSPEngine::instance()->addAudioSink(&m_audioFifo); - m_udpBufferAudio = new UDPSink(this, m_udpBlockSize, m_config.m_udpPort); + m_udpBufferAudio = new UDPSink(this, m_udpBlockSize, m_settings.m_udpPort); + + applySettings(m_settings, true); } AMDemod::~AMDemod() @@ -142,8 +142,8 @@ void AMDemod::feed(const SampleVector::const_iterator& begin, const SampleVector void AMDemod::start() { - qDebug() << "AMDemod::start: m_inputSampleRate: " << m_config.m_inputSampleRate - << " m_inputFrequencyOffset: " << m_config.m_inputFrequencyOffset; + qDebug() << "AMDemod::start: m_inputSampleRate: " << m_settings.m_inputSampleRate + << " m_inputFrequencyOffset: " << m_settings.m_inputFrequencyOffset; m_squelchCount = 0; m_audioFifo.clear(); @@ -161,41 +161,45 @@ bool AMDemod::handleMessage(const Message& cmd) { DownChannelizer::MsgChannelizerNotification& notif = (DownChannelizer::MsgChannelizerNotification&) cmd; - m_config.m_inputSampleRate = notif.getSampleRate(); - m_config.m_inputFrequencyOffset = notif.getFrequencyOffset(); + AMDemodSettings settings = m_settings; - apply(); + settings.m_inputSampleRate = notif.getSampleRate(); + settings.m_inputFrequencyOffset = notif.getFrequencyOffset(); - qDebug() << "AMDemod::handleMessage: MsgChannelizerNotification:" - << " m_inputSampleRate: " << m_config.m_inputSampleRate - << " m_inputFrequencyOffset: " << m_config.m_inputFrequencyOffset; + applySettings(settings); + + qDebug() << "AMDemod::handleMessage: MsgChannelizerNotification:" + << " m_inputSampleRate: " << settings.m_inputSampleRate + << " m_inputFrequencyOffset: " << settings.m_inputFrequencyOffset; return true; } else if (MsgConfigureAMDemod::match(cmd)) { - MsgConfigureAMDemod& cfg = (MsgConfigureAMDemod&) cmd; + MsgConfigureAMDemod& cfg = (MsgConfigureAMDemod&) cmd; - m_config.m_rfBandwidth = cfg.getRFBandwidth(); - m_config.m_volume = cfg.getVolume(); - m_config.m_squelch = cfg.getSquelch(); - m_config.m_audioMute = cfg.getAudioMute(); - m_config.m_bandpassEnable = cfg.getBandpassEnable(); - m_config.m_copyAudioToUDP = cfg.getCopyAudioToUDP(); - m_config.m_udpAddress = cfg.getUDPAddress(); - m_config.m_udpPort = cfg.getUDPPort(); + AMDemodSettings settings = m_settings; - apply(cfg.getForce()); + settings.m_rfBandwidth = cfg.getRFBandwidth(); + settings.m_volume = cfg.getVolume(); + settings.m_squelch = cfg.getSquelch(); + settings.m_audioMute = cfg.getAudioMute(); + settings.m_bandpassEnable = cfg.getBandpassEnable(); + settings.m_copyAudioToUDP = cfg.getCopyAudioToUDP(); + settings.m_udpAddress = cfg.getUDPAddress(); + settings.m_udpPort = cfg.getUDPPort(); - qDebug() << "AMDemod::handleMessage: MsgConfigureAMDemod:" - << " m_rfBandwidth: " << m_config.m_rfBandwidth - << " m_volume: " << m_config.m_volume - << " m_squelch: " << m_config.m_squelch - << " m_audioMute: " << m_config.m_audioMute - << " m_bandpassEnable: " << m_config.m_bandpassEnable - << " m_copyAudioToUDP: " << m_config.m_copyAudioToUDP - << " m_udpAddress: " << m_config.m_udpAddress - << " m_udpPort: " << m_config.m_udpPort; + applySettings(settings); + + qDebug() << "AMDemod::handleMessage: MsgConfigureAMDemod:" + << " m_rfBandwidth: " << settings.m_rfBandwidth + << " m_volume: " << settings.m_volume + << " m_squelch: " << settings.m_squelch + << " m_audioMute: " << settings.m_audioMute + << " m_bandpassEnable: " << settings.m_bandpassEnable + << " m_copyAudioToUDP: " << settings.m_copyAudioToUDP + << " m_udpAddress: " << settings.m_udpAddress + << " m_udpPort: " << settings.m_udpPort; return true; } @@ -205,40 +209,77 @@ bool AMDemod::handleMessage(const Message& cmd) } } -void AMDemod::apply(bool force) +//void AMDemod::apply(bool force) +//{ +// +// if ((m_config.m_inputFrequencyOffset != m_running.m_inputFrequencyOffset) || +// (m_config.m_inputSampleRate != m_running.m_inputSampleRate) || force) +// { +// m_nco.setFreq(-m_config.m_inputFrequencyOffset, m_config.m_inputSampleRate); +// } +// +// if((m_config.m_inputSampleRate != m_running.m_inputSampleRate) || +// (m_config.m_rfBandwidth != m_running.m_rfBandwidth) || +// (m_config.m_audioSampleRate != m_running.m_audioSampleRate) || +// (m_config.m_bandpassEnable != m_running.m_bandpassEnable) || force) +// { +// m_settingsMutex.lock(); +// m_interpolator.create(16, m_config.m_inputSampleRate, m_config.m_rfBandwidth / 2.2f); +// m_interpolatorDistanceRemain = 0; +// m_interpolatorDistance = (Real) m_config.m_inputSampleRate / (Real) m_config.m_audioSampleRate; +// m_bandpass.create(301, m_config.m_audioSampleRate, 300.0, m_config.m_rfBandwidth / 2.0f); +// m_settingsMutex.unlock(); +// } +// +// if ((m_config.m_squelch != m_running.m_squelch) || force) +// { +// m_squelchLevel = pow(10.0, m_config.m_squelch / 20.0); +// m_squelchLevel *= m_squelchLevel; +// qDebug("AMDemod::applySettings: m_squelchLevel: %f", m_squelchLevel); +// } +// +// if ((m_config.m_udpAddress != m_running.m_udpAddress) +// || (m_config.m_udpPort != m_running.m_udpPort) || force) +// { +// m_udpBufferAudio->setAddress(m_config.m_udpAddress); +// m_udpBufferAudio->setPort(m_config.m_udpPort); +// } +// +// m_running = m_config; +//} + +void AMDemod::applySettings(const AMDemodSettings& settings, bool force) { - - if ((m_config.m_inputFrequencyOffset != m_running.m_inputFrequencyOffset) || - (m_config.m_inputSampleRate != m_running.m_inputSampleRate) || force) - { - m_nco.setFreq(-m_config.m_inputFrequencyOffset, m_config.m_inputSampleRate); - } - - if((m_config.m_inputSampleRate != m_running.m_inputSampleRate) || - (m_config.m_rfBandwidth != m_running.m_rfBandwidth) || - (m_config.m_audioSampleRate != m_running.m_audioSampleRate) || - (m_config.m_bandpassEnable != m_running.m_bandpassEnable) || force) - { - m_settingsMutex.lock(); - m_interpolator.create(16, m_config.m_inputSampleRate, m_config.m_rfBandwidth / 2.2f); - m_interpolatorDistanceRemain = 0; - m_interpolatorDistance = (Real) m_config.m_inputSampleRate / (Real) m_config.m_audioSampleRate; - m_bandpass.create(301, m_config.m_audioSampleRate, 300.0, m_config.m_rfBandwidth / 2.0f); - m_settingsMutex.unlock(); - } - - if ((m_config.m_squelch != m_running.m_squelch) || force) - { - m_squelchLevel = pow(10.0, m_config.m_squelch / 20.0); - m_squelchLevel *= m_squelchLevel; - } - - if ((m_config.m_udpAddress != m_running.m_udpAddress) - || (m_config.m_udpPort != m_running.m_udpPort) || force) + if ((m_settings.m_inputFrequencyOffset != settings.m_inputFrequencyOffset) || + (m_settings.m_inputSampleRate != settings.m_inputSampleRate) || force) { - m_udpBufferAudio->setAddress(m_config.m_udpAddress); - m_udpBufferAudio->setPort(m_config.m_udpPort); + m_nco.setFreq(-settings.m_inputFrequencyOffset, settings.m_inputSampleRate); } - m_running = m_config; + if((m_settings.m_inputSampleRate != settings.m_inputSampleRate) || + (m_settings.m_rfBandwidth != settings.m_rfBandwidth) || + (m_settings.m_audioSampleRate != settings.m_audioSampleRate) || + (m_settings.m_bandpassEnable != settings.m_bandpassEnable) || force) + { + m_settingsMutex.lock(); + m_interpolator.create(16, settings.m_inputSampleRate, settings.m_rfBandwidth / 2.2f); + m_interpolatorDistanceRemain = 0; + m_interpolatorDistance = (Real) settings.m_inputSampleRate / (Real) settings.m_audioSampleRate; + m_bandpass.create(301, settings.m_audioSampleRate, 300.0, settings.m_rfBandwidth / 2.0f); + m_settingsMutex.unlock(); + } + + if ((m_settings.m_squelch != settings.m_squelch) || force) + { + m_squelchLevel = pow(10.0, settings.m_squelch / 10.0); + } + + if ((m_settings.m_udpAddress != settings.m_udpAddress) + || (m_settings.m_udpPort != settings.m_udpPort) || force) + { + m_udpBufferAudio->setAddress(const_cast(settings.m_udpAddress)); + m_udpBufferAudio->setPort(settings.m_udpPort); + } + + m_settings = settings; } diff --git a/plugins/channelrx/demodam/amdemod.h b/plugins/channelrx/demodam/amdemod.h index 2bf2ad7ca..3e459807d 100644 --- a/plugins/channelrx/demodam/amdemod.h +++ b/plugins/channelrx/demodam/amdemod.h @@ -27,6 +27,7 @@ #include "dsp/bandpass.h" #include "audio/audiofifo.h" #include "util/message.h" +#include "amdemodsettings.h" class AMDemod : public BasebandSampleSink { Q_OBJECT @@ -137,36 +138,37 @@ private: RSRunning }; - struct Config { - int m_inputSampleRate; - qint64 m_inputFrequencyOffset; - Real m_rfBandwidth; - Real m_squelch; - Real m_volume; - quint32 m_audioSampleRate; - bool m_audioMute; - bool m_bandpassEnable; - bool m_copyAudioToUDP; - QString m_udpAddress; - quint16 m_udpPort; +// struct Config { +// int m_inputSampleRate; +// qint64 m_inputFrequencyOffset; +// Real m_rfBandwidth; +// Real m_squelch; +// Real m_volume; +// quint32 m_audioSampleRate; +// bool m_audioMute; +// bool m_bandpassEnable; +// bool m_copyAudioToUDP; +// QString m_udpAddress; +// quint16 m_udpPort; +// +// Config() : +// m_inputSampleRate(-1), +// m_inputFrequencyOffset(0), +// m_rfBandwidth(-1), +// m_squelch(0), +// m_volume(0), +// m_audioSampleRate(0), +// m_audioMute(false), +// m_bandpassEnable(false), +// m_copyAudioToUDP(false), +// m_udpAddress("127.0.0.1"), +// m_udpPort(9999) +// { } +// }; - Config() : - m_inputSampleRate(-1), - m_inputFrequencyOffset(0), - m_rfBandwidth(-1), - m_squelch(0), - m_volume(0), - m_audioSampleRate(0), - m_audioMute(false), - m_bandpassEnable(false), - m_copyAudioToUDP(false), - m_udpAddress("127.0.0.1"), - m_udpPort(9999) - { } - }; - - Config m_config; - Config m_running; + AMDemodSettings m_settings; +// Config m_config; +// Config m_running; NCO m_nco; Interpolator m_interpolator; @@ -194,7 +196,8 @@ private: QMutex m_settingsMutex; - void apply(bool force = false); +// void apply(bool force = false); + void applySettings(const AMDemodSettings& settings, bool force = false); void processOneSample(Complex &ci) { @@ -213,9 +216,9 @@ private: if (m_magsq >= m_squelchLevel) { - if (m_squelchCount <= m_running.m_audioSampleRate / 10) + if (m_squelchCount <= m_settings.m_audioSampleRate / 10) { - if (m_squelchCount == m_running.m_audioSampleRate / 20) { + if (m_squelchCount == m_settings.m_audioSampleRate / 20) { m_volumeAGC.fill(1.0); } @@ -232,28 +235,28 @@ private: qint16 sample; - if ((m_squelchCount >= m_running.m_audioSampleRate / 20) && !m_running.m_audioMute) + if ((m_squelchCount >= m_settings.m_audioSampleRate / 20) && !m_settings.m_audioMute) { Real demod = sqrt(magsq); m_volumeAGC.feed(demod); demod = (demod - m_volumeAGC.getValue()) / m_volumeAGC.getValue(); - if (m_running.m_bandpassEnable) + if (m_settings.m_bandpassEnable) { demod = m_bandpass.filter(demod); demod /= 301.0f; } - Real attack = (m_squelchCount - 0.05f * m_running.m_audioSampleRate) / (0.05f * m_running.m_audioSampleRate); - sample = demod * attack * 2048 * m_running.m_volume; - if (m_running.m_copyAudioToUDP) m_udpBufferAudio->write(demod * attack * 32768); + Real attack = (m_squelchCount - 0.05f * m_settings.m_audioSampleRate) / (0.05f * m_settings.m_audioSampleRate); + sample = demod * attack * 2048 * m_settings.m_volume; + if (m_settings.m_copyAudioToUDP) m_udpBufferAudio->write(demod * attack * 32768); m_squelchOpen = true; } else { sample = 0; - if (m_running.m_copyAudioToUDP) m_udpBufferAudio->write(0); + if (m_settings.m_copyAudioToUDP) m_udpBufferAudio->write(0); m_squelchOpen = false; } @@ -273,6 +276,7 @@ private: m_audioBufferFill = 0; } } + }; #endif // INCLUDE_AMDEMOD_H diff --git a/plugins/channelrx/demodam/amdemodsettings.cpp b/plugins/channelrx/demodam/amdemodsettings.cpp new file mode 100644 index 000000000..d5a969368 --- /dev/null +++ b/plugins/channelrx/demodam/amdemodsettings.cpp @@ -0,0 +1,87 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2015 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 // +// // +// This program is distributed in the hope that it will be useful, // +// but WITHOUT ANY WARRANTY; without even the implied warranty of // +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // +// GNU General Public License V3 for more details. // +// // +// You should have received a copy of the GNU General Public License // +// along with this program. If not, see . // +/////////////////////////////////////////////////////////////////////////////////// + +#include "dsp/dspengine.h" +#include "util/simpleserializer.h" +#include "amdemodsettings.h" + +AMDemodSettings::AMDemodSettings() +{ + resetToDefaults(); +} + +void AMDemodSettings::resetToDefaults() +{ + m_inputSampleRate = 96000; + m_inputFrequencyOffset = 0; + m_rfBandwidth = 5000; + m_squelch = -40.0; + m_volume = 2.0; + m_audioSampleRate = DSPEngine::instance()->getAudioSampleRate(); + m_audioMute = false; + m_bandpassEnable = false; + m_copyAudioToUDP = false; + m_udpAddress = "127.0.0.1"; + m_udpPort = 9999; +} + +QByteArray AMDemodSettings::serialize() const +{ + SimpleSerializer s(1); + s.writeS32(1, m_inputFrequencyOffset); + s.writeS32(2, m_rfBandwidth/1000); + s.writeS32(4, m_volume*10); + s.writeS32(5, m_squelch*10); + s.writeBlob(6, m_channelMarkerBytes); + s.writeBool(8, m_bandpassEnable); + return s.final(); +} + +bool AMDemodSettings::deserialize(const QByteArray& data) +{ + SimpleDeserializer d(data); + + if(!d.isValid()) + { + resetToDefaults(); + return false; + } + + if(d.getVersion() == 1) + { + QByteArray bytetmp; + qint32 tmp; + QString strtmp; + + d.readS32(1, &m_inputFrequencyOffset, 0); + d.readS32(2, &tmp, 4); + m_rfBandwidth = 1000 * tmp; + d.readS32(4, &tmp, 20); + m_volume = tmp * 0.1; + d.readS32(5, &tmp, -40); + m_squelch = tmp * 0.1; + d.readBlob(6, &m_channelMarkerBytes); + d.readBool(8, &m_bandpassEnable, false); + return true; + } + else + { + resetToDefaults(); + return false; + } +} + + diff --git a/plugins/channelrx/demodam/amdemodsettings.h b/plugins/channelrx/demodam/amdemodsettings.h new file mode 100644 index 000000000..fb54136d5 --- /dev/null +++ b/plugins/channelrx/demodam/amdemodsettings.h @@ -0,0 +1,45 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2015 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 // +// // +// This program is distributed in the hope that it will be useful, // +// but WITHOUT ANY WARRANTY; without even the implied warranty of // +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // +// GNU General Public License V3 for more details. // +// // +// You should have received a copy of the GNU General Public License // +// along with this program. If not, see . // +/////////////////////////////////////////////////////////////////////////////////// + +#ifndef PLUGINS_CHANNELRX_DEMODAM_AMDEMODSETTINGS_H_ +#define PLUGINS_CHANNELRX_DEMODAM_AMDEMODSETTINGS_H_ + +#include + +struct AMDemodSettings +{ + int m_inputSampleRate; + qint32 m_inputFrequencyOffset; + Real m_rfBandwidth; + Real m_squelch; + Real m_volume; + quint32 m_audioSampleRate; + bool m_audioMute; + bool m_bandpassEnable; + bool m_copyAudioToUDP; + QString m_udpAddress; + quint16 m_udpPort; + QByteArray m_channelMarkerBytes; + + AMDemodSettings(); + void resetToDefaults(); + QByteArray serialize() const; + bool deserialize(const QByteArray& data); +}; + + + +#endif /* PLUGINS_CHANNELRX_DEMODAM_AMDEMODSETTINGS_H_ */ From 1bb612bf624a8849979133235a0b8b65d3c39e40 Mon Sep 17 00:00:00 2001 From: f4exb Date: Tue, 26 Sep 2017 23:53:35 +0200 Subject: [PATCH 26/71] AM demod: use settings object to apply settings --- plugins/channelrx/demodam/amdemod.cpp | 7 --- plugins/channelrx/demodam/amdemod.h | 30 ---------- plugins/channelrx/demodam/amdemodgui.cpp | 76 ++++++++++++++++++++---- plugins/channelrx/demodam/amdemodgui.h | 3 + 4 files changed, 66 insertions(+), 50 deletions(-) diff --git a/plugins/channelrx/demodam/amdemod.cpp b/plugins/channelrx/demodam/amdemod.cpp index 9ef6b2d57..5cbfbb8d7 100644 --- a/plugins/channelrx/demodam/amdemod.cpp +++ b/plugins/channelrx/demodam/amdemod.cpp @@ -43,13 +43,6 @@ AMDemod::AMDemod() : { setObjectName("AMDemod"); -// m_config.m_inputSampleRate = 96000; -// m_config.m_inputFrequencyOffset = 0; -// m_config.m_rfBandwidth = 5000; -// m_config.m_squelch = -40.0; -// m_config.m_volume = 2.0; -// m_config.m_audioSampleRate = DSPEngine::instance()->getAudioSampleRate(); - m_audioBuffer.resize(1<<14); m_audioBufferFill = 0; diff --git a/plugins/channelrx/demodam/amdemod.h b/plugins/channelrx/demodam/amdemod.h index 3e459807d..10ea0e9e7 100644 --- a/plugins/channelrx/demodam/amdemod.h +++ b/plugins/channelrx/demodam/amdemod.h @@ -138,37 +138,7 @@ private: RSRunning }; -// struct Config { -// int m_inputSampleRate; -// qint64 m_inputFrequencyOffset; -// Real m_rfBandwidth; -// Real m_squelch; -// Real m_volume; -// quint32 m_audioSampleRate; -// bool m_audioMute; -// bool m_bandpassEnable; -// bool m_copyAudioToUDP; -// QString m_udpAddress; -// quint16 m_udpPort; -// -// Config() : -// m_inputSampleRate(-1), -// m_inputFrequencyOffset(0), -// m_rfBandwidth(-1), -// m_squelch(0), -// m_volume(0), -// m_audioSampleRate(0), -// m_audioMute(false), -// m_bandpassEnable(false), -// m_copyAudioToUDP(false), -// m_udpAddress("127.0.0.1"), -// m_udpPort(9999) -// { } -// }; - AMDemodSettings m_settings; -// Config m_config; -// Config m_running; NCO m_nco; Interpolator m_interpolator; diff --git a/plugins/channelrx/demodam/amdemodgui.cpp b/plugins/channelrx/demodam/amdemodgui.cpp index f8a238cf4..3f5fe156e 100644 --- a/plugins/channelrx/demodam/amdemodgui.cpp +++ b/plugins/channelrx/demodam/amdemodgui.cpp @@ -155,6 +155,9 @@ bool AMDemodGUI::handleMessage(const Message& message __attribute__((unused))) void AMDemodGUI::channelMarkerChanged() { this->setWindowTitle(m_channelMarker.getTitle()); + m_settings.m_inputFrequencyOffset = m_channelMarker.getCenterFrequency(); + m_settings.m_udpAddress = m_channelMarker.getUDPAddress(), + m_settings.m_udpPort = m_channelMarker.getUDPSendPort(), displayUDPAddress(); applySettings(); } @@ -162,10 +165,13 @@ void AMDemodGUI::channelMarkerChanged() void AMDemodGUI::on_deltaFrequency_changed(qint64 value) { m_channelMarker.setCenterFrequency(value); + m_settings.m_inputFrequencyOffset = m_channelMarker.getCenterFrequency(); + applySettings(); } -void AMDemodGUI::on_bandpassEnable_toggled(bool checked __attribute__((unused))) +void AMDemodGUI::on_bandpassEnable_toggled(bool checked) { + m_settings.m_bandpassEnable = checked; applySettings(); } @@ -173,28 +179,33 @@ void AMDemodGUI::on_rfBW_valueChanged(int value) { ui->rfBWText->setText(QString("%1 kHz").arg(value / 10.0, 0, 'f', 1)); m_channelMarker.setBandwidth(value * 100); + m_settings.m_rfBandwidth = value * 100; applySettings(); } void AMDemodGUI::on_volume_valueChanged(int value) { ui->volumeText->setText(QString("%1").arg(value / 10.0, 0, 'f', 1)); + m_settings.m_volume = value / 10.0; applySettings(); } void AMDemodGUI::on_squelch_valueChanged(int value) { ui->squelchText->setText(QString("%1 dB").arg(value)); + m_settings.m_squelch = value; applySettings(); } -void AMDemodGUI::on_audioMute_toggled(bool checked __attribute__((unused))) +void AMDemodGUI::on_audioMute_toggled(bool checked) { + m_settings.m_audioMute = checked; applySettings(); } -void AMDemodGUI::on_copyAudioToUDP_toggled(bool checked __attribute__((unused))) +void AMDemodGUI::on_copyAudioToUDP_toggled(bool checked) { + m_settings.m_copyAudioToUDP = checked; applySettings(); } @@ -257,6 +268,7 @@ AMDemodGUI::AMDemodGUI(PluginAPI* pluginAPI, DeviceSourceAPI *deviceAPI, QWidget m_deviceAPI->addChannelMarker(&m_channelMarker); m_deviceAPI->addRollupWidget(this); + displaySettings(); applySettings(true); } @@ -288,19 +300,57 @@ void AMDemodGUI::applySettings(bool force) ui->deltaFrequency->setValue(m_channelMarker.getCenterFrequency()); - m_amDemod->configure(m_amDemod->getInputMessageQueue(), - ui->rfBW->value() * 100.0, - ui->volume->value() / 10.0, - ui->squelch->value(), - ui->audioMute->isChecked(), - ui->bandpassEnable->isChecked(), - ui->copyAudioToUDP->isChecked(), - m_channelMarker.getUDPAddress(), - m_channelMarker.getUDPSendPort(), - force); +// m_amDemod->configure(m_amDemod->getInputMessageQueue(), +// ui->rfBW->value() * 100.0, +// ui->volume->value() / 10.0, +// ui->squelch->value(), +// ui->audioMute->isChecked(), +// ui->bandpassEnable->isChecked(), +// ui->copyAudioToUDP->isChecked(), +// m_channelMarker.getUDPAddress(), +// m_channelMarker.getUDPSendPort(), +// force); + + m_amDemod->configure(m_amDemod->getInputMessageQueue(), + m_settings.m_rfBandwidth, + m_settings.m_volume, + m_settings.m_squelch, + m_settings.m_audioMute, + m_settings.m_bandpassEnable, + m_settings.m_copyAudioToUDP, + m_settings.m_udpAddress, + m_settings.m_udpPort, + force); + } } +void AMDemodGUI::displaySettings() +{ + blockApplySettings(true); + + int displayValue = m_settings.m_rfBandwidth/100.0; + ui->rfBW->setValue(displayValue); + ui->rfBWText->setText(QString("%1 kHz").arg(displayValue / 10.0, 0, 'f', 1)); + m_channelMarker.setBandwidth(m_settings.m_rfBandwidth); + + ui->volume->setValue(m_settings.m_volume * 10.0); + ui->volumeText->setText(QString("%1").arg(m_settings.m_volume, 0, 'f', 1)); + + ui->squelch->setValue(m_settings.m_squelch); + ui->squelchText->setText(QString("%1 dB").arg(m_settings.m_squelch)); + + ui->audioMute->setChecked(m_settings.m_audioMute); + ui->bandpassEnable->setChecked(m_settings.m_bandpassEnable); + ui->copyAudioToUDP->setChecked(m_settings.m_copyAudioToUDP); + + m_channelMarker.setCenterFrequency(m_settings.m_inputFrequencyOffset); + m_channelMarker.setUDPAddress(m_settings.m_udpAddress); + m_channelMarker.setUDPSendPort(m_settings.m_udpPort); + + blockApplySettings(false); +} + void AMDemodGUI::displayUDPAddress() { ui->copyAudioToUDP->setToolTip(QString("Copy audio output to UDP %1:%2").arg(m_channelMarker.getUDPAddress()).arg(m_channelMarker.getUDPSendPort())); diff --git a/plugins/channelrx/demodam/amdemodgui.h b/plugins/channelrx/demodam/amdemodgui.h index de9c20d6e..909e39cef 100644 --- a/plugins/channelrx/demodam/amdemodgui.h +++ b/plugins/channelrx/demodam/amdemodgui.h @@ -6,6 +6,7 @@ #include "dsp/channelmarker.h" #include "dsp/movingaverage.h" #include "util/messagequeue.h" +#include "amdemodsettings.h" class PluginAPI; class DeviceSourceAPI; @@ -56,6 +57,7 @@ private: PluginAPI* m_pluginAPI; DeviceSourceAPI* m_deviceAPI; ChannelMarker m_channelMarker; + AMDemodSettings m_settings; bool m_doApplySettings; ThreadedBasebandSampleSink* m_threadedChannelizer; @@ -70,6 +72,7 @@ private: void blockApplySettings(bool block); void applySettings(bool force = false); + void displaySettings(); void displayUDPAddress(); void leaveEvent(QEvent*); From 7159ffff09ca870d6b0f0ec5948a0993a80a02d5 Mon Sep 17 00:00:00 2001 From: f4exb Date: Wed, 27 Sep 2017 00:16:35 +0200 Subject: [PATCH 27/71] AM Demod: use settings object to pass data from GUI to demod --- plugins/channelrx/demodam/amdemod.cpp | 80 ++---------------- plugins/channelrx/demodam/amdemod.h | 102 +++++------------------ plugins/channelrx/demodam/amdemodgui.cpp | 26 +----- 3 files changed, 32 insertions(+), 176 deletions(-) diff --git a/plugins/channelrx/demodam/amdemod.cpp b/plugins/channelrx/demodam/amdemod.cpp index 5cbfbb8d7..13b29cd30 100644 --- a/plugins/channelrx/demodam/amdemod.cpp +++ b/plugins/channelrx/demodam/amdemod.cpp @@ -62,29 +62,6 @@ AMDemod::~AMDemod() delete m_udpBufferAudio; } -void AMDemod::configure(MessageQueue* messageQueue, - Real rfBandwidth, - Real volume, - Real squelch, - bool audioMute, - bool bandpassEnable, - bool copyAudioToUDP, - const QString& udpAddress, - quint16 udpPort, - bool force) -{ - Message* cmd = MsgConfigureAMDemod::create(rfBandwidth, - volume, - squelch, - audioMute, - bandpassEnable, - copyAudioToUDP, - udpAddress, - udpPort, - force); - messageQueue->push(cmd); -} - void AMDemod::feed(const SampleVector::const_iterator& begin, const SampleVector::const_iterator& end, bool firstOfBurst __attribute__((unused))) { Complex ci; @@ -171,18 +148,13 @@ bool AMDemod::handleMessage(const Message& cmd) { MsgConfigureAMDemod& cfg = (MsgConfigureAMDemod&) cmd; - AMDemodSettings settings = m_settings; + AMDemodSettings settings = cfg.getSettings(); - settings.m_rfBandwidth = cfg.getRFBandwidth(); - settings.m_volume = cfg.getVolume(); - settings.m_squelch = cfg.getSquelch(); - settings.m_audioMute = cfg.getAudioMute(); - settings.m_bandpassEnable = cfg.getBandpassEnable(); - settings.m_copyAudioToUDP = cfg.getCopyAudioToUDP(); - settings.m_udpAddress = cfg.getUDPAddress(); - settings.m_udpPort = cfg.getUDPPort(); + // These settings are set with DownChannelizer::MsgChannelizerNotification + settings.m_inputSampleRate = m_settings.m_inputSampleRate; + settings.m_inputFrequencyOffset = m_settings.m_inputFrequencyOffset; - applySettings(settings); + applySettings(settings, cfg.getForce()); qDebug() << "AMDemod::handleMessage: MsgConfigureAMDemod:" << " m_rfBandwidth: " << settings.m_rfBandwidth @@ -192,7 +164,8 @@ bool AMDemod::handleMessage(const Message& cmd) << " m_bandpassEnable: " << settings.m_bandpassEnable << " m_copyAudioToUDP: " << settings.m_copyAudioToUDP << " m_udpAddress: " << settings.m_udpAddress - << " m_udpPort: " << settings.m_udpPort; + << " m_udpPort: " << settings.m_udpPort + << " force: " << cfg.getForce(); return true; } @@ -202,45 +175,6 @@ bool AMDemod::handleMessage(const Message& cmd) } } -//void AMDemod::apply(bool force) -//{ -// -// if ((m_config.m_inputFrequencyOffset != m_running.m_inputFrequencyOffset) || -// (m_config.m_inputSampleRate != m_running.m_inputSampleRate) || force) -// { -// m_nco.setFreq(-m_config.m_inputFrequencyOffset, m_config.m_inputSampleRate); -// } -// -// if((m_config.m_inputSampleRate != m_running.m_inputSampleRate) || -// (m_config.m_rfBandwidth != m_running.m_rfBandwidth) || -// (m_config.m_audioSampleRate != m_running.m_audioSampleRate) || -// (m_config.m_bandpassEnable != m_running.m_bandpassEnable) || force) -// { -// m_settingsMutex.lock(); -// m_interpolator.create(16, m_config.m_inputSampleRate, m_config.m_rfBandwidth / 2.2f); -// m_interpolatorDistanceRemain = 0; -// m_interpolatorDistance = (Real) m_config.m_inputSampleRate / (Real) m_config.m_audioSampleRate; -// m_bandpass.create(301, m_config.m_audioSampleRate, 300.0, m_config.m_rfBandwidth / 2.0f); -// m_settingsMutex.unlock(); -// } -// -// if ((m_config.m_squelch != m_running.m_squelch) || force) -// { -// m_squelchLevel = pow(10.0, m_config.m_squelch / 20.0); -// m_squelchLevel *= m_squelchLevel; -// qDebug("AMDemod::applySettings: m_squelchLevel: %f", m_squelchLevel); -// } -// -// if ((m_config.m_udpAddress != m_running.m_udpAddress) -// || (m_config.m_udpPort != m_running.m_udpPort) || force) -// { -// m_udpBufferAudio->setAddress(m_config.m_udpAddress); -// m_udpBufferAudio->setPort(m_config.m_udpPort); -// } -// -// m_running = m_config; -//} - void AMDemod::applySettings(const AMDemodSettings& settings, bool force) { if ((m_settings.m_inputFrequencyOffset != settings.m_inputFrequencyOffset) || diff --git a/plugins/channelrx/demodam/amdemod.h b/plugins/channelrx/demodam/amdemod.h index 10ea0e9e7..5f725b72e 100644 --- a/plugins/channelrx/demodam/amdemod.h +++ b/plugins/channelrx/demodam/amdemod.h @@ -32,20 +32,32 @@ class AMDemod : public BasebandSampleSink { Q_OBJECT public: + class MsgConfigureAMDemod : public Message { + MESSAGE_CLASS_DECLARATION + + public: + const AMDemodSettings& getSettings() const { return m_settings; } + bool getForce() const { return m_force; } + + static MsgConfigureAMDemod* create(const AMDemodSettings& settings, bool force) + { + return new MsgConfigureAMDemod(settings, force); + } + + private: + AMDemodSettings m_settings; + bool m_force; + + MsgConfigureAMDemod(const AMDemodSettings& settings, bool force) : + Message(), + m_settings(settings), + m_force(force) + { } + }; + AMDemod(); ~AMDemod(); - void configure(MessageQueue* messageQueue, - Real rfBandwidth, - Real volume, - Real squelch, - bool audioMute, - bool bandpassEnable, - bool copyAudioToUDP, - const QString& udpAddress, - quint16 udpPort, - bool force); - virtual void feed(const SampleVector::const_iterator& begin, const SampleVector::const_iterator& end, bool po); virtual void start(); virtual void stop(); @@ -65,74 +77,6 @@ public: } private: - class MsgConfigureAMDemod : public Message { - MESSAGE_CLASS_DECLARATION - - public: - Real getRFBandwidth() const { return m_rfBandwidth; } - Real getVolume() const { return m_volume; } - Real getSquelch() const { return m_squelch; } - bool getAudioMute() const { return m_audioMute; } - bool getBandpassEnable() const { return m_bandpassEnable; } - bool getCopyAudioToUDP() const { return m_copyAudioToUDP; } - const QString& getUDPAddress() const { return m_udpAddress; } - quint16 getUDPPort() const { return m_udpPort; } - bool getForce() const { return m_force; } - - static MsgConfigureAMDemod* create(Real rfBandwidth, - Real volume, - Real squelch, - bool audioMute, - bool bandpassEnable, - bool copyAudioToUDP, - const QString& udpAddress, - quint16 udpPort, - bool force) - { - return new MsgConfigureAMDemod(rfBandwidth, - volume, - squelch, - audioMute, - bandpassEnable, - copyAudioToUDP, - udpAddress, - udpPort, - force); - } - - private: - Real m_rfBandwidth; - Real m_volume; - Real m_squelch; - bool m_audioMute; - bool m_bandpassEnable; - bool m_copyAudioToUDP; - QString m_udpAddress; - quint16 m_udpPort; - bool m_force; - - MsgConfigureAMDemod(Real rfBandwidth, - Real volume, - Real squelch, - bool audioMute, - bool bandpassEnable, - bool copyAudioToUDP, - const QString& udpAddress, - quint16 udpPort, - bool force) : - Message(), - m_rfBandwidth(rfBandwidth), - m_volume(volume), - m_squelch(squelch), - m_audioMute(audioMute), - m_bandpassEnable(bandpassEnable), - m_copyAudioToUDP(copyAudioToUDP), - m_udpAddress(udpAddress), - m_udpPort(udpPort), - m_force(force) - { } - }; - enum RateState { RSInitialFill, RSRunning diff --git a/plugins/channelrx/demodam/amdemodgui.cpp b/plugins/channelrx/demodam/amdemodgui.cpp index 3f5fe156e..e36cfff44 100644 --- a/plugins/channelrx/demodam/amdemodgui.cpp +++ b/plugins/channelrx/demodam/amdemodgui.cpp @@ -252,7 +252,6 @@ AMDemodGUI::AMDemodGUI(PluginAPI* pluginAPI, DeviceSourceAPI *deviceAPI, QWidget ui->deltaFrequency->setValueRange(false, 7, -9999999, 9999999); ui->channelPowerMeter->setColorTheme(LevelMeterSignalDB::ColorGreenAndBlue); - //m_channelMarker = new ChannelMarker(this); m_channelMarker.setColor(Qt::yellow); m_channelMarker.setBandwidth(5000); m_channelMarker.setCenterFrequency(0); @@ -279,7 +278,6 @@ AMDemodGUI::~AMDemodGUI() delete m_threadedChannelizer; delete m_channelizer; delete m_amDemod; - //delete m_channelMarker; delete ui; } @@ -300,28 +298,8 @@ void AMDemodGUI::applySettings(bool force) ui->deltaFrequency->setValue(m_channelMarker.getCenterFrequency()); -// m_amDemod->configure(m_amDemod->getInputMessageQueue(), -// ui->rfBW->value() * 100.0, -// ui->volume->value() / 10.0, -// ui->squelch->value(), -// ui->audioMute->isChecked(), -// ui->bandpassEnable->isChecked(), -// ui->copyAudioToUDP->isChecked(), -// m_channelMarker.getUDPAddress(), -// m_channelMarker.getUDPSendPort(), -// force); - - m_amDemod->configure(m_amDemod->getInputMessageQueue(), - m_settings.m_rfBandwidth, - m_settings.m_volume, - m_settings.m_squelch, - m_settings.m_audioMute, - m_settings.m_bandpassEnable, - m_settings.m_copyAudioToUDP, - m_settings.m_udpAddress, - m_settings.m_udpPort, - force); - + AMDemod::MsgConfigureAMDemod* message = AMDemod::MsgConfigureAMDemod::create( m_settings, force); + m_amDemod->getInputMessageQueue()->push(message); } } From 7f9b22ccac25199a5800b4825b7c7d2dc78c3333 Mon Sep 17 00:00:00 2001 From: f4exb Date: Wed, 27 Sep 2017 00:55:33 +0200 Subject: [PATCH 28/71] AM demod: use settings object serialization / deserialization --- plugins/channelrx/demodam/amdemodgui.cpp | 98 ++++++------------- plugins/channelrx/demodam/amdemodgui.h | 1 + plugins/channelrx/demodam/amdemodsettings.cpp | 10 +- plugins/channelrx/demodam/amdemodsettings.h | 1 + 4 files changed, 37 insertions(+), 73 deletions(-) diff --git a/plugins/channelrx/demodam/amdemodgui.cpp b/plugins/channelrx/demodam/amdemodgui.cpp index e36cfff44..c3892ce2d 100644 --- a/plugins/channelrx/demodam/amdemodgui.cpp +++ b/plugins/channelrx/demodam/amdemodgui.cpp @@ -68,83 +68,27 @@ void AMDemodGUI::setCenterFrequency(qint64 centerFrequency) void AMDemodGUI::resetToDefaults() { - blockApplySettings(true); - - ui->rfBW->setValue(50); - ui->volume->setValue(20); - ui->squelch->setValue(-40); - ui->deltaFrequency->setValue(0); - - blockApplySettings(false); - applySettings(); + m_settings.resetToDefaults(); + displaySettings(); + applySettings(true); } QByteArray AMDemodGUI::serialize() const { - SimpleSerializer s(1); - s.writeS32(1, m_channelMarker.getCenterFrequency()); - s.writeS32(2, ui->rfBW->value()); - s.writeS32(4, ui->volume->value()); - s.writeS32(5, ui->squelch->value()); - s.writeBlob(6, m_channelMarker.serialize()); - s.writeU32(7, m_channelMarker.getColor().rgb()); - s.writeBool(8, ui->bandpassEnable->isChecked()); - return s.final(); + return m_settings.serialize(); } bool AMDemodGUI::deserialize(const QByteArray& data) { - SimpleDeserializer d(data); - - if(!d.isValid()) - { - resetToDefaults(); - return false; - } - - if(d.getVersion() == 1) - { - QByteArray bytetmp; - quint32 u32tmp; - qint32 tmp; - bool boolTmp; - QString strtmp; - - blockApplySettings(true); - m_channelMarker.blockSignals(true); - - d.readBlob(6, &bytetmp); - m_channelMarker.deserialize(bytetmp); - d.readS32(1, &tmp, 0); - m_channelMarker.setCenterFrequency(tmp); - d.readS32(2, &tmp, 4); - ui->rfBW->setValue(tmp); - d.readS32(3, &tmp, 3); - //ui->afBW->setValue(tmp); - d.readS32(4, &tmp, 20); - ui->volume->setValue(tmp); - d.readS32(5, &tmp, -40); - ui->squelch->setValue(tmp); - if(d.readU32(7, &u32tmp)) { - m_channelMarker.setColor(u32tmp); - } - d.readBool(8, &boolTmp, false); - ui->bandpassEnable->setChecked(boolTmp); - - this->setWindowTitle(m_channelMarker.getTitle()); - displayUDPAddress(); - - blockApplySettings(false); - m_channelMarker.blockSignals(false); - - applySettings(true); - return true; - } - else - { - resetToDefaults(); - return false; - } + if(m_settings.deserialize(data)) { + updateChannelMarker(); + displaySettings(); + applySettings(true); + return true; + } else { + resetToDefaults(); + return false; + } } bool AMDemodGUI::handleMessage(const Message& message __attribute__((unused))) @@ -158,7 +102,9 @@ void AMDemodGUI::channelMarkerChanged() m_settings.m_inputFrequencyOffset = m_channelMarker.getCenterFrequency(); m_settings.m_udpAddress = m_channelMarker.getUDPAddress(), m_settings.m_udpPort = m_channelMarker.getUDPSendPort(), + m_settings.m_rgbColor = m_channelMarker.getColor().rgb(); displayUDPAddress(); + m_settings.m_channelMarkerBytes = m_channelMarker.serialize(); applySettings(); } @@ -322,9 +268,13 @@ void AMDemodGUI::displaySettings() ui->bandpassEnable->setChecked(m_settings.m_bandpassEnable); ui->copyAudioToUDP->setChecked(m_settings.m_copyAudioToUDP); + m_channelMarker.blockSignals(true); m_channelMarker.setCenterFrequency(m_settings.m_inputFrequencyOffset); m_channelMarker.setUDPAddress(m_settings.m_udpAddress); m_channelMarker.setUDPSendPort(m_settings.m_udpPort); + m_channelMarker.setColor(m_settings.m_rgbColor); + setTitleColor(m_settings.m_rgbColor); + m_channelMarker.blockSignals(false); blockApplySettings(false); } @@ -334,6 +284,16 @@ void AMDemodGUI::displayUDPAddress() ui->copyAudioToUDP->setToolTip(QString("Copy audio output to UDP %1:%2").arg(m_channelMarker.getUDPAddress()).arg(m_channelMarker.getUDPSendPort())); } +void AMDemodGUI::updateChannelMarker() +{ + m_channelMarker.blockSignals(true); + + m_channelMarker.deserialize(m_settings.m_channelMarkerBytes); + this->setWindowTitle(m_channelMarker.getTitle()); + + m_channelMarker.blockSignals(false); +} + void AMDemodGUI::leaveEvent(QEvent*) { blockApplySettings(true); diff --git a/plugins/channelrx/demodam/amdemodgui.h b/plugins/channelrx/demodam/amdemodgui.h index 909e39cef..00db7921f 100644 --- a/plugins/channelrx/demodam/amdemodgui.h +++ b/plugins/channelrx/demodam/amdemodgui.h @@ -74,6 +74,7 @@ private: void applySettings(bool force = false); void displaySettings(); void displayUDPAddress(); + void updateChannelMarker(); void leaveEvent(QEvent*); void enterEvent(QEvent*); diff --git a/plugins/channelrx/demodam/amdemodsettings.cpp b/plugins/channelrx/demodam/amdemodsettings.cpp index d5a969368..3778e8723 100644 --- a/plugins/channelrx/demodam/amdemodsettings.cpp +++ b/plugins/channelrx/demodam/amdemodsettings.cpp @@ -42,10 +42,11 @@ QByteArray AMDemodSettings::serialize() const { SimpleSerializer s(1); s.writeS32(1, m_inputFrequencyOffset); - s.writeS32(2, m_rfBandwidth/1000); + s.writeS32(2, m_rfBandwidth/100); s.writeS32(4, m_volume*10); - s.writeS32(5, m_squelch*10); + s.writeS32(5, m_squelch); s.writeBlob(6, m_channelMarkerBytes); + s.writeU32(7, m_rgbColor); s.writeBool(8, m_bandpassEnable); return s.final(); } @@ -68,12 +69,13 @@ bool AMDemodSettings::deserialize(const QByteArray& data) d.readS32(1, &m_inputFrequencyOffset, 0); d.readS32(2, &tmp, 4); - m_rfBandwidth = 1000 * tmp; + m_rfBandwidth = 100 * tmp; d.readS32(4, &tmp, 20); m_volume = tmp * 0.1; d.readS32(5, &tmp, -40); - m_squelch = tmp * 0.1; + m_squelch = tmp; d.readBlob(6, &m_channelMarkerBytes); + d.readU32(7, &m_rgbColor); d.readBool(8, &m_bandpassEnable, false); return true; } diff --git a/plugins/channelrx/demodam/amdemodsettings.h b/plugins/channelrx/demodam/amdemodsettings.h index fb54136d5..5652636b7 100644 --- a/plugins/channelrx/demodam/amdemodsettings.h +++ b/plugins/channelrx/demodam/amdemodsettings.h @@ -32,6 +32,7 @@ struct AMDemodSettings bool m_copyAudioToUDP; QString m_udpAddress; quint16 m_udpPort; + quint32 m_rgbColor; QByteArray m_channelMarkerBytes; AMDemodSettings(); From 5ab144da82c632c03ce4eb9946484e34cf066594 Mon Sep 17 00:00:00 2001 From: f4exb Date: Wed, 27 Sep 2017 01:04:04 +0200 Subject: [PATCH 29/71] AM demod: Windows build update --- plugins/channelrx/demodam/demodam.pro | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/plugins/channelrx/demodam/demodam.pro b/plugins/channelrx/demodam/demodam.pro index 2fb2826ad..ed42eeec6 100644 --- a/plugins/channelrx/demodam/demodam.pro +++ b/plugins/channelrx/demodam/demodam.pro @@ -25,11 +25,13 @@ CONFIG(Debug):build_subdir = debug SOURCES += amdemod.cpp\ amdemodgui.cpp\ - amdemodplugin.cpp + amdemodplugin.cpp\ + amdemodsettings.cpp HEADERS += amdemod.h\ amdemodgui.h\ - amdemodplugin.h + amdemodplugin.h\ + amdemodsettings.h FORMS += amdemodgui.ui From 95891164d507f113a5acdf3033744b96193a8d2a Mon Sep 17 00:00:00 2001 From: f4exb Date: Wed, 27 Sep 2017 23:47:29 +0200 Subject: [PATCH 30/71] Channel Rx / GUI new messaging system --- plugins/channelrx/demodatv/atvdemod.cpp | 2 +- plugins/channelrx/demodatv/atvdemodgui.cpp | 5 +++-- sdrbase/dsp/basebandsamplesink.cpp | 3 ++- sdrbase/dsp/basebandsamplesink.h | 5 +++-- sdrbase/dsp/threadedbasebandsamplesink.h | 2 -- 5 files changed, 9 insertions(+), 8 deletions(-) diff --git a/plugins/channelrx/demodatv/atvdemod.cpp b/plugins/channelrx/demodatv/atvdemod.cpp index 7d41a828c..a2e38a0a2 100644 --- a/plugins/channelrx/demodatv/atvdemod.cpp +++ b/plugins/channelrx/demodatv/atvdemod.cpp @@ -636,7 +636,7 @@ void ATVDemod::applySettings() int sampleRate = m_objRFRunning.m_blndecimatorEnable ? m_objRunningPrivate.m_intTVSampleRate : m_objRunning.m_intSampleRate; MsgReportEffectiveSampleRate *report; report = MsgReportEffectiveSampleRate::create(sampleRate, m_objRunningPrivate.m_intNumberSamplePerLine); - getOutputMessageQueue()->push(report); + getMessageQueueToGUI()->push(report); } } diff --git a/plugins/channelrx/demodatv/atvdemodgui.cpp b/plugins/channelrx/demodatv/atvdemodgui.cpp index 15c4976d1..8ad7c80fa 100644 --- a/plugins/channelrx/demodatv/atvdemodgui.cpp +++ b/plugins/channelrx/demodatv/atvdemodgui.cpp @@ -242,7 +242,7 @@ void ATVDemodGUI::handleSourceMessages() { Message* message; - while ((message = m_objATVDemod->getOutputMessageQueue()->pop()) != 0) + while ((message = getInputMessageQueue()->pop()) != 0) { if (handleMessage(*message)) { @@ -285,6 +285,7 @@ ATVDemodGUI::ATVDemodGUI(PluginAPI* objPluginAPI, DeviceSourceAPI *objDeviceAPI, m_objScopeVis = new ScopeVisNG(ui->glScope); m_objATVDemod = new ATVDemod(m_objScopeVis); + m_objATVDemod->setMessageQueueToGUI(getInputMessageQueue()); m_objATVDemod->setATVScreen(ui->screenTV); m_objChannelizer = new DownChannelizer(m_objATVDemod); @@ -337,7 +338,7 @@ ATVDemodGUI::ATVDemodGUI(PluginAPI* objPluginAPI, DeviceSourceAPI *objDeviceAPI, ui->scopeGUI->changeTrigger(0, triggerData); ui->scopeGUI->focusOnTrigger(0); // re-focus to take changes into account in the GUI - connect(m_objATVDemod->getOutputMessageQueue(), SIGNAL(messageEnqueued()), this, SLOT(handleSourceMessages())); + connect(getInputMessageQueue(), SIGNAL(messageEnqueued()), this, SLOT(handleSourceMessages())); QChar delta = QChar(0x94, 0x03); ui->fmDeviationLabel->setText(delta); diff --git a/sdrbase/dsp/basebandsamplesink.cpp b/sdrbase/dsp/basebandsamplesink.cpp index dac936700..7887f768d 100644 --- a/sdrbase/dsp/basebandsamplesink.cpp +++ b/sdrbase/dsp/basebandsamplesink.cpp @@ -1,7 +1,8 @@ #include #include "util/message.h" -BasebandSampleSink::BasebandSampleSink() +BasebandSampleSink::BasebandSampleSink() : + m_guiMessageQueue(0) { connect(&m_inputMessageQueue, SIGNAL(messageEnqueued()), this, SLOT(handleInputMessages())); } diff --git a/sdrbase/dsp/basebandsamplesink.h b/sdrbase/dsp/basebandsamplesink.h index adf47fe9e..9897d280f 100644 --- a/sdrbase/dsp/basebandsamplesink.h +++ b/sdrbase/dsp/basebandsamplesink.h @@ -37,11 +37,12 @@ public: virtual bool handleMessage(const Message& cmd) = 0; //!< Processing of a message. Returns true if message has actually been processed MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; } //!< Get the queue for asynchronous inbound communication - MessageQueue *getOutputMessageQueue() { return &m_outputMessageQueue; } //!< Get the queue for asynchronous outbound communication + virtual void setMessageQueueToGUI(MessageQueue *queue) { m_guiMessageQueue = queue; } + MessageQueue *getMessageQueueToGUI() { return m_guiMessageQueue; } protected: MessageQueue m_inputMessageQueue; //!< Queue for asynchronous inbound communication - MessageQueue m_outputMessageQueue; //!< Queue for asynchronous outbound communication + MessageQueue *m_guiMessageQueue; //!< Input message queue to the GUI protected slots: void handleInputMessages(); diff --git a/sdrbase/dsp/threadedbasebandsamplesink.h b/sdrbase/dsp/threadedbasebandsamplesink.h index 416d4d283..93368c6bb 100644 --- a/sdrbase/dsp/threadedbasebandsamplesink.h +++ b/sdrbase/dsp/threadedbasebandsamplesink.h @@ -58,8 +58,6 @@ public: ~ThreadedBasebandSampleSink(); const BasebandSampleSink *getSink() const { return m_basebandSampleSink; } - MessageQueue* getInputMessageQueue() { return m_basebandSampleSink->getInputMessageQueue(); } //!< Return pointer to sample sink's input message queue - MessageQueue* getOutputMessageQueue() { return m_basebandSampleSink->getOutputMessageQueue(); } //!< Return pointer to sample sink's output message queue void start(); //!< this thread start() void stop(); //!< this thread exit() and wait() From ff5e233eb03907912f9f209cc9948bb0348862f8 Mon Sep 17 00:00:00 2001 From: f4exb Date: Thu, 28 Sep 2017 00:24:03 +0200 Subject: [PATCH 31/71] AM demod: move channelizer and threaded channelizer from GUI to demod --- plugins/channelrx/demodam/amdemod.cpp | 20 +++++++++++++- plugins/channelrx/demodam/amdemod.h | 33 +++++++++++++++++++++++- plugins/channelrx/demodam/amdemodgui.cpp | 15 +++-------- plugins/channelrx/demodam/amdemodgui.h | 4 +-- 4 files changed, 57 insertions(+), 15 deletions(-) diff --git a/plugins/channelrx/demodam/amdemod.cpp b/plugins/channelrx/demodam/amdemod.cpp index 13b29cd30..b1d93b286 100644 --- a/plugins/channelrx/demodam/amdemod.cpp +++ b/plugins/channelrx/demodam/amdemod.cpp @@ -26,12 +26,16 @@ #include "audio/audiooutput.h" #include "dsp/dspengine.h" #include "dsp/pidcontroller.h" +#include "dsp/threadedbasebandsamplesink.h" +#include "device/devicesourceapi.h" MESSAGE_CLASS_DEFINITION(AMDemod::MsgConfigureAMDemod, Message) +MESSAGE_CLASS_DEFINITION(AMDemod::MsgConfigureChannelizer, Message) const int AMDemod::m_udpBlockSize = 512; -AMDemod::AMDemod() : +AMDemod::AMDemod(DeviceSourceAPI *deviceAPI) : + m_deviceAPI(deviceAPI), m_squelchOpen(false), m_magsqSum(0.0f), m_magsqPeak(0.0f), @@ -43,6 +47,10 @@ AMDemod::AMDemod() : { setObjectName("AMDemod"); + m_channelizer = new DownChannelizer(this); + m_threadedChannelizer = new ThreadedBasebandSampleSink(m_channelizer, this); + m_deviceAPI->addThreadedSink(m_threadedChannelizer); + m_audioBuffer.resize(1<<14); m_audioBufferFill = 0; @@ -144,6 +152,16 @@ bool AMDemod::handleMessage(const Message& cmd) return true; } + else if (MsgConfigureChannelizer::match(cmd)) + { + MsgConfigureChannelizer& cfg = (MsgConfigureChannelizer&) cmd; + + m_channelizer->configure(m_channelizer->getInputMessageQueue(), + cfg.getSampleRate(), + cfg.getCenterFrequency()); + + return true; + } else if (MsgConfigureAMDemod::match(cmd)) { MsgConfigureAMDemod& cfg = (MsgConfigureAMDemod&) cmd; diff --git a/plugins/channelrx/demodam/amdemod.h b/plugins/channelrx/demodam/amdemod.h index 5f725b72e..8c48c2914 100644 --- a/plugins/channelrx/demodam/amdemod.h +++ b/plugins/channelrx/demodam/amdemod.h @@ -29,6 +29,10 @@ #include "util/message.h" #include "amdemodsettings.h" +class DeviceSourceAPI; +class DownChannelizer; +class ThreadedBasebandSampleSink; + class AMDemod : public BasebandSampleSink { Q_OBJECT public: @@ -55,7 +59,30 @@ public: { } }; - AMDemod(); + class MsgConfigureChannelizer : public Message { + MESSAGE_CLASS_DECLARATION + + public: + int getSampleRate() const { return m_sampleRate; } + int getCenterFrequency() const { return m_centerFrequency; } + + static MsgConfigureChannelizer* create(int sampleRate, int centerFrequency) + { + return new MsgConfigureChannelizer(sampleRate, centerFrequency); + } + + private: + int m_sampleRate; + int m_centerFrequency; + + MsgConfigureChannelizer(int sampleRate, int centerFrequency) : + Message(), + m_sampleRate(sampleRate), + m_centerFrequency(centerFrequency) + { } + }; + + AMDemod(DeviceSourceAPI *deviceAPI); ~AMDemod(); virtual void feed(const SampleVector::const_iterator& begin, const SampleVector::const_iterator& end, bool po); @@ -82,6 +109,10 @@ private: RSRunning }; + DeviceSourceAPI *m_deviceAPI; + ThreadedBasebandSampleSink* m_threadedChannelizer; + DownChannelizer* m_channelizer; + AMDemodSettings m_settings; NCO m_nco; diff --git a/plugins/channelrx/demodam/amdemodgui.cpp b/plugins/channelrx/demodam/amdemodgui.cpp index c3892ce2d..06c879983 100644 --- a/plugins/channelrx/demodam/amdemodgui.cpp +++ b/plugins/channelrx/demodam/amdemodgui.cpp @@ -185,11 +185,7 @@ AMDemodGUI::AMDemodGUI(PluginAPI* pluginAPI, DeviceSourceAPI *deviceAPI, QWidget connect(this, SIGNAL(widgetRolled(QWidget*,bool)), this, SLOT(onWidgetRolled(QWidget*,bool))); connect(this, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(onMenuDialogCalled(const QPoint &))); - m_amDemod = new AMDemod(); - m_channelizer = new DownChannelizer(m_amDemod); - m_threadedChannelizer = new ThreadedBasebandSampleSink(m_channelizer, this); - //m_pluginAPI->addThreadedSink(m_threadedChannelizer); - m_deviceAPI->addThreadedSink(m_threadedChannelizer); + m_amDemod = new AMDemod(m_deviceAPI); connect(&m_pluginAPI->getMainWindow()->getMasterTimer(), SIGNAL(timeout()), this, SLOT(tick())); // 50 ms @@ -220,9 +216,6 @@ AMDemodGUI::AMDemodGUI(PluginAPI* pluginAPI, DeviceSourceAPI *deviceAPI, QWidget AMDemodGUI::~AMDemodGUI() { m_deviceAPI->removeChannelInstance(this); - m_deviceAPI->removeThreadedSink(m_threadedChannelizer); - delete m_threadedChannelizer; - delete m_channelizer; delete m_amDemod; delete ui; } @@ -238,9 +231,9 @@ void AMDemodGUI::applySettings(bool force) { setTitleColor(m_channelMarker.getColor()); - m_channelizer->configure(m_channelizer->getInputMessageQueue(), - 48000, - m_channelMarker.getCenterFrequency()); + AMDemod::MsgConfigureChannelizer* channelConfigMsg = AMDemod::MsgConfigureChannelizer::create( + 48000, m_channelMarker.getCenterFrequency()); + m_amDemod->getInputMessageQueue()->push(channelConfigMsg); ui->deltaFrequency->setValue(m_channelMarker.getCenterFrequency()); diff --git a/plugins/channelrx/demodam/amdemodgui.h b/plugins/channelrx/demodam/amdemodgui.h index 00db7921f..fdc82a477 100644 --- a/plugins/channelrx/demodam/amdemodgui.h +++ b/plugins/channelrx/demodam/amdemodgui.h @@ -60,8 +60,8 @@ private: AMDemodSettings m_settings; bool m_doApplySettings; - ThreadedBasebandSampleSink* m_threadedChannelizer; - DownChannelizer* m_channelizer; +// ThreadedBasebandSampleSink* m_threadedChannelizer; +// DownChannelizer* m_channelizer; AMDemod* m_amDemod; bool m_squelchOpen; uint32_t m_tickCount; From dda9a1dcbb4afa27f4c624ac769ae5a2d9294081 Mon Sep 17 00:00:00 2001 From: f4exb Date: Thu, 28 Sep 2017 08:33:05 +0200 Subject: [PATCH 32/71] Baseband sample source: change messaging mechanism between channel sink and GUI --- plugins/channeltx/modam/ammod.cpp | 4 +- plugins/channeltx/modam/ammodgui.cpp | 5 +- plugins/channeltx/modatv/atvmod.cpp | 16 +-- plugins/channeltx/modatv/atvmodgui.cpp | 5 +- plugins/channeltx/modnfm/nfmmod.cpp | 4 +- plugins/channeltx/modnfm/nfmmodgui.cpp | 5 +- plugins/channeltx/modssb/ssbmod.cpp | 4 +- plugins/channeltx/modssb/ssbmodgui.cpp | 5 +- plugins/channeltx/modwfm/wfmmod.cpp | 4 +- plugins/channeltx/modwfm/wfmmodgui.cpp | 5 +- plugins/channeltx/udpsink/udpsinkgui.cpp | 5 +- sdrbase/dsp/basebandsamplesource.h | 143 +++++++++++---------- sdrbase/dsp/threadedbasebandsamplesource.h | 2 - 13 files changed, 106 insertions(+), 101 deletions(-) diff --git a/plugins/channeltx/modam/ammod.cpp b/plugins/channeltx/modam/ammod.cpp index dc724f09b..793389dee 100644 --- a/plugins/channeltx/modam/ammod.cpp +++ b/plugins/channeltx/modam/ammod.cpp @@ -338,7 +338,7 @@ bool AMMod::handleMessage(const Message& cmd) MsgReportFileSourceStreamTiming *report; report = MsgReportFileSourceStreamTiming::create(samplesCount); - getOutputMessageQueue()->push(report); + getMessageQueueToGUI()->push(report); return true; } @@ -415,7 +415,7 @@ void AMMod::openFileStream() MsgReportFileSourceStreamData *report; report = MsgReportFileSourceStreamData::create(m_sampleRate, m_recordLength); - getOutputMessageQueue()->push(report); + getMessageQueueToGUI()->push(report); } void AMMod::seekFileStream(int seekPercentage) diff --git a/plugins/channeltx/modam/ammodgui.cpp b/plugins/channeltx/modam/ammodgui.cpp index 125804ffe..fba939cb6 100644 --- a/plugins/channeltx/modam/ammodgui.cpp +++ b/plugins/channeltx/modam/ammodgui.cpp @@ -178,7 +178,7 @@ void AMModGUI::handleSourceMessages() { Message* message; - while ((message = m_amMod->getOutputMessageQueue()->pop()) != 0) + while ((message = getInputMessageQueue()->pop()) != 0) { if (handleMessage(*message)) { @@ -339,6 +339,7 @@ AMModGUI::AMModGUI(PluginAPI* pluginAPI, DeviceSinkAPI *deviceAPI, QWidget* pare connect(this, SIGNAL(menuDoubleClickEvent()), this, SLOT(onMenuDoubleClicked())); m_amMod = new AMMod(); + m_amMod->setMessageQueueToGUI(getInputMessageQueue()); m_channelizer = new UpChannelizer(m_amMod); m_threadedChannelizer = new ThreadedBasebandSampleSource(m_channelizer, this); //m_pluginAPI->addThreadedSink(m_threadedChannelizer); @@ -372,7 +373,7 @@ AMModGUI::AMModGUI(PluginAPI* pluginAPI, DeviceSinkAPI *deviceAPI, QWidget* pare applySettings(); - connect(m_amMod->getOutputMessageQueue(), SIGNAL(messageEnqueued()), this, SLOT(handleSourceMessages())); + connect(getInputMessageQueue(), SIGNAL(messageEnqueued()), this, SLOT(handleSourceMessages())); connect(m_amMod, SIGNAL(levelChanged(qreal, qreal, int)), ui->volumeMeter, SLOT(levelChanged(qreal, qreal, int))); } diff --git a/plugins/channeltx/modatv/atvmod.cpp b/plugins/channeltx/modatv/atvmod.cpp index 046b9a967..dec3d9194 100644 --- a/plugins/channeltx/modatv/atvmod.cpp +++ b/plugins/channeltx/modatv/atvmod.cpp @@ -394,7 +394,7 @@ void ATVMod::pullVideo(Real& sample) camera.m_videoWidth, camera.m_videoHeight, 1); // open splash screen on GUI side - getOutputMessageQueue()->push(report); + getMessageQueueToGUI()->push(report); int nbFrames = 0; time(&start); @@ -422,7 +422,7 @@ void ATVMod::pullVideo(Real& sample) camera.m_videoWidth, camera.m_videoHeight, 2); // close splash screen on GUI side - getOutputMessageQueue()->push(report); + getMessageQueueToGUI()->push(report); } else if (camera.m_videoFPS == 0.0f) // Hideous hack for windows { @@ -440,7 +440,7 @@ void ATVMod::pullVideo(Real& sample) camera.m_videoWidth, camera.m_videoHeight, 0); - getOutputMessageQueue()->push(report); + getMessageQueueToGUI()->push(report); } int fpsIncrement = (int) camera.m_videoFPSCount - camera.m_videoPrevFPSCount; @@ -603,7 +603,7 @@ bool ATVMod::handleMessage(const Message& cmd) MsgReportVideoFileSourceStreamTiming *report; report = MsgReportVideoFileSourceStreamTiming::create(framesCount); - getOutputMessageQueue()->push(report); + getMessageQueueToGUI()->push(report); return true; } @@ -624,7 +624,7 @@ bool ATVMod::handleMessage(const Message& cmd) m_cameras[m_cameraIndex].m_videoWidth, m_cameras[m_cameraIndex].m_videoHeight, 0); - getOutputMessageQueue()->push(report); + getMessageQueueToGUI()->push(report); } return true; @@ -723,7 +723,7 @@ void ATVMod::apply(bool force) MsgReportEffectiveSampleRate *report; report = MsgReportEffectiveSampleRate::create(m_tvSampleRate, m_pointsPerLine); - getOutputMessageQueue()->push(report); + getMessageQueueToGUI()->push(report); } if ((m_config.m_outputSampleRate != m_running.m_outputSampleRate) @@ -979,7 +979,7 @@ void ATVMod::openVideo(const QString& fileName) MsgReportVideoFileSourceStreamData *report; report = MsgReportVideoFileSourceStreamData::create(m_videoFPS, m_videoLength); - getOutputMessageQueue()->push(report); + getMessageQueueToGUI()->push(report); } else { @@ -1123,7 +1123,7 @@ void ATVMod::getCameraNumbers(std::vector& numbers) m_cameras[0].m_videoWidth, m_cameras[0].m_videoHeight, 0); - getOutputMessageQueue()->push(report); + getMessageQueueToGUI()->push(report); } } diff --git a/plugins/channeltx/modatv/atvmodgui.cpp b/plugins/channeltx/modatv/atvmodgui.cpp index 0e1738d59..52d16f23d 100644 --- a/plugins/channeltx/modatv/atvmodgui.cpp +++ b/plugins/channeltx/modatv/atvmodgui.cpp @@ -363,7 +363,7 @@ void ATVModGUI::handleSourceMessages() { Message* message; - while ((message = m_atvMod->getOutputMessageQueue()->pop()) != 0) + while ((message = getInputMessageQueue()->pop()) != 0) { if (handleMessage(*message)) { @@ -622,6 +622,7 @@ ATVModGUI::ATVModGUI(PluginAPI* pluginAPI, DeviceSinkAPI *deviceAPI, QWidget* pa connect(this, SIGNAL(menuDoubleClickEvent()), this, SLOT(onMenuDoubleClicked())); m_atvMod = new ATVMod(); + m_atvMod->setMessageQueueToGUI(getInputMessageQueue()); m_channelizer = new UpChannelizer(m_atvMod); m_threadedChannelizer = new ThreadedBasebandSampleSource(m_channelizer, this); //m_pluginAPI->addThreadedSink(m_threadedChannelizer); @@ -648,7 +649,7 @@ ATVModGUI::ATVModGUI(PluginAPI* pluginAPI, DeviceSinkAPI *deviceAPI, QWidget* pa resetToDefaults(); - connect(m_atvMod->getOutputMessageQueue(), SIGNAL(messageEnqueued()), this, SLOT(handleSourceMessages())); + connect(getInputMessageQueue(), SIGNAL(messageEnqueued()), this, SLOT(handleSourceMessages())); connect(m_atvMod, SIGNAL(levelChanged(qreal, qreal, int)), ui->volumeMeter, SLOT(levelChanged(qreal, qreal, int))); std::vector cameraNumbers; diff --git a/plugins/channeltx/modnfm/nfmmod.cpp b/plugins/channeltx/modnfm/nfmmod.cpp index 1e2fc94ff..3078e7785 100644 --- a/plugins/channeltx/modnfm/nfmmod.cpp +++ b/plugins/channeltx/modnfm/nfmmod.cpp @@ -367,7 +367,7 @@ bool NFMMod::handleMessage(const Message& cmd) MsgReportFileSourceStreamTiming *report; report = MsgReportFileSourceStreamTiming::create(samplesCount); - getOutputMessageQueue()->push(report); + getMessageQueueToGUI()->push(report); return true; } @@ -462,7 +462,7 @@ void NFMMod::openFileStream() MsgReportFileSourceStreamData *report; report = MsgReportFileSourceStreamData::create(m_sampleRate, m_recordLength); - getOutputMessageQueue()->push(report); + getMessageQueueToGUI()->push(report); } void NFMMod::seekFileStream(int seekPercentage) diff --git a/plugins/channeltx/modnfm/nfmmodgui.cpp b/plugins/channeltx/modnfm/nfmmodgui.cpp index 48845be99..09e469538 100644 --- a/plugins/channeltx/modnfm/nfmmodgui.cpp +++ b/plugins/channeltx/modnfm/nfmmodgui.cpp @@ -202,7 +202,7 @@ void NFMModGUI::handleSourceMessages() { Message* message; - while ((message = m_nfmMod->getOutputMessageQueue()->pop()) != 0) + while ((message = getInputMessageQueue()->pop()) != 0) { if (handleMessage(*message)) { @@ -388,6 +388,7 @@ NFMModGUI::NFMModGUI(PluginAPI* pluginAPI, DeviceSinkAPI *deviceAPI, QWidget* pa connect(this, SIGNAL(menuDoubleClickEvent()), this, SLOT(onMenuDoubleClicked())); m_nfmMod = new NFMMod(); + m_nfmMod->setMessageQueueToGUI(getInputMessageQueue()); m_channelizer = new UpChannelizer(m_nfmMod); m_threadedChannelizer = new ThreadedBasebandSampleSource(m_channelizer, this); //m_pluginAPI->addThreadedSink(m_threadedChannelizer); @@ -425,7 +426,7 @@ NFMModGUI::NFMModGUI(PluginAPI* pluginAPI, DeviceSinkAPI *deviceAPI, QWidget* pa applySettings(); - connect(m_nfmMod->getOutputMessageQueue(), SIGNAL(messageEnqueued()), this, SLOT(handleSourceMessages())); + connect(getInputMessageQueue(), SIGNAL(messageEnqueued()), this, SLOT(handleSourceMessages())); connect(m_nfmMod, SIGNAL(levelChanged(qreal, qreal, int)), ui->volumeMeter, SLOT(levelChanged(qreal, qreal, int))); } diff --git a/plugins/channeltx/modssb/ssbmod.cpp b/plugins/channeltx/modssb/ssbmod.cpp index 71405ace8..7ab668f09 100644 --- a/plugins/channeltx/modssb/ssbmod.cpp +++ b/plugins/channeltx/modssb/ssbmod.cpp @@ -685,7 +685,7 @@ bool SSBMod::handleMessage(const Message& cmd) MsgReportFileSourceStreamTiming *report; report = MsgReportFileSourceStreamTiming::create(samplesCount); - getOutputMessageQueue()->push(report); + getMessageQueueToGUI()->push(report); return true; } @@ -824,7 +824,7 @@ void SSBMod::openFileStream() MsgReportFileSourceStreamData *report; report = MsgReportFileSourceStreamData::create(m_sampleRate, m_recordLength); - getOutputMessageQueue()->push(report); + getMessageQueueToGUI()->push(report); } void SSBMod::seekFileStream(int seekPercentage) diff --git a/plugins/channeltx/modssb/ssbmodgui.cpp b/plugins/channeltx/modssb/ssbmodgui.cpp index fd5b77a78..b3f63d49d 100644 --- a/plugins/channeltx/modssb/ssbmodgui.cpp +++ b/plugins/channeltx/modssb/ssbmodgui.cpp @@ -237,7 +237,7 @@ void SSBModGUI::handleSourceMessages() { Message* message; - while ((message = m_ssbMod->getOutputMessageQueue()->pop()) != 0) + while ((message = getInputMessageQueue()->pop()) != 0) { if (handleMessage(*message)) { @@ -540,6 +540,7 @@ SSBModGUI::SSBModGUI(PluginAPI* pluginAPI, DeviceSinkAPI *deviceAPI, QWidget* pa m_spectrumVis = new SpectrumVis(ui->glSpectrum); m_ssbMod = new SSBMod(m_spectrumVis); + m_ssbMod->setMessageQueueToGUI(getInputMessageQueue()); m_channelizer = new UpChannelizer(m_ssbMod); m_threadedChannelizer = new ThreadedBasebandSampleSource(m_channelizer, this); //m_pluginAPI->addThreadedSink(m_threadedChannelizer); @@ -580,7 +581,7 @@ SSBModGUI::SSBModGUI(PluginAPI* pluginAPI, DeviceSinkAPI *deviceAPI, QWidget* pa applySettings(); setNewRate(m_spanLog2); - connect(m_ssbMod->getOutputMessageQueue(), SIGNAL(messageEnqueued()), this, SLOT(handleSourceMessages())); + connect(getInputMessageQueue(), SIGNAL(messageEnqueued()), this, SLOT(handleSourceMessages())); connect(m_ssbMod, SIGNAL(levelChanged(qreal, qreal, int)), ui->volumeMeter, SLOT(levelChanged(qreal, qreal, int))); } diff --git a/plugins/channeltx/modwfm/wfmmod.cpp b/plugins/channeltx/modwfm/wfmmod.cpp index d6be5516d..8038f67d1 100644 --- a/plugins/channeltx/modwfm/wfmmod.cpp +++ b/plugins/channeltx/modwfm/wfmmod.cpp @@ -367,7 +367,7 @@ bool WFMMod::handleMessage(const Message& cmd) MsgReportFileSourceStreamTiming *report; report = MsgReportFileSourceStreamTiming::create(samplesCount); - getOutputMessageQueue()->push(report); + getMessageQueueToGUI()->push(report); return true; } @@ -463,7 +463,7 @@ void WFMMod::openFileStream() MsgReportFileSourceStreamData *report; report = MsgReportFileSourceStreamData::create(m_sampleRate, m_recordLength); - getOutputMessageQueue()->push(report); + getMessageQueueToGUI()->push(report); } void WFMMod::seekFileStream(int seekPercentage) diff --git a/plugins/channeltx/modwfm/wfmmodgui.cpp b/plugins/channeltx/modwfm/wfmmodgui.cpp index 7b84e6f13..3f5e45d86 100644 --- a/plugins/channeltx/modwfm/wfmmodgui.cpp +++ b/plugins/channeltx/modwfm/wfmmodgui.cpp @@ -183,7 +183,7 @@ void WFMModGUI::handleSourceMessages() { Message* message; - while ((message = m_wfmMod->getOutputMessageQueue()->pop()) != 0) + while ((message = getInputMessageQueue()->pop()) != 0) { if (handleMessage(*message)) { @@ -358,6 +358,7 @@ WFMModGUI::WFMModGUI(PluginAPI* pluginAPI, DeviceSinkAPI *deviceAPI, QWidget* pa connect(this, SIGNAL(menuDoubleClickEvent()), this, SLOT(onMenuDoubleClicked())); m_wfmMod = new WFMMod(); + m_wfmMod->setMessageQueueToGUI(getInputMessageQueue()); m_channelizer = new UpChannelizer(m_wfmMod); m_threadedChannelizer = new ThreadedBasebandSampleSource(m_channelizer, this); //m_pluginAPI->addThreadedSink(m_threadedChannelizer); @@ -390,7 +391,7 @@ WFMModGUI::WFMModGUI(PluginAPI* pluginAPI, DeviceSinkAPI *deviceAPI, QWidget* pa applySettings(); - connect(m_wfmMod->getOutputMessageQueue(), SIGNAL(messageEnqueued()), this, SLOT(handleSourceMessages())); + connect(getInputMessageQueue(), SIGNAL(messageEnqueued()), this, SLOT(handleSourceMessages())); connect(m_wfmMod, SIGNAL(levelChanged(qreal, qreal, int)), ui->volumeMeter, SLOT(levelChanged(qreal, qreal, int))); } diff --git a/plugins/channeltx/udpsink/udpsinkgui.cpp b/plugins/channeltx/udpsink/udpsinkgui.cpp index fcd9c860f..300f92e97 100644 --- a/plugins/channeltx/udpsink/udpsinkgui.cpp +++ b/plugins/channeltx/udpsink/udpsinkgui.cpp @@ -178,7 +178,7 @@ void UDPSinkGUI::handleSourceMessages() { Message* message; - while ((message = m_udpSink->getOutputMessageQueue()->pop()) != 0) + while ((message = getInputMessageQueue()->pop()) != 0) { if (handleMessage(*message)) { @@ -205,6 +205,7 @@ UDPSinkGUI::UDPSinkGUI(PluginAPI* pluginAPI, DeviceSinkAPI *deviceAPI, QWidget* m_spectrumVis = new SpectrumVis(ui->glSpectrum); m_udpSink = new UDPSink(m_pluginAPI->getMainWindowMessageQueue(), this, m_spectrumVis); + m_udpSink->setMessageQueueToGUI(getInputMessageQueue()); m_channelizer = new UpChannelizer(m_udpSink); m_threadedChannelizer = new ThreadedBasebandSampleSource(m_channelizer, this); m_deviceAPI->addThreadedSource(m_threadedChannelizer); @@ -241,7 +242,7 @@ UDPSinkGUI::UDPSinkGUI(PluginAPI* pluginAPI, DeviceSinkAPI *deviceAPI, QWidget* displaySettings(); applySettings(true); - connect(m_udpSink->getOutputMessageQueue(), SIGNAL(messageEnqueued()), this, SLOT(handleSourceMessages())); + connect(getInputMessageQueue(), SIGNAL(messageEnqueued()), this, SLOT(handleSourceMessages())); connect(m_udpSink, SIGNAL(levelChanged(qreal, qreal, int)), ui->volumeMeter, SLOT(levelChanged(qreal, qreal, int))); } diff --git a/sdrbase/dsp/basebandsamplesource.h b/sdrbase/dsp/basebandsamplesource.h index ce7b0014b..d860505d1 100644 --- a/sdrbase/dsp/basebandsamplesource.h +++ b/sdrbase/dsp/basebandsamplesource.h @@ -1,71 +1,72 @@ -/////////////////////////////////////////////////////////////////////////////////// -// Copyright (C) 2016 F4EXB // -// written by Edouard Griffiths // -// // -// This program is free software; you can redistribute it and/or modify // -// it under the terms of the GNU General Public License as published by // -// the Free Software Foundation as version 3 of the License, or // -// // -// This program is distributed in the hope that it will be useful, // -// but WITHOUT ANY WARRANTY; without even the implied warranty of // -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // -// GNU General Public License V3 for more details. // -// // -// You should have received a copy of the GNU General Public License // -// along with this program. If not, see . // -/////////////////////////////////////////////////////////////////////////////////// - -#ifndef SDRBASE_DSP_BASEBANDSAMPLESOURCE_H_ -#define SDRBASE_DSP_BASEBANDSAMPLESOURCE_H_ - -#include -#include "dsp/dsptypes.h" -#include "dsp/samplesourcefifo.h" -#include "util/export.h" -#include "util/messagequeue.h" - -class Message; - -class SDRANGEL_API BasebandSampleSource : public QObject { - Q_OBJECT -public: - BasebandSampleSource(); - virtual ~BasebandSampleSource(); - - virtual void start() = 0; - virtual void stop() = 0; - virtual void pull(Sample& sample) = 0; - virtual void pullAudio(int nbSamples __attribute__((unused))) {} - - /** direct feeding of sample source FIFO */ - void feed(SampleSourceFifo* sampleFifo, int nbSamples) - { - SampleVector::iterator writeAt; - sampleFifo->getWriteIterator(writeAt); - pullAudio(nbSamples); // Pre-fetch input audio samples this is mandatory to keep things running smoothly - - for (int i = 0; i < nbSamples; i++) - { - pull((*writeAt)); - sampleFifo->bumpIndex(writeAt); - } - } - - SampleSourceFifo& getSampleSourceFifo() { return m_sampleFifo; } - - virtual bool handleMessage(const Message& cmd) = 0; //!< Processing of a message. Returns true if message has actually been processed - - MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; } //!< Get the queue for asynchronous inbound communication - MessageQueue *getOutputMessageQueue() { return &m_outputMessageQueue; } //!< Get the queue for asynchronous outbound communication - -protected: - MessageQueue m_inputMessageQueue; //!< Queue for asynchronous inbound communication - MessageQueue m_outputMessageQueue; //!< Queue for asynchronous outbound communication - SampleSourceFifo m_sampleFifo; //!< Internal FIFO for multi-channel processing - -protected slots: - void handleInputMessages(); - void handleWriteToFifo(int nbSamples); -}; - -#endif /* SDRBASE_DSP_BASEBANDSAMPLESOURCE_H_ */ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2016 F4EXB // +// written by Edouard Griffiths // +// // +// This program is free software; you can redistribute it and/or modify // +// it under the terms of the GNU General Public License as published by // +// the Free Software Foundation as version 3 of the License, or // +// // +// This program is distributed in the hope that it will be useful, // +// but WITHOUT ANY WARRANTY; without even the implied warranty of // +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // +// GNU General Public License V3 for more details. // +// // +// You should have received a copy of the GNU General Public License // +// along with this program. If not, see . // +/////////////////////////////////////////////////////////////////////////////////// + +#ifndef SDRBASE_DSP_BASEBANDSAMPLESOURCE_H_ +#define SDRBASE_DSP_BASEBANDSAMPLESOURCE_H_ + +#include +#include "dsp/dsptypes.h" +#include "dsp/samplesourcefifo.h" +#include "util/export.h" +#include "util/messagequeue.h" + +class Message; + +class SDRANGEL_API BasebandSampleSource : public QObject { + Q_OBJECT +public: + BasebandSampleSource(); + virtual ~BasebandSampleSource(); + + virtual void start() = 0; + virtual void stop() = 0; + virtual void pull(Sample& sample) = 0; + virtual void pullAudio(int nbSamples __attribute__((unused))) {} + + /** direct feeding of sample source FIFO */ + void feed(SampleSourceFifo* sampleFifo, int nbSamples) + { + SampleVector::iterator writeAt; + sampleFifo->getWriteIterator(writeAt); + pullAudio(nbSamples); // Pre-fetch input audio samples this is mandatory to keep things running smoothly + + for (int i = 0; i < nbSamples; i++) + { + pull((*writeAt)); + sampleFifo->bumpIndex(writeAt); + } + } + + SampleSourceFifo& getSampleSourceFifo() { return m_sampleFifo; } + + virtual bool handleMessage(const Message& cmd) = 0; //!< Processing of a message. Returns true if message has actually been processed + + MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; } //!< Get the queue for asynchronous inbound communication + virtual void setMessageQueueToGUI(MessageQueue *queue) { m_guiMessageQueue = queue; } + MessageQueue *getMessageQueueToGUI() { return m_guiMessageQueue; } + +protected: + MessageQueue m_inputMessageQueue; //!< Queue for asynchronous inbound communication + MessageQueue *m_guiMessageQueue; //!< Input message queue to the GUI + SampleSourceFifo m_sampleFifo; //!< Internal FIFO for multi-channel processing + +protected slots: + void handleInputMessages(); + void handleWriteToFifo(int nbSamples); +}; + +#endif /* SDRBASE_DSP_BASEBANDSAMPLESOURCE_H_ */ diff --git a/sdrbase/dsp/threadedbasebandsamplesource.h b/sdrbase/dsp/threadedbasebandsamplesource.h index 35fd47bdc..4f509ee88 100644 --- a/sdrbase/dsp/threadedbasebandsamplesource.h +++ b/sdrbase/dsp/threadedbasebandsamplesource.h @@ -38,8 +38,6 @@ public: ~ThreadedBasebandSampleSource(); const BasebandSampleSource *getSource() const { return m_basebandSampleSource; } - MessageQueue* getInputMessageQueue() { return m_basebandSampleSource->getInputMessageQueue(); } //!< Return pointer to sample source's input message queue - MessageQueue* getOutputMessageQueue() { return m_basebandSampleSource->getOutputMessageQueue(); } //!< Return pointer to sample source's output message queue void start(); //!< this thread start() void stop(); //!< this thread exit() and wait() From c4bad4d8341270d2eab5d98528ba98eef22e8463 Mon Sep 17 00:00:00 2001 From: f4exb Date: Thu, 28 Sep 2017 14:07:41 +0200 Subject: [PATCH 33/71] CRLF problem --- .../limesdroutput/limesdroutputsettings.h | 124 +-- .../samplesource/fcdproplus/fcdproplus.pro | 86 +- .../limesdrinput/limesdrinputsettings.h | 152 +-- sdrbase/audio/audioinput.h | 138 +-- sdrbase/dsp/basebandsamplesource.cpp | 116 +-- sdrbase/dsp/devicesamplesink.cpp | 90 +- sdrbase/gui/cwkeyergui.ui | 882 +++++++++--------- sdrbase/gui/myposdialog.ui | 244 ++--- sdrbase/gui/valuedialz.h | 166 ++-- 9 files changed, 999 insertions(+), 999 deletions(-) diff --git a/plugins/samplesink/limesdroutput/limesdroutputsettings.h b/plugins/samplesink/limesdroutput/limesdroutputsettings.h index cf84863e0..991f0932e 100644 --- a/plugins/samplesink/limesdroutput/limesdroutputsettings.h +++ b/plugins/samplesink/limesdroutput/limesdroutputsettings.h @@ -1,62 +1,62 @@ -/////////////////////////////////////////////////////////////////////////////////// -// Copyright (C) 2017 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 // -// // -// This program is distributed in the hope that it will be useful, // -// but WITHOUT ANY WARRANTY; without even the implied warranty of // -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // -// GNU General Public License V3 for more details. // -// // -// You should have received a copy of the GNU General Public License // -// along with this program. If not, see . // -/////////////////////////////////////////////////////////////////////////////////// - -#ifndef PLUGINS_SAMPLESOURCE_LIMESDROUTPUT_LIMESDROUTPUTSETTINGS_H_ -#define PLUGINS_SAMPLESOURCE_LIMESDROUTPUT_LIMESDROUTPUTSETTINGS_H_ - -#include -#include - -/** - * These are the settings individual to each hardware channel or software Tx chain - * Plus the settings to be saved in the presets - */ -struct LimeSDROutputSettings -{ - typedef enum { - FC_POS_INFRA = 0, - FC_POS_SUPRA, - FC_POS_CENTER - } fcPos_t; - - enum PathRFE - { - PATH_RFE_NONE = 0, - PATH_RFE_TXRF1, - PATH_RFE_TXEF2 - }; - - // global settings to be saved - uint64_t m_centerFrequency; - int m_devSampleRate; - uint32_t m_log2HardInterp; - // channel settings - uint32_t m_log2SoftInterp; - float m_lpfBW; //!< LMS amalog lowpass filter bandwidth (Hz) - bool m_lpfFIREnable; //!< Enable LMS digital lowpass FIR filters - float m_lpfFIRBW; //!< LMS digital lowpass FIR filters bandwidth (Hz) - uint32_t m_gain; //!< Optimally distributed gain (dB) - bool m_ncoEnable; //!< Enable TSP NCO and mixing - int m_ncoFrequency; //!< Actual NCO frequency (the resulting frequency with mixing is displayed) - PathRFE m_antennaPath; - - LimeSDROutputSettings(); - void resetToDefaults(); - QByteArray serialize() const; - bool deserialize(const QByteArray& data); -}; - -#endif /* PLUGINS_SAMPLESOURCE_LIMESDRINPUT_LIMESDRINPUTSETTINGS_H_ */ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2017 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 // +// // +// This program is distributed in the hope that it will be useful, // +// but WITHOUT ANY WARRANTY; without even the implied warranty of // +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // +// GNU General Public License V3 for more details. // +// // +// You should have received a copy of the GNU General Public License // +// along with this program. If not, see . // +/////////////////////////////////////////////////////////////////////////////////// + +#ifndef PLUGINS_SAMPLESOURCE_LIMESDROUTPUT_LIMESDROUTPUTSETTINGS_H_ +#define PLUGINS_SAMPLESOURCE_LIMESDROUTPUT_LIMESDROUTPUTSETTINGS_H_ + +#include +#include + +/** + * These are the settings individual to each hardware channel or software Tx chain + * Plus the settings to be saved in the presets + */ +struct LimeSDROutputSettings +{ + typedef enum { + FC_POS_INFRA = 0, + FC_POS_SUPRA, + FC_POS_CENTER + } fcPos_t; + + enum PathRFE + { + PATH_RFE_NONE = 0, + PATH_RFE_TXRF1, + PATH_RFE_TXEF2 + }; + + // global settings to be saved + uint64_t m_centerFrequency; + int m_devSampleRate; + uint32_t m_log2HardInterp; + // channel settings + uint32_t m_log2SoftInterp; + float m_lpfBW; //!< LMS amalog lowpass filter bandwidth (Hz) + bool m_lpfFIREnable; //!< Enable LMS digital lowpass FIR filters + float m_lpfFIRBW; //!< LMS digital lowpass FIR filters bandwidth (Hz) + uint32_t m_gain; //!< Optimally distributed gain (dB) + bool m_ncoEnable; //!< Enable TSP NCO and mixing + int m_ncoFrequency; //!< Actual NCO frequency (the resulting frequency with mixing is displayed) + PathRFE m_antennaPath; + + LimeSDROutputSettings(); + void resetToDefaults(); + QByteArray serialize() const; + bool deserialize(const QByteArray& data); +}; + +#endif /* PLUGINS_SAMPLESOURCE_LIMESDRINPUT_LIMESDRINPUTSETTINGS_H_ */ diff --git a/plugins/samplesource/fcdproplus/fcdproplus.pro b/plugins/samplesource/fcdproplus/fcdproplus.pro index 45cf21dc2..c6ea9344f 100644 --- a/plugins/samplesource/fcdproplus/fcdproplus.pro +++ b/plugins/samplesource/fcdproplus/fcdproplus.pro @@ -1,43 +1,43 @@ -#-------------------------------------------------------- -# -# Pro file for Android and Windows builds with Qt Creator -# -#-------------------------------------------------------- - -TEMPLATE = lib -CONFIG += plugin - -QT += core gui widgets multimedia network - -TARGET = inputfcdproplus - -DEFINES += USE_SSE2=1 -QMAKE_CXXFLAGS += -msse2 -DEFINES += USE_SSE4_1=1 -QMAKE_CXXFLAGS += -msse4.1 - -INCLUDEPATH += $$PWD -INCLUDEPATH += ../../../sdrbase -INCLUDEPATH += ../../../fcdhid -INCLUDEPATH += ../../../fcdlib - -CONFIG(Release):build_subdir = release -CONFIG(Debug):build_subdir = debug - -SOURCES = fcdproplusgui.cpp\ - fcdproplusinputqt.cpp\ - fcdproplusplugin.cpp\ - fcdproplussettings.cpp\ - fcdproplusreader.cpp - -HEADERS = fcdproplusgui.h\ - fcdproplusinputqt.h\ - fcdproplusplugin.h\ - fcdproplussettings.h\ - fcdproplusreader.h - -FORMS += fcdproplusgui.ui - -LIBS += -L../../../fcdlib/$${build_subdir} -lfcdlib -LIBS += -L../../../fcdhid/$${build_subdir} -lfcdhid -LIBS += -L../../../sdrbase/$${build_subdir} -lsdrbase +#-------------------------------------------------------- +# +# Pro file for Android and Windows builds with Qt Creator +# +#-------------------------------------------------------- + +TEMPLATE = lib +CONFIG += plugin + +QT += core gui widgets multimedia network + +TARGET = inputfcdproplus + +DEFINES += USE_SSE2=1 +QMAKE_CXXFLAGS += -msse2 +DEFINES += USE_SSE4_1=1 +QMAKE_CXXFLAGS += -msse4.1 + +INCLUDEPATH += $$PWD +INCLUDEPATH += ../../../sdrbase +INCLUDEPATH += ../../../fcdhid +INCLUDEPATH += ../../../fcdlib + +CONFIG(Release):build_subdir = release +CONFIG(Debug):build_subdir = debug + +SOURCES = fcdproplusgui.cpp\ + fcdproplusinputqt.cpp\ + fcdproplusplugin.cpp\ + fcdproplussettings.cpp\ + fcdproplusreader.cpp + +HEADERS = fcdproplusgui.h\ + fcdproplusinputqt.h\ + fcdproplusplugin.h\ + fcdproplussettings.h\ + fcdproplusreader.h + +FORMS += fcdproplusgui.ui + +LIBS += -L../../../fcdlib/$${build_subdir} -lfcdlib +LIBS += -L../../../fcdhid/$${build_subdir} -lfcdhid +LIBS += -L../../../sdrbase/$${build_subdir} -lsdrbase diff --git a/plugins/samplesource/limesdrinput/limesdrinputsettings.h b/plugins/samplesource/limesdrinput/limesdrinputsettings.h index cb5f858f5..32caafa2f 100644 --- a/plugins/samplesource/limesdrinput/limesdrinputsettings.h +++ b/plugins/samplesource/limesdrinput/limesdrinputsettings.h @@ -1,76 +1,76 @@ -/////////////////////////////////////////////////////////////////////////////////// -// Copyright (C) 2017 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 // -// // -// This program is distributed in the hope that it will be useful, // -// but WITHOUT ANY WARRANTY; without even the implied warranty of // -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // -// GNU General Public License V3 for more details. // -// // -// You should have received a copy of the GNU General Public License // -// along with this program. If not, see . // -/////////////////////////////////////////////////////////////////////////////////// - -#ifndef PLUGINS_SAMPLESOURCE_LIMESDRINPUT_LIMESDRINPUTSETTINGS_H_ -#define PLUGINS_SAMPLESOURCE_LIMESDRINPUT_LIMESDRINPUTSETTINGS_H_ - -#include -#include - -/** - * These are the settings individual to each hardware channel or software Rx chain - * Plus the settings to be saved in the presets - */ -struct LimeSDRInputSettings -{ - typedef enum { - FC_POS_INFRA = 0, - FC_POS_SUPRA, - FC_POS_CENTER - } fcPos_t; - - enum PathRFE - { - PATH_RFE_NONE = 0, - PATH_RFE_LNAH, - PATH_RFE_LNAL, - PATH_RFE_LNAW, - PATH_RFE_LB1, - PATH_RFE_LB2 - }; - - typedef enum { - GAIN_AUTO, - GAIN_MANUAL - } GainMode; - - // global settings to be saved - uint64_t m_centerFrequency; - int m_devSampleRate; - uint32_t m_log2HardDecim; - // channel settings - bool m_dcBlock; - bool m_iqCorrection; - uint32_t m_log2SoftDecim; - float m_lpfBW; //!< LMS amalog lowpass filter bandwidth (Hz) - bool m_lpfFIREnable; //!< Enable LMS digital lowpass FIR filters - float m_lpfFIRBW; //!< LMS digital lowpass FIR filters bandwidth (Hz) - uint32_t m_gain; //!< Optimally distributed gain (dB) - bool m_ncoEnable; //!< Enable TSP NCO and mixing - int m_ncoFrequency; //!< Actual NCO frequency (the resulting frequency with mixing is displayed) - PathRFE m_antennaPath; - GainMode m_gainMode; //!< Gain mode: auto or manual - uint32_t m_lnaGain; //!< Manual LAN gain - uint32_t m_tiaGain; //!< Manual TIA gain - uint32_t m_pgaGain; //!< Manual PGA gain - - LimeSDRInputSettings(); - void resetToDefaults(); - QByteArray serialize() const; - bool deserialize(const QByteArray& data); -}; - -#endif /* PLUGINS_SAMPLESOURCE_LIMESDRINPUT_LIMESDRINPUTSETTINGS_H_ */ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2017 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 // +// // +// This program is distributed in the hope that it will be useful, // +// but WITHOUT ANY WARRANTY; without even the implied warranty of // +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // +// GNU General Public License V3 for more details. // +// // +// You should have received a copy of the GNU General Public License // +// along with this program. If not, see . // +/////////////////////////////////////////////////////////////////////////////////// + +#ifndef PLUGINS_SAMPLESOURCE_LIMESDRINPUT_LIMESDRINPUTSETTINGS_H_ +#define PLUGINS_SAMPLESOURCE_LIMESDRINPUT_LIMESDRINPUTSETTINGS_H_ + +#include +#include + +/** + * These are the settings individual to each hardware channel or software Rx chain + * Plus the settings to be saved in the presets + */ +struct LimeSDRInputSettings +{ + typedef enum { + FC_POS_INFRA = 0, + FC_POS_SUPRA, + FC_POS_CENTER + } fcPos_t; + + enum PathRFE + { + PATH_RFE_NONE = 0, + PATH_RFE_LNAH, + PATH_RFE_LNAL, + PATH_RFE_LNAW, + PATH_RFE_LB1, + PATH_RFE_LB2 + }; + + typedef enum { + GAIN_AUTO, + GAIN_MANUAL + } GainMode; + + // global settings to be saved + uint64_t m_centerFrequency; + int m_devSampleRate; + uint32_t m_log2HardDecim; + // channel settings + bool m_dcBlock; + bool m_iqCorrection; + uint32_t m_log2SoftDecim; + float m_lpfBW; //!< LMS amalog lowpass filter bandwidth (Hz) + bool m_lpfFIREnable; //!< Enable LMS digital lowpass FIR filters + float m_lpfFIRBW; //!< LMS digital lowpass FIR filters bandwidth (Hz) + uint32_t m_gain; //!< Optimally distributed gain (dB) + bool m_ncoEnable; //!< Enable TSP NCO and mixing + int m_ncoFrequency; //!< Actual NCO frequency (the resulting frequency with mixing is displayed) + PathRFE m_antennaPath; + GainMode m_gainMode; //!< Gain mode: auto or manual + uint32_t m_lnaGain; //!< Manual LAN gain + uint32_t m_tiaGain; //!< Manual TIA gain + uint32_t m_pgaGain; //!< Manual PGA gain + + LimeSDRInputSettings(); + void resetToDefaults(); + QByteArray serialize() const; + bool deserialize(const QByteArray& data); +}; + +#endif /* PLUGINS_SAMPLESOURCE_LIMESDRINPUT_LIMESDRINPUTSETTINGS_H_ */ diff --git a/sdrbase/audio/audioinput.h b/sdrbase/audio/audioinput.h index 39e7ed40c..c08d366b6 100644 --- a/sdrbase/audio/audioinput.h +++ b/sdrbase/audio/audioinput.h @@ -1,69 +1,69 @@ -/////////////////////////////////////////////////////////////////////////////////// -// Copyright (C) 2016 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 // -// // -// This program is distributed in the hope that it will be useful, // -// but WITHOUT ANY WARRANTY; without even the implied warranty of // -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // -// GNU General Public License V3 for more details. // -// // -// You should have received a copy of the GNU General Public License // -// along with this program. If not, see . // -/////////////////////////////////////////////////////////////////////////////////// - -#ifndef SDRBASE_AUDIO_AUDIOINPUT_H_ -#define SDRBASE_AUDIO_AUDIOINPUT_H_ - -#include -#include -#include -#include -#include -#include "util/export.h" - -class QAudioInput; -class AudioFifo; -class AudioOutputPipe; - - -class SDRANGEL_API AudioInput : public QIODevice { -public: - AudioInput(); - virtual ~AudioInput(); - - bool start(int device, int rate); - void stop(); - - void addFifo(AudioFifo* audioFifo); - void removeFifo(AudioFifo* audioFifo); - - uint getRate() const { return m_audioFormat.sampleRate(); } - void setOnExit(bool onExit) { m_onExit = onExit; } - void setVolume(float volume) { m_volume = volume; } - -private: - QMutex m_mutex; - QAudioInput* m_audioInput; - uint m_audioUsageCount; - bool m_onExit; - float m_volume; - - typedef std::list AudioFifos; - AudioFifos m_audioFifos; - std::vector m_mixBuffer; - - QAudioFormat m_audioFormat; - - //virtual bool open(OpenMode mode); - virtual qint64 readData(char* data, qint64 maxLen); - virtual qint64 writeData(const char* data, qint64 len); - - friend class AudioOutputPipe; -}; - - - -#endif /* SDRBASE_AUDIO_AUDIOINPUT_H_ */ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2016 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 // +// // +// This program is distributed in the hope that it will be useful, // +// but WITHOUT ANY WARRANTY; without even the implied warranty of // +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // +// GNU General Public License V3 for more details. // +// // +// You should have received a copy of the GNU General Public License // +// along with this program. If not, see . // +/////////////////////////////////////////////////////////////////////////////////// + +#ifndef SDRBASE_AUDIO_AUDIOINPUT_H_ +#define SDRBASE_AUDIO_AUDIOINPUT_H_ + +#include +#include +#include +#include +#include +#include "util/export.h" + +class QAudioInput; +class AudioFifo; +class AudioOutputPipe; + + +class SDRANGEL_API AudioInput : public QIODevice { +public: + AudioInput(); + virtual ~AudioInput(); + + bool start(int device, int rate); + void stop(); + + void addFifo(AudioFifo* audioFifo); + void removeFifo(AudioFifo* audioFifo); + + uint getRate() const { return m_audioFormat.sampleRate(); } + void setOnExit(bool onExit) { m_onExit = onExit; } + void setVolume(float volume) { m_volume = volume; } + +private: + QMutex m_mutex; + QAudioInput* m_audioInput; + uint m_audioUsageCount; + bool m_onExit; + float m_volume; + + typedef std::list AudioFifos; + AudioFifos m_audioFifos; + std::vector m_mixBuffer; + + QAudioFormat m_audioFormat; + + //virtual bool open(OpenMode mode); + virtual qint64 readData(char* data, qint64 maxLen); + virtual qint64 writeData(const char* data, qint64 len); + + friend class AudioOutputPipe; +}; + + + +#endif /* SDRBASE_AUDIO_AUDIOINPUT_H_ */ diff --git a/sdrbase/dsp/basebandsamplesource.cpp b/sdrbase/dsp/basebandsamplesource.cpp index 63c2d9853..76ea093a3 100644 --- a/sdrbase/dsp/basebandsamplesource.cpp +++ b/sdrbase/dsp/basebandsamplesource.cpp @@ -1,58 +1,58 @@ -/////////////////////////////////////////////////////////////////////////////////// -// Copyright (C) 2016 F4EXB // -// written by Edouard Griffiths // -// // -// This program is free software; you can redistribute it and/or modify // -// it under the terms of the GNU General Public License as published by // -// the Free Software Foundation as version 3 of the License, or // -// // -// This program is distributed in the hope that it will be useful, // -// but WITHOUT ANY WARRANTY; without even the implied warranty of // -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // -// GNU General Public License V3 for more details. // -// // -// You should have received a copy of the GNU General Public License // -// along with this program. If not, see . // -/////////////////////////////////////////////////////////////////////////////////// - -#include "dsp/basebandsamplesource.h" -#include "util/message.h" - -BasebandSampleSource::BasebandSampleSource() : - m_sampleFifo(48000) // arbitrary, will be adjusted to match device sink FIFO size -{ - connect(&m_inputMessageQueue, SIGNAL(messageEnqueued()), this, SLOT(handleInputMessages())); - connect(&m_sampleFifo, SIGNAL(dataWrite(int)), this, SLOT(handleWriteToFifo(int))); -} - -BasebandSampleSource::~BasebandSampleSource() -{ -} - -void BasebandSampleSource::handleInputMessages() -{ - Message* message; - - while ((message = m_inputMessageQueue.pop()) != 0) - { - if (handleMessage(*message)) - { - delete message; - } - } -} - -void BasebandSampleSource::handleWriteToFifo(int nbSamples) -{ - SampleVector::iterator writeAt; - m_sampleFifo.getWriteIterator(writeAt); - pullAudio(nbSamples); // Pre-fetch input audio samples this is mandatory to keep things running smoothly - - for (int i = 0; i < nbSamples; i++) - { - pull((*writeAt)); - m_sampleFifo.bumpIndex(writeAt); - } -} - - +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2016 F4EXB // +// written by Edouard Griffiths // +// // +// This program is free software; you can redistribute it and/or modify // +// it under the terms of the GNU General Public License as published by // +// the Free Software Foundation as version 3 of the License, or // +// // +// This program is distributed in the hope that it will be useful, // +// but WITHOUT ANY WARRANTY; without even the implied warranty of // +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // +// GNU General Public License V3 for more details. // +// // +// You should have received a copy of the GNU General Public License // +// along with this program. If not, see . // +/////////////////////////////////////////////////////////////////////////////////// + +#include "dsp/basebandsamplesource.h" +#include "util/message.h" + +BasebandSampleSource::BasebandSampleSource() : + m_sampleFifo(48000) // arbitrary, will be adjusted to match device sink FIFO size +{ + connect(&m_inputMessageQueue, SIGNAL(messageEnqueued()), this, SLOT(handleInputMessages())); + connect(&m_sampleFifo, SIGNAL(dataWrite(int)), this, SLOT(handleWriteToFifo(int))); +} + +BasebandSampleSource::~BasebandSampleSource() +{ +} + +void BasebandSampleSource::handleInputMessages() +{ + Message* message; + + while ((message = m_inputMessageQueue.pop()) != 0) + { + if (handleMessage(*message)) + { + delete message; + } + } +} + +void BasebandSampleSource::handleWriteToFifo(int nbSamples) +{ + SampleVector::iterator writeAt; + m_sampleFifo.getWriteIterator(writeAt); + pullAudio(nbSamples); // Pre-fetch input audio samples this is mandatory to keep things running smoothly + + for (int i = 0; i < nbSamples; i++) + { + pull((*writeAt)); + m_sampleFifo.bumpIndex(writeAt); + } +} + + diff --git a/sdrbase/dsp/devicesamplesink.cpp b/sdrbase/dsp/devicesamplesink.cpp index bd76d6e5a..dfedfdbb7 100644 --- a/sdrbase/dsp/devicesamplesink.cpp +++ b/sdrbase/dsp/devicesamplesink.cpp @@ -1,45 +1,45 @@ -/////////////////////////////////////////////////////////////////////////////////// -// Copyright (C) 2016 F4EXB // -// written by Edouard Griffiths // -// // -// This program is free software; you can redistribute it and/or modify // -// it under the terms of the GNU General Public License as published by // -// the Free Software Foundation as version 3 of the License, or // -// // -// This program is distributed in the hope that it will be useful, // -// but WITHOUT ANY WARRANTY; without even the implied warranty of // -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // -// GNU General Public License V3 for more details. // -// // -// You should have received a copy of the GNU General Public License // -// along with this program. If not, see . // -/////////////////////////////////////////////////////////////////////////////////// - -#include "dsp/devicesamplesink.h" - -DeviceSampleSink::DeviceSampleSink() : - m_sampleSourceFifo(1<<19) -{ - connect(&m_inputMessageQueue, SIGNAL(messageEnqueued()), this, SLOT(handleInputMessages())); -} - -DeviceSampleSink::~DeviceSampleSink() -{ -} - -void DeviceSampleSink::handleInputMessages() -{ - Message* message; - - while ((message = m_inputMessageQueue.pop()) != 0) - { - if (handleMessage(*message)) - { - delete message; - } - } -} - - - - +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2016 F4EXB // +// written by Edouard Griffiths // +// // +// This program is free software; you can redistribute it and/or modify // +// it under the terms of the GNU General Public License as published by // +// the Free Software Foundation as version 3 of the License, or // +// // +// This program is distributed in the hope that it will be useful, // +// but WITHOUT ANY WARRANTY; without even the implied warranty of // +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // +// GNU General Public License V3 for more details. // +// // +// You should have received a copy of the GNU General Public License // +// along with this program. If not, see . // +/////////////////////////////////////////////////////////////////////////////////// + +#include "dsp/devicesamplesink.h" + +DeviceSampleSink::DeviceSampleSink() : + m_sampleSourceFifo(1<<19) +{ + connect(&m_inputMessageQueue, SIGNAL(messageEnqueued()), this, SLOT(handleInputMessages())); +} + +DeviceSampleSink::~DeviceSampleSink() +{ +} + +void DeviceSampleSink::handleInputMessages() +{ + Message* message; + + while ((message = m_inputMessageQueue.pop()) != 0) + { + if (handleMessage(*message)) + { + delete message; + } + } +} + + + + diff --git a/sdrbase/gui/cwkeyergui.ui b/sdrbase/gui/cwkeyergui.ui index de024323a..fe5899f94 100644 --- a/sdrbase/gui/cwkeyergui.ui +++ b/sdrbase/gui/cwkeyergui.ui @@ -1,441 +1,441 @@ - - - CWKeyerGUI - - - - 0 - 0 - 375 - 60 - - - - - Sans Serif - 8 - - - - CW Keyer - - - - 2 - - - 3 - - - - - 3 - - - - - WPM - - - - - - - - 24 - 24 - - - - CW speed (WPM) - - - 1 - - - 26 - - - 1 - - - 13 - - - - - - - - 16 - 0 - - - - - 9 - - - - CW speed display (WPM) - - - 13 - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - - 0 - 0 - - - - - 24 - 24 - - - - - - - - - 255 - 255 - 255 - - - - - - - - - 255 - 255 - 255 - - - - - - - - - 255 - 255 - 255 - - - - - - - - - 12 - 75 - true - - - - Send dots - - - . - - - - - - - - 0 - 0 - - - - - 24 - 24 - - - - - - - - - 255 - 255 - 255 - - - - - - - - - 255 - 255 - 255 - - - - - - - - - 255 - 255 - 255 - - - - - - - - - 12 - 75 - true - - - - Send dashes - - - - - - - - - - - Qt::Vertical - - - - - - - - 0 - 0 - - - - - 24 - 24 - - - - - - - - - 255 - 255 - 255 - - - - - - - - - 255 - 255 - 255 - - - - - - - - - 106 - 104 - 100 - - - - - - - - - DejaVu Serif - 9 - 75 - true - - - - Send text written above - - - T - - - true - - - - - - - - 0 - 0 - - - - - 24 - 24 - - - - Play text in a loop - - - - :/playloop.png:/playloop.png - - - - 16 - 16 - - - - true - - - - - - - - 0 - 0 - - - - - 24 - 24 - - - - Play / stop text coding - - - - :/play.png - :/stop.png:/play.png - - - - 16 - 16 - - - - true - - - false - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - - - CW text - - - - - - - - 24 - 24 - - - - - 24 - 24 - - - - Clear CW text - - - - - - - :/clear.png:/clear.png - - - - 16 - 16 - - - - - - - - - - - ButtonSwitch - QToolButton -
gui/buttonswitch.h
-
-
- - playLoopCW - - - - - -
+ + + CWKeyerGUI + + + + 0 + 0 + 375 + 60 + + + + + Sans Serif + 8 + + + + CW Keyer + + + + 2 + + + 3 + + + + + 3 + + + + + WPM + + + + + + + + 24 + 24 + + + + CW speed (WPM) + + + 1 + + + 26 + + + 1 + + + 13 + + + + + + + + 16 + 0 + + + + + 9 + + + + CW speed display (WPM) + + + 13 + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + 0 + 0 + + + + + 24 + 24 + + + + + + + + + 255 + 255 + 255 + + + + + + + + + 255 + 255 + 255 + + + + + + + + + 255 + 255 + 255 + + + + + + + + + 12 + 75 + true + + + + Send dots + + + . + + + + + + + + 0 + 0 + + + + + 24 + 24 + + + + + + + + + 255 + 255 + 255 + + + + + + + + + 255 + 255 + 255 + + + + + + + + + 255 + 255 + 255 + + + + + + + + + 12 + 75 + true + + + + Send dashes + + + - + + + + + + + Qt::Vertical + + + + + + + + 0 + 0 + + + + + 24 + 24 + + + + + + + + + 255 + 255 + 255 + + + + + + + + + 255 + 255 + 255 + + + + + + + + + 106 + 104 + 100 + + + + + + + + + DejaVu Serif + 9 + 75 + true + + + + Send text written above + + + T + + + true + + + + + + + + 0 + 0 + + + + + 24 + 24 + + + + Play text in a loop + + + + :/playloop.png:/playloop.png + + + + 16 + 16 + + + + true + + + + + + + + 0 + 0 + + + + + 24 + 24 + + + + Play / stop text coding + + + + :/play.png + :/stop.png:/play.png + + + + 16 + 16 + + + + true + + + false + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + CW text + + + + + + + + 24 + 24 + + + + + 24 + 24 + + + + Clear CW text + + + + + + + :/clear.png:/clear.png + + + + 16 + 16 + + + + + + + + + + + ButtonSwitch + QToolButton +
gui/buttonswitch.h
+
+
+ + playLoopCW + + + + + +
diff --git a/sdrbase/gui/myposdialog.ui b/sdrbase/gui/myposdialog.ui index a794c7925..d87ff3ad8 100644 --- a/sdrbase/gui/myposdialog.ui +++ b/sdrbase/gui/myposdialog.ui @@ -1,122 +1,122 @@ - - - MyPositionDialog - - - - 0 - 0 - 324 - 127 - - - - - Sans Serif - 9 - - - - Dialog - - - - - - My Station Position - - - - - - Latitude - - - - - - - Longitude - - - - - - - 6 - - - -180.000000000000000 - - - 180.000000000000000 - - - - - - - 6 - - - -90.000000000000000 - - - 90.000000000000000 - - - - - - - - - - Qt::Horizontal - - - QDialogButtonBox::Cancel|QDialogButtonBox::Ok - - - - - - - buttonBox - - - - - buttonBox - accepted() - MyPositionDialog - accept() - - - 257 - 194 - - - 157 - 203 - - - - - buttonBox - rejected() - MyPositionDialog - reject() - - - 314 - 194 - - - 286 - 203 - - - - - + + + MyPositionDialog + + + + 0 + 0 + 324 + 127 + + + + + Sans Serif + 9 + + + + Dialog + + + + + + My Station Position + + + + + + Latitude + + + + + + + Longitude + + + + + + + 6 + + + -180.000000000000000 + + + 180.000000000000000 + + + + + + + 6 + + + -90.000000000000000 + + + 90.000000000000000 + + + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + buttonBox + + + + + buttonBox + accepted() + MyPositionDialog + accept() + + + 257 + 194 + + + 157 + 203 + + + + + buttonBox + rejected() + MyPositionDialog + reject() + + + 314 + 194 + + + 286 + 203 + + + + + diff --git a/sdrbase/gui/valuedialz.h b/sdrbase/gui/valuedialz.h index c7ad6b005..f7da0d8ab 100644 --- a/sdrbase/gui/valuedialz.h +++ b/sdrbase/gui/valuedialz.h @@ -1,83 +1,83 @@ -/////////////////////////////////////////////////////////////////////////////////// -// Copyright (C) 2017 F4EXB // -// written by Edouard Griffiths // -// // -// Same as ValueDial but handles optionally positive and negative numbers with // -// sign display. // -// // -// This program is free software; you can redistribute it and/or modify // -// it under the terms of the GNU General Public License as published by // -// the Free Software Foundation as version 3 of the License, or // -// // -// This program is distributed in the hope that it will be useful, // -// but WITHOUT ANY WARRANTY; without even the implied warranty of // -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // -// GNU General Public License V3 for more details. // -// // -// You should have received a copy of the GNU General Public License // -// along with this program. If not, see . // -/////////////////////////////////////////////////////////////////////////////////// - -#include -#include -#include "gui/colormapper.h" -#include "util/export.h" - -class SDRANGEL_API ValueDialZ : public QWidget { - Q_OBJECT - -public: - ValueDialZ(bool positiveOnly = true, QWidget* parent = NULL, ColorMapper colorMapper = ColorMapper(ColorMapper::Normal)); - - void setValue(qint64 value); - void setValueRange(bool positiveOnly, uint numDigits, qint64 min, qint64 max); - void setFont(const QFont& font); - void setBold(bool bold); - void setColorMapper(ColorMapper colorMapper); - qint64 getValue() const { return m_value; } - qint64 getValueNew() const { return m_valueNew; } - -signals: - void changed(qint64 value); - -private: - QLinearGradient m_background; - int m_numDigits; - int m_numDecimalPoints; - int m_digitWidth; - int m_digitHeight; - int m_hightlightedDigit; - int m_cursor; - bool m_cursorState; - qint64 m_value; - qint64 m_valueMax; - qint64 m_valueMin; - bool m_positiveOnly; - QString m_text; - - qint64 m_valueNew; - QString m_textNew; - int m_animationState; - QTimer m_animationTimer; - QTimer m_blinkTimer; - - ColorMapper m_colorMapper; - - quint64 findExponent(int digit); - QChar digitNeigh(QChar c, bool dir); - QString formatText(qint64 value); - - void paintEvent(QPaintEvent*); - - void mousePressEvent(QMouseEvent*); - void mouseMoveEvent(QMouseEvent*); - void wheelEvent(QWheelEvent*); - void leaveEvent(QEvent*); - void keyPressEvent(QKeyEvent*); - void focusInEvent(QFocusEvent*); - void focusOutEvent(QFocusEvent*); - -private slots: - void animate(); - void blink(); -}; +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2017 F4EXB // +// written by Edouard Griffiths // +// // +// Same as ValueDial but handles optionally positive and negative numbers with // +// sign display. // +// // +// This program is free software; you can redistribute it and/or modify // +// it under the terms of the GNU General Public License as published by // +// the Free Software Foundation as version 3 of the License, or // +// // +// This program is distributed in the hope that it will be useful, // +// but WITHOUT ANY WARRANTY; without even the implied warranty of // +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // +// GNU General Public License V3 for more details. // +// // +// You should have received a copy of the GNU General Public License // +// along with this program. If not, see . // +/////////////////////////////////////////////////////////////////////////////////// + +#include +#include +#include "gui/colormapper.h" +#include "util/export.h" + +class SDRANGEL_API ValueDialZ : public QWidget { + Q_OBJECT + +public: + ValueDialZ(bool positiveOnly = true, QWidget* parent = NULL, ColorMapper colorMapper = ColorMapper(ColorMapper::Normal)); + + void setValue(qint64 value); + void setValueRange(bool positiveOnly, uint numDigits, qint64 min, qint64 max); + void setFont(const QFont& font); + void setBold(bool bold); + void setColorMapper(ColorMapper colorMapper); + qint64 getValue() const { return m_value; } + qint64 getValueNew() const { return m_valueNew; } + +signals: + void changed(qint64 value); + +private: + QLinearGradient m_background; + int m_numDigits; + int m_numDecimalPoints; + int m_digitWidth; + int m_digitHeight; + int m_hightlightedDigit; + int m_cursor; + bool m_cursorState; + qint64 m_value; + qint64 m_valueMax; + qint64 m_valueMin; + bool m_positiveOnly; + QString m_text; + + qint64 m_valueNew; + QString m_textNew; + int m_animationState; + QTimer m_animationTimer; + QTimer m_blinkTimer; + + ColorMapper m_colorMapper; + + quint64 findExponent(int digit); + QChar digitNeigh(QChar c, bool dir); + QString formatText(qint64 value); + + void paintEvent(QPaintEvent*); + + void mousePressEvent(QMouseEvent*); + void mouseMoveEvent(QMouseEvent*); + void wheelEvent(QWheelEvent*); + void leaveEvent(QEvent*); + void keyPressEvent(QKeyEvent*); + void focusInEvent(QFocusEvent*); + void focusOutEvent(QFocusEvent*); + +private slots: + void animate(); + void blink(); +}; From 54bd4b38f009284dcc5a4bd2527534524d81b2ab Mon Sep 17 00:00:00 2001 From: f4exb Date: Thu, 28 Sep 2017 23:06:06 +0200 Subject: [PATCH 34/71] ChannelAnalyzer: decouple demod and GUI --- plugins/channelrx/chanalyzer/chanalyzer.cpp | 38 +++++- plugins/channelrx/chanalyzer/chanalyzer.h | 119 ++++++++++++------ .../channelrx/chanalyzer/chanalyzergui.cpp | 46 ++++--- plugins/channelrx/chanalyzer/chanalyzergui.h | 6 +- 4 files changed, 150 insertions(+), 59 deletions(-) diff --git a/plugins/channelrx/chanalyzer/chanalyzer.cpp b/plugins/channelrx/chanalyzer/chanalyzer.cpp index 641f75037..d7c42629f 100644 --- a/plugins/channelrx/chanalyzer/chanalyzer.cpp +++ b/plugins/channelrx/chanalyzer/chanalyzer.cpp @@ -14,19 +14,25 @@ // along with this program. If not, see . // /////////////////////////////////////////////////////////////////////////////////// -#include "../../channelrx/chanalyzer/chanalyzer.h" +#include "chanalyzer.h" -#include #include #include #include + +#include +#include "dsp/threadedbasebandsamplesink.h" +#include "device/devicesourceapi.h" #include "audio/audiooutput.h" MESSAGE_CLASS_DEFINITION(ChannelAnalyzer::MsgConfigureChannelAnalyzer, Message) +MESSAGE_CLASS_DEFINITION(ChannelAnalyzer::MsgConfigureChannelizer, Message) +MESSAGE_CLASS_DEFINITION(ChannelAnalyzer::MsgReportChannelSampleRateChanged, Message) -ChannelAnalyzer::ChannelAnalyzer(BasebandSampleSink* sampleSink) : - m_sampleSink(sampleSink), +ChannelAnalyzer::ChannelAnalyzer(DeviceSourceAPI *deviceAPI) : + m_deviceAPI(deviceAPI), + m_sampleSink(0), m_settingsMutex(QMutex::Recursive) { m_Bandwidth = 5000; @@ -42,12 +48,20 @@ ChannelAnalyzer::ChannelAnalyzer(BasebandSampleSink* sampleSink) : m_magsq = 0; SSBFilter = new fftfilt(m_LowCutoff / m_sampleRate, m_Bandwidth / m_sampleRate, ssbFftLen); DSBFilter = new fftfilt(m_Bandwidth / m_sampleRate, 2*ssbFftLen); + + m_channelizer = new DownChannelizer(this); + m_threadedChannelizer = new ThreadedBasebandSampleSink(m_channelizer, this); + connect(m_channelizer, SIGNAL(inputSampleRateChanged()), this, SLOT(channelSampleRateChanged())); + m_deviceAPI->addThreadedSink(m_threadedChannelizer); } ChannelAnalyzer::~ChannelAnalyzer() { if (SSBFilter) delete SSBFilter; if (DSBFilter) delete DSBFilter; + m_deviceAPI->removeThreadedSink(m_threadedChannelizer); + delete m_threadedChannelizer; + delete m_channelizer; } void ChannelAnalyzer::configure(MessageQueue* messageQueue, @@ -130,6 +144,12 @@ void ChannelAnalyzer::stop() { } +void ChannelAnalyzer::channelSampleRateChanged() +{ + MsgReportChannelSampleRateChanged *msg = MsgReportChannelSampleRateChanged::create(); + getMessageQueueToGUI()->push(msg); +} + bool ChannelAnalyzer::handleMessage(const Message& cmd) { float band, lowCutoff; @@ -148,6 +168,16 @@ bool ChannelAnalyzer::handleMessage(const Message& cmd) return true; } + else if (MsgConfigureChannelizer::match(cmd)) + { + MsgConfigureChannelizer& cfg = (MsgConfigureChannelizer&) cmd; + + m_channelizer->configure(m_channelizer->getInputMessageQueue(), + m_channelizer->getInputSampleRate(), + cfg.getCenterFrequency()); + + return true; + } else if (MsgConfigureChannelAnalyzer::match(cmd)) { MsgConfigureChannelAnalyzer& cfg = (MsgConfigureChannelAnalyzer&) cmd; diff --git a/plugins/channelrx/chanalyzer/chanalyzer.h b/plugins/channelrx/chanalyzer/chanalyzer.h index adc2c1361..7dd26732f 100644 --- a/plugins/channelrx/chanalyzer/chanalyzer.h +++ b/plugins/channelrx/chanalyzer/chanalyzer.h @@ -27,10 +27,87 @@ #define ssbFftLen 1024 +class DeviceSourceAPI; +class ThreadedBasebandSampleSink; +class DownChannelizer; + class ChannelAnalyzer : public BasebandSampleSink { public: - ChannelAnalyzer(BasebandSampleSink* m_sampleSink); + class MsgConfigureChannelAnalyzer : public Message { + MESSAGE_CLASS_DECLARATION + + public: + Real getBandwidth() const { return m_Bandwidth; } + Real getLoCutoff() const { return m_LowCutoff; } + int getSpanLog2() const { return m_spanLog2; } + bool getSSB() const { return m_ssb; } + + static MsgConfigureChannelAnalyzer* create(Real Bandwidth, + Real LowCutoff, + int spanLog2, + bool ssb) + { + return new MsgConfigureChannelAnalyzer(Bandwidth, LowCutoff, spanLog2, ssb); + } + + private: + Real m_Bandwidth; + Real m_LowCutoff; + int m_spanLog2; + bool m_ssb; + + MsgConfigureChannelAnalyzer(Real Bandwidth, + Real LowCutoff, + int spanLog2, + bool ssb) : + Message(), + m_Bandwidth(Bandwidth), + m_LowCutoff(LowCutoff), + m_spanLog2(spanLog2), + m_ssb(ssb) + { } + }; + + class MsgConfigureChannelizer : public Message { + MESSAGE_CLASS_DECLARATION + + public: + int getCenterFrequency() const { return m_centerFrequency; } + + static MsgConfigureChannelizer* create(int centerFrequency) + { + return new MsgConfigureChannelizer(centerFrequency); + } + + private: + int m_centerFrequency; + + MsgConfigureChannelizer(int centerFrequency) : + Message(), + m_centerFrequency(centerFrequency) + { } + }; + + class MsgReportChannelSampleRateChanged : public Message { + MESSAGE_CLASS_DECLARATION + + public: + + static MsgReportChannelSampleRateChanged* create() + { + return new MsgReportChannelSampleRateChanged(); + } + + private: + + MsgReportChannelSampleRateChanged() : + Message() + { } + }; + + ChannelAnalyzer(DeviceSourceAPI *deviceAPI); virtual ~ChannelAnalyzer(); + void setSampleSink(BasebandSampleSink* sampleSink) { m_sampleSink = sampleSink; } void configure(MessageQueue* messageQueue, Real Bandwidth, @@ -46,41 +123,13 @@ public: virtual void stop(); virtual bool handleMessage(const Message& cmd); +private slots: + void channelSampleRateChanged(); + private: - class MsgConfigureChannelAnalyzer : public Message { - MESSAGE_CLASS_DECLARATION - - public: - Real getBandwidth() const { return m_Bandwidth; } - Real getLoCutoff() const { return m_LowCutoff; } - int getSpanLog2() const { return m_spanLog2; } - bool getSSB() const { return m_ssb; } - - static MsgConfigureChannelAnalyzer* create(Real Bandwidth, - Real LowCutoff, - int spanLog2, - bool ssb) - { - return new MsgConfigureChannelAnalyzer(Bandwidth, LowCutoff, spanLog2, ssb); - } - - private: - Real m_Bandwidth; - Real m_LowCutoff; - int m_spanLog2; - bool m_ssb; - - MsgConfigureChannelAnalyzer(Real Bandwidth, - Real LowCutoff, - int spanLog2, - bool ssb) : - Message(), - m_Bandwidth(Bandwidth), - m_LowCutoff(LowCutoff), - m_spanLog2(spanLog2), - m_ssb(ssb) - { } - }; + DeviceSourceAPI *m_deviceAPI; + ThreadedBasebandSampleSink* m_threadedChannelizer; + DownChannelizer* m_channelizer; Real m_Bandwidth; Real m_LowCutoff; diff --git a/plugins/channelrx/chanalyzer/chanalyzergui.cpp b/plugins/channelrx/chanalyzer/chanalyzergui.cpp index 0cc9b561d..147edac22 100644 --- a/plugins/channelrx/chanalyzer/chanalyzergui.cpp +++ b/plugins/channelrx/chanalyzer/chanalyzergui.cpp @@ -154,11 +154,32 @@ bool ChannelAnalyzerGUI::deserialize(const QByteArray& data) } } -bool ChannelAnalyzerGUI::handleMessage(const Message& message __attribute__((unused))) +bool ChannelAnalyzerGUI::handleMessage(const Message& message) { + if (ChannelAnalyzer::MsgReportChannelSampleRateChanged::match(message)) + { + setNewRate(m_spanLog2); + return true; + } + return false; } +void ChannelAnalyzerGUI::handleInputMessages() +{ + Message* message; + + while ((message = getInputMessageQueue()->pop()) != 0) + { + qDebug("ChannelAnalyzerGUI::handleInputMessages: message: %s", message->getIdentifier()); + + if (handleMessage(*message)) + { + delete message; + } + } +} + void ChannelAnalyzerGUI::viewChanged() { applySettings(); @@ -171,11 +192,6 @@ void ChannelAnalyzerGUI::tick() ui->channelPower->setText(QString::number(m_channelPowerDbAvg.average(), 'f', 1)); } -void ChannelAnalyzerGUI::channelSampleRateChanged() -{ - setNewRate(m_spanLog2); -} - void ChannelAnalyzerGUI::on_deltaMinus_toggled(bool minus) { int deltaFrequency = m_channelMarker.getCenterFrequency(); @@ -326,11 +342,9 @@ ChannelAnalyzerGUI::ChannelAnalyzerGUI(PluginAPI* pluginAPI, DeviceSourceAPI *de m_spectrumVis = new SpectrumVis(ui->glSpectrum); m_scopeVis = new ScopeVis(ui->glScope); m_spectrumScopeComboVis = new SpectrumScopeComboVis(m_spectrumVis, m_scopeVis); - m_channelAnalyzer = new ChannelAnalyzer(m_spectrumScopeComboVis); - m_channelizer = new DownChannelizer(m_channelAnalyzer); - m_threadedChannelizer = new ThreadedBasebandSampleSink(m_channelizer, this); - connect(m_channelizer, SIGNAL(inputSampleRateChanged()), this, SLOT(channelSampleRateChanged())); - m_deviceAPI->addThreadedSink(m_threadedChannelizer); + m_channelAnalyzer = new ChannelAnalyzer(m_deviceAPI); + m_channelAnalyzer->setSampleSink(m_spectrumScopeComboVis); + m_channelAnalyzer->setMessageQueueToGUI(getInputMessageQueue()); ui->deltaFrequency->setColorMapper(ColorMapper(ColorMapper::ReverseGold)); ui->deltaFrequency->setValueRange(7, 0U, 9999999U); @@ -361,6 +375,8 @@ ChannelAnalyzerGUI::ChannelAnalyzerGUI(PluginAPI* pluginAPI, DeviceSourceAPI *de ui->spectrumGUI->setBuddies(m_spectrumVis->getInputMessageQueue(), m_spectrumVis, ui->glSpectrum); ui->scopeGUI->setBuddies(m_scopeVis->getInputMessageQueue(), m_scopeVis, ui->glScope); + connect(getInputMessageQueue(), SIGNAL(messageEnqueued()), this, SLOT(handleInputMessages())); + applySettings(); setNewRate(m_spanLog2); } @@ -368,9 +384,6 @@ ChannelAnalyzerGUI::ChannelAnalyzerGUI(PluginAPI* pluginAPI, DeviceSourceAPI *de ChannelAnalyzerGUI::~ChannelAnalyzerGUI() { m_deviceAPI->removeChannelInstance(this); - m_deviceAPI->removeThreadedSink(m_threadedChannelizer); - delete m_threadedChannelizer; - delete m_channelizer; delete m_channelAnalyzer; delete m_spectrumVis; delete m_scopeVis; @@ -457,9 +470,8 @@ void ChannelAnalyzerGUI::applySettings() ui->deltaFrequency->setValue(abs(m_channelMarker.getCenterFrequency())); ui->deltaMinus->setChecked(m_channelMarker.getCenterFrequency() < 0); - m_channelizer->configure(m_channelizer->getInputMessageQueue(), - m_channelizer->getInputSampleRate(), - m_channelMarker.getCenterFrequency()); + ChannelAnalyzer::MsgConfigureChannelizer *msg = ChannelAnalyzer::MsgConfigureChannelizer::create(m_channelMarker.getCenterFrequency()); + m_channelAnalyzer->getInputMessageQueue()->push(msg); m_channelAnalyzer->configure(m_channelAnalyzer->getInputMessageQueue(), ui->BW->value() * 100.0, diff --git a/plugins/channelrx/chanalyzer/chanalyzergui.h b/plugins/channelrx/chanalyzer/chanalyzergui.h index 36d00b8ce..c13238f40 100644 --- a/plugins/channelrx/chanalyzer/chanalyzergui.h +++ b/plugins/channelrx/chanalyzer/chanalyzergui.h @@ -59,7 +59,6 @@ public: private slots: void viewChanged(); - void channelSampleRateChanged(); void on_deltaFrequency_changed(quint64 value); void on_deltaMinus_toggled(bool minus); void on_BW_valueChanged(int value); @@ -68,6 +67,7 @@ private slots: void on_ssb_toggled(bool checked); void onWidgetRolled(QWidget* widget, bool rollDown); void onMenuDoubleClicked(); + void handleInputMessages(); void tick(); private: @@ -81,8 +81,8 @@ private: int m_spanLog2; MovingAverage m_channelPowerDbAvg; - ThreadedBasebandSampleSink* m_threadedChannelizer; - DownChannelizer* m_channelizer; +// ThreadedBasebandSampleSink* m_threadedChannelizer; +// DownChannelizer* m_channelizer; ChannelAnalyzer* m_channelAnalyzer; SpectrumScopeComboVis* m_spectrumScopeComboVis; SpectrumVis* m_spectrumVis; From 4d072725034bd4ac29c7ec4494868e1d7d8f6049 Mon Sep 17 00:00:00 2001 From: f4exb Date: Fri, 29 Sep 2017 18:36:33 +0200 Subject: [PATCH 35/71] ChannelAnalyzerNG: decouple demod and GUI --- .../channelrx/chanalyzerng/chanalyzerng.cpp | 41 +- plugins/channelrx/chanalyzerng/chanalyzerng.h | 425 ++++--- .../chanalyzerng/chanalyzernggui.cpp | 1127 +++++++++-------- .../channelrx/chanalyzerng/chanalyzernggui.h | 7 +- 4 files changed, 864 insertions(+), 736 deletions(-) diff --git a/plugins/channelrx/chanalyzerng/chanalyzerng.cpp b/plugins/channelrx/chanalyzerng/chanalyzerng.cpp index f27ea6407..ddfa63fc3 100644 --- a/plugins/channelrx/chanalyzerng/chanalyzerng.cpp +++ b/plugins/channelrx/chanalyzerng/chanalyzerng.cpp @@ -16,17 +16,23 @@ #include "chanalyzerng.h" -#include #include #include #include + +#include "device/devicesourceapi.h" #include "audio/audiooutput.h" +#include "dsp/threadedbasebandsamplesink.h" +#include "dsp/downchannelizer.h" MESSAGE_CLASS_DEFINITION(ChannelAnalyzerNG::MsgConfigureChannelAnalyzer, Message) +MESSAGE_CLASS_DEFINITION(ChannelAnalyzerNG::MsgConfigureChannelizer, Message) +MESSAGE_CLASS_DEFINITION(ChannelAnalyzerNG::MsgReportChannelSampleRateChanged, Message) -ChannelAnalyzerNG::ChannelAnalyzerNG(BasebandSampleSink* sampleSink) : - m_sampleSink(sampleSink), +ChannelAnalyzerNG::ChannelAnalyzerNG(DeviceSourceAPI *deviceAPI) : + m_deviceAPI(deviceAPI), + m_sampleSink(0), m_settingsMutex(QMutex::Recursive) { m_undersampleCount = 0; @@ -38,6 +44,12 @@ ChannelAnalyzerNG::ChannelAnalyzerNG(BasebandSampleSink* sampleSink) : m_interpolatorDistanceRemain = 0.0f; SSBFilter = new fftfilt(m_config.m_LowCutoff / m_config.m_inputSampleRate, m_config.m_Bandwidth / m_config.m_inputSampleRate, ssbFftLen); DSBFilter = new fftfilt(m_config.m_Bandwidth / m_config.m_inputSampleRate, 2*ssbFftLen); + + m_channelizer = new DownChannelizer(this); + m_threadedChannelizer = new ThreadedBasebandSampleSink(m_channelizer, this); + connect(m_channelizer, SIGNAL(inputSampleRateChanged()), this, SLOT(channelizerInputSampleRateChanged())); + m_deviceAPI->addThreadedSink(m_threadedChannelizer); + apply(true); } @@ -45,6 +57,9 @@ ChannelAnalyzerNG::~ChannelAnalyzerNG() { if (SSBFilter) delete SSBFilter; if (DSBFilter) delete DSBFilter; + m_deviceAPI->removeThreadedSink(m_threadedChannelizer); + delete m_threadedChannelizer; + delete m_channelizer; } void ChannelAnalyzerNG::configure(MessageQueue* messageQueue, @@ -54,7 +69,7 @@ void ChannelAnalyzerNG::configure(MessageQueue* messageQueue, int spanLog2, bool ssb) { - Message* cmd = MsgConfigureChannelAnalyzer::create(channelSampleRate, Bandwidth, LowCutoff, spanLog2, ssb); + Message* cmd = MsgConfigureChannelAnalyzer::create(channelSampleRate, Bandwidth, LowCutoff, spanLog2, ssb); messageQueue->push(cmd); } @@ -102,6 +117,12 @@ void ChannelAnalyzerNG::stop() { } +void ChannelAnalyzerNG::channelizerInputSampleRateChanged() +{ + MsgReportChannelSampleRateChanged *msg = MsgReportChannelSampleRateChanged::create(); + getMessageQueueToGUI()->push(msg); +} + bool ChannelAnalyzerNG::handleMessage(const Message& cmd) { qDebug() << "ChannelAnalyzerNG::handleMessage: " << cmd.getIdentifier(); @@ -120,11 +141,19 @@ bool ChannelAnalyzerNG::handleMessage(const Message& cmd) apply(); return true; } + else if (MsgConfigureChannelizer::match(cmd)) + { + MsgConfigureChannelizer& cfg = (MsgConfigureChannelizer&) cmd; + m_channelizer->configure(m_channelizer->getInputMessageQueue(), + cfg.getSampleRate(), + cfg.getCenterFrequency()); + return true; + } else if (MsgConfigureChannelAnalyzer::match(cmd)) { MsgConfigureChannelAnalyzer& cfg = (MsgConfigureChannelAnalyzer&) cmd; - m_config.m_channelSampleRate = cfg.getChannelSampleRate(); + m_config.m_channelSampleRate = cfg.getChannelSampleRate(); m_config.m_Bandwidth = cfg.getBandwidth(); m_config.m_LowCutoff = cfg.getLoCutoff(); m_config.m_spanLog2 = cfg.getSpanLog2(); @@ -153,6 +182,8 @@ bool ChannelAnalyzerNG::handleMessage(const Message& cmd) } } + + void ChannelAnalyzerNG::apply(bool force) { if ((m_running.m_frequency != m_config.m_frequency) || diff --git a/plugins/channelrx/chanalyzerng/chanalyzerng.h b/plugins/channelrx/chanalyzerng/chanalyzerng.h index c58b74105..bee680725 100644 --- a/plugins/channelrx/chanalyzerng/chanalyzerng.h +++ b/plugins/channelrx/chanalyzerng/chanalyzerng.h @@ -1,183 +1,242 @@ -/////////////////////////////////////////////////////////////////////////////////// -// Copyright (C) 2017 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 // -// // -// This program is distributed in the hope that it will be useful, // -// but WITHOUT ANY WARRANTY; without even the implied warranty of // -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // -// GNU General Public License V3 for more details. // -// // -// You should have received a copy of the GNU General Public License // -// along with this program. If not, see . // -/////////////////////////////////////////////////////////////////////////////////// - -#ifndef INCLUDE_CHANALYZERNG_H -#define INCLUDE_CHANALYZERNG_H - -#include -#include -#include - -#include "dsp/interpolator.h" -#include "dsp/ncof.h" -#include "dsp/fftfilt.h" -#include "audio/audiofifo.h" -#include "util/message.h" - -#define ssbFftLen 1024 - -class ChannelAnalyzerNG : public BasebandSampleSink { -public: - ChannelAnalyzerNG(BasebandSampleSink* m_sampleSink); - virtual ~ChannelAnalyzerNG(); - - void configure(MessageQueue* messageQueue, - int channelSampleRate, - Real Bandwidth, - Real LowCutoff, - int spanLog2, - bool ssb); - - int getInputSampleRate() const { return m_running.m_inputSampleRate; } - int getChannelSampleRate() const { return m_running.m_channelSampleRate; } - double getMagSq() const { return m_magsq; } - - virtual void feed(const SampleVector::const_iterator& begin, const SampleVector::const_iterator& end, bool positiveOnly); - virtual void start(); - virtual void stop(); - virtual bool handleMessage(const Message& cmd); - -private: - class MsgConfigureChannelAnalyzer : public Message { - MESSAGE_CLASS_DECLARATION - - public: - int getChannelSampleRate() const { return m_channelSampleRate; } - Real getBandwidth() const { return m_Bandwidth; } - Real getLoCutoff() const { return m_LowCutoff; } - int getSpanLog2() const { return m_spanLog2; } - bool getSSB() const { return m_ssb; } - - static MsgConfigureChannelAnalyzer* create( - int channelSampleRate, - Real Bandwidth, - Real LowCutoff, - int spanLog2, - bool ssb) - { - return new MsgConfigureChannelAnalyzer(channelSampleRate, Bandwidth, LowCutoff, spanLog2, ssb); - } - - private: - int m_channelSampleRate; - Real m_Bandwidth; - Real m_LowCutoff; - int m_spanLog2; - bool m_ssb; - - MsgConfigureChannelAnalyzer( - int channelSampleRate, - Real Bandwidth, - Real LowCutoff, - int spanLog2, - bool ssb) : - Message(), - m_channelSampleRate(channelSampleRate), - m_Bandwidth(Bandwidth), - m_LowCutoff(LowCutoff), - m_spanLog2(spanLog2), - m_ssb(ssb) - { } - }; - - struct Config - { - int m_frequency; - int m_inputSampleRate; - int m_channelSampleRate; - Real m_Bandwidth; - Real m_LowCutoff; - int m_spanLog2; - bool m_ssb; - - Config() : - m_frequency(0), - m_inputSampleRate(96000), - m_channelSampleRate(96000), - m_Bandwidth(5000), - m_LowCutoff(300), - m_spanLog2(3), - m_ssb(false) - {} - }; - - Config m_config; - Config m_running; - - int m_undersampleCount; - fftfilt::cmplx m_sum; - bool m_usb; - double m_magsq; - bool m_useInterpolator; - - NCOF m_nco; - Interpolator m_interpolator; - Real m_interpolatorDistance; - Real m_interpolatorDistanceRemain; - - fftfilt* SSBFilter; - fftfilt* DSBFilter; - - BasebandSampleSink* m_sampleSink; - SampleVector m_sampleBuffer; - QMutex m_settingsMutex; - - void apply(bool force = false); - - void processOneSample(Complex& c, fftfilt::cmplx *sideband) - { - int n_out; - int decim = 1<runSSB(c, &sideband, m_usb); - } - else - { - n_out = DSBFilter->runDSB(c, &sideband); - } - - for (int i = 0; i < n_out; i++) - { - // Downsample by 2^(m_scaleLog2 - 1) for SSB band spectrum display - // smart decimation with bit gain using float arithmetic (23 bits significand) - - m_sum += sideband[i]; - - if (!(m_undersampleCount++ & (decim - 1))) // counter LSB bit mask for decimation by 2^(m_scaleLog2 - 1) - { - m_sum /= decim; - m_magsq = (m_sum.real() * m_sum.real() + m_sum.imag() * m_sum.imag())/ (1<<30); - - if (m_running.m_ssb & !m_usb) - { // invert spectrum for LSB - //m_sampleBuffer.push_back(Sample(m_sum.imag() * 32768.0, m_sum.real() * 32768.0)); - m_sampleBuffer.push_back(Sample(m_sum.imag(), m_sum.real())); - } - else - { - //m_sampleBuffer.push_back(Sample(m_sum.real() * 32768.0, m_sum.imag() * 32768.0)); - m_sampleBuffer.push_back(Sample(m_sum.real(), m_sum.imag())); - } - - m_sum = 0; - } - } - } -}; - -#endif // INCLUDE_CHANALYZERNG_H +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2017 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 // +// // +// This program is distributed in the hope that it will be useful, // +// but WITHOUT ANY WARRANTY; without even the implied warranty of // +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // +// GNU General Public License V3 for more details. // +// // +// You should have received a copy of the GNU General Public License // +// along with this program. If not, see . // +/////////////////////////////////////////////////////////////////////////////////// + +#ifndef INCLUDE_CHANALYZERNG_H +#define INCLUDE_CHANALYZERNG_H + +#include +#include +#include + +#include "dsp/interpolator.h" +#include "dsp/ncof.h" +#include "dsp/fftfilt.h" +#include "audio/audiofifo.h" +#include "util/message.h" + +#define ssbFftLen 1024 + +class DeviceSourceAPI; +class ThreadedBasebandSampleSink; +class DownChannelizer; + +class ChannelAnalyzerNG : public BasebandSampleSink { +public: + class MsgConfigureChannelAnalyzer : public Message { + MESSAGE_CLASS_DECLARATION + + public: + int getChannelSampleRate() const { return m_channelSampleRate; } + Real getBandwidth() const { return m_Bandwidth; } + Real getLoCutoff() const { return m_LowCutoff; } + int getSpanLog2() const { return m_spanLog2; } + bool getSSB() const { return m_ssb; } + + static MsgConfigureChannelAnalyzer* create( + int channelSampleRate, + Real Bandwidth, + Real LowCutoff, + int spanLog2, + bool ssb) + { + return new MsgConfigureChannelAnalyzer( + channelSampleRate, + Bandwidth, + LowCutoff, + spanLog2, + ssb); + } + + private: + int m_channelSampleRate; + Real m_Bandwidth; + Real m_LowCutoff; + int m_spanLog2; + bool m_ssb; + + MsgConfigureChannelAnalyzer( + int channelSampleRate, + Real Bandwidth, + Real LowCutoff, + int spanLog2, + bool ssb) : + Message(), + m_channelSampleRate(channelSampleRate), + m_Bandwidth(Bandwidth), + m_LowCutoff(LowCutoff), + m_spanLog2(spanLog2), + m_ssb(ssb) + { } + }; + + class MsgConfigureChannelizer : public Message { + MESSAGE_CLASS_DECLARATION + + public: + int getSampleRate() const { return m_sampleRate; } + int getCenterFrequency() const { return m_centerFrequency; } + + static MsgConfigureChannelizer* create(int sampleRate, int centerFrequency) + { + return new MsgConfigureChannelizer(sampleRate, centerFrequency); + } + + private: + int m_sampleRate; + int m_centerFrequency; + + MsgConfigureChannelizer(int sampleRate, int centerFrequency) : + Message(), + m_sampleRate(sampleRate), + m_centerFrequency(centerFrequency) + { } + }; + + class MsgReportChannelSampleRateChanged : public Message { + MESSAGE_CLASS_DECLARATION + + public: + + static MsgReportChannelSampleRateChanged* create() + { + return new MsgReportChannelSampleRateChanged(); + } + + private: + + MsgReportChannelSampleRateChanged() : + Message() + { } + }; + + ChannelAnalyzerNG(DeviceSourceAPI *deviceAPI); + virtual ~ChannelAnalyzerNG(); + void setSampleSink(BasebandSampleSink* sampleSink) { m_sampleSink = sampleSink; } + + void configure(MessageQueue* messageQueue, + int channelSampleRate, + Real Bandwidth, + Real LowCutoff, + int spanLog2, + bool ssb); + + DownChannelizer *getChannelizer() { return m_channelizer; } + int getInputSampleRate() const { return m_running.m_inputSampleRate; } + int getChannelSampleRate() const { return m_running.m_channelSampleRate; } + double getMagSq() const { return m_magsq; } + + virtual void feed(const SampleVector::const_iterator& begin, const SampleVector::const_iterator& end, bool positiveOnly); + virtual void start(); + virtual void stop(); + virtual bool handleMessage(const Message& cmd); + +private slots: + void channelizerInputSampleRateChanged(); + +private: + + struct Config + { + int m_frequency; + int m_inputSampleRate; + int m_channelSampleRate; + Real m_Bandwidth; + Real m_LowCutoff; + int m_spanLog2; + bool m_ssb; + + Config() : + m_frequency(0), + m_inputSampleRate(96000), + m_channelSampleRate(96000), + m_Bandwidth(5000), + m_LowCutoff(300), + m_spanLog2(3), + m_ssb(false) + {} + }; + + Config m_config; + Config m_running; + + DeviceSourceAPI *m_deviceAPI; + ThreadedBasebandSampleSink* m_threadedChannelizer; + DownChannelizer* m_channelizer; + + int m_undersampleCount; + fftfilt::cmplx m_sum; + bool m_usb; + double m_magsq; + bool m_useInterpolator; + + NCOF m_nco; + Interpolator m_interpolator; + Real m_interpolatorDistance; + Real m_interpolatorDistanceRemain; + + fftfilt* SSBFilter; + fftfilt* DSBFilter; + + BasebandSampleSink* m_sampleSink; + SampleVector m_sampleBuffer; + QMutex m_settingsMutex; + + void apply(bool force = false); + + void processOneSample(Complex& c, fftfilt::cmplx *sideband) + { + int n_out; + int decim = 1<runSSB(c, &sideband, m_usb); + } + else + { + n_out = DSBFilter->runDSB(c, &sideband); + } + + for (int i = 0; i < n_out; i++) + { + // Downsample by 2^(m_scaleLog2 - 1) for SSB band spectrum display + // smart decimation with bit gain using float arithmetic (23 bits significand) + + m_sum += sideband[i]; + + if (!(m_undersampleCount++ & (decim - 1))) // counter LSB bit mask for decimation by 2^(m_scaleLog2 - 1) + { + m_sum /= decim; + m_magsq = (m_sum.real() * m_sum.real() + m_sum.imag() * m_sum.imag())/ (1<<30); + + if (m_running.m_ssb & !m_usb) + { // invert spectrum for LSB + //m_sampleBuffer.push_back(Sample(m_sum.imag() * 32768.0, m_sum.real() * 32768.0)); + m_sampleBuffer.push_back(Sample(m_sum.imag(), m_sum.real())); + } + else + { + //m_sampleBuffer.push_back(Sample(m_sum.real() * 32768.0, m_sum.imag() * 32768.0)); + m_sampleBuffer.push_back(Sample(m_sum.real(), m_sum.imag())); + } + + m_sum = 0; + } + } + } +}; + +#endif // INCLUDE_CHANALYZERNG_H diff --git a/plugins/channelrx/chanalyzerng/chanalyzernggui.cpp b/plugins/channelrx/chanalyzerng/chanalyzernggui.cpp index d71ac0855..cd05da0a3 100644 --- a/plugins/channelrx/chanalyzerng/chanalyzernggui.cpp +++ b/plugins/channelrx/chanalyzerng/chanalyzernggui.cpp @@ -1,545 +1,582 @@ -/////////////////////////////////////////////////////////////////////////////////// -// Copyright (C) 2017 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 // -// // -// This program is distributed in the hope that it will be useful, // -// but WITHOUT ANY WARRANTY; without even the implied warranty of // -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // -// GNU General Public License V3 for more details. // -// // -// You should have received a copy of the GNU General Public License // -// along with this program. If not, see . // -/////////////////////////////////////////////////////////////////////////////////// - -#include "chanalyzernggui.h" - -#include -#include -#include -#include - -#include "dsp/threadedbasebandsamplesink.h" -#include "ui_chanalyzernggui.h" -#include "dsp/spectrumscopengcombovis.h" -#include "dsp/spectrumvis.h" -#include "dsp/scopevis.h" -#include "gui/glspectrum.h" -#include "gui/glscopeng.h" -#include "plugin/pluginapi.h" -#include "util/simpleserializer.h" -#include "util/db.h" -#include "gui/basicchannelsettingswidget.h" -#include "dsp/dspengine.h" -#include "mainwindow.h" - -#include "chanalyzerng.h" - -const QString ChannelAnalyzerNGGUI::m_channelID = "sdrangel.channel.chanalyzerng"; - -ChannelAnalyzerNGGUI* ChannelAnalyzerNGGUI::create(PluginAPI* pluginAPI, DeviceSourceAPI *deviceAPI) -{ - ChannelAnalyzerNGGUI* gui = new ChannelAnalyzerNGGUI(pluginAPI, deviceAPI); - return gui; -} - -void ChannelAnalyzerNGGUI::destroy() -{ - delete this; -} - -void ChannelAnalyzerNGGUI::setName(const QString& name) -{ - setObjectName(name); -} - -QString ChannelAnalyzerNGGUI::getName() const -{ - return objectName(); -} - -qint64 ChannelAnalyzerNGGUI::getCenterFrequency() const -{ - return m_channelMarker.getCenterFrequency(); -} - -void ChannelAnalyzerNGGUI::setCenterFrequency(qint64 centerFrequency) -{ - m_channelMarker.setCenterFrequency(centerFrequency); - applySettings(); -} - -void ChannelAnalyzerNGGUI::resetToDefaults() -{ - blockApplySettings(true); - - ui->useRationalDownsampler->setChecked(false); - ui->BW->setValue(30); - ui->deltaFrequency->setValue(0); - ui->spanLog2->setCurrentIndex(3); - - blockApplySettings(false); - applySettings(); -} - -QByteArray ChannelAnalyzerNGGUI::serialize() const -{ - SimpleSerializer s(1); - s.writeS32(1, m_channelMarker.getCenterFrequency()); - s.writeS32(2, ui->BW->value()); - s.writeBlob(3, ui->spectrumGUI->serialize()); - s.writeU32(4, m_channelMarker.getColor().rgb()); - s.writeS32(5, ui->lowCut->value()); - s.writeS32(6, ui->spanLog2->currentIndex()); - s.writeBool(7, ui->ssb->isChecked()); - s.writeBlob(8, ui->scopeGUI->serialize()); - s.writeU64(9, ui->channelSampleRate->getValueNew()); - return s.final(); -} - -bool ChannelAnalyzerNGGUI::deserialize(const QByteArray& data) -{ - SimpleDeserializer d(data); - - if(!d.isValid()) - { - resetToDefaults(); - return false; - } - - if(d.getVersion() == 1) - { - QByteArray bytetmp; - quint32 u32tmp; - quint64 u64tmp; - qint32 tmp, spanLog2, bw, lowCut; - bool tmpBool; - - blockApplySettings(true); - m_channelMarker.blockSignals(true); - - d.readS32(1, &tmp, 0); - m_channelMarker.setCenterFrequency(tmp); - d.readS32(2, &bw, 30); - d.readBlob(3, &bytetmp); - ui->spectrumGUI->deserialize(bytetmp); - - if(d.readU32(4, &u32tmp)) - { - m_channelMarker.setColor(u32tmp); - } - - d.readS32(5, &lowCut, 3); - d.readS32(6, &spanLog2, 3); - d.readBool(7, &tmpBool, false); - ui->ssb->setChecked(tmpBool); - d.readBlob(8, &bytetmp); - ui->scopeGUI->deserialize(bytetmp); - d.readU64(9, &u64tmp, 2000U); - ui->channelSampleRate->setValue(u64tmp); - - blockApplySettings(false); - m_channelMarker.blockSignals(false); - - ui->spanLog2->setCurrentIndex(spanLog2); - setNewFinalRate(spanLog2); - ui->BW->setValue(bw); - ui->lowCut->setValue(lowCut); // does applySettings(); - - return true; - } - else - { - resetToDefaults(); - return false; - } -} - -bool ChannelAnalyzerNGGUI::handleMessage(const Message& message __attribute__((unused))) -{ - return false; -} - -void ChannelAnalyzerNGGUI::viewChanged() -{ - applySettings(); -} - -void ChannelAnalyzerNGGUI::tick() -{ - double powDb = CalcDb::dbPower(m_channelAnalyzer->getMagSq()); - m_channelPowerDbAvg.feed(powDb); - ui->channelPower->setText(tr("%1 dB").arg(m_channelPowerDbAvg.average(), 0, 'f', 1)); -} - -void ChannelAnalyzerNGGUI::channelizerInputSampleRateChanged() -{ - //ui->channelSampleRate->setValueRange(7, 2000U, m_channelAnalyzer->getInputSampleRate()); - setNewFinalRate(m_spanLog2); - applySettings(); -} - -void ChannelAnalyzerNGGUI::on_channelSampleRate_changed(quint64 value) -{ - ui->channelSampleRate->setValueRange(7, 2000U, m_channelAnalyzer->getInputSampleRate()); - - if (ui->useRationalDownsampler->isChecked()) - { - qDebug("ChannelAnalyzerNGGUI::on_channelSampleRate_changed: %llu", value); - setNewFinalRate(m_spanLog2); - applySettings(); - } -} - -void ChannelAnalyzerNGGUI::on_useRationalDownsampler_toggled(bool checked __attribute__((unused))) -{ - setNewFinalRate(m_spanLog2); - applySettings(); -} - -int ChannelAnalyzerNGGUI::getRequestedChannelSampleRate() -{ - if (ui->useRationalDownsampler->isChecked()) { - return ui->channelSampleRate->getValueNew(); - } else { - return m_channelizer->getInputSampleRate(); - } -} - -void ChannelAnalyzerNGGUI::on_deltaFrequency_changed(qint64 value) -{ - m_channelMarker.setCenterFrequency(value); -} - -void ChannelAnalyzerNGGUI::on_BW_valueChanged(int value) -{ - m_channelMarker.setBandwidth(value * 100 * 2); - - if (ui->ssb->isChecked()) - { - QString s = QString::number(value/10.0, 'f', 1); - ui->BWText->setText(tr("%1k").arg(s)); - } - else - { - QString s = QString::number(value/5.0, 'f', 1); // BW = value * 2 - ui->BWText->setText(tr("%1k").arg(s)); - } - - displayBandwidth(); - on_lowCut_valueChanged(m_channelMarker.getLowCutoff()/100); -} - -int ChannelAnalyzerNGGUI::getEffectiveLowCutoff(int lowCutoff) -{ - int ssbBW = m_channelMarker.getBandwidth() / 2; - int effectiveLowCutoff = lowCutoff; - const int guard = 100; - - if (ssbBW < 0) { - if (effectiveLowCutoff < ssbBW + guard) { - effectiveLowCutoff = ssbBW + guard; - } - if (effectiveLowCutoff > 0) { - effectiveLowCutoff = 0; - } - } else { - if (effectiveLowCutoff > ssbBW - guard) { - effectiveLowCutoff = ssbBW - guard; - } - if (effectiveLowCutoff < 0) { - effectiveLowCutoff = 0; - } - } - - return effectiveLowCutoff; -} - -void ChannelAnalyzerNGGUI::on_lowCut_valueChanged(int value) -{ - int lowCutoff = getEffectiveLowCutoff(value * 100); - m_channelMarker.setLowCutoff(lowCutoff); - QString s = QString::number(lowCutoff/1000.0, 'f', 1); - ui->lowCutText->setText(tr("%1k").arg(s)); - ui->lowCut->setValue(lowCutoff/100); - applySettings(); -} - -void ChannelAnalyzerNGGUI::on_spanLog2_currentIndexChanged(int index) -{ - if (setNewFinalRate(index)) { - applySettings(); - } - -} - -void ChannelAnalyzerNGGUI::on_ssb_toggled(bool checked) -{ - //int bw = m_channelMarker.getBandwidth(); - - if (checked) - { - setFiltersUIBoundaries(); - - ui->BWLabel->setText("LP"); - QString s = QString::number(ui->BW->value()/10.0, 'f', 1); // bw/2 - ui->BWText->setText(tr("%1k").arg(s)); - - on_lowCut_valueChanged(m_channelMarker.getLowCutoff()/100); - } - else - { - if (ui->BW->value() < 0) { - ui->BW->setValue(-ui->BW->value()); - } - - setFiltersUIBoundaries(); - //m_channelMarker.setBandwidth(ui->BW->value() * 200.0); - - ui->BWLabel->setText("BP"); - QString s = QString::number(ui->BW->value()/5.0, 'f', 1); // bw - ui->BWText->setText(tr("%1k").arg(s)); - - ui->lowCut->setEnabled(false); - ui->lowCut->setValue(0); - ui->lowCutText->setText("0.0k"); - } - - applySettings(); - displayBandwidth(); -} - -void ChannelAnalyzerNGGUI::onWidgetRolled(QWidget* widget __attribute__((unused)), bool rollDown __attribute__((unused))) -{ - /* - if((widget == ui->spectrumContainer) && (m_ssbDemod != NULL)) - m_ssbDemod->setSpectrum(m_threadedSampleSink->getMessageQueue(), rollDown); - */ -} - -void ChannelAnalyzerNGGUI::onMenuDoubleClicked() -{ - if(!m_basicSettingsShown) { - m_basicSettingsShown = true; - BasicChannelSettingsWidget* bcsw = new BasicChannelSettingsWidget(&m_channelMarker, this); - bcsw->show(); - } -} - -ChannelAnalyzerNGGUI::ChannelAnalyzerNGGUI(PluginAPI* pluginAPI, DeviceSourceAPI *deviceAPI, QWidget* parent) : - RollupWidget(parent), - ui(new Ui::ChannelAnalyzerNGGUI), - m_pluginAPI(pluginAPI), - m_deviceAPI(deviceAPI), - m_channelMarker(this), - m_basicSettingsShown(false), - m_doApplySettings(true), - m_rate(6000), - m_spanLog2(0), - m_channelPowerDbAvg(40,0) -{ - ui->setupUi(this); - setAttribute(Qt::WA_DeleteOnClose, true); - connect(this, SIGNAL(widgetRolled(QWidget*,bool)), this, SLOT(onWidgetRolled(QWidget*,bool))); - connect(this, SIGNAL(menuDoubleClickEvent()), this, SLOT(onMenuDoubleClicked())); - - m_spectrumVis = new SpectrumVis(ui->glSpectrum); - m_scopeVis = new ScopeVisNG(ui->glScope); - m_spectrumScopeComboVis = new SpectrumScopeNGComboVis(m_spectrumVis, m_scopeVis); - m_channelAnalyzer = new ChannelAnalyzerNG(m_spectrumScopeComboVis); - m_channelizer = new DownChannelizer(m_channelAnalyzer); - m_threadedChannelizer = new ThreadedBasebandSampleSink(m_channelizer, this); - connect(m_channelizer, SIGNAL(inputSampleRateChanged()), this, SLOT(channelizerInputSampleRateChanged())); - m_deviceAPI->addThreadedSink(m_threadedChannelizer); - - ui->deltaFrequencyLabel->setText(QString("%1f").arg(QChar(0x94, 0x03))); - ui->deltaFrequency->setColorMapper(ColorMapper(ColorMapper::GrayGold)); - ui->deltaFrequency->setValueRange(false, 7, -9999999, 9999999); - - ui->channelSampleRate->setColorMapper(ColorMapper(ColorMapper::GrayGreenYellow)); - ui->channelSampleRate->setValueRange(7, 2000U, 9999999U); - - ui->glSpectrum->setCenterFrequency(m_rate/2); - ui->glSpectrum->setSampleRate(m_rate); - ui->glSpectrum->setDisplayWaterfall(true); - ui->glSpectrum->setDisplayMaxHold(true); - ui->glSpectrum->setSsbSpectrum(false); - ui->glSpectrum->setLsbDisplay(false); - ui->BWLabel->setText("BP"); - - ui->glSpectrum->connectTimer(m_pluginAPI->getMainWindow()->getMasterTimer()); - ui->glScope->connectTimer(m_pluginAPI->getMainWindow()->getMasterTimer()); - connect(&m_pluginAPI->getMainWindow()->getMasterTimer(), SIGNAL(timeout()), this, SLOT(tick())); - - //m_channelMarker = new ChannelMarker(this); - m_channelMarker.setColor(Qt::gray); - m_channelMarker.setBandwidth(m_rate); - m_channelMarker.setSidebands(ChannelMarker::usb); - m_channelMarker.setCenterFrequency(0); - m_channelMarker.setVisible(true); - - connect(&m_channelMarker, SIGNAL(changed()), this, SLOT(viewChanged())); - - m_deviceAPI->registerChannelInstance(m_channelID, this); - m_deviceAPI->addChannelMarker(&m_channelMarker); - m_deviceAPI->addRollupWidget(this); - - ui->spectrumGUI->setBuddies(m_spectrumVis->getInputMessageQueue(), m_spectrumVis, ui->glSpectrum); - ui->scopeGUI->setBuddies(m_scopeVis->getInputMessageQueue(), m_scopeVis, ui->glScope); - - applySettings(); - setNewFinalRate(m_spanLog2); -} - -ChannelAnalyzerNGGUI::~ChannelAnalyzerNGGUI() -{ - m_deviceAPI->removeChannelInstance(this); - m_deviceAPI->removeThreadedSink(m_threadedChannelizer); - delete m_threadedChannelizer; - delete m_channelizer; - delete m_channelAnalyzer; - delete m_spectrumVis; - delete m_scopeVis; - delete m_spectrumScopeComboVis; - //delete m_channelMarker; - delete ui; -} - -bool ChannelAnalyzerNGGUI::setNewFinalRate(int spanLog2) -{ - qDebug("ChannelAnalyzerNGGUI::setNewRate"); - - if ((spanLog2 < 0) || (spanLog2 > 6)) { - return false; - } - - m_spanLog2 = spanLog2; - //m_rate = 48000 / (1<getInputSampleRate() / (1<spanText->setText(tr("%1 kS/s").arg(s)); - - displayBandwidth(); - - ui->glScope->setSampleRate(m_rate); - m_scopeVis->setSampleRate(m_rate); - - return true; -} - -void ChannelAnalyzerNGGUI::displayBandwidth() -{ - if (ui->ssb->isChecked()) - { - if (ui->BW->value() < 0) - { - m_channelMarker.setSidebands(ChannelMarker::lsb); - ui->glSpectrum->setLsbDisplay(true); - } - else - { - m_channelMarker.setSidebands(ChannelMarker::usb); - ui->glSpectrum->setLsbDisplay(false); - } - - ui->glSpectrum->setCenterFrequency(m_rate/4); - ui->glSpectrum->setSampleRate(m_rate/2); - ui->glSpectrum->setSsbSpectrum(true); - } - else - { - m_channelMarker.setSidebands(ChannelMarker::dsb); - - ui->glSpectrum->setCenterFrequency(0); - ui->glSpectrum->setSampleRate(m_rate); - ui->glSpectrum->setLsbDisplay(false); - ui->glSpectrum->setSsbSpectrum(false); - } - - -} - -void ChannelAnalyzerNGGUI::setFiltersUIBoundaries() -{ - if (ui->BW->value() < -m_rate/200) { - ui->BW->setValue(-m_rate/200); - m_channelMarker.setBandwidth(-m_rate*2); - } else if (ui->BW->value() > m_rate/200) { - ui->BW->setValue(m_rate/200); - m_channelMarker.setBandwidth(m_rate*2); - } - - if (ui->lowCut->value() < -m_rate/200) { - ui->lowCut->setValue(-m_rate/200); - m_channelMarker.setLowCutoff(-m_rate); - } else if (ui->lowCut->value() > m_rate/200) { - ui->lowCut->setValue(m_rate/200); - m_channelMarker.setLowCutoff(m_rate); - } - - if (ui->ssb->isChecked()) { - ui->BW->setMinimum(-m_rate/200); - ui->lowCut->setMinimum(-m_rate/200); - } else { - ui->BW->setMinimum(0); - ui->lowCut->setMinimum(-m_rate/200); - ui->lowCut->setValue(0); - } - - ui->BW->setMaximum(m_rate/200); - ui->lowCut->setMaximum(m_rate/200); -} - -void ChannelAnalyzerNGGUI::blockApplySettings(bool block) -{ - ui->glScope->blockSignals(block); - ui->glSpectrum->blockSignals(block); - m_doApplySettings = !block; -} - -void ChannelAnalyzerNGGUI::applySettings() -{ - if (m_doApplySettings) - { - setTitleColor(m_channelMarker.getColor()); - ui->deltaFrequency->setValue(m_channelMarker.getCenterFrequency()); - - m_channelizer->configure(m_channelizer->getInputMessageQueue(), - //m_channelizer->getInputSampleRate(), - getRequestedChannelSampleRate(), - m_channelMarker.getCenterFrequency()); - - m_channelAnalyzer->configure(m_channelAnalyzer->getInputMessageQueue(), - //m_channelizer->getInputSampleRate(), // TODO: specify required channel sample rate - getRequestedChannelSampleRate(), // TODO: specify required channel sample rate - ui->BW->value() * 100.0, - ui->lowCut->value() * 100.0, - m_spanLog2, - ui->ssb->isChecked()); - } -} - -void ChannelAnalyzerNGGUI::leaveEvent(QEvent*) -{ - blockApplySettings(true); - m_channelMarker.setHighlighted(false); - blockApplySettings(false); -} - -void ChannelAnalyzerNGGUI::enterEvent(QEvent*) -{ - blockApplySettings(true); - m_channelMarker.setHighlighted(true); - blockApplySettings(false); -} - +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2017 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 // +// // +// This program is distributed in the hope that it will be useful, // +// but WITHOUT ANY WARRANTY; without even the implied warranty of // +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // +// GNU General Public License V3 for more details. // +// // +// You should have received a copy of the GNU General Public License // +// along with this program. If not, see . // +/////////////////////////////////////////////////////////////////////////////////// + +#include "chanalyzernggui.h" + +#include +#include +#include +#include + +#include "dsp/threadedbasebandsamplesink.h" +#include "ui_chanalyzernggui.h" +#include "dsp/spectrumscopengcombovis.h" +#include "dsp/spectrumvis.h" +#include "dsp/scopevis.h" +#include "gui/glspectrum.h" +#include "gui/glscopeng.h" +#include "plugin/pluginapi.h" +#include "util/simpleserializer.h" +#include "util/db.h" +#include "gui/basicchannelsettingswidget.h" +#include "dsp/dspengine.h" +#include "mainwindow.h" + +#include "chanalyzerng.h" + +const QString ChannelAnalyzerNGGUI::m_channelID = "sdrangel.channel.chanalyzerng"; + +ChannelAnalyzerNGGUI* ChannelAnalyzerNGGUI::create(PluginAPI* pluginAPI, DeviceSourceAPI *deviceAPI) +{ + ChannelAnalyzerNGGUI* gui = new ChannelAnalyzerNGGUI(pluginAPI, deviceAPI); + return gui; +} + +void ChannelAnalyzerNGGUI::destroy() +{ + delete this; +} + +void ChannelAnalyzerNGGUI::setName(const QString& name) +{ + setObjectName(name); +} + +QString ChannelAnalyzerNGGUI::getName() const +{ + return objectName(); +} + +qint64 ChannelAnalyzerNGGUI::getCenterFrequency() const +{ + return m_channelMarker.getCenterFrequency(); +} + +void ChannelAnalyzerNGGUI::setCenterFrequency(qint64 centerFrequency) +{ + m_channelMarker.setCenterFrequency(centerFrequency); + applySettings(); +} + +void ChannelAnalyzerNGGUI::resetToDefaults() +{ + blockApplySettings(true); + + ui->useRationalDownsampler->setChecked(false); + ui->BW->setValue(30); + ui->deltaFrequency->setValue(0); + ui->spanLog2->setCurrentIndex(3); + + blockApplySettings(false); + applySettings(); +} + +QByteArray ChannelAnalyzerNGGUI::serialize() const +{ + SimpleSerializer s(1); + s.writeS32(1, m_channelMarker.getCenterFrequency()); + s.writeS32(2, ui->BW->value()); + s.writeBlob(3, ui->spectrumGUI->serialize()); + s.writeU32(4, m_channelMarker.getColor().rgb()); + s.writeS32(5, ui->lowCut->value()); + s.writeS32(6, ui->spanLog2->currentIndex()); + s.writeBool(7, ui->ssb->isChecked()); + s.writeBlob(8, ui->scopeGUI->serialize()); + s.writeU64(9, ui->channelSampleRate->getValueNew()); + return s.final(); +} + +bool ChannelAnalyzerNGGUI::deserialize(const QByteArray& data) +{ + SimpleDeserializer d(data); + + if(!d.isValid()) + { + resetToDefaults(); + return false; + } + + if(d.getVersion() == 1) + { + QByteArray bytetmp; + quint32 u32tmp; + quint64 u64tmp; + qint32 tmp, spanLog2, bw, lowCut; + bool tmpBool; + + blockApplySettings(true); + m_channelMarker.blockSignals(true); + + d.readS32(1, &tmp, 0); + m_channelMarker.setCenterFrequency(tmp); + d.readS32(2, &bw, 30); + d.readBlob(3, &bytetmp); + ui->spectrumGUI->deserialize(bytetmp); + + if(d.readU32(4, &u32tmp)) + { + m_channelMarker.setColor(u32tmp); + } + + d.readS32(5, &lowCut, 3); + d.readS32(6, &spanLog2, 3); + d.readBool(7, &tmpBool, false); + ui->ssb->setChecked(tmpBool); + d.readBlob(8, &bytetmp); + ui->scopeGUI->deserialize(bytetmp); + d.readU64(9, &u64tmp, 2000U); + ui->channelSampleRate->setValue(u64tmp); + + blockApplySettings(false); + m_channelMarker.blockSignals(false); + + ui->spanLog2->setCurrentIndex(spanLog2); + setNewFinalRate(spanLog2); + ui->BW->setValue(bw); + ui->lowCut->setValue(lowCut); // does applySettings(); + + return true; + } + else + { + resetToDefaults(); + return false; + } +} + +bool ChannelAnalyzerNGGUI::handleMessage(const Message& message __attribute__((unused))) +{ + if (ChannelAnalyzerNG::MsgReportChannelSampleRateChanged::match(message)) + { + setNewFinalRate(m_spanLog2); + applySettings(); + return true; + } + + return false; +} + +void ChannelAnalyzerNGGUI::handleInputMessages() +{ + Message* message; + + while ((message = getInputMessageQueue()->pop()) != 0) + { + qDebug("ChannelAnalyzerGUI::handleInputMessages: message: %s", message->getIdentifier()); + + if (handleMessage(*message)) + { + delete message; + } + } +} + +void ChannelAnalyzerNGGUI::viewChanged() +{ + applySettings(); +} + +void ChannelAnalyzerNGGUI::tick() +{ + double powDb = CalcDb::dbPower(m_channelAnalyzer->getMagSq()); + m_channelPowerDbAvg.feed(powDb); + ui->channelPower->setText(tr("%1 dB").arg(m_channelPowerDbAvg.average(), 0, 'f', 1)); +} + +//void ChannelAnalyzerNGGUI::channelizerInputSampleRateChanged() +//{ +// //ui->channelSampleRate->setValueRange(7, 2000U, m_channelAnalyzer->getInputSampleRate()); +// setNewFinalRate(m_spanLog2); +// applySettings(); +//} + +void ChannelAnalyzerNGGUI::on_channelSampleRate_changed(quint64 value) +{ + ui->channelSampleRate->setValueRange(7, 2000U, m_channelAnalyzer->getInputSampleRate()); + + if (ui->useRationalDownsampler->isChecked()) + { + qDebug("ChannelAnalyzerNGGUI::on_channelSampleRate_changed: %llu", value); + setNewFinalRate(m_spanLog2); + applySettings(); + } +} + +void ChannelAnalyzerNGGUI::on_useRationalDownsampler_toggled(bool checked __attribute__((unused))) +{ + setNewFinalRate(m_spanLog2); + applySettings(); +} + +int ChannelAnalyzerNGGUI::getRequestedChannelSampleRate() +{ + if (ui->useRationalDownsampler->isChecked()) { + return ui->channelSampleRate->getValueNew(); + } else { + return m_channelAnalyzer->getChannelizer()->getInputSampleRate(); + } +} + +void ChannelAnalyzerNGGUI::on_deltaFrequency_changed(qint64 value) +{ + m_channelMarker.setCenterFrequency(value); +} + +void ChannelAnalyzerNGGUI::on_BW_valueChanged(int value) +{ + m_channelMarker.setBandwidth(value * 100 * 2); + + if (ui->ssb->isChecked()) + { + QString s = QString::number(value/10.0, 'f', 1); + ui->BWText->setText(tr("%1k").arg(s)); + } + else + { + QString s = QString::number(value/5.0, 'f', 1); // BW = value * 2 + ui->BWText->setText(tr("%1k").arg(s)); + } + + displayBandwidth(); + on_lowCut_valueChanged(m_channelMarker.getLowCutoff()/100); +} + +int ChannelAnalyzerNGGUI::getEffectiveLowCutoff(int lowCutoff) +{ + int ssbBW = m_channelMarker.getBandwidth() / 2; + int effectiveLowCutoff = lowCutoff; + const int guard = 100; + + if (ssbBW < 0) { + if (effectiveLowCutoff < ssbBW + guard) { + effectiveLowCutoff = ssbBW + guard; + } + if (effectiveLowCutoff > 0) { + effectiveLowCutoff = 0; + } + } else { + if (effectiveLowCutoff > ssbBW - guard) { + effectiveLowCutoff = ssbBW - guard; + } + if (effectiveLowCutoff < 0) { + effectiveLowCutoff = 0; + } + } + + return effectiveLowCutoff; +} + +void ChannelAnalyzerNGGUI::on_lowCut_valueChanged(int value) +{ + int lowCutoff = getEffectiveLowCutoff(value * 100); + m_channelMarker.setLowCutoff(lowCutoff); + QString s = QString::number(lowCutoff/1000.0, 'f', 1); + ui->lowCutText->setText(tr("%1k").arg(s)); + ui->lowCut->setValue(lowCutoff/100); + applySettings(); +} + +void ChannelAnalyzerNGGUI::on_spanLog2_currentIndexChanged(int index) +{ + if (setNewFinalRate(index)) { + applySettings(); + } + +} + +void ChannelAnalyzerNGGUI::on_ssb_toggled(bool checked) +{ + //int bw = m_channelMarker.getBandwidth(); + + if (checked) + { + setFiltersUIBoundaries(); + + ui->BWLabel->setText("LP"); + QString s = QString::number(ui->BW->value()/10.0, 'f', 1); // bw/2 + ui->BWText->setText(tr("%1k").arg(s)); + + on_lowCut_valueChanged(m_channelMarker.getLowCutoff()/100); + } + else + { + if (ui->BW->value() < 0) { + ui->BW->setValue(-ui->BW->value()); + } + + setFiltersUIBoundaries(); + //m_channelMarker.setBandwidth(ui->BW->value() * 200.0); + + ui->BWLabel->setText("BP"); + QString s = QString::number(ui->BW->value()/5.0, 'f', 1); // bw + ui->BWText->setText(tr("%1k").arg(s)); + + ui->lowCut->setEnabled(false); + ui->lowCut->setValue(0); + ui->lowCutText->setText("0.0k"); + } + + applySettings(); + displayBandwidth(); +} + +void ChannelAnalyzerNGGUI::onWidgetRolled(QWidget* widget __attribute__((unused)), bool rollDown __attribute__((unused))) +{ + /* + if((widget == ui->spectrumContainer) && (m_ssbDemod != NULL)) + m_ssbDemod->setSpectrum(m_threadedSampleSink->getMessageQueue(), rollDown); + */ +} + +void ChannelAnalyzerNGGUI::onMenuDoubleClicked() +{ + if(!m_basicSettingsShown) { + m_basicSettingsShown = true; + BasicChannelSettingsWidget* bcsw = new BasicChannelSettingsWidget(&m_channelMarker, this); + bcsw->show(); + } +} + +ChannelAnalyzerNGGUI::ChannelAnalyzerNGGUI(PluginAPI* pluginAPI, DeviceSourceAPI *deviceAPI, QWidget* parent) : + RollupWidget(parent), + ui(new Ui::ChannelAnalyzerNGGUI), + m_pluginAPI(pluginAPI), + m_deviceAPI(deviceAPI), + m_channelMarker(this), + m_basicSettingsShown(false), + m_doApplySettings(true), + m_rate(6000), + m_spanLog2(0), + m_channelPowerDbAvg(40,0) +{ + ui->setupUi(this); + setAttribute(Qt::WA_DeleteOnClose, true); + connect(this, SIGNAL(widgetRolled(QWidget*,bool)), this, SLOT(onWidgetRolled(QWidget*,bool))); + connect(this, SIGNAL(menuDoubleClickEvent()), this, SLOT(onMenuDoubleClicked())); + + m_spectrumVis = new SpectrumVis(ui->glSpectrum); + m_scopeVis = new ScopeVisNG(ui->glScope); + m_spectrumScopeComboVis = new SpectrumScopeNGComboVis(m_spectrumVis, m_scopeVis); + m_channelAnalyzer = new ChannelAnalyzerNG(m_deviceAPI); + m_channelAnalyzer->setSampleSink(m_spectrumScopeComboVis); + m_channelAnalyzer->setMessageQueueToGUI(getInputMessageQueue()); +// m_channelizer = new DownChannelizer(m_channelAnalyzer); +// m_threadedChannelizer = new ThreadedBasebandSampleSink(m_channelizer, this); +// connect(m_channelizer, SIGNAL(inputSampleRateChanged()), this, SLOT(channelizerInputSampleRateChanged())); +// m_deviceAPI->addThreadedSink(m_threadedChannelizer); + + ui->deltaFrequencyLabel->setText(QString("%1f").arg(QChar(0x94, 0x03))); + ui->deltaFrequency->setColorMapper(ColorMapper(ColorMapper::GrayGold)); + ui->deltaFrequency->setValueRange(false, 7, -9999999, 9999999); + + ui->channelSampleRate->setColorMapper(ColorMapper(ColorMapper::GrayGreenYellow)); + ui->channelSampleRate->setValueRange(7, 2000U, 9999999U); + + ui->glSpectrum->setCenterFrequency(m_rate/2); + ui->glSpectrum->setSampleRate(m_rate); + ui->glSpectrum->setDisplayWaterfall(true); + ui->glSpectrum->setDisplayMaxHold(true); + ui->glSpectrum->setSsbSpectrum(false); + ui->glSpectrum->setLsbDisplay(false); + ui->BWLabel->setText("BP"); + + ui->glSpectrum->connectTimer(m_pluginAPI->getMainWindow()->getMasterTimer()); + ui->glScope->connectTimer(m_pluginAPI->getMainWindow()->getMasterTimer()); + connect(&m_pluginAPI->getMainWindow()->getMasterTimer(), SIGNAL(timeout()), this, SLOT(tick())); + + //m_channelMarker = new ChannelMarker(this); + m_channelMarker.setColor(Qt::gray); + m_channelMarker.setBandwidth(m_rate); + m_channelMarker.setSidebands(ChannelMarker::usb); + m_channelMarker.setCenterFrequency(0); + m_channelMarker.setVisible(true); + + connect(&m_channelMarker, SIGNAL(changed()), this, SLOT(viewChanged())); + + m_deviceAPI->registerChannelInstance(m_channelID, this); + m_deviceAPI->addChannelMarker(&m_channelMarker); + m_deviceAPI->addRollupWidget(this); + + ui->spectrumGUI->setBuddies(m_spectrumVis->getInputMessageQueue(), m_spectrumVis, ui->glSpectrum); + ui->scopeGUI->setBuddies(m_scopeVis->getInputMessageQueue(), m_scopeVis, ui->glScope); + + connect(getInputMessageQueue(), SIGNAL(messageEnqueued()), this, SLOT(handleInputMessages())); + + applySettings(); + setNewFinalRate(m_spanLog2); +} + +ChannelAnalyzerNGGUI::~ChannelAnalyzerNGGUI() +{ + m_deviceAPI->removeChannelInstance(this); +// m_deviceAPI->removeThreadedSink(m_threadedChannelizer); +// delete m_threadedChannelizer; +// delete m_channelizer; + delete m_channelAnalyzer; + delete m_spectrumVis; + delete m_scopeVis; + delete m_spectrumScopeComboVis; + //delete m_channelMarker; + delete ui; +} + +bool ChannelAnalyzerNGGUI::setNewFinalRate(int spanLog2) +{ + qDebug("ChannelAnalyzerNGGUI::setNewRate"); + + if ((spanLog2 < 0) || (spanLog2 > 6)) { + return false; + } + + m_spanLog2 = spanLog2; + //m_rate = 48000 / (1<getInputSampleRate() / (1<spanText->setText(tr("%1 kS/s").arg(s)); + + displayBandwidth(); + + ui->glScope->setSampleRate(m_rate); + m_scopeVis->setSampleRate(m_rate); + + return true; +} + +void ChannelAnalyzerNGGUI::displayBandwidth() +{ + if (ui->ssb->isChecked()) + { + if (ui->BW->value() < 0) + { + m_channelMarker.setSidebands(ChannelMarker::lsb); + ui->glSpectrum->setLsbDisplay(true); + } + else + { + m_channelMarker.setSidebands(ChannelMarker::usb); + ui->glSpectrum->setLsbDisplay(false); + } + + ui->glSpectrum->setCenterFrequency(m_rate/4); + ui->glSpectrum->setSampleRate(m_rate/2); + ui->glSpectrum->setSsbSpectrum(true); + } + else + { + m_channelMarker.setSidebands(ChannelMarker::dsb); + + ui->glSpectrum->setCenterFrequency(0); + ui->glSpectrum->setSampleRate(m_rate); + ui->glSpectrum->setLsbDisplay(false); + ui->glSpectrum->setSsbSpectrum(false); + } + + +} + +void ChannelAnalyzerNGGUI::setFiltersUIBoundaries() +{ + if (ui->BW->value() < -m_rate/200) { + ui->BW->setValue(-m_rate/200); + m_channelMarker.setBandwidth(-m_rate*2); + } else if (ui->BW->value() > m_rate/200) { + ui->BW->setValue(m_rate/200); + m_channelMarker.setBandwidth(m_rate*2); + } + + if (ui->lowCut->value() < -m_rate/200) { + ui->lowCut->setValue(-m_rate/200); + m_channelMarker.setLowCutoff(-m_rate); + } else if (ui->lowCut->value() > m_rate/200) { + ui->lowCut->setValue(m_rate/200); + m_channelMarker.setLowCutoff(m_rate); + } + + if (ui->ssb->isChecked()) { + ui->BW->setMinimum(-m_rate/200); + ui->lowCut->setMinimum(-m_rate/200); + } else { + ui->BW->setMinimum(0); + ui->lowCut->setMinimum(-m_rate/200); + ui->lowCut->setValue(0); + } + + ui->BW->setMaximum(m_rate/200); + ui->lowCut->setMaximum(m_rate/200); +} + +void ChannelAnalyzerNGGUI::blockApplySettings(bool block) +{ + ui->glScope->blockSignals(block); + ui->glSpectrum->blockSignals(block); + m_doApplySettings = !block; +} + +void ChannelAnalyzerNGGUI::applySettings() +{ + if (m_doApplySettings) + { + setTitleColor(m_channelMarker.getColor()); + ui->deltaFrequency->setValue(m_channelMarker.getCenterFrequency()); + + int sampleRate = getRequestedChannelSampleRate(); + + ChannelAnalyzerNG::MsgConfigureChannelizer *msgChannelizer = ChannelAnalyzerNG::MsgConfigureChannelizer::create(sampleRate, m_channelMarker.getCenterFrequency()); + m_channelAnalyzer->getInputMessageQueue()->push(msgChannelizer); + + ChannelAnalyzerNG::MsgConfigureChannelizer *msg = + ChannelAnalyzerNG::MsgConfigureChannelizer::create( + sampleRate, + m_channelMarker.getCenterFrequency()); + m_channelAnalyzer->getInputMessageQueue()->push(msg); + +// m_channelizer->configure(m_channelizer->getInputMessageQueue(), +// //m_channelizer->getInputSampleRate(), +// getRequestedChannelSampleRate(), +// m_channelMarker.getCenterFrequency()); + + m_channelAnalyzer->configure(m_channelAnalyzer->getInputMessageQueue(), + //m_channelizer->getInputSampleRate(), // TODO: specify required channel sample rate + sampleRate, // TODO: specify required channel sample rate + ui->BW->value() * 100.0, + ui->lowCut->value() * 100.0, + m_spanLog2, + ui->ssb->isChecked()); + } +} + +void ChannelAnalyzerNGGUI::leaveEvent(QEvent*) +{ + blockApplySettings(true); + m_channelMarker.setHighlighted(false); + blockApplySettings(false); +} + +void ChannelAnalyzerNGGUI::enterEvent(QEvent*) +{ + blockApplySettings(true); + m_channelMarker.setHighlighted(true); + blockApplySettings(false); +} + diff --git a/plugins/channelrx/chanalyzerng/chanalyzernggui.h b/plugins/channelrx/chanalyzerng/chanalyzernggui.h index 1fc764357..7ef686b66 100644 --- a/plugins/channelrx/chanalyzerng/chanalyzernggui.h +++ b/plugins/channelrx/chanalyzerng/chanalyzernggui.h @@ -59,7 +59,7 @@ public: private slots: void viewChanged(); - void channelizerInputSampleRateChanged(); +// void channelizerInputSampleRateChanged(); void on_deltaFrequency_changed(qint64 value); void on_channelSampleRate_changed(quint64 value); void on_useRationalDownsampler_toggled(bool checked); @@ -69,6 +69,7 @@ private slots: void on_ssb_toggled(bool checked); void onWidgetRolled(QWidget* widget, bool rollDown); void onMenuDoubleClicked(); + void handleInputMessages(); void tick(); private: @@ -82,8 +83,8 @@ private: int m_spanLog2; MovingAverage m_channelPowerDbAvg; - ThreadedBasebandSampleSink* m_threadedChannelizer; - DownChannelizer* m_channelizer; +// ThreadedBasebandSampleSink* m_threadedChannelizer; +// DownChannelizer* m_channelizer; ChannelAnalyzerNG* m_channelAnalyzer; SpectrumScopeNGComboVis* m_spectrumScopeComboVis; SpectrumVis* m_spectrumVis; From 95b191353b5db1db97d2c1afee0510f042c3cdd7 Mon Sep 17 00:00:00 2001 From: f4exb Date: Sat, 30 Sep 2017 04:05:32 +0200 Subject: [PATCH 36/71] Fixed warnings with g++ 6.3 --- plugins/channelrx/udpsrc/udpsrc.cpp | 2 +- sdrbase/device/devicesinkapi.cpp | 4 ---- sdrbase/device/devicesourceapi.cpp | 4 ---- sdrbase/gui/audiodialog.cpp | 6 ++++-- 4 files changed, 5 insertions(+), 11 deletions(-) diff --git a/plugins/channelrx/udpsrc/udpsrc.cpp b/plugins/channelrx/udpsrc/udpsrc.cpp index 5a91326b1..3954b6582 100644 --- a/plugins/channelrx/udpsrc/udpsrc.cpp +++ b/plugins/channelrx/udpsrc/udpsrc.cpp @@ -476,7 +476,7 @@ void UDPSrc::apply(bool force) m_outMovingAverage.resize(m_config.m_outputSampleRate * 0.01, 1e-10); // 10 ms } - if ((m_config.m_audioActive != m_config.m_audioActive) || force) + if ((m_config.m_audioActive != m_running.m_audioActive) || force) { if (m_config.m_audioActive) { diff --git a/sdrbase/device/devicesinkapi.cpp b/sdrbase/device/devicesinkapi.cpp index e634c5d68..d5e3413b1 100644 --- a/sdrbase/device/devicesinkapi.cpp +++ b/sdrbase/device/devicesinkapi.cpp @@ -395,8 +395,6 @@ bool DeviceSinkAPI::ChannelInstanceRegistration::operator<(const ChannelInstance void DeviceSinkAPI::addSourceBuddy(DeviceSourceAPI* buddy) { - std::vector::iterator it = m_sourceBuddies.begin(); - m_sourceBuddies.push_back(buddy); buddy->m_sinkBuddies.push_back(this); qDebug("DeviceSinkAPI::addSourceBuddy: added buddy %s(%s) to the list [%lx] <-> [%lx]", @@ -408,8 +406,6 @@ void DeviceSinkAPI::addSourceBuddy(DeviceSourceAPI* buddy) void DeviceSinkAPI::addSinkBuddy(DeviceSinkAPI* buddy) { - std::vector::iterator it = m_sinkBuddies.begin(); - m_sinkBuddies.push_back(buddy); buddy->m_sinkBuddies.push_back(this); qDebug("DeviceSinkAPI::addSinkBuddy: added buddy %s(%s) to the list [%lx] <-> [%lx]", diff --git a/sdrbase/device/devicesourceapi.cpp b/sdrbase/device/devicesourceapi.cpp index 17afc8233..fb63fc50a 100644 --- a/sdrbase/device/devicesourceapi.cpp +++ b/sdrbase/device/devicesourceapi.cpp @@ -398,8 +398,6 @@ bool DeviceSourceAPI::ChannelInstanceRegistration::operator<(const ChannelInstan void DeviceSourceAPI::addSourceBuddy(DeviceSourceAPI* buddy) { - std::vector::iterator it = m_sourceBuddies.begin(); - m_sourceBuddies.push_back(buddy); buddy->m_sourceBuddies.push_back(this); qDebug("DeviceSourceAPI::addSourceBuddy: added buddy %s(%s) [%lx] <-> [%lx]", @@ -411,8 +409,6 @@ void DeviceSourceAPI::addSourceBuddy(DeviceSourceAPI* buddy) void DeviceSourceAPI::addSinkBuddy(DeviceSinkAPI* buddy) { - std::vector::iterator it = m_sinkBuddies.begin(); - m_sinkBuddies.push_back(buddy); buddy->m_sourceBuddies.push_back(this); qDebug("DeviceSourceAPI::addSinkBuddy: added buddy %s(%s) [%lx] <-> [%lx]", diff --git a/sdrbase/gui/audiodialog.cpp b/sdrbase/gui/audiodialog.cpp index 827f336b6..c8874cfa7 100644 --- a/sdrbase/gui/audiodialog.cpp +++ b/sdrbase/gui/audiodialog.cpp @@ -54,11 +54,13 @@ AudioDialog::AudioDialog(AudioDeviceInfo* audioDeviceInfo, QWidget* parent) : i++; } - if(ui->audioOutTree->currentItem() == NULL) + if(ui->audioOutTree->currentItem() == 0) { ui->audioOutTree->setCurrentItem(ui->audioOutTree->topLevelItem(0)); + } - if(ui->audioInTree->currentItem() == NULL) + if(ui->audioInTree->currentItem() == 0) { ui->audioInTree->setCurrentItem(ui->audioInTree->topLevelItem(0)); + } ui->tabWidget->setCurrentIndex(0); From 9f79ac24bfb402b2c4096323e1760490eaea4f83 Mon Sep 17 00:00:00 2001 From: f4exb Date: Sat, 30 Sep 2017 09:29:22 +0200 Subject: [PATCH 37/71] CRLF problem --- devices/limesdr/devicelimesdr.h | 112 ++++++++++++++++---------------- 1 file changed, 56 insertions(+), 56 deletions(-) diff --git a/devices/limesdr/devicelimesdr.h b/devices/limesdr/devicelimesdr.h index 8a50ceb94..4cc34d177 100644 --- a/devices/limesdr/devicelimesdr.h +++ b/devices/limesdr/devicelimesdr.h @@ -1,56 +1,56 @@ -/////////////////////////////////////////////////////////////////////////////////// -// Copyright (C) 2017 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 // -// // -// This program is distributed in the hope that it will be useful, // -// but WITHOUT ANY WARRANTY; without even the implied warranty of // -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // -// GNU General Public License V3 for more details. // -// // -// You should have received a copy of the GNU General Public License // -// along with this program. If not, see . // -/////////////////////////////////////////////////////////////////////////////////// - -#ifndef DEVICES_LIMESDR_DEVICELIMESDR_H_ -#define DEVICES_LIMESDR_DEVICELIMESDR_H_ - -#include "lime/LimeSuite.h" - -class DeviceLimeSDR -{ -public: - enum PathRxRFE - { - PATH_RFE_RX_NONE = 0, - PATH_RFE_LNAH, - PATH_RFE_LNAL, - PATH_RFE_LNAW, - PATH_RFE_LB1, - PATH_RFE_LB2 - }; - - enum PathTxRFE - { - PATH_RFE_TX_NONE = 0, - PATH_RFE_TXRF1, - PATH_RFE_TXRF2, - }; - - /** set NCO frequency with positive or negative frequency (deals with up/down convert). Enables or disables NCO */ - static bool setNCOFrequency(lms_device_t *device, bool dir_tx, std::size_t chan, bool enable, float frequency); - /** set LNA gain Range: [1-30] (dB) **/ - static bool SetRFELNA_dB(lms_device_t *device, std::size_t chan, int value); - /** set TIA gain Range: [1-3] **/ - static bool SetRFETIA_dB(lms_device_t *device, std::size_t chan, int value); - /** set PGA gain Range: [0-32] (dB) **/ - static bool SetRBBPGA_dB(lms_device_t *device, std::size_t chan, float value); - /** Set Rx antenna path **/ - static bool setRxAntennaPath(lms_device_t *device, std::size_t chan, int path); - /** Set Tx antenna path **/ - static bool setTxAntennaPath(lms_device_t *device, std::size_t chan, int path); -}; - -#endif /* DEVICES_LIMESDR_DEVICELIMESDR_H_ */ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2017 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 // +// // +// This program is distributed in the hope that it will be useful, // +// but WITHOUT ANY WARRANTY; without even the implied warranty of // +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // +// GNU General Public License V3 for more details. // +// // +// You should have received a copy of the GNU General Public License // +// along with this program. If not, see . // +/////////////////////////////////////////////////////////////////////////////////// + +#ifndef DEVICES_LIMESDR_DEVICELIMESDR_H_ +#define DEVICES_LIMESDR_DEVICELIMESDR_H_ + +#include "lime/LimeSuite.h" + +class DeviceLimeSDR +{ +public: + enum PathRxRFE + { + PATH_RFE_RX_NONE = 0, + PATH_RFE_LNAH, + PATH_RFE_LNAL, + PATH_RFE_LNAW, + PATH_RFE_LB1, + PATH_RFE_LB2 + }; + + enum PathTxRFE + { + PATH_RFE_TX_NONE = 0, + PATH_RFE_TXRF1, + PATH_RFE_TXRF2, + }; + + /** set NCO frequency with positive or negative frequency (deals with up/down convert). Enables or disables NCO */ + static bool setNCOFrequency(lms_device_t *device, bool dir_tx, std::size_t chan, bool enable, float frequency); + /** set LNA gain Range: [1-30] (dB) **/ + static bool SetRFELNA_dB(lms_device_t *device, std::size_t chan, int value); + /** set TIA gain Range: [1-3] **/ + static bool SetRFETIA_dB(lms_device_t *device, std::size_t chan, int value); + /** set PGA gain Range: [0-32] (dB) **/ + static bool SetRBBPGA_dB(lms_device_t *device, std::size_t chan, float value); + /** Set Rx antenna path **/ + static bool setRxAntennaPath(lms_device_t *device, std::size_t chan, int path); + /** Set Tx antenna path **/ + static bool setTxAntennaPath(lms_device_t *device, std::size_t chan, int path); +}; + +#endif /* DEVICES_LIMESDR_DEVICELIMESDR_H_ */ From 229027c34580138eb0e58674a3e72ee3b174a4f6 Mon Sep 17 00:00:00 2001 From: f4exb Date: Sat, 30 Sep 2017 09:30:07 +0200 Subject: [PATCH 38/71] Debian build: indicate libnanomsg4 as an alternative for dependency on libnanomsg --- debian/control | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/debian/control b/debian/control index 8aa57f309..5ae42f3a4 100644 --- a/debian/control +++ b/debian/control @@ -10,7 +10,7 @@ Homepage: https://github.com/f4exb/sdrangel Package: sdrangel Architecture: any -Depends: libc6, libasound2, libfftw3-single3, libgcc1, libgl1-mesa-glx, libnanomsg0, libqt5core5a, libqt5gui5, libqt5multimedia5, libqt5network5, libqt5opengl5, libqt5widgets5, libqt5multimedia5-plugins, libstdc++6, libusb-1.0-0, libopencv-dev, libsqlite3-dev, pulseaudio, libxml2, ${shlibs:Depends}, ${misc:Depends} +Depends: libc6, libasound2, libfftw3-single3, libgcc1, libgl1-mesa-glx, libnanomsg0|libnanomsg4, libqt5core5a, libqt5gui5, libqt5multimedia5, libqt5network5, libqt5opengl5, libqt5widgets5, libqt5multimedia5-plugins, libstdc++6, libusb-1.0-0, libopencv-dev, libsqlite3-dev, pulseaudio, libxml2, ${shlibs:Depends}, ${misc:Depends} Description: SDR/Analyzer/Generator front-end for various hardware SDR/Analyzer/Generator front-end for Airspy, BladeRF, HackRF, RTL-SDR, FunCube, LimeSDR, PlutoSDR. Also File source and sink for I/Q samples, network I/Q sources with SDRDaemon. From 7c558b15f5f7b3f08ccd9632a03e16616c6bfca9 Mon Sep 17 00:00:00 2001 From: f4exb Date: Sat, 30 Sep 2017 18:29:53 +0200 Subject: [PATCH 39/71] LimeSDR: use CMIX_BYP_TXTSP to control NCO on/off --- devices/limesdr/devicelimesdr.cpp | 671 +++++++++++++++--------------- 1 file changed, 346 insertions(+), 325 deletions(-) diff --git a/devices/limesdr/devicelimesdr.cpp b/devices/limesdr/devicelimesdr.cpp index 1806072c1..88e0e69d4 100644 --- a/devices/limesdr/devicelimesdr.cpp +++ b/devices/limesdr/devicelimesdr.cpp @@ -1,325 +1,346 @@ -/////////////////////////////////////////////////////////////////////////////////// -// Copyright (C) 2017 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 // -// // -// This program is distributed in the hope that it will be useful, // -// but WITHOUT ANY WARRANTY; without even the implied warranty of // -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // -// GNU General Public License V3 for more details. // -// // -// You should have received a copy of the GNU General Public License // -// along with this program. If not, see . // -/////////////////////////////////////////////////////////////////////////////////// - -#include -#include -#include -#include "devicelimesdr.h" - -bool DeviceLimeSDR::setNCOFrequency(lms_device_t *device, bool dir_tx, std::size_t chan, bool enable, float frequency) -{ - if (enable) - { - bool positive; - float_type freqs[LMS_NCO_VAL_COUNT]; - float_type phos[LMS_NCO_VAL_COUNT]; - - if (LMS_GetNCOFrequency(device, dir_tx, chan, freqs, phos) < 0) - { - fprintf(stderr, "DeviceLimeSDR::setNCOFrequency: cannot get NCO frequencies and phases\n"); - } - - if (frequency < 0) - { - positive = false; - frequency = -frequency; - } - else - { - positive = true; - } - - freqs[0] = frequency; - - if (LMS_SetNCOFrequency(device, dir_tx, chan, freqs, 0.0f) < 0) - { - fprintf(stderr, "DeviceLimeSDR::setNCOFrequency: cannot set frequency to %f\n", frequency); - return false; - } - - if (LMS_SetNCOIndex(device, dir_tx, chan, 0, !positive) < 0) - { - fprintf(stderr, "DeviceLimeSDR::setNCOFrequency: cannot set conversion direction %sfreq\n", positive ? "+" : "-"); - return false; - } - - return true; - } - else - { - if (LMS_SetNCOIndex(device, dir_tx, chan, LMS_NCO_VAL_COUNT, true) < 0) - { - fprintf(stderr, "DeviceLimeSDR::setNCOFrequency: cannot disable NCO\n"); - return false; - } - else - { - fprintf(stderr, "DeviceLimeSDR::setNCOFrequency: NCO disabled\n"); - return true; - } - } -} - -bool DeviceLimeSDR::SetRFELNA_dB(lms_device_t *device, std::size_t chan, int value) -{ - if (LMS_WriteParam(device, LMS7param(MAC), chan+1) < 0) - { - fprintf(stderr, "DeviceLimeSDR::SetRFELNA_dB: cannot set channel to #%lu\n", chan); - return false; - } - - if (value > 30) { - value = 30; - } - - int val = value - 30; - - int g_lna_rfe = 0; - if (val >= 0) g_lna_rfe = 15; - else if (val >= -1) g_lna_rfe = 14; - else if (val >= -2) g_lna_rfe = 13; - else if (val >= -3) g_lna_rfe = 12; - else if (val >= -4) g_lna_rfe = 11; - else if (val >= -5) g_lna_rfe = 10; - else if (val >= -6) g_lna_rfe = 9; - else if (val >= -9) g_lna_rfe = 8; - else if (val >= -12) g_lna_rfe = 7; - else if (val >= -15) g_lna_rfe = 6; - else if (val >= -18) g_lna_rfe = 5; - else if (val >= -21) g_lna_rfe = 4; - else if (val >= -24) g_lna_rfe = 3; - else if (val >= -27) g_lna_rfe = 2; - else g_lna_rfe = 1; - - if (LMS_WriteParam(device, LMS7param(G_LNA_RFE), g_lna_rfe) < 0) - { - fprintf(stderr, "DeviceLimeSDR::SetRFELNA_dB: cannot set LNA gain to %d (%d)\n", value, g_lna_rfe); - return false; - } - - return true; -} - -bool DeviceLimeSDR::SetRFETIA_dB(lms_device_t *device, std::size_t chan, int value) -{ - if (LMS_WriteParam(device, LMS7param(MAC), chan+1) < 0) - { - fprintf(stderr, "DeviceLimeSDR::SetRFETIA_dB: cannot set channel to #%lu\n", chan); - return false; - } - - if (value > 3) { - value = 3; - } else if (value < 1) { - value = 1; - } - - int g_tia_rfe = value; - - if (LMS_WriteParam(device, LMS7param(G_TIA_RFE), g_tia_rfe) < 0) - { - fprintf(stderr, "DeviceLimeSDR::SetRFELNA_dB: cannot set TIA gain to %d (%d)\n", value, g_tia_rfe); - return false; - } - - return true; -} - -bool DeviceLimeSDR::SetRBBPGA_dB(lms_device_t *device, std::size_t chan, float value) -{ - if (LMS_WriteParam(device, LMS7param(MAC), chan+1) < 0) - { - fprintf(stderr, "DeviceLimeSDR::SetRBBPGA_dB: cannot set channel to #%lu\n", chan); - return false; - } - - int g_pga_rbb = (int)(value + 12.5); - if (g_pga_rbb > 0x1f) g_pga_rbb = 0x1f; - if (g_pga_rbb < 0) g_pga_rbb = 0; - - if (LMS_WriteParam(device, LMS7param(G_PGA_RBB), g_pga_rbb) < 0) - { - fprintf(stderr, "DeviceLimeSDR::SetRBBPGA_dB: cannot set G_PGA_RBB to %d\n", g_pga_rbb); - return false; - } - - int rcc_ctl_pga_rbb = (430.0*pow(0.65, (g_pga_rbb/10.0))-110.35)/20.4516 + 16; - - int c_ctl_pga_rbb = 0; - if (0 <= g_pga_rbb && g_pga_rbb < 8) c_ctl_pga_rbb = 3; - if (8 <= g_pga_rbb && g_pga_rbb < 13) c_ctl_pga_rbb = 2; - if (13 <= g_pga_rbb && g_pga_rbb < 21) c_ctl_pga_rbb = 1; - if (21 <= g_pga_rbb) c_ctl_pga_rbb = 0; - - if (LMS_WriteParam(device, LMS7param(RCC_CTL_PGA_RBB), rcc_ctl_pga_rbb) < 0) - { - fprintf(stderr, "DeviceLimeSDR::SetRBBPGA_dB: cannot set RCC_CTL_PGA_RBB to %d\n", rcc_ctl_pga_rbb); - return false; - } - - if (LMS_WriteParam(device, LMS7param(C_CTL_PGA_RBB), c_ctl_pga_rbb) < 0) - { - fprintf(stderr, "DeviceLimeSDR::SetRBBPGA_dB: cannot set C_CTL_PGA_RBB to %d\n", c_ctl_pga_rbb); - return false; - } - - return true; -} - -bool DeviceLimeSDR::setRxAntennaPath(lms_device_t *device, std::size_t chan, int path) -{ -// if (LMS_WriteParam(device, LMS7param(MAC), chan+1) < 0) -// { -// fprintf(stderr, "DeviceLimeSDR::setAntennaPath: cannot set channel to #%lu\n", chan); -// return false; -// } -// -// int sel_path_rfe = 0; -// switch ((PathRFE) path) -// { -// case PATH_RFE_NONE: sel_path_rfe = 0; break; -// case PATH_RFE_LNAH: sel_path_rfe = 1; break; -// case PATH_RFE_LNAL: sel_path_rfe = 2; break; -// case PATH_RFE_LNAW: sel_path_rfe = 3; break; -// case PATH_RFE_LB1: sel_path_rfe = 3; break; -// case PATH_RFE_LB2: sel_path_rfe = 2; break; -// } -// -// int pd_lna_rfe = 1; -// switch ((PathRFE) path) -// { -// case PATH_RFE_LNAH: -// case PATH_RFE_LNAL: -// case PATH_RFE_LNAW: pd_lna_rfe = 0; break; -// default: break; -// } -// -// int pd_rloopb_1_rfe = (path == (int) PATH_RFE_LB1) ? 0 : 1; -// int pd_rloopb_2_rfe = (path == (int) PATH_RFE_LB2) ? 0 : 1; -// int en_inshsw_l_rfe = (path == (int) PATH_RFE_LNAL ) ? 0 : 1; -// int en_inshsw_w_rfe = (path == (int) PATH_RFE_LNAW) ? 0 : 1; -// int en_inshsw_lb1_rfe = (path == (int) PATH_RFE_LB1) ? 0 : 1; -// int en_inshsw_lb2_rfe = (path == (int) PATH_RFE_LB2) ? 0 : 1; -// -// int ret = 0; -// -// ret += LMS_WriteParam(device, LMS7param(PD_LNA_RFE), pd_lna_rfe); -// ret += LMS_WriteParam(device, LMS7param(PD_RLOOPB_1_RFE), pd_rloopb_1_rfe); -// ret += LMS_WriteParam(device, LMS7param(PD_RLOOPB_2_RFE), pd_rloopb_2_rfe); -// ret += LMS_WriteParam(device, LMS7param(EN_INSHSW_LB1_RFE), en_inshsw_lb1_rfe); -// ret += LMS_WriteParam(device, LMS7param(EN_INSHSW_LB2_RFE), en_inshsw_lb2_rfe); -// ret += LMS_WriteParam(device, LMS7param(EN_INSHSW_L_RFE), en_inshsw_l_rfe); -// ret += LMS_WriteParam(device, LMS7param(EN_INSHSW_W_RFE), en_inshsw_w_rfe); -// ret += LMS_WriteParam(device, LMS7param(SEL_PATH_RFE), sel_path_rfe); -// -// if (ret < 0) -// { -// fprintf(stderr, "DeviceLimeSDR::setAntennaPath: cannot set channel #%lu to %d\n", chan, path); -// return false; -// } -// -// //enable/disable the loopback path -// const bool loopback = (path == (int) PATH_RFE_LB1) or (path == (int) PATH_RFE_LB2); -// -// if (LMS_WriteParam(device, LMS7param(EN_LOOPB_TXPAD_TRF), loopback ? 1 : 0) < 0) -// { -// fprintf(stderr, "DeviceLimeSDR::setAntennaPath: cannot %sset loopback on channel #%lu\n", loopback ? "" : "re", chan); -// return false; -// } -// -// //update external band-selection to match -// //this->UpdateExternalBandSelect(); -// -// return true; - - switch ((PathRxRFE) path) - { - case PATH_RFE_LNAH: - if (LMS_SetAntenna(device, LMS_CH_RX, chan, 1) < 0) - { - fprintf(stderr, "DeviceLimeSDR::setRxAntennaPath: cannot set to LNAH\n"); - return false; - } - break; - case PATH_RFE_LNAL: - if (LMS_SetAntenna(device, LMS_CH_RX, chan, 2) < 0) - { - fprintf(stderr, "DeviceLimeSDR::setRxAntennaPath: cannot set to LNAL\n"); - return false; - } - break; - case PATH_RFE_LNAW: - if (LMS_SetAntenna(device, LMS_CH_RX, chan, 3) < 0) - { - fprintf(stderr, "DeviceLimeSDR::setRxAntennaPath: cannot set to LNAW\n"); - return false; - } - break; - case PATH_RFE_LB1: - if (LMS_SetAntenna(device, LMS_CH_TX, chan, 1) < 0) - { - fprintf(stderr, "DeviceLimeSDR::setRxAntennaPath: cannot set to Loopback TX1\n"); - return false; - } - break; - case PATH_RFE_LB2: - if (LMS_SetAntenna(device, LMS_CH_TX, chan, 2) < 0) - { - fprintf(stderr, "DeviceLimeSDR::setRxAntennaPath: cannot set to Loopback TX2\n"); - return false; - } - break; - case PATH_RFE_RX_NONE: - default: - if (LMS_SetAntenna(device, LMS_CH_RX, chan, 0) < 0) - { - fprintf(stderr, "DeviceLimeSDR::setRxAntennaPath: cannot set to none\n"); - return false; - } - } - - return true; -} - -bool DeviceLimeSDR::setTxAntennaPath(lms_device_t *device, std::size_t chan, int path) -{ - switch ((PathTxRFE) path) - { - case PATH_RFE_TXRF1: - if (LMS_SetAntenna(device, LMS_CH_TX, chan, 1) < 0) - { - fprintf(stderr, "DeviceLimeSDR::setTxAntennaPath: cannot set to TXRF1\n"); - return false; - } - break; - case PATH_RFE_TXRF2: - if (LMS_SetAntenna(device, LMS_CH_TX, chan, 2) < 0) - { - fprintf(stderr, "DeviceLimeSDR::setTxAntennaPath: cannot set to TXRF2\n"); - return false; - } - break; - case PATH_RFE_TX_NONE: - default: - if (LMS_SetAntenna(device, LMS_CH_TX, chan, 0) < 0) - { - fprintf(stderr, "DeviceLimeSDR::setTxAntennaPath: cannot set to none\n"); - return false; - } - } - - return true; -} +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2017 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 // +// // +// This program is distributed in the hope that it will be useful, // +// but WITHOUT ANY WARRANTY; without even the implied warranty of // +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // +// GNU General Public License V3 for more details. // +// // +// You should have received a copy of the GNU General Public License // +// along with this program. If not, see . // +/////////////////////////////////////////////////////////////////////////////////// + +#include +#include +#include +#include "devicelimesdr.h" + +bool DeviceLimeSDR::setNCOFrequency(lms_device_t *device, bool dir_tx, std::size_t chan, bool enable, float frequency) +{ + if (enable) + { + bool positive; + float_type freqs[LMS_NCO_VAL_COUNT]; + float_type phos[LMS_NCO_VAL_COUNT]; + + if (LMS_GetNCOFrequency(device, dir_tx, chan, freqs, phos) < 0) + { + fprintf(stderr, "DeviceLimeSDR::setNCOFrequency: cannot get NCO frequencies and phases\n"); + } + + if (frequency < 0) + { + positive = false; + frequency = -frequency; + } + else + { + positive = true; + } + + freqs[0] = frequency; + + if (LMS_SetNCOFrequency(device, dir_tx, chan, freqs, 0.0f) < 0) + { + fprintf(stderr, "DeviceLimeSDR::setNCOFrequency: cannot set frequency to %f\n", frequency); + return false; + } + + if (LMS_SetNCOIndex(device, dir_tx, chan, 0, !positive) < 0) + { + fprintf(stderr, "DeviceLimeSDR::setNCOFrequency: cannot set conversion direction %sfreq\n", positive ? "+" : "-"); + return false; + } + + if (dir_tx) + { + if (LMS_WriteParam(device,LMS7param(CMIX_BYP_TXTSP),0) < 0) { + fprintf(stderr, "DeviceLimeSDR::setNCOFrequency: cannot enable Tx NCO\n"); + return false; + } + } + else + { + if (LMS_WriteParam(device,LMS7param(CMIX_BYP_RXTSP),0) < 0) { + fprintf(stderr, "DeviceLimeSDR::setNCOFrequency: cannot enable Rx NCO\n"); + return false; + } + } + + return true; + } + else + { + if (dir_tx) + { + if (LMS_WriteParam(device,LMS7param(CMIX_BYP_TXTSP),1) < 0) { + fprintf(stderr, "DeviceLimeSDR::setNCOFrequency: cannot disable Tx NCO\n"); + return false; + } + } + else + { + if (LMS_WriteParam(device,LMS7param(CMIX_BYP_RXTSP),1) < 0) { + fprintf(stderr, "DeviceLimeSDR::setNCOFrequency: cannot disable Rx NCO\n"); + return false; + } + } + + return true; + } +} + +bool DeviceLimeSDR::SetRFELNA_dB(lms_device_t *device, std::size_t chan, int value) +{ + if (LMS_WriteParam(device, LMS7param(MAC), chan+1) < 0) + { + fprintf(stderr, "DeviceLimeSDR::SetRFELNA_dB: cannot set channel to #%lu\n", chan); + return false; + } + + if (value > 30) { + value = 30; + } + + int val = value - 30; + + int g_lna_rfe = 0; + if (val >= 0) g_lna_rfe = 15; + else if (val >= -1) g_lna_rfe = 14; + else if (val >= -2) g_lna_rfe = 13; + else if (val >= -3) g_lna_rfe = 12; + else if (val >= -4) g_lna_rfe = 11; + else if (val >= -5) g_lna_rfe = 10; + else if (val >= -6) g_lna_rfe = 9; + else if (val >= -9) g_lna_rfe = 8; + else if (val >= -12) g_lna_rfe = 7; + else if (val >= -15) g_lna_rfe = 6; + else if (val >= -18) g_lna_rfe = 5; + else if (val >= -21) g_lna_rfe = 4; + else if (val >= -24) g_lna_rfe = 3; + else if (val >= -27) g_lna_rfe = 2; + else g_lna_rfe = 1; + + if (LMS_WriteParam(device, LMS7param(G_LNA_RFE), g_lna_rfe) < 0) + { + fprintf(stderr, "DeviceLimeSDR::SetRFELNA_dB: cannot set LNA gain to %d (%d)\n", value, g_lna_rfe); + return false; + } + + return true; +} + +bool DeviceLimeSDR::SetRFETIA_dB(lms_device_t *device, std::size_t chan, int value) +{ + if (LMS_WriteParam(device, LMS7param(MAC), chan+1) < 0) + { + fprintf(stderr, "DeviceLimeSDR::SetRFETIA_dB: cannot set channel to #%lu\n", chan); + return false; + } + + if (value > 3) { + value = 3; + } else if (value < 1) { + value = 1; + } + + int g_tia_rfe = value; + + if (LMS_WriteParam(device, LMS7param(G_TIA_RFE), g_tia_rfe) < 0) + { + fprintf(stderr, "DeviceLimeSDR::SetRFELNA_dB: cannot set TIA gain to %d (%d)\n", value, g_tia_rfe); + return false; + } + + return true; +} + +bool DeviceLimeSDR::SetRBBPGA_dB(lms_device_t *device, std::size_t chan, float value) +{ + if (LMS_WriteParam(device, LMS7param(MAC), chan+1) < 0) + { + fprintf(stderr, "DeviceLimeSDR::SetRBBPGA_dB: cannot set channel to #%lu\n", chan); + return false; + } + + int g_pga_rbb = (int)(value + 12.5); + if (g_pga_rbb > 0x1f) g_pga_rbb = 0x1f; + if (g_pga_rbb < 0) g_pga_rbb = 0; + + if (LMS_WriteParam(device, LMS7param(G_PGA_RBB), g_pga_rbb) < 0) + { + fprintf(stderr, "DeviceLimeSDR::SetRBBPGA_dB: cannot set G_PGA_RBB to %d\n", g_pga_rbb); + return false; + } + + int rcc_ctl_pga_rbb = (430.0*pow(0.65, (g_pga_rbb/10.0))-110.35)/20.4516 + 16; + + int c_ctl_pga_rbb = 0; + if (0 <= g_pga_rbb && g_pga_rbb < 8) c_ctl_pga_rbb = 3; + if (8 <= g_pga_rbb && g_pga_rbb < 13) c_ctl_pga_rbb = 2; + if (13 <= g_pga_rbb && g_pga_rbb < 21) c_ctl_pga_rbb = 1; + if (21 <= g_pga_rbb) c_ctl_pga_rbb = 0; + + if (LMS_WriteParam(device, LMS7param(RCC_CTL_PGA_RBB), rcc_ctl_pga_rbb) < 0) + { + fprintf(stderr, "DeviceLimeSDR::SetRBBPGA_dB: cannot set RCC_CTL_PGA_RBB to %d\n", rcc_ctl_pga_rbb); + return false; + } + + if (LMS_WriteParam(device, LMS7param(C_CTL_PGA_RBB), c_ctl_pga_rbb) < 0) + { + fprintf(stderr, "DeviceLimeSDR::SetRBBPGA_dB: cannot set C_CTL_PGA_RBB to %d\n", c_ctl_pga_rbb); + return false; + } + + return true; +} + +bool DeviceLimeSDR::setRxAntennaPath(lms_device_t *device, std::size_t chan, int path) +{ +// if (LMS_WriteParam(device, LMS7param(MAC), chan+1) < 0) +// { +// fprintf(stderr, "DeviceLimeSDR::setAntennaPath: cannot set channel to #%lu\n", chan); +// return false; +// } +// +// int sel_path_rfe = 0; +// switch ((PathRFE) path) +// { +// case PATH_RFE_NONE: sel_path_rfe = 0; break; +// case PATH_RFE_LNAH: sel_path_rfe = 1; break; +// case PATH_RFE_LNAL: sel_path_rfe = 2; break; +// case PATH_RFE_LNAW: sel_path_rfe = 3; break; +// case PATH_RFE_LB1: sel_path_rfe = 3; break; +// case PATH_RFE_LB2: sel_path_rfe = 2; break; +// } +// +// int pd_lna_rfe = 1; +// switch ((PathRFE) path) +// { +// case PATH_RFE_LNAH: +// case PATH_RFE_LNAL: +// case PATH_RFE_LNAW: pd_lna_rfe = 0; break; +// default: break; +// } +// +// int pd_rloopb_1_rfe = (path == (int) PATH_RFE_LB1) ? 0 : 1; +// int pd_rloopb_2_rfe = (path == (int) PATH_RFE_LB2) ? 0 : 1; +// int en_inshsw_l_rfe = (path == (int) PATH_RFE_LNAL ) ? 0 : 1; +// int en_inshsw_w_rfe = (path == (int) PATH_RFE_LNAW) ? 0 : 1; +// int en_inshsw_lb1_rfe = (path == (int) PATH_RFE_LB1) ? 0 : 1; +// int en_inshsw_lb2_rfe = (path == (int) PATH_RFE_LB2) ? 0 : 1; +// +// int ret = 0; +// +// ret += LMS_WriteParam(device, LMS7param(PD_LNA_RFE), pd_lna_rfe); +// ret += LMS_WriteParam(device, LMS7param(PD_RLOOPB_1_RFE), pd_rloopb_1_rfe); +// ret += LMS_WriteParam(device, LMS7param(PD_RLOOPB_2_RFE), pd_rloopb_2_rfe); +// ret += LMS_WriteParam(device, LMS7param(EN_INSHSW_LB1_RFE), en_inshsw_lb1_rfe); +// ret += LMS_WriteParam(device, LMS7param(EN_INSHSW_LB2_RFE), en_inshsw_lb2_rfe); +// ret += LMS_WriteParam(device, LMS7param(EN_INSHSW_L_RFE), en_inshsw_l_rfe); +// ret += LMS_WriteParam(device, LMS7param(EN_INSHSW_W_RFE), en_inshsw_w_rfe); +// ret += LMS_WriteParam(device, LMS7param(SEL_PATH_RFE), sel_path_rfe); +// +// if (ret < 0) +// { +// fprintf(stderr, "DeviceLimeSDR::setAntennaPath: cannot set channel #%lu to %d\n", chan, path); +// return false; +// } +// +// //enable/disable the loopback path +// const bool loopback = (path == (int) PATH_RFE_LB1) or (path == (int) PATH_RFE_LB2); +// +// if (LMS_WriteParam(device, LMS7param(EN_LOOPB_TXPAD_TRF), loopback ? 1 : 0) < 0) +// { +// fprintf(stderr, "DeviceLimeSDR::setAntennaPath: cannot %sset loopback on channel #%lu\n", loopback ? "" : "re", chan); +// return false; +// } +// +// //update external band-selection to match +// //this->UpdateExternalBandSelect(); +// +// return true; + + switch ((PathRxRFE) path) + { + case PATH_RFE_LNAH: + if (LMS_SetAntenna(device, LMS_CH_RX, chan, 1) < 0) + { + fprintf(stderr, "DeviceLimeSDR::setRxAntennaPath: cannot set to LNAH\n"); + return false; + } + break; + case PATH_RFE_LNAL: + if (LMS_SetAntenna(device, LMS_CH_RX, chan, 2) < 0) + { + fprintf(stderr, "DeviceLimeSDR::setRxAntennaPath: cannot set to LNAL\n"); + return false; + } + break; + case PATH_RFE_LNAW: + if (LMS_SetAntenna(device, LMS_CH_RX, chan, 3) < 0) + { + fprintf(stderr, "DeviceLimeSDR::setRxAntennaPath: cannot set to LNAW\n"); + return false; + } + break; + case PATH_RFE_LB1: + if (LMS_SetAntenna(device, LMS_CH_TX, chan, 1) < 0) + { + fprintf(stderr, "DeviceLimeSDR::setRxAntennaPath: cannot set to Loopback TX1\n"); + return false; + } + break; + case PATH_RFE_LB2: + if (LMS_SetAntenna(device, LMS_CH_TX, chan, 2) < 0) + { + fprintf(stderr, "DeviceLimeSDR::setRxAntennaPath: cannot set to Loopback TX2\n"); + return false; + } + break; + case PATH_RFE_RX_NONE: + default: + if (LMS_SetAntenna(device, LMS_CH_RX, chan, 0) < 0) + { + fprintf(stderr, "DeviceLimeSDR::setRxAntennaPath: cannot set to none\n"); + return false; + } + } + + return true; +} + +bool DeviceLimeSDR::setTxAntennaPath(lms_device_t *device, std::size_t chan, int path) +{ + switch ((PathTxRFE) path) + { + case PATH_RFE_TXRF1: + if (LMS_SetAntenna(device, LMS_CH_TX, chan, 1) < 0) + { + fprintf(stderr, "DeviceLimeSDR::setTxAntennaPath: cannot set to TXRF1\n"); + return false; + } + break; + case PATH_RFE_TXRF2: + if (LMS_SetAntenna(device, LMS_CH_TX, chan, 2) < 0) + { + fprintf(stderr, "DeviceLimeSDR::setTxAntennaPath: cannot set to TXRF2\n"); + return false; + } + break; + case PATH_RFE_TX_NONE: + default: + if (LMS_SetAntenna(device, LMS_CH_TX, chan, 0) < 0) + { + fprintf(stderr, "DeviceLimeSDR::setTxAntennaPath: cannot set to none\n"); + return false; + } + } + + return true; +} From 463abb637fadfb045162540510ea2bf9f4ba1a64 Mon Sep 17 00:00:00 2001 From: f4exb Date: Sat, 30 Sep 2017 19:05:16 +0200 Subject: [PATCH 40/71] LimeSDR input: code cleanup --- plugins/samplesource/limesdrinput/limesdrinput.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/plugins/samplesource/limesdrinput/limesdrinput.cpp b/plugins/samplesource/limesdrinput/limesdrinput.cpp index 73f7f55c9..723685305 100644 --- a/plugins/samplesource/limesdrinput/limesdrinput.cpp +++ b/plugins/samplesource/limesdrinput/limesdrinput.cpp @@ -269,6 +269,8 @@ void LimeSDRInput::closeDevice() return; } + if (m_running) { stop(); } + // destroy the stream LMS_DestroyStream(m_deviceShared.m_deviceParams->getDevice(), &m_streamId); m_streamId.handle = 0; @@ -298,7 +300,7 @@ bool LimeSDRInput::start() return false; } - if (m_running) stop(); + if (m_running) { stop(); } applySettings(m_settings, true); From d524378d8e8ba237c2ce27da19d203564188ab1a Mon Sep 17 00:00:00 2001 From: f4exb Date: Sat, 30 Sep 2017 20:07:08 +0200 Subject: [PATCH 41/71] LimeSDR: put the code to suspend buddies in one place --- .../limesdroutput/limesdroutput.cpp | 180 +++++++----------- .../samplesink/limesdroutput/limesdroutput.h | 6 +- .../limesdrinput/limesdrinput.cpp | 164 ++++++---------- .../samplesource/limesdrinput/limesdrinput.h | 6 +- 4 files changed, 133 insertions(+), 223 deletions(-) diff --git a/plugins/samplesink/limesdroutput/limesdroutput.cpp b/plugins/samplesink/limesdroutput/limesdroutput.cpp index 5208eab7d..20d0a605d 100644 --- a/plugins/samplesink/limesdroutput/limesdroutput.cpp +++ b/plugins/samplesink/limesdroutput/limesdroutput.cpp @@ -45,17 +45,21 @@ LimeSDROutput::LimeSDROutput(DeviceSinkAPI *deviceAPI) : m_channelAcquired(false) { m_streamId.handle = 0; - suspendBuddies(); + suspendRxBuddies(); + suspendTxBuddies(); openDevice(); - resumeBuddies(); + resumeTxBuddies(); + resumeRxBuddies(); } LimeSDROutput::~LimeSDROutput() { if (m_running) stop(); - suspendBuddies(); + suspendRxBuddies(); + suspendTxBuddies(); closeDevice(); - resumeBuddies(); + resumeTxBuddies(); + resumeRxBuddies(); } void LimeSDROutput::destroy() @@ -161,56 +165,74 @@ bool LimeSDROutput::openDevice() return true; } -void LimeSDROutput::suspendBuddies() +void LimeSDROutput::suspendRxBuddies() { - // suspend Tx buddy's threads + const std::vector& sourceBuddies = m_deviceAPI->getSourceBuddies(); + std::vector::const_iterator itSource = sourceBuddies.begin(); - for (unsigned int i = 0; i < m_deviceAPI->getSinkBuddies().size(); i++) + for (; itSource != sourceBuddies.end(); ++itSource) { - DeviceSinkAPI *buddy = m_deviceAPI->getSinkBuddies()[i]; - DeviceLimeSDRShared *buddyShared = (DeviceLimeSDRShared *) buddy->getBuddySharedPtr(); + DeviceLimeSDRShared *buddySharedPtr = (DeviceLimeSDRShared *) (*itSource)->getBuddySharedPtr(); - if (buddyShared->m_thread) { - buddyShared->m_thread->stopWork(); + if (buddySharedPtr->m_thread && buddySharedPtr->m_thread->isRunning()) + { + buddySharedPtr->m_thread->stopWork(); + buddySharedPtr->m_threadWasRunning = true; } - } - - // suspend Rx buddy's threads - - for (unsigned int i = 0; i < m_deviceAPI->getSourceBuddies().size(); i++) - { - DeviceSourceAPI *buddy = m_deviceAPI->getSourceBuddies()[i]; - DeviceLimeSDRShared *buddyShared = (DeviceLimeSDRShared *) buddy->getBuddySharedPtr(); - - if (buddyShared->m_thread) { - buddyShared->m_thread->stopWork(); + else + { + buddySharedPtr->m_threadWasRunning = false; } } } -void LimeSDROutput::resumeBuddies() +void LimeSDROutput::suspendTxBuddies() { - // resume Tx buddy's threads + const std::vector& sinkBuddies = m_deviceAPI->getSinkBuddies(); + std::vector::const_iterator itSink = sinkBuddies.begin(); - for (unsigned int i = 0; i < m_deviceAPI->getSinkBuddies().size(); i++) + for (; itSink != sinkBuddies.end(); ++itSink) { - DeviceSinkAPI *buddy = m_deviceAPI->getSinkBuddies()[i]; - DeviceLimeSDRShared *buddyShared = (DeviceLimeSDRShared *) buddy->getBuddySharedPtr(); + DeviceLimeSDRShared *buddySharedPtr = (DeviceLimeSDRShared *) (*itSink)->getBuddySharedPtr(); - if (buddyShared->m_thread) { - buddyShared->m_thread->startWork(); + if (buddySharedPtr->m_thread && buddySharedPtr->m_thread->isRunning()) + { + buddySharedPtr->m_thread->stopWork(); + buddySharedPtr->m_threadWasRunning = true; + } + else + { + buddySharedPtr->m_threadWasRunning = false; } } +} - // resume Rx buddy's threads +void LimeSDROutput::resumeRxBuddies() +{ + const std::vector& sourceBuddies = m_deviceAPI->getSourceBuddies(); + std::vector::const_iterator itSource = sourceBuddies.begin(); - for (unsigned int i = 0; i < m_deviceAPI->getSourceBuddies().size(); i++) + for (; itSource != sourceBuddies.end(); ++itSource) { - DeviceSourceAPI *buddy = m_deviceAPI->getSourceBuddies()[i]; - DeviceLimeSDRShared *buddyShared = (DeviceLimeSDRShared *) buddy->getBuddySharedPtr(); + DeviceLimeSDRShared *buddySharedPtr = (DeviceLimeSDRShared *) (*itSource)->getBuddySharedPtr(); - if (buddyShared->m_thread) { - buddyShared->m_thread->startWork(); + if (buddySharedPtr->m_threadWasRunning) { + buddySharedPtr->m_thread->startWork(); + } + } +} + +void LimeSDROutput::resumeTxBuddies() +{ + const std::vector& sinkBuddies = m_deviceAPI->getSinkBuddies(); + std::vector::const_iterator itSink = sinkBuddies.begin(); + + for (; itSink != sinkBuddies.end(); ++itSink) + { + DeviceLimeSDRShared *buddySharedPtr = (DeviceLimeSDRShared *) (*itSink)->getBuddySharedPtr(); + + if (buddySharedPtr->m_threadWasRunning) { + buddySharedPtr->m_thread->startWork(); } } } @@ -293,7 +315,7 @@ bool LimeSDROutput::start() return false; } - if (m_running) stop(); + if (m_running) { stop(); } if (!acquireChannel()) { @@ -573,41 +595,8 @@ bool LimeSDROutput::applySettings(const LimeSDROutputSettings& settings, bool fo if (suspendAllThread) { - const std::vector& sourceBuddies = m_deviceAPI->getSourceBuddies(); - std::vector::const_iterator itSource = sourceBuddies.begin(); - - for (; itSource != sourceBuddies.end(); ++itSource) - { - DeviceLimeSDRShared *buddySharedPtr = (DeviceLimeSDRShared *) (*itSource)->getBuddySharedPtr(); - - if (buddySharedPtr->m_thread && buddySharedPtr->m_thread->isRunning()) - { - buddySharedPtr->m_thread->stopWork(); - buddySharedPtr->m_threadWasRunning = true; - } - else - { - buddySharedPtr->m_threadWasRunning = false; - } - } - - const std::vector& sinkBuddies = m_deviceAPI->getSinkBuddies(); - std::vector::const_iterator itSink = sinkBuddies.begin(); - - for (; itSink != sinkBuddies.end(); ++itSink) - { - DeviceLimeSDRShared *buddySharedPtr = (DeviceLimeSDRShared *) (*itSink)->getBuddySharedPtr(); - - if (buddySharedPtr->m_thread && buddySharedPtr->m_thread->isRunning()) - { - buddySharedPtr->m_thread->stopWork(); - buddySharedPtr->m_threadWasRunning = true; - } - else - { - buddySharedPtr->m_threadWasRunning = false; - } - } + suspendRxBuddies(); + suspendTxBuddies(); if (m_limeSDROutputThread && m_limeSDROutputThread->isRunning()) { @@ -617,17 +606,7 @@ bool LimeSDROutput::applySettings(const LimeSDROutputSettings& settings, bool fo } else if (suspendTxThread) { - const std::vector& sinkBuddies = m_deviceAPI->getSinkBuddies(); - std::vector::const_iterator itSink = sinkBuddies.begin(); - - for (; itSink != sinkBuddies.end(); ++itSink) - { - DeviceLimeSDRShared *buddySharedPtr = (DeviceLimeSDRShared *) (*itSink)->getBuddySharedPtr(); - - if (buddySharedPtr->m_thread) { - buddySharedPtr->m_thread->stopWork(); - } - } + suspendTxBuddies(); if (m_limeSDROutputThread && m_limeSDROutputThread->isRunning()) { @@ -851,29 +830,8 @@ bool LimeSDROutput::applySettings(const LimeSDROutputSettings& settings, bool fo if (suspendAllThread) { - const std::vector& sourceBuddies = m_deviceAPI->getSourceBuddies(); - std::vector::const_iterator itSource = sourceBuddies.begin(); - - for (; itSource != sourceBuddies.end(); ++itSource) - { - DeviceLimeSDRShared *buddySharedPtr = (DeviceLimeSDRShared *) (*itSource)->getBuddySharedPtr(); - - if (buddySharedPtr->m_threadWasRunning) { - buddySharedPtr->m_thread->startWork(); - } - } - - const std::vector& sinkBuddies = m_deviceAPI->getSinkBuddies(); - std::vector::const_iterator itSink = sinkBuddies.begin(); - - for (; itSink != sinkBuddies.end(); ++itSink) - { - DeviceLimeSDRShared *buddySharedPtr = (DeviceLimeSDRShared *) (*itSink)->getBuddySharedPtr(); - - if (buddySharedPtr->m_threadWasRunning) { - buddySharedPtr->m_thread->startWork(); - } - } + resumeTxBuddies(); + resumeRxBuddies(); if (ownThreadWasRunning) { m_limeSDROutputThread->startWork(); @@ -881,17 +839,7 @@ bool LimeSDROutput::applySettings(const LimeSDROutputSettings& settings, bool fo } else if (suspendTxThread) { - const std::vector& sinkBuddies = m_deviceAPI->getSinkBuddies(); - std::vector::const_iterator itSink = sinkBuddies.begin(); - - for (; itSink != sinkBuddies.end(); ++itSink) - { - DeviceLimeSDRShared *buddySharedPtr = (DeviceLimeSDRShared *) (*itSink)->getBuddySharedPtr(); - - if (buddySharedPtr->m_threadWasRunning) { - buddySharedPtr->m_thread->startWork(); - } - } + resumeTxBuddies(); if (ownThreadWasRunning) { m_limeSDROutputThread->startWork(); diff --git a/plugins/samplesink/limesdroutput/limesdroutput.h b/plugins/samplesink/limesdroutput/limesdroutput.h index 9f2e9baca..8166e6b85 100644 --- a/plugins/samplesink/limesdroutput/limesdroutput.h +++ b/plugins/samplesink/limesdroutput/limesdroutput.h @@ -224,8 +224,10 @@ private: void closeDevice(); bool acquireChannel(); void releaseChannel(); - void suspendBuddies(); - void resumeBuddies(); + void suspendRxBuddies(); + void resumeRxBuddies(); + void suspendTxBuddies(); + void resumeTxBuddies(); bool applySettings(const LimeSDROutputSettings& settings, bool force = false); }; diff --git a/plugins/samplesource/limesdrinput/limesdrinput.cpp b/plugins/samplesource/limesdrinput/limesdrinput.cpp index 723685305..6620dc3d5 100644 --- a/plugins/samplesource/limesdrinput/limesdrinput.cpp +++ b/plugins/samplesource/limesdrinput/limesdrinput.cpp @@ -46,9 +46,11 @@ LimeSDRInput::LimeSDRInput(DeviceSourceAPI *deviceAPI) : m_firstConfig(true) { m_streamId.handle = 0; - suspendBuddies(); + suspendRxBuddies(); + suspendTxBuddies(); openDevice(); - resumeBuddies(); + resumeTxBuddies(); + resumeRxBuddies(); char recFileNameCStr[30]; sprintf(recFileNameCStr, "test_%d.sdriq", m_deviceAPI->getDeviceUID()); @@ -61,9 +63,11 @@ LimeSDRInput::~LimeSDRInput() if (m_running) stop(); m_deviceAPI->removeSink(m_fileSink); delete m_fileSink; - suspendBuddies(); + suspendRxBuddies(); + suspendTxBuddies(); closeDevice(); - resumeBuddies(); + resumeTxBuddies(); + resumeRxBuddies(); } void LimeSDRInput::destroy() @@ -209,56 +213,73 @@ bool LimeSDRInput::openDevice() return true; } -void LimeSDRInput::suspendBuddies() +void LimeSDRInput::suspendRxBuddies() { - // suspend Rx buddy's threads + const std::vector& sourceBuddies = m_deviceAPI->getSourceBuddies(); + std::vector::const_iterator itSource = sourceBuddies.begin(); - for (unsigned int i = 0; i < m_deviceAPI->getSourceBuddies().size(); i++) + for (; itSource != sourceBuddies.end(); ++itSource) { - DeviceSourceAPI *buddy = m_deviceAPI->getSourceBuddies()[i]; - DeviceLimeSDRShared *buddyShared = (DeviceLimeSDRShared *) buddy->getBuddySharedPtr(); + DeviceLimeSDRShared *buddySharedPtr = (DeviceLimeSDRShared *) (*itSource)->getBuddySharedPtr(); - if (buddyShared->m_thread) { - buddyShared->m_thread->stopWork(); + if (buddySharedPtr->m_thread && buddySharedPtr->m_thread->isRunning()) + { + buddySharedPtr->m_thread->stopWork(); + buddySharedPtr->m_threadWasRunning = true; } - } - - // suspend Tx buddy's threads - - for (unsigned int i = 0; i < m_deviceAPI->getSinkBuddies().size(); i++) - { - DeviceSinkAPI *buddy = m_deviceAPI->getSinkBuddies()[i]; - DeviceLimeSDRShared *buddyShared = (DeviceLimeSDRShared *) buddy->getBuddySharedPtr(); - - if (buddyShared->m_thread) { - buddyShared->m_thread->stopWork(); + else + { + buddySharedPtr->m_threadWasRunning = false; } } } -void LimeSDRInput::resumeBuddies() +void LimeSDRInput::suspendTxBuddies() { - // resume Rx buddy's threads + const std::vector& sinkBuddies = m_deviceAPI->getSinkBuddies(); + std::vector::const_iterator itSink = sinkBuddies.begin(); - for (unsigned int i = 0; i < m_deviceAPI->getSourceBuddies().size(); i++) + for (; itSink != sinkBuddies.end(); ++itSink) { - DeviceSourceAPI *buddy = m_deviceAPI->getSourceBuddies()[i]; - DeviceLimeSDRShared *buddyShared = (DeviceLimeSDRShared *) buddy->getBuddySharedPtr(); + DeviceLimeSDRShared *buddySharedPtr = (DeviceLimeSDRShared *) (*itSink)->getBuddySharedPtr(); - if (buddyShared->m_thread) { - buddyShared->m_thread->startWork(); + if (buddySharedPtr->m_thread) { + buddySharedPtr->m_thread->stopWork(); + buddySharedPtr->m_threadWasRunning = true; + } + else + { + buddySharedPtr->m_threadWasRunning = false; } } +} - // resume Tx buddy's threads +void LimeSDRInput::resumeRxBuddies() +{ + const std::vector& sourceBuddies = m_deviceAPI->getSourceBuddies(); + std::vector::const_iterator itSource = sourceBuddies.begin(); - for (unsigned int i = 0; i < m_deviceAPI->getSinkBuddies().size(); i++) + for (; itSource != sourceBuddies.end(); ++itSource) { - DeviceSinkAPI *buddy = m_deviceAPI->getSinkBuddies()[i]; - DeviceLimeSDRShared *buddyShared = (DeviceLimeSDRShared *) buddy->getBuddySharedPtr(); + DeviceLimeSDRShared *buddySharedPtr = (DeviceLimeSDRShared *) (*itSource)->getBuddySharedPtr(); - if (buddyShared->m_thread) { - buddyShared->m_thread->startWork(); + if (buddySharedPtr->m_threadWasRunning) { + buddySharedPtr->m_thread->startWork(); + } + } +} + +void LimeSDRInput::resumeTxBuddies() +{ + const std::vector& sinkBuddies = m_deviceAPI->getSinkBuddies(); + std::vector::const_iterator itSink = sinkBuddies.begin(); + + for (; itSink != sinkBuddies.end(); ++itSink) + { + DeviceLimeSDRShared *buddySharedPtr = (DeviceLimeSDRShared *) (*itSink)->getBuddySharedPtr(); + + if (buddySharedPtr->m_threadWasRunning) { + buddySharedPtr->m_thread->startWork(); } } } @@ -593,40 +614,8 @@ bool LimeSDRInput::applySettings(const LimeSDRInputSettings& settings, bool forc if (suspendAllThread) { - const std::vector& sourceBuddies = m_deviceAPI->getSourceBuddies(); - std::vector::const_iterator itSource = sourceBuddies.begin(); - - for (; itSource != sourceBuddies.end(); ++itSource) - { - DeviceLimeSDRShared *buddySharedPtr = (DeviceLimeSDRShared *) (*itSource)->getBuddySharedPtr(); - - if (buddySharedPtr->m_thread && buddySharedPtr->m_thread->isRunning()) - { - buddySharedPtr->m_thread->stopWork(); - buddySharedPtr->m_threadWasRunning = true; - } - else - { - buddySharedPtr->m_threadWasRunning = false; - } - } - - const std::vector& sinkBuddies = m_deviceAPI->getSinkBuddies(); - std::vector::const_iterator itSink = sinkBuddies.begin(); - - for (; itSink != sinkBuddies.end(); ++itSink) - { - DeviceLimeSDRShared *buddySharedPtr = (DeviceLimeSDRShared *) (*itSink)->getBuddySharedPtr(); - - if (buddySharedPtr->m_thread) { - buddySharedPtr->m_thread->stopWork(); - buddySharedPtr->m_threadWasRunning = true; - } - else - { - buddySharedPtr->m_threadWasRunning = false; - } - } + suspendRxBuddies(); + suspendTxBuddies(); if (m_limeSDRInputThread && m_limeSDRInputThread->isRunning()) { @@ -636,17 +625,7 @@ bool LimeSDRInput::applySettings(const LimeSDRInputSettings& settings, bool forc } else if (suspendRxThread) { - const std::vector& sourceBuddies = m_deviceAPI->getSourceBuddies(); - std::vector::const_iterator itSource = sourceBuddies.begin(); - - for (; itSource != sourceBuddies.end(); ++itSource) - { - DeviceLimeSDRShared *buddySharedPtr = (DeviceLimeSDRShared *) (*itSource)->getBuddySharedPtr(); - - if (buddySharedPtr->m_thread) { - buddySharedPtr->m_thread->stopWork(); - } - } + suspendRxBuddies(); if (m_limeSDRInputThread && m_limeSDRInputThread->isRunning()) { @@ -1015,29 +994,8 @@ bool LimeSDRInput::applySettings(const LimeSDRInputSettings& settings, bool forc if (suspendAllThread) { - const std::vector& sourceBuddies = m_deviceAPI->getSourceBuddies(); - std::vector::const_iterator itSource = sourceBuddies.begin(); - - for (; itSource != sourceBuddies.end(); ++itSource) - { - DeviceLimeSDRShared *buddySharedPtr = (DeviceLimeSDRShared *) (*itSource)->getBuddySharedPtr(); - - if (buddySharedPtr->m_threadWasRunning) { - buddySharedPtr->m_thread->startWork(); - } - } - - const std::vector& sinkBuddies = m_deviceAPI->getSinkBuddies(); - std::vector::const_iterator itSink = sinkBuddies.begin(); - - for (; itSink != sinkBuddies.end(); ++itSink) - { - DeviceLimeSDRShared *buddySharedPtr = (DeviceLimeSDRShared *) (*itSink)->getBuddySharedPtr(); - - if (buddySharedPtr->m_threadWasRunning) { - buddySharedPtr->m_thread->startWork(); - } - } + resumeTxBuddies(); + resumeRxBuddies(); if (ownThreadWasRunning) { m_limeSDRInputThread->startWork(); diff --git a/plugins/samplesource/limesdrinput/limesdrinput.h b/plugins/samplesource/limesdrinput/limesdrinput.h index 1b0b96143..1411b1ada 100644 --- a/plugins/samplesource/limesdrinput/limesdrinput.h +++ b/plugins/samplesource/limesdrinput/limesdrinput.h @@ -241,8 +241,10 @@ private: bool openDevice(); void closeDevice(); - void suspendBuddies(); - void resumeBuddies(); + void suspendRxBuddies(); + void resumeRxBuddies(); + void suspendTxBuddies(); + void resumeTxBuddies(); bool applySettings(const LimeSDRInputSettings& settings, bool force = false); }; From dcfdffaf4929a11110c185f5b5ad81931ec9ddc6 Mon Sep 17 00:00:00 2001 From: f4exb Date: Sat, 30 Sep 2017 20:25:20 +0200 Subject: [PATCH 42/71] LimeSDR output: suspend/resume buddies threads before/after start/stop --- plugins/samplesink/limesdroutput/limesdroutput.cpp | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/plugins/samplesink/limesdroutput/limesdroutput.cpp b/plugins/samplesink/limesdroutput/limesdroutput.cpp index 20d0a605d..39eabcf5d 100644 --- a/plugins/samplesink/limesdroutput/limesdroutput.cpp +++ b/plugins/samplesink/limesdroutput/limesdroutput.cpp @@ -259,6 +259,9 @@ void LimeSDROutput::closeDevice() bool LimeSDROutput::acquireChannel() { + suspendRxBuddies(); + suspendTxBuddies(); + // acquire the channel if (LMS_EnableChannel(m_deviceShared.m_deviceParams->getDevice(), LMS_CH_TX, m_deviceShared.m_channel, true) != 0) @@ -282,6 +285,8 @@ bool LimeSDROutput::acquireChannel() if (LMS_SetupStream(m_deviceShared.m_deviceParams->getDevice(), &m_streamId) != 0) { qCritical("LimeSDROutput::acquireChannel: cannot setup the stream on Tx channel %d", m_deviceShared.m_channel); + resumeTxBuddies(); + resumeRxBuddies(); return false; } else @@ -290,11 +295,17 @@ bool LimeSDROutput::acquireChannel() } m_channelAcquired = true; + resumeTxBuddies(); + resumeRxBuddies(); + return true; } void LimeSDROutput::releaseChannel() { + suspendRxBuddies(); + suspendTxBuddies(); + // destroy the stream LMS_DestroyStream(m_deviceShared.m_deviceParams->getDevice(), &m_streamId); m_streamId.handle = 0; @@ -307,6 +318,8 @@ void LimeSDROutput::releaseChannel() } m_channelAcquired = false; + resumeTxBuddies(); + resumeRxBuddies(); } bool LimeSDROutput::start() From 35c5d623fdea5111ea807c52e46e12ee93826c8c Mon Sep 17 00:00:00 2001 From: f4exb Date: Sun, 1 Oct 2017 09:06:55 +0200 Subject: [PATCH 43/71] ATV Demod: renaming of some attributes --- plugins/channelrx/demodatv/atvdemod.cpp | 202 ++++++++++----------- plugins/channelrx/demodatv/atvdemod.h | 56 +++--- plugins/channelrx/demodatv/atvdemodgui.cpp | 134 +++++++------- plugins/channelrx/demodatv/atvdemodgui.h | 14 +- 4 files changed, 203 insertions(+), 203 deletions(-) diff --git a/plugins/channelrx/demodatv/atvdemod.cpp b/plugins/channelrx/demodatv/atvdemod.cpp index a2e38a0a2..9379f1853 100644 --- a/plugins/channelrx/demodatv/atvdemod.cpp +++ b/plugins/channelrx/demodatv/atvdemod.cpp @@ -70,7 +70,7 @@ ATVDemod::ATVDemod(BasebandSampleSink* objScopeSink) : m_objMagSqAverage.resize(32, 1.0); - m_DSBFilter = new fftfilt((2.0f * m_objRFConfig.m_fltRFBandwidth) / 1000000, 2 * m_ssbFftLen); // arbitrary 1 MS/s sample rate + m_DSBFilter = new fftfilt((2.0f * m_rfConfig.m_fltRFBandwidth) / 1000000, 2 * m_ssbFftLen); // arbitrary 1 MS/s sample rate m_DSBFilterBuffer = new Complex[m_ssbFftLen]; memset(m_DSBFilterBuffer, 0, sizeof(Complex)*(m_ssbFftLen)); @@ -188,12 +188,12 @@ void ATVDemod::feed(const SampleVector::const_iterator& begin, const SampleVecto #endif Complex c(fltI, fltQ); - if (m_objRFRunning.m_intFrequencyOffset != 0) + if (m_rfRunning.m_intFrequencyOffset != 0) { c *= m_nco.nextIQ(); } - if (m_objRFRunning.m_blndecimatorEnable) + if (m_rfRunning.m_blndecimatorEnable) { if (m_interpolator.decimate(&m_interpolatorDistanceRemain, c, &ci)) { @@ -207,7 +207,7 @@ void ATVDemod::feed(const SampleVector::const_iterator& begin, const SampleVecto } } - if ((m_objRunning.m_intVideoTabIndex == 1) && (m_objScopeSink != 0)) // do only if scope tab is selected and scope is available + if ((m_running.m_intVideoTabIndex == 1) && (m_objScopeSink != 0)) // do only if scope tab is selected and scope is available { m_objScopeSink->feed(m_objScopeSampleBuffer.begin(), m_objScopeSampleBuffer.end(), false); // m_ssb = positive only m_objScopeSampleBuffer.clear(); @@ -223,7 +223,7 @@ void ATVDemod::feed(const SampleVector::const_iterator& begin, const SampleVecto void ATVDemod::demod(Complex& c) { - float fltDivSynchroBlack = 1.0f - m_objRunning.m_fltVoltLevelSynchroBlack; + float fltDivSynchroBlack = 1.0f - m_running.m_fltVoltLevelSynchroBlack; float fltNormI; float fltNormQ; float fltNorm; @@ -232,12 +232,12 @@ void ATVDemod::demod(Complex& c) //********** FFT filtering ********** - if (m_objRFRunning.m_blnFFTFiltering) + if (m_rfRunning.m_blnFFTFiltering) { int n_out; fftfilt::cmplx *filtered; - n_out = m_DSBFilter->runAsym(c, &filtered, m_objRFRunning.m_enmModulation != ATV_LSB); // all usb except explicitely lsb + n_out = m_DSBFilter->runAsym(c, &filtered, m_rfRunning.m_enmModulation != ATV_LSB); // all usb except explicitely lsb if (n_out > 0) { @@ -250,11 +250,11 @@ void ATVDemod::demod(Complex& c) //********** demodulation ********** - const float& fltI = m_objRFRunning.m_blnFFTFiltering ? m_DSBFilterBuffer[m_DSBFilterBufferIndex-1].real() : c.real(); - const float& fltQ = m_objRFRunning.m_blnFFTFiltering ? m_DSBFilterBuffer[m_DSBFilterBufferIndex-1].imag() : c.imag(); + const float& fltI = m_rfRunning.m_blnFFTFiltering ? m_DSBFilterBuffer[m_DSBFilterBufferIndex-1].real() : c.real(); + const float& fltQ = m_rfRunning.m_blnFFTFiltering ? m_DSBFilterBuffer[m_DSBFilterBufferIndex-1].imag() : c.imag(); double magSq; - if ((m_objRFRunning.m_enmModulation == ATV_FM1) || (m_objRFRunning.m_enmModulation == ATV_FM2)) + if ((m_rfRunning.m_enmModulation == ATV_FM1) || (m_rfRunning.m_enmModulation == ATV_FM2)) { //Amplitude FM magSq = fltI*fltI + fltQ*fltQ; @@ -266,7 +266,7 @@ void ATVDemod::demod(Complex& c) //-2 > 2 : 0 -> 1 volt //0->0.3 synchro 0.3->1 image - if (m_objRFRunning.m_enmModulation == ATV_FM1) + if (m_rfRunning.m_enmModulation == ATV_FM1) { //YDiff Cd fltVal = m_fltBufferI[0]*(fltNormQ - m_fltBufferQ[1]); @@ -304,12 +304,12 @@ void ATVDemod::demod(Complex& c) m_fltBufferI[0]=fltNormI; m_fltBufferQ[0]=fltNormQ; - if (m_objRFRunning.m_fmDeviation != 1.0f) + if (m_rfRunning.m_fmDeviation != 1.0f) { - fltVal = ((fltVal - 0.5f) / m_objRFRunning.m_fmDeviation) + 0.5f; + fltVal = ((fltVal - 0.5f) / m_rfRunning.m_fmDeviation) + 0.5f; } } - else if (m_objRFRunning.m_enmModulation == ATV_AM) + else if (m_rfRunning.m_enmModulation == ATV_AM) { //Amplitude AM magSq = fltI*fltI + fltQ*fltQ; @@ -334,7 +334,7 @@ void ATVDemod::demod(Complex& c) fltVal -= m_fltAmpMin; fltVal /=m_fltAmpDelta; } - else if ((m_objRFRunning.m_enmModulation == ATV_USB) || (m_objRFRunning.m_enmModulation == ATV_LSB)) + else if ((m_rfRunning.m_enmModulation == ATV_USB) || (m_rfRunning.m_enmModulation == ATV_LSB)) { magSq = fltI*fltI + fltQ*fltQ; m_objMagSqAverage.feed(magSq); @@ -349,7 +349,7 @@ void ATVDemod::demod(Complex& c) float mixI = fltI * bfoValues[0] - fltQ * bfoValues[1]; float mixQ = fltI * bfoValues[1] + fltQ * bfoValues[0]; - if (m_objRFRunning.m_enmModulation == ATV_USB) { + if (m_rfRunning.m_enmModulation == ATV_USB) { fltVal = (mixI + mixQ); } else { fltVal = (mixI - mixQ); @@ -371,7 +371,7 @@ void ATVDemod::demod(Complex& c) fltVal -= m_fltAmpMin; fltVal /=m_fltAmpDelta; } - else if (m_objRFRunning.m_enmModulation == ATV_FM3) + else if (m_rfRunning.m_enmModulation == ATV_FM3) { float rawDeviation; fltVal = m_objPhaseDiscri.phaseDiscriminatorDelta(c, magSq, rawDeviation) + 0.5f; @@ -387,10 +387,10 @@ void ATVDemod::demod(Complex& c) fltVal = 0.0f; } - fltVal = m_objRunning.m_blnInvertVideo ? 1.0f - fltVal : fltVal; + fltVal = m_running.m_blnInvertVideo ? 1.0f - fltVal : fltVal; fltVal = (fltVal < -1.0f) ? -1.0f : (fltVal > 1.0f) ? 1.0f : fltVal; - if ((m_objRunning.m_intVideoTabIndex == 1) && (m_objScopeSink != 0)) { // feed scope buffer only if scope is present and visible + if ((m_running.m_intVideoTabIndex == 1) && (m_objScopeSink != 0)) { // feed scope buffer only if scope is present and visible m_objScopeSampleBuffer.push_back(Sample(fltVal*32767.0f, 0.0f)); } @@ -398,7 +398,7 @@ void ATVDemod::demod(Complex& c) //********** gray level ********** //-0.3 -> 0.7 - intVal = (int) 255.0*(fltVal - m_objRunning.m_fltVoltLevelSynchroBlack) / fltDivSynchroBlack; + intVal = (int) 255.0*(fltVal - m_running.m_fltVoltLevelSynchroBlack) / fltDivSynchroBlack; //0 -> 255 if(intVal<0) @@ -412,7 +412,7 @@ void ATVDemod::demod(Complex& c) //********** process video sample ********** - if (m_objRunning.m_enmATVStandard == ATVStdHSkip) + if (m_running.m_enmATVStandard == ATVStdHSkip) { processHSkip(fltVal, intVal); } @@ -438,12 +438,12 @@ bool ATVDemod::handleMessage(const Message& cmd) if (DownChannelizer::MsgChannelizerNotification::match(cmd)) { DownChannelizer::MsgChannelizerNotification& objNotif = (DownChannelizer::MsgChannelizerNotification&) cmd; - m_objConfig.m_intSampleRate = objNotif.getSampleRate(); - m_objRFConfig.m_intFrequencyOffset = objNotif.getFrequencyOffset(); + m_config.m_intSampleRate = objNotif.getSampleRate(); + m_rfConfig.m_intFrequencyOffset = objNotif.getFrequencyOffset(); qDebug() << "ATVDemod::handleMessage: MsgChannelizerNotification:" - << " m_intSampleRate: " << m_objConfig.m_intSampleRate - << " m_intFrequencyOffset: " << m_objRFConfig.m_intFrequencyOffset; + << " m_intSampleRate: " << m_config.m_intSampleRate + << " m_intFrequencyOffset: " << m_rfConfig.m_intFrequencyOffset; applySettings(); @@ -453,17 +453,17 @@ bool ATVDemod::handleMessage(const Message& cmd) { MsgConfigureATVDemod& objCfg = (MsgConfigureATVDemod&) cmd; - m_objConfig = objCfg.m_objMsgConfig; + m_config = objCfg.m_objMsgConfig; qDebug() << "ATVDemod::handleMessage: MsgConfigureATVDemod:" - << " m_fltVoltLevelSynchroBlack:" << m_objConfig.m_fltVoltLevelSynchroBlack - << " m_fltVoltLevelSynchroTop:" << m_objConfig.m_fltVoltLevelSynchroTop - << " m_fltFramePerS:" << m_objConfig.m_fltFramePerS - << " m_fltLineDurationUs:" << m_objConfig.m_fltLineDuration - << " m_fltRatioOfRowsToDisplay:" << m_objConfig.m_fltRatioOfRowsToDisplay - << " m_fltTopDurationUs:" << m_objConfig.m_fltTopDuration - << " m_blnHSync:" << m_objConfig.m_blnHSync - << " m_blnVSync:" << m_objConfig.m_blnVSync; + << " m_fltVoltLevelSynchroBlack:" << m_config.m_fltVoltLevelSynchroBlack + << " m_fltVoltLevelSynchroTop:" << m_config.m_fltVoltLevelSynchroTop + << " m_fltFramePerS:" << m_config.m_fltFramePerS + << " m_fltLineDurationUs:" << m_config.m_fltLineDuration + << " m_fltRatioOfRowsToDisplay:" << m_config.m_fltRatioOfRowsToDisplay + << " m_fltTopDurationUs:" << m_config.m_fltTopDuration + << " m_blnHSync:" << m_config.m_blnHSync + << " m_blnVSync:" << m_config.m_blnVSync; applySettings(); @@ -473,16 +473,16 @@ bool ATVDemod::handleMessage(const Message& cmd) { MsgConfigureRFATVDemod& objCfg = (MsgConfigureRFATVDemod&) cmd; - m_objRFConfig = objCfg.m_objMsgConfig; + m_rfConfig = objCfg.m_objMsgConfig; qDebug() << "ATVDemod::handleMessage: MsgConfigureRFATVDemod:" - << " m_enmModulation:" << m_objRFConfig.m_enmModulation - << " m_fltRFBandwidth:" << m_objRFConfig.m_fltRFBandwidth - << " m_fltRFOppBandwidth:" << m_objRFConfig.m_fltRFOppBandwidth - << " m_blnFFTFiltering:" << m_objRFConfig.m_blnFFTFiltering - << " m_blnDecimatorEnable:" << m_objRFConfig.m_blndecimatorEnable - << " m_fltBFOFrequency:" << m_objRFConfig.m_fltBFOFrequency - << " m_fmDeviation:" << m_objRFConfig.m_fmDeviation; + << " m_enmModulation:" << m_rfConfig.m_enmModulation + << " m_fltRFBandwidth:" << m_rfConfig.m_fltRFBandwidth + << " m_fltRFOppBandwidth:" << m_rfConfig.m_fltRFOppBandwidth + << " m_blnFFTFiltering:" << m_rfConfig.m_blnFFTFiltering + << " m_blnDecimatorEnable:" << m_rfConfig.m_blndecimatorEnable + << " m_fltBFOFrequency:" << m_rfConfig.m_fltBFOFrequency + << " m_fmDeviation:" << m_rfConfig.m_fmDeviation; applySettings(); @@ -504,30 +504,30 @@ bool ATVDemod::handleMessage(const Message& cmd) void ATVDemod::applySettings() { - if (m_objConfig.m_intSampleRate == 0) + if (m_config.m_intSampleRate == 0) { return; } bool forwardSampleRateChange = false; - if((m_objRFConfig.m_intFrequencyOffset != m_objRFRunning.m_intFrequencyOffset) - || (m_objRFConfig.m_enmModulation != m_objRFRunning.m_enmModulation) - || (m_objConfig.m_intSampleRate != m_objRunning.m_intSampleRate)) + if((m_rfConfig.m_intFrequencyOffset != m_rfRunning.m_intFrequencyOffset) + || (m_rfConfig.m_enmModulation != m_rfRunning.m_enmModulation) + || (m_config.m_intSampleRate != m_running.m_intSampleRate)) { - m_nco.setFreq(-m_objRFConfig.m_intFrequencyOffset, m_objConfig.m_intSampleRate); + m_nco.setFreq(-m_rfConfig.m_intFrequencyOffset, m_config.m_intSampleRate); } - if ((m_objConfig.m_intSampleRate != m_objRunning.m_intSampleRate) - || (m_objRFConfig.m_fltRFBandwidth != m_objRFRunning.m_fltRFBandwidth) - || (m_objConfig.m_fltFramePerS != m_objRunning.m_fltFramePerS) - || (m_objConfig.m_intNumberOfLines != m_objRunning.m_intNumberOfLines)) + if ((m_config.m_intSampleRate != m_running.m_intSampleRate) + || (m_rfConfig.m_fltRFBandwidth != m_rfRunning.m_fltRFBandwidth) + || (m_config.m_fltFramePerS != m_running.m_fltFramePerS) + || (m_config.m_intNumberOfLines != m_running.m_intNumberOfLines)) { m_objSettingsMutex.lock(); - int linesPerSecond = m_objConfig.m_intNumberOfLines * m_objConfig.m_fltFramePerS; + int linesPerSecond = m_config.m_intNumberOfLines * m_config.m_fltFramePerS; - int maxPoints = m_objConfig.m_intSampleRate / linesPerSecond; + int maxPoints = m_config.m_intSampleRate / linesPerSecond; int i = maxPoints; for (; i > 0; i--) @@ -537,53 +537,53 @@ void ATVDemod::applySettings() } int nbPointsPerRateUnit = i == 0 ? maxPoints : i; - m_objConfigPrivate.m_intTVSampleRate = nbPointsPerRateUnit * linesPerSecond; + m_configPrivate.m_intTVSampleRate = nbPointsPerRateUnit * linesPerSecond; - if (m_objConfigPrivate.m_intTVSampleRate > 0) + if (m_configPrivate.m_intTVSampleRate > 0) { - m_interpolatorDistance = (Real) m_objConfigPrivate.m_intTVSampleRate / (Real) m_objConfig.m_intSampleRate; + m_interpolatorDistance = (Real) m_configPrivate.m_intTVSampleRate / (Real) m_config.m_intSampleRate; } else { - m_objConfigPrivate.m_intTVSampleRate = m_objConfig.m_intSampleRate; + m_configPrivate.m_intTVSampleRate = m_config.m_intSampleRate; m_interpolatorDistance = 1.0f; } m_interpolatorDistanceRemain = 0; m_interpolator.create(24, - m_objConfigPrivate.m_intTVSampleRate, - m_objRFConfig.m_fltRFBandwidth / getRFBandwidthDivisor(m_objRFConfig.m_enmModulation), + m_configPrivate.m_intTVSampleRate, + m_rfConfig.m_fltRFBandwidth / getRFBandwidthDivisor(m_rfConfig.m_enmModulation), 3.0); m_objSettingsMutex.unlock(); } - if((m_objConfig.m_fltFramePerS != m_objRunning.m_fltFramePerS) - || (m_objConfig.m_fltLineDuration != m_objRunning.m_fltLineDuration) - || (m_objConfig.m_intSampleRate != m_objRunning.m_intSampleRate) - || (m_objConfig.m_fltTopDuration != m_objRunning.m_fltTopDuration) - || (m_objConfig.m_fltRatioOfRowsToDisplay != m_objRunning.m_fltRatioOfRowsToDisplay) - || (m_objConfig.m_enmATVStandard != m_objRunning.m_enmATVStandard) - || (m_objConfig.m_intNumberOfLines != m_objRunning.m_intNumberOfLines)) + if((m_config.m_fltFramePerS != m_running.m_fltFramePerS) + || (m_config.m_fltLineDuration != m_running.m_fltLineDuration) + || (m_config.m_intSampleRate != m_running.m_intSampleRate) + || (m_config.m_fltTopDuration != m_running.m_fltTopDuration) + || (m_config.m_fltRatioOfRowsToDisplay != m_running.m_fltRatioOfRowsToDisplay) + || (m_config.m_enmATVStandard != m_running.m_enmATVStandard) + || (m_config.m_intNumberOfLines != m_running.m_intNumberOfLines)) { m_objSettingsMutex.lock(); - m_intNumberOfLines = m_objConfig.m_intNumberOfLines; + m_intNumberOfLines = m_config.m_intNumberOfLines; applyStandard(); - m_objConfigPrivate.m_intNumberSamplePerLine = (int) (m_objConfig.m_fltLineDuration * m_objConfig.m_intSampleRate); - m_intNumberSamplePerTop = (int) (m_objConfig.m_fltTopDuration * m_objConfig.m_intSampleRate); + m_configPrivate.m_intNumberSamplePerLine = (int) (m_config.m_fltLineDuration * m_config.m_intSampleRate); + m_intNumberSamplePerTop = (int) (m_config.m_fltTopDuration * m_config.m_intSampleRate); - m_objRegisteredATVScreen->setRenderImmediate(!(m_objConfig.m_fltFramePerS > 25.0f)); + m_objRegisteredATVScreen->setRenderImmediate(!(m_config.m_fltFramePerS > 25.0f)); m_objRegisteredATVScreen->resizeATVScreen( - m_objConfigPrivate.m_intNumberSamplePerLine - m_intNumberSamplePerLineSignals, + m_configPrivate.m_intNumberSamplePerLine - m_intNumberSamplePerLineSignals, m_intNumberOfLines - m_intNumberOfBlackLines); qDebug() << "ATVDemod::applySettings:" - << " m_fltLineDuration: " << m_objConfig.m_fltLineDuration - << " m_fltFramePerS: " << m_objConfig.m_fltFramePerS + << " m_fltLineDuration: " << m_config.m_fltLineDuration + << " m_fltFramePerS: " << m_config.m_fltFramePerS << " m_intNumberOfLines: " << m_intNumberOfLines - << " m_intNumberSamplePerLine: " << m_objConfigPrivate.m_intNumberSamplePerLine + << " m_intNumberSamplePerLine: " << m_configPrivate.m_intNumberSamplePerLine << " m_intNumberOfBlackLines: " << m_intNumberOfBlackLines; m_intImageIndex = 0; @@ -593,56 +593,56 @@ void ATVDemod::applySettings() m_objSettingsMutex.unlock(); } - if ((m_objConfigPrivate.m_intTVSampleRate != m_objRunningPrivate.m_intTVSampleRate) - || (m_objConfigPrivate.m_intNumberSamplePerLine != m_objRunningPrivate.m_intNumberSamplePerLine) - || (m_objConfig.m_intSampleRate != m_objRunning.m_intSampleRate) - || (m_objRFConfig.m_blndecimatorEnable != m_objRFRunning.m_blndecimatorEnable)) + if ((m_configPrivate.m_intTVSampleRate != m_runningPrivate.m_intTVSampleRate) + || (m_configPrivate.m_intNumberSamplePerLine != m_runningPrivate.m_intNumberSamplePerLine) + || (m_config.m_intSampleRate != m_running.m_intSampleRate) + || (m_rfConfig.m_blndecimatorEnable != m_rfRunning.m_blndecimatorEnable)) { forwardSampleRateChange = true; } - if ((m_objConfigPrivate.m_intTVSampleRate != m_objRunningPrivate.m_intTVSampleRate) - || (m_objRFConfig.m_fltRFBandwidth != m_objRFRunning.m_fltRFBandwidth) - || (m_objRFConfig.m_fltRFOppBandwidth != m_objRFRunning.m_fltRFOppBandwidth)) + if ((m_configPrivate.m_intTVSampleRate != m_runningPrivate.m_intTVSampleRate) + || (m_rfConfig.m_fltRFBandwidth != m_rfRunning.m_fltRFBandwidth) + || (m_rfConfig.m_fltRFOppBandwidth != m_rfRunning.m_fltRFOppBandwidth)) { m_objSettingsMutex.lock(); - m_DSBFilter->create_asym_filter(m_objRFConfig.m_fltRFOppBandwidth / m_objConfigPrivate.m_intTVSampleRate, - m_objRFConfig.m_fltRFBandwidth / m_objConfigPrivate.m_intTVSampleRate); + m_DSBFilter->create_asym_filter(m_rfConfig.m_fltRFOppBandwidth / m_configPrivate.m_intTVSampleRate, + m_rfConfig.m_fltRFBandwidth / m_configPrivate.m_intTVSampleRate); memset(m_DSBFilterBuffer, 0, sizeof(Complex)*(m_ssbFftLen)); m_DSBFilterBufferIndex = 0; m_objSettingsMutex.unlock(); } - if ((m_objConfigPrivate.m_intTVSampleRate != m_objRunningPrivate.m_intTVSampleRate) - || (m_objRFConfig.m_fltBFOFrequency != m_objRFRunning.m_fltBFOFrequency)) + if ((m_configPrivate.m_intTVSampleRate != m_runningPrivate.m_intTVSampleRate) + || (m_rfConfig.m_fltBFOFrequency != m_rfRunning.m_fltBFOFrequency)) { - m_bfoPLL.configure(m_objRFConfig.m_fltBFOFrequency / m_objConfigPrivate.m_intTVSampleRate, - 100.0 / m_objConfigPrivate.m_intTVSampleRate, + m_bfoPLL.configure(m_rfConfig.m_fltBFOFrequency / m_configPrivate.m_intTVSampleRate, + 100.0 / m_configPrivate.m_intTVSampleRate, 0.01); - m_bfoFilter.setFrequencies(m_objRFConfig.m_fltBFOFrequency, m_objConfigPrivate.m_intTVSampleRate); + m_bfoFilter.setFrequencies(m_rfConfig.m_fltBFOFrequency, m_configPrivate.m_intTVSampleRate); } - if (m_objRFConfig.m_fmDeviation != m_objRFRunning.m_fmDeviation) + if (m_rfConfig.m_fmDeviation != m_rfRunning.m_fmDeviation) { - m_objPhaseDiscri.setFMScaling(1.0f / m_objRFConfig.m_fmDeviation); + m_objPhaseDiscri.setFMScaling(1.0f / m_rfConfig.m_fmDeviation); } - m_objRunning = m_objConfig; - m_objRFRunning = m_objRFConfig; - m_objRunningPrivate = m_objConfigPrivate; + m_running = m_config; + m_rfRunning = m_rfConfig; + m_runningPrivate = m_configPrivate; if (forwardSampleRateChange) { - int sampleRate = m_objRFRunning.m_blndecimatorEnable ? m_objRunningPrivate.m_intTVSampleRate : m_objRunning.m_intSampleRate; + int sampleRate = m_rfRunning.m_blndecimatorEnable ? m_runningPrivate.m_intTVSampleRate : m_running.m_intSampleRate; MsgReportEffectiveSampleRate *report; - report = MsgReportEffectiveSampleRate::create(sampleRate, m_objRunningPrivate.m_intNumberSamplePerLine); + report = MsgReportEffectiveSampleRate::create(sampleRate, m_runningPrivate.m_intNumberSamplePerLine); getMessageQueueToGUI()->push(report); } } void ATVDemod::applyStandard() { - switch(m_objConfig.m_enmATVStandard) + switch(m_config.m_enmATVStandard) { case ATVStdHSkip: // what is left in a line for the image @@ -689,23 +689,23 @@ void ATVDemod::applyStandard() } // for now all standards apply this - m_intNumberSamplePerLineSignals = (int) ((12.0f/64.0f)*m_objConfig.m_fltLineDuration * m_objConfig.m_intSampleRate); // 12.0 = 7.3 + 4.7 - m_intNumberSaplesPerHSync = (int) ((9.6f/64.0f)*m_objConfig.m_fltLineDuration * m_objConfig.m_intSampleRate); // 9.4 = 4.7 + 4.7 + m_intNumberSamplePerLineSignals = (int) ((12.0f/64.0f)*m_config.m_fltLineDuration * m_config.m_intSampleRate); // 12.0 = 7.3 + 4.7 + m_intNumberSaplesPerHSync = (int) ((9.6f/64.0f)*m_config.m_fltLineDuration * m_config.m_intSampleRate); // 9.4 = 4.7 + 4.7 } int ATVDemod::getSampleRate() { - return m_objRunning.m_intSampleRate; + return m_running.m_intSampleRate; } int ATVDemod::getEffectiveSampleRate() { - return m_objRFRunning.m_blndecimatorEnable ? m_objRunningPrivate.m_intTVSampleRate : m_objRunning.m_intSampleRate; + return m_rfRunning.m_blndecimatorEnable ? m_runningPrivate.m_intTVSampleRate : m_running.m_intSampleRate; } bool ATVDemod::getBFOLocked() { - if ((m_objRFRunning.m_enmModulation == ATV_USB) || (m_objRFRunning.m_enmModulation == ATV_LSB)) + if ((m_rfRunning.m_enmModulation == ATV_USB) || (m_rfRunning.m_enmModulation == ATV_LSB)) { return m_bfoPLL.locked(); } diff --git a/plugins/channelrx/demodatv/atvdemod.h b/plugins/channelrx/demodatv/atvdemod.h index 60b19f015..414bb7156 100644 --- a/plugins/channelrx/demodatv/atvdemod.h +++ b/plugins/channelrx/demodatv/atvdemod.h @@ -411,14 +411,14 @@ private: //QElapsedTimer m_objTimer; - ATVConfig m_objRunning; - ATVConfig m_objConfig; + ATVConfig m_running; + ATVConfig m_config; - ATVRFConfig m_objRFRunning; - ATVRFConfig m_objRFConfig; + ATVRFConfig m_rfRunning; + ATVRFConfig m_rfConfig; - ATVConfigPrivate m_objRunningPrivate; - ATVConfigPrivate m_objConfigPrivate; + ATVConfigPrivate m_runningPrivate; + ATVConfigPrivate m_configPrivate; QMutex m_objSettingsMutex; @@ -434,12 +434,12 @@ private: // Horizontal Synchro detection // Floor Detection 0 - if (fltVal < m_objRunning.m_fltVoltLevelSynchroTop) + if (fltVal < m_running.m_fltVoltLevelSynchroTop) { m_intSynchroPoints++; } // Black detection 0.3 - else if (fltVal > m_objRunning.m_fltVoltLevelSynchroBlack) + else if (fltVal > m_running.m_fltVoltLevelSynchroBlack) { m_intSynchroPoints = 0; } @@ -450,7 +450,7 @@ private: if (m_blnSynchroDetected) { - if (m_intSampleIndex >= (3 * m_objRunningPrivate.m_intNumberSamplePerLine)/2) // first after skip + if (m_intSampleIndex >= (3 * m_runningPrivate.m_intNumberSamplePerLine)/2) // first after skip { //qDebug("VSync: %d %d %d", m_intColIndex, m_intSampleIndex, m_intLineIndex); m_intAvgColIndex = m_intColIndex; @@ -468,25 +468,25 @@ private: m_intSampleIndex++; } - if (m_intColIndex < m_objRunningPrivate.m_intNumberSamplePerLine + m_intNumberSamplePerTop - 1) + if (m_intColIndex < m_runningPrivate.m_intNumberSamplePerLine + m_intNumberSamplePerTop - 1) { m_intColIndex++; } else { - if (m_objRunning.m_blnHSync && (m_intLineIndex == 0)) + if (m_running.m_blnHSync && (m_intLineIndex == 0)) { //qDebug("HCorr: %d", m_intAvgColIndex); - m_intColIndex = m_intNumberSamplePerTop + (m_objRunningPrivate.m_intNumberSamplePerLine - m_intAvgColIndex)/2; // amortizing factor 1/2 + m_intColIndex = m_intNumberSamplePerTop + (m_runningPrivate.m_intNumberSamplePerLine - m_intAvgColIndex)/2; // amortizing factor 1/2 } else { m_intColIndex = m_intNumberSamplePerTop; } - if ((m_objRFRunning.m_enmModulation == ATV_AM) - || (m_objRFRunning.m_enmModulation == ATV_USB) - || (m_objRFRunning.m_enmModulation == ATV_LSB)) + if ((m_rfRunning.m_enmModulation == ATV_AM) + || (m_rfRunning.m_enmModulation == ATV_USB) + || (m_rfRunning.m_enmModulation == ATV_LSB)) { m_fltAmpMin = m_fltEffMin; m_fltAmpMax = m_fltEffMax; @@ -510,18 +510,18 @@ private: inline void processClassic(float& fltVal, int& intVal) { - int intSynchroTimeSamples= (3 * m_objRunningPrivate.m_intNumberSamplePerLine)/4; - float fltSynchroTrameLevel = 0.5f*((float)intSynchroTimeSamples) * m_objRunning.m_fltVoltLevelSynchroBlack; + int intSynchroTimeSamples= (3 * m_runningPrivate.m_intNumberSamplePerLine)/4; + float fltSynchroTrameLevel = 0.5f*((float)intSynchroTimeSamples) * m_running.m_fltVoltLevelSynchroBlack; // Horizontal Synchro detection // Floor Detection 0 - if (fltVal < m_objRunning.m_fltVoltLevelSynchroTop) + if (fltVal < m_running.m_fltVoltLevelSynchroTop) { m_intSynchroPoints++; } // Black detection 0.3 - else if (fltVal > m_objRunning.m_fltVoltLevelSynchroBlack) + else if (fltVal > m_running.m_fltVoltLevelSynchroBlack) { m_intSynchroPoints = 0; } @@ -534,7 +534,7 @@ private: if (m_blnSynchroDetected) { - m_intAvgColIndex = m_intSampleIndex - m_intColIndex - (m_intColIndex < m_objRunningPrivate.m_intNumberSamplePerLine/2 ? 150 : 0); + m_intAvgColIndex = m_intSampleIndex - m_intColIndex - (m_intColIndex < m_runningPrivate.m_intNumberSamplePerLine/2 ? 150 : 0); //qDebug("HSync: %d %d %d", m_intSampleIndex, m_intColIndex, m_intAvgColIndex); m_intSampleIndex = 0; } @@ -543,14 +543,14 @@ private: m_intSampleIndex++; } - if (!m_objRunning.m_blnHSync && (m_intColIndex >= m_objRunningPrivate.m_intNumberSamplePerLine)) // H Sync not active + if (!m_running.m_blnHSync && (m_intColIndex >= m_runningPrivate.m_intNumberSamplePerLine)) // H Sync not active { m_intColIndex = 0; blnNewLine = true; } - else if (m_intColIndex >= m_objRunningPrivate.m_intNumberSamplePerLine + m_intNumberSamplePerTop) // No valid H sync + else if (m_intColIndex >= m_runningPrivate.m_intNumberSamplePerLine + m_intNumberSamplePerTop) // No valid H sync { - if (m_objRunning.m_blnHSync && (m_intLineIndex == 0)) + if (m_running.m_blnHSync && (m_intLineIndex == 0)) { //qDebug("HSync: %d %d", m_intColIndex, m_intAvgColIndex); m_intColIndex = m_intNumberSamplePerTop + m_intAvgColIndex/4; // amortizing 1/4 @@ -565,9 +565,9 @@ private: if (blnNewLine) { - if ((m_objRFRunning.m_enmModulation == ATV_AM) - || (m_objRFRunning.m_enmModulation == ATV_USB) - || (m_objRFRunning.m_enmModulation == ATV_LSB)) + if ((m_rfRunning.m_enmModulation == ATV_AM) + || (m_rfRunning.m_enmModulation == ATV_USB) + || (m_rfRunning.m_enmModulation == ATV_LSB)) { m_fltAmpMin = m_fltEffMin; m_fltAmpMax = m_fltEffMax; @@ -604,7 +604,7 @@ private: // Vertical sync and image rendering - if ((m_objRunning.m_blnVSync) && (m_intLineIndex < m_intNumberOfLines)) // VSync activated and lines in range + if ((m_running.m_blnVSync) && (m_intLineIndex < m_intNumberOfLines)) // VSync activated and lines in range { if (m_intColIndex >= intSynchroTimeSamples) { @@ -645,7 +645,7 @@ private: { m_objRegisteredATVScreen->renderImage(0); - if (m_objRFRunning.m_enmModulation == ATV_AM) + if (m_rfRunning.m_enmModulation == ATV_AM) { m_fltAmpMin = m_fltEffMin; m_fltAmpMax = m_fltEffMax; diff --git a/plugins/channelrx/demodatv/atvdemodgui.cpp b/plugins/channelrx/demodatv/atvdemodgui.cpp index 8ad7c80fa..7ad3ee474 100644 --- a/plugins/channelrx/demodatv/atvdemodgui.cpp +++ b/plugins/channelrx/demodatv/atvdemodgui.cpp @@ -61,12 +61,12 @@ QString ATVDemodGUI::getName() const qint64 ATVDemodGUI::getCenterFrequency() const { - return m_objChannelMarker.getCenterFrequency(); + return m_channelMarker.getCenterFrequency(); } void ATVDemodGUI::setCenterFrequency(qint64 intCenterFrequency) { - m_objChannelMarker.setCenterFrequency(intCenterFrequency); + m_channelMarker.setCenterFrequency(intCenterFrequency); applySettings(); } @@ -105,8 +105,8 @@ QByteArray ATVDemodGUI::serialize() const { SimpleSerializer s(1); - s.writeS32(1, m_objChannelMarker.getCenterFrequency()); - s.writeU32(2, m_objChannelMarker.getColor().rgb()); + s.writeS32(1, m_channelMarker.getCenterFrequency()); + s.writeU32(2, m_channelMarker.getColor().rgb()); s.writeS32(3, ui->synchLevel->value()); s.writeS32(4, ui->blackLevel->value()); s.writeS32(5, ui->lineTime->value()); @@ -144,10 +144,10 @@ bool ATVDemodGUI::deserialize(const QByteArray& arrData) bool booltmp; blockApplySettings(true); - m_objChannelMarker.blockSignals(true); + m_channelMarker.blockSignals(true); d.readS32(1, &tmp, 0); - m_objChannelMarker.setCenterFrequency(tmp); + m_channelMarker.setCenterFrequency(tmp); // if (d.readU32(2, &u32tmp)) { // m_objChannelMarker.setColor(u32tmp); @@ -189,7 +189,7 @@ bool ATVDemodGUI::deserialize(const QByteArray& arrData) ui->standard->setCurrentIndex(tmp); blockApplySettings(false); - m_objChannelMarker.blockSignals(false); + m_channelMarker.blockSignals(false); lineTimeUpdate(); topTimeUpdate(); @@ -211,7 +211,7 @@ bool ATVDemodGUI::handleMessage(const Message& objMessage) int nbPointsPerLine = ((ATVDemod::MsgReportEffectiveSampleRate&)objMessage).getNbPointsPerLine(); ui->channelSampleRateText->setText(tr("%1k").arg(sampleRate/1000.0f, 0, 'f', 2)); ui->nbPointsPerLineText->setText(tr("%1p").arg(nbPointsPerLine)); - m_objScopeVis->setSampleRate(sampleRate); + m_scopeVis->setSampleRate(sampleRate); setRFFiltersSlidersRange(sampleRate); lineTimeUpdate(); topTimeUpdate(); @@ -261,7 +261,7 @@ void ATVDemodGUI::onMenuDoubleClicked() { m_blnBasicSettingsShown = true; BasicChannelSettingsWidget* bcsw = new BasicChannelSettingsWidget( - &m_objChannelMarker, this); + &m_channelMarker, this); bcsw->show(); } } @@ -270,9 +270,9 @@ ATVDemodGUI::ATVDemodGUI(PluginAPI* objPluginAPI, DeviceSourceAPI *objDeviceAPI, QWidget* objParent) : RollupWidget(objParent), ui(new Ui::ATVDemodGUI), - m_objPluginAPI(objPluginAPI), - m_objDeviceAPI(objDeviceAPI), - m_objChannelMarker(this), + m_pluginAPI(objPluginAPI), + m_deviceAPI(objDeviceAPI), + m_channelMarker(this), m_blnBasicSettingsShown(false), m_blnDoApplySettings(true), m_objMagSqAverage(40, 0), @@ -283,43 +283,43 @@ ATVDemodGUI::ATVDemodGUI(PluginAPI* objPluginAPI, DeviceSourceAPI *objDeviceAPI, connect(this, SIGNAL(widgetRolled(QWidget*,bool)), this, SLOT(onWidgetRolled(QWidget*,bool))); connect(this, SIGNAL(menuDoubleClickEvent()), this, SLOT(onMenuDoubleClicked())); - m_objScopeVis = new ScopeVisNG(ui->glScope); - m_objATVDemod = new ATVDemod(m_objScopeVis); - m_objATVDemod->setMessageQueueToGUI(getInputMessageQueue()); - m_objATVDemod->setATVScreen(ui->screenTV); + m_scopeVis = new ScopeVisNG(ui->glScope); + m_atvDemod = new ATVDemod(m_scopeVis); + m_atvDemod->setMessageQueueToGUI(getInputMessageQueue()); + m_atvDemod->setATVScreen(ui->screenTV); - m_objChannelizer = new DownChannelizer(m_objATVDemod); - m_objThreadedChannelizer = new ThreadedBasebandSampleSink(m_objChannelizer, this); - m_objDeviceAPI->addThreadedSink(m_objThreadedChannelizer); + m_channelizer = new DownChannelizer(m_atvDemod); + m_threadedChannelizer = new ThreadedBasebandSampleSink(m_channelizer, this); + m_deviceAPI->addThreadedSink(m_threadedChannelizer); - ui->glScope->connectTimer(m_objPluginAPI->getMainWindow()->getMasterTimer()); - connect(&m_objPluginAPI->getMainWindow()->getMasterTimer(), SIGNAL(timeout()), this, SLOT(tick())); // 50 ms + ui->glScope->connectTimer(m_pluginAPI->getMainWindow()->getMasterTimer()); + connect(&m_pluginAPI->getMainWindow()->getMasterTimer(), SIGNAL(timeout()), this, SLOT(tick())); // 50 ms ui->deltaFrequencyLabel->setText(QString("%1f").arg(QChar(0x94, 0x03))); ui->deltaFrequency->setColorMapper(ColorMapper(ColorMapper::GrayGold)); ui->deltaFrequency->setValueRange(false, 7, -9999999, 9999999); - connect(m_objChannelizer, SIGNAL(inputSampleRateChanged()), this, SLOT(channelSampleRateChanged())); + connect(m_channelizer, SIGNAL(inputSampleRateChanged()), this, SLOT(channelSampleRateChanged())); //m_objPluginAPI->addThreadedSink(m_objThreadedChannelizer); - m_objChannelMarker.setColor(Qt::white); - m_objChannelMarker.setMovable(false); - m_objChannelMarker.setBandwidth(6000000); - m_objChannelMarker.setCenterFrequency(0); - m_objChannelMarker.setVisible(true); - setTitleColor(m_objChannelMarker.getColor()); + m_channelMarker.setColor(Qt::white); + m_channelMarker.setMovable(false); + m_channelMarker.setBandwidth(6000000); + m_channelMarker.setCenterFrequency(0); + m_channelMarker.setVisible(true); + setTitleColor(m_channelMarker.getColor()); - connect(&m_objChannelMarker, SIGNAL(changed()), this, SLOT(viewChanged())); + connect(&m_channelMarker, SIGNAL(changed()), this, SLOT(viewChanged())); - m_objDeviceAPI->registerChannelInstance(m_strChannelID, this); - m_objDeviceAPI->addChannelMarker(&m_objChannelMarker); - m_objDeviceAPI->addRollupWidget(this); + m_deviceAPI->registerChannelInstance(m_strChannelID, this); + m_deviceAPI->addChannelMarker(&m_channelMarker); + m_deviceAPI->addRollupWidget(this); //ui->screenTV->connectTimer(m_objPluginAPI->getMainWindow()->getMasterTimer()); m_objMagSqAverage.resize(4, 1.0); - ui->scopeGUI->setBuddies(m_objScopeVis->getInputMessageQueue(), m_objScopeVis, ui->glScope); + ui->scopeGUI->setBuddies(m_scopeVis->getInputMessageQueue(), m_scopeVis, ui->glScope); resetToDefaults(); // does applySettings() @@ -346,12 +346,12 @@ ATVDemodGUI::ATVDemodGUI(PluginAPI* objPluginAPI, DeviceSourceAPI *objDeviceAPI, ATVDemodGUI::~ATVDemodGUI() { - m_objDeviceAPI->removeChannelInstance(this); - m_objDeviceAPI->removeThreadedSink(m_objThreadedChannelizer); - delete m_objThreadedChannelizer; - delete m_objChannelizer; - delete m_objATVDemod; - delete m_objScopeVis; + m_deviceAPI->removeChannelInstance(this); + m_deviceAPI->removeThreadedSink(m_threadedChannelizer); + delete m_threadedChannelizer; + delete m_channelizer; + delete m_atvDemod; + delete m_scopeVis; delete ui; } @@ -364,13 +364,13 @@ void ATVDemodGUI::applySettings() { if (m_blnDoApplySettings) { - ui->deltaFrequency->setValue(m_objChannelMarker.getCenterFrequency()); + ui->deltaFrequency->setValue(m_channelMarker.getCenterFrequency()); - m_objChannelizer->configure(m_objChannelizer->getInputMessageQueue(), - m_objChannelizer->getInputSampleRate(), // always use maximum available bandwidth - m_objChannelMarker.getCenterFrequency()); + m_channelizer->configure(m_channelizer->getInputMessageQueue(), + m_channelizer->getInputSampleRate(), // always use maximum available bandwidth + m_channelMarker.getCenterFrequency()); - m_objATVDemod->configure(m_objATVDemod->getInputMessageQueue(), + m_atvDemod->configure(m_atvDemod->getInputMessageQueue(), getNominalLineTime(ui->nbLines->currentIndex(), ui->fps->currentIndex()) + ui->lineTime->value() * m_fltLineTimeMultiplier, getNominalLineTime(ui->nbLines->currentIndex(), ui->fps->currentIndex()) * (4.7f / 64.0f) + ui->topTime->value() * m_fltTopTimeMultiplier, getFps(ui->fps->currentIndex()), @@ -385,8 +385,8 @@ void ATVDemodGUI::applySettings() ui->screenTabWidget->currentIndex()); qDebug() << "ATVDemodGUI::applySettings:" - << " m_objChannelizer.inputSampleRate: " << m_objChannelizer->getInputSampleRate() - << " m_objATVDemod.sampleRate: " << m_objATVDemod->getSampleRate(); + << " m_objChannelizer.inputSampleRate: " << m_channelizer->getInputSampleRate() + << " m_objATVDemod.sampleRate: " << m_atvDemod->getSampleRate(); } } @@ -394,7 +394,7 @@ void ATVDemodGUI::applyRFSettings() { if (m_blnDoApplySettings) { - m_objATVDemod->configureRF(m_objATVDemod->getInputMessageQueue(), + m_atvDemod->configureRF(m_atvDemod->getInputMessageQueue(), (ATVDemod::ATVModulation) ui->modulation->currentIndex(), ui->rfBW->value() * m_rfSliderDivisor * 1.0f, ui->rfOppBW->value() * m_rfSliderDivisor * 1.0f, @@ -411,26 +411,26 @@ void ATVDemodGUI::setChannelMarkerBandwidth() if (ui->rfFiltering->isChecked()) // FFT filter { - m_objChannelMarker.setBandwidth(ui->rfBW->value()*m_rfSliderDivisor); - m_objChannelMarker.setOppositeBandwidth(ui->rfOppBW->value()*m_rfSliderDivisor); + m_channelMarker.setBandwidth(ui->rfBW->value()*m_rfSliderDivisor); + m_channelMarker.setOppositeBandwidth(ui->rfOppBW->value()*m_rfSliderDivisor); if (ui->modulation->currentIndex() == (int) ATVDemod::ATV_LSB) { - m_objChannelMarker.setSidebands(ChannelMarker::vlsb); + m_channelMarker.setSidebands(ChannelMarker::vlsb); } else if (ui->modulation->currentIndex() == (int) ATVDemod::ATV_USB) { - m_objChannelMarker.setSidebands(ChannelMarker::vusb); + m_channelMarker.setSidebands(ChannelMarker::vusb); } else { - m_objChannelMarker.setSidebands(ChannelMarker::vusb); + m_channelMarker.setSidebands(ChannelMarker::vusb); } } else { if (ui->decimatorEnable->isChecked()) { - m_objChannelMarker.setBandwidth(ui->rfBW->value()*m_rfSliderDivisor); + m_channelMarker.setBandwidth(ui->rfBW->value()*m_rfSliderDivisor); } else { - m_objChannelMarker.setBandwidth(m_objChannelizer->getInputSampleRate()); + m_channelMarker.setBandwidth(m_channelizer->getInputSampleRate()); } - m_objChannelMarker.setSidebands(ChannelMarker::dsb); + m_channelMarker.setSidebands(ChannelMarker::dsb); } m_blnDoApplySettings = true; @@ -464,14 +464,14 @@ void ATVDemodGUI::setRFFiltersSlidersRange(int sampleRate) void ATVDemodGUI::leaveEvent(QEvent*) { blockApplySettings(true); - m_objChannelMarker.setHighlighted(false); + m_channelMarker.setHighlighted(false); blockApplySettings(false); } void ATVDemodGUI::enterEvent(QEvent*) { blockApplySettings(true); - m_objChannelMarker.setHighlighted(true); + m_channelMarker.setHighlighted(true); blockApplySettings(false); } @@ -483,13 +483,13 @@ void ATVDemodGUI::tick() } else { - if (m_objATVDemod) + if (m_atvDemod) { - m_objMagSqAverage.feed(m_objATVDemod->getMagSq()); + m_objMagSqAverage.feed(m_atvDemod->getMagSq()); double magSqDB = CalcDb::dbPower(m_objMagSqAverage.average() / (1<<30)); ui->channePowerText->setText(tr("%1 dB").arg(magSqDB, 0, 'f', 1)); - if (m_objATVDemod->getBFOLocked()) { + if (m_atvDemod->getBFOLocked()) { ui->bfoLockedLabel->setStyleSheet("QLabel { background-color : green; }"); } else { ui->bfoLockedLabel->setStyleSheet("QLabel { background:rgb(79,79,79); }"); @@ -574,7 +574,7 @@ void ATVDemodGUI::on_reset_clicked(bool checked __attribute__((unused))) void ATVDemodGUI::on_modulation_currentIndexChanged(int index __attribute__((unused))) { - setRFFiltersSlidersRange(m_objATVDemod->getEffectiveSampleRate()); + setRFFiltersSlidersRange(m_atvDemod->getEffectiveSampleRate()); setChannelMarkerBandwidth(); applyRFSettings(); } @@ -595,7 +595,7 @@ void ATVDemodGUI::on_rfOppBW_valueChanged(int value) void ATVDemodGUI::on_rfFiltering_toggled(bool checked __attribute__((unused))) { - setRFFiltersSlidersRange(m_objATVDemod->getEffectiveSampleRate()); + setRFFiltersSlidersRange(m_atvDemod->getEffectiveSampleRate()); setChannelMarkerBandwidth(); applyRFSettings(); } @@ -608,7 +608,7 @@ void ATVDemodGUI::on_decimatorEnable_toggled(bool checked __attribute__((unused) void ATVDemodGUI::on_deltaFrequency_changed(qint64 value) { - m_objChannelMarker.setCenterFrequency(value); + m_channelMarker.setCenterFrequency(value); } void ATVDemodGUI::on_bfo_valueChanged(int value) @@ -633,10 +633,10 @@ void ATVDemodGUI::lineTimeUpdate() float nominalLineTime = getNominalLineTime(ui->nbLines->currentIndex(), ui->fps->currentIndex()); int lineTimeScaleFactor = (int) std::log10(nominalLineTime); - if (m_objATVDemod->getEffectiveSampleRate() == 0) { + if (m_atvDemod->getEffectiveSampleRate() == 0) { m_fltLineTimeMultiplier = std::pow(10.0, lineTimeScaleFactor-3); } else { - m_fltLineTimeMultiplier = 1.0f / m_objATVDemod->getEffectiveSampleRate(); + m_fltLineTimeMultiplier = 1.0f / m_atvDemod->getEffectiveSampleRate(); } float lineTime = nominalLineTime + m_fltLineTimeMultiplier * ui->lineTime->value(); @@ -658,10 +658,10 @@ void ATVDemodGUI::topTimeUpdate() float nominalTopTime = getNominalLineTime(ui->nbLines->currentIndex(), ui->fps->currentIndex()) * (4.7f / 64.0f); int topTimeScaleFactor = (int) std::log10(nominalTopTime); - if (m_objATVDemod->getEffectiveSampleRate() == 0) { + if (m_atvDemod->getEffectiveSampleRate() == 0) { m_fltTopTimeMultiplier = std::pow(10.0, topTimeScaleFactor-3); } else { - m_fltTopTimeMultiplier = 1.0f / m_objATVDemod->getEffectiveSampleRate(); + m_fltTopTimeMultiplier = 1.0f / m_atvDemod->getEffectiveSampleRate(); } float topTime = nominalTopTime + m_fltTopTimeMultiplier * ui->topTime->value(); diff --git a/plugins/channelrx/demodatv/atvdemodgui.h b/plugins/channelrx/demodatv/atvdemodgui.h index 7f6764acc..917076294 100644 --- a/plugins/channelrx/demodatv/atvdemodgui.h +++ b/plugins/channelrx/demodatv/atvdemodgui.h @@ -89,12 +89,12 @@ private slots: private: Ui::ATVDemodGUI* ui; - PluginAPI* m_objPluginAPI; - DeviceSourceAPI* m_objDeviceAPI; - ChannelMarker m_objChannelMarker; - ThreadedBasebandSampleSink* m_objThreadedChannelizer; - DownChannelizer* m_objChannelizer; - ATVDemod* m_objATVDemod; + PluginAPI* m_pluginAPI; + DeviceSourceAPI* m_deviceAPI; + ChannelMarker m_channelMarker; + ThreadedBasebandSampleSink* m_threadedChannelizer; + DownChannelizer* m_channelizer; + ATVDemod* m_atvDemod; bool m_blnBasicSettingsShown; bool m_blnDoApplySettings; @@ -102,7 +102,7 @@ private: MovingAverage m_objMagSqAverage; int m_intTickCount; - ScopeVisNG* m_objScopeVis; + ScopeVisNG* m_scopeVis; float m_fltLineTimeMultiplier; float m_fltTopTimeMultiplier; From b11cf719d60052da524ca24be553592ebd5eba40 Mon Sep 17 00:00:00 2001 From: f4exb Date: Sun, 1 Oct 2017 10:12:54 +0200 Subject: [PATCH 44/71] ATV modulator: fixed segfault when there is no GUI message queue --- plugins/channelrx/demodatv/atvdemod.cpp | 26 ++-- plugins/channelrx/demodatv/atvdemod.h | 30 +++-- plugins/channelrx/demodatv/atvdemodgui.cpp | 3 +- plugins/channeltx/modatv/atvmod.cpp | 144 ++++++++++++--------- sdrbase/dsp/basebandsamplesource.cpp | 1 + 5 files changed, 119 insertions(+), 85 deletions(-) diff --git a/plugins/channelrx/demodatv/atvdemod.cpp b/plugins/channelrx/demodatv/atvdemod.cpp index 9379f1853..93e8192cb 100644 --- a/plugins/channelrx/demodatv/atvdemod.cpp +++ b/plugins/channelrx/demodatv/atvdemod.cpp @@ -31,9 +31,9 @@ MESSAGE_CLASS_DEFINITION(ATVDemod::MsgReportEffectiveSampleRate, Message) const int ATVDemod::m_ssbFftLen = 1024; -ATVDemod::ATVDemod(BasebandSampleSink* objScopeSink) : - m_objScopeSink(objScopeSink), - m_objRegisteredATVScreen(NULL), +ATVDemod::ATVDemod(DeviceSourceAPI *deviceAPI) : + m_deviceAPI(deviceAPI), + m_registeredATVScreen(NULL), m_intNumberSamplePerTop(0), m_intImageIndex(0), m_intSynchroPoints(0), @@ -88,7 +88,7 @@ ATVDemod::~ATVDemod() void ATVDemod::setATVScreen(ATVScreen *objScreen) { - m_objRegisteredATVScreen = objScreen; + m_registeredATVScreen = objScreen; } void ATVDemod::configure( @@ -207,10 +207,10 @@ void ATVDemod::feed(const SampleVector::const_iterator& begin, const SampleVecto } } - if ((m_running.m_intVideoTabIndex == 1) && (m_objScopeSink != 0)) // do only if scope tab is selected and scope is available + if ((m_running.m_intVideoTabIndex == 1) && (m_scopeSink != 0)) // do only if scope tab is selected and scope is available { - m_objScopeSink->feed(m_objScopeSampleBuffer.begin(), m_objScopeSampleBuffer.end(), false); // m_ssb = positive only - m_objScopeSampleBuffer.clear(); + m_scopeSink->feed(m_scopeSampleBuffer.begin(), m_scopeSampleBuffer.end(), false); // m_ssb = positive only + m_scopeSampleBuffer.clear(); } if (ptrBufferToRelease != 0) @@ -390,8 +390,8 @@ void ATVDemod::demod(Complex& c) fltVal = m_running.m_blnInvertVideo ? 1.0f - fltVal : fltVal; fltVal = (fltVal < -1.0f) ? -1.0f : (fltVal > 1.0f) ? 1.0f : fltVal; - if ((m_running.m_intVideoTabIndex == 1) && (m_objScopeSink != 0)) { // feed scope buffer only if scope is present and visible - m_objScopeSampleBuffer.push_back(Sample(fltVal*32767.0f, 0.0f)); + if ((m_running.m_intVideoTabIndex == 1) && (m_scopeSink != 0)) { // feed scope buffer only if scope is present and visible + m_scopeSampleBuffer.push_back(Sample(fltVal*32767.0f, 0.0f)); } m_fltAmpLineAverage += fltVal; @@ -490,9 +490,9 @@ bool ATVDemod::handleMessage(const Message& cmd) } else { - if (m_objScopeSink != 0) + if (m_scopeSink != 0) { - return m_objScopeSink->handleMessage(cmd); + return m_scopeSink->handleMessage(cmd); } else { @@ -574,8 +574,8 @@ void ATVDemod::applySettings() m_configPrivate.m_intNumberSamplePerLine = (int) (m_config.m_fltLineDuration * m_config.m_intSampleRate); m_intNumberSamplePerTop = (int) (m_config.m_fltTopDuration * m_config.m_intSampleRate); - m_objRegisteredATVScreen->setRenderImmediate(!(m_config.m_fltFramePerS > 25.0f)); - m_objRegisteredATVScreen->resizeATVScreen( + m_registeredATVScreen->setRenderImmediate(!(m_config.m_fltFramePerS > 25.0f)); + m_registeredATVScreen->resizeATVScreen( m_configPrivate.m_intNumberSamplePerLine - m_intNumberSamplePerLineSignals, m_intNumberOfLines - m_intNumberOfBlackLines); diff --git a/plugins/channelrx/demodatv/atvdemod.h b/plugins/channelrx/demodatv/atvdemod.h index 414bb7156..a561d834e 100644 --- a/plugins/channelrx/demodatv/atvdemod.h +++ b/plugins/channelrx/demodatv/atvdemod.h @@ -38,6 +38,7 @@ #include "util/message.h" #include "atvscreen.h" +class DeviceSourceAPI; class ATVDemod : public BasebandSampleSink { @@ -146,8 +147,9 @@ public: { } }; - ATVDemod(BasebandSampleSink* objScopeSink); + ATVDemod(DeviceSourceAPI *deviceAPI); ~ATVDemod(); + void setScopeSink(BasebandSampleSink* scopeSink) { m_scopeSink = scopeSink; } void configure(MessageQueue* objMessageQueue, float fltLineDurationUs, @@ -339,13 +341,15 @@ private: bool m_start; }; + DeviceSourceAPI* m_deviceAPI; + //*************** SCOPE *************** - BasebandSampleSink* m_objScopeSink; - SampleVector m_objScopeSampleBuffer; + BasebandSampleSink* m_scopeSink; + SampleVector m_scopeSampleBuffer; //*************** ATV PARAMETERS *************** - ATVScreen * m_objRegisteredATVScreen; + ATVScreen * m_registeredATVScreen; //int m_intNumberSamplePerLine; int m_intNumberSamplePerTop; @@ -429,7 +433,7 @@ private: inline void processHSkip(float& fltVal, int& intVal) { - m_objRegisteredATVScreen->setDataColor(m_intColIndex - m_intNumberSaplesPerHSync + m_intNumberSamplePerTop, intVal, intVal, intVal); + m_registeredATVScreen->setDataColor(m_intColIndex - m_intNumberSaplesPerHSync + m_intNumberSamplePerTop, intVal, intVal, intVal); // Horizontal Synchro detection @@ -454,7 +458,7 @@ private: { //qDebug("VSync: %d %d %d", m_intColIndex, m_intSampleIndex, m_intLineIndex); m_intAvgColIndex = m_intColIndex; - m_objRegisteredATVScreen->renderImage(0); + m_registeredATVScreen->renderImage(0); m_intImageIndex++; m_intLineIndex = 0; @@ -502,7 +506,7 @@ private: m_fltEffMax = -2000000.0f; } - m_objRegisteredATVScreen->selectRow(m_intRowIndex); + m_registeredATVScreen->selectRow(m_intRowIndex); m_intLineIndex++; m_intRowIndex++; } @@ -590,7 +594,7 @@ private: if (m_intRowIndex < m_intNumberOfLines) { - m_objRegisteredATVScreen->selectRow(m_intRowIndex - m_intNumberOfSyncLines); + m_registeredATVScreen->selectRow(m_intRowIndex - m_intNumberOfSyncLines); } m_intLineIndex++; @@ -599,7 +603,7 @@ private: // Filling pixels // +4 is to compensate shift due to hsync amortizing factor of 1/4 - m_objRegisteredATVScreen->setDataColor(m_intColIndex - m_intNumberSaplesPerHSync + m_intNumberSamplePerTop + 4, intVal, intVal, intVal); + m_registeredATVScreen->setDataColor(m_intColIndex - m_intNumberSaplesPerHSync + m_intNumberSamplePerTop + 4, intVal, intVal, intVal); m_intColIndex++; // Vertical sync and image rendering @@ -618,7 +622,7 @@ private: if ((m_intLineIndex % 2 == 0) || !m_interleaved) // even => odd image { - m_objRegisteredATVScreen->renderImage(0); + m_registeredATVScreen->renderImage(0); m_intRowIndex = 1; } else @@ -626,7 +630,7 @@ private: m_intRowIndex = 0; } - m_objRegisteredATVScreen->selectRow(m_intRowIndex - m_intNumberOfSyncLines); + m_registeredATVScreen->selectRow(m_intRowIndex - m_intNumberOfSyncLines); m_intLineIndex = 0; m_intImageIndex++; } @@ -643,7 +647,7 @@ private: { if (m_intImageIndex % 2 == 1) // odd image { - m_objRegisteredATVScreen->renderImage(0); + m_registeredATVScreen->renderImage(0); if (m_rfRunning.m_enmModulation == ATV_AM) { @@ -668,7 +672,7 @@ private: m_intRowIndex = 0; } - m_objRegisteredATVScreen->selectRow(m_intRowIndex - m_intNumberOfSyncLines); + m_registeredATVScreen->selectRow(m_intRowIndex - m_intNumberOfSyncLines); m_intLineIndex = 0; m_intImageIndex++; } diff --git a/plugins/channelrx/demodatv/atvdemodgui.cpp b/plugins/channelrx/demodatv/atvdemodgui.cpp index 7ad3ee474..7683dbc22 100644 --- a/plugins/channelrx/demodatv/atvdemodgui.cpp +++ b/plugins/channelrx/demodatv/atvdemodgui.cpp @@ -284,7 +284,8 @@ ATVDemodGUI::ATVDemodGUI(PluginAPI* objPluginAPI, DeviceSourceAPI *objDeviceAPI, connect(this, SIGNAL(menuDoubleClickEvent()), this, SLOT(onMenuDoubleClicked())); m_scopeVis = new ScopeVisNG(ui->glScope); - m_atvDemod = new ATVDemod(m_scopeVis); + m_atvDemod = new ATVDemod(m_deviceAPI); + m_atvDemod->setScopeSink(m_scopeVis); m_atvDemod->setMessageQueueToGUI(getInputMessageQueue()); m_atvDemod->setATVScreen(ui->screenTV); diff --git a/plugins/channeltx/modatv/atvmod.cpp b/plugins/channeltx/modatv/atvmod.cpp index dec3d9194..643857d92 100644 --- a/plugins/channeltx/modatv/atvmod.cpp +++ b/plugins/channeltx/modatv/atvmod.cpp @@ -385,16 +385,20 @@ void ATVMod::pullVideo(Real& sample) time_t start, end; cv::Mat frame; - MsgReportCameraData *report; - report = MsgReportCameraData::create( - camera.m_cameraNumber, - 0.0f, - camera.m_videoFPSManual, - camera.m_videoFPSManualEnable, - camera.m_videoWidth, - camera.m_videoHeight, - 1); // open splash screen on GUI side - getMessageQueueToGUI()->push(report); + if (getMessageQueueToGUI()) + { + MsgReportCameraData *report; + report = MsgReportCameraData::create( + camera.m_cameraNumber, + 0.0f, + camera.m_videoFPSManual, + camera.m_videoFPSManualEnable, + camera.m_videoWidth, + camera.m_videoHeight, + 1); // open splash screen on GUI side + getMessageQueueToGUI()->push(report); + } + int nbFrames = 0; time(&start); @@ -414,15 +418,19 @@ void ATVMod::pullVideo(Real& sample) camera.m_videoFPSCount = camera.m_videoFPSq; camera.m_videoPrevFPSCount = 0; - report = MsgReportCameraData::create( - camera.m_cameraNumber, - camera.m_videoFPS, - camera.m_videoFPSManual, - camera.m_videoFPSManualEnable, - camera.m_videoWidth, - camera.m_videoHeight, - 2); // close splash screen on GUI side - getMessageQueueToGUI()->push(report); + if (getMessageQueueToGUI()) + { + MsgReportCameraData *report; + report = MsgReportCameraData::create( + camera.m_cameraNumber, + camera.m_videoFPS, + camera.m_videoFPSManual, + camera.m_videoFPSManualEnable, + camera.m_videoWidth, + camera.m_videoHeight, + 2); // close splash screen on GUI side + getMessageQueueToGUI()->push(report); + } } else if (camera.m_videoFPS == 0.0f) // Hideous hack for windows { @@ -431,16 +439,19 @@ void ATVMod::pullVideo(Real& sample) camera.m_videoFPSCount = camera.m_videoFPSq; camera.m_videoPrevFPSCount = 0; - MsgReportCameraData *report; - report = MsgReportCameraData::create( - camera.m_cameraNumber, - camera.m_videoFPS, - camera.m_videoFPSManual, - camera.m_videoFPSManualEnable, - camera.m_videoWidth, - camera.m_videoHeight, - 0); - getMessageQueueToGUI()->push(report); + if (getMessageQueueToGUI()) + { + MsgReportCameraData *report; + report = MsgReportCameraData::create( + camera.m_cameraNumber, + camera.m_videoFPS, + camera.m_videoFPSManual, + camera.m_videoFPSManualEnable, + camera.m_videoWidth, + camera.m_videoHeight, + 0); + getMessageQueueToGUI()->push(report); + } } int fpsIncrement = (int) camera.m_videoFPSCount - camera.m_videoPrevFPSCount; @@ -601,9 +612,12 @@ bool ATVMod::handleMessage(const Message& cmd) framesCount = 0; } - MsgReportVideoFileSourceStreamTiming *report; - report = MsgReportVideoFileSourceStreamTiming::create(framesCount); - getMessageQueueToGUI()->push(report); + if (getMessageQueueToGUI()) + { + MsgReportVideoFileSourceStreamTiming *report; + report = MsgReportVideoFileSourceStreamTiming::create(framesCount); + getMessageQueueToGUI()->push(report); + } return true; } @@ -615,16 +629,20 @@ bool ATVMod::handleMessage(const Message& cmd) if (index < m_cameras.size()) { m_cameraIndex = index; - MsgReportCameraData *report; - report = MsgReportCameraData::create( - m_cameras[m_cameraIndex].m_cameraNumber, - m_cameras[m_cameraIndex].m_videoFPS, - m_cameras[m_cameraIndex].m_videoFPSManual, - m_cameras[m_cameraIndex].m_videoFPSManualEnable, - m_cameras[m_cameraIndex].m_videoWidth, - m_cameras[m_cameraIndex].m_videoHeight, - 0); - getMessageQueueToGUI()->push(report); + + if (getMessageQueueToGUI()) + { + MsgReportCameraData *report; + report = MsgReportCameraData::create( + m_cameras[m_cameraIndex].m_cameraNumber, + m_cameras[m_cameraIndex].m_videoFPS, + m_cameras[m_cameraIndex].m_videoFPSManual, + m_cameras[m_cameraIndex].m_videoFPSManualEnable, + m_cameras[m_cameraIndex].m_videoWidth, + m_cameras[m_cameraIndex].m_videoHeight, + 0); + getMessageQueueToGUI()->push(report); + } } return true; @@ -721,9 +739,12 @@ void ATVMod::apply(bool force) applyStandard(); // set all timings m_settingsMutex.unlock(); - MsgReportEffectiveSampleRate *report; - report = MsgReportEffectiveSampleRate::create(m_tvSampleRate, m_pointsPerLine); - getMessageQueueToGUI()->push(report); + if (getMessageQueueToGUI()) + { + MsgReportEffectiveSampleRate *report; + report = MsgReportEffectiveSampleRate::create(m_tvSampleRate, m_pointsPerLine); + getMessageQueueToGUI()->push(report); + } } if ((m_config.m_outputSampleRate != m_running.m_outputSampleRate) @@ -977,9 +998,12 @@ void ATVMod::openVideo(const QString& fileName) calculateVideoSizes(); m_videoEOF = false; - MsgReportVideoFileSourceStreamData *report; - report = MsgReportVideoFileSourceStreamData::create(m_videoFPS, m_videoLength); - getMessageQueueToGUI()->push(report); + if (getMessageQueueToGUI()) + { + MsgReportVideoFileSourceStreamData *report; + report = MsgReportVideoFileSourceStreamData::create(m_videoFPS, m_videoLength); + getMessageQueueToGUI()->push(report); + } } else { @@ -1114,16 +1138,20 @@ void ATVMod::getCameraNumbers(std::vector& numbers) if (m_cameras.size() > 0) { m_cameraIndex = 0; - MsgReportCameraData *report; - report = MsgReportCameraData::create( - m_cameras[0].m_cameraNumber, - m_cameras[0].m_videoFPS, - m_cameras[0].m_videoFPSManual, - m_cameras[0].m_videoFPSManualEnable, - m_cameras[0].m_videoWidth, - m_cameras[0].m_videoHeight, - 0); - getMessageQueueToGUI()->push(report); + + if (getMessageQueueToGUI()) + { + MsgReportCameraData *report; + report = MsgReportCameraData::create( + m_cameras[0].m_cameraNumber, + m_cameras[0].m_videoFPS, + m_cameras[0].m_videoFPSManual, + m_cameras[0].m_videoFPSManualEnable, + m_cameras[0].m_videoWidth, + m_cameras[0].m_videoHeight, + 0); + getMessageQueueToGUI()->push(report); + } } } diff --git a/sdrbase/dsp/basebandsamplesource.cpp b/sdrbase/dsp/basebandsamplesource.cpp index 76ea093a3..edbf2d2f4 100644 --- a/sdrbase/dsp/basebandsamplesource.cpp +++ b/sdrbase/dsp/basebandsamplesource.cpp @@ -19,6 +19,7 @@ #include "util/message.h" BasebandSampleSource::BasebandSampleSource() : + m_guiMessageQueue(0), m_sampleFifo(48000) // arbitrary, will be adjusted to match device sink FIFO size { connect(&m_inputMessageQueue, SIGNAL(messageEnqueued()), this, SLOT(handleInputMessages())); From a9d1b2ef65bfbbdc74cf98745444af0b961f57a1 Mon Sep 17 00:00:00 2001 From: f4exb Date: Sun, 1 Oct 2017 11:50:16 +0200 Subject: [PATCH 45/71] BFM demod: moved RDS parser in the demod --- plugins/channelrx/demodbfm/bfmdemod.cpp | 9 +- plugins/channelrx/demodbfm/bfmdemod.h | 11 +- plugins/channelrx/demodbfm/bfmdemodgui.cpp | 164 ++++++++++----------- plugins/channelrx/demodbfm/bfmdemodgui.h | 4 +- 4 files changed, 94 insertions(+), 94 deletions(-) diff --git a/plugins/channelrx/demodbfm/bfmdemod.cpp b/plugins/channelrx/demodbfm/bfmdemod.cpp index f6dd35444..6e612e2ee 100644 --- a/plugins/channelrx/demodbfm/bfmdemod.cpp +++ b/plugins/channelrx/demodbfm/bfmdemod.cpp @@ -35,12 +35,12 @@ MESSAGE_CLASS_DEFINITION(BFMDemod::MsgConfigureBFMDemod, Message) const Real BFMDemod::default_deemphasis = 50.0; // 50 us const int BFMDemod::m_udpBlockSize = 512; -BFMDemod::BFMDemod(BasebandSampleSink* sampleSink, RDSParser *rdsParser) : +BFMDemod::BFMDemod(DeviceSourceAPI *deviceAPI, BasebandSampleSink* sampleSink) : + m_deviceAPI(deviceAPI), m_sampleSink(sampleSink), m_audioFifo(250000), m_settingsMutex(QMutex::Recursive), m_pilotPLL(19000/384000, 50/384000, 0.01), - m_rdsParser(rdsParser), m_deemphasisFilterX(default_deemphasis * 48000 * 1.0e-6), m_deemphasisFilterY(default_deemphasis * 48000 * 1.0e-6), m_fmExcursion(default_excursion) @@ -182,10 +182,7 @@ void BFMDemod::feed(const SampleVector::const_iterator& begin, const SampleVecto { if (m_rdsDecoder.frameSync(bit)) { - if (m_rdsParser) - { - m_rdsParser->parseGroup(m_rdsDecoder.getGroup()); - } + m_rdsParser.parseGroup(m_rdsDecoder.getGroup()); } } diff --git a/plugins/channelrx/demodbfm/bfmdemod.h b/plugins/channelrx/demodbfm/bfmdemod.h index 5c6dc813c..484bd9d47 100644 --- a/plugins/channelrx/demodbfm/bfmdemod.h +++ b/plugins/channelrx/demodbfm/bfmdemod.h @@ -33,14 +33,15 @@ #include "util/message.h" #include "util/udpsink.h" +#include "rdsparser.h" #include "rdsdecoder.h" #include "rdsdemod.h" -class RDSParser; +class DeviceSourceAPI; class BFMDemod : public BasebandSampleSink { public: - BFMDemod(BasebandSampleSink* sampleSink, RDSParser* rdsParser); + BFMDemod(DeviceSourceAPI *deviceAPI, BasebandSampleSink* sampleSink); virtual ~BFMDemod(); void configure(MessageQueue* messageQueue, @@ -85,6 +86,8 @@ public: m_magsqCount = 0; } + RDSParser& getRDSParser() { return m_rdsParser; } + private: class MsgConfigureBFMDemod : public Message { MESSAGE_CLASS_DECLARATION @@ -214,6 +217,8 @@ private: Config m_config; Config m_running; + DeviceSourceAPI *m_deviceAPI; + NCO m_nco; Interpolator m_interpolator; //!< Interpolator between fixed demod bandwidth and audio bandwidth (rational) Real m_interpolatorDistance; @@ -254,7 +259,7 @@ private: RDSDemod m_rdsDemod; RDSDecoder m_rdsDecoder; - RDSParser *m_rdsParser; + RDSParser m_rdsParser; LowPassFilterRC m_deemphasisFilterX; LowPassFilterRC m_deemphasisFilterY; diff --git a/plugins/channelrx/demodbfm/bfmdemodgui.cpp b/plugins/channelrx/demodbfm/bfmdemodgui.cpp index 82170bb6c..a9a824f49 100644 --- a/plugins/channelrx/demodbfm/bfmdemodgui.cpp +++ b/plugins/channelrx/demodbfm/bfmdemodgui.cpp @@ -277,7 +277,7 @@ void BFMDemodGUI::on_clearData_clicked(bool checked __attribute__((unused))) { if (ui->rds->isChecked()) { - m_rdsParser.clearAllFields(); + m_bfmDemod->getRDSParser().clearAllFields(); ui->g14ProgServiceNames->clear(); ui->g14MappedFrequencies->clear(); @@ -298,9 +298,9 @@ void BFMDemodGUI::on_g14ProgServiceNames_currentIndexChanged(int _index) if (index < m_g14ComboIndex.size()) { unsigned int piKey = m_g14ComboIndex[index]; - RDSParser::freqs_map_t::const_iterator mIt = m_rdsParser.m_g14_mapped_freqs.find(piKey); + RDSParser::freqs_map_t::const_iterator mIt = m_bfmDemod->getRDSParser().m_g14_mapped_freqs.find(piKey); - if (mIt != m_rdsParser.m_g14_mapped_freqs.end()) + if (mIt != m_bfmDemod->getRDSParser().m_g14_mapped_freqs.end()) { ui->g14MappedFrequencies->clear(); RDSParser::freqs_set_t::iterator sIt = (mIt->second).begin(); @@ -316,9 +316,9 @@ void BFMDemodGUI::on_g14ProgServiceNames_currentIndexChanged(int _index) ui->g14MappedFrequencies->setEnabled(ui->g14MappedFrequencies->count() > 0); } - mIt = m_rdsParser.m_g14_alt_freqs.find(piKey); + mIt = m_bfmDemod->getRDSParser().m_g14_alt_freqs.find(piKey); - if (mIt != m_rdsParser.m_g14_alt_freqs.end()) + if (mIt != m_bfmDemod->getRDSParser().m_g14_alt_freqs.end()) { ui->g14AltFrequencies->clear(); RDSParser::freqs_set_t::iterator sIt = (mIt->second).begin(); @@ -387,7 +387,7 @@ BFMDemodGUI::BFMDemodGUI(PluginAPI* pluginAPI, DeviceSourceAPI *deviceAPI, QWidg connect(this, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(onMenuDialogCalled(const QPoint &))); m_spectrumVis = new SpectrumVis(ui->glSpectrum); - m_bfmDemod = new BFMDemod(m_spectrumVis, &m_rdsParser); + m_bfmDemod = new BFMDemod(m_deviceAPI, m_spectrumVis); m_channelizer = new DownChannelizer(m_bfmDemod); m_threadedChannelizer = new ThreadedBasebandSampleSink(m_channelizer, this); connect(m_channelizer, SIGNAL(inputSampleRateChanged()), this, SLOT(channelSampleRateChanged())); @@ -550,29 +550,29 @@ void BFMDemodGUI::channelSampleRateChanged() void BFMDemodGUI::rdsUpdateFixedFields() { - ui->g00Label->setText(m_rdsParser.rds_group_acronym_tags[0].c_str()); - ui->g01Label->setText(m_rdsParser.rds_group_acronym_tags[1].c_str()); - ui->g02Label->setText(m_rdsParser.rds_group_acronym_tags[2].c_str()); - ui->g03Label->setText(m_rdsParser.rds_group_acronym_tags[3].c_str()); - ui->g04Label->setText(m_rdsParser.rds_group_acronym_tags[4].c_str()); - //ui->g05Label->setText(m_rdsParser.rds_group_acronym_tags[5].c_str()); - //ui->g06Label->setText(m_rdsParser.rds_group_acronym_tags[6].c_str()); - //ui->g07Label->setText(m_rdsParser.rds_group_acronym_tags[7].c_str()); - ui->g08Label->setText(m_rdsParser.rds_group_acronym_tags[8].c_str()); - ui->g09Label->setText(m_rdsParser.rds_group_acronym_tags[9].c_str()); - ui->g14Label->setText(m_rdsParser.rds_group_acronym_tags[14].c_str()); + ui->g00Label->setText(m_bfmDemod->getRDSParser().rds_group_acronym_tags[0].c_str()); + ui->g01Label->setText(m_bfmDemod->getRDSParser().rds_group_acronym_tags[1].c_str()); + ui->g02Label->setText(m_bfmDemod->getRDSParser().rds_group_acronym_tags[2].c_str()); + ui->g03Label->setText(m_bfmDemod->getRDSParser().rds_group_acronym_tags[3].c_str()); + ui->g04Label->setText(m_bfmDemod->getRDSParser().rds_group_acronym_tags[4].c_str()); + //ui->g05Label->setText(m_bfmDemod->getRDSParser().rds_group_acronym_tags[5].c_str()); + //ui->g06Label->setText(m_bfmDemod->getRDSParser().rds_group_acronym_tags[6].c_str()); + //ui->g07Label->setText(m_bfmDemod->getRDSParser().rds_group_acronym_tags[7].c_str()); + ui->g08Label->setText(m_bfmDemod->getRDSParser().rds_group_acronym_tags[8].c_str()); + ui->g09Label->setText(m_bfmDemod->getRDSParser().rds_group_acronym_tags[9].c_str()); + ui->g14Label->setText(m_bfmDemod->getRDSParser().rds_group_acronym_tags[14].c_str()); - ui->g00CountLabel->setText(m_rdsParser.rds_group_acronym_tags[0].c_str()); - ui->g01CountLabel->setText(m_rdsParser.rds_group_acronym_tags[1].c_str()); - ui->g02CountLabel->setText(m_rdsParser.rds_group_acronym_tags[2].c_str()); - ui->g03CountLabel->setText(m_rdsParser.rds_group_acronym_tags[3].c_str()); - ui->g04CountLabel->setText(m_rdsParser.rds_group_acronym_tags[4].c_str()); - ui->g05CountLabel->setText(m_rdsParser.rds_group_acronym_tags[5].c_str()); - ui->g06CountLabel->setText(m_rdsParser.rds_group_acronym_tags[6].c_str()); - ui->g07CountLabel->setText(m_rdsParser.rds_group_acronym_tags[7].c_str()); - ui->g08CountLabel->setText(m_rdsParser.rds_group_acronym_tags[8].c_str()); - ui->g09CountLabel->setText(m_rdsParser.rds_group_acronym_tags[9].c_str()); - ui->g14CountLabel->setText(m_rdsParser.rds_group_acronym_tags[14].c_str()); + ui->g00CountLabel->setText(m_bfmDemod->getRDSParser().rds_group_acronym_tags[0].c_str()); + ui->g01CountLabel->setText(m_bfmDemod->getRDSParser().rds_group_acronym_tags[1].c_str()); + ui->g02CountLabel->setText(m_bfmDemod->getRDSParser().rds_group_acronym_tags[2].c_str()); + ui->g03CountLabel->setText(m_bfmDemod->getRDSParser().rds_group_acronym_tags[3].c_str()); + ui->g04CountLabel->setText(m_bfmDemod->getRDSParser().rds_group_acronym_tags[4].c_str()); + ui->g05CountLabel->setText(m_bfmDemod->getRDSParser().rds_group_acronym_tags[5].c_str()); + ui->g06CountLabel->setText(m_bfmDemod->getRDSParser().rds_group_acronym_tags[6].c_str()); + ui->g07CountLabel->setText(m_bfmDemod->getRDSParser().rds_group_acronym_tags[7].c_str()); + ui->g08CountLabel->setText(m_bfmDemod->getRDSParser().rds_group_acronym_tags[8].c_str()); + ui->g09CountLabel->setText(m_bfmDemod->getRDSParser().rds_group_acronym_tags[9].c_str()); + ui->g14CountLabel->setText(m_bfmDemod->getRDSParser().rds_group_acronym_tags[14].c_str()); } void BFMDemodGUI::rdsUpdate(bool force) @@ -591,21 +591,21 @@ void BFMDemodGUI::rdsUpdate(bool force) } // PI group - if (m_rdsParser.m_pi_updated || force) + if (m_bfmDemod->getRDSParser().m_pi_updated || force) { ui->piLabel->setStyleSheet("QLabel { background-color : green; }"); - ui->piCountText->setNum((int) m_rdsParser.m_pi_count); - QString pistring(str(boost::format("%04X") % m_rdsParser.m_pi_program_identification).c_str()); + ui->piCountText->setNum((int) m_bfmDemod->getRDSParser().m_pi_count); + QString pistring(str(boost::format("%04X") % m_bfmDemod->getRDSParser().m_pi_program_identification).c_str()); ui->piText->setText(pistring); - if (m_rdsParser.m_pi_traffic_program) { + if (m_bfmDemod->getRDSParser().m_pi_traffic_program) { ui->piTPIndicator->setStyleSheet("QLabel { background-color : green; }"); } else { ui->piTPIndicator->setStyleSheet("QLabel { background:rgb(79,79,79); }"); } - ui->piType->setText(QString(m_rdsParser.pty_table[m_rdsParser.m_pi_program_type].c_str())); - ui->piCoverage->setText(QString(m_rdsParser.coverage_area_codes[m_rdsParser.m_pi_area_coverage_index].c_str())); + ui->piType->setText(QString(m_bfmDemod->getRDSParser().pty_table[m_bfmDemod->getRDSParser().m_pi_program_type].c_str())); + ui->piCoverage->setText(QString(m_bfmDemod->getRDSParser().coverage_area_codes[m_bfmDemod->getRDSParser().m_pi_area_coverage_index].c_str())); } else { @@ -613,29 +613,29 @@ void BFMDemodGUI::rdsUpdate(bool force) } // G0 group - if (m_rdsParser.m_g0_updated || force) + if (m_bfmDemod->getRDSParser().m_g0_updated || force) { ui->g00Label->setStyleSheet("QLabel { background-color : green; }"); - ui->g00CountText->setNum((int) m_rdsParser.m_g0_count); + ui->g00CountText->setNum((int) m_bfmDemod->getRDSParser().m_g0_count); - if (m_rdsParser.m_g0_psn_bitmap == 0b1111) { - ui->g00ProgServiceName->setText(QString(m_rdsParser.m_g0_program_service_name)); + if (m_bfmDemod->getRDSParser().m_g0_psn_bitmap == 0b1111) { + ui->g00ProgServiceName->setText(QString(m_bfmDemod->getRDSParser().m_g0_program_service_name)); } - if (m_rdsParser.m_g0_traffic_announcement) { + if (m_bfmDemod->getRDSParser().m_g0_traffic_announcement) { ui->g00TrafficAnnouncement->setStyleSheet("QLabel { background-color : green; }"); } else { ui->g00TrafficAnnouncement->setStyleSheet("QLabel { background:rgb(79,79,79); }"); } - ui->g00MusicSpeech->setText(QString((m_rdsParser.m_g0_music_speech ? "Music" : "Speech"))); - ui->g00MonoStereo->setText(QString((m_rdsParser.m_g0_mono_stereo ? "Mono" : "Stereo"))); + ui->g00MusicSpeech->setText(QString((m_bfmDemod->getRDSParser().m_g0_music_speech ? "Music" : "Speech"))); + ui->g00MonoStereo->setText(QString((m_bfmDemod->getRDSParser().m_g0_mono_stereo ? "Mono" : "Stereo"))); - if (m_rdsParser.m_g0_af_updated) + if (m_bfmDemod->getRDSParser().m_g0_af_updated) { ui->g00AltFrequenciesBox->clear(); - for (std::set::iterator it = m_rdsParser.m_g0_alt_freq.begin(); it != m_rdsParser.m_g0_alt_freq.end(); ++it) + for (std::set::iterator it = m_bfmDemod->getRDSParser().m_g0_alt_freq.begin(); it != m_bfmDemod->getRDSParser().m_g0_alt_freq.end(); ++it) { if (*it > 76.0) { @@ -654,20 +654,20 @@ void BFMDemodGUI::rdsUpdate(bool force) } // G1 group - if (m_rdsParser.m_g1_updated || force) + if (m_bfmDemod->getRDSParser().m_g1_updated || force) { ui->g01Label->setStyleSheet("QLabel { background-color : green; }"); - ui->g01CountText->setNum((int) m_rdsParser.m_g1_count); + ui->g01CountText->setNum((int) m_bfmDemod->getRDSParser().m_g1_count); - if ((m_rdsParser.m_g1_country_page_index >= 0) && (m_rdsParser.m_g1_country_index >= 0)) { - ui->g01CountryCode->setText(QString((m_rdsParser.pi_country_codes[m_rdsParser.m_g1_country_page_index][m_rdsParser.m_g1_country_index]).c_str())); + if ((m_bfmDemod->getRDSParser().m_g1_country_page_index >= 0) && (m_bfmDemod->getRDSParser().m_g1_country_index >= 0)) { + ui->g01CountryCode->setText(QString((m_bfmDemod->getRDSParser().pi_country_codes[m_bfmDemod->getRDSParser().m_g1_country_page_index][m_bfmDemod->getRDSParser().m_g1_country_index]).c_str())); } - if (m_rdsParser.m_g1_language_index >= 0) { - ui->g01Language->setText(QString(m_rdsParser.language_codes[m_rdsParser.m_g1_language_index].c_str())); + if (m_bfmDemod->getRDSParser().m_g1_language_index >= 0) { + ui->g01Language->setText(QString(m_bfmDemod->getRDSParser().language_codes[m_bfmDemod->getRDSParser().m_g1_language_index].c_str())); } - ui->g01DHM->setText(QString(str(boost::format("%id:%i:%i") % m_rdsParser.m_g1_pin_day % m_rdsParser.m_g1_pin_hour % m_rdsParser.m_g1_pin_minute).c_str())); + ui->g01DHM->setText(QString(str(boost::format("%id:%i:%i") % m_bfmDemod->getRDSParser().m_g1_pin_day % m_bfmDemod->getRDSParser().m_g1_pin_hour % m_bfmDemod->getRDSParser().m_g1_pin_minute).c_str())); } else { @@ -675,11 +675,11 @@ void BFMDemodGUI::rdsUpdate(bool force) } // G2 group - if (m_rdsParser.m_g2_updated || force) + if (m_bfmDemod->getRDSParser().m_g2_updated || force) { ui->g02Label->setStyleSheet("QLabel { background-color : green; }"); - ui->g02CountText->setNum((int) m_rdsParser.m_g2_count); - ui->go2Text->setText(QString(m_rdsParser.m_g2_radiotext)); + ui->g02CountText->setNum((int) m_bfmDemod->getRDSParser().m_g2_count); + ui->go2Text->setText(QString(m_bfmDemod->getRDSParser().m_g2_radiotext)); } else { @@ -687,11 +687,11 @@ void BFMDemodGUI::rdsUpdate(bool force) } // G3 group - if (m_rdsParser.m_g3_updated || force) + if (m_bfmDemod->getRDSParser().m_g3_updated || force) { ui->g03Label->setStyleSheet("QLabel { background-color : green; }"); - ui->g03CountText->setNum((int) m_rdsParser.m_g3_count); - std::string g3str = str(boost::format("%02X%c %04X %04X") % m_rdsParser.m_g3_appGroup % (m_rdsParser.m_g3_groupB ? 'B' : 'A') % m_rdsParser.m_g3_message % m_rdsParser.m_g3_aid); + ui->g03CountText->setNum((int) m_bfmDemod->getRDSParser().m_g3_count); + std::string g3str = str(boost::format("%02X%c %04X %04X") % m_bfmDemod->getRDSParser().m_g3_appGroup % (m_bfmDemod->getRDSParser().m_g3_groupB ? 'B' : 'A') % m_bfmDemod->getRDSParser().m_g3_message % m_bfmDemod->getRDSParser().m_g3_aid); ui->g03Data->setText(QString(g3str.c_str())); } else @@ -700,12 +700,12 @@ void BFMDemodGUI::rdsUpdate(bool force) } // G4 group - if (m_rdsParser.m_g4_updated || force) + if (m_bfmDemod->getRDSParser().m_g4_updated || force) { ui->g04Label->setStyleSheet("QLabel { background-color : green; }"); - ui->g04CountText->setNum((int) m_rdsParser.m_g4_count); + ui->g04CountText->setNum((int) m_bfmDemod->getRDSParser().m_g4_count); std::string time = str(boost::format("%02i.%02i.%4i, %02i:%02i (%+.1fh)")\ - % m_rdsParser.m_g4_day % m_rdsParser.m_g4_month % (1900 + m_rdsParser.m_g4_year) % m_rdsParser.m_g4_hours % m_rdsParser.m_g4_minutes % m_rdsParser.m_g4_local_time_offset); + % m_bfmDemod->getRDSParser().m_g4_day % m_bfmDemod->getRDSParser().m_g4_month % (1900 + m_bfmDemod->getRDSParser().m_g4_year) % m_bfmDemod->getRDSParser().m_g4_hours % m_bfmDemod->getRDSParser().m_g4_minutes % m_bfmDemod->getRDSParser().m_g4_local_time_offset); ui->g04Time->setText(QString(time.c_str())); } else @@ -714,42 +714,42 @@ void BFMDemodGUI::rdsUpdate(bool force) } // G5 group - if (m_rdsParser.m_g5_updated || force) + if (m_bfmDemod->getRDSParser().m_g5_updated || force) { - ui->g05CountText->setNum((int) m_rdsParser.m_g5_count); + ui->g05CountText->setNum((int) m_bfmDemod->getRDSParser().m_g5_count); } // G6 group - if (m_rdsParser.m_g6_updated || force) + if (m_bfmDemod->getRDSParser().m_g6_updated || force) { - ui->g06CountText->setNum((int) m_rdsParser.m_g6_count); + ui->g06CountText->setNum((int) m_bfmDemod->getRDSParser().m_g6_count); } // G7 group - if (m_rdsParser.m_g7_updated || force) + if (m_bfmDemod->getRDSParser().m_g7_updated || force) { - ui->g07CountText->setNum((int) m_rdsParser.m_g7_count); + ui->g07CountText->setNum((int) m_bfmDemod->getRDSParser().m_g7_count); } // G8 group - if (m_rdsParser.m_g8_updated || force) + if (m_bfmDemod->getRDSParser().m_g8_updated || force) { ui->g08Label->setStyleSheet("QLabel { background-color : green; }"); - ui->g08CountText->setNum((int) m_rdsParser.m_g8_count); + ui->g08CountText->setNum((int) m_bfmDemod->getRDSParser().m_g8_count); std::ostringstream os; - os << (m_rdsParser.m_g8_sign ? "-" : "+") << m_rdsParser.m_g8_extent + 1; + os << (m_bfmDemod->getRDSParser().m_g8_sign ? "-" : "+") << m_bfmDemod->getRDSParser().m_g8_extent + 1; ui->g08Extent->setText(QString(os.str().c_str())); - int event_line = RDSTMC::get_tmc_event_code_index(m_rdsParser.m_g8_event, 1); + int event_line = RDSTMC::get_tmc_event_code_index(m_bfmDemod->getRDSParser().m_g8_event, 1); ui->g08TMCEvent->setText(QString(RDSTMC::get_tmc_events(event_line, 1).c_str())); - QString pistring(str(boost::format("%04X") % m_rdsParser.m_g8_location).c_str()); + QString pistring(str(boost::format("%04X") % m_bfmDemod->getRDSParser().m_g8_location).c_str()); ui->g08Location->setText(pistring); - if (m_rdsParser.m_g8_label_index >= 0) { - ui->g08Description->setText(QString(m_rdsParser.label_descriptions[m_rdsParser.m_g8_label_index].c_str())); + if (m_bfmDemod->getRDSParser().m_g8_label_index >= 0) { + ui->g08Description->setText(QString(m_bfmDemod->getRDSParser().label_descriptions[m_bfmDemod->getRDSParser().m_g8_label_index].c_str())); } - ui->g08Content->setNum(m_rdsParser.m_g8_content); + ui->g08Content->setNum(m_bfmDemod->getRDSParser().m_g8_content); } else { @@ -757,11 +757,11 @@ void BFMDemodGUI::rdsUpdate(bool force) } // G9 group - if (m_rdsParser.m_g9_updated || force) + if (m_bfmDemod->getRDSParser().m_g9_updated || force) { ui->g09Label->setStyleSheet("QLabel { background-color : green; }"); - ui->g09CountText->setNum((int) m_rdsParser.m_g9_count); - std::string g9str = str(boost::format("%02X %04X %04X %02X %04X") % m_rdsParser.m_g9_varA % m_rdsParser.m_g9_cA % m_rdsParser.m_g9_dA % m_rdsParser.m_g9_varB % m_rdsParser.m_g9_dB); + ui->g09CountText->setNum((int) m_bfmDemod->getRDSParser().m_g9_count); + std::string g9str = str(boost::format("%02X %04X %04X %02X %04X") % m_bfmDemod->getRDSParser().m_g9_varA % m_bfmDemod->getRDSParser().m_g9_cA % m_bfmDemod->getRDSParser().m_g9_dA % m_bfmDemod->getRDSParser().m_g9_varB % m_bfmDemod->getRDSParser().m_g9_dB); ui->g09Data->setText(QString(g9str.c_str())); } else @@ -770,18 +770,18 @@ void BFMDemodGUI::rdsUpdate(bool force) } // G14 group - if (m_rdsParser.m_g14_updated || force) + if (m_bfmDemod->getRDSParser().m_g14_updated || force) { - ui->g14CountText->setNum((int) m_rdsParser.m_g14_count); + ui->g14CountText->setNum((int) m_bfmDemod->getRDSParser().m_g14_count); - if (m_rdsParser.m_g14_data_available) + if (m_bfmDemod->getRDSParser().m_g14_data_available) { ui->g14Label->setStyleSheet("QLabel { background-color : green; }"); m_g14ComboIndex.clear(); ui->g14ProgServiceNames->clear(); - RDSParser::psns_map_t::iterator it = m_rdsParser.m_g14_program_service_names.begin(); - const RDSParser::psns_map_t::iterator itEnd = m_rdsParser.m_g14_program_service_names.end(); + RDSParser::psns_map_t::iterator it = m_bfmDemod->getRDSParser().m_g14_program_service_names.begin(); + const RDSParser::psns_map_t::iterator itEnd = m_bfmDemod->getRDSParser().m_g14_program_service_names.end(); int i = 0; for (; it != itEnd; ++it, i++) @@ -797,7 +797,7 @@ void BFMDemodGUI::rdsUpdate(bool force) } } - m_rdsParser.clearUpdateFlags(); + m_bfmDemod->getRDSParser().clearUpdateFlags(); } void BFMDemodGUI::changeFrequency(qint64 f) diff --git a/plugins/channelrx/demodbfm/bfmdemodgui.h b/plugins/channelrx/demodbfm/bfmdemodgui.h index 126d80e6d..11c623f53 100644 --- a/plugins/channelrx/demodbfm/bfmdemodgui.h +++ b/plugins/channelrx/demodbfm/bfmdemodgui.h @@ -24,10 +24,9 @@ #include "dsp/movingaverage.h" #include "util/messagequeue.h" -#include "rdsparser.h" - class PluginAPI; class DeviceSourceAPI; +class RDSParser; class ThreadedBasebandSampleSink; class DownChannelizer; @@ -91,7 +90,6 @@ private: ThreadedBasebandSampleSink* m_threadedChannelizer; DownChannelizer* m_channelizer; SpectrumVis* m_spectrumVis; - RDSParser m_rdsParser; BFMDemod* m_bfmDemod; MovingAverage m_channelPowerDbAvg; From b646d0c89f695c03560461eb0984a0bf2e67ab73 Mon Sep 17 00:00:00 2001 From: f4exb Date: Sun, 1 Oct 2017 12:48:31 +0200 Subject: [PATCH 46/71] BFM demod: GUI and demod separation --- plugins/channelrx/demodbfm/bfmdemod.cpp | 28 +++++++-- plugins/channelrx/demodbfm/bfmdemod.h | 53 ++++++++++++++++- plugins/channelrx/demodbfm/bfmdemodgui.cpp | 68 +++++++++++++++------- plugins/channelrx/demodbfm/bfmdemodgui.h | 6 +- plugins/channelrx/demodbfm/bfmplugin.cpp | 2 +- 5 files changed, 126 insertions(+), 31 deletions(-) diff --git a/plugins/channelrx/demodbfm/bfmdemod.cpp b/plugins/channelrx/demodbfm/bfmdemod.cpp index 6e612e2ee..e0c0537d3 100644 --- a/plugins/channelrx/demodbfm/bfmdemod.cpp +++ b/plugins/channelrx/demodbfm/bfmdemod.cpp @@ -15,29 +15,30 @@ // along with this program. If not, see . // /////////////////////////////////////////////////////////////////////////////////// -#include "../../channelrx/demodbfm/bfmdemod.h" - #include #include #include #include + #include "audio/audiooutput.h" #include "dsp/dspengine.h" #include "dsp/pidcontroller.h" -#include "bfmdemod.h" - #include +#include "dsp/threadedbasebandsamplesink.h" +#include "device/devicesourceapi.h" #include "rdsparser.h" +#include "bfmdemod.h" +MESSAGE_CLASS_DEFINITION(BFMDemod::MsgConfigureChannelizer, Message) +MESSAGE_CLASS_DEFINITION(BFMDemod::MsgReportChannelSampleRateChanged, Message) MESSAGE_CLASS_DEFINITION(BFMDemod::MsgConfigureBFMDemod, Message) const Real BFMDemod::default_deemphasis = 50.0; // 50 us const int BFMDemod::m_udpBlockSize = 512; -BFMDemod::BFMDemod(DeviceSourceAPI *deviceAPI, BasebandSampleSink* sampleSink) : +BFMDemod::BFMDemod(DeviceSourceAPI *deviceAPI) : m_deviceAPI(deviceAPI), - m_sampleSink(sampleSink), m_audioFifo(250000), m_settingsMutex(QMutex::Recursive), m_pilotPLL(19000/384000, 50/384000, 0.01), @@ -47,6 +48,11 @@ BFMDemod::BFMDemod(DeviceSourceAPI *deviceAPI, BasebandSampleSink* sampleSink) : { setObjectName("BFMDemod"); + m_channelizer = new DownChannelizer(this); + m_threadedChannelizer = new ThreadedBasebandSampleSink(m_channelizer, this); + connect(m_channelizer, SIGNAL(inputSampleRateChanged()), this, SLOT(channelSampleRateChanged())); + m_deviceAPI->addThreadedSink(m_threadedChannelizer); + m_config.m_inputSampleRate = 384000; m_config.m_inputFrequencyOffset = 0; m_config.m_rfBandwidth = 180000; @@ -83,6 +89,10 @@ BFMDemod::~BFMDemod() DSPEngine::instance()->removeAudioSink(&m_audioFifo); delete m_udpBufferAudio; + + m_deviceAPI->removeThreadedSink(m_threadedChannelizer); + delete m_threadedChannelizer; + delete m_channelizer; } void BFMDemod::configure(MessageQueue* messageQueue, @@ -310,6 +320,12 @@ void BFMDemod::stop() { } +void BFMDemod::channelSampleRateChanged() +{ + MsgReportChannelSampleRateChanged *msg = MsgReportChannelSampleRateChanged::create(getSampleRate()); + getMessageQueueToGUI()->push(msg); +} + bool BFMDemod::handleMessage(const Message& cmd) { if (DownChannelizer::MsgChannelizerNotification::match(cmd)) diff --git a/plugins/channelrx/demodbfm/bfmdemod.h b/plugins/channelrx/demodbfm/bfmdemod.h index 484bd9d47..0d9322246 100644 --- a/plugins/channelrx/demodbfm/bfmdemod.h +++ b/plugins/channelrx/demodbfm/bfmdemod.h @@ -38,11 +38,57 @@ #include "rdsdemod.h" class DeviceSourceAPI; +class ThreadedBasebandSampleSink; +class DownChannelizer; class BFMDemod : public BasebandSampleSink { public: - BFMDemod(DeviceSourceAPI *deviceAPI, BasebandSampleSink* sampleSink); + class MsgConfigureChannelizer : public Message { + MESSAGE_CLASS_DECLARATION + + public: + int getSampleRate() const { return m_sampleRate; } + int getCenterFrequency() const { return m_centerFrequency; } + + static MsgConfigureChannelizer* create(int sampleRate, int centerFrequency) + { + return new MsgConfigureChannelizer(sampleRate, centerFrequency); + } + + private: + int m_sampleRate; + int m_centerFrequency; + + MsgConfigureChannelizer(int sampleRate, int centerFrequency) : + Message(), + m_sampleRate(sampleRate), + m_centerFrequency(centerFrequency) + { } + }; + + class MsgReportChannelSampleRateChanged : public Message { + MESSAGE_CLASS_DECLARATION + + public: + int getSampleRate() const { return m_sampleRate; } + + static MsgReportChannelSampleRateChanged* create(int sampleRate) + { + return new MsgReportChannelSampleRateChanged(sampleRate); + } + + private: + int m_sampleRate; + + MsgReportChannelSampleRateChanged(int sampleRate) : + Message(), + m_sampleRate(sampleRate) + { } + }; + + BFMDemod(DeviceSourceAPI *deviceAPI); virtual ~BFMDemod(); + void setSampleSink(BasebandSampleSink* sampleSink) { m_sampleSink = sampleSink; } void configure(MessageQueue* messageQueue, Real rfBandwidth, @@ -88,6 +134,9 @@ public: RDSParser& getRDSParser() { return m_rdsParser; } +private slots: + void channelSampleRateChanged(); + private: class MsgConfigureBFMDemod : public Message { MESSAGE_CLASS_DECLARATION @@ -218,6 +267,8 @@ private: Config m_running; DeviceSourceAPI *m_deviceAPI; + ThreadedBasebandSampleSink* m_threadedChannelizer; + DownChannelizer* m_channelizer; NCO m_nco; Interpolator m_interpolator; //!< Interpolator between fixed demod bandwidth and audio bandwidth (rational) diff --git a/plugins/channelrx/demodbfm/bfmdemodgui.cpp b/plugins/channelrx/demodbfm/bfmdemodgui.cpp index a9a824f49..34967179d 100644 --- a/plugins/channelrx/demodbfm/bfmdemodgui.cpp +++ b/plugins/channelrx/demodbfm/bfmdemodgui.cpp @@ -201,11 +201,38 @@ bool BFMDemodGUI::deserialize(const QByteArray& data) } } -bool BFMDemodGUI::handleMessage(const Message& message __attribute__((unused))) +bool BFMDemodGUI::handleMessage(const Message& message) { - return false; + if (BFMDemod::MsgReportChannelSampleRateChanged::match(message)) + { + BFMDemod::MsgReportChannelSampleRateChanged& report = (BFMDemod::MsgReportChannelSampleRateChanged&) message; + m_rate = report.getSampleRate(); + ui->glSpectrum->setCenterFrequency(m_rate / 4); + ui->glSpectrum->setSampleRate(m_rate / 2); + return true; + } + else + { + return false; + } } +void BFMDemodGUI::handleInputMessages() +{ + Message* message; + + while ((message = getInputMessageQueue()->pop()) != 0) + { + qDebug("BFMDemodGUI::handleInputMessages: message: %s", message->getIdentifier()); + + if (handleMessage(*message)) + { + delete message; + } + } +} + + void BFMDemodGUI::channelMarkerChanged() { this->setWindowTitle(m_channelMarker.getTitle()); @@ -385,13 +412,16 @@ BFMDemodGUI::BFMDemodGUI(PluginAPI* pluginAPI, DeviceSourceAPI *deviceAPI, QWidg setAttribute(Qt::WA_DeleteOnClose, true); connect(this, SIGNAL(widgetRolled(QWidget*,bool)), this, SLOT(onWidgetRolled(QWidget*,bool))); connect(this, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(onMenuDialogCalled(const QPoint &))); + connect(getInputMessageQueue(), SIGNAL(messageEnqueued()), this, SLOT(handleInputMessages())); m_spectrumVis = new SpectrumVis(ui->glSpectrum); - m_bfmDemod = new BFMDemod(m_deviceAPI, m_spectrumVis); - m_channelizer = new DownChannelizer(m_bfmDemod); - m_threadedChannelizer = new ThreadedBasebandSampleSink(m_channelizer, this); - connect(m_channelizer, SIGNAL(inputSampleRateChanged()), this, SLOT(channelSampleRateChanged())); - m_deviceAPI->addThreadedSink(m_threadedChannelizer); + m_bfmDemod = new BFMDemod(m_deviceAPI); + m_bfmDemod->setMessageQueueToGUI(getInputMessageQueue()); + m_bfmDemod->setSampleSink(m_spectrumVis); +// m_channelizer = new DownChannelizer(m_bfmDemod); +// m_threadedChannelizer = new ThreadedBasebandSampleSink(m_channelizer, this); +// connect(m_channelizer, SIGNAL(inputSampleRateChanged()), this, SLOT(channelSampleRateChanged())); +// m_deviceAPI->addThreadedSink(m_threadedChannelizer); ui->glSpectrum->setCenterFrequency(m_rate / 4); ui->glSpectrum->setSampleRate(m_rate / 2); @@ -432,9 +462,9 @@ BFMDemodGUI::BFMDemodGUI(PluginAPI* pluginAPI, DeviceSourceAPI *deviceAPI, QWidg BFMDemodGUI::~BFMDemodGUI() { m_deviceAPI->removeChannelInstance(this); - m_deviceAPI->removeThreadedSink(m_threadedChannelizer); - delete m_threadedChannelizer; - delete m_channelizer; +// m_deviceAPI->removeThreadedSink(m_threadedChannelizer); +// delete m_threadedChannelizer; +// delete m_channelizer; delete m_bfmDemod; //delete m_channelMarker; delete ui; @@ -456,9 +486,14 @@ void BFMDemodGUI::applySettings(bool force) { setTitleColor(m_channelMarker.getColor()); - m_channelizer->configure(m_channelizer->getInputMessageQueue(), - requiredBW(m_rfBW[ui->rfBW->value()]), // TODO: this is where requested sample rate is specified - m_channelMarker.getCenterFrequency()); + BFMDemod::MsgConfigureChannelizer *message = BFMDemod::MsgConfigureChannelizer::create( + requiredBW(m_rfBW[ui->rfBW->value()]), + m_channelMarker.getCenterFrequency()); + m_bfmDemod->getInputMessageQueue()->push(message); + +// m_channelizer->configure(m_channelizer->getInputMessageQueue(), +// requiredBW(m_rfBW[ui->rfBW->value()]), // TODO: this is where requested sample rate is specified +// m_channelMarker.getCenterFrequency()); ui->deltaFrequency->setValue(m_channelMarker.getCenterFrequency()); @@ -541,13 +576,6 @@ void BFMDemodGUI::tick() //qDebug() << "Pilot lock: " << m_bfmDemod->getPilotLock() << ":" << m_bfmDemod->getPilotLevel(); TODO: update a GUI item with status } -void BFMDemodGUI::channelSampleRateChanged() -{ - m_rate = m_bfmDemod->getSampleRate(); - ui->glSpectrum->setCenterFrequency(m_rate / 4); - ui->glSpectrum->setSampleRate(m_rate / 2); -} - void BFMDemodGUI::rdsUpdateFixedFields() { ui->g00Label->setText(m_bfmDemod->getRDSParser().rds_group_acronym_tags[0].c_str()); diff --git a/plugins/channelrx/demodbfm/bfmdemodgui.h b/plugins/channelrx/demodbfm/bfmdemodgui.h index 11c623f53..611a1af6f 100644 --- a/plugins/channelrx/demodbfm/bfmdemodgui.h +++ b/plugins/channelrx/demodbfm/bfmdemodgui.h @@ -59,7 +59,6 @@ public: private slots: void channelMarkerChanged(); - void channelSampleRateChanged(); void on_deltaFrequency_changed(qint64 value); void on_rfBW_valueChanged(int value); void on_afBW_valueChanged(int value); @@ -77,6 +76,7 @@ private slots: void on_g14AltFrequencies_activated(int index); void onWidgetRolled(QWidget* widget, bool rollDown); void onMenuDialogCalled(const QPoint& p); + void handleInputMessages(); void tick(); private: @@ -87,8 +87,8 @@ private: bool m_doApplySettings; int m_rdsTimerCount; - ThreadedBasebandSampleSink* m_threadedChannelizer; - DownChannelizer* m_channelizer; +// ThreadedBasebandSampleSink* m_threadedChannelizer; +// DownChannelizer* m_channelizer; SpectrumVis* m_spectrumVis; BFMDemod* m_bfmDemod; diff --git a/plugins/channelrx/demodbfm/bfmplugin.cpp b/plugins/channelrx/demodbfm/bfmplugin.cpp index 153984c0c..9aee0f780 100644 --- a/plugins/channelrx/demodbfm/bfmplugin.cpp +++ b/plugins/channelrx/demodbfm/bfmplugin.cpp @@ -24,7 +24,7 @@ const PluginDescriptor BFMPlugin::m_pluginDescriptor = { QString("Broadcast FM Demodulator"), - QString("3.6.1"), + QString("3.7.3"), QString("(c) Edouard Griffiths, F4EXB"), QString("https://github.com/f4exb/sdrangel"), true, From f10d486b289f755f8b9d956c125408c581735d4c Mon Sep 17 00:00:00 2001 From: f4exb Date: Sun, 1 Oct 2017 16:02:34 +0200 Subject: [PATCH 47/71] BFM demod: fixed segfault --- plugins/channelrx/demodbfm/bfmdemod.cpp | 30 ++++++++++++++++++------- 1 file changed, 22 insertions(+), 8 deletions(-) diff --git a/plugins/channelrx/demodbfm/bfmdemod.cpp b/plugins/channelrx/demodbfm/bfmdemod.cpp index e0c0537d3..8fb23a96c 100644 --- a/plugins/channelrx/demodbfm/bfmdemod.cpp +++ b/plugins/channelrx/demodbfm/bfmdemod.cpp @@ -48,6 +48,27 @@ BFMDemod::BFMDemod(DeviceSourceAPI *deviceAPI) : { setObjectName("BFMDemod"); + m_magsq = 0.0f; + m_magsqSum = 0.0f; + m_magsqPeak = 0.0f; + m_magsqCount = 0; + + m_squelchLevel = 0; + + m_interpolatorDistance = 0.0f; + m_interpolatorDistanceRemain = 0.0f; + + m_interpolatorRDSDistance = 0.0f; + m_interpolatorRDSDistanceRemain = 0.0f; + + m_interpolatorStereoDistance = 0.0f; + m_interpolatorStereoDistanceRemain = 0.0f; + + m_sampleSink = 0; + m_m1Arg = 0; + + m_rfFilter = new fftfilt(-50000.0 / 384000.0, 50000.0 / 384000.0, filtFftLen); + m_channelizer = new DownChannelizer(this); m_threadedChannelizer = new ThreadedBasebandSampleSink(m_channelizer, this); connect(m_channelizer, SIGNAL(inputSampleRateChanged()), this, SLOT(channelSampleRateChanged())); @@ -62,20 +83,13 @@ BFMDemod::BFMDemod(DeviceSourceAPI *deviceAPI) : m_config.m_audioSampleRate = DSPEngine::instance()->getAudioSampleRate(); // normally 48 kHz m_deemphasisFilterX.configure(default_deemphasis * m_config.m_audioSampleRate * 1.0e-6); m_deemphasisFilterY.configure(default_deemphasis * m_config.m_audioSampleRate * 1.0e-6); - m_rfFilter = new fftfilt(-50000.0 / 384000.0, 50000.0 / 384000.0, filtFftLen); - m_phaseDiscri.setFMScaling(384000/m_fmExcursion); + m_phaseDiscri.setFMScaling(384000/m_fmExcursion); apply(); m_audioBuffer.resize(16384); m_audioBufferFill = 0; -// m_movingAverage.resize(16, 0); - m_magsq = 0.0f; - m_magsqSum = 0.0f; - m_magsqPeak = 0.0f; - m_magsqCount = 0; - DSPEngine::instance()->addAudioSink(&m_audioFifo); m_udpBufferAudio = new UDPSink(this, m_udpBlockSize, m_config.m_udpPort); } From 2b2b0eff8d9e759b40220213b1d6c5cf5c3a4d49 Mon Sep 17 00:00:00 2001 From: f4exb Date: Sun, 1 Oct 2017 16:52:23 +0200 Subject: [PATCH 48/71] Created a Serializable interface for where only the serialization methods are needed from an object. Applied to AM demod channel marker --- plugins/channelrx/demodam/amdemodgui.cpp | 5 ++-- plugins/channelrx/demodam/amdemodsettings.cpp | 17 +++++++++-- plugins/channelrx/demodam/amdemodsettings.h | 5 +++- sdrbase/dsp/channelmarker.h | 7 +++-- sdrbase/settings/serializable.h | 28 +++++++++++++++++++ 5 files changed, 53 insertions(+), 9 deletions(-) create mode 100644 sdrbase/settings/serializable.h diff --git a/plugins/channelrx/demodam/amdemodgui.cpp b/plugins/channelrx/demodam/amdemodgui.cpp index 06c879983..649d5c306 100644 --- a/plugins/channelrx/demodam/amdemodgui.cpp +++ b/plugins/channelrx/demodam/amdemodgui.cpp @@ -104,7 +104,7 @@ void AMDemodGUI::channelMarkerChanged() m_settings.m_udpPort = m_channelMarker.getUDPSendPort(), m_settings.m_rgbColor = m_channelMarker.getColor().rgb(); displayUDPAddress(); - m_settings.m_channelMarkerBytes = m_channelMarker.serialize(); + //m_settings.m_channelMarkerBytes = m_channelMarker.serialize(); applySettings(); } @@ -202,6 +202,7 @@ AMDemodGUI::AMDemodGUI(PluginAPI* pluginAPI, DeviceSourceAPI *deviceAPI, QWidget m_channelMarker.setUDPSendPort(9999); m_channelMarker.setVisible(true); setTitleColor(m_channelMarker.getColor()); + m_settings.setChannelMarker(&m_channelMarker); connect(&m_channelMarker, SIGNAL(changed()), this, SLOT(channelMarkerChanged())); @@ -281,7 +282,7 @@ void AMDemodGUI::updateChannelMarker() { m_channelMarker.blockSignals(true); - m_channelMarker.deserialize(m_settings.m_channelMarkerBytes); + //m_channelMarker.deserialize(m_settings.m_channelMarkerBytes); this->setWindowTitle(m_channelMarker.getTitle()); m_channelMarker.blockSignals(false); diff --git a/plugins/channelrx/demodam/amdemodsettings.cpp b/plugins/channelrx/demodam/amdemodsettings.cpp index 3778e8723..e9a14c14f 100644 --- a/plugins/channelrx/demodam/amdemodsettings.cpp +++ b/plugins/channelrx/demodam/amdemodsettings.cpp @@ -16,9 +16,11 @@ #include "dsp/dspengine.h" #include "util/simpleserializer.h" +#include "settings/serializable.h" #include "amdemodsettings.h" -AMDemodSettings::AMDemodSettings() +AMDemodSettings::AMDemodSettings() : + m_channelMarker(0) { resetToDefaults(); } @@ -45,7 +47,11 @@ QByteArray AMDemodSettings::serialize() const s.writeS32(2, m_rfBandwidth/100); s.writeS32(4, m_volume*10); s.writeS32(5, m_squelch); - s.writeBlob(6, m_channelMarkerBytes); + + if (m_channelMarker) { + s.writeBlob(6, m_channelMarker->serialize()); + } + s.writeU32(7, m_rgbColor); s.writeBool(8, m_bandpassEnable); return s.final(); @@ -74,7 +80,12 @@ bool AMDemodSettings::deserialize(const QByteArray& data) m_volume = tmp * 0.1; d.readS32(5, &tmp, -40); m_squelch = tmp; - d.readBlob(6, &m_channelMarkerBytes); + d.readBlob(6, &bytetmp); + + if (m_channelMarker) { + m_channelMarker->deserialize(bytetmp); + } + d.readU32(7, &m_rgbColor); d.readBool(8, &m_bandpassEnable, false); return true; diff --git a/plugins/channelrx/demodam/amdemodsettings.h b/plugins/channelrx/demodam/amdemodsettings.h index 5652636b7..abbb12556 100644 --- a/plugins/channelrx/demodam/amdemodsettings.h +++ b/plugins/channelrx/demodam/amdemodsettings.h @@ -19,6 +19,8 @@ #include +class Serializable; + struct AMDemodSettings { int m_inputSampleRate; @@ -33,10 +35,11 @@ struct AMDemodSettings QString m_udpAddress; quint16 m_udpPort; quint32 m_rgbColor; - QByteArray m_channelMarkerBytes; + Serializable *m_channelMarker; AMDemodSettings(); void resetToDefaults(); + void setChannelMarker(Serializable *channelMarker) { m_channelMarker = channelMarker; } QByteArray serialize() const; bool deserialize(const QByteArray& data); }; diff --git a/sdrbase/dsp/channelmarker.h b/sdrbase/dsp/channelmarker.h index f64365b5e..8685ac887 100644 --- a/sdrbase/dsp/channelmarker.h +++ b/sdrbase/dsp/channelmarker.h @@ -5,9 +5,10 @@ #include #include +#include "settings/serializable.h" #include "util/export.h" -class SDRANGEL_API ChannelMarker : public QObject { +class SDRANGEL_API ChannelMarker : public QObject, public Serializable { Q_OBJECT public: @@ -76,8 +77,8 @@ public: const QString& getDisplayAddressSend() const { return m_displayAddressSend; } const QString& getDisplayAddressReceive() const { return m_displayAddressReceive; } - QByteArray serialize() const; - bool deserialize(const QByteArray& data); + virtual QByteArray serialize() const; + virtual bool deserialize(const QByteArray& data); protected: static QRgb m_colorTable[]; diff --git a/sdrbase/settings/serializable.h b/sdrbase/settings/serializable.h new file mode 100644 index 000000000..b5a088e74 --- /dev/null +++ b/sdrbase/settings/serializable.h @@ -0,0 +1,28 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2017 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 // +// // +// This program is distributed in the hope that it will be useful, // +// but WITHOUT ANY WARRANTY; without even the implied warranty of // +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // +// GNU General Public License V3 for more details. // +// // +// You should have received a copy of the GNU General Public License // +// along with this program. If not, see . // +/////////////////////////////////////////////////////////////////////////////////// + +#ifndef SDRBASE_SETTINGS_SERIALIZABLE_H_ +#define SDRBASE_SETTINGS_SERIALIZABLE_H_ + +class Serializable +{ +public: + virtual ~Serializable() {} + virtual QByteArray serialize() const = 0; + virtual bool deserialize(const QByteArray& data) = 0; +}; + +#endif /* SDRBASE_SETTINGS_SERIALIZABLE_H_ */ From edd0adde3b577881b09e24db1050baa3f5ae5f5c Mon Sep 17 00:00:00 2001 From: f4exb Date: Sun, 1 Oct 2017 17:54:48 +0200 Subject: [PATCH 49/71] BFM demod: created a settings class --- plugins/channelrx/demodbfm/CMakeLists.txt | 2 + plugins/channelrx/demodbfm/bfmdemodgui.cpp | 17 +- plugins/channelrx/demodbfm/bfmdemodgui.h | 4 +- .../channelrx/demodbfm/bfmdemodsettings.cpp | 151 ++++++++++++++++++ plugins/channelrx/demodbfm/bfmdemodsettings.h | 58 +++++++ plugins/channelrx/demodbfm/demodbfm.pro | 2 + sdrbase/gui/glspectrumgui.h | 7 +- 7 files changed, 226 insertions(+), 15 deletions(-) create mode 100644 plugins/channelrx/demodbfm/bfmdemodsettings.cpp create mode 100644 plugins/channelrx/demodbfm/bfmdemodsettings.h diff --git a/plugins/channelrx/demodbfm/CMakeLists.txt b/plugins/channelrx/demodbfm/CMakeLists.txt index 82de4604d..17f901d0f 100644 --- a/plugins/channelrx/demodbfm/CMakeLists.txt +++ b/plugins/channelrx/demodbfm/CMakeLists.txt @@ -3,6 +3,7 @@ project(bfm) set(bfm_SOURCES bfmdemod.cpp bfmdemodgui.cpp + bfmdemodsettings.cpp bfmplugin.cpp rdsdemod.cpp rdsdecoder.cpp @@ -13,6 +14,7 @@ set(bfm_SOURCES set(bfm_HEADERS bfmdemod.h bfmdemodgui.h + bfmdemodsettings.h bfmplugin.h rdsdemod.h rdsdecoder.h diff --git a/plugins/channelrx/demodbfm/bfmdemodgui.cpp b/plugins/channelrx/demodbfm/bfmdemodgui.cpp index 34967179d..278809dce 100644 --- a/plugins/channelrx/demodbfm/bfmdemodgui.cpp +++ b/plugins/channelrx/demodbfm/bfmdemodgui.cpp @@ -37,16 +37,13 @@ #include "gui/basicchannelsettingsdialog.h" #include "mainwindow.h" +#include "bfmdemodsettings.h" #include "bfmdemod.h" #include "rdstmc.h" #include "ui_bfmdemodgui.h" const QString BFMDemodGUI::m_channelID = "sdrangel.channel.bfm"; -const int BFMDemodGUI::m_rfBW[] = { - 80000, 100000, 120000, 140000, 160000, 180000, 200000, 220000, 250000 -}; - //int requiredBW(int rfBW) //{ // if (rfBW <= 48000) @@ -159,8 +156,8 @@ bool BFMDemodGUI::deserialize(const QByteArray& data) d.readS32(2, &tmp, 4); ui->rfBW->setValue(tmp); - ui->rfBWText->setText(QString("%1 kHz").arg(m_rfBW[tmp] / 1000.0)); - m_channelMarker.setBandwidth(m_rfBW[tmp]); + ui->rfBWText->setText(QString("%1 kHz").arg(BFMDemodSettings::getRFBW(tmp) / 1000.0)); + m_channelMarker.setBandwidth(BFMDemodSettings::getRFBW(tmp)); d.readS32(3, &tmp, 3); ui->afBW->setValue(tmp); @@ -247,8 +244,8 @@ void BFMDemodGUI::on_deltaFrequency_changed(qint64 value) void BFMDemodGUI::on_rfBW_valueChanged(int value) { - ui->rfBWText->setText(QString("%1 kHz").arg(m_rfBW[value] / 1000.0)); - m_channelMarker.setBandwidth(m_rfBW[value]); + ui->rfBWText->setText(QString("%1 kHz").arg(BFMDemodSettings::getRFBW(value) / 1000.0)); + m_channelMarker.setBandwidth(BFMDemodSettings::getRFBW(value)); applySettings(); } @@ -487,7 +484,7 @@ void BFMDemodGUI::applySettings(bool force) setTitleColor(m_channelMarker.getColor()); BFMDemod::MsgConfigureChannelizer *message = BFMDemod::MsgConfigureChannelizer::create( - requiredBW(m_rfBW[ui->rfBW->value()]), + requiredBW(BFMDemodSettings::getRFBW(ui->rfBW->value())), m_channelMarker.getCenterFrequency()); m_bfmDemod->getInputMessageQueue()->push(message); @@ -498,7 +495,7 @@ void BFMDemodGUI::applySettings(bool force) ui->deltaFrequency->setValue(m_channelMarker.getCenterFrequency()); m_bfmDemod->configure(m_bfmDemod->getInputMessageQueue(), - m_rfBW[ui->rfBW->value()], + BFMDemodSettings::getRFBW(ui->rfBW->value()), ui->afBW->value() * 1000.0, ui->volume->value() / 10.0, ui->squelch->value(), diff --git a/plugins/channelrx/demodbfm/bfmdemodgui.h b/plugins/channelrx/demodbfm/bfmdemodgui.h index 611a1af6f..9da69207c 100644 --- a/plugins/channelrx/demodbfm/bfmdemodgui.h +++ b/plugins/channelrx/demodbfm/bfmdemodgui.h @@ -23,6 +23,7 @@ #include "dsp/channelmarker.h" #include "dsp/movingaverage.h" #include "util/messagequeue.h" +#include "bfmdemodsettings.h" class PluginAPI; class DeviceSourceAPI; @@ -84,6 +85,7 @@ private: PluginAPI* m_pluginAPI; DeviceSourceAPI* m_deviceAPI; ChannelMarker m_channelMarker; + BFMDemodSettings m_settings; bool m_doApplySettings; int m_rdsTimerCount; @@ -97,8 +99,6 @@ private: std::vector m_g14ComboIndex; MessageQueue m_inputMessageQueue; - static const int m_rfBW[]; - explicit BFMDemodGUI(PluginAPI* pluginAPI, DeviceSourceAPI *deviceAPI, QWidget* parent = NULL); virtual ~BFMDemodGUI(); diff --git a/plugins/channelrx/demodbfm/bfmdemodsettings.cpp b/plugins/channelrx/demodbfm/bfmdemodsettings.cpp new file mode 100644 index 000000000..2aff8f7ea --- /dev/null +++ b/plugins/channelrx/demodbfm/bfmdemodsettings.cpp @@ -0,0 +1,151 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2017 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 // +// // +// This program is distributed in the hope that it will be useful, // +// but WITHOUT ANY WARRANTY; without even the implied warranty of // +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // +// GNU General Public License V3 for more details. // +// // +// You should have received a copy of the GNU General Public License // +// along with this program. If not, see . // +/////////////////////////////////////////////////////////////////////////////////// + +#include "dsp/dspengine.h" +#include "util/simpleserializer.h" +#include "settings/serializable.h" + +#include "bfmdemodsettings.h" + +const int BFMDemodSettings::m_nbRFBW = 9; +const int BFMDemodSettings::m_rfBW[] = { + 80000, 100000, 120000, 140000, 160000, 180000, 200000, 220000, 250000 +}; + +BFMDemodSettings::BFMDemodSettings() : + m_channelMarker(0), + m_spectrumGUI(0) +{ + resetToDefaults(); +} + +void BFMDemodSettings::resetToDefaults() +{ + m_inputSampleRate = 384000; + m_inputFrequencyOffset = 0; + m_rfBandwidth = getRFBW(4); + m_afBandwidth = 3000; + m_volume = 2.0; + m_squelch = -60.0; + m_audioSampleRate = DSPEngine::instance()->getAudioSampleRate(); + m_audioStereo = false; + m_lsbStereo = false; + m_showPilot = false; + m_rdsActive = false; + m_copyAudioToUDP = false; + m_udpAddress = "127.0.0.1"; + m_udpPort = 9999; +} + +QByteArray BFMDemodSettings::serialize() const +{ + SimpleSerializer s(1); + s.writeS32(1, m_inputFrequencyOffset); + s.writeS32(2, getRFBWIndex(m_rfBandwidth)); + s.writeS32(3, m_afBandwidth/1000.0); + s.writeS32(4, m_volume*10.0); + s.writeS32(5, m_squelch); + s.writeU32(7, m_rgbColor); + + if (m_spectrumGUI) { + s.writeBlob(8, m_spectrumGUI->serialize()); + } + + s.writeBool(9, m_audioStereo); + s.writeBool(10, m_lsbStereo); + + if (m_channelMarker) { + s.writeBlob(11, m_channelMarker->serialize()); + } + + return s.final(); +} + +bool BFMDemodSettings::deserialize(const QByteArray& data) +{ + SimpleDeserializer d(data); + + if(!d.isValid()) + { + resetToDefaults(); + return false; + } + + if(d.getVersion() == 1) + { + QByteArray bytetmp; + qint32 tmp; + QString strtmp; + + d.readS32(1, &tmp, 0); + m_inputFrequencyOffset = tmp; + d.readS32(2, &tmp, 4); + m_rfBandwidth = getRFBW(tmp); + d.readS32(3, &tmp, 3); + m_afBandwidth = tmp * 1000.0; + d.readS32(4, &tmp, 20); + m_volume = tmp * 0.1; + d.readS32(5, &tmp, -60); + m_squelch = tmp; + d.readU32(7, &m_rgbColor); + + d.readBlob(8, &bytetmp); + + if (m_spectrumGUI) { + m_spectrumGUI->deserialize(bytetmp); + } + + d.readBool(9, &m_audioStereo, false); + d.readBool(10, &m_lsbStereo, false); + + d.readBlob(11, &bytetmp); + + if (m_channelMarker) { + m_channelMarker->deserialize(bytetmp); + } + + return true; + } + else + { + resetToDefaults(); + return false; + } +} + +int BFMDemodSettings::getRFBW(int index) +{ + if (index < 0) { + return m_rfBW[0]; + } else if (index < m_nbRFBW) { + return m_rfBW[index]; + } else { + return m_rfBW[m_nbRFBW-1]; + } +} + +int BFMDemodSettings::getRFBWIndex(int rfbw) +{ + for (int i = 0; i < m_nbRFBW; i++) + { + if (rfbw >= m_rfBW[i]) + { + return i; + } + } + + return 0; +} diff --git a/plugins/channelrx/demodbfm/bfmdemodsettings.h b/plugins/channelrx/demodbfm/bfmdemodsettings.h new file mode 100644 index 000000000..3f8f69ec2 --- /dev/null +++ b/plugins/channelrx/demodbfm/bfmdemodsettings.h @@ -0,0 +1,58 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2017 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 // +// // +// This program is distributed in the hope that it will be useful, // +// but WITHOUT ANY WARRANTY; without even the implied warranty of // +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // +// GNU General Public License V3 for more details. // +// // +// You should have received a copy of the GNU General Public License // +// along with this program. If not, see . // +/////////////////////////////////////////////////////////////////////////////////// + +#ifndef PLUGINS_CHANNELRX_DEMODBFM_BFMDEMODSETTINGS_H_ +#define PLUGINS_CHANNELRX_DEMODBFM_BFMDEMODSETTINGS_H_ + +class Serializable; + +struct BFMDemodSettings +{ + int m_inputSampleRate; + qint64 m_inputFrequencyOffset; + Real m_rfBandwidth; + Real m_afBandwidth; + Real m_volume; + Real m_squelch; + quint32 m_audioSampleRate; + bool m_audioStereo; + bool m_lsbStereo; + bool m_showPilot; + bool m_rdsActive; + bool m_copyAudioToUDP; + QString m_udpAddress; + quint16 m_udpPort; + quint32 m_rgbColor; + + Serializable *m_channelMarker; + Serializable *m_spectrumGUI; + + static const int m_nbRFBW; + static const int m_rfBW[]; + + BFMDemodSettings(); + void resetToDefaults(); + void setChannelMarker(Serializable *channelMarker) { m_channelMarker = channelMarker; } + void setSpectrumGUI(Serializable *spectrumGUI) { m_spectrumGUI = spectrumGUI; } + QByteArray serialize() const; + bool deserialize(const QByteArray& data); + + static int getRFBW(int index); + static int getRFBWIndex(int rfbw); +}; + + +#endif /* PLUGINS_CHANNELRX_DEMODBFM_BFMDEMODSETTINGS_H_ */ diff --git a/plugins/channelrx/demodbfm/demodbfm.pro b/plugins/channelrx/demodbfm/demodbfm.pro index cd6f5b130..908d69982 100644 --- a/plugins/channelrx/demodbfm/demodbfm.pro +++ b/plugins/channelrx/demodbfm/demodbfm.pro @@ -30,6 +30,7 @@ CONFIG(Debug):build_subdir = debug SOURCES += bfmdemod.cpp\ bfmdemodgui.cpp\ + bfmdemodsettings.cpp\ bfmplugin.cpp\ rdsdemod.cpp\ rdsdecoder.cpp\ @@ -38,6 +39,7 @@ SOURCES += bfmdemod.cpp\ HEADERS += bfmdemod.h\ bfmdemodgui.h\ + bfmdemodsettings.h\ bfmplugin.h\ rdsdemod.h\ rdsdecoder.h\ diff --git a/sdrbase/gui/glspectrumgui.h b/sdrbase/gui/glspectrumgui.h index 51514aeb5..4f29d9da9 100644 --- a/sdrbase/gui/glspectrumgui.h +++ b/sdrbase/gui/glspectrumgui.h @@ -4,6 +4,7 @@ #include #include "dsp/dsptypes.h" #include "util/export.h" +#include "settings/serializable.h" namespace Ui { class GLSpectrumGUI; @@ -13,7 +14,7 @@ class MessageQueue; class SpectrumVis; class GLSpectrum; -class SDRANGEL_API GLSpectrumGUI : public QWidget { +class SDRANGEL_API GLSpectrumGUI : public QWidget, public Serializable { Q_OBJECT public: @@ -23,8 +24,8 @@ public: void setBuddies(MessageQueue* messageQueue, SpectrumVis* spectrumVis, GLSpectrum* glSpectrum); void resetToDefaults(); - QByteArray serialize() const; - bool deserialize(const QByteArray& data); + virtual QByteArray serialize() const; + virtual bool deserialize(const QByteArray& data); private: Ui::GLSpectrumGUI* ui; From 5192d7fe59bd9edc4ee9a34eef7ae82363278f0b Mon Sep 17 00:00:00 2001 From: f4exb Date: Sun, 1 Oct 2017 19:20:56 +0200 Subject: [PATCH 50/71] BFM demod: use settings in the GUI only --- plugins/channelrx/demodbfm/bfmdemodgui.cpp | 195 +++++++----------- plugins/channelrx/demodbfm/bfmdemodgui.h | 4 +- .../channelrx/demodbfm/bfmdemodsettings.cpp | 4 +- 3 files changed, 78 insertions(+), 125 deletions(-) diff --git a/plugins/channelrx/demodbfm/bfmdemodgui.cpp b/plugins/channelrx/demodbfm/bfmdemodgui.cpp index 278809dce..7a7a932e4 100644 --- a/plugins/channelrx/demodbfm/bfmdemodgui.cpp +++ b/plugins/channelrx/demodbfm/bfmdemodgui.cpp @@ -44,16 +44,6 @@ const QString BFMDemodGUI::m_channelID = "sdrangel.channel.bfm"; -//int requiredBW(int rfBW) -//{ -// if (rfBW <= 48000) -// return 48000; -// else if (rfBW < 100000) -// return 96000; -// else -// return 384000; -//} - BFMDemodGUI* BFMDemodGUI::create(PluginAPI* pluginAPI, DeviceSourceAPI *deviceAPI) { BFMDemodGUI* gui = new BFMDemodGUI(pluginAPI, deviceAPI); @@ -88,114 +78,34 @@ void BFMDemodGUI::setCenterFrequency(qint64 centerFrequency) void BFMDemodGUI::resetToDefaults() { - blockApplySettings(true); + m_settings.resetToDefaults(); + displaySettings(); - ui->rfBW->setValue(4); - ui->afBW->setValue(3); - ui->volume->setValue(20); - ui->squelch->setValue(-40); - ui->deltaFrequency->setValue(0); - ui->copyAudioToUDP->setChecked(false); - m_channelMarker.setTitle("Broadcast FM Demod"); - m_channelMarker.setColor(QColor(80, 120, 228)); - m_channelMarker.setBandwidth(12500); - m_channelMarker.setCenterFrequency(0); - m_channelMarker.setUDPAddress("127.0.0.1"); - m_channelMarker.setUDPSendPort(9999); - setTitleColor(m_channelMarker.getColor()); + blockApplySettings(true); ui->g00AltFrequenciesBox->setEnabled(false); ui->g14MappedFrequencies->setEnabled(false); ui->g14AltFrequencies->setEnabled(false); - blockApplySettings(false); + applySettings(); } QByteArray BFMDemodGUI::serialize() const { - SimpleSerializer s(1); - s.writeS32(1, m_channelMarker.getCenterFrequency()); - s.writeS32(2, ui->rfBW->value()); - s.writeS32(3, ui->afBW->value()); - s.writeS32(4, ui->volume->value()); - s.writeS32(5, ui->squelch->value()); - s.writeU32(7, m_channelMarker.getColor().rgb()); - s.writeBlob(8, ui->spectrumGUI->serialize()); - s.writeBool(9, ui->audioStereo->isChecked()); - s.writeBool(10, ui->lsbStereo->isChecked()); - s.writeBlob(11, m_channelMarker.serialize()); - return s.final(); + return m_settings.serialize(); } bool BFMDemodGUI::deserialize(const QByteArray& data) { - SimpleDeserializer d(data); - - if (!d.isValid()) - { - resetToDefaults(); - return false; - } - - if (d.getVersion() == 1) - { - QByteArray bytetmp; - qint32 tmp; - quint32 u32tmp; - bool booltmp; - QString strtmp; - - blockApplySettings(true); - m_channelMarker.blockSignals(true); - - d.readBlob(11, &bytetmp); - m_channelMarker.deserialize(bytetmp); - - d.readS32(1, &tmp, 0); - m_channelMarker.setCenterFrequency(tmp); - - d.readS32(2, &tmp, 4); - ui->rfBW->setValue(tmp); - ui->rfBWText->setText(QString("%1 kHz").arg(BFMDemodSettings::getRFBW(tmp) / 1000.0)); - m_channelMarker.setBandwidth(BFMDemodSettings::getRFBW(tmp)); - - d.readS32(3, &tmp, 3); - ui->afBW->setValue(tmp); - - d.readS32(4, &tmp, 20); - ui->volume->setValue(tmp); - - d.readS32(5, &tmp, -40); - ui->squelch->setValue(tmp); - - if(d.readU32(7, &u32tmp)) - { - m_channelMarker.setColor(u32tmp); - } - - d.readBlob(8, &bytetmp); - ui->spectrumGUI->deserialize(bytetmp); - - d.readBool(9, &booltmp, false); - ui->audioStereo->setChecked(booltmp); - - d.readBool(10, &booltmp, false); - ui->lsbStereo->setChecked(booltmp); - - this->setWindowTitle(m_channelMarker.getTitle()); - displayUDPAddress(); - - blockApplySettings(false); - m_channelMarker.blockSignals(false); - - applySettings(true); - return true; - } - else - { - resetToDefaults(); - return false; - } + if(m_settings.deserialize(data)) { + updateChannelMarker(); + displaySettings(); + applySettings(true); + return true; + } else { + resetToDefaults(); + return false; + } } bool BFMDemodGUI::handleMessage(const Message& message) @@ -229,7 +139,6 @@ void BFMDemodGUI::handleInputMessages() } } - void BFMDemodGUI::channelMarkerChanged() { this->setWindowTitle(m_channelMarker.getTitle()); @@ -240,30 +149,36 @@ void BFMDemodGUI::channelMarkerChanged() void BFMDemodGUI::on_deltaFrequency_changed(qint64 value) { m_channelMarker.setCenterFrequency(value); + m_settings.m_inputFrequencyOffset = m_channelMarker.getCenterFrequency(); + applySettings(); } void BFMDemodGUI::on_rfBW_valueChanged(int value) { ui->rfBWText->setText(QString("%1 kHz").arg(BFMDemodSettings::getRFBW(value) / 1000.0)); m_channelMarker.setBandwidth(BFMDemodSettings::getRFBW(value)); + m_settings.m_rfBandwidth = BFMDemodSettings::getRFBW(value); applySettings(); } void BFMDemodGUI::on_afBW_valueChanged(int value) { ui->afBWText->setText(QString("%1 kHz").arg(value)); + m_settings.m_afBandwidth = value * 1000.0; applySettings(); } void BFMDemodGUI::on_volume_valueChanged(int value) { ui->volumeText->setText(QString("%1").arg(value / 10.0, 0, 'f', 1)); + m_settings.m_volume = value / 10.0; applySettings(); } void BFMDemodGUI::on_squelch_valueChanged(int value) { ui->squelchText->setText(QString("%1 dB").arg(value)); + m_settings.m_squelch = value; applySettings(); } @@ -274,26 +189,31 @@ void BFMDemodGUI::on_audioStereo_toggled(bool stereo) ui->audioStereo->setStyleSheet("QToolButton { background:rgb(79,79,79); }"); } + m_settings.m_audioStereo = stereo; applySettings(); } -void BFMDemodGUI::on_lsbStereo_toggled(bool lsb __attribute__((unused))) +void BFMDemodGUI::on_lsbStereo_toggled(bool lsb) { + m_settings.m_lsbStereo = lsb; applySettings(); } -void BFMDemodGUI::on_copyAudioToUDP_toggled(bool copy __attribute__((unused))) +void BFMDemodGUI::on_copyAudioToUDP_toggled(bool copy) { + m_settings.m_copyAudioToUDP = copy; applySettings(); } void BFMDemodGUI::on_showPilot_clicked() { + m_settings.m_showPilot = ui->showPilot->isChecked(); applySettings(); } void BFMDemodGUI::on_rds_clicked() { + m_settings.m_rdsActive = ui->rds->isChecked(); applySettings(); } @@ -415,10 +335,6 @@ BFMDemodGUI::BFMDemodGUI(PluginAPI* pluginAPI, DeviceSourceAPI *deviceAPI, QWidg m_bfmDemod = new BFMDemod(m_deviceAPI); m_bfmDemod->setMessageQueueToGUI(getInputMessageQueue()); m_bfmDemod->setSampleSink(m_spectrumVis); -// m_channelizer = new DownChannelizer(m_bfmDemod); -// m_threadedChannelizer = new ThreadedBasebandSampleSink(m_channelizer, this); -// connect(m_channelizer, SIGNAL(inputSampleRateChanged()), this, SLOT(channelSampleRateChanged())); -// m_deviceAPI->addThreadedSink(m_threadedChannelizer); ui->glSpectrum->setCenterFrequency(m_rate / 4); ui->glSpectrum->setSampleRate(m_rate / 2); @@ -428,7 +344,6 @@ BFMDemodGUI::BFMDemodGUI(PluginAPI* pluginAPI, DeviceSourceAPI *deviceAPI, QWidg m_spectrumVis->configure(m_spectrumVis->getInputMessageQueue(), 64, 10, FFTWindow::BlackmanHarris); connect(&m_pluginAPI->getMainWindow()->getMasterTimer(), SIGNAL(timeout()), this, SLOT(tick())); - //m_channelMarker = new ChannelMarker(this); m_channelMarker.setTitle("Broadcast FM Demod"); m_channelMarker.setColor(QColor(80, 120, 228)); m_channelMarker.setBandwidth(12500); @@ -438,6 +353,9 @@ BFMDemodGUI::BFMDemodGUI(PluginAPI* pluginAPI, DeviceSourceAPI *deviceAPI, QWidg m_channelMarker.setVisible(true); setTitleColor(m_channelMarker.getColor()); + m_settings.setChannelMarker(&m_channelMarker); + m_settings.setSpectrumGUI(ui->spectrumGUI); + connect(&m_channelMarker, SIGNAL(changed()), this, SLOT(channelMarkerChanged())); m_deviceAPI->registerChannelInstance(m_channelID, this); @@ -452,6 +370,7 @@ BFMDemodGUI::BFMDemodGUI(PluginAPI* pluginAPI, DeviceSourceAPI *deviceAPI, QWidg rdsUpdateFixedFields(); rdsUpdate(true); + displaySettings(); displayUDPAddress(); applySettings(true); } @@ -459,11 +378,7 @@ BFMDemodGUI::BFMDemodGUI(PluginAPI* pluginAPI, DeviceSourceAPI *deviceAPI, QWidg BFMDemodGUI::~BFMDemodGUI() { m_deviceAPI->removeChannelInstance(this); -// m_deviceAPI->removeThreadedSink(m_threadedChannelizer); -// delete m_threadedChannelizer; -// delete m_channelizer; delete m_bfmDemod; - //delete m_channelMarker; delete ui; } @@ -472,6 +387,13 @@ void BFMDemodGUI::displayUDPAddress() ui->copyAudioToUDP->setToolTip(QString("Copy audio output to UDP %1:%2").arg(m_channelMarker.getUDPAddress()).arg(m_channelMarker.getUDPSendPort())); } +void BFMDemodGUI::updateChannelMarker() +{ + m_channelMarker.blockSignals(true); + this->setWindowTitle(m_channelMarker.getTitle()); + m_channelMarker.blockSignals(false); +} + void BFMDemodGUI::blockApplySettings(bool block) { m_doApplySettings = !block; @@ -488,10 +410,6 @@ void BFMDemodGUI::applySettings(bool force) m_channelMarker.getCenterFrequency()); m_bfmDemod->getInputMessageQueue()->push(message); -// m_channelizer->configure(m_channelizer->getInputMessageQueue(), -// requiredBW(m_rfBW[ui->rfBW->value()]), // TODO: this is where requested sample rate is specified -// m_channelMarker.getCenterFrequency()); - ui->deltaFrequency->setValue(m_channelMarker.getCenterFrequency()); m_bfmDemod->configure(m_bfmDemod->getInputMessageQueue(), @@ -510,6 +428,42 @@ void BFMDemodGUI::applySettings(bool force) } } +void BFMDemodGUI::displaySettings() +{ + blockApplySettings(true); + + ui->deltaFrequency->setValue(m_settings.m_inputFrequencyOffset); + + ui->rfBW->setValue(BFMDemodSettings::getRFBWIndex(m_settings.m_rfBandwidth)); + ui->rfBWText->setText(QString("%1 kHz").arg(m_settings.m_rfBandwidth / 1000.0)); + m_channelMarker.setBandwidth(m_settings.m_rfBandwidth); + + ui->afBW->setValue(m_settings.m_afBandwidth/1000.0); + ui->afBWText->setText(QString("%1 kHz").arg(m_settings.m_afBandwidth/1000.0)); + + ui->volume->setValue(m_settings.m_volume * 10.0); + ui->volumeText->setText(QString("%1").arg(m_settings.m_volume, 0, 'f', 1)); + + ui->squelch->setValue(m_settings.m_squelch); + ui->squelchText->setText(QString("%1 dB").arg(m_settings.m_squelch)); + + ui->audioStereo->setChecked(m_settings.m_audioStereo); + ui->lsbStereo->setChecked(m_settings.m_lsbStereo); + ui->showPilot->setChecked(m_settings.m_showPilot); + ui->rds->setChecked(m_settings.m_rdsActive); + ui->copyAudioToUDP->setChecked(m_settings.m_copyAudioToUDP); + + m_channelMarker.blockSignals(true); + m_channelMarker.setCenterFrequency(m_settings.m_inputFrequencyOffset); + m_channelMarker.setUDPAddress(m_settings.m_udpAddress); + m_channelMarker.setUDPSendPort(m_settings.m_udpPort); + m_channelMarker.setColor(m_settings.m_rgbColor); + setTitleColor(m_settings.m_rgbColor); + m_channelMarker.blockSignals(false); + + blockApplySettings(false); +} + void BFMDemodGUI::leaveEvent(QEvent*) { blockApplySettings(true); @@ -829,5 +783,4 @@ void BFMDemodGUI::changeFrequency(qint64 f) { qint64 df = m_channelMarker.getCenterFrequency(); qDebug() << "BFMDemodGUI::changeFrequency: " << f - df; - // TODO: in the future it should be able to set the center frequency of the sample source this channel plugin is linked to } diff --git a/plugins/channelrx/demodbfm/bfmdemodgui.h b/plugins/channelrx/demodbfm/bfmdemodgui.h index 9da69207c..efcdc4f94 100644 --- a/plugins/channelrx/demodbfm/bfmdemodgui.h +++ b/plugins/channelrx/demodbfm/bfmdemodgui.h @@ -89,8 +89,6 @@ private: bool m_doApplySettings; int m_rdsTimerCount; -// ThreadedBasebandSampleSink* m_threadedChannelizer; -// DownChannelizer* m_channelizer; SpectrumVis* m_spectrumVis; BFMDemod* m_bfmDemod; @@ -104,7 +102,9 @@ private: void blockApplySettings(bool block); void applySettings(bool force = false); + void displaySettings(); void displayUDPAddress(); + void updateChannelMarker(); void rdsUpdate(bool force); void rdsUpdateFixedFields(); diff --git a/plugins/channelrx/demodbfm/bfmdemodsettings.cpp b/plugins/channelrx/demodbfm/bfmdemodsettings.cpp index 2aff8f7ea..38a8bcd06 100644 --- a/plugins/channelrx/demodbfm/bfmdemodsettings.cpp +++ b/plugins/channelrx/demodbfm/bfmdemodsettings.cpp @@ -141,11 +141,11 @@ int BFMDemodSettings::getRFBWIndex(int rfbw) { for (int i = 0; i < m_nbRFBW; i++) { - if (rfbw >= m_rfBW[i]) + if (rfbw <= m_rfBW[i]) { return i; } } - return 0; + return m_nbRFBW-1; } From 6095cf549c5baadeef8916a166ed31a0795c68ce Mon Sep 17 00:00:00 2001 From: f4exb Date: Sun, 1 Oct 2017 20:17:20 +0200 Subject: [PATCH 51/71] BFM demod: use settings in the demod --- plugins/channelrx/demodbfm/bfmdemod.cpp | 301 ++++++++---------- plugins/channelrx/demodbfm/bfmdemod.h | 167 ++-------- plugins/channelrx/demodbfm/bfmdemodgui.cpp | 22 +- .../channelrx/demodbfm/bfmdemodsettings.cpp | 7 +- 4 files changed, 170 insertions(+), 327 deletions(-) diff --git a/plugins/channelrx/demodbfm/bfmdemod.cpp b/plugins/channelrx/demodbfm/bfmdemod.cpp index 8fb23a96c..0e9115879 100644 --- a/plugins/channelrx/demodbfm/bfmdemod.cpp +++ b/plugins/channelrx/demodbfm/bfmdemod.cpp @@ -54,6 +54,7 @@ BFMDemod::BFMDemod(DeviceSourceAPI *deviceAPI) : m_magsqCount = 0; m_squelchLevel = 0; + m_squelchState = 0; m_interpolatorDistance = 0.0f; m_interpolatorDistanceRemain = 0.0f; @@ -74,24 +75,17 @@ BFMDemod::BFMDemod(DeviceSourceAPI *deviceAPI) : connect(m_channelizer, SIGNAL(inputSampleRateChanged()), this, SLOT(channelSampleRateChanged())); m_deviceAPI->addThreadedSink(m_threadedChannelizer); - m_config.m_inputSampleRate = 384000; - m_config.m_inputFrequencyOffset = 0; - m_config.m_rfBandwidth = 180000; - m_config.m_afBandwidth = 15000; - m_config.m_squelch = -60.0; - m_config.m_volume = 2.0; - m_config.m_audioSampleRate = DSPEngine::instance()->getAudioSampleRate(); // normally 48 kHz - m_deemphasisFilterX.configure(default_deemphasis * m_config.m_audioSampleRate * 1.0e-6); - m_deemphasisFilterY.configure(default_deemphasis * m_config.m_audioSampleRate * 1.0e-6); + m_deemphasisFilterX.configure(default_deemphasis * m_settings.m_audioSampleRate * 1.0e-6); + m_deemphasisFilterY.configure(default_deemphasis * m_settings.m_audioSampleRate * 1.0e-6); m_phaseDiscri.setFMScaling(384000/m_fmExcursion); - apply(); - m_audioBuffer.resize(16384); m_audioBufferFill = 0; DSPEngine::instance()->addAudioSink(&m_audioFifo); - m_udpBufferAudio = new UDPSink(this, m_udpBlockSize, m_config.m_udpPort); + m_udpBufferAudio = new UDPSink(this, m_udpBlockSize, m_settings.m_udpPort); + + applySettings(m_settings, true); } BFMDemod::~BFMDemod() @@ -109,35 +103,6 @@ BFMDemod::~BFMDemod() delete m_channelizer; } -void BFMDemod::configure(MessageQueue* messageQueue, - Real rfBandwidth, - Real afBandwidth, - Real volume, - Real squelch, - bool audioStereo, - bool lsbStereo, - bool showPilot, - bool rdsActive, - bool copyAudioToUDP, - const QString& udpAddress, - quint16 udpPort, - bool force) -{ - Message* cmd = MsgConfigureBFMDemod::create(rfBandwidth, - afBandwidth, - volume, - squelch, - audioStereo, - lsbStereo, - showPilot, - rdsActive, - copyAudioToUDP, - udpAddress, - udpPort, - force); - messageQueue->push(cmd); -} - void BFMDemod::feed(const SampleVector::const_iterator& begin, const SampleVector::const_iterator& end, bool firstOfBurst __attribute__((unused))) { Complex ci, cs, cr; @@ -173,7 +138,7 @@ void BFMDemod::feed(const SampleVector::const_iterator& begin, const SampleVecto // m_movingAverage.feed(msq); if(m_magsq >= m_squelchLevel) { - m_squelchState = m_running.m_rfBandwidth / 20; // decay rate + m_squelchState = m_settings.m_rfBandwidth / 20; // decay rate } if(m_squelchState > 0) @@ -188,12 +153,12 @@ void BFMDemod::feed(const SampleVector::const_iterator& begin, const SampleVecto demod = 0; } - if (!m_running.m_showPilot) + if (!m_settings.m_showPilot) { m_sampleBuffer.push_back(Sample(demod * (1<<15), 0.0)); } - if (m_running.m_rdsActive) + if (m_settings.m_rdsActive) { //Complex r(demod * 2.0 * std::cos(3.0 * m_pilotPLLSamples[3]), 0.0); Complex r(demod * 2.0 * std::cos(3.0 * m_pilotPLLSamples[3]), 0.0); @@ -218,16 +183,16 @@ void BFMDemod::feed(const SampleVector::const_iterator& begin, const SampleVecto // Process stereo if stereo mode is selected - if (m_running.m_audioStereo) + if (m_settings.m_audioStereo) { m_pilotPLL.process(demod, m_pilotPLLSamples); - if (m_running.m_showPilot) + if (m_settings.m_showPilot) { m_sampleBuffer.push_back(Sample(m_pilotPLLSamples[1] * (1<<15), 0.0)); // debug 38 kHz pilot } - if (m_running.m_lsbStereo) + if (m_settings.m_lsbStereo) { // 1.17 * 0.7 = 0.819 Complex s(demod * m_pilotPLLSamples[1], demod * m_pilotPLLSamples[2]); @@ -254,32 +219,32 @@ void BFMDemod::feed(const SampleVector::const_iterator& begin, const SampleVecto if (m_interpolator.decimate(&m_interpolatorDistanceRemain, e, &ci)) { - if (m_running.m_audioStereo) + if (m_settings.m_audioStereo) { Real deemph_l, deemph_r; // Pre-emphasis is applied on each channel before multiplexing m_deemphasisFilterX.process(ci.real() + sampleStereo, deemph_l); m_deemphasisFilterY.process(ci.real() - sampleStereo, deemph_r); - if (m_running.m_lsbStereo) + if (m_settings.m_lsbStereo) { - m_audioBuffer[m_audioBufferFill].l = (qint16)(deemph_l * (1<<12) * m_running.m_volume); - m_audioBuffer[m_audioBufferFill].r = (qint16)(deemph_r * (1<<12) * m_running.m_volume); - if (m_running.m_copyAudioToUDP) m_udpBufferAudio->write(m_audioBuffer[m_audioBufferFill]); + m_audioBuffer[m_audioBufferFill].l = (qint16)(deemph_l * (1<<12) * m_settings.m_volume); + m_audioBuffer[m_audioBufferFill].r = (qint16)(deemph_r * (1<<12) * m_settings.m_volume); + if (m_settings.m_copyAudioToUDP) m_udpBufferAudio->write(m_audioBuffer[m_audioBufferFill]); } else { - m_audioBuffer[m_audioBufferFill].l = (qint16)(deemph_l * (1<<12) * m_running.m_volume); - m_audioBuffer[m_audioBufferFill].r = (qint16)(deemph_r * (1<<12) * m_running.m_volume); - if (m_running.m_copyAudioToUDP) m_udpBufferAudio->write(m_audioBuffer[m_audioBufferFill]); + m_audioBuffer[m_audioBufferFill].l = (qint16)(deemph_l * (1<<12) * m_settings.m_volume); + m_audioBuffer[m_audioBufferFill].r = (qint16)(deemph_r * (1<<12) * m_settings.m_volume); + if (m_settings.m_copyAudioToUDP) m_udpBufferAudio->write(m_audioBuffer[m_audioBufferFill]); } } else { Real deemph; m_deemphasisFilterX.process(ci.real(), deemph); - quint16 sample = (qint16)(deemph * (1<<12) * m_running.m_volume); + quint16 sample = (qint16)(deemph * (1<<12) * m_settings.m_volume); m_audioBuffer[m_audioBufferFill].l = sample; m_audioBuffer[m_audioBufferFill].r = sample; - if (m_running.m_copyAudioToUDP) m_udpBufferAudio->write(m_audioBuffer[m_audioBufferFill]); + if (m_settings.m_copyAudioToUDP) m_udpBufferAudio->write(m_audioBuffer[m_audioBufferFill]); } ++m_audioBufferFill; @@ -346,48 +311,46 @@ bool BFMDemod::handleMessage(const Message& cmd) { DownChannelizer::MsgChannelizerNotification& notif = (DownChannelizer::MsgChannelizerNotification&) cmd; - m_config.m_inputSampleRate = notif.getSampleRate(); - m_config.m_inputFrequencyOffset = notif.getFrequencyOffset(); + BFMDemodSettings settings = m_settings; - apply(); + settings.m_inputSampleRate = notif.getSampleRate(); + settings.m_inputFrequencyOffset = notif.getFrequencyOffset(); - qDebug() << "BFMDemod::handleMessage: MsgChannelizerNotification: m_inputSampleRate: " << m_config.m_inputSampleRate - << " m_inputFrequencyOffset: " << m_config.m_inputFrequencyOffset; + applySettings(settings); + + qDebug() << "BFMDemod::handleMessage: MsgChannelizerNotification:" + << " m_inputSampleRate: " << settings.m_inputSampleRate + << " m_inputFrequencyOffset: " << settings.m_inputFrequencyOffset; return true; } - else if (MsgConfigureBFMDemod::match(cmd)) - { - MsgConfigureBFMDemod& cfg = (MsgConfigureBFMDemod&) cmd; + else if (MsgConfigureBFMDemod::match(cmd)) + { + MsgConfigureBFMDemod& cfg = (MsgConfigureBFMDemod&) cmd; - m_config.m_rfBandwidth = cfg.getRFBandwidth(); - m_config.m_afBandwidth = cfg.getAFBandwidth(); - m_config.m_volume = cfg.getVolume(); - m_config.m_squelch = cfg.getSquelch(); - m_config.m_audioStereo = cfg.getAudioStereo(); - m_config.m_lsbStereo = cfg.getLsbStereo(); - m_config.m_showPilot = cfg.getShowPilot(); - m_config.m_rdsActive = cfg.getRDSActive(); - m_config.m_copyAudioToUDP= cfg.getCopyAudioToUDP(); - m_config.m_udpAddress = cfg.getUDPAddress(); - m_config.m_udpPort = cfg.getUDPPort(); + BFMDemodSettings settings = cfg.getSettings(); - apply(cfg.getForce()); + // These settings are set with DownChannelizer::MsgChannelizerNotification + settings.m_inputSampleRate = m_settings.m_inputSampleRate; + settings.m_inputFrequencyOffset = m_settings.m_inputFrequencyOffset; - qDebug() << "BFMDemod::handleMessage: MsgConfigureBFMDemod: m_rfBandwidth: " << m_config.m_rfBandwidth - << " m_afBandwidth: " << m_config.m_afBandwidth - << " m_volume: " << m_config.m_volume - << " m_squelch: " << m_config.m_squelch - << " m_audioStereo: " << m_config.m_audioStereo - << " m_lsbStereo: " << m_config.m_lsbStereo - << " m_showPilot: " << m_config.m_showPilot - << " m_rdsActive: " << m_config.m_rdsActive - << " m_copyAudioToUDP: " << m_config.m_copyAudioToUDP - << " m_udpAddress: " << m_config.m_udpAddress - << " m_udpPort: " << m_config.m_udpPort; + applySettings(settings, cfg.getForce()); - return true; - } + qDebug() << "BFMDemod::handleMessage: MsgConfigureBFMDemod:" + << " m_rfBandwidth: " << settings.m_rfBandwidth + << " m_volume: " << settings.m_volume + << " m_squelch: " << settings.m_squelch + << " m_audioStereo: " << settings.m_audioStereo + << " m_lsbStereo: " << settings.m_lsbStereo + << " m_showPilot: " << settings.m_showPilot + << " m_rdsActive: " << settings.m_rdsActive + << " m_copyAudioToUDP: " << settings.m_copyAudioToUDP + << " m_udpAddress: " << settings.m_udpAddress + << " m_udpPort: " << settings.m_udpPort + << " force: " << cfg.getForce(); + + return true; + } else { qDebug() << "BFMDemod::handleMessage: none"; @@ -403,87 +366,87 @@ bool BFMDemod::handleMessage(const Message& cmd) } } -void BFMDemod::apply(bool force) +void BFMDemod::applySettings(const BFMDemodSettings& settings, bool force) { - if ((m_config.m_inputSampleRate != m_running.m_inputSampleRate) - || (m_config.m_audioStereo && (m_config.m_audioStereo != m_running.m_audioStereo)) || force) - { - m_pilotPLL.configure(19000.0/m_config.m_inputSampleRate, 50.0/m_config.m_inputSampleRate, 0.01); - } - - if((m_config.m_inputFrequencyOffset != m_running.m_inputFrequencyOffset) || - (m_config.m_inputSampleRate != m_running.m_inputSampleRate) || force) - { - qDebug() << "BFMDemod::handleMessage: m_nco.setFreq"; - m_nco.setFreq(-m_config.m_inputFrequencyOffset, m_config.m_inputSampleRate); - } - - if((m_config.m_inputSampleRate != m_running.m_inputSampleRate) || - (m_config.m_afBandwidth != m_running.m_afBandwidth) || force) - { - m_settingsMutex.lock(); - qDebug() << "BFMDemod::handleMessage: m_interpolator.create"; - - m_interpolator.create(16, m_config.m_inputSampleRate, m_config.m_afBandwidth); - m_interpolatorDistanceRemain = (Real) m_config.m_inputSampleRate / m_config.m_audioSampleRate; - m_interpolatorDistance = (Real) m_config.m_inputSampleRate / (Real) m_config.m_audioSampleRate; - - m_interpolatorStereo.create(16, m_config.m_inputSampleRate, m_config.m_afBandwidth); - m_interpolatorStereoDistanceRemain = (Real) m_config.m_inputSampleRate / m_config.m_audioSampleRate; - m_interpolatorStereoDistance = (Real) m_config.m_inputSampleRate / (Real) m_config.m_audioSampleRate; - - m_interpolatorRDS.create(4, m_config.m_inputSampleRate, 600.0); - m_interpolatorRDSDistanceRemain = (Real) m_config.m_inputSampleRate / 250000.0; - m_interpolatorRDSDistance = (Real) m_config.m_inputSampleRate / 250000.0; - - m_settingsMutex.unlock(); - } - - if((m_config.m_inputSampleRate != m_running.m_inputSampleRate) || - (m_config.m_rfBandwidth != m_running.m_rfBandwidth) || - (m_config.m_inputFrequencyOffset != m_running.m_inputFrequencyOffset) || force) - { - m_settingsMutex.lock(); - Real lowCut = -(m_config.m_rfBandwidth / 2.0) / m_config.m_inputSampleRate; - Real hiCut = (m_config.m_rfBandwidth / 2.0) / m_config.m_inputSampleRate; - m_rfFilter->create_filter(lowCut, hiCut); - m_phaseDiscri.setFMScaling(m_config.m_inputSampleRate / m_fmExcursion); - m_settingsMutex.unlock(); - - qDebug() << "BFMDemod::handleMessage: m_rfFilter->create_filter: sampleRate: " - << m_config.m_inputSampleRate - << " lowCut: " << lowCut * m_config.m_inputSampleRate - << " hiCut: " << hiCut * m_config.m_inputSampleRate; - } - - if ((m_config.m_afBandwidth != m_running.m_afBandwidth) || - (m_config.m_audioSampleRate != m_running.m_audioSampleRate) || force) - { - m_settingsMutex.lock(); - qDebug() << "BFMDemod::handleMessage: m_lowpass.create"; - m_lowpass.create(21, m_config.m_audioSampleRate, m_config.m_afBandwidth); - m_settingsMutex.unlock(); - } - - if ((m_config.m_squelch != m_running.m_squelch) || force) - { - qDebug() << "BFMDemod::handleMessage: set m_squelchLevel"; - m_squelchLevel = std::pow(10.0, m_config.m_squelch / 20.0); - m_squelchLevel *= m_squelchLevel; - } - - if ((m_config.m_audioSampleRate != m_running.m_audioSampleRate) || force) - { - m_deemphasisFilterX.configure(default_deemphasis * m_config.m_audioSampleRate * 1.0e-6); - m_deemphasisFilterY.configure(default_deemphasis * m_config.m_audioSampleRate * 1.0e-6); - } - - if ((m_config.m_udpAddress != m_running.m_udpAddress) - || (m_config.m_udpPort != m_running.m_udpPort) || force) + if ((settings.m_inputSampleRate != m_settings.m_inputSampleRate) + || (settings.m_audioStereo && (settings.m_audioStereo != m_settings.m_audioStereo)) || force) { - m_udpBufferAudio->setAddress(m_config.m_udpAddress); - m_udpBufferAudio->setPort(m_config.m_udpPort); + m_pilotPLL.configure(19000.0/settings.m_inputSampleRate, 50.0/settings.m_inputSampleRate, 0.01); } - m_running = m_config; + if((settings.m_inputFrequencyOffset != m_settings.m_inputFrequencyOffset) || + (settings.m_inputSampleRate != m_settings.m_inputSampleRate) || force) + { + qDebug() << "BFMDemod::handleMessage: m_nco.setFreq"; + m_nco.setFreq(-settings.m_inputFrequencyOffset, settings.m_inputSampleRate); + } + + if((settings.m_inputSampleRate != m_settings.m_inputSampleRate) || + (settings.m_afBandwidth != m_settings.m_afBandwidth) || force) + { + m_settingsMutex.lock(); + qDebug() << "BFMDemod::handleMessage: m_interpolator.create"; + + m_interpolator.create(16, settings.m_inputSampleRate, settings.m_afBandwidth); + m_interpolatorDistanceRemain = (Real) settings.m_inputSampleRate / settings.m_audioSampleRate; + m_interpolatorDistance = (Real) settings.m_inputSampleRate / (Real) settings.m_audioSampleRate; + + m_interpolatorStereo.create(16, settings.m_inputSampleRate, settings.m_afBandwidth); + m_interpolatorStereoDistanceRemain = (Real) settings.m_inputSampleRate / settings.m_audioSampleRate; + m_interpolatorStereoDistance = (Real) settings.m_inputSampleRate / (Real) settings.m_audioSampleRate; + + m_interpolatorRDS.create(4, settings.m_inputSampleRate, 600.0); + m_interpolatorRDSDistanceRemain = (Real) settings.m_inputSampleRate / 250000.0; + m_interpolatorRDSDistance = (Real) settings.m_inputSampleRate / 250000.0; + + m_settingsMutex.unlock(); + } + + if((settings.m_inputSampleRate != m_settings.m_inputSampleRate) || + (settings.m_rfBandwidth != m_settings.m_rfBandwidth) || + (settings.m_inputFrequencyOffset != m_settings.m_inputFrequencyOffset) || force) + { + m_settingsMutex.lock(); + Real lowCut = -(settings.m_rfBandwidth / 2.0) / settings.m_inputSampleRate; + Real hiCut = (settings.m_rfBandwidth / 2.0) / settings.m_inputSampleRate; + m_rfFilter->create_filter(lowCut, hiCut); + m_phaseDiscri.setFMScaling(settings.m_inputSampleRate / m_fmExcursion); + m_settingsMutex.unlock(); + + qDebug() << "BFMDemod::handleMessage: m_rfFilter->create_filter: sampleRate: " + << settings.m_inputSampleRate + << " lowCut: " << lowCut * settings.m_inputSampleRate + << " hiCut: " << hiCut * settings.m_inputSampleRate; + } + + if ((settings.m_afBandwidth != m_settings.m_afBandwidth) || + (settings.m_audioSampleRate != m_settings.m_audioSampleRate) || force) + { + m_settingsMutex.lock(); + qDebug() << "BFMDemod::handleMessage: m_lowpass.create"; + m_lowpass.create(21, settings.m_audioSampleRate, settings.m_afBandwidth); + m_settingsMutex.unlock(); + } + + if ((settings.m_squelch != m_settings.m_squelch) || force) + { + qDebug() << "BFMDemod::handleMessage: set m_squelchLevel"; + m_squelchLevel = std::pow(10.0, settings.m_squelch / 20.0); + m_squelchLevel *= m_squelchLevel; + } + + if ((settings.m_audioSampleRate != m_settings.m_audioSampleRate) || force) + { + m_deemphasisFilterX.configure(default_deemphasis * settings.m_audioSampleRate * 1.0e-6); + m_deemphasisFilterY.configure(default_deemphasis * settings.m_audioSampleRate * 1.0e-6); + } + + if ((settings.m_udpAddress != m_settings.m_udpAddress) + || (settings.m_udpPort != m_settings.m_udpPort) || force) + { + m_udpBufferAudio->setAddress(const_cast(settings.m_udpAddress)); + m_udpBufferAudio->setPort(settings.m_udpPort); + } + + m_settings = settings; } diff --git a/plugins/channelrx/demodbfm/bfmdemod.h b/plugins/channelrx/demodbfm/bfmdemod.h index 0d9322246..3c403bb19 100644 --- a/plugins/channelrx/demodbfm/bfmdemod.h +++ b/plugins/channelrx/demodbfm/bfmdemod.h @@ -36,6 +36,7 @@ #include "rdsparser.h" #include "rdsdecoder.h" #include "rdsdemod.h" +#include "bfmdemodsettings.h" class DeviceSourceAPI; class ThreadedBasebandSampleSink; @@ -43,6 +44,29 @@ class DownChannelizer; class BFMDemod : public BasebandSampleSink { public: + class MsgConfigureBFMDemod : public Message { + MESSAGE_CLASS_DECLARATION + + public: + const BFMDemodSettings& getSettings() const { return m_settings; } + bool getForce() const { return m_force; } + + static MsgConfigureBFMDemod* create(const BFMDemodSettings& settings, bool force) + { + return new MsgConfigureBFMDemod(settings, force); + } + + private: + BFMDemodSettings m_settings; + bool m_force; + + MsgConfigureBFMDemod(const BFMDemodSettings& settings, bool force) : + Message(), + m_settings(settings), + m_force(force) + { } + }; + class MsgConfigureChannelizer : public Message { MESSAGE_CLASS_DECLARATION @@ -90,21 +114,7 @@ public: virtual ~BFMDemod(); void setSampleSink(BasebandSampleSink* sampleSink) { m_sampleSink = sampleSink; } - void configure(MessageQueue* messageQueue, - Real rfBandwidth, - Real afBandwidth, - Real volume, - Real squelch, - bool audioStereo, - bool lsbStereo, - bool showPilot, - bool rdsActive, - bool copyAudioUDP, - const QString& m_udpAddress, - quint16 udpPort, - bool force = false); - - int getSampleRate() const { return m_config.m_inputSampleRate; } + int getSampleRate() const { return m_settings.m_inputSampleRate; } virtual void feed(const SampleVector::const_iterator& begin, const SampleVector::const_iterator& end, bool po); virtual void start(); virtual void stop(); @@ -138,138 +148,17 @@ private slots: void channelSampleRateChanged(); private: - class MsgConfigureBFMDemod : public Message { - MESSAGE_CLASS_DECLARATION - - public: - Real getRFBandwidth() const { return m_rfBandwidth; } - Real getAFBandwidth() const { return m_afBandwidth; } - Real getVolume() const { return m_volume; } - Real getSquelch() const { return m_squelch; } - bool getAudioStereo() const { return m_audioStereo; } - bool getLsbStereo() const { return m_lsbStereo; } - bool getShowPilot() const { return m_showPilot; } - bool getRDSActive() const { return m_rdsActive; } - bool getCopyAudioToUDP() const { return m_copyAudioToUDP; } - const QString& getUDPAddress() const { return m_udpAddress; } - quint16 getUDPPort() const { return m_udpPort; } - bool getForce() const { return m_force; } - - static MsgConfigureBFMDemod* create(Real rfBandwidth, - Real afBandwidth, - Real volume, - Real squelch, - bool audioStereo, - bool lsbStereo, - bool showPilot, - bool rdsActive, - bool copyAudioToUDP, - const QString& udpAddress, - quint16 udpPort, - bool force) - { - return new MsgConfigureBFMDemod(rfBandwidth, - afBandwidth, - volume, - squelch, - audioStereo, - lsbStereo, - showPilot, - rdsActive, - copyAudioToUDP, - udpAddress, - udpPort, - force); - } - - private: - Real m_rfBandwidth; - Real m_afBandwidth; - Real m_volume; - Real m_squelch; - bool m_audioStereo; - bool m_lsbStereo; - bool m_showPilot; - bool m_rdsActive; - bool m_copyAudioToUDP; - QString m_udpAddress; - quint16 m_udpPort; - bool m_force; - - MsgConfigureBFMDemod(Real rfBandwidth, - Real afBandwidth, - Real volume, - Real squelch, - bool audioStereo, - bool lsbStereo, - bool showPilot, - bool rdsActive, - bool copyAudioToUDP, - const QString& udpAddress, - quint16 udpPort, - bool force) : - Message(), - m_rfBandwidth(rfBandwidth), - m_afBandwidth(afBandwidth), - m_volume(volume), - m_squelch(squelch), - m_audioStereo(audioStereo), - m_lsbStereo(lsbStereo), - m_showPilot(showPilot), - m_rdsActive(rdsActive), - m_copyAudioToUDP(copyAudioToUDP), - m_udpAddress(udpAddress), - m_udpPort(udpPort), - m_force(force) - { } - }; - enum RateState { RSInitialFill, RSRunning }; - struct Config { - int m_inputSampleRate; - qint64 m_inputFrequencyOffset; - Real m_rfBandwidth; - Real m_afBandwidth; - Real m_squelch; - Real m_volume; - quint32 m_audioSampleRate; - bool m_audioStereo; - bool m_lsbStereo; - bool m_showPilot; - bool m_rdsActive; - bool m_copyAudioToUDP; - QString m_udpAddress; - quint16 m_udpPort; - - Config() : - m_inputSampleRate(-1), - m_inputFrequencyOffset(0), - m_rfBandwidth(-1), - m_afBandwidth(-1), - m_squelch(0), - m_volume(0), - m_audioSampleRate(0), - m_audioStereo(false), - m_lsbStereo(false), - m_showPilot(false), - m_rdsActive(false), - m_copyAudioToUDP(false), - m_udpAddress("127.0.0.1"), - m_udpPort(9999) - { } - }; - - Config m_config; - Config m_running; - DeviceSourceAPI *m_deviceAPI; ThreadedBasebandSampleSink* m_threadedChannelizer; DownChannelizer* m_channelizer; + BFMDemodSettings m_settings; + NCO m_nco; Interpolator m_interpolator; //!< Interpolator between fixed demod bandwidth and audio bandwidth (rational) Real m_interpolatorDistance; @@ -324,7 +213,7 @@ private: static const int m_udpBlockSize; - void apply(bool force = false); + void applySettings(const BFMDemodSettings& settings, bool force = false); }; #endif // INCLUDE_BFMDEMOD_H diff --git a/plugins/channelrx/demodbfm/bfmdemodgui.cpp b/plugins/channelrx/demodbfm/bfmdemodgui.cpp index 7a7a932e4..02c86f2ff 100644 --- a/plugins/channelrx/demodbfm/bfmdemodgui.cpp +++ b/plugins/channelrx/demodbfm/bfmdemodgui.cpp @@ -298,7 +298,6 @@ void BFMDemodGUI::on_g14AltFrequencies_activated(int index __attribute__((unused changeFrequency(f); } - void BFMDemodGUI::onWidgetRolled(QWidget* widget __attribute__((unused)), bool rollDown __attribute__((unused))) { } @@ -345,12 +344,12 @@ BFMDemodGUI::BFMDemodGUI(PluginAPI* pluginAPI, DeviceSourceAPI *deviceAPI, QWidg connect(&m_pluginAPI->getMainWindow()->getMasterTimer(), SIGNAL(timeout()), this, SLOT(tick())); m_channelMarker.setTitle("Broadcast FM Demod"); - m_channelMarker.setColor(QColor(80, 120, 228)); m_channelMarker.setBandwidth(12500); m_channelMarker.setCenterFrequency(0); m_channelMarker.setUDPAddress("127.0.0.1"); m_channelMarker.setUDPSendPort(9999); m_channelMarker.setVisible(true); + m_channelMarker.setColor(m_settings.m_rgbColor); setTitleColor(m_channelMarker.getColor()); m_settings.setChannelMarker(&m_channelMarker); @@ -405,26 +404,15 @@ void BFMDemodGUI::applySettings(bool force) { setTitleColor(m_channelMarker.getColor()); - BFMDemod::MsgConfigureChannelizer *message = BFMDemod::MsgConfigureChannelizer::create( + BFMDemod::MsgConfigureChannelizer *msgChan = BFMDemod::MsgConfigureChannelizer::create( requiredBW(BFMDemodSettings::getRFBW(ui->rfBW->value())), m_channelMarker.getCenterFrequency()); - m_bfmDemod->getInputMessageQueue()->push(message); + m_bfmDemod->getInputMessageQueue()->push(msgChan); ui->deltaFrequency->setValue(m_channelMarker.getCenterFrequency()); - m_bfmDemod->configure(m_bfmDemod->getInputMessageQueue(), - BFMDemodSettings::getRFBW(ui->rfBW->value()), - ui->afBW->value() * 1000.0, - ui->volume->value() / 10.0, - ui->squelch->value(), - ui->audioStereo->isChecked(), - ui->lsbStereo->isChecked(), - ui->showPilot->isChecked(), - ui->rds->isChecked(), - ui->copyAudioToUDP->isChecked(), - m_channelMarker.getUDPAddress(), - m_channelMarker.getUDPSendPort(), - force); + BFMDemod::MsgConfigureBFMDemod* msgConfig = BFMDemod::MsgConfigureBFMDemod::create( m_settings, force); + m_bfmDemod->getInputMessageQueue()->push(msgConfig); } } diff --git a/plugins/channelrx/demodbfm/bfmdemodsettings.cpp b/plugins/channelrx/demodbfm/bfmdemodsettings.cpp index 38a8bcd06..6efa0385c 100644 --- a/plugins/channelrx/demodbfm/bfmdemodsettings.cpp +++ b/plugins/channelrx/demodbfm/bfmdemodsettings.cpp @@ -14,6 +14,8 @@ // along with this program. If not, see . // /////////////////////////////////////////////////////////////////////////////////// +#include + #include "dsp/dspengine.h" #include "util/simpleserializer.h" #include "settings/serializable.h" @@ -36,8 +38,8 @@ void BFMDemodSettings::resetToDefaults() { m_inputSampleRate = 384000; m_inputFrequencyOffset = 0; - m_rfBandwidth = getRFBW(4); - m_afBandwidth = 3000; + m_rfBandwidth = getRFBW(5); + m_afBandwidth = 15000; m_volume = 2.0; m_squelch = -60.0; m_audioSampleRate = DSPEngine::instance()->getAudioSampleRate(); @@ -48,6 +50,7 @@ void BFMDemodSettings::resetToDefaults() m_copyAudioToUDP = false; m_udpAddress = "127.0.0.1"; m_udpPort = 9999; + m_rgbColor = QColor(80, 120, 228).rgb(); } QByteArray BFMDemodSettings::serialize() const From 06ac0d6b4db9541a225dd2433a021dfc336b5bd1 Mon Sep 17 00:00:00 2001 From: f4exb Date: Sun, 1 Oct 2017 22:12:10 +0200 Subject: [PATCH 52/71] SSB demod: separate GUI from demod --- plugins/channelrx/demodssb/ssbdemod.cpp | 34 ++++++++++++++++++---- plugins/channelrx/demodssb/ssbdemod.h | 34 +++++++++++++++++++++- plugins/channelrx/demodssb/ssbdemodgui.cpp | 20 ++++--------- plugins/channelrx/demodssb/ssbdemodgui.h | 4 --- 4 files changed, 68 insertions(+), 24 deletions(-) diff --git a/plugins/channelrx/demodssb/ssbdemod.cpp b/plugins/channelrx/demodssb/ssbdemod.cpp index 387b7bdb4..715d1bd40 100644 --- a/plugins/channelrx/demodssb/ssbdemod.cpp +++ b/plugins/channelrx/demodssb/ssbdemod.cpp @@ -16,19 +16,25 @@ // along with this program. If not, see . // /////////////////////////////////////////////////////////////////////////////////// -#include "ssbdemod.h" -#include #include #include #include + #include "audio/audiooutput.h" #include "dsp/dspengine.h" +#include +#include "dsp/threadedbasebandsamplesink.h" +#include "device/devicesourceapi.h" #include "util/db.h" -MESSAGE_CLASS_DEFINITION(SSBDemod::MsgConfigureSSBDemod, Message) +#include "ssbdemod.h" -SSBDemod::SSBDemod(BasebandSampleSink* sampleSink) : +MESSAGE_CLASS_DEFINITION(SSBDemod::MsgConfigureSSBDemod, Message) +MESSAGE_CLASS_DEFINITION(SSBDemod::MsgConfigureChannelizer, Message) + +SSBDemod::SSBDemod(DeviceSourceAPI *deviceAPI) : + m_deviceAPI(deviceAPI), m_audioBinaual(false), m_audioFlipChannels(false), m_dsb(false), @@ -40,7 +46,7 @@ SSBDemod::SSBDemod(BasebandSampleSink* sampleSink) : m_agcPowerThreshold(1e-2), m_agcThresholdGate(0), m_audioActive(false), - m_sampleSink(sampleSink), + m_sampleSink(0), m_audioFifo(24000), m_settingsMutex(QMutex::Recursive) { @@ -75,6 +81,10 @@ SSBDemod::SSBDemod(BasebandSampleSink* sampleSink) : SSBFilter = new fftfilt(m_LowCutoff / m_audioSampleRate, m_Bandwidth / m_audioSampleRate, ssbFftLen); DSBFilter = new fftfilt((2.0f * m_Bandwidth) / m_audioSampleRate, 2 * ssbFftLen); + m_channelizer = new DownChannelizer(this); + m_threadedChannelizer = new ThreadedBasebandSampleSink(m_channelizer, this); + m_deviceAPI->addThreadedSink(m_threadedChannelizer); + DSPEngine::instance()->addAudioSink(&m_audioFifo); } @@ -84,6 +94,10 @@ SSBDemod::~SSBDemod() if (DSBFilter) delete DSBFilter; DSPEngine::instance()->removeAudioSink(&m_audioFifo); + + m_deviceAPI->removeThreadedSink(m_threadedChannelizer); + delete m_threadedChannelizer; + delete m_channelizer; } void SSBDemod::configure(MessageQueue* messageQueue, @@ -284,6 +298,16 @@ bool SSBDemod::handleMessage(const Message& cmd) return true; } + else if (MsgConfigureChannelizer::match(cmd)) + { + MsgConfigureChannelizer& cfg = (MsgConfigureChannelizer&) cmd; + + m_channelizer->configure(m_channelizer->getInputMessageQueue(), + cfg.getSampleRate(), + cfg.getCenterFrequency()); + + return true; + } else if (MsgConfigureSSBDemod::match(cmd)) { MsgConfigureSSBDemod& cfg = (MsgConfigureSSBDemod&) cmd; diff --git a/plugins/channelrx/demodssb/ssbdemod.h b/plugins/channelrx/demodssb/ssbdemod.h index dd6e4f74b..2e23568d4 100644 --- a/plugins/channelrx/demodssb/ssbdemod.h +++ b/plugins/channelrx/demodssb/ssbdemod.h @@ -31,10 +31,38 @@ #define ssbFftLen 1024 #define agcTarget 3276.8 // -10 dB amplitude => -20 dB power: center of normal signal +class DeviceSourceAPI; +class ThreadedBasebandSampleSink; +class DownChannelizer; + class SSBDemod : public BasebandSampleSink { public: - SSBDemod(BasebandSampleSink* sampleSink); + class MsgConfigureChannelizer : public Message { + MESSAGE_CLASS_DECLARATION + + public: + int getSampleRate() const { return m_sampleRate; } + int getCenterFrequency() const { return m_centerFrequency; } + + static MsgConfigureChannelizer* create(int sampleRate, int centerFrequency) + { + return new MsgConfigureChannelizer(sampleRate, centerFrequency); + } + + private: + int m_sampleRate; + int m_centerFrequency; + + MsgConfigureChannelizer(int sampleRate, int centerFrequency) : + Message(), + m_sampleRate(sampleRate), + m_centerFrequency(centerFrequency) + { } + }; + + SSBDemod(DeviceSourceAPI *deviceAPI); virtual ~SSBDemod(); + void setSampleSink(BasebandSampleSink* sampleSink) { m_sampleSink = sampleSink; } void configure(MessageQueue* messageQueue, Real Bandwidth, @@ -164,6 +192,10 @@ private: { } }; + DeviceSourceAPI *m_deviceAPI; + ThreadedBasebandSampleSink* m_threadedChannelizer; + DownChannelizer* m_channelizer; + Real m_Bandwidth; Real m_LowCutoff; Real m_volume; diff --git a/plugins/channelrx/demodssb/ssbdemodgui.cpp b/plugins/channelrx/demodssb/ssbdemodgui.cpp index 2af1b61a4..de143e298 100644 --- a/plugins/channelrx/demodssb/ssbdemodgui.cpp +++ b/plugins/channelrx/demodssb/ssbdemodgui.cpp @@ -2,11 +2,9 @@ #include "ssbdemodgui.h" #include -#include #include #include -#include "dsp/threadedbasebandsamplesink.h" #include "ui_ssbdemodgui.h" #include "ui_ssbdemodgui.h" #include "dsp/spectrumvis.h" @@ -373,10 +371,9 @@ SSBDemodGUI::SSBDemodGUI(PluginAPI* pluginAPI, DeviceSourceAPI *deviceAPI, QWidg connect(this, SIGNAL(menuDoubleClickEvent()), this, SLOT(onMenuDoubleClicked())); m_spectrumVis = new SpectrumVis(ui->glSpectrum); - m_ssbDemod = new SSBDemod(m_spectrumVis); - m_channelizer = new DownChannelizer(m_ssbDemod); - m_threadedChannelizer = new ThreadedBasebandSampleSink(m_channelizer, this); - m_deviceAPI->addThreadedSink(m_threadedChannelizer); + m_ssbDemod = new SSBDemod(m_deviceAPI); + m_ssbDemod->setMessageQueueToGUI(getInputMessageQueue()); + m_ssbDemod->setSampleSink(m_spectrumVis); ui->deltaFrequencyLabel->setText(QString("%1f").arg(QChar(0x94, 0x03))); ui->deltaFrequency->setColorMapper(ColorMapper(ColorMapper::GrayGold)); @@ -389,7 +386,6 @@ SSBDemodGUI::SSBDemodGUI(PluginAPI* pluginAPI, DeviceSourceAPI *deviceAPI, QWidg connect(&m_pluginAPI->getMainWindow()->getMasterTimer(), SIGNAL(timeout()), this, SLOT(tick())); - //m_channelMarker = new ChannelMarker(this); m_channelMarker.setColor(Qt::green); m_channelMarker.setBandwidth(m_rate); m_channelMarker.setSidebands(ChannelMarker::usb); @@ -413,12 +409,8 @@ SSBDemodGUI::SSBDemodGUI(PluginAPI* pluginAPI, DeviceSourceAPI *deviceAPI, QWidg SSBDemodGUI::~SSBDemodGUI() { m_deviceAPI->removeChannelInstance(this); - m_deviceAPI->removeThreadedSink(m_threadedChannelizer); - delete m_threadedChannelizer; - delete m_channelizer; delete m_ssbDemod; delete m_spectrumVis; - //delete m_channelMarker; delete ui; } @@ -511,9 +503,9 @@ void SSBDemodGUI::applySettings() setTitleColor(m_channelMarker.getColor()); ui->deltaFrequency->setValue(m_channelMarker.getCenterFrequency()); - m_channelizer->configure(m_channelizer->getInputMessageQueue(), - 48000, - m_channelMarker.getCenterFrequency()); + SSBDemod::MsgConfigureChannelizer* channelConfigMsg = SSBDemod::MsgConfigureChannelizer::create( + 48000, m_channelMarker.getCenterFrequency()); + m_ssbDemod->getInputMessageQueue()->push(channelConfigMsg); m_ssbDemod->configure(m_ssbDemod->getInputMessageQueue(), ui->BW->value() * 100.0, diff --git a/plugins/channelrx/demodssb/ssbdemodgui.h b/plugins/channelrx/demodssb/ssbdemodgui.h index e59bf74c2..626bc0112 100644 --- a/plugins/channelrx/demodssb/ssbdemodgui.h +++ b/plugins/channelrx/demodssb/ssbdemodgui.h @@ -11,8 +11,6 @@ class PluginAPI; class DeviceSourceAPI; class AudioFifo; -class ThreadedBasebandSampleSink; -class DownChannelizer; class SSBDemod; class SpectrumVis; @@ -76,8 +74,6 @@ private: bool m_squelchOpen; uint32_t m_tickCount; - ThreadedBasebandSampleSink* m_threadedChannelizer; - DownChannelizer* m_channelizer; SSBDemod* m_ssbDemod; SpectrumVis* m_spectrumVis; MessageQueue m_inputMessageQueue; From 9b53041eea88ab2128d592a0bb03322b1581244f Mon Sep 17 00:00:00 2001 From: f4exb Date: Sun, 1 Oct 2017 23:22:06 +0200 Subject: [PATCH 53/71] SSB demod: added settings class --- plugins/channelrx/demodam/amdemodsettings.h | 2 +- plugins/channelrx/demodssb/CMakeLists.txt | 2 + plugins/channelrx/demodssb/demodssb.pro | 2 + .../channelrx/demodssb/ssbdemodsettings.cpp | 120 ++++++++++++++++++ plugins/channelrx/demodssb/ssbdemodsettings.h | 57 +++++++++ 5 files changed, 182 insertions(+), 1 deletion(-) create mode 100644 plugins/channelrx/demodssb/ssbdemodsettings.cpp create mode 100644 plugins/channelrx/demodssb/ssbdemodsettings.h diff --git a/plugins/channelrx/demodam/amdemodsettings.h b/plugins/channelrx/demodam/amdemodsettings.h index abbb12556..b07bc0c74 100644 --- a/plugins/channelrx/demodam/amdemodsettings.h +++ b/plugins/channelrx/demodam/amdemodsettings.h @@ -1,5 +1,5 @@ /////////////////////////////////////////////////////////////////////////////////// -// Copyright (C) 2015 Edouard Griffiths, F4EXB. // +// Copyright (C) 2017 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 // diff --git a/plugins/channelrx/demodssb/CMakeLists.txt b/plugins/channelrx/demodssb/CMakeLists.txt index f1b1449f1..53cf45296 100644 --- a/plugins/channelrx/demodssb/CMakeLists.txt +++ b/plugins/channelrx/demodssb/CMakeLists.txt @@ -3,12 +3,14 @@ project(ssb) set(ssb_SOURCES ssbdemod.cpp ssbdemodgui.cpp + ssbdemodsettings.cpp ssbplugin.cpp ) set(ssb_HEADERS ssbdemod.h ssbdemodgui.h + ssbdemodsettings.h ssbplugin.h ) diff --git a/plugins/channelrx/demodssb/demodssb.pro b/plugins/channelrx/demodssb/demodssb.pro index d65971658..6b347d66f 100644 --- a/plugins/channelrx/demodssb/demodssb.pro +++ b/plugins/channelrx/demodssb/demodssb.pro @@ -25,10 +25,12 @@ CONFIG(Debug):build_subdir = debug SOURCES += ssbdemod.cpp\ ssbdemodgui.cpp\ + ssbdemodsettings.cpp\ ssbplugin.cpp HEADERS += ssbdemod.h\ ssbdemodgui.h\ + ssbdemodsettings.h\ ssbplugin.h FORMS += ssbdemodgui.ui diff --git a/plugins/channelrx/demodssb/ssbdemodsettings.cpp b/plugins/channelrx/demodssb/ssbdemodsettings.cpp new file mode 100644 index 000000000..ff949ddbc --- /dev/null +++ b/plugins/channelrx/demodssb/ssbdemodsettings.cpp @@ -0,0 +1,120 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2017 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 // +// // +// This program is distributed in the hope that it will be useful, // +// but WITHOUT ANY WARRANTY; without even the implied warranty of // +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // +// GNU General Public License V3 for more details. // +// // +// You should have received a copy of the GNU General Public License // +// along with this program. If not, see . // +/////////////////////////////////////////////////////////////////////////////////// + +#include "dsp/dspengine.h" +#include "util/simpleserializer.h" +#include "settings/serializable.h" +#include "ssbdemodsettings.h" + +SSBDemodSettings::SSBDemodSettings() : + m_channelMarker(0), + m_spectrumGUI(0) +{ + resetToDefaults(); +} + +void SSBDemodSettings::resetToDefaults() +{ + m_audioBinaural = false; + m_audioFlipChannels = false; + m_dsb = false; + m_audioMute = false; + m_agc = false; + m_agcClamping = false; + m_agcPowerThreshold = -40; + m_agcThresholdGate = 4; + m_agcTimeLog2 = 7; + m_rfBandwidth = 3000; + m_lowCutoff = 300; + m_volume = 3.0; + m_spanLog2 = 3; + m_inputSampleRate = 96000; + m_inputFrequencyOffset = 0; +} + +QByteArray SSBDemodSettings::serialize() const +{ + SimpleSerializer s(1); + s.writeS32(1, m_inputFrequencyOffset); + s.writeS32(2, m_rfBandwidth / 100.0); + s.writeS32(3, m_volume * 10.0); + + if (m_spectrumGUI) { + s.writeBlob(4, m_spectrumGUI->serialize()); + } + + s.writeU32(5, m_rgbColor); + s.writeS32(6, m_lowCutoff / 100.0); + s.writeS32(7, m_spanLog2); + s.writeBool(8, m_audioBinaural); + s.writeBool(9, m_audioFlipChannels); + s.writeBool(10, m_dsb); + s.writeBool(11, m_agc); + s.writeS32(12, m_agcTimeLog2); + s.writeS32(13, m_agcPowerThreshold); + s.writeS32(14, m_agcThresholdGate); + s.writeBool(15, m_agcClamping); + return s.final(); +} + +bool SSBDemodSettings::deserialize(const QByteArray& data) +{ + SimpleDeserializer d(data); + + if(!d.isValid()) + { + resetToDefaults(); + return false; + } + + if(d.getVersion() == 1) + { + QByteArray bytetmp; + qint32 tmp; + QString strtmp; + + d.readS32(1, &m_inputFrequencyOffset, 0); + d.readS32(2, &tmp, 30); + m_rfBandwidth = tmp * 100.0; + d.readS32(3, &tmp, 30); + m_volume = tmp / 10.0; + + if (m_spectrumGUI) { + d.readBlob(4, &bytetmp); + m_spectrumGUI->deserialize(bytetmp); + } + + d.readU32(5, &m_rgbColor); + d.readS32(6, &tmp, 30); + m_lowCutoff = tmp * 100.0; + d.readS32(7, &m_spanLog2, 3); + d.readBool(8, &m_audioBinaural, false); + d.readBool(9, &m_audioFlipChannels, false); + d.readBool(10, &m_dsb, false); + d.readBool(11, &m_agc, false); + d.readS32(12, &m_agcTimeLog2, 7); + d.readS32(13, &m_agcPowerThreshold, -40); + d.readS32(14, &m_agcThresholdGate, 4); + d.readBool(15, &m_agcClamping, false); + + return true; + } + else + { + resetToDefaults(); + return false; + } +} diff --git a/plugins/channelrx/demodssb/ssbdemodsettings.h b/plugins/channelrx/demodssb/ssbdemodsettings.h new file mode 100644 index 000000000..30ec2e3ee --- /dev/null +++ b/plugins/channelrx/demodssb/ssbdemodsettings.h @@ -0,0 +1,57 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2017 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 // +// // +// This program is distributed in the hope that it will be useful, // +// but WITHOUT ANY WARRANTY; without even the implied warranty of // +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // +// GNU General Public License V3 for more details. // +// // +// You should have received a copy of the GNU General Public License // +// along with this program. If not, see . // +/////////////////////////////////////////////////////////////////////////////////// + +#ifndef PLUGINS_CHANNELRX_DEMODSSB_SSBDEMODSETTINGS_H_ +#define PLUGINS_CHANNELRX_DEMODSSB_SSBDEMODSETTINGS_H_ + +#include + +class Serializable; + +struct SSBDemodSettings +{ + int m_inputSampleRate; + qint32 m_inputFrequencyOffset; + Real m_rfBandwidth; + Real m_lowCutoff; + Real m_volume; + int m_spanLog2; + bool m_audioBinaural; + bool m_audioFlipChannels; + bool m_dsb; + bool m_audioMute; + bool m_agc; + bool m_agcClamping; + int m_agcTimeLog2; + int m_agcPowerThreshold; + int m_agcThresholdGate; + QString m_udpAddress; + quint16 m_udpPort; + quint32 m_rgbColor; + + Serializable *m_channelMarker; + Serializable *m_spectrumGUI; + + SSBDemodSettings(); + void resetToDefaults(); + void setChannelMarker(Serializable *channelMarker) { m_channelMarker = channelMarker; } + void setSpectrumGUI(Serializable *spectrumGUI) { m_spectrumGUI = spectrumGUI; } + QByteArray serialize() const; + bool deserialize(const QByteArray& data); +}; + + +#endif /* PLUGINS_CHANNELRX_DEMODSSB_SSBDEMODSETTINGS_H_ */ From 673047c7e296aa1894015fba47daeb7855d22f92 Mon Sep 17 00:00:00 2001 From: f4exb Date: Mon, 2 Oct 2017 01:45:19 +0200 Subject: [PATCH 54/71] SSB demod: use settings class in demod --- plugins/channelrx/demodssb/ssbdemod.cpp | 232 +++++++++++------- plugins/channelrx/demodssb/ssbdemod.h | 39 ++- plugins/channelrx/demodssb/ssbdemodgui.cpp | 232 +++++++++--------- plugins/channelrx/demodssb/ssbdemodgui.h | 6 +- .../channelrx/demodssb/ssbdemodsettings.cpp | 4 + plugins/channelrx/demodssb/ssbdemodsettings.h | 1 + 6 files changed, 301 insertions(+), 213 deletions(-) diff --git a/plugins/channelrx/demodssb/ssbdemod.cpp b/plugins/channelrx/demodssb/ssbdemod.cpp index 715d1bd40..2a01da180 100644 --- a/plugins/channelrx/demodssb/ssbdemod.cpp +++ b/plugins/channelrx/demodssb/ssbdemod.cpp @@ -31,6 +31,7 @@ #include "ssbdemod.h" MESSAGE_CLASS_DEFINITION(SSBDemod::MsgConfigureSSBDemod, Message) +MESSAGE_CLASS_DEFINITION(SSBDemod::MsgConfigureSSBDemodPrivate, Message) MESSAGE_CLASS_DEFINITION(SSBDemod::MsgConfigureChannelizer, Message) SSBDemod::SSBDemod(DeviceSourceAPI *deviceAPI) : @@ -86,6 +87,8 @@ SSBDemod::SSBDemod(DeviceSourceAPI *deviceAPI) : m_deviceAPI->addThreadedSink(m_threadedChannelizer); DSPEngine::instance()->addAudioSink(&m_audioFifo); + + applySettings(m_settings, true); } SSBDemod::~SSBDemod() @@ -115,7 +118,7 @@ void SSBDemod::configure(MessageQueue* messageQueue, int agcPowerThreshold, int agcThresholdGate) { - Message* cmd = MsgConfigureSSBDemod::create( + Message* cmd = MsgConfigureSSBDemodPrivate::create( Bandwidth, LowCutoff, volume, @@ -276,10 +279,6 @@ void SSBDemod::stop() bool SSBDemod::handleMessage(const Message& cmd) { - float band, lowCutoff; - - qDebug() << "SSBDemod::handleMessage"; - if (DownChannelizer::MsgChannelizerNotification::match(cmd)) { DownChannelizer::MsgChannelizerNotification& notif = (DownChannelizer::MsgChannelizerNotification&) cmd; @@ -306,96 +305,40 @@ bool SSBDemod::handleMessage(const Message& cmd) cfg.getSampleRate(), cfg.getCenterFrequency()); + qDebug() << "SSBDemod::handleMessage: MsgConfigureChannelizer: sampleRate: " << cfg.getSampleRate() + << " centerFrequency: " << cfg.getCenterFrequency(); + return true; } - else if (MsgConfigureSSBDemod::match(cmd)) - { - MsgConfigureSSBDemod& cfg = (MsgConfigureSSBDemod&) cmd; + else if (MsgConfigureSSBDemod::match(cmd)) + { + MsgConfigureSSBDemod& cfg = (MsgConfigureSSBDemod&) cmd; - m_settingsMutex.lock(); + SSBDemodSettings settings = cfg.getSettings(); - band = cfg.getBandwidth(); - lowCutoff = cfg.getLoCutoff(); + // These settings are set with DownChannelizer::MsgChannelizerNotification + settings.m_inputSampleRate = m_settings.m_inputSampleRate; + settings.m_inputFrequencyOffset = m_settings.m_inputFrequencyOffset; - if (band < 0) { - band = -band; - lowCutoff = -lowCutoff; - m_usb = false; - } else - m_usb = true; + applySettings(settings, cfg.getForce()); - if (band < 100.0f) - { - band = 100.0f; - lowCutoff = 0; - } - m_Bandwidth = band; - m_LowCutoff = lowCutoff; + qDebug() << "SSBDemod::handleMessage: MsgConfigureSSBDemod:" + << " m_rfBandwidth: " << settings.m_rfBandwidth + << " m_lowCutoff: " << settings.m_lowCutoff + << " m_volume: " << settings.m_volume + << " m_spanLog2: " << settings.m_spanLog2 + << " m_audioBinaual: " << settings.m_audioBinaural + << " m_audioFlipChannels: " << settings.m_audioFlipChannels + << " m_dsb: " << settings.m_dsb + << " m_audioMute: " << settings.m_audioMute + << " m_agcActive: " << settings.m_agc + << " m_agcClamping: " << settings.m_agcClamping + << " m_agcTimeLog2: " << settings.m_agcTimeLog2 + << " agcPowerThreshold: " << settings.m_agcPowerThreshold + << " agcThresholdGate: " << settings.m_agcThresholdGate; - m_interpolator.create(16, m_sampleRate, band * 2.0f); - SSBFilter->create_filter(m_LowCutoff / (float) m_audioSampleRate, m_Bandwidth / (float) m_audioSampleRate); - DSBFilter->create_dsb_filter((2.0f * m_Bandwidth) / (float) m_audioSampleRate); - - m_volume = cfg.getVolume(); - //m_volume *= 2.0; // for 327.68 - m_volume /= 4.0; // for 3276.8 - - m_spanLog2 = cfg.getSpanLog2(); - m_audioBinaual = cfg.getAudioBinaural(); - m_audioFlipChannels = cfg.getAudioFlipChannels(); - m_dsb = cfg.getDSB(); - m_audioMute = cfg.getAudioMute(); - m_agcActive = cfg.getAGC(); - - int agcNbSamples = 48 * (1<create_filter(m_LowCutoff / (float) m_audioSampleRate, m_Bandwidth / (float) m_audioSampleRate); + DSBFilter->create_dsb_filter((2.0f * m_Bandwidth) / (float) m_audioSampleRate); + m_settingsMutex.unlock(); + } + + if ((m_settings.m_volume != settings.m_volume) || force) + { + m_volume = settings.m_volume; + m_volume /= 4.0; // for 3276.8 + } + + if ((m_settings.m_agcTimeLog2 != settings.m_agcTimeLog2) || + (m_settings.m_agcPowerThreshold != settings.m_agcPowerThreshold) || + (m_settings.m_agcThresholdGate != settings.m_agcThresholdGate) || + (m_settings.m_agcClamping != settings.m_agcClamping) || force) + { + int agcNbSamples = 48 * (1<setAddress(const_cast(settings.m_udpAddress)); +// m_udpBufferAudio->setPort(settings.m_udpPort); +// } + + m_spanLog2 = settings.m_spanLog2; + m_audioBinaual = settings.m_audioBinaural; + m_audioFlipChannels = settings.m_audioFlipChannels; + m_dsb = settings.m_dsb; + m_audioMute = settings.m_audioMute; + m_agcActive = settings.m_agc; + + m_settings = settings; +} + diff --git a/plugins/channelrx/demodssb/ssbdemod.h b/plugins/channelrx/demodssb/ssbdemod.h index 2e23568d4..f5b148f3d 100644 --- a/plugins/channelrx/demodssb/ssbdemod.h +++ b/plugins/channelrx/demodssb/ssbdemod.h @@ -18,9 +18,10 @@ #ifndef INCLUDE_SSBDEMOD_H #define INCLUDE_SSBDEMOD_H -#include #include #include + +#include #include "dsp/ncof.h" #include "dsp/interpolator.h" #include "dsp/fftfilt.h" @@ -28,6 +29,8 @@ #include "audio/audiofifo.h" #include "util/message.h" +#include "ssbdemodsettings.h" + #define ssbFftLen 1024 #define agcTarget 3276.8 // -10 dB amplitude => -20 dB power: center of normal signal @@ -37,6 +40,29 @@ class DownChannelizer; class SSBDemod : public BasebandSampleSink { public: + class MsgConfigureSSBDemod : public Message { + MESSAGE_CLASS_DECLARATION + + public: + const SSBDemodSettings& getSettings() const { return m_settings; } + bool getForce() const { return m_force; } + + static MsgConfigureSSBDemod* create(const SSBDemodSettings& settings, bool force) + { + return new MsgConfigureSSBDemod(settings, force); + } + + private: + SSBDemodSettings m_settings; + bool m_force; + + MsgConfigureSSBDemod(const SSBDemodSettings& settings, bool force) : + Message(), + m_settings(settings), + m_force(force) + { } + }; + class MsgConfigureChannelizer : public Message { MESSAGE_CLASS_DECLARATION @@ -99,7 +125,7 @@ public: } private: - class MsgConfigureSSBDemod : public Message { + class MsgConfigureSSBDemodPrivate : public Message { MESSAGE_CLASS_DECLARATION public: @@ -117,7 +143,7 @@ private: int getAGCPowerThershold() const { return m_agcPowerThreshold; } int getAGCThersholdGate() const { return m_agcThresholdGate; } - static MsgConfigureSSBDemod* create(Real Bandwidth, + static MsgConfigureSSBDemodPrivate* create(Real Bandwidth, Real LowCutoff, Real volume, int spanLog2, @@ -131,7 +157,7 @@ private: int agcPowerThreshold, int agcThresholdGate) { - return new MsgConfigureSSBDemod( + return new MsgConfigureSSBDemodPrivate( Bandwidth, LowCutoff, volume, @@ -162,7 +188,7 @@ private: int m_agcPowerThreshold; int m_agcThresholdGate; - MsgConfigureSSBDemod(Real Bandwidth, + MsgConfigureSSBDemodPrivate(Real Bandwidth, Real LowCutoff, Real volume, int spanLog2, @@ -195,6 +221,7 @@ private: DeviceSourceAPI *m_deviceAPI; ThreadedBasebandSampleSink* m_threadedChannelizer; DownChannelizer* m_channelizer; + SSBDemodSettings m_settings; Real m_Bandwidth; Real m_LowCutoff; @@ -236,6 +263,8 @@ private: quint32 m_audioSampleRate; QMutex m_settingsMutex; + + void applySettings(const SSBDemodSettings& settings, bool force = false); }; #endif // INCLUDE_SSBDEMOD_H diff --git a/plugins/channelrx/demodssb/ssbdemodgui.cpp b/plugins/channelrx/demodssb/ssbdemodgui.cpp index de143e298..80ba67b83 100644 --- a/plugins/channelrx/demodssb/ssbdemodgui.cpp +++ b/plugins/channelrx/demodssb/ssbdemodgui.cpp @@ -5,7 +5,6 @@ #include #include -#include "ui_ssbdemodgui.h" #include "ui_ssbdemodgui.h" #include "dsp/spectrumvis.h" #include "gui/glspectrum.h" @@ -48,113 +47,36 @@ qint64 SSBDemodGUI::getCenterFrequency() const void SSBDemodGUI::setCenterFrequency(qint64 centerFrequency) { m_channelMarker.setCenterFrequency(centerFrequency); + m_settings.m_inputFrequencyOffset = m_channelMarker.getCenterFrequency(); applySettings(); } void SSBDemodGUI::resetToDefaults() { - blockApplySettings(true); - - ui->BW->setValue(30); - ui->volume->setValue(30); - ui->deltaFrequency->setValue(0); - ui->spanLog2->setValue(3); - ui->agc->setChecked(false); - ui->agcTimeLog2->setValue(7); - ui->agcPowerThreshold->setValue(-40); - ui->agcThresholdGate->setValue(4); - - blockApplySettings(false); + m_settings.resetToDefaults(); } QByteArray SSBDemodGUI::serialize() const { - SimpleSerializer s(1); - s.writeS32(1, m_channelMarker.getCenterFrequency()); - s.writeS32(2, ui->BW->value()); - s.writeS32(3, ui->volume->value()); - s.writeBlob(4, ui->spectrumGUI->serialize()); - s.writeU32(5, m_channelMarker.getColor().rgb()); - s.writeS32(6, ui->lowCut->value()); - s.writeS32(7, ui->spanLog2->value()); - s.writeBool(8, m_audioBinaural); - s.writeBool(9, m_audioFlipChannels); - s.writeBool(10, m_dsb); - s.writeBool(11, ui->agc->isChecked()); - s.writeS32(12, ui->agcTimeLog2->value()); - s.writeS32(13, ui->agcPowerThreshold->value()); - s.writeS32(14, ui->agcThresholdGate->value()); - s.writeBool(15, ui->agcClamping->isChecked()); - return s.final(); + return m_settings.serialize(); } bool SSBDemodGUI::deserialize(const QByteArray& data) { - SimpleDeserializer d(data); - - if (!d.isValid()) - { - resetToDefaults(); - applySettings(); - return false; - } - - if (d.getVersion() == 1) - { - QByteArray bytetmp; - quint32 u32tmp; - qint32 tmp; - bool booltmp; - - blockApplySettings(true); - m_channelMarker.blockSignals(true); - - d.readS32(1, &tmp, 0); - m_channelMarker.setCenterFrequency(tmp); - d.readS32(2, &tmp, 30); - ui->BW->setValue(tmp); - d.readS32(3, &tmp, 30); - ui->volume->setValue(tmp); - d.readBlob(4, &bytetmp); - ui->spectrumGUI->deserialize(bytetmp); - if(d.readU32(5, &u32tmp)) - m_channelMarker.setColor(u32tmp); - d.readS32(6, &tmp, 3); - ui->lowCut->setValue(tmp); - d.readS32(7, &tmp, 20); - ui->spanLog2->setValue(tmp); - setNewRate(tmp); - d.readBool(8, &m_audioBinaural); - ui->audioBinaural->setChecked(m_audioBinaural); - d.readBool(9, &m_audioFlipChannels); - ui->audioFlipChannels->setChecked(m_audioFlipChannels); - d.readBool(10, &m_dsb); - ui->dsb->setChecked(m_dsb); - d.readBool(11, &booltmp, false); - ui->agc->setChecked(booltmp); - d.readS32(12, &tmp, 7); - ui->agcTimeLog2->setValue(tmp); - d.readS32(13, &tmp, -40); - ui->agcPowerThreshold->setValue(tmp); - d.readS32(14, &tmp, 4); - ui->agcThresholdGate->setValue(tmp); - d.readBool(15, &booltmp, false); - ui->agcClamping->setChecked(booltmp); - + if(m_settings.deserialize(data)) + { + updateChannelMarker(); displaySettings(); - - blockApplySettings(false); - m_channelMarker.blockSignals(false); - - applySettings(); - return true; - } - else - { - resetToDefaults(); - applySettings(); - return false; - } + applySettings(true); // will have true + return true; + } + else + { + m_settings.resetToDefaults(); + displaySettings(); + applySettings(true); // will have true + return false; + } } bool SSBDemodGUI::handleMessage(const Message& message __attribute__((unused))) @@ -170,18 +92,21 @@ void SSBDemodGUI::viewChanged() void SSBDemodGUI::on_audioBinaural_toggled(bool binaural) { m_audioBinaural = binaural; + m_settings.m_audioBinaural = binaural; applySettings(); } void SSBDemodGUI::on_audioFlipChannels_toggled(bool flip) { m_audioFlipChannels = flip; + m_settings.m_audioFlipChannels = flip; applySettings(); } void SSBDemodGUI::on_dsb_toggled(bool dsb) { m_dsb = dsb; + m_settings.m_dsb = dsb; if (m_dsb) { @@ -218,6 +143,8 @@ void SSBDemodGUI::on_dsb_toggled(bool dsb) void SSBDemodGUI::on_deltaFrequency_changed(qint64 value) { m_channelMarker.setCenterFrequency(value); + m_settings.m_inputFrequencyOffset = m_channelMarker.getCenterFrequency(); + applySettings(); } void SSBDemodGUI::on_BW_valueChanged(int value) @@ -234,6 +161,7 @@ void SSBDemodGUI::on_BW_valueChanged(int value) ui->BWText->setText(tr("%1k").arg(s)); } + m_settings.m_rfBandwidth = value * 100; on_lowCut_valueChanged(m_channelMarker.getLowCutoff()/100); setNewRate(m_spanLog2); } @@ -277,22 +205,26 @@ void SSBDemodGUI::on_lowCut_valueChanged(int value) QString s = QString::number(lowCutoff/1000.0, 'f', 1); ui->lowCutText->setText(tr("%1k").arg(s)); ui->lowCut->setValue(lowCutoff/100); + m_settings.m_lowCutoff = lowCutoff; applySettings(); } void SSBDemodGUI::on_volume_valueChanged(int value) { ui->volumeText->setText(QString("%1").arg(value / 10.0, 0, 'f', 1)); + m_settings.m_volume = value / 10.0; applySettings(); } -void SSBDemodGUI::on_agc_toggled(bool checked __attribute((__unused__))) +void SSBDemodGUI::on_agc_toggled(bool checked) { + m_settings.m_agc = checked; applySettings(); } -void SSBDemodGUI::on_agcClamping_toggled(bool checked __attribute((__unused__))) +void SSBDemodGUI::on_agcClamping_toggled(bool checked) { + m_settings.m_agcClamping = checked; applySettings(); } @@ -300,12 +232,14 @@ void SSBDemodGUI::on_agcTimeLog2_valueChanged(int value) { QString s = QString::number((1<agcTimeText->setText(s); + m_settings.m_agcTimeLog2 = value; applySettings(); } void SSBDemodGUI::on_agcPowerThreshold_valueChanged(int value) { displayAGCPowerThreshold(value); + m_settings.m_agcPowerThreshold = value; applySettings(); } @@ -313,12 +247,14 @@ void SSBDemodGUI::on_agcThresholdGate_valueChanged(int value) { QString s = QString::number(value, 'f', 0); ui->agcThresholdGateText->setText(s); + m_settings.m_agcThresholdGate = value; applySettings(); } void SSBDemodGUI::on_audioMute_toggled(bool checked) { m_audioMute = checked; + m_settings.m_audioMute = checked; applySettings(); } @@ -326,6 +262,7 @@ void SSBDemodGUI::on_spanLog2_valueChanged(int value) { if (setNewRate(value)) { + m_settings.m_spanLog2 = value; applySettings(); } @@ -386,12 +323,11 @@ SSBDemodGUI::SSBDemodGUI(PluginAPI* pluginAPI, DeviceSourceAPI *deviceAPI, QWidg connect(&m_pluginAPI->getMainWindow()->getMasterTimer(), SIGNAL(timeout()), this, SLOT(tick())); - m_channelMarker.setColor(Qt::green); - m_channelMarker.setBandwidth(m_rate); - m_channelMarker.setSidebands(ChannelMarker::usb); - m_channelMarker.setCenterFrequency(0); m_channelMarker.setVisible(true); + m_settings.setChannelMarker(&m_channelMarker); + m_settings.setSpectrumGUI(ui->spectrumGUI); + connect(&m_channelMarker, SIGNAL(changed()), this, SLOT(viewChanged())); m_deviceAPI->registerChannelInstance(m_channelID, this); @@ -400,9 +336,8 @@ SSBDemodGUI::SSBDemodGUI(PluginAPI* pluginAPI, DeviceSourceAPI *deviceAPI, QWidg ui->spectrumGUI->setBuddies(m_spectrumVis->getInputMessageQueue(), m_spectrumVis, ui->glSpectrum); - resetToDefaults(); displaySettings(); - applySettings(); + applySettings(true); setNewRate(m_spanLog2); } @@ -446,7 +381,6 @@ bool SSBDemodGUI::setNewRate(int spanLog2) m_channelMarker.setLowCutoff(m_rate); } - QString s = QString::number(m_rate/1000.0, 'f', 1); if (m_dsb) @@ -496,7 +430,7 @@ void SSBDemodGUI::blockApplySettings(bool block) m_doApplySettings = !block; } -void SSBDemodGUI::applySettings() +void SSBDemodGUI::applySettings(bool force) { if (m_doApplySettings) { @@ -507,30 +441,90 @@ void SSBDemodGUI::applySettings() 48000, m_channelMarker.getCenterFrequency()); m_ssbDemod->getInputMessageQueue()->push(channelConfigMsg); - m_ssbDemod->configure(m_ssbDemod->getInputMessageQueue(), - ui->BW->value() * 100.0, - ui->lowCut->value() * 100.0, - ui->volume->value() / 10.0, - m_spanLog2, - m_audioBinaural, - m_audioFlipChannels, - m_dsb, - ui->audioMute->isChecked(), - ui->agc->isChecked(), - ui->agcClamping->isChecked(), - ui->agcTimeLog2->value(), - ui->agcPowerThreshold->value(), - ui->agcThresholdGate->value()); + SSBDemod::MsgConfigureSSBDemod* message = SSBDemod::MsgConfigureSSBDemod::create( m_settings, force); + m_ssbDemod->getInputMessageQueue()->push(message); } } void SSBDemodGUI::displaySettings() { - QString s = QString::number((1<agcTimeLog2->value()), 'f', 0); + m_channelMarker.blockSignals(true); + m_channelMarker.setCenterFrequency(m_settings.m_inputFrequencyOffset); + m_channelMarker.setBandwidth(m_settings.m_rfBandwidth * 2); + m_channelMarker.setLowCutoff(m_settings.m_lowCutoff); + m_channelMarker.setUDPAddress(m_settings.m_udpAddress); + m_channelMarker.setUDPSendPort(m_settings.m_udpPort); + m_channelMarker.setColor(m_settings.m_rgbColor); + setTitleColor(m_settings.m_rgbColor); + + if (m_settings.m_dsb) { + m_channelMarker.setSidebands(ChannelMarker::dsb); + } else { + if (m_settings.m_rfBandwidth < 0) { + m_channelMarker.setSidebands(ChannelMarker::lsb); + } else { + m_channelMarker.setSidebands(ChannelMarker::usb); + } + } + + m_channelMarker.blockSignals(false); + + blockApplySettings(true); + + ui->agc->setChecked(m_settings.m_agc); + ui->agcClamping->setChecked(m_settings.m_agcClamping); + ui->audioBinaural->setChecked(m_settings.m_audioBinaural); + ui->audioFlipChannels->setChecked(m_settings.m_audioFlipChannels); + ui->audioMute->setChecked(m_settings.m_audioMute); + ui->deltaFrequency->setValue(m_channelMarker.getCenterFrequency()); + ui->dsb->setChecked(m_settings.m_dsb); + ui->spanLog2->setValue(m_settings.m_spanLog2); + + ui->BW->setValue(m_settings.m_rfBandwidth / 100.0); + QString s = QString::number(m_settings.m_rfBandwidth/1000.0, 'f', 1); + + if (m_settings.m_dsb) + { + ui->BWText->setText(tr("%1%2k").arg(QChar(0xB1, 0x00)).arg(s)); + } + else + { + ui->BWText->setText(tr("%1k").arg(s)); + } + + ui->lowCut->setValue(m_settings.m_lowCutoff / 100.0); + ui->lowCutText->setText(tr("%1k").arg(m_settings.m_lowCutoff / 1000.0)); + + ui->volume->setValue(m_settings.m_volume * 10.0); + ui->volumeText->setText(QString("%1").arg(m_settings.m_volume, 0, 'f', 1)); + + ui->agcTimeLog2->setValue(m_settings.m_agcTimeLog2); + s = QString::number((1<agcTimeLog2->value()), 'f', 0); ui->agcTimeText->setText(s); + + ui->agcPowerThreshold->setValue(m_settings.m_agcPowerThreshold); displayAGCPowerThreshold(ui->agcPowerThreshold->value()); + + ui->agcThresholdGate->setValue(m_settings.m_agcThresholdGate); s = QString::number(ui->agcThresholdGate->value(), 'f', 0); ui->agcThresholdGateText->setText(s); + + blockApplySettings(false); +} + +void SSBDemodGUI::displayUDPAddress() +{ + //TODO: ui->copyAudioToUDP->setToolTip(QString("Copy audio output to UDP %1:%2").arg(m_channelMarker.getUDPAddress()).arg(m_channelMarker.getUDPSendPort())); +} + +void SSBDemodGUI::updateChannelMarker() +{ + m_channelMarker.blockSignals(true); + + //m_channelMarker.deserialize(m_settings.m_channelMarkerBytes); + this->setWindowTitle(m_channelMarker.getTitle()); + + m_channelMarker.blockSignals(false); } void SSBDemodGUI::displayAGCPowerThreshold(int value) diff --git a/plugins/channelrx/demodssb/ssbdemodgui.h b/plugins/channelrx/demodssb/ssbdemodgui.h index 626bc0112..789707e0f 100644 --- a/plugins/channelrx/demodssb/ssbdemodgui.h +++ b/plugins/channelrx/demodssb/ssbdemodgui.h @@ -6,6 +6,7 @@ #include "dsp/channelmarker.h" #include "dsp/movingaverage.h" #include "util/messagequeue.h" +#include "ssbdemodsettings.h" class PluginAPI; class DeviceSourceAPI; @@ -63,6 +64,7 @@ private: PluginAPI* m_pluginAPI; DeviceSourceAPI* m_deviceAPI; ChannelMarker m_channelMarker; + SSBDemodSettings m_settings; bool m_basicSettingsShown; bool m_doApplySettings; int m_rate; @@ -85,8 +87,10 @@ private: bool setNewRate(int spanLog2); void blockApplySettings(bool block); - void applySettings(); + void applySettings(bool force = false); void displaySettings(); + void displayUDPAddress(); + void updateChannelMarker(); void displayAGCPowerThreshold(int value); diff --git a/plugins/channelrx/demodssb/ssbdemodsettings.cpp b/plugins/channelrx/demodssb/ssbdemodsettings.cpp index ff949ddbc..fd18ea716 100644 --- a/plugins/channelrx/demodssb/ssbdemodsettings.cpp +++ b/plugins/channelrx/demodssb/ssbdemodsettings.cpp @@ -14,6 +14,8 @@ // along with this program. If not, see . // /////////////////////////////////////////////////////////////////////////////////// +#include + #include "dsp/dspengine.h" #include "util/simpleserializer.h" #include "settings/serializable.h" @@ -43,6 +45,8 @@ void SSBDemodSettings::resetToDefaults() m_spanLog2 = 3; m_inputSampleRate = 96000; m_inputFrequencyOffset = 0; + m_audioSampleRate = DSPEngine::instance()->getAudioSampleRate(); + m_rgbColor = QColor(0, 255, 0).rgb(); } QByteArray SSBDemodSettings::serialize() const diff --git a/plugins/channelrx/demodssb/ssbdemodsettings.h b/plugins/channelrx/demodssb/ssbdemodsettings.h index 30ec2e3ee..0fc1ca589 100644 --- a/plugins/channelrx/demodssb/ssbdemodsettings.h +++ b/plugins/channelrx/demodssb/ssbdemodsettings.h @@ -25,6 +25,7 @@ struct SSBDemodSettings { int m_inputSampleRate; qint32 m_inputFrequencyOffset; + quint32 m_audioSampleRate; Real m_rfBandwidth; Real m_lowCutoff; Real m_volume; From 610333a88359590cb9f33d6754fceed61d3aacde Mon Sep 17 00:00:00 2001 From: f4exb Date: Mon, 2 Oct 2017 01:46:06 +0200 Subject: [PATCH 55/71] SSB demod: updated version --- plugins/channelrx/demodssb/ssbplugin.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/channelrx/demodssb/ssbplugin.cpp b/plugins/channelrx/demodssb/ssbplugin.cpp index 1b9218a23..3373cdc03 100644 --- a/plugins/channelrx/demodssb/ssbplugin.cpp +++ b/plugins/channelrx/demodssb/ssbplugin.cpp @@ -7,7 +7,7 @@ const PluginDescriptor SSBPlugin::m_pluginDescriptor = { QString("SSB Demodulator"), - QString("3.5.4"), + QString("3.7.3"), QString("(c) Edouard Griffiths, F4EXB"), QString("https://github.com/f4exb/sdrangel"), true, From 918aff8b8fffee3cab9a283d9fbdffd208e18234 Mon Sep 17 00:00:00 2001 From: f4exb Date: Mon, 2 Oct 2017 13:56:40 +0200 Subject: [PATCH 56/71] DSD demod: separate GUI from demod --- plugins/channelrx/demoddsd/CMakeLists.txt | 2 + plugins/channelrx/demoddsd/demoddsd.pro | 6 ++- plugins/channelrx/demoddsd/dsddemod.cpp | 32 ++++++++++-- plugins/channelrx/demoddsd/dsddemod.h | 39 ++++++++++++--- .../channelrx/demoddsd/dsddemodbaudrates.cpp | 50 +++++++++++++++++++ .../channelrx/demoddsd/dsddemodbaudrates.h | 35 +++++++++++++ plugins/channelrx/demoddsd/dsddemodgui.cpp | 49 +++--------------- plugins/channelrx/demoddsd/dsddemodgui.h | 18 ------- 8 files changed, 158 insertions(+), 73 deletions(-) create mode 100644 plugins/channelrx/demoddsd/dsddemodbaudrates.cpp create mode 100644 plugins/channelrx/demoddsd/dsddemodbaudrates.h diff --git a/plugins/channelrx/demoddsd/CMakeLists.txt b/plugins/channelrx/demoddsd/CMakeLists.txt index 04823c5a4..6547bdef5 100644 --- a/plugins/channelrx/demoddsd/CMakeLists.txt +++ b/plugins/channelrx/demoddsd/CMakeLists.txt @@ -4,6 +4,7 @@ set(dsddemod_SOURCES dsddemod.cpp dsddemodgui.cpp dsddemodplugin.cpp + dsddemodbaudrates.cpp dsddecoder.cpp ) @@ -11,6 +12,7 @@ set(dsddemod_HEADERS dsddemod.h dsddemodgui.h dsddemodplugin.h + dsddemodbaudrates.h dsddecoder.h ) diff --git a/plugins/channelrx/demoddsd/demoddsd.pro b/plugins/channelrx/demoddsd/demoddsd.pro index 3255ff461..6f7f0f900 100644 --- a/plugins/channelrx/demoddsd/demoddsd.pro +++ b/plugins/channelrx/demoddsd/demoddsd.pro @@ -40,12 +40,14 @@ CONFIG(Debug):build_subdir = debug SOURCES = dsddecoder.cpp\ dsddemod.cpp\ dsddemodgui.cpp\ -dsddemodplugin.cpp +dsddemodplugin.cpp\ +dsddemodbaudrates.cpp HEADERS = dsddecoder.h\ dsddemod.h\ dsddemodgui.h\ -dsddemodplugin.h +dsddemodplugin.h\ +dsddemodbaudrates.h FORMS = dsddemodgui.ui diff --git a/plugins/channelrx/demoddsd/dsddemod.cpp b/plugins/channelrx/demoddsd/dsddemod.cpp index d1bf7df5c..d06502a9f 100644 --- a/plugins/channelrx/demoddsd/dsddemod.cpp +++ b/plugins/channelrx/demoddsd/dsddemod.cpp @@ -15,24 +15,30 @@ // along with this program. If not, see . // /////////////////////////////////////////////////////////////////////////////////// -#include "../../channelrx/demoddsd/dsddemod.h" #include #include #include #include + #include #include "audio/audiooutput.h" #include "dsp/pidcontroller.h" #include "dsp/dspengine.h" -#include "dsddemodgui.h" +#include "dsp/threadedbasebandsamplesink.h" +#include +#include +#include "dsddemod.h" + +MESSAGE_CLASS_DEFINITION(DSDDemod::MsgConfigureChannelizer, Message) MESSAGE_CLASS_DEFINITION(DSDDemod::MsgConfigureDSDDemod, Message) MESSAGE_CLASS_DEFINITION(DSDDemod::MsgConfigureMyPosition, Message) const int DSDDemod::m_udpBlockSize = 512; -DSDDemod::DSDDemod(BasebandSampleSink* sampleSink) : +DSDDemod::DSDDemod(DeviceSourceAPI *deviceAPI) : + m_deviceAPI(deviceAPI), m_sampleCount(0), m_squelchCount(0), m_squelchOpen(false), @@ -40,7 +46,7 @@ DSDDemod::DSDDemod(BasebandSampleSink* sampleSink) : m_fmExcursion(24), m_audioFifo1(48000), m_audioFifo2(48000), - m_scope(sampleSink), + m_scope(0), m_scopeEnabled(true), m_dsdDecoder(), m_settingsMutex(QMutex::Recursive) @@ -79,6 +85,10 @@ DSDDemod::DSDDemod(BasebandSampleSink* sampleSink) : m_audioFifo1.setUDPSink(m_udpBufferAudio); m_audioFifo2.setUDPSink(m_udpBufferAudio); + m_channelizer = new DownChannelizer(this); + m_threadedChannelizer = new ThreadedBasebandSampleSink(m_channelizer, this); + m_deviceAPI->addThreadedSink(m_threadedChannelizer); + apply(true); } @@ -88,6 +98,10 @@ DSDDemod::~DSDDemod() DSPEngine::instance()->removeAudioSink(&m_audioFifo1); DSPEngine::instance()->removeAudioSink(&m_audioFifo2); delete m_udpBufferAudio; + + m_deviceAPI->removeThreadedSink(m_threadedChannelizer); + delete m_threadedChannelizer; + delete m_channelizer; } void DSDDemod::configure(MessageQueue* messageQueue, @@ -364,6 +378,16 @@ bool DSDDemod::handleMessage(const Message& cmd) return true; } + else if (MsgConfigureChannelizer::match(cmd)) + { + MsgConfigureChannelizer& cfg = (MsgConfigureChannelizer&) cmd; + + m_channelizer->configure(m_channelizer->getInputMessageQueue(), + cfg.getSampleRate(), + cfg.getCenterFrequency()); + + return true; + } else if (MsgConfigureDSDDemod::match(cmd)) { MsgConfigureDSDDemod& cfg = (MsgConfigureDSDDemod&) cmd; diff --git a/plugins/channelrx/demoddsd/dsddemod.h b/plugins/channelrx/demoddsd/dsddemod.h index 3b17ad66b..6c6a23253 100644 --- a/plugins/channelrx/demoddsd/dsddemod.h +++ b/plugins/channelrx/demoddsd/dsddemod.h @@ -35,12 +35,38 @@ #include "dsddecoder.h" -class DSDDemodGUI; +class DeviceSourceAPI; +class ThreadedBasebandSampleSink; +class DownChannelizer; class DSDDemod : public BasebandSampleSink { public: - DSDDemod(BasebandSampleSink* sampleSink); + class MsgConfigureChannelizer : public Message { + MESSAGE_CLASS_DECLARATION + + public: + int getSampleRate() const { return m_sampleRate; } + int getCenterFrequency() const { return m_centerFrequency; } + + static MsgConfigureChannelizer* create(int sampleRate, int centerFrequency) + { + return new MsgConfigureChannelizer(sampleRate, centerFrequency); + } + + private: + int m_sampleRate; + int m_centerFrequency; + + MsgConfigureChannelizer(int sampleRate, int centerFrequency) : + Message(), + m_sampleRate(sampleRate), + m_centerFrequency(centerFrequency) + { } + }; + + DSDDemod(DeviceSourceAPI *deviceAPI); ~DSDDemod(); + void setScopeSink(BasebandSampleSink* sampleSink) { m_scope = sampleSink; } void configure(MessageQueue* messageQueue, int rfBandwidth, @@ -69,10 +95,6 @@ public: virtual void stop(); virtual bool handleMessage(const Message& cmd); - void registerGUI(DSDDemodGUI *dsdDemodGUI) { - m_dsdDemodGUI = dsdDemodGUI; - } - double getMagSq() { return m_magsq; } bool getSquelchOpen() const { return m_squelchOpen; } @@ -288,6 +310,10 @@ private: Config m_config; Config m_running; + DeviceSourceAPI *m_deviceAPI; + ThreadedBasebandSampleSink* m_threadedChannelizer; + DownChannelizer* m_channelizer; + NCO m_nco; Interpolator m_interpolator; Real m_interpolatorDistance; @@ -320,7 +346,6 @@ private: bool m_scopeEnabled; DSDDecoder m_dsdDecoder; - DSDDemodGUI *m_dsdDemodGUI; QMutex m_settingsMutex; PhaseDiscriminators m_phaseDiscri; diff --git a/plugins/channelrx/demoddsd/dsddemodbaudrates.cpp b/plugins/channelrx/demoddsd/dsddemodbaudrates.cpp new file mode 100644 index 000000000..5dc099b61 --- /dev/null +++ b/plugins/channelrx/demoddsd/dsddemodbaudrates.cpp @@ -0,0 +1,50 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2016 F4EXB // +// written by Edouard Griffiths // +// // +// This program is free software; you can redistribute it and/or modify // +// it under the terms of the GNU General Public License as published by // +// the Free Software Foundation as version 3 of the License, or // +// // +// This program is distributed in the hope that it will be useful, // +// but WITHOUT ANY WARRANTY; without even the implied warranty of // +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // +// GNU General Public License V3 for more details. // +// // +// You should have received a copy of the GNU General Public License // +// along with this program. If not, see . // +/////////////////////////////////////////////////////////////////////////////////// + +#include "dsddemodbaudrates.h" + +unsigned int DSDDemodBaudRates::m_rates[] = {2400, 4800}; +unsigned int DSDDemodBaudRates::m_nb_rates = 2; +unsigned int DSDDemodBaudRates::m_defaultRateIndex = 1; // 4800 bauds + +unsigned int DSDDemodBaudRates::getRate(unsigned int rate_index) +{ + if (rate_index < m_nb_rates) + { + return m_rates[rate_index]; + } + else + { + return m_rates[m_defaultRateIndex]; + } +} + +unsigned int DSDDemodBaudRates::getRateIndex(unsigned int rate) +{ + for (unsigned int i=0; i < m_nb_rates; i++) + { + if (rate == m_rates[i]) + { + return i; + } + } + + return m_defaultRateIndex; +} + + + diff --git a/plugins/channelrx/demoddsd/dsddemodbaudrates.h b/plugins/channelrx/demoddsd/dsddemodbaudrates.h new file mode 100644 index 000000000..2dbd18a8f --- /dev/null +++ b/plugins/channelrx/demoddsd/dsddemodbaudrates.h @@ -0,0 +1,35 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2016 F4EXB // +// written by Edouard Griffiths // +// // +// This program is free software; you can redistribute it and/or modify // +// it under the terms of the GNU General Public License as published by // +// the Free Software Foundation as version 3 of the License, or // +// // +// This program is distributed in the hope that it will be useful, // +// but WITHOUT ANY WARRANTY; without even the implied warranty of // +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // +// GNU General Public License V3 for more details. // +// // +// You should have received a copy of the GNU General Public License // +// along with this program. If not, see . // +/////////////////////////////////////////////////////////////////////////////////// + +#ifndef PLUGINS_CHANNELRX_DEMODDSD_DSDDEMODBAUDRATES_H_ +#define PLUGINS_CHANNELRX_DEMODDSD_DSDDEMODBAUDRATES_H_ + +class DSDDemodBaudRates +{ +public: + static unsigned int getRate(unsigned int rate_index); + static unsigned int getRateIndex(unsigned int rate); + static unsigned int getDefaultRate() { return m_rates[m_defaultRateIndex]; } + static unsigned int getDefaultRateIndex() { return m_defaultRateIndex; } + static unsigned int getNbRates() { return m_nb_rates; } +private: + static unsigned int m_nb_rates; + static unsigned int m_rates[2]; + static unsigned int m_defaultRateIndex; +}; + +#endif /* PLUGINS_CHANNELRX_DEMODDSD_DSDDEMODBAUDRATES_H_ */ diff --git a/plugins/channelrx/demoddsd/dsddemodgui.cpp b/plugins/channelrx/demoddsd/dsddemodgui.cpp index 2015c6ce1..00756059f 100644 --- a/plugins/channelrx/demoddsd/dsddemodgui.cpp +++ b/plugins/channelrx/demoddsd/dsddemodgui.cpp @@ -34,14 +34,11 @@ #include "dsp/dspengine.h" #include "mainwindow.h" +#include "dsddemodbaudrates.h" #include "dsddemod.h" const QString DSDDemodGUI::m_channelID = "sdrangel.channel.dsddemod"; -unsigned int DSDDemodBaudRates::m_rates[] = {2400, 4800}; -unsigned int DSDDemodBaudRates::m_nb_rates = 2; -unsigned int DSDDemodBaudRates::m_defaultRateIndex = 1; // 4800 bauds - DSDDemodGUI* DSDDemodGUI::create(PluginAPI* pluginAPI, DeviceSourceAPI *deviceAPI) { DSDDemodGUI* gui = new DSDDemodGUI(pluginAPI, deviceAPI); @@ -322,8 +319,9 @@ DSDDemodGUI::DSDDemodGUI(PluginAPI* pluginAPI, DeviceSourceAPI *deviceAPI, QWidg connect(this, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(onMenuDialogCalled(const QPoint &))); m_scopeVis = new ScopeVis(ui->glScope); - m_dsdDemod = new DSDDemod(m_scopeVis); - m_dsdDemod->registerGUI(this); + m_dsdDemod = new DSDDemod(m_deviceAPI); + m_dsdDemod->setScopeSink(m_scopeVis); + m_dsdDemod->setMessageQueueToGUI(getInputMessageQueue()); ui->glScope->setSampleRate(48000); m_scopeVis->setSampleRate(48000); @@ -339,11 +337,7 @@ DSDDemodGUI::DSDDemodGUI(PluginAPI* pluginAPI, DeviceSourceAPI *deviceAPI, QWidg ui->deltaFrequency->setValueRange(false, 7, -9999999, 9999999); ui->channelPowerMeter->setColorTheme(LevelMeterSignalDB::ColorGreenAndBlue); - m_channelizer = new DownChannelizer(m_dsdDemod); - m_threadedChannelizer = new ThreadedBasebandSampleSink(m_channelizer, this); - m_deviceAPI->addThreadedSink(m_threadedChannelizer); - //m_channelMarker = new ChannelMarker(this); m_channelMarker.setTitle(windowTitle()); m_channelMarker.setColor(Qt::cyan); m_channelMarker.setBandwidth(10000); @@ -366,11 +360,7 @@ DSDDemodGUI::DSDDemodGUI(PluginAPI* pluginAPI, DeviceSourceAPI *deviceAPI, QWidg DSDDemodGUI::~DSDDemodGUI() { m_deviceAPI->removeChannelInstance(this); - m_deviceAPI->removeThreadedSink(m_threadedChannelizer); - delete m_threadedChannelizer; - delete m_channelizer; delete m_dsdDemod; - //delete m_channelMarker; delete ui; } @@ -400,9 +390,9 @@ void DSDDemodGUI::applySettings(bool force) setTitleColor(m_channelMarker.getColor()); - m_channelizer->configure(m_channelizer->getInputMessageQueue(), - 48000, - m_channelMarker.getCenterFrequency()); + DSDDemod::MsgConfigureChannelizer* channelConfigMsg = DSDDemod::MsgConfigureChannelizer::create( + 48000, m_channelMarker.getCenterFrequency()); + m_dsdDemod->getInputMessageQueue()->push(channelConfigMsg); ui->deltaFrequency->setValue(m_channelMarker.getCenterFrequency()); ui->rfBWText->setText(QString("%1k").arg(ui->rfBW->value() / 10.0, 0, 'f', 1)); @@ -683,28 +673,3 @@ void DSDDemodGUI::tick() m_tickCount++; } - -unsigned int DSDDemodBaudRates::getRate(unsigned int rate_index) -{ - if (rate_index < m_nb_rates) - { - return m_rates[rate_index]; - } - else - { - return m_rates[m_defaultRateIndex]; - } -} - -unsigned int DSDDemodBaudRates::getRateIndex(unsigned int rate) -{ - for (unsigned int i=0; i < m_nb_rates; i++) - { - if (rate == m_rates[i]) - { - return i; - } - } - - return m_defaultRateIndex; -} diff --git a/plugins/channelrx/demoddsd/dsddemodgui.h b/plugins/channelrx/demoddsd/dsddemodgui.h index 0b36ae0ad..689ba7b2a 100644 --- a/plugins/channelrx/demoddsd/dsddemodgui.h +++ b/plugins/channelrx/demoddsd/dsddemodgui.h @@ -30,8 +30,6 @@ class PluginAPI; class DeviceSourceAPI; -class ThreadedBasebandSampleSink; -class DownChannelizer; class ScopeVis; class DSDDemod; @@ -100,8 +98,6 @@ private: char m_formatStatusText[82+1]; //!< Fixed signal format dependent status text SignalFormat m_signalFormat; - ThreadedBasebandSampleSink* m_threadedChannelizer; - DownChannelizer* m_channelizer; ScopeVis* m_scopeVis; DSDDemod* m_dsdDemod; @@ -131,18 +127,4 @@ private: void enterEvent(QEvent*); }; -class DSDDemodBaudRates -{ -public: - static unsigned int getRate(unsigned int rate_index); - static unsigned int getRateIndex(unsigned int rate); - static unsigned int getDefaultRate() { return m_rates[m_defaultRateIndex]; } - static unsigned int getDefaultRateIndex() { return m_defaultRateIndex; } - static unsigned int getNbRates(); -private: - static unsigned int m_nb_rates; - static unsigned int m_rates[2]; - static unsigned int m_defaultRateIndex; -}; - #endif // INCLUDE_DSDDEMODGUI_H From 9d7bfe4a25024f1d1d3d328ea6577309cadbdb17 Mon Sep 17 00:00:00 2001 From: f4exb Date: Mon, 2 Oct 2017 19:38:52 +0200 Subject: [PATCH 57/71] DSD demod: settings (1) --- plugins/channelrx/demoddsd/demoddsdsettings.h | 59 +++++++++++++++++++ 1 file changed, 59 insertions(+) create mode 100644 plugins/channelrx/demoddsd/demoddsdsettings.h diff --git a/plugins/channelrx/demoddsd/demoddsdsettings.h b/plugins/channelrx/demoddsd/demoddsdsettings.h new file mode 100644 index 000000000..544e3e3ea --- /dev/null +++ b/plugins/channelrx/demoddsd/demoddsdsettings.h @@ -0,0 +1,59 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2017 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 // +// // +// This program is distributed in the hope that it will be useful, // +// but WITHOUT ANY WARRANTY; without even the implied warranty of // +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // +// GNU General Public License V3 for more details. // +// // +// You should have received a copy of the GNU General Public License // +// along with this program. If not, see . // +/////////////////////////////////////////////////////////////////////////////////// + +#ifndef PLUGINS_CHANNELRX_DEMODDSD_DEMODDSDSETTINGS_H_ +#define PLUGINS_CHANNELRX_DEMODDSD_DEMODDSDSETTINGS_H_ + +#include + +class Serializable; + +struct DSDDemodSettings +{ + int m_inputSampleRate; + qint64 m_inputFrequencyOffset; + int m_rfBandwidth; + int m_demodGain; + int m_volume; + int m_baudRate; + int m_fmDeviation; + int m_squelchGate; + Real m_squelch; + bool m_audioMute; + quint32 m_audioSampleRate; + bool m_enableCosineFiltering; + bool m_syncOrConstellation; + bool m_slot1On; + bool m_slot2On; + bool m_tdmaStereo; + bool m_pllLock; + bool m_udpCopyAudio; + QString m_udpAddress; + quint16 m_udpPort; + + Serializable *m_channelMarker; + Serializable *m_scopeGUI; + + DSDDemodSettings(); + void resetToDefaults(); + void setChannelMarker(Serializable *channelMarker) { m_channelMarker = channelMarker; } + void setScopeGUI(Serializable *scopeGUI) { m_scopeGUI = scopeGUI; } + QByteArray serialize() const; + bool deserialize(const QByteArray& data); +}; + + +#endif /* PLUGINS_CHANNELRX_DEMODDSD_DEMODDSDSETTINGS_H_ */ From a03d08248b0b074d99ca166cabc033a2d93dab6b Mon Sep 17 00:00:00 2001 From: f4exb Date: Mon, 2 Oct 2017 23:01:13 +0200 Subject: [PATCH 58/71] DSD demod: settings --- plugins/channelrx/demoddsd/CMakeLists.txt | 2 + plugins/channelrx/demoddsd/demoddsd.pro | 6 +- plugins/channelrx/demoddsd/dsddemodplugin.cpp | 2 +- .../channelrx/demoddsd/dsddemodsettings.cpp | 141 ++++++++++++++++++ ...{demoddsdsettings.h => dsddemodsettings.h} | 15 +- 5 files changed, 156 insertions(+), 10 deletions(-) create mode 100644 plugins/channelrx/demoddsd/dsddemodsettings.cpp rename plugins/channelrx/demoddsd/{demoddsdsettings.h => dsddemodsettings.h} (87%) diff --git a/plugins/channelrx/demoddsd/CMakeLists.txt b/plugins/channelrx/demoddsd/CMakeLists.txt index 6547bdef5..02a1b533a 100644 --- a/plugins/channelrx/demoddsd/CMakeLists.txt +++ b/plugins/channelrx/demoddsd/CMakeLists.txt @@ -5,6 +5,7 @@ set(dsddemod_SOURCES dsddemodgui.cpp dsddemodplugin.cpp dsddemodbaudrates.cpp + dsddemodsettings.cpp dsddecoder.cpp ) @@ -13,6 +14,7 @@ set(dsddemod_HEADERS dsddemodgui.h dsddemodplugin.h dsddemodbaudrates.h + dsddemodsettings.h dsddecoder.h ) diff --git a/plugins/channelrx/demoddsd/demoddsd.pro b/plugins/channelrx/demoddsd/demoddsd.pro index 6f7f0f900..1779fcd1c 100644 --- a/plugins/channelrx/demoddsd/demoddsd.pro +++ b/plugins/channelrx/demoddsd/demoddsd.pro @@ -41,13 +41,15 @@ SOURCES = dsddecoder.cpp\ dsddemod.cpp\ dsddemodgui.cpp\ dsddemodplugin.cpp\ -dsddemodbaudrates.cpp +dsddemodbaudrates.cpp\ +dsddemodsettings.cpp HEADERS = dsddecoder.h\ dsddemod.h\ dsddemodgui.h\ dsddemodplugin.h\ -dsddemodbaudrates.h +dsddemodbaudrates.h\ +dsddemodsettings.h FORMS = dsddemodgui.ui diff --git a/plugins/channelrx/demoddsd/dsddemodplugin.cpp b/plugins/channelrx/demoddsd/dsddemodplugin.cpp index f6a84a23f..2c1de0032 100644 --- a/plugins/channelrx/demoddsd/dsddemodplugin.cpp +++ b/plugins/channelrx/demoddsd/dsddemodplugin.cpp @@ -24,7 +24,7 @@ const PluginDescriptor DSDDemodPlugin::m_pluginDescriptor = { QString("DSD Demodulator"), - QString("3.6.1"), + QString("3.7.3"), QString("(c) Edouard Griffiths, F4EXB"), QString("https://github.com/f4exb/sdrangel"), true, diff --git a/plugins/channelrx/demoddsd/dsddemodsettings.cpp b/plugins/channelrx/demoddsd/dsddemodsettings.cpp new file mode 100644 index 000000000..a927d419f --- /dev/null +++ b/plugins/channelrx/demoddsd/dsddemodsettings.cpp @@ -0,0 +1,141 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2017 Edouard Griffiths, F4EXB. // +// // +// This program is free som_udpCopyAudioftware; you can redistribute it and/or modify // +// it under the terms of the GNU General Public License as published by // +// the Free Software Foundation as version 3 of the License, or // +// // +// This program is distributed in the hope that it will be useful, // +// but WITHOUT ANY WARRANTY; without even the implied warranty of // +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // +// GNU General Public License V3 for more details. // +// // +// You should have received a copy of the GNU General Public License // +// along with this program. If not, see . // +/////////////////////////////////////////////////////////////////////////////////// + +#include + +#include "dsp/dspengine.h" +#include "util/simpleserializer.h" +#include "settings/serializable.h" +#include "dsddemodsettings.h" + +DSDDemodSettings::DSDDemodSettings() : + m_channelMarker(0), + m_scopeGUI(0) +{ + resetToDefaults(); +} + +void DSDDemodSettings::resetToDefaults() +{ + m_inputSampleRate = 96000; + m_inputFrequencyOffset = 0; + m_rfBandwidth = 10000.0; + m_demodGain = 1.0; + m_volume = 1.0; + m_baudRate = 4800; + m_fmDeviation = 5000.0; + m_squelchGate = 5; // 10s of ms at 48000 Hz sample rate. Corresponds to 2400 for AGC attack + m_squelch = -30.0; + m_audioMute = false; + m_audioSampleRate = DSPEngine::instance()->getAudioSampleRate(); + m_enableCosineFiltering = false; + m_syncOrConstellation = false; + m_slot1On = true; + m_slot2On = false; + m_tdmaStereo = false; + m_pllLock = true; + m_udpCopyAudio = false; + m_udpAddress = "127.0.0.1"; + m_udpPort = 9999; + m_rgbColor = QColor(0, 255, 255).rgb(); +} + +QByteArray DSDDemodSettings::serialize() const +{ + SimpleSerializer s(1); + s.writeS32(1, m_inputSampleRate); + s.writeS32(2, m_rfBandwidth/100.0); + s.writeS32(3, m_demodGain*100.0); + s.writeS32(4, m_fmDeviation/100.0); + s.writeS32(5, m_squelch); + s.writeU32(7, m_rgbColor); + s.writeS32(8, m_squelchGate); + s.writeS32(9, m_volume*10.0); + + if (m_scopeGUI) { + s.writeBlob(10, m_scopeGUI->serialize()); + } + + s.writeS32(11, m_baudRate); + s.writeBool(12, m_enableCosineFiltering); + s.writeBool(13, m_syncOrConstellation); + s.writeBool(14, m_slot1On); + s.writeBool(15, m_slot2On); + s.writeBool(16, m_tdmaStereo); + + if (m_channelMarker) { + s.writeBlob(17, m_channelMarker->serialize()); + } + + return s.final(); +} + +bool DSDDemodSettings::deserialize(const QByteArray& data) +{ + SimpleDeserializer d(data); + + if (!d.isValid()) + { + resetToDefaults(); + return false; + } + + if (d.getVersion() == 1) + { + QByteArray bytetmp; + QString strtmp; + qint32 tmp; + + if (m_channelMarker) { + d.readBlob(17, &bytetmp); + m_channelMarker->deserialize(bytetmp); + } + + d.readS32(1, &m_inputSampleRate, 96000); + d.readS32(2, &tmp, 4); + m_rfBandwidth = tmp * 100.0; + d.readS32(3, &tmp, 3); + m_demodGain = tmp / 100.0; + d.readS32(4, &tmp, 20); + m_fmDeviation = tmp * 100.0; + d.readS32(5, &tmp, -40); + m_squelch = tmp; + d.readU32(7, &m_rgbColor); + d.readS32(8, &m_squelchGate, 5); + d.readS32(9, &tmp, 20); + m_volume = tmp / 10.0; + + if (m_scopeGUI) { + d.readBlob(10, &bytetmp); + m_scopeGUI->deserialize(bytetmp); + } + + d.readS32(11, &m_baudRate, 4800); + d.readBool(12, &m_enableCosineFiltering, false); + d.readBool(13, &m_syncOrConstellation, false); + d.readBool(14, &m_slot1On, false); + d.readBool(15, &m_slot2On, false); + d.readBool(16, &m_tdmaStereo, false); + + return true; + } + else + { + resetToDefaults(); + return false; + } +} + diff --git a/plugins/channelrx/demoddsd/demoddsdsettings.h b/plugins/channelrx/demoddsd/dsddemodsettings.h similarity index 87% rename from plugins/channelrx/demoddsd/demoddsdsettings.h rename to plugins/channelrx/demoddsd/dsddemodsettings.h index 544e3e3ea..4ccf441d5 100644 --- a/plugins/channelrx/demoddsd/demoddsdsettings.h +++ b/plugins/channelrx/demoddsd/dsddemodsettings.h @@ -14,8 +14,8 @@ // along with this program. If not, see . // /////////////////////////////////////////////////////////////////////////////////// -#ifndef PLUGINS_CHANNELRX_DEMODDSD_DEMODDSDSETTINGS_H_ -#define PLUGINS_CHANNELRX_DEMODDSD_DEMODDSDSETTINGS_H_ +#ifndef PLUGINS_CHANNELRX_DEMODDSD_DSDDEMODSETTINGS_H_ +#define PLUGINS_CHANNELRX_DEMODDSD_DSDDEMODSETTINGS_H_ #include @@ -25,11 +25,11 @@ struct DSDDemodSettings { int m_inputSampleRate; qint64 m_inputFrequencyOffset; - int m_rfBandwidth; - int m_demodGain; - int m_volume; + Real m_rfBandwidth; + Real m_demodGain; + Real m_volume; int m_baudRate; - int m_fmDeviation; + Real m_fmDeviation; int m_squelchGate; Real m_squelch; bool m_audioMute; @@ -43,6 +43,7 @@ struct DSDDemodSettings bool m_udpCopyAudio; QString m_udpAddress; quint16 m_udpPort; + quint32 m_rgbColor; Serializable *m_channelMarker; Serializable *m_scopeGUI; @@ -56,4 +57,4 @@ struct DSDDemodSettings }; -#endif /* PLUGINS_CHANNELRX_DEMODDSD_DEMODDSDSETTINGS_H_ */ +#endif /* PLUGINS_CHANNELRX_DEMODDSD_DSDDEMODSETTINGS_H_ */ From 3e9be4181c1a0d2f7417617fa01b176b2e6321eb Mon Sep 17 00:00:00 2001 From: f4exb Date: Tue, 3 Oct 2017 22:19:40 +0200 Subject: [PATCH 59/71] DSD demod settings: save input requency offset --- plugins/channelrx/demoddsd/dsddemodsettings.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/plugins/channelrx/demoddsd/dsddemodsettings.cpp b/plugins/channelrx/demoddsd/dsddemodsettings.cpp index a927d419f..c9c7d1dce 100644 --- a/plugins/channelrx/demoddsd/dsddemodsettings.cpp +++ b/plugins/channelrx/demoddsd/dsddemodsettings.cpp @@ -61,6 +61,7 @@ QByteArray DSDDemodSettings::serialize() const s.writeS32(3, m_demodGain*100.0); s.writeS32(4, m_fmDeviation/100.0); s.writeS32(5, m_squelch); + s.writeS32(6, m_inputFrequencyOffset); s.writeU32(7, m_rgbColor); s.writeS32(8, m_squelchGate); s.writeS32(9, m_volume*10.0); @@ -113,6 +114,8 @@ bool DSDDemodSettings::deserialize(const QByteArray& data) m_fmDeviation = tmp * 100.0; d.readS32(5, &tmp, -40); m_squelch = tmp; + d.readS32(6, &tmp, 0); + m_inputFrequencyOffset = tmp; d.readU32(7, &m_rgbColor); d.readS32(8, &m_squelchGate, 5); d.readS32(9, &tmp, 20); From 2cf107ee34cd6a40c9173203c296becf7e3322db Mon Sep 17 00:00:00 2001 From: f4exb Date: Tue, 3 Oct 2017 22:24:07 +0200 Subject: [PATCH 60/71] DSD demod settings: correct serialize/deserialize frequency offset --- plugins/channelrx/demoddsd/dsddemodsettings.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/plugins/channelrx/demoddsd/dsddemodsettings.cpp b/plugins/channelrx/demoddsd/dsddemodsettings.cpp index c9c7d1dce..ea5ece657 100644 --- a/plugins/channelrx/demoddsd/dsddemodsettings.cpp +++ b/plugins/channelrx/demoddsd/dsddemodsettings.cpp @@ -56,12 +56,12 @@ void DSDDemodSettings::resetToDefaults() QByteArray DSDDemodSettings::serialize() const { SimpleSerializer s(1); - s.writeS32(1, m_inputSampleRate); + s.writeS32(1, m_inputFrequencyOffset); s.writeS32(2, m_rfBandwidth/100.0); s.writeS32(3, m_demodGain*100.0); s.writeS32(4, m_fmDeviation/100.0); s.writeS32(5, m_squelch); - s.writeS32(6, m_inputFrequencyOffset); + s.writeS32(6, m_inputSampleRate); s.writeU32(7, m_rgbColor); s.writeS32(8, m_squelchGate); s.writeS32(9, m_volume*10.0); @@ -105,7 +105,8 @@ bool DSDDemodSettings::deserialize(const QByteArray& data) m_channelMarker->deserialize(bytetmp); } - d.readS32(1, &m_inputSampleRate, 96000); + d.readS32(1, &tmp, 0); + m_inputFrequencyOffset = tmp; d.readS32(2, &tmp, 4); m_rfBandwidth = tmp * 100.0; d.readS32(3, &tmp, 3); @@ -114,8 +115,7 @@ bool DSDDemodSettings::deserialize(const QByteArray& data) m_fmDeviation = tmp * 100.0; d.readS32(5, &tmp, -40); m_squelch = tmp; - d.readS32(6, &tmp, 0); - m_inputFrequencyOffset = tmp; + d.readS32(6, &m_inputSampleRate, 96000); d.readU32(7, &m_rgbColor); d.readS32(8, &m_squelchGate, 5); d.readS32(9, &tmp, 20); From 878871e1202632c45d2bd059448ad0541621a49b Mon Sep 17 00:00:00 2001 From: f4exb Date: Tue, 3 Oct 2017 22:43:34 +0200 Subject: [PATCH 61/71] DSD demod: reorder parameters in configure method --- plugins/channelrx/demoddsd/dsddemod.cpp | 2 +- plugins/channelrx/demoddsd/dsddemod.h | 2 +- plugins/channelrx/demoddsd/dsddemodgui.cpp | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/plugins/channelrx/demoddsd/dsddemod.cpp b/plugins/channelrx/demoddsd/dsddemod.cpp index d06502a9f..ec85c0fca 100644 --- a/plugins/channelrx/demoddsd/dsddemod.cpp +++ b/plugins/channelrx/demoddsd/dsddemod.cpp @@ -106,8 +106,8 @@ DSDDemod::~DSDDemod() void DSDDemod::configure(MessageQueue* messageQueue, int rfBandwidth, + int fmDeviation, int demodGain, - int fmDeviation, int volume, int baudRate, int squelchGate, diff --git a/plugins/channelrx/demoddsd/dsddemod.h b/plugins/channelrx/demoddsd/dsddemod.h index 6c6a23253..9bbdb086c 100644 --- a/plugins/channelrx/demoddsd/dsddemod.h +++ b/plugins/channelrx/demoddsd/dsddemod.h @@ -70,10 +70,10 @@ public: void configure(MessageQueue* messageQueue, int rfBandwidth, + int fmDeviation, int demodGain, int volume, int baudRate, - int fmDeviation, int squelchGate, Real squelch, bool audioMute, diff --git a/plugins/channelrx/demoddsd/dsddemodgui.cpp b/plugins/channelrx/demoddsd/dsddemodgui.cpp index 00756059f..63b8ef874 100644 --- a/plugins/channelrx/demoddsd/dsddemodgui.cpp +++ b/plugins/channelrx/demoddsd/dsddemodgui.cpp @@ -408,8 +408,8 @@ void DSDDemodGUI::applySettings(bool force) m_dsdDemod->configure(m_dsdDemod->getInputMessageQueue(), ui->rfBW->value(), + ui->fmDeviation->value(), ui->demodGain->value(), - ui->fmDeviation->value(), ui->volume->value(), DSDDemodBaudRates::getRate(ui->baudRate->currentIndex()), ui->squelchGate->value(), // in 10ths of ms From 65ec5015df90d20d9e86e2b2221ef3ea4d567fe8 Mon Sep 17 00:00:00 2001 From: f4exb Date: Tue, 3 Oct 2017 22:49:30 +0200 Subject: [PATCH 62/71] DSD demod: rescale RF bandwidth and FM deviation --- plugins/channelrx/demoddsd/dsddemod.cpp | 16 ++++++------- plugins/channelrx/demoddsd/dsddemod.h | 28 +++++++++++----------- plugins/channelrx/demoddsd/dsddemodgui.cpp | 4 ++-- 3 files changed, 24 insertions(+), 24 deletions(-) diff --git a/plugins/channelrx/demoddsd/dsddemod.cpp b/plugins/channelrx/demoddsd/dsddemod.cpp index ec85c0fca..997eb4138 100644 --- a/plugins/channelrx/demoddsd/dsddemod.cpp +++ b/plugins/channelrx/demoddsd/dsddemod.cpp @@ -55,9 +55,9 @@ DSDDemod::DSDDemod(DeviceSourceAPI *deviceAPI) : m_config.m_inputSampleRate = 96000; m_config.m_inputFrequencyOffset = 0; - m_config.m_rfBandwidth = 100; + m_config.m_rfBandwidth = 10000.0; + m_config.m_fmDeviation = 5000.0; m_config.m_demodGain = 100; - m_config.m_fmDeviation = 100; m_config.m_squelchGate = 5; // 10s of ms at 48000 Hz sample rate. Corresponds to 2400 for AGC attack m_config.m_squelch = -30.0; m_config.m_volume = 1.0; @@ -105,8 +105,8 @@ DSDDemod::~DSDDemod() } void DSDDemod::configure(MessageQueue* messageQueue, - int rfBandwidth, - int fmDeviation, + Real rfBandwidth, + Real fmDeviation, int demodGain, int volume, int baudRate, @@ -125,8 +125,8 @@ void DSDDemod::configure(MessageQueue* messageQueue, bool force) { Message* cmd = MsgConfigureDSDDemod::create(rfBandwidth, + fmDeviation, demodGain, - fmDeviation, volume, baudRate, squelchGate, @@ -412,9 +412,9 @@ bool DSDDemod::handleMessage(const Message& cmd) apply(); - qDebug() << "DSDDemod::handleMessage: MsgConfigureDSDDemod: m_rfBandwidth: " << m_config.m_rfBandwidth * 100 + qDebug() << "DSDDemod::handleMessage: MsgConfigureDSDDemod: m_rfBandwidth: " << m_config.m_rfBandwidth + << " m_fmDeviation: " << m_config.m_fmDeviation << " m_demodGain: " << m_config.m_demodGain / 100.0 - << " m_fmDeviation: " << m_config.m_fmDeviation * 100 << " m_volume: " << m_config.m_volume / 10.0 << " m_baudRate: " << m_config.m_baudRate << " m_squelchGate" << m_config.m_squelchGate @@ -456,7 +456,7 @@ void DSDDemod::apply(bool force) (m_config.m_rfBandwidth != m_running.m_rfBandwidth) || force) { m_settingsMutex.lock(); - m_interpolator.create(16, m_config.m_inputSampleRate, (m_config.m_rfBandwidth * 100) / 2.2); + m_interpolator.create(16, m_config.m_inputSampleRate, (m_config.m_rfBandwidth) / 2.2); m_interpolatorDistanceRemain = 0; m_interpolatorDistance = (Real) m_config.m_inputSampleRate / (Real) m_config.m_audioSampleRate; m_phaseDiscri.setFMScaling((float) m_config.m_rfBandwidth / (float) m_config.m_fmDeviation); diff --git a/plugins/channelrx/demoddsd/dsddemod.h b/plugins/channelrx/demoddsd/dsddemod.h index 9bbdb086c..48a16b210 100644 --- a/plugins/channelrx/demoddsd/dsddemod.h +++ b/plugins/channelrx/demoddsd/dsddemod.h @@ -69,8 +69,8 @@ public: void setScopeSink(BasebandSampleSink* sampleSink) { m_scope = sampleSink; } void configure(MessageQueue* messageQueue, - int rfBandwidth, - int fmDeviation, + Real rfBandwidth, + Real fmDeviation, int demodGain, int volume, int baudRate, @@ -139,9 +139,9 @@ private: MESSAGE_CLASS_DECLARATION public: - int getRFBandwidth() const { return m_rfBandwidth; } + Real getRFBandwidth() const { return m_rfBandwidth; } + Real getFMDeviation() const { return m_fmDeviation; } int getDemodGain() const { return m_demodGain; } - int getFMDeviation() const { return m_fmDeviation; } int getVolume() const { return m_volume; } int getBaudRate() const { return m_baudRate; } int getSquelchGate() const { return m_squelchGate; } @@ -157,9 +157,9 @@ private: const QString& getUDPAddress() const { return m_udpAddress; } quint16 getUDPPort() const { return m_udpPort; } - static MsgConfigureDSDDemod* create(int rfBandwidth, + static MsgConfigureDSDDemod* create(Real rfBandwidth, + Real fmDeviation, int demodGain, - int fmDeviation, int volume, int baudRate, int squelchGate, @@ -177,8 +177,8 @@ private: bool force) { return new MsgConfigureDSDDemod(rfBandwidth, + fmDeviation, demodGain, - fmDeviation, volume, baudRate, squelchGate, @@ -198,8 +198,8 @@ private: private: Real m_rfBandwidth; + Real m_fmDeviation; Real m_demodGain; - int m_fmDeviation; int m_volume; int m_baudRate; int m_squelchGate; @@ -217,8 +217,8 @@ private: bool m_force; MsgConfigureDSDDemod(int rfBandwidth, + int fmDeviation, int demodGain, - int fmDeviation, int volume, int baudRate, int squelchGate, @@ -236,8 +236,8 @@ private: bool force) : Message(), m_rfBandwidth(rfBandwidth), + m_fmDeviation(fmDeviation), m_demodGain(demodGain), - m_fmDeviation(fmDeviation), m_volume(volume), m_baudRate(baudRate), m_squelchGate(squelchGate), @@ -264,11 +264,11 @@ private: struct Config { int m_inputSampleRate; qint64 m_inputFrequencyOffset; - int m_rfBandwidth; + Real m_rfBandwidth; + Real m_fmDeviation; int m_demodGain; int m_volume; int m_baudRate; - int m_fmDeviation; int m_squelchGate; Real m_squelch; bool m_audioMute; @@ -286,11 +286,11 @@ private: Config() : m_inputSampleRate(-1), m_inputFrequencyOffset(0), - m_rfBandwidth(-1), + m_rfBandwidth(10000.0), + m_fmDeviation(5000.0), m_demodGain(-1), m_volume(-1), m_baudRate(4800), - m_fmDeviation(1), m_squelchGate(1), m_squelch(0), m_audioMute(false), diff --git a/plugins/channelrx/demoddsd/dsddemodgui.cpp b/plugins/channelrx/demoddsd/dsddemodgui.cpp index 63b8ef874..5924161ea 100644 --- a/plugins/channelrx/demoddsd/dsddemodgui.cpp +++ b/plugins/channelrx/demoddsd/dsddemodgui.cpp @@ -407,8 +407,8 @@ void DSDDemodGUI::applySettings(bool force) ui->tdmaStereoSplit->setChecked(m_tdmaStereo); m_dsdDemod->configure(m_dsdDemod->getInputMessageQueue(), - ui->rfBW->value(), - ui->fmDeviation->value(), + ui->rfBW->value() * 100.0, + ui->fmDeviation->value() * 100.0, ui->demodGain->value(), ui->volume->value(), DSDDemodBaudRates::getRate(ui->baudRate->currentIndex()), From 6e2e8dc2b5e7363206664cf1310ec079f48c0b68 Mon Sep 17 00:00:00 2001 From: f4exb Date: Tue, 3 Oct 2017 23:00:18 +0200 Subject: [PATCH 63/71] DSD demod: rescale demod gain and volume --- plugins/channelrx/demoddsd/dsddemod.cpp | 14 ++++---- plugins/channelrx/demoddsd/dsddemod.h | 34 +++++++++---------- plugins/channelrx/demoddsd/dsddemodgui.cpp | 4 +-- .../channelrx/demoddsd/dsddemodsettings.cpp | 2 +- plugins/channelrx/demoddsd/dsddemodsettings.h | 2 +- 5 files changed, 28 insertions(+), 28 deletions(-) diff --git a/plugins/channelrx/demoddsd/dsddemod.cpp b/plugins/channelrx/demoddsd/dsddemod.cpp index 997eb4138..38210fafc 100644 --- a/plugins/channelrx/demoddsd/dsddemod.cpp +++ b/plugins/channelrx/demoddsd/dsddemod.cpp @@ -57,7 +57,7 @@ DSDDemod::DSDDemod(DeviceSourceAPI *deviceAPI) : m_config.m_inputFrequencyOffset = 0; m_config.m_rfBandwidth = 10000.0; m_config.m_fmDeviation = 5000.0; - m_config.m_demodGain = 100; + m_config.m_demodGain = 1.0; m_config.m_squelchGate = 5; // 10s of ms at 48000 Hz sample rate. Corresponds to 2400 for AGC attack m_config.m_squelch = -30.0; m_config.m_volume = 1.0; @@ -107,8 +107,8 @@ DSDDemod::~DSDDemod() void DSDDemod::configure(MessageQueue* messageQueue, Real rfBandwidth, Real fmDeviation, - int demodGain, - int volume, + Real demodGain, + Real volume, int baudRate, int squelchGate, Real squelch, @@ -182,7 +182,7 @@ void DSDDemod::feed(const SampleVector::const_iterator& begin, const SampleVecto m_magsqCount++; - Real demod = 32768.0f * m_phaseDiscri.phaseDiscriminator(ci) * ((float) m_running.m_demodGain / 100.0f); + Real demod = 32768.0f * m_phaseDiscri.phaseDiscriminator(ci) * m_running.m_demodGain; m_sampleCount++; // AF processing @@ -414,8 +414,8 @@ bool DSDDemod::handleMessage(const Message& cmd) qDebug() << "DSDDemod::handleMessage: MsgConfigureDSDDemod: m_rfBandwidth: " << m_config.m_rfBandwidth << " m_fmDeviation: " << m_config.m_fmDeviation - << " m_demodGain: " << m_config.m_demodGain / 100.0 - << " m_volume: " << m_config.m_volume / 10.0 + << " m_demodGain: " << m_config.m_demodGain + << " m_volume: " << m_config.m_volume << " m_baudRate: " << m_config.m_baudRate << " m_squelchGate" << m_config.m_squelchGate << " m_squelch: " << m_config.m_squelch @@ -483,7 +483,7 @@ void DSDDemod::apply(bool force) if ((m_config.m_volume != m_running.m_volume) || force) { - m_dsdDecoder.setAudioGain(m_config.m_volume / 10.0f); + m_dsdDecoder.setAudioGain(m_config.m_volume); } if ((m_config.m_baudRate != m_running.m_baudRate) || force) diff --git a/plugins/channelrx/demoddsd/dsddemod.h b/plugins/channelrx/demoddsd/dsddemod.h index 48a16b210..5d6e14579 100644 --- a/plugins/channelrx/demoddsd/dsddemod.h +++ b/plugins/channelrx/demoddsd/dsddemod.h @@ -69,10 +69,10 @@ public: void setScopeSink(BasebandSampleSink* sampleSink) { m_scope = sampleSink; } void configure(MessageQueue* messageQueue, - Real rfBandwidth, - Real fmDeviation, - int demodGain, - int volume, + Real rfBandwidth, + Real fmDeviation, + Real demodGain, + Real volume, int baudRate, int squelchGate, Real squelch, @@ -141,8 +141,8 @@ private: public: Real getRFBandwidth() const { return m_rfBandwidth; } Real getFMDeviation() const { return m_fmDeviation; } - int getDemodGain() const { return m_demodGain; } - int getVolume() const { return m_volume; } + Real getDemodGain() const { return m_demodGain; } + Real getVolume() const { return m_volume; } int getBaudRate() const { return m_baudRate; } int getSquelchGate() const { return m_squelchGate; } Real getSquelch() const { return m_squelch; } @@ -159,8 +159,8 @@ private: static MsgConfigureDSDDemod* create(Real rfBandwidth, Real fmDeviation, - int demodGain, - int volume, + Real demodGain, + Real volume, int baudRate, int squelchGate, Real squelch, @@ -200,7 +200,7 @@ private: Real m_rfBandwidth; Real m_fmDeviation; Real m_demodGain; - int m_volume; + Real m_volume; int m_baudRate; int m_squelchGate; Real m_squelch; @@ -216,10 +216,10 @@ private: quint16 m_udpPort; bool m_force; - MsgConfigureDSDDemod(int rfBandwidth, - int fmDeviation, - int demodGain, - int volume, + MsgConfigureDSDDemod(Real rfBandwidth, + Real fmDeviation, + Real demodGain, + Real volume, int baudRate, int squelchGate, Real squelch, @@ -266,8 +266,8 @@ private: qint64 m_inputFrequencyOffset; Real m_rfBandwidth; Real m_fmDeviation; - int m_demodGain; - int m_volume; + Real m_demodGain; + Real m_volume; int m_baudRate; int m_squelchGate; Real m_squelch; @@ -288,8 +288,8 @@ private: m_inputFrequencyOffset(0), m_rfBandwidth(10000.0), m_fmDeviation(5000.0), - m_demodGain(-1), - m_volume(-1), + m_demodGain(1.0), + m_volume(1.0), m_baudRate(4800), m_squelchGate(1), m_squelch(0), diff --git a/plugins/channelrx/demoddsd/dsddemodgui.cpp b/plugins/channelrx/demoddsd/dsddemodgui.cpp index 5924161ea..1b25679f9 100644 --- a/plugins/channelrx/demoddsd/dsddemodgui.cpp +++ b/plugins/channelrx/demoddsd/dsddemodgui.cpp @@ -409,8 +409,8 @@ void DSDDemodGUI::applySettings(bool force) m_dsdDemod->configure(m_dsdDemod->getInputMessageQueue(), ui->rfBW->value() * 100.0, ui->fmDeviation->value() * 100.0, - ui->demodGain->value(), - ui->volume->value(), + ui->demodGain->value() / 100.0, + ui->volume->value() / 10.0, DSDDemodBaudRates::getRate(ui->baudRate->currentIndex()), ui->squelchGate->value(), // in 10ths of ms ui->squelch->value(), diff --git a/plugins/channelrx/demoddsd/dsddemodsettings.cpp b/plugins/channelrx/demoddsd/dsddemodsettings.cpp index ea5ece657..46a0710f7 100644 --- a/plugins/channelrx/demoddsd/dsddemodsettings.cpp +++ b/plugins/channelrx/demoddsd/dsddemodsettings.cpp @@ -33,10 +33,10 @@ void DSDDemodSettings::resetToDefaults() m_inputSampleRate = 96000; m_inputFrequencyOffset = 0; m_rfBandwidth = 10000.0; + m_fmDeviation = 5000.0; m_demodGain = 1.0; m_volume = 1.0; m_baudRate = 4800; - m_fmDeviation = 5000.0; m_squelchGate = 5; // 10s of ms at 48000 Hz sample rate. Corresponds to 2400 for AGC attack m_squelch = -30.0; m_audioMute = false; diff --git a/plugins/channelrx/demoddsd/dsddemodsettings.h b/plugins/channelrx/demoddsd/dsddemodsettings.h index 4ccf441d5..d8729a222 100644 --- a/plugins/channelrx/demoddsd/dsddemodsettings.h +++ b/plugins/channelrx/demoddsd/dsddemodsettings.h @@ -26,10 +26,10 @@ struct DSDDemodSettings int m_inputSampleRate; qint64 m_inputFrequencyOffset; Real m_rfBandwidth; + Real m_fmDeviation; Real m_demodGain; Real m_volume; int m_baudRate; - Real m_fmDeviation; int m_squelchGate; Real m_squelch; bool m_audioMute; From 96530f13f4a8e522e06d9ebe9e0217781b1f4c87 Mon Sep 17 00:00:00 2001 From: f4exb Date: Tue, 3 Oct 2017 23:03:29 +0200 Subject: [PATCH 64/71] DSD demod: rescale squelch --- plugins/channelrx/demoddsd/dsddemod.cpp | 4 ++-- plugins/channelrx/demoddsd/dsddemod.h | 2 +- plugins/channelrx/demoddsd/dsddemodgui.cpp | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/plugins/channelrx/demoddsd/dsddemod.cpp b/plugins/channelrx/demoddsd/dsddemod.cpp index 38210fafc..46e69993d 100644 --- a/plugins/channelrx/demoddsd/dsddemod.cpp +++ b/plugins/channelrx/demoddsd/dsddemod.cpp @@ -476,8 +476,8 @@ void DSDDemod::apply(bool force) if ((m_config.m_squelch != m_running.m_squelch) || force) { - // input is a value in tenths of dB - m_squelchLevel = std::pow(10.0, m_config.m_squelch / 100.0); + // input is a value in dB + m_squelchLevel = std::pow(10.0, m_config.m_squelch / 10.0); //m_squelchLevel *= m_squelchLevel; } diff --git a/plugins/channelrx/demoddsd/dsddemod.h b/plugins/channelrx/demoddsd/dsddemod.h index 5d6e14579..b57dd074f 100644 --- a/plugins/channelrx/demoddsd/dsddemod.h +++ b/plugins/channelrx/demoddsd/dsddemod.h @@ -292,7 +292,7 @@ private: m_volume(1.0), m_baudRate(4800), m_squelchGate(1), - m_squelch(0), + m_squelch(-40.0), m_audioMute(false), m_audioSampleRate(0), m_enableCosineFiltering(false), diff --git a/plugins/channelrx/demoddsd/dsddemodgui.cpp b/plugins/channelrx/demoddsd/dsddemodgui.cpp index 1b25679f9..3508e5cf4 100644 --- a/plugins/channelrx/demoddsd/dsddemodgui.cpp +++ b/plugins/channelrx/demoddsd/dsddemodgui.cpp @@ -413,7 +413,7 @@ void DSDDemodGUI::applySettings(bool force) ui->volume->value() / 10.0, DSDDemodBaudRates::getRate(ui->baudRate->currentIndex()), ui->squelchGate->value(), // in 10ths of ms - ui->squelch->value(), + ui->squelch->value() / 10.0, ui->audioMute->isChecked(), m_enableCosineFiltering, m_syncOrConstellation, From 601b429a9611a358bcaa2675ee01d59fe9edec9b Mon Sep 17 00:00:00 2001 From: f4exb Date: Tue, 3 Oct 2017 23:05:18 +0200 Subject: [PATCH 65/71] DSD demod settings: corrected squelch scaling --- plugins/channelrx/demoddsd/dsddemodsettings.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/plugins/channelrx/demoddsd/dsddemodsettings.cpp b/plugins/channelrx/demoddsd/dsddemodsettings.cpp index 46a0710f7..82617adc0 100644 --- a/plugins/channelrx/demoddsd/dsddemodsettings.cpp +++ b/plugins/channelrx/demoddsd/dsddemodsettings.cpp @@ -60,7 +60,7 @@ QByteArray DSDDemodSettings::serialize() const s.writeS32(2, m_rfBandwidth/100.0); s.writeS32(3, m_demodGain*100.0); s.writeS32(4, m_fmDeviation/100.0); - s.writeS32(5, m_squelch); + s.writeS32(5, m_squelch*10.0); s.writeS32(6, m_inputSampleRate); s.writeU32(7, m_rgbColor); s.writeS32(8, m_squelchGate); @@ -113,8 +113,8 @@ bool DSDDemodSettings::deserialize(const QByteArray& data) m_demodGain = tmp / 100.0; d.readS32(4, &tmp, 20); m_fmDeviation = tmp * 100.0; - d.readS32(5, &tmp, -40); - m_squelch = tmp; + d.readS32(5, &tmp, -400); + m_squelch = tmp / 10.0; d.readS32(6, &m_inputSampleRate, 96000); d.readU32(7, &m_rgbColor); d.readS32(8, &m_squelchGate, 5); From eccea4a4fcb1e79a1336572e2ec825beacdc9f37 Mon Sep 17 00:00:00 2001 From: f4exb Date: Tue, 3 Oct 2017 23:28:04 +0200 Subject: [PATCH 66/71] GLscopeGUIs: implement Serializable interface --- sdrbase/gui/glscopegui.h | 7 ++++--- sdrbase/gui/glscopenggui.h | 7 ++++--- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/sdrbase/gui/glscopegui.h b/sdrbase/gui/glscopegui.h index 74c17b1e9..38866cbd5 100644 --- a/sdrbase/gui/glscopegui.h +++ b/sdrbase/gui/glscopegui.h @@ -6,6 +6,7 @@ #include "util/export.h" #include "util/message.h" #include "dsp/scopevis.h" +#include "settings/serializable.h" namespace Ui { class GLScopeGUI; @@ -14,7 +15,7 @@ namespace Ui { class MessageQueue; class GLScope; -class SDRANGEL_API GLScopeGUI : public QWidget { +class SDRANGEL_API GLScopeGUI : public QWidget, public Serializable { Q_OBJECT public: @@ -25,8 +26,8 @@ public: void setSampleRate(int sampleRate); void resetToDefaults(); - QByteArray serialize() const; - bool deserialize(const QByteArray& data); + virtual QByteArray serialize() const; + virtual bool deserialize(const QByteArray& data); bool handleMessage(Message* message); diff --git a/sdrbase/gui/glscopenggui.h b/sdrbase/gui/glscopenggui.h index e58408902..8b3c67891 100644 --- a/sdrbase/gui/glscopenggui.h +++ b/sdrbase/gui/glscopenggui.h @@ -25,6 +25,7 @@ #include "util/export.h" #include "util/message.h" #include "dsp/scopevisng.h" +#include "settings/serializable.h" namespace Ui { class GLScopeNGGUI; @@ -33,7 +34,7 @@ namespace Ui { class MessageQueue; class GLScopeNG; -class SDRANGEL_API GLScopeNGGUI : public QWidget { +class SDRANGEL_API GLScopeNGGUI : public QWidget, public Serializable { Q_OBJECT public: @@ -52,8 +53,8 @@ public: void setSampleRate(int sampleRate); void resetToDefaults(); - QByteArray serialize() const; - bool deserialize(const QByteArray& data); + virtual QByteArray serialize() const; + virtual bool deserialize(const QByteArray& data); bool handleMessage(Message* message); From 2bcf9e09337d6c8b823dc279ccbebb370a74a371 Mon Sep 17 00:00:00 2001 From: f4exb Date: Tue, 3 Oct 2017 23:42:56 +0200 Subject: [PATCH 67/71] DSD demod: use settings in GUI --- plugins/channelrx/demoddsd/dsddemodgui.cpp | 336 +++++++++++++-------- plugins/channelrx/demoddsd/dsddemodgui.h | 4 + 2 files changed, 206 insertions(+), 134 deletions(-) diff --git a/plugins/channelrx/demoddsd/dsddemodgui.cpp b/plugins/channelrx/demoddsd/dsddemodgui.cpp index 3508e5cf4..918de087d 100644 --- a/plugins/channelrx/demoddsd/dsddemodgui.cpp +++ b/plugins/channelrx/demoddsd/dsddemodgui.cpp @@ -73,112 +73,116 @@ void DSDDemodGUI::setCenterFrequency(qint64 centerFrequency) void DSDDemodGUI::resetToDefaults() { + m_settings.resetToDefaults(); blockApplySettings(true); - - ui->rfBW->setValue(100); // x100 Hz - ui->demodGain->setValue(100); // 100ths - ui->fmDeviation->setValue(50); // x100 Hz - ui->volume->setValue(20); // /10.0 - ui->baudRate->setCurrentIndex(DSDDemodBaudRates::getDefaultRateIndex()); - ui->squelchGate->setValue(5); - ui->squelch->setValue(-40); - ui->deltaFrequency->setValue(0); - ui->symbolPLLLock->setChecked(true); - + displaySettings(); blockApplySettings(false); applySettings(); } QByteArray DSDDemodGUI::serialize() const { - SimpleSerializer s(1); - s.writeS32(1, m_channelMarker.getCenterFrequency()); - s.writeS32(2, ui->rfBW->value()); - s.writeS32(3, ui->demodGain->value()); - s.writeS32(4, ui->fmDeviation->value()); - s.writeS32(5, ui->squelch->value()); - s.writeU32(7, m_channelMarker.getColor().rgb()); - s.writeS32(8, ui->squelchGate->value()); - s.writeS32(9, ui->volume->value()); - s.writeBlob(10, ui->scopeGUI->serialize()); - s.writeS32(11, ui->baudRate->currentIndex()); - s.writeBool(12, m_enableCosineFiltering); - s.writeBool(13, m_syncOrConstellation); - s.writeBool(14, m_slot1On); - s.writeBool(15, m_slot2On); - s.writeBool(16, m_tdmaStereo); - s.writeBlob(17, m_channelMarker.serialize()); - return s.final(); + return m_settings.serialize(); +// SimpleSerializer s(1); +// s.writeS32(1, m_channelMarker.getCenterFrequency()); +// s.writeS32(2, ui->rfBW->value()); +// s.writeS32(3, ui->demodGain->value()); +// s.writeS32(4, ui->fmDeviation->value()); +// s.writeS32(5, ui->squelch->value()); +// s.writeU32(7, m_channelMarker.getColor().rgb()); +// s.writeS32(8, ui->squelchGate->value()); +// s.writeS32(9, ui->volume->value()); +// s.writeBlob(10, ui->scopeGUI->serialize()); +// s.writeS32(11, ui->baudRate->currentIndex()); +// s.writeBool(12, m_enableCosineFiltering); +// s.writeBool(13, m_syncOrConstellation); +// s.writeBool(14, m_slot1On); +// s.writeBool(15, m_slot2On); +// s.writeBool(16, m_tdmaStereo); +// s.writeBlob(17, m_channelMarker.serialize()); +// return s.final(); } bool DSDDemodGUI::deserialize(const QByteArray& data) { - SimpleDeserializer d(data); + if (m_settings.deserialize(data)) + { + displaySettings(); + applySettings(true); + return true; + } + else + { + resetToDefaults(); + return false; + } - if (!d.isValid()) - { - resetToDefaults(); - return false; - } - - if (d.getVersion() == 1) - { - QByteArray bytetmp; - QString strtmp; - quint32 u32tmp; - qint32 tmp; - - blockApplySettings(true); - m_channelMarker.blockSignals(true); - - d.readBlob(17, &bytetmp); - m_channelMarker.deserialize(bytetmp); - - d.readS32(1, &tmp, 0); - m_channelMarker.setCenterFrequency(tmp); - d.readS32(2, &tmp, 4); - ui->rfBW->setValue(tmp); - d.readS32(3, &tmp, 3); - ui->demodGain->setValue(tmp); - d.readS32(4, &tmp, 20); - ui->fmDeviation->setValue(tmp); - d.readS32(5, &tmp, -40); - ui->squelch->setValue(tmp); - - if(d.readU32(7, &u32tmp)) - { - m_channelMarker.setColor(u32tmp); - } - - d.readS32(8, &tmp, 5); - ui->squelchGate->setValue(tmp); - d.readS32(9, &tmp, 20); - ui->volume->setValue(tmp); - d.readBlob(10, &bytetmp); - ui->scopeGUI->deserialize(bytetmp); - d.readS32(11, &tmp, 20); - ui->baudRate->setCurrentIndex(tmp); - d.readBool(12, &m_enableCosineFiltering, false); - d.readBool(13, &m_syncOrConstellation, false); - d.readBool(14, &m_slot1On, false); - d.readBool(15, &m_slot2On, false); - d.readBool(16, &m_tdmaStereo, false); - - this->setWindowTitle(m_channelMarker.getTitle()); - displayUDPAddress(); - - blockApplySettings(false); - m_channelMarker.blockSignals(false); - - updateMyPosition(); // we do it also here to be able to refresh with latest settings - applySettings(true); - return true; - } - else - { - resetToDefaults(); - return false; - } +// SimpleDeserializer d(data); +// +// if (!d.isValid()) +// { +// resetToDefaults(); +// return false; +// } +// +// if (d.getVersion() == 1) +// { +// QByteArray bytetmp; +// QString strtmp; +// quint32 u32tmp; +// qint32 tmp; +// +// blockApplySettings(true); +// m_channelMarker.blockSignals(true); +// +// d.readBlob(17, &bytetmp); +// m_channelMarker.deserialize(bytetmp); +// +// d.readS32(1, &tmp, 0); +// m_channelMarker.setCenterFrequency(tmp); +// d.readS32(2, &tmp, 4); +// ui->rfBW->setValue(tmp); +// d.readS32(3, &tmp, 3); +// ui->demodGain->setValue(tmp); +// d.readS32(4, &tmp, 20); +// ui->fmDeviation->setValue(tmp); +// d.readS32(5, &tmp, -40); +// ui->squelch->setValue(tmp); +// +// if(d.readU32(7, &u32tmp)) +// { +// m_channelMarker.setColor(u32tmp); +// } +// +// d.readS32(8, &tmp, 5); +// ui->squelchGate->setValue(tmp); +// d.readS32(9, &tmp, 20); +// ui->volume->setValue(tmp); +// d.readBlob(10, &bytetmp); +// ui->scopeGUI->deserialize(bytetmp); +// d.readS32(11, &tmp, 20); +// ui->baudRate->setCurrentIndex(tmp); +// d.readBool(12, &m_enableCosineFiltering, false); +// d.readBool(13, &m_syncOrConstellation, false); +// d.readBool(14, &m_slot1On, false); +// d.readBool(15, &m_slot2On, false); +// d.readBool(16, &m_tdmaStereo, false); +// +// this->setWindowTitle(m_channelMarker.getTitle()); +// displayUDPAddress(); +// +// blockApplySettings(false); +// m_channelMarker.blockSignals(false); +// +// updateMyPosition(); // we do it also here to be able to refresh with latest settings +// applySettings(true); +// return true; +// } +// else +// { +// resetToDefaults(); +// return false; +// } } bool DSDDemodGUI::handleMessage(const Message& message __attribute__((unused))) @@ -189,79 +193,92 @@ bool DSDDemodGUI::handleMessage(const Message& message __attribute__((unused))) void DSDDemodGUI::on_deltaFrequency_changed(qint64 value) { m_channelMarker.setCenterFrequency(value); + m_settings.m_inputFrequencyOffset = m_channelMarker.getCenterFrequency(); + applySettings(); } void DSDDemodGUI::on_rfBW_valueChanged(int value) { - qDebug() << "DSDDemodGUI::on_rfBW_valueChanged" << value * 100; m_channelMarker.setBandwidth(value * 100); + m_settings.m_rfBandwidth = value * 100.0; + ui->rfBWText->setText(QString("%1k").arg(value / 10.0, 0, 'f', 1)); applySettings(); } -void DSDDemodGUI::on_demodGain_valueChanged(int value __attribute__((unused))) +void DSDDemodGUI::on_demodGain_valueChanged(int value) { + m_settings.m_demodGain = value / 100.0; + ui->demodGainText->setText(QString("%1").arg(value / 100.0, 0, 'f', 2)); applySettings(); } -void DSDDemodGUI::on_fmDeviation_valueChanged(int value __attribute__((unused))) +void DSDDemodGUI::on_fmDeviation_valueChanged(int value) { + m_settings.m_fmDeviation = value * 100.0; + ui->fmDeviationText->setText(QString("%1k").arg(value / 10.0, 0, 'f', 1)); applySettings(); } -void DSDDemodGUI::on_volume_valueChanged(int value __attribute__((unused))) +void DSDDemodGUI::on_volume_valueChanged(int value) { + m_settings.m_volume= value / 10.0; + ui->volumeText->setText(QString("%1").arg(value / 10.0, 0, 'f', 1)); applySettings(); } -void DSDDemodGUI::on_baudRate_currentIndexChanged(int index __attribute__((unused))) +void DSDDemodGUI::on_baudRate_currentIndexChanged(int index) { + m_settings.m_baudRate = DSDDemodBaudRates::getRate(index); applySettings(); } void DSDDemodGUI::on_enableCosineFiltering_toggled(bool enable) { - m_enableCosineFiltering = enable; + m_settings.m_enableCosineFiltering = enable; applySettings(); } void DSDDemodGUI::on_syncOrConstellation_toggled(bool checked) { - m_syncOrConstellation = checked; + m_settings.m_syncOrConstellation = checked; applySettings(); } void DSDDemodGUI::on_slot1On_toggled(bool checked) { - m_slot1On = checked; + m_settings.m_slot1On = checked; applySettings(); } void DSDDemodGUI::on_slot2On_toggled(bool checked) { - m_slot2On = checked; + m_settings.m_slot2On = checked; applySettings(); } void DSDDemodGUI::on_tdmaStereoSplit_toggled(bool checked) { - m_tdmaStereo = checked; + m_settings.m_tdmaStereo = checked; applySettings(); } -void DSDDemodGUI::on_squelchGate_valueChanged(int value __attribute__((unused))) +void DSDDemodGUI::on_squelchGate_valueChanged(int value) { + m_settings.m_squelchGate = value; + ui->squelchGateText->setText(QString("%1").arg(value * 10.0, 0, 'f', 0)); applySettings(); } void DSDDemodGUI::on_squelch_valueChanged(int value) { ui->squelchText->setText(QString("%1").arg(value / 10.0, 0, 'f', 1)); + m_settings.m_squelch = value / 10.0; applySettings(); } void DSDDemodGUI::on_audioMute_toggled(bool checked) { - m_audioMute = checked; + m_settings.m_audioMute = checked; applySettings(); } @@ -272,11 +289,13 @@ void DSDDemodGUI::on_symbolPLLLock_toggled(bool checked) } else { ui->symbolPLLLock->setStyleSheet("QToolButton { background:rgb(53,53,53); }"); } + m_settings.m_pllLock = checked; applySettings(); } -void DSDDemodGUI::on_udpOutput_toggled(bool checked __attribute__((unused))) +void DSDDemodGUI::on_udpOutput_toggled(bool checked) { + m_settings.m_udpCopyAudio = checked; applySettings(); } @@ -352,7 +371,11 @@ DSDDemodGUI::DSDDemodGUI(PluginAPI* pluginAPI, DeviceSourceAPI *deviceAPI, QWidg ui->scopeGUI->setBuddies(m_scopeVis->getInputMessageQueue(), m_scopeVis, ui->glScope); + m_settings.setChannelMarker(&m_channelMarker); + m_settings.setScopeGUI(ui->scopeGUI); + updateMyPosition(); + displaySettings(); displayUDPAddress(); applySettings(true); } @@ -382,46 +405,91 @@ void DSDDemodGUI::displayUDPAddress() ui->udpOutput->setToolTip(QString("Copy audio output to UDP %1:%2").arg(m_channelMarker.getUDPAddress()).arg(m_channelMarker.getUDPSendPort())); } +void DSDDemodGUI::displaySettings() +{ + blockApplySettings(true); + + m_channelMarker.blockSignals(true); + m_channelMarker.setCenterFrequency(m_settings.m_inputFrequencyOffset); + m_channelMarker.setUDPAddress(m_settings.m_udpAddress); + m_channelMarker.setUDPSendPort(m_settings.m_udpPort); + m_channelMarker.setColor(m_settings.m_rgbColor); + this->setWindowTitle(m_channelMarker.getTitle()); + setTitleColor(m_settings.m_rgbColor); + m_channelMarker.blockSignals(false); + + ui->deltaFrequency->setValue(m_channelMarker.getCenterFrequency()); + + ui->rfBW->setValue(m_settings.m_rfBandwidth / 100.0); + ui->rfBWText->setText(QString("%1k").arg(ui->rfBW->value() / 10.0, 0, 'f', 1)); + + ui->fmDeviation->setValue(m_settings.m_fmDeviation / 100.0); + ui->fmDeviationText->setText(QString("%1k").arg(ui->fmDeviation->value() / 10.0, 0, 'f', 1)); + + ui->squelch->setValue(m_settings.m_squelch * 10.0); + ui->squelchText->setText(QString("%1").arg(ui->squelch->value() / 10.0, 0, 'f', 1)); + + ui->squelchGate->setValue(m_settings.m_squelchGate); + ui->squelchGateText->setText(QString("%1").arg(ui->squelchGate->value() * 10.0, 0, 'f', 0)); + + ui->demodGain->setValue(m_settings.m_demodGain * 100.0); + ui->demodGainText->setText(QString("%1").arg(ui->demodGain->value() / 100.0, 0, 'f', 2)); + + ui->volume->setValue(m_settings.m_volume * 10.0); + ui->volumeText->setText(QString("%1").arg(ui->volume->value() / 10.0, 0, 'f', 1)); + + ui->enableCosineFiltering->setChecked(m_settings.m_enableCosineFiltering); + ui->syncOrConstellation->setChecked(m_settings.m_syncOrConstellation); + ui->slot1On->setChecked(m_settings.m_slot1On); + ui->slot2On->setChecked(m_settings.m_slot2On); + ui->tdmaStereoSplit->setChecked(m_settings.m_tdmaStereo); + ui->audioMute->setChecked(m_settings.m_audioMute); + ui->udpOutput->setChecked(m_settings.m_udpCopyAudio); + ui->symbolPLLLock->setChecked(m_settings.m_pllLock); + + ui->baudRate->setCurrentIndex(DSDDemodBaudRates::getRateIndex(m_settings.m_baudRate)); + + blockApplySettings(false); +} + void DSDDemodGUI::applySettings(bool force) { if (m_doApplySettings) { qDebug() << "DSDDemodGUI::applySettings"; - setTitleColor(m_channelMarker.getColor()); - DSDDemod::MsgConfigureChannelizer* channelConfigMsg = DSDDemod::MsgConfigureChannelizer::create( 48000, m_channelMarker.getCenterFrequency()); m_dsdDemod->getInputMessageQueue()->push(channelConfigMsg); - ui->deltaFrequency->setValue(m_channelMarker.getCenterFrequency()); - ui->rfBWText->setText(QString("%1k").arg(ui->rfBW->value() / 10.0, 0, 'f', 1)); - ui->demodGainText->setText(QString("%1").arg(ui->demodGain->value() / 100.0, 0, 'f', 2)); - ui->fmDeviationText->setText(QString("%1k").arg(ui->fmDeviation->value() / 10.0, 0, 'f', 1)); - ui->squelchGateText->setText(QString("%1").arg(ui->squelchGate->value() * 10.0, 0, 'f', 0)); - ui->volumeText->setText(QString("%1").arg(ui->volume->value() / 10.0, 0, 'f', 1)); - ui->enableCosineFiltering->setChecked(m_enableCosineFiltering); - ui->syncOrConstellation->setChecked(m_syncOrConstellation); - ui->slot1On->setChecked(m_slot1On); - ui->slot2On->setChecked(m_slot2On); - ui->tdmaStereoSplit->setChecked(m_tdmaStereo); +// ui->deltaFrequency->setValue(m_channelMarker.getCenterFrequency()); +// ui->rfBWText->setText(QString("%1k").arg(ui->rfBW->value() / 10.0, 0, 'f', 1)); +// ui->demodGainText->setText(QString("%1").arg(ui->demodGain->value() / 100.0, 0, 'f', 2)); +// ui->fmDeviationText->setText(QString("%1k").arg(ui->fmDeviation->value() / 10.0, 0, 'f', 1)); +// ui->squelchGateText->setText(QString("%1").arg(ui->squelchGate->value() * 10.0, 0, 'f', 0)); +// ui->volumeText->setText(QString("%1").arg(ui->volume->value() / 10.0, 0, 'f', 1)); +// ui->enableCosineFiltering->setChecked(m_enableCosineFiltering); +// ui->syncOrConstellation->setChecked(m_syncOrConstellation); +// ui->slot1On->setChecked(m_slot1On); +// ui->slot2On->setChecked(m_slot2On); +// ui->tdmaStereoSplit->setChecked(m_tdmaStereo); m_dsdDemod->configure(m_dsdDemod->getInputMessageQueue(), - ui->rfBW->value() * 100.0, - ui->fmDeviation->value() * 100.0, - ui->demodGain->value() / 100.0, - ui->volume->value() / 10.0, + m_settings.m_rfBandwidth, + m_settings.m_fmDeviation, + m_settings.m_demodGain, + m_settings.m_volume, DSDDemodBaudRates::getRate(ui->baudRate->currentIndex()), - ui->squelchGate->value(), // in 10ths of ms - ui->squelch->value() / 10.0, - ui->audioMute->isChecked(), - m_enableCosineFiltering, - m_syncOrConstellation, - m_slot1On, - m_slot2On, - m_tdmaStereo, - ui->symbolPLLLock->isChecked(), - ui->udpOutput->isChecked(), + m_settings.m_squelchGate, // in 10ths of ms + m_settings.m_squelch, + m_settings.m_audioMute, + m_settings.m_enableCosineFiltering, + m_settings.m_syncOrConstellation, + m_settings.m_slot1On, + m_settings.m_slot2On, + m_settings.m_tdmaStereo, + m_settings.m_pllLock, + m_settings.m_udpCopyAudio, m_channelMarker.getUDPAddress(), m_channelMarker.getUDPSendPort(), force); diff --git a/plugins/channelrx/demoddsd/dsddemodgui.h b/plugins/channelrx/demoddsd/dsddemodgui.h index 689ba7b2a..add6e5b83 100644 --- a/plugins/channelrx/demoddsd/dsddemodgui.h +++ b/plugins/channelrx/demoddsd/dsddemodgui.h @@ -27,6 +27,8 @@ #include "dsp/movingaverage.h" #include "util/messagequeue.h" +#include "dsddemodsettings.h" + class PluginAPI; class DeviceSourceAPI; @@ -94,6 +96,7 @@ private: PluginAPI* m_pluginAPI; DeviceSourceAPI* m_deviceAPI; ChannelMarker m_channelMarker; + DSDDemodSettings m_settings; bool m_doApplySettings; char m_formatStatusText[82+1]; //!< Fixed signal format dependent status text SignalFormat m_signalFormat; @@ -120,6 +123,7 @@ private: void blockApplySettings(bool block); void applySettings(bool force = false); + void displaySettings(); void updateMyPosition(); void displayUDPAddress(); From 392f1f43d6795becd7f745d0768acd13b63f6280 Mon Sep 17 00:00:00 2001 From: f4exb Date: Wed, 4 Oct 2017 00:02:59 +0200 Subject: [PATCH 68/71] DSD demod: use settings in demod --- plugins/channelrx/demoddsd/dsddemod.cpp | 158 ++++++++++++++++++--- plugins/channelrx/demoddsd/dsddemod.h | 34 ++++- plugins/channelrx/demoddsd/dsddemodgui.cpp | 41 +++--- 3 files changed, 188 insertions(+), 45 deletions(-) diff --git a/plugins/channelrx/demoddsd/dsddemod.cpp b/plugins/channelrx/demoddsd/dsddemod.cpp index 46e69993d..da4fbab84 100644 --- a/plugins/channelrx/demoddsd/dsddemod.cpp +++ b/plugins/channelrx/demoddsd/dsddemod.cpp @@ -33,6 +33,7 @@ MESSAGE_CLASS_DEFINITION(DSDDemod::MsgConfigureChannelizer, Message) MESSAGE_CLASS_DEFINITION(DSDDemod::MsgConfigureDSDDemod, Message) +MESSAGE_CLASS_DEFINITION(DSDDemod::MsgConfigureDSDDemodPrivate, Message) MESSAGE_CLASS_DEFINITION(DSDDemod::MsgConfigureMyPosition, Message) const int DSDDemod::m_udpBlockSize = 512; @@ -124,7 +125,7 @@ void DSDDemod::configure(MessageQueue* messageQueue, quint16 udpPort, bool force) { - Message* cmd = MsgConfigureDSDDemod::create(rfBandwidth, + Message* cmd = MsgConfigureDSDDemodPrivate::create(rfBandwidth, fmDeviation, demodGain, volume, @@ -182,7 +183,7 @@ void DSDDemod::feed(const SampleVector::const_iterator& begin, const SampleVecto m_magsqCount++; - Real demod = 32768.0f * m_phaseDiscri.phaseDiscriminator(ci) * m_running.m_demodGain; + Real demod = 32768.0f * m_phaseDiscri.phaseDiscriminator(ci) * m_settings.m_demodGain; m_sampleCount++; // AF processing @@ -219,7 +220,7 @@ void DSDDemod::feed(const SampleVector::const_iterator& begin, const SampleVecto m_dsdDecoder.pushSample(sample); - if (m_running.m_enableCosineFiltering) { // show actual input to FSK demod + if (m_settings.m_enableCosineFiltering) { // show actual input to FSK demod sample = m_dsdDecoder.getFilteredSample(); } @@ -237,7 +238,7 @@ void DSDDemod::feed(const SampleVector::const_iterator& begin, const SampleVecto delayedSample = m_sampleBuffer[m_sampleBufferIndex - samplesPerSymbol]; } - if (m_running.m_syncOrConstellation) + if (m_settings.m_syncOrConstellation) { Sample s(sample, m_dsdDecoder.getSymbolSyncSample()); m_scopeSampleBuffer.push_back(s); @@ -250,30 +251,30 @@ void DSDDemod::feed(const SampleVector::const_iterator& begin, const SampleVecto if (DSPEngine::instance()->hasDVSerialSupport()) { - if ((m_running.m_slot1On) && m_dsdDecoder.mbeDVReady1()) + if ((m_settings.m_slot1On) && m_dsdDecoder.mbeDVReady1()) { - if (!m_running.m_audioMute) + if (!m_settings.m_audioMute) { DSPEngine::instance()->pushMbeFrame( m_dsdDecoder.getMbeDVFrame1(), m_dsdDecoder.getMbeRateIndex(), - m_running.m_volume, - m_running.m_tdmaStereo ? 1 : 3, // left or both channels + m_settings.m_volume, + m_settings.m_tdmaStereo ? 1 : 3, // left or both channels &m_audioFifo1); } m_dsdDecoder.resetMbeDV1(); } - if ((m_running.m_slot2On) && m_dsdDecoder.mbeDVReady2()) + if ((m_settings.m_slot2On) && m_dsdDecoder.mbeDVReady2()) { - if (!m_running.m_audioMute) + if (!m_settings.m_audioMute) { DSPEngine::instance()->pushMbeFrame( m_dsdDecoder.getMbeDVFrame2(), m_dsdDecoder.getMbeRateIndex(), - m_running.m_volume, - m_running.m_tdmaStereo ? 2 : 3, // right or both channels + m_settings.m_volume, + m_settings.m_tdmaStereo ? 2 : 3, // right or both channels &m_audioFifo2); } @@ -283,9 +284,9 @@ void DSDDemod::feed(const SampleVector::const_iterator& begin, const SampleVecto // if (DSPEngine::instance()->hasDVSerialSupport() && m_dsdDecoder.mbeDVReady1()) // { -// if (!m_running.m_audioMute) +// if (!m_settings.m_audioMute) // { -// DSPEngine::instance()->pushMbeFrame(m_dsdDecoder.getMbeDVFrame1(), m_dsdDecoder.getMbeRateIndex(), m_running.m_volume, &m_audioFifo1); +// DSPEngine::instance()->pushMbeFrame(m_dsdDecoder.getMbeDVFrame1(), m_dsdDecoder.getMbeRateIndex(), m_settings.m_volume, &m_audioFifo1); // } // // m_dsdDecoder.resetMbeDV1(); @@ -297,14 +298,14 @@ void DSDDemod::feed(const SampleVector::const_iterator& begin, const SampleVecto if (!DSPEngine::instance()->hasDVSerialSupport()) { - if (m_running.m_slot1On) + if (m_settings.m_slot1On) { int nbAudioSamples; short *dsdAudio = m_dsdDecoder.getAudio1(nbAudioSamples); if (nbAudioSamples > 0) { - if (!m_running.m_audioMute) { + if (!m_settings.m_audioMute) { m_audioFifo1.write((const quint8*) dsdAudio, nbAudioSamples, 10); } @@ -312,14 +313,14 @@ void DSDDemod::feed(const SampleVector::const_iterator& begin, const SampleVecto } } - if (m_running.m_slot2On) + if (m_settings.m_slot2On) { int nbAudioSamples; short *dsdAudio = m_dsdDecoder.getAudio2(nbAudioSamples); if (nbAudioSamples > 0) { - if (!m_running.m_audioMute) { + if (!m_settings.m_audioMute) { m_audioFifo2.write((const quint8*) dsdAudio, nbAudioSamples, 10); } @@ -332,7 +333,7 @@ void DSDDemod::feed(const SampleVector::const_iterator& begin, const SampleVecto // // if (nbAudioSamples > 0) // { -// if (!m_running.m_audioMute) { +// if (!m_settings.m_audioMute) { // uint res = m_audioFifo1.write((const quint8*) dsdAudio, nbAudioSamples, 10); // } // @@ -388,9 +389,42 @@ bool DSDDemod::handleMessage(const Message& cmd) return true; } - else if (MsgConfigureDSDDemod::match(cmd)) + else if (MsgConfigureDSDDemod::match(cmd)) + { + MsgConfigureDSDDemod& cfg = (MsgConfigureDSDDemod&) cmd; + + DSDDemodSettings settings = cfg.getSettings(); + + // These settings are set with DownChannelizer::MsgChannelizerNotification + settings.m_inputSampleRate = m_settings.m_inputSampleRate; + settings.m_inputFrequencyOffset = m_settings.m_inputFrequencyOffset; + + applySettings(settings, cfg.getForce()); + + qDebug() << "DSDDemod::handleMessage: MsgConfigureDSDDemod: m_rfBandwidth: " << m_settings.m_rfBandwidth + << " m_fmDeviation: " << m_settings.m_fmDeviation + << " m_demodGain: " << m_settings.m_demodGain + << " m_volume: " << m_settings.m_volume + << " m_baudRate: " << m_settings.m_baudRate + << " m_squelchGate" << m_settings.m_squelchGate + << " m_squelch: " << m_settings.m_squelch + << " m_audioMute: " << m_settings.m_audioMute + << " m_enableCosineFiltering: " << m_settings.m_enableCosineFiltering + << " m_syncOrConstellation: " << m_settings.m_syncOrConstellation + << " m_slot1On: " << m_settings.m_slot1On + << " m_slot2On: " << m_settings.m_slot2On + << " m_tdmaStereo: " << m_settings.m_tdmaStereo + << " m_pllLock: " << m_settings.m_pllLock + << " m_udpCopyAudio: " << m_settings.m_udpCopyAudio + << " m_udpAddress: " << m_settings.m_udpAddress + << " m_udpPort: " << m_settings.m_udpPort + << " force: " << cfg.getForce(); + + return true; + } + else if (MsgConfigureDSDDemodPrivate::match(cmd)) { - MsgConfigureDSDDemod& cfg = (MsgConfigureDSDDemod&) cmd; + MsgConfigureDSDDemodPrivate& cfg = (MsgConfigureDSDDemodPrivate&) cmd; m_config.m_rfBandwidth = cfg.getRFBandwidth(); m_config.m_demodGain = cfg.getDemodGain(); @@ -412,7 +446,7 @@ bool DSDDemod::handleMessage(const Message& cmd) apply(); - qDebug() << "DSDDemod::handleMessage: MsgConfigureDSDDemod: m_rfBandwidth: " << m_config.m_rfBandwidth + qDebug() << "DSDDemod::handleMessage: MsgConfigureDSDDemodPrivate: m_rfBandwidth: " << m_config.m_rfBandwidth << " m_fmDeviation: " << m_config.m_fmDeviation << " m_demodGain: " << m_config.m_demodGain << " m_volume: " << m_config.m_volume @@ -523,3 +557,83 @@ void DSDDemod::apply(bool force) m_running = m_config; } + +void DSDDemod::applySettings(DSDDemodSettings& settings, bool force) +{ + if ((settings.m_inputFrequencyOffset != m_settings.m_inputFrequencyOffset) || + (settings.m_inputSampleRate != m_settings.m_inputSampleRate) || force) + { + m_nco.setFreq(-settings.m_inputFrequencyOffset, settings.m_inputSampleRate); + } + + if ((settings.m_inputSampleRate != m_settings.m_inputSampleRate) || + (settings.m_rfBandwidth != m_settings.m_rfBandwidth) || force) + { + m_settingsMutex.lock(); + m_interpolator.create(16, settings.m_inputSampleRate, (settings.m_rfBandwidth) / 2.2); + m_interpolatorDistanceRemain = 0; + m_interpolatorDistance = (Real) settings.m_inputSampleRate / (Real) settings.m_audioSampleRate; + m_phaseDiscri.setFMScaling((float) settings.m_rfBandwidth / (float) settings.m_fmDeviation); + m_settingsMutex.unlock(); + } + + if ((settings.m_fmDeviation != m_settings.m_fmDeviation) || force) + { + m_phaseDiscri.setFMScaling((float) settings.m_rfBandwidth / (float) settings.m_fmDeviation); + } + + if ((settings.m_squelchGate != m_settings.m_squelchGate) || force) + { + m_squelchGate = 480 * settings.m_squelchGate; // gate is given in 10s of ms at 48000 Hz audio sample rate + m_squelchCount = 0; // reset squelch open counter + } + + if ((settings.m_squelch != m_settings.m_squelch) || force) + { + // input is a value in dB + m_squelchLevel = std::pow(10.0, settings.m_squelch / 10.0); + //m_squelchLevel *= m_squelchLevel; + } + + if ((settings.m_volume != m_settings.m_volume) || force) + { + m_dsdDecoder.setAudioGain(settings.m_volume); + } + + if ((settings.m_baudRate != m_settings.m_baudRate) || force) + { + m_dsdDecoder.setBaudRate(settings.m_baudRate); + } + + if ((settings.m_enableCosineFiltering != m_settings.m_enableCosineFiltering) || force) + { + m_dsdDecoder.enableCosineFiltering(settings.m_enableCosineFiltering); + } + + if ((settings.m_tdmaStereo != m_settings.m_tdmaStereo) || force) + { + m_dsdDecoder.setTDMAStereo(settings.m_tdmaStereo); + } + + if ((settings.m_pllLock != m_settings.m_pllLock) || force) + { + m_dsdDecoder.setSymbolPLLLock(settings.m_pllLock); + } + + if ((settings.m_udpAddress != m_settings.m_udpAddress) + || (settings.m_udpPort != m_settings.m_udpPort) || force) + { + m_udpBufferAudio->setAddress(settings.m_udpAddress); + m_udpBufferAudio->setPort(settings.m_udpPort); + } + + if ((settings.m_udpCopyAudio != m_settings.m_udpCopyAudio) + || (settings.m_slot1On != m_settings.m_slot1On) + || (settings.m_slot2On != m_settings.m_slot2On) || force) + { + m_audioFifo1.setCopyToUDP(settings.m_slot1On && settings.m_udpCopyAudio); + m_audioFifo2.setCopyToUDP(settings.m_slot2On && !settings.m_slot1On && settings.m_udpCopyAudio); + } + + m_settings = settings; +} diff --git a/plugins/channelrx/demoddsd/dsddemod.h b/plugins/channelrx/demoddsd/dsddemod.h index b57dd074f..fa6050195 100644 --- a/plugins/channelrx/demoddsd/dsddemod.h +++ b/plugins/channelrx/demoddsd/dsddemod.h @@ -33,6 +33,7 @@ #include "util/message.h" #include "util/udpsink.h" +#include "dsddemodsettings.h" #include "dsddecoder.h" class DeviceSourceAPI; @@ -41,6 +42,29 @@ class DownChannelizer; class DSDDemod : public BasebandSampleSink { public: + class MsgConfigureDSDDemod : public Message { + MESSAGE_CLASS_DECLARATION + + public: + const DSDDemodSettings& getSettings() const { return m_settings; } + bool getForce() const { return m_force; } + + static MsgConfigureDSDDemod* create(const DSDDemodSettings& settings, bool force) + { + return new MsgConfigureDSDDemod(settings, force); + } + + private: + DSDDemodSettings m_settings; + bool m_force; + + MsgConfigureDSDDemod(const DSDDemodSettings& settings, bool force) : + Message(), + m_settings(settings), + m_force(force) + { } + }; + class MsgConfigureChannelizer : public Message { MESSAGE_CLASS_DECLARATION @@ -135,7 +159,7 @@ private: {} }; - class MsgConfigureDSDDemod : public Message { + class MsgConfigureDSDDemodPrivate : public Message { MESSAGE_CLASS_DECLARATION public: @@ -157,7 +181,7 @@ private: const QString& getUDPAddress() const { return m_udpAddress; } quint16 getUDPPort() const { return m_udpPort; } - static MsgConfigureDSDDemod* create(Real rfBandwidth, + static MsgConfigureDSDDemodPrivate* create(Real rfBandwidth, Real fmDeviation, Real demodGain, Real volume, @@ -176,7 +200,7 @@ private: quint16 udpPort, bool force) { - return new MsgConfigureDSDDemod(rfBandwidth, + return new MsgConfigureDSDDemodPrivate(rfBandwidth, fmDeviation, demodGain, volume, @@ -216,7 +240,7 @@ private: quint16 m_udpPort; bool m_force; - MsgConfigureDSDDemod(Real rfBandwidth, + MsgConfigureDSDDemodPrivate(Real rfBandwidth, Real fmDeviation, Real demodGain, Real volume, @@ -309,6 +333,7 @@ private: Config m_config; Config m_running; + DSDDemodSettings m_settings; DeviceSourceAPI *m_deviceAPI; ThreadedBasebandSampleSink* m_threadedChannelizer; @@ -354,6 +379,7 @@ private: static const int m_udpBlockSize; void apply(bool force = false); + void applySettings(DSDDemodSettings& settings, bool force = false); }; #endif // INCLUDE_DSDDEMOD_H diff --git a/plugins/channelrx/demoddsd/dsddemodgui.cpp b/plugins/channelrx/demoddsd/dsddemodgui.cpp index 918de087d..e75ae5a53 100644 --- a/plugins/channelrx/demoddsd/dsddemodgui.cpp +++ b/plugins/channelrx/demoddsd/dsddemodgui.cpp @@ -462,6 +462,9 @@ void DSDDemodGUI::applySettings(bool force) 48000, m_channelMarker.getCenterFrequency()); m_dsdDemod->getInputMessageQueue()->push(channelConfigMsg); + DSDDemod::MsgConfigureDSDDemod* message = DSDDemod::MsgConfigureDSDDemod::create( m_settings, force); + m_dsdDemod->getInputMessageQueue()->push(message); + // ui->deltaFrequency->setValue(m_channelMarker.getCenterFrequency()); // ui->rfBWText->setText(QString("%1k").arg(ui->rfBW->value() / 10.0, 0, 'f', 1)); // ui->demodGainText->setText(QString("%1").arg(ui->demodGain->value() / 100.0, 0, 'f', 2)); @@ -474,25 +477,25 @@ void DSDDemodGUI::applySettings(bool force) // ui->slot2On->setChecked(m_slot2On); // ui->tdmaStereoSplit->setChecked(m_tdmaStereo); - m_dsdDemod->configure(m_dsdDemod->getInputMessageQueue(), - m_settings.m_rfBandwidth, - m_settings.m_fmDeviation, - m_settings.m_demodGain, - m_settings.m_volume, - DSDDemodBaudRates::getRate(ui->baudRate->currentIndex()), - m_settings.m_squelchGate, // in 10ths of ms - m_settings.m_squelch, - m_settings.m_audioMute, - m_settings.m_enableCosineFiltering, - m_settings.m_syncOrConstellation, - m_settings.m_slot1On, - m_settings.m_slot2On, - m_settings.m_tdmaStereo, - m_settings.m_pllLock, - m_settings.m_udpCopyAudio, - m_channelMarker.getUDPAddress(), - m_channelMarker.getUDPSendPort(), - force); +// m_dsdDemod->configure(m_dsdDemod->getInputMessageQueue(), +// m_settings.m_rfBandwidth, +// m_settings.m_fmDeviation, +// m_settings.m_demodGain, +// m_settings.m_volume, +// DSDDemodBaudRates::getRate(ui->baudRate->currentIndex()), +// m_settings.m_squelchGate, // in 10ths of ms +// m_settings.m_squelch, +// m_settings.m_audioMute, +// m_settings.m_enableCosineFiltering, +// m_settings.m_syncOrConstellation, +// m_settings.m_slot1On, +// m_settings.m_slot2On, +// m_settings.m_tdmaStereo, +// m_settings.m_pllLock, +// m_settings.m_udpCopyAudio, +// m_channelMarker.getUDPAddress(), +// m_channelMarker.getUDPSendPort(), +// force); } } From 3405424ad1f9fa0a9ae0d785278d3312c46c17e6 Mon Sep 17 00:00:00 2001 From: f4exb Date: Wed, 4 Oct 2017 00:29:47 +0200 Subject: [PATCH 69/71] DSD demod: old code cleanup --- plugins/channelrx/demoddsd/dsddemod.cpp | 207 ++---------------- plugins/channelrx/demoddsd/dsddemod.h | 191 ---------------- plugins/channelrx/demoddsd/dsddemodgui.cpp | 117 ---------- .../channelrx/demoddsd/dsddemodsettings.cpp | 14 +- 4 files changed, 23 insertions(+), 506 deletions(-) diff --git a/plugins/channelrx/demoddsd/dsddemod.cpp b/plugins/channelrx/demoddsd/dsddemod.cpp index da4fbab84..6a69c6fe2 100644 --- a/plugins/channelrx/demoddsd/dsddemod.cpp +++ b/plugins/channelrx/demoddsd/dsddemod.cpp @@ -33,19 +33,22 @@ MESSAGE_CLASS_DEFINITION(DSDDemod::MsgConfigureChannelizer, Message) MESSAGE_CLASS_DEFINITION(DSDDemod::MsgConfigureDSDDemod, Message) -MESSAGE_CLASS_DEFINITION(DSDDemod::MsgConfigureDSDDemodPrivate, Message) MESSAGE_CLASS_DEFINITION(DSDDemod::MsgConfigureMyPosition, Message) const int DSDDemod::m_udpBlockSize = 512; DSDDemod::DSDDemod(DeviceSourceAPI *deviceAPI) : m_deviceAPI(deviceAPI), - m_sampleCount(0), - m_squelchCount(0), - m_squelchOpen(false), + m_interpolatorDistance(0.0f), + m_interpolatorDistanceRemain(0.0f), + m_sampleCount(0), + m_squelchCount(0), + m_squelchGate(0), + m_squelchLevel(1e-4), + m_squelchOpen(false), m_movingAverage(40, 0), m_fmExcursion(24), - m_audioFifo1(48000), + m_audioFifo1(48000), m_audioFifo2(48000), m_scope(0), m_scopeEnabled(true), @@ -54,19 +57,6 @@ DSDDemod::DSDDemod(DeviceSourceAPI *deviceAPI) : { setObjectName("DSDDemod"); - m_config.m_inputSampleRate = 96000; - m_config.m_inputFrequencyOffset = 0; - m_config.m_rfBandwidth = 10000.0; - m_config.m_fmDeviation = 5000.0; - m_config.m_demodGain = 1.0; - m_config.m_squelchGate = 5; // 10s of ms at 48000 Hz sample rate. Corresponds to 2400 for AGC attack - m_config.m_squelch = -30.0; - m_config.m_volume = 1.0; - m_config.m_baudRate = 4800; - m_config.m_audioMute = false; - m_config.m_audioSampleRate = DSPEngine::instance()->getAudioSampleRate(); - m_config.m_enableCosineFiltering = false; - m_audioBuffer.resize(1<<14); m_audioBufferFill = 0; @@ -82,7 +72,7 @@ DSDDemod::DSDDemod(DeviceSourceAPI *deviceAPI) : DSPEngine::instance()->addAudioSink(&m_audioFifo1); DSPEngine::instance()->addAudioSink(&m_audioFifo2); - m_udpBufferAudio = new UDPSink(this, m_udpBlockSize, m_config.m_udpPort); + m_udpBufferAudio = new UDPSink(this, m_udpBlockSize, m_settings.m_udpPort); m_audioFifo1.setUDPSink(m_udpBufferAudio); m_audioFifo2.setUDPSink(m_udpBufferAudio); @@ -90,7 +80,7 @@ DSDDemod::DSDDemod(DeviceSourceAPI *deviceAPI) : m_threadedChannelizer = new ThreadedBasebandSampleSink(m_channelizer, this); m_deviceAPI->addThreadedSink(m_threadedChannelizer); - apply(true); + applySettings(m_settings, true); } DSDDemod::~DSDDemod() @@ -105,47 +95,6 @@ DSDDemod::~DSDDemod() delete m_channelizer; } -void DSDDemod::configure(MessageQueue* messageQueue, - Real rfBandwidth, - Real fmDeviation, - Real demodGain, - Real volume, - int baudRate, - int squelchGate, - Real squelch, - bool audioMute, - bool enableCosineFiltering, - bool syncOrConstellation, - bool slot1On, - bool slot2On, - bool tdmaStereo, - bool pllLock, - bool udpCopyAudio, - const QString& udpAddress, - quint16 udpPort, - bool force) -{ - Message* cmd = MsgConfigureDSDDemodPrivate::create(rfBandwidth, - fmDeviation, - demodGain, - volume, - baudRate, - squelchGate, - squelch, - audioMute, - enableCosineFiltering, - syncOrConstellation, - slot1On, - slot2On, - tdmaStereo, - pllLock, - udpCopyAudio, - udpAddress, - udpPort, - force); - messageQueue->push(cmd); -} - void DSDDemod::configureMyPosition(MessageQueue* messageQueue, float myLatitude, float myLongitude) { Message* cmd = MsgConfigureMyPosition::create(myLatitude, myLongitude); @@ -369,13 +318,14 @@ bool DSDDemod::handleMessage(const Message& cmd) { DownChannelizer::MsgChannelizerNotification& notif = (DownChannelizer::MsgChannelizerNotification&) cmd; - m_config.m_inputSampleRate = notif.getSampleRate(); - m_config.m_inputFrequencyOffset = notif.getFrequencyOffset(); + DSDDemodSettings settings = m_settings; + settings.m_inputSampleRate = notif.getSampleRate(); + settings.m_inputFrequencyOffset = notif.getFrequencyOffset(); - apply(); + applySettings(settings); - qDebug() << "DSDDemod::handleMessage: MsgChannelizerNotification: m_inputSampleRate: " << m_config.m_inputSampleRate - << " m_inputFrequencyOffset: " << m_config.m_inputFrequencyOffset; + qDebug() << "DSDDemod::handleMessage: MsgChannelizerNotification: m_inputSampleRate: " << settings.m_inputSampleRate + << " m_inputFrequencyOffset: " << settings.m_inputFrequencyOffset; return true; } @@ -422,50 +372,6 @@ bool DSDDemod::handleMessage(const Message& cmd) return true; } - else if (MsgConfigureDSDDemodPrivate::match(cmd)) - { - MsgConfigureDSDDemodPrivate& cfg = (MsgConfigureDSDDemodPrivate&) cmd; - - m_config.m_rfBandwidth = cfg.getRFBandwidth(); - m_config.m_demodGain = cfg.getDemodGain(); - m_config.m_fmDeviation = cfg.getFMDeviation(); - m_config.m_volume = cfg.getVolume(); - m_config.m_baudRate = cfg.getBaudRate(); - m_config.m_squelchGate = cfg.getSquelchGate(); - m_config.m_squelch = cfg.getSquelch(); - m_config.m_audioMute = cfg.getAudioMute(); - m_config.m_enableCosineFiltering = cfg.getEnableCosineFiltering(); - m_config.m_syncOrConstellation = cfg.getSyncOrConstellation(); - m_config.m_slot1On = cfg.getSlot1On(); - m_config.m_slot2On = cfg.getSlot2On(); - m_config.m_tdmaStereo = cfg.getTDMAStereo(); - m_config.m_pllLock = cfg.getPLLLock(); - m_config.m_udpCopyAudio = cfg.getUDPCopyAudio(); - m_config.m_udpAddress = cfg.getUDPAddress(); - m_config.m_udpPort = cfg.getUDPPort(); - - apply(); - - qDebug() << "DSDDemod::handleMessage: MsgConfigureDSDDemodPrivate: m_rfBandwidth: " << m_config.m_rfBandwidth - << " m_fmDeviation: " << m_config.m_fmDeviation - << " m_demodGain: " << m_config.m_demodGain - << " m_volume: " << m_config.m_volume - << " m_baudRate: " << m_config.m_baudRate - << " m_squelchGate" << m_config.m_squelchGate - << " m_squelch: " << m_config.m_squelch - << " m_audioMute: " << m_config.m_audioMute - << " m_enableCosineFiltering: " << m_config.m_enableCosineFiltering - << " m_syncOrConstellation: " << m_config.m_syncOrConstellation - << " m_slot1On: " << m_config.m_slot1On - << " m_slot2On: " << m_config.m_slot2On - << " m_tdmaStereo: " << m_config.m_tdmaStereo - << " m_pllLock: " << m_config.m_pllLock - << " m_udpCopyAudio: " << m_config.m_udpCopyAudio - << " m_udpAddress: " << m_config.m_udpAddress - << " m_udpPort: " << m_config.m_udpPort; - - return true; - } else if (MsgConfigureMyPosition::match(cmd)) { MsgConfigureMyPosition& cfg = (MsgConfigureMyPosition&) cmd; @@ -478,86 +384,6 @@ bool DSDDemod::handleMessage(const Message& cmd) } } -void DSDDemod::apply(bool force) -{ - if ((m_config.m_inputFrequencyOffset != m_running.m_inputFrequencyOffset) || - (m_config.m_inputSampleRate != m_running.m_inputSampleRate) || force) - { - m_nco.setFreq(-m_config.m_inputFrequencyOffset, m_config.m_inputSampleRate); - } - - if ((m_config.m_inputSampleRate != m_running.m_inputSampleRate) || - (m_config.m_rfBandwidth != m_running.m_rfBandwidth) || force) - { - m_settingsMutex.lock(); - m_interpolator.create(16, m_config.m_inputSampleRate, (m_config.m_rfBandwidth) / 2.2); - m_interpolatorDistanceRemain = 0; - m_interpolatorDistance = (Real) m_config.m_inputSampleRate / (Real) m_config.m_audioSampleRate; - m_phaseDiscri.setFMScaling((float) m_config.m_rfBandwidth / (float) m_config.m_fmDeviation); - m_settingsMutex.unlock(); - } - - if ((m_config.m_fmDeviation != m_running.m_fmDeviation) || force) - { - m_phaseDiscri.setFMScaling((float) m_config.m_rfBandwidth / (float) m_config.m_fmDeviation); - } - - if ((m_config.m_squelchGate != m_running.m_squelchGate) || force) - { - m_squelchGate = 480 * m_config.m_squelchGate; // gate is given in 10s of ms at 48000 Hz audio sample rate - m_squelchCount = 0; // reset squelch open counter - } - - if ((m_config.m_squelch != m_running.m_squelch) || force) - { - // input is a value in dB - m_squelchLevel = std::pow(10.0, m_config.m_squelch / 10.0); - //m_squelchLevel *= m_squelchLevel; - } - - if ((m_config.m_volume != m_running.m_volume) || force) - { - m_dsdDecoder.setAudioGain(m_config.m_volume); - } - - if ((m_config.m_baudRate != m_running.m_baudRate) || force) - { - m_dsdDecoder.setBaudRate(m_config.m_baudRate); - } - - if ((m_config.m_enableCosineFiltering != m_running.m_enableCosineFiltering) || force) - { - m_dsdDecoder.enableCosineFiltering(m_config.m_enableCosineFiltering); - } - - if ((m_config.m_tdmaStereo != m_running.m_tdmaStereo) || force) - { - m_dsdDecoder.setTDMAStereo(m_config.m_tdmaStereo); - } - - if ((m_config.m_pllLock != m_running.m_pllLock) || force) - { - m_dsdDecoder.setSymbolPLLLock(m_config.m_pllLock); - } - - if ((m_config.m_udpAddress != m_running.m_udpAddress) - || (m_config.m_udpPort != m_running.m_udpPort) || force) - { - m_udpBufferAudio->setAddress(m_config.m_udpAddress); - m_udpBufferAudio->setPort(m_config.m_udpPort); - } - - if ((m_config.m_udpCopyAudio != m_running.m_udpCopyAudio) - || (m_config.m_slot1On != m_running.m_slot1On) - || (m_config.m_slot2On != m_running.m_slot2On) || force) - { - m_audioFifo1.setCopyToUDP(m_config.m_slot1On && m_config.m_udpCopyAudio); - m_audioFifo2.setCopyToUDP(m_config.m_slot2On && !m_config.m_slot1On && m_config.m_udpCopyAudio); - } - - m_running = m_config; -} - void DSDDemod::applySettings(DSDDemodSettings& settings, bool force) { if ((settings.m_inputFrequencyOffset != m_settings.m_inputFrequencyOffset) || @@ -592,7 +418,6 @@ void DSDDemod::applySettings(DSDDemodSettings& settings, bool force) { // input is a value in dB m_squelchLevel = std::pow(10.0, settings.m_squelch / 10.0); - //m_squelchLevel *= m_squelchLevel; } if ((settings.m_volume != m_settings.m_volume) || force) diff --git a/plugins/channelrx/demoddsd/dsddemod.h b/plugins/channelrx/demoddsd/dsddemod.h index fa6050195..501c58ccc 100644 --- a/plugins/channelrx/demoddsd/dsddemod.h +++ b/plugins/channelrx/demoddsd/dsddemod.h @@ -92,26 +92,6 @@ public: ~DSDDemod(); void setScopeSink(BasebandSampleSink* sampleSink) { m_scope = sampleSink; } - void configure(MessageQueue* messageQueue, - Real rfBandwidth, - Real fmDeviation, - Real demodGain, - Real volume, - int baudRate, - int squelchGate, - Real squelch, - bool audioMute, - bool enableCosineFiltering, - bool syncOrConstellation, - bool slot1On, - bool slot2On, - bool tdmaStereo, - bool pllLock, - bool udpCopyAudio, - const QString& udpAddress, - quint16 udpPort, - bool force); - void configureMyPosition(MessageQueue* messageQueue, float myLatitude, float myLongitude); virtual void feed(const SampleVector::const_iterator& begin, const SampleVector::const_iterator& end, bool po); @@ -159,180 +139,11 @@ private: {} }; - class MsgConfigureDSDDemodPrivate : public Message { - MESSAGE_CLASS_DECLARATION - - public: - Real getRFBandwidth() const { return m_rfBandwidth; } - Real getFMDeviation() const { return m_fmDeviation; } - Real getDemodGain() const { return m_demodGain; } - Real getVolume() const { return m_volume; } - int getBaudRate() const { return m_baudRate; } - int getSquelchGate() const { return m_squelchGate; } - Real getSquelch() const { return m_squelch; } - bool getAudioMute() const { return m_audioMute; } - bool getEnableCosineFiltering() const { return m_enableCosineFiltering; } - bool getSyncOrConstellation() const { return m_syncOrConstellation; } - bool getSlot1On() const { return m_slot1On; } - bool getSlot2On() const { return m_slot2On; } - bool getTDMAStereo() const { return m_tdmaStereo; } - bool getPLLLock() const { return m_pllLock; } - bool getUDPCopyAudio() const { return m_udpCopyAudio; } - const QString& getUDPAddress() const { return m_udpAddress; } - quint16 getUDPPort() const { return m_udpPort; } - - static MsgConfigureDSDDemodPrivate* create(Real rfBandwidth, - Real fmDeviation, - Real demodGain, - Real volume, - int baudRate, - int squelchGate, - Real squelch, - bool audioMute, - bool enableCosineFiltering, - bool syncOrConstellation, - bool slot1On, - bool slot2On, - bool tdmaStereo, - bool pllLock, - bool udpCopyAudio, - const QString& udpAddress, - quint16 udpPort, - bool force) - { - return new MsgConfigureDSDDemodPrivate(rfBandwidth, - fmDeviation, - demodGain, - volume, - baudRate, - squelchGate, - squelch, - audioMute, - enableCosineFiltering, - syncOrConstellation, - slot1On, - slot2On, - tdmaStereo, - pllLock, - udpCopyAudio, - udpAddress, - udpPort, - force); - } - - private: - Real m_rfBandwidth; - Real m_fmDeviation; - Real m_demodGain; - Real m_volume; - int m_baudRate; - int m_squelchGate; - Real m_squelch; - bool m_audioMute; - bool m_enableCosineFiltering; - bool m_syncOrConstellation; - bool m_slot1On; - bool m_slot2On; - bool m_tdmaStereo; - bool m_pllLock; - bool m_udpCopyAudio; - QString m_udpAddress; - quint16 m_udpPort; - bool m_force; - - MsgConfigureDSDDemodPrivate(Real rfBandwidth, - Real fmDeviation, - Real demodGain, - Real volume, - int baudRate, - int squelchGate, - Real squelch, - bool audioMute, - bool enableCosineFiltering, - bool syncOrConstellation, - bool slot1On, - bool slot2On, - bool tdmaStereo, - bool pllLock, - bool udpCopyAudio, - const QString& udpAddress, - quint16 udpPort, - bool force) : - Message(), - m_rfBandwidth(rfBandwidth), - m_fmDeviation(fmDeviation), - m_demodGain(demodGain), - m_volume(volume), - m_baudRate(baudRate), - m_squelchGate(squelchGate), - m_squelch(squelch), - m_audioMute(audioMute), - m_enableCosineFiltering(enableCosineFiltering), - m_syncOrConstellation(syncOrConstellation), - m_slot1On(slot1On), - m_slot2On(slot2On), - m_tdmaStereo(tdmaStereo), - m_pllLock(pllLock), - m_udpCopyAudio(udpCopyAudio), - m_udpAddress(udpAddress), - m_udpPort(udpPort), - m_force(force) - { } - }; - enum RateState { RSInitialFill, RSRunning }; - struct Config { - int m_inputSampleRate; - qint64 m_inputFrequencyOffset; - Real m_rfBandwidth; - Real m_fmDeviation; - Real m_demodGain; - Real m_volume; - int m_baudRate; - int m_squelchGate; - Real m_squelch; - bool m_audioMute; - quint32 m_audioSampleRate; - bool m_enableCosineFiltering; - bool m_syncOrConstellation; - bool m_slot1On; - bool m_slot2On; - bool m_tdmaStereo; - bool m_pllLock; - bool m_udpCopyAudio; - QString m_udpAddress; - quint16 m_udpPort; - - Config() : - m_inputSampleRate(-1), - m_inputFrequencyOffset(0), - m_rfBandwidth(10000.0), - m_fmDeviation(5000.0), - m_demodGain(1.0), - m_volume(1.0), - m_baudRate(4800), - m_squelchGate(1), - m_squelch(-40.0), - m_audioMute(false), - m_audioSampleRate(0), - m_enableCosineFiltering(false), - m_syncOrConstellation(false), - m_slot1On(false), - m_slot2On(false), - m_tdmaStereo(false), - m_pllLock(true), - m_udpCopyAudio(false), - m_udpAddress("127.0.0.1"), - m_udpPort(9999) - { } - }; - - Config m_config; - Config m_running; DSDDemodSettings m_settings; DeviceSourceAPI *m_deviceAPI; @@ -350,7 +161,6 @@ private: double m_squelchLevel; bool m_squelchOpen; - Real m_lastArgument; MovingAverage m_movingAverage; double m_magsq; double m_magsqSum; @@ -378,7 +188,6 @@ private: static const int m_udpBlockSize; - void apply(bool force = false); void applySettings(DSDDemodSettings& settings, bool force = false); }; diff --git a/plugins/channelrx/demoddsd/dsddemodgui.cpp b/plugins/channelrx/demoddsd/dsddemodgui.cpp index e75ae5a53..dd42a01e2 100644 --- a/plugins/channelrx/demoddsd/dsddemodgui.cpp +++ b/plugins/channelrx/demoddsd/dsddemodgui.cpp @@ -83,24 +83,6 @@ void DSDDemodGUI::resetToDefaults() QByteArray DSDDemodGUI::serialize() const { return m_settings.serialize(); -// SimpleSerializer s(1); -// s.writeS32(1, m_channelMarker.getCenterFrequency()); -// s.writeS32(2, ui->rfBW->value()); -// s.writeS32(3, ui->demodGain->value()); -// s.writeS32(4, ui->fmDeviation->value()); -// s.writeS32(5, ui->squelch->value()); -// s.writeU32(7, m_channelMarker.getColor().rgb()); -// s.writeS32(8, ui->squelchGate->value()); -// s.writeS32(9, ui->volume->value()); -// s.writeBlob(10, ui->scopeGUI->serialize()); -// s.writeS32(11, ui->baudRate->currentIndex()); -// s.writeBool(12, m_enableCosineFiltering); -// s.writeBool(13, m_syncOrConstellation); -// s.writeBool(14, m_slot1On); -// s.writeBool(15, m_slot2On); -// s.writeBool(16, m_tdmaStereo); -// s.writeBlob(17, m_channelMarker.serialize()); -// return s.final(); } bool DSDDemodGUI::deserialize(const QByteArray& data) @@ -116,73 +98,6 @@ bool DSDDemodGUI::deserialize(const QByteArray& data) resetToDefaults(); return false; } - -// SimpleDeserializer d(data); -// -// if (!d.isValid()) -// { -// resetToDefaults(); -// return false; -// } -// -// if (d.getVersion() == 1) -// { -// QByteArray bytetmp; -// QString strtmp; -// quint32 u32tmp; -// qint32 tmp; -// -// blockApplySettings(true); -// m_channelMarker.blockSignals(true); -// -// d.readBlob(17, &bytetmp); -// m_channelMarker.deserialize(bytetmp); -// -// d.readS32(1, &tmp, 0); -// m_channelMarker.setCenterFrequency(tmp); -// d.readS32(2, &tmp, 4); -// ui->rfBW->setValue(tmp); -// d.readS32(3, &tmp, 3); -// ui->demodGain->setValue(tmp); -// d.readS32(4, &tmp, 20); -// ui->fmDeviation->setValue(tmp); -// d.readS32(5, &tmp, -40); -// ui->squelch->setValue(tmp); -// -// if(d.readU32(7, &u32tmp)) -// { -// m_channelMarker.setColor(u32tmp); -// } -// -// d.readS32(8, &tmp, 5); -// ui->squelchGate->setValue(tmp); -// d.readS32(9, &tmp, 20); -// ui->volume->setValue(tmp); -// d.readBlob(10, &bytetmp); -// ui->scopeGUI->deserialize(bytetmp); -// d.readS32(11, &tmp, 20); -// ui->baudRate->setCurrentIndex(tmp); -// d.readBool(12, &m_enableCosineFiltering, false); -// d.readBool(13, &m_syncOrConstellation, false); -// d.readBool(14, &m_slot1On, false); -// d.readBool(15, &m_slot2On, false); -// d.readBool(16, &m_tdmaStereo, false); -// -// this->setWindowTitle(m_channelMarker.getTitle()); -// displayUDPAddress(); -// -// blockApplySettings(false); -// m_channelMarker.blockSignals(false); -// -// updateMyPosition(); // we do it also here to be able to refresh with latest settings -// applySettings(true); -// return true; -// } -// else -// { -// resetToDefaults(); -// return false; -// } } bool DSDDemodGUI::handleMessage(const Message& message __attribute__((unused))) @@ -464,38 +379,6 @@ void DSDDemodGUI::applySettings(bool force) DSDDemod::MsgConfigureDSDDemod* message = DSDDemod::MsgConfigureDSDDemod::create( m_settings, force); m_dsdDemod->getInputMessageQueue()->push(message); - -// ui->deltaFrequency->setValue(m_channelMarker.getCenterFrequency()); -// ui->rfBWText->setText(QString("%1k").arg(ui->rfBW->value() / 10.0, 0, 'f', 1)); -// ui->demodGainText->setText(QString("%1").arg(ui->demodGain->value() / 100.0, 0, 'f', 2)); -// ui->fmDeviationText->setText(QString("%1k").arg(ui->fmDeviation->value() / 10.0, 0, 'f', 1)); -// ui->squelchGateText->setText(QString("%1").arg(ui->squelchGate->value() * 10.0, 0, 'f', 0)); -// ui->volumeText->setText(QString("%1").arg(ui->volume->value() / 10.0, 0, 'f', 1)); -// ui->enableCosineFiltering->setChecked(m_enableCosineFiltering); -// ui->syncOrConstellation->setChecked(m_syncOrConstellation); -// ui->slot1On->setChecked(m_slot1On); -// ui->slot2On->setChecked(m_slot2On); -// ui->tdmaStereoSplit->setChecked(m_tdmaStereo); - -// m_dsdDemod->configure(m_dsdDemod->getInputMessageQueue(), -// m_settings.m_rfBandwidth, -// m_settings.m_fmDeviation, -// m_settings.m_demodGain, -// m_settings.m_volume, -// DSDDemodBaudRates::getRate(ui->baudRate->currentIndex()), -// m_settings.m_squelchGate, // in 10ths of ms -// m_settings.m_squelch, -// m_settings.m_audioMute, -// m_settings.m_enableCosineFiltering, -// m_settings.m_syncOrConstellation, -// m_settings.m_slot1On, -// m_settings.m_slot2On, -// m_settings.m_tdmaStereo, -// m_settings.m_pllLock, -// m_settings.m_udpCopyAudio, -// m_channelMarker.getUDPAddress(), -// m_channelMarker.getUDPSendPort(), -// force); } } diff --git a/plugins/channelrx/demoddsd/dsddemodsettings.cpp b/plugins/channelrx/demoddsd/dsddemodsettings.cpp index 82617adc0..6d409c2b3 100644 --- a/plugins/channelrx/demoddsd/dsddemodsettings.cpp +++ b/plugins/channelrx/demoddsd/dsddemodsettings.cpp @@ -32,13 +32,13 @@ void DSDDemodSettings::resetToDefaults() { m_inputSampleRate = 96000; m_inputFrequencyOffset = 0; - m_rfBandwidth = 10000.0; + m_rfBandwidth = 12500.0; m_fmDeviation = 5000.0; - m_demodGain = 1.0; - m_volume = 1.0; + m_demodGain = 1.25; + m_volume = 2.0; m_baudRate = 4800; m_squelchGate = 5; // 10s of ms at 48000 Hz sample rate. Corresponds to 2400 for AGC attack - m_squelch = -30.0; + m_squelch = -40.0; m_audioMute = false; m_audioSampleRate = DSPEngine::instance()->getAudioSampleRate(); m_enableCosineFiltering = false; @@ -107,11 +107,11 @@ bool DSDDemodSettings::deserialize(const QByteArray& data) d.readS32(1, &tmp, 0); m_inputFrequencyOffset = tmp; - d.readS32(2, &tmp, 4); + d.readS32(2, &tmp, 125); m_rfBandwidth = tmp * 100.0; - d.readS32(3, &tmp, 3); + d.readS32(3, &tmp, 125); m_demodGain = tmp / 100.0; - d.readS32(4, &tmp, 20); + d.readS32(4, &tmp, 50); m_fmDeviation = tmp * 100.0; d.readS32(5, &tmp, -400); m_squelch = tmp / 10.0; From 53daaa5b0c42a8df6cf6dbf3ea77cc47e2f95216 Mon Sep 17 00:00:00 2001 From: f4exb Date: Wed, 4 Oct 2017 00:50:42 +0200 Subject: [PATCH 70/71] Tentative fix for possible lockup of mutex at DSPDevieSourceEngine thread exit --- debian/changelog | 3 ++- sdrbase/dsp/dspdevicesourceengine.cpp | 7 +++++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/debian/changelog b/debian/changelog index be06903b1..1d9b44c88 100644 --- a/debian/changelog +++ b/debian/changelog @@ -2,8 +2,9 @@ sdrangel (3.7.3-1) unstable; urgency=medium * For Airspy, Funcube Pro and Pro+, PlutoSDR Rx and Tx, RTLSDR: * Button and dialog to set frequency translation for transverter operation + * GUI and demod separation step 1 partial - -- Edouard Griffiths, F4EXB Sat, 01 Oct 2017 05:14:18 +0200 + -- Edouard Griffiths, F4EXB Wed, 04 Oct 2017 23:14:18 +0200 sdrangel (3.7.2-1) unstable; urgency=medium diff --git a/sdrbase/dsp/dspdevicesourceengine.cpp b/sdrbase/dsp/dspdevicesourceengine.cpp index ca0b8aed0..14c9d2f75 100644 --- a/sdrbase/dsp/dspdevicesourceengine.cpp +++ b/sdrbase/dsp/dspdevicesourceengine.cpp @@ -73,8 +73,11 @@ void DSPDeviceSourceEngine::start() void DSPDeviceSourceEngine::stop() { qDebug() << "DSPDeviceSourceEngine::stop"; - DSPExit cmd; - m_syncMessenger.sendWait(cmd); + gotoIdle(); + m_state = StNotStarted; + QThread::exit(); +// DSPExit cmd; +// m_syncMessenger.sendWait(cmd); } bool DSPDeviceSourceEngine::initAcquisition() From a30bda2d3a2d0988482deebc5456641456365c48 Mon Sep 17 00:00:00 2001 From: f4exb Date: Wed, 4 Oct 2017 01:20:02 +0200 Subject: [PATCH 71/71] Updated version of touched plugins --- plugins/channelrx/demodam/amdemodplugin.cpp | 2 +- plugins/channelrx/demodatv/atvdemodplugin.cpp | 2 +- plugins/channeltx/modatv/atvmodplugin.cpp | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/plugins/channelrx/demodam/amdemodplugin.cpp b/plugins/channelrx/demodam/amdemodplugin.cpp index 265bd921b..4cb488aff 100644 --- a/plugins/channelrx/demodam/amdemodplugin.cpp +++ b/plugins/channelrx/demodam/amdemodplugin.cpp @@ -7,7 +7,7 @@ const PluginDescriptor AMDemodPlugin::m_pluginDescriptor = { QString("AM Demodulator"), - QString("3.6.1"), + QString("3.7.3"), QString("(c) Edouard Griffiths, F4EXB"), QString("https://github.com/f4exb/sdrangel"), true, diff --git a/plugins/channelrx/demodatv/atvdemodplugin.cpp b/plugins/channelrx/demodatv/atvdemodplugin.cpp index c42bb89d4..745f13921 100644 --- a/plugins/channelrx/demodatv/atvdemodplugin.cpp +++ b/plugins/channelrx/demodatv/atvdemodplugin.cpp @@ -26,7 +26,7 @@ const PluginDescriptor ATVDemodPlugin::m_ptrPluginDescriptor = { QString("ATV Demodulator"), - QString("3.5.0"), + QString("3.7.3"), QString("(c) F4HKW for F4EXB / SDRAngel"), QString("https://github.com/f4exb/sdrangel"), true, diff --git a/plugins/channeltx/modatv/atvmodplugin.cpp b/plugins/channeltx/modatv/atvmodplugin.cpp index 33482b2c0..4fe1e9f68 100644 --- a/plugins/channeltx/modatv/atvmodplugin.cpp +++ b/plugins/channeltx/modatv/atvmodplugin.cpp @@ -23,7 +23,7 @@ const PluginDescriptor ATVModPlugin::m_pluginDescriptor = { QString("ATV Modulator"), - QString("3.5.0"), + QString("3.7.3"), QString("(c) Edouard Griffiths, F4EXB"), QString("https://github.com/f4exb/sdrangel"), true,