diff --git a/.github/workflows/sdrangel.yml b/.github/workflows/sdrangel.yml index ac183aa87..28b653fe9 100644 --- a/.github/workflows/sdrangel.yml +++ b/.github/workflows/sdrangel.yml @@ -6,6 +6,7 @@ on: push: branches: - master + - v7 tags: - 'v*' pull_request: diff --git a/CMakeLists.txt b/CMakeLists.txt index b7c5e02ba..2f0a2fcde 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -14,10 +14,10 @@ set(CMAKE_CXX_EXTENSIONS OFF) set(CMAKE_EXPORT_COMPILE_COMMANDS ON) # configure version -set(sdrangel_VERSION_MAJOR "6") -set(sdrangel_VERSION_MINOR "20") -set(sdrangel_VERSION_PATCH "3") -set(sdrangel_VERSION_SUFFIX "") +set(sdrangel_VERSION_MAJOR "7") +set(sdrangel_VERSION_MINOR "0") +set(sdrangel_VERSION_PATCH "0") +set(sdrangel_VERSION_SUFFIX "alpha.4") # SDRAngel cmake options option(DEBUG_OUTPUT "Print debug messages" OFF) diff --git a/app/main.cpp b/app/main.cpp index 943c2a9b7..045b6e88a 100644 --- a/app/main.cpp +++ b/app/main.cpp @@ -49,20 +49,20 @@ static int runQtApplication(int argc, char* argv[], qtwebapp::LoggerWithFile *lo qApp->setStyle(QStyleFactory::create("fusion")); QPalette palette; - palette.setColor(QPalette::Window, QColor(53,53,53)); + palette.setColor(QPalette::Window, QColor(64,64,64)); palette.setColor(QPalette::WindowText, Qt::white); palette.setColor(QPalette::Base, QColor(25,25,25)); palette.setColor(QPalette::AlternateBase, QColor(53,53,53)); palette.setColor(QPalette::ToolTipBase, Qt::white); palette.setColor(QPalette::ToolTipText, Qt::black); palette.setColor(QPalette::Text, Qt::white); - palette.setColor(QPalette::Button, QColor(0x40, 0x40, 0x40)); + palette.setColor(QPalette::Button, QColor(64,64,64)); palette.setColor(QPalette::ButtonText, Qt::white); palette.setColor(QPalette::BrightText, Qt::red); - palette.setColor(QPalette::Light, QColor(53,53,53).lighter(125).lighter()); - palette.setColor(QPalette::Mid, QColor(53,53,53).lighter(125)); - palette.setColor(QPalette::Dark, QColor(53,53,53).lighter(125).darker()); + palette.setColor(QPalette::Light, QColor(64,64,64).lighter(125).lighter()); + palette.setColor(QPalette::Mid, QColor(64,64,64).lighter(125)); + palette.setColor(QPalette::Dark, QColor(64,64,64).lighter(125).darker()); palette.setColor(QPalette::Link, QColor(0,0xa0,0xa0)); palette.setColor(QPalette::LinkVisited, QColor(0,0xa0,0xa0).lighter()); diff --git a/devices/usrp/deviceusrp.cpp b/devices/usrp/deviceusrp.cpp index 843027958..a0ec4edd9 100644 --- a/devices/usrp/deviceusrp.cpp +++ b/devices/usrp/deviceusrp.cpp @@ -45,8 +45,8 @@ void DeviceUSRP::enumOriginDevices(const QString& hardwareId, PluginInterface::O for(unsigned i = 0; i != dev_addrs.size(); i++) { QString id = QString::fromStdString(dev_addrs[i].to_string()); - QString name = QString::fromStdString(dev_addrs[i].get("name")); - QString serial = QString::fromStdString(dev_addrs[i].get("serial")); + QString name = QString::fromStdString(dev_addrs[i].get("name", "N/A")); + QString serial = QString::fromStdString(dev_addrs[i].get("serial", "N/A")); QString displayedName(QString("%1[%2:$1] %3").arg(name).arg(i).arg(serial)); qDebug() << "DeviceUSRP::enumOriginDevices: found USRP device " << displayedName; diff --git a/doc/img/BasicChannelSettings.png b/doc/img/BasicChannelSettings.png index ec2065606..99c2c01d3 100644 Binary files a/doc/img/BasicChannelSettings.png and b/doc/img/BasicChannelSettings.png differ diff --git a/doc/img/BasicChannelSettings.xcf b/doc/img/BasicChannelSettings.xcf index 5fafecc35..a68769e83 100644 Binary files a/doc/img/BasicChannelSettings.xcf and b/doc/img/BasicChannelSettings.xcf differ diff --git a/doc/img/BeamsteeringCWMod_plugin.png b/doc/img/BeamsteeringCWMod_plugin.png index 0a0dead8c..56c30be23 100644 Binary files a/doc/img/BeamsteeringCWMod_plugin.png and b/doc/img/BeamsteeringCWMod_plugin.png differ diff --git a/doc/img/BeamsteeringCWMod_plugin.xcf b/doc/img/BeamsteeringCWMod_plugin.xcf index beb80beb8..dbe0728d3 100644 Binary files a/doc/img/BeamsteeringCWMod_plugin.xcf and b/doc/img/BeamsteeringCWMod_plugin.xcf differ diff --git a/doc/img/ChannelWindow.png b/doc/img/ChannelWindow.png new file mode 100644 index 000000000..c08a109d0 Binary files /dev/null and b/doc/img/ChannelWindow.png differ diff --git a/doc/img/ChannelWindow.xcf b/doc/img/ChannelWindow.xcf new file mode 100644 index 000000000..e0f63eaef Binary files /dev/null and b/doc/img/ChannelWindow.xcf differ diff --git a/doc/img/ChannelWindow_bottom.png b/doc/img/ChannelWindow_bottom.png new file mode 100644 index 000000000..81953046d Binary files /dev/null and b/doc/img/ChannelWindow_bottom.png differ diff --git a/doc/img/ChannelWindow_bottom.xcf b/doc/img/ChannelWindow_bottom.xcf new file mode 100644 index 000000000..09d2acbd8 Binary files /dev/null and b/doc/img/ChannelWindow_bottom.xcf differ diff --git a/doc/img/ChannelWindow_top.png b/doc/img/ChannelWindow_top.png new file mode 100644 index 000000000..aeee32ccc Binary files /dev/null and b/doc/img/ChannelWindow_top.png differ diff --git a/doc/img/ChannelWindow_top.xcf b/doc/img/ChannelWindow_top.xcf new file mode 100644 index 000000000..2074ca6bb Binary files /dev/null and b/doc/img/ChannelWindow_top.xcf differ diff --git a/doc/img/Configurations.png b/doc/img/Configurations.png new file mode 100644 index 000000000..e56c54430 Binary files /dev/null and b/doc/img/Configurations.png differ diff --git a/doc/img/Configurations.xcf b/doc/img/Configurations.xcf new file mode 100644 index 000000000..c3fbab3ad Binary files /dev/null and b/doc/img/Configurations.xcf differ diff --git a/doc/img/DeviceWindow.png b/doc/img/DeviceWindow.png new file mode 100644 index 000000000..8b83351df Binary files /dev/null and b/doc/img/DeviceWindow.png differ diff --git a/doc/img/DeviceWindow.xcf b/doc/img/DeviceWindow.xcf new file mode 100644 index 000000000..8177ac32d Binary files /dev/null and b/doc/img/DeviceWindow.xcf differ diff --git a/doc/img/DeviceWindow_bottom.png b/doc/img/DeviceWindow_bottom.png new file mode 100644 index 000000000..e6a398588 Binary files /dev/null and b/doc/img/DeviceWindow_bottom.png differ diff --git a/doc/img/DeviceWindow_bottom.xcf b/doc/img/DeviceWindow_bottom.xcf new file mode 100644 index 000000000..7f5e5fd38 Binary files /dev/null and b/doc/img/DeviceWindow_bottom.xcf differ diff --git a/doc/img/DeviceWindow_top.png b/doc/img/DeviceWindow_top.png new file mode 100644 index 000000000..7a6dfa4bf Binary files /dev/null and b/doc/img/DeviceWindow_top.png differ diff --git a/doc/img/DeviceWindow_top.xcf b/doc/img/DeviceWindow_top.xcf new file mode 100644 index 000000000..b183dce7a Binary files /dev/null and b/doc/img/DeviceWindow_top.xcf differ diff --git a/doc/img/FeatureWindow.png b/doc/img/FeatureWindow.png new file mode 100644 index 000000000..d6733cddb Binary files /dev/null and b/doc/img/FeatureWindow.png differ diff --git a/doc/img/FeatureWindow.xcf b/doc/img/FeatureWindow.xcf new file mode 100644 index 000000000..2b9af2048 Binary files /dev/null and b/doc/img/FeatureWindow.xcf differ diff --git a/doc/img/Features_basic_dialog.png b/doc/img/Features_basic_dialog.png index be775266a..4a12b9a81 100644 Binary files a/doc/img/Features_basic_dialog.png and b/doc/img/Features_basic_dialog.png differ diff --git a/doc/img/Features_basic_dialog.xcf b/doc/img/Features_basic_dialog.xcf index 242511197..7bfd91340 100644 Binary files a/doc/img/Features_basic_dialog.xcf and b/doc/img/Features_basic_dialog.xcf differ diff --git a/doc/img/MainSpectrum.png b/doc/img/MainSpectrum.png new file mode 100644 index 000000000..75533ecf9 Binary files /dev/null and b/doc/img/MainSpectrum.png differ diff --git a/doc/img/MainSpectrum.xcf b/doc/img/MainSpectrum.xcf new file mode 100644 index 000000000..e856b9748 Binary files /dev/null and b/doc/img/MainSpectrum.xcf differ diff --git a/doc/img/MainWindow.png b/doc/img/MainWindow.png new file mode 100644 index 000000000..cac8a5e99 Binary files /dev/null and b/doc/img/MainWindow.png differ diff --git a/doc/img/MainWindow_presets.png b/doc/img/MainWindow_presets.png index 31791a730..f6e1b7096 100644 Binary files a/doc/img/MainWindow_presets.png and b/doc/img/MainWindow_presets.png differ diff --git a/doc/img/MainWindow_presets.xcf b/doc/img/MainWindow_presets.xcf index ace00b859..51008e7cc 100644 Binary files a/doc/img/MainWindow_presets.xcf and b/doc/img/MainWindow_presets.xcf differ diff --git a/doc/img/MainWindow_presets_view.png b/doc/img/MainWindow_presets_view.png index ee48e7bb8..6fece5e25 100644 Binary files a/doc/img/MainWindow_presets_view.png and b/doc/img/MainWindow_presets_view.png differ diff --git a/doc/img/MainWindow_presets_view.xcf b/doc/img/MainWindow_presets_view.xcf index 11ba24eba..802ba0869 100644 Binary files a/doc/img/MainWindow_presets_view.xcf and b/doc/img/MainWindow_presets_view.xcf differ diff --git a/doc/img/MainWindow_spectrum_gui.png b/doc/img/MainWindow_spectrum_gui.png index f55f68dff..274c9e8fb 100644 Binary files a/doc/img/MainWindow_spectrum_gui.png and b/doc/img/MainWindow_spectrum_gui.png differ diff --git a/doc/img/MainWindow_spectrum_gui.xcf b/doc/img/MainWindow_spectrum_gui.xcf index 58bb3a34a..b3a130d2b 100644 Binary files a/doc/img/MainWindow_spectrum_gui.xcf and b/doc/img/MainWindow_spectrum_gui.xcf differ diff --git a/doc/img/MainWindow_spectrum_gui_A.png b/doc/img/MainWindow_spectrum_gui_A.png index aa3ed9bfe..82c25a13a 100644 Binary files a/doc/img/MainWindow_spectrum_gui_A.png and b/doc/img/MainWindow_spectrum_gui_A.png differ diff --git a/doc/img/MainWindow_spectrum_gui_A.xcf b/doc/img/MainWindow_spectrum_gui_A.xcf index 6740c18ad..71a93fea2 100644 Binary files a/doc/img/MainWindow_spectrum_gui_A.xcf and b/doc/img/MainWindow_spectrum_gui_A.xcf differ diff --git a/doc/img/MainWindow_spectrum_gui_B.png b/doc/img/MainWindow_spectrum_gui_B.png index c76bd3902..6486f2f9d 100644 Binary files a/doc/img/MainWindow_spectrum_gui_B.png and b/doc/img/MainWindow_spectrum_gui_B.png differ diff --git a/doc/img/MainWindow_spectrum_gui_B.xcf b/doc/img/MainWindow_spectrum_gui_B.xcf index cb7e2e2c8..42f30055a 100644 Binary files a/doc/img/MainWindow_spectrum_gui_B.xcf and b/doc/img/MainWindow_spectrum_gui_B.xcf differ diff --git a/doc/img/MainWindow_spectrum_gui_D.png b/doc/img/MainWindow_spectrum_gui_D.png new file mode 100644 index 000000000..a3cb42df0 Binary files /dev/null and b/doc/img/MainWindow_spectrum_gui_D.png differ diff --git a/doc/img/MainWindow_spectrum_gui_D.xcf b/doc/img/MainWindow_spectrum_gui_D.xcf new file mode 100644 index 000000000..865af983a Binary files /dev/null and b/doc/img/MainWindow_spectrum_gui_D.xcf differ diff --git a/doc/img/MainWindow_spectrum_gui_narrow.png b/doc/img/MainWindow_spectrum_gui_narrow.png new file mode 100644 index 000000000..d441c209e Binary files /dev/null and b/doc/img/MainWindow_spectrum_gui_narrow.png differ diff --git a/doc/img/MainWindow_spectrum_gui_wide.png b/doc/img/MainWindow_spectrum_gui_wide.png new file mode 100644 index 000000000..2e5ac34fd Binary files /dev/null and b/doc/img/MainWindow_spectrum_gui_wide.png differ diff --git a/doc/img/VORLocalizer_plugin.png b/doc/img/VORLocalizer_plugin.png index 319c42aab..e80750b7d 100644 Binary files a/doc/img/VORLocalizer_plugin.png and b/doc/img/VORLocalizer_plugin.png differ diff --git a/doc/img/VORLocalizer_plugin.xcf b/doc/img/VORLocalizer_plugin.xcf index 930e0cdc9..a0927b554 100644 Binary files a/doc/img/VORLocalizer_plugin.xcf and b/doc/img/VORLocalizer_plugin.xcf differ diff --git a/doc/img/VORLocalizer_settings.png b/doc/img/VORLocalizer_settings.png index 8f57cf452..5630fbd16 100644 Binary files a/doc/img/VORLocalizer_settings.png and b/doc/img/VORLocalizer_settings.png differ diff --git a/doc/img/VORLocalizer_settings.xcf b/doc/img/VORLocalizer_settings.xcf index b62d8525d..ce1bd733f 100644 Binary files a/doc/img/VORLocalizer_settings.xcf and b/doc/img/VORLocalizer_settings.xcf differ diff --git a/doc/img/Workspace_create_feature.png b/doc/img/Workspace_create_feature.png new file mode 100644 index 000000000..3a40e8c1a Binary files /dev/null and b/doc/img/Workspace_create_feature.png differ diff --git a/doc/img/Workspace_create_rx.png b/doc/img/Workspace_create_rx.png new file mode 100644 index 000000000..168689e77 Binary files /dev/null and b/doc/img/Workspace_create_rx.png differ diff --git a/doc/img/Workspace_top.png b/doc/img/Workspace_top.png new file mode 100644 index 000000000..3b3e823e0 Binary files /dev/null and b/doc/img/Workspace_top.png differ diff --git a/doc/img/Workspace_top.xcf b/doc/img/Workspace_top.xcf new file mode 100644 index 000000000..126038b6a Binary files /dev/null and b/doc/img/Workspace_top.xcf differ diff --git a/doc/img/Workspaces.png b/doc/img/Workspaces.png new file mode 100644 index 000000000..a796693e1 Binary files /dev/null and b/doc/img/Workspaces.png differ diff --git a/doc/img/Workspaces.xcf b/doc/img/Workspaces.xcf new file mode 100644 index 000000000..eb17155fb Binary files /dev/null and b/doc/img/Workspaces.xcf differ diff --git a/doc/img/channel.xcf b/doc/img/channel.xcf new file mode 100644 index 000000000..61cbff543 Binary files /dev/null and b/doc/img/channel.xcf differ diff --git a/doc/img/corner.xcf b/doc/img/corner.xcf new file mode 100644 index 000000000..1fb705730 Binary files /dev/null and b/doc/img/corner.xcf differ diff --git a/doc/img/cross.xcf b/doc/img/cross.xcf new file mode 100644 index 000000000..7c64325c5 Binary files /dev/null and b/doc/img/cross.xcf differ diff --git a/doc/img/dock.xcf b/doc/img/dock.xcf new file mode 100644 index 000000000..b7bd5f1d1 Binary files /dev/null and b/doc/img/dock.xcf differ diff --git a/doc/img/exit.xcf b/doc/img/exit.xcf new file mode 100644 index 000000000..711f58188 Binary files /dev/null and b/doc/img/exit.xcf differ diff --git a/doc/img/exit_round.xcf b/doc/img/exit_round.xcf new file mode 100644 index 000000000..46ddba6e9 Binary files /dev/null and b/doc/img/exit_round.xcf differ diff --git a/doc/img/gear.xcf b/doc/img/gear.xcf new file mode 100644 index 000000000..f0b589179 Binary files /dev/null and b/doc/img/gear.xcf differ diff --git a/doc/img/help.xcf b/doc/img/help.xcf new file mode 100644 index 000000000..ddb3d0411 Binary files /dev/null and b/doc/img/help.xcf differ diff --git a/doc/img/hide.xcf b/doc/img/hide.xcf new file mode 100644 index 000000000..022857dd4 Binary files /dev/null and b/doc/img/hide.xcf differ diff --git a/doc/img/mimo.xcf b/doc/img/mimo.xcf new file mode 100644 index 000000000..d3c4e98c9 Binary files /dev/null and b/doc/img/mimo.xcf differ diff --git a/doc/img/rxtx.xcf b/doc/img/rxtx.xcf new file mode 100644 index 000000000..d1cb79a4d Binary files /dev/null and b/doc/img/rxtx.xcf differ diff --git a/doc/img/shrink.xcf b/doc/img/shrink.xcf new file mode 100644 index 000000000..c77dfa390 Binary files /dev/null and b/doc/img/shrink.xcf differ diff --git a/doc/img/tiles.xcf b/doc/img/tiles.xcf new file mode 100644 index 000000000..7bc7066a3 Binary files /dev/null and b/doc/img/tiles.xcf differ diff --git a/doc/img/tool.xcf b/doc/img/tool.xcf new file mode 100644 index 000000000..5d181b4c1 Binary files /dev/null and b/doc/img/tool.xcf differ diff --git a/plugins/channelmimo/beamsteeringcwmod/beamsteeringcwmod.cpp b/plugins/channelmimo/beamsteeringcwmod/beamsteeringcwmod.cpp index cd21f50b5..2915538d2 100644 --- a/plugins/channelmimo/beamsteeringcwmod/beamsteeringcwmod.cpp +++ b/plugins/channelmimo/beamsteeringcwmod/beamsteeringcwmod.cpp @@ -22,6 +22,7 @@ #include #include "SWGChannelSettings.h" +#include "SWGWorkspaceInfo.h" #include "device/deviceapi.h" #include "dsp/hbfilterchainconverter.h" @@ -80,6 +81,18 @@ BeamSteeringCWMod::~BeamSteeringCWMod() delete m_thread; } +void BeamSteeringCWMod::setDeviceAPI(DeviceAPI *deviceAPI) +{ + if (deviceAPI != m_deviceAPI) + { + m_deviceAPI->removeChannelSinkAPI(this); + m_deviceAPI->removeMIMOChannel(this); + m_deviceAPI = deviceAPI; + m_deviceAPI->addMIMOChannel(this); + m_deviceAPI->addChannelSinkAPI(this); + } +} + void BeamSteeringCWMod::startSources() { qDebug("BeamSteeringCWMod::startSources"); @@ -271,6 +284,15 @@ int BeamSteeringCWMod::webapiSettingsGet( return 200; } +int BeamSteeringCWMod::webapiWorkspaceGet( + SWGSDRangel::SWGWorkspaceInfo& response, + QString& errorMessage) +{ + (void) errorMessage; + response.setIndex(m_settings.m_workspaceIndex); + return 200; +} + int BeamSteeringCWMod::webapiSettingsPutPatch( bool force, const QStringList& channelSettingsKeys, diff --git a/plugins/channelmimo/beamsteeringcwmod/beamsteeringcwmod.h b/plugins/channelmimo/beamsteeringcwmod/beamsteeringcwmod.h index 04f56beeb..90979c5c0 100644 --- a/plugins/channelmimo/beamsteeringcwmod/beamsteeringcwmod.h +++ b/plugins/channelmimo/beamsteeringcwmod/beamsteeringcwmod.h @@ -88,8 +88,10 @@ public: BeamSteeringCWMod(DeviceAPI *deviceAPI); virtual ~BeamSteeringCWMod(); virtual void destroy() { delete this; } + virtual void setDeviceAPI(DeviceAPI *deviceAPI); + virtual DeviceAPI *getDeviceAPI() { return m_deviceAPI; } - virtual void startSinks() {} + virtual void startSinks() {} virtual void stopSinks() {} virtual void startSources(); //!< thread start() virtual void stopSources(); //!< thread exit() and wait() @@ -132,6 +134,10 @@ public: SWGSDRangel::SWGChannelSettings& response, QString& errorMessage); + virtual int webapiWorkspaceGet( + SWGSDRangel::SWGWorkspaceInfo& query, + QString& errorMessage); + static void webapiFormatChannelSettings( SWGSDRangel::SWGChannelSettings& response, const BeamSteeringCWModSettings& settings); diff --git a/plugins/channelmimo/beamsteeringcwmod/beamsteeringcwmodgui.cpp b/plugins/channelmimo/beamsteeringcwmod/beamsteeringcwmodgui.cpp index bcf3afc0b..f54ec2100 100644 --- a/plugins/channelmimo/beamsteeringcwmod/beamsteeringcwmodgui.cpp +++ b/plugins/channelmimo/beamsteeringcwmod/beamsteeringcwmodgui.cpp @@ -16,6 +16,7 @@ /////////////////////////////////////////////////////////////////////////////////// #include +#include #include "device/deviceuiset.h" #include "gui/basicchannelsettingsdialog.h" @@ -61,6 +62,14 @@ bool BeamSteeringCWModGUI::deserialize(const QByteArray& data) } } +void BeamSteeringCWModGUI::resizeEvent(QResizeEvent* size) +{ + int maxWidth = getRollupContents()->maximumWidth(); + int minHeight = getRollupContents()->minimumHeight() + getAdditionalHeight(); + resize(width() < maxWidth ? width() : maxWidth, minHeight); + size->accept(); +} + bool BeamSteeringCWModGUI::handleMessage(const Message& message) { if (BeamSteeringCWMod::MsgBasebandNotification::match(message)) @@ -96,11 +105,13 @@ BeamSteeringCWModGUI::BeamSteeringCWModGUI(PluginAPI* pluginAPI, DeviceUISet *de m_centerFrequency(435000000), m_tickCount(0) { - ui->setupUi(this); setAttribute(Qt::WA_DeleteOnClose, true); - setStreamIndicator("M"); - - connect(this, SIGNAL(widgetRolled(QWidget*,bool)), this, SLOT(onWidgetRolled(QWidget*,bool))); + m_helpURL = "plugins/channelmimo/beamSteeringcwmod/readme.md"; + RollupContents *rollupContents = getRollupContents(); + ui->setupUi(rollupContents); + setSizePolicy(rollupContents->sizePolicy()); + rollupContents->arrangeRollups(); + connect(rollupContents, SIGNAL(widgetRolled(QWidget*,bool)), this, SLOT(onWidgetRolled(QWidget*,bool))); connect(this, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(onMenuDialogCalled(const QPoint &))); m_bsCWSource = (BeamSteeringCWMod*) mimoChannel; @@ -113,7 +124,7 @@ BeamSteeringCWModGUI::BeamSteeringCWModGUI(PluginAPI* pluginAPI, DeviceUISet *de m_channelMarker.addStreamIndex(1); m_channelMarker.setColor(m_settings.m_rgbColor); m_channelMarker.setCenterFrequency(0); - m_channelMarker.setTitle("Beam Steering CW Source"); + m_channelMarker.setTitle("BeamSteeringCWMod"); m_channelMarker.setSourceOrSinkStream(false); m_channelMarker.blockSignals(false); m_channelMarker.setVisible(true); // activate signal on the last setting only @@ -122,11 +133,11 @@ BeamSteeringCWModGUI::BeamSteeringCWModGUI(PluginAPI* pluginAPI, DeviceUISet *de m_settings.setRollupState(&m_rollupState); m_deviceUISet->addChannelMarker(&m_channelMarker); - m_deviceUISet->addRollupWidget(this); connect(getInputMessageQueue(), SIGNAL(messageEnqueued()), this, SLOT(handleSourceMessages())); displaySettings(); + makeUIConnections(); displayRateAndShift(); applySettings(true); } @@ -164,12 +175,13 @@ void BeamSteeringCWModGUI::displaySettings() setTitleColor(m_settings.m_rgbColor); setWindowTitle(m_channelMarker.getTitle()); + setTitle(m_channelMarker.getTitle()); blockApplySettings(true); ui->interpolationFactor->setCurrentIndex(m_settings.m_log2Interp); applyInterpolation(); ui->steeringDegreesText->setText(tr("%1").arg(m_settings.m_steerDegrees)); - restoreState(m_rollupState); + getRollupContents()->restoreState(m_rollupState); blockApplySettings(false); } @@ -212,7 +224,7 @@ void BeamSteeringCWModGUI::onWidgetRolled(QWidget* widget, bool rollDown) (void) widget; (void) rollDown; - saveState(m_rollupState); + getRollupContents()->saveState(m_rollupState); applySettings(); } @@ -226,6 +238,7 @@ void BeamSteeringCWModGUI::onMenuDialogCalled(const QPoint &p) dialog.setReverseAPIPort(m_settings.m_reverseAPIPort); dialog.setReverseAPIDeviceIndex(m_settings.m_reverseAPIDeviceIndex); dialog.setReverseAPIChannelIndex(m_settings.m_reverseAPIChannelIndex); + dialog.setDefaultTitle(m_displayedName); dialog.move(p); dialog.exec(); @@ -239,6 +252,7 @@ void BeamSteeringCWModGUI::onMenuDialogCalled(const QPoint &p) m_settings.m_reverseAPIChannelIndex = dialog.getReverseAPIChannelIndex(); setWindowTitle(m_settings.m_title); + setTitle(m_channelMarker.getTitle()); setTitleColor(m_settings.m_rgbColor); applySettings(); @@ -303,3 +317,11 @@ void BeamSteeringCWModGUI::tick() m_tickCount = 0; } } + +void BeamSteeringCWModGUI::makeUIConnections() +{ + QObject::connect(ui->channelOutput, QOverload::of(&QComboBox::currentIndexChanged), this, &BeamSteeringCWModGUI::on_channelOutput_currentIndexChanged); + QObject::connect(ui->interpolationFactor, QOverload::of(&QComboBox::currentIndexChanged), this, &BeamSteeringCWModGUI::on_interpolationFactor_currentIndexChanged); + QObject::connect(ui->position, &QSlider::valueChanged, this, &BeamSteeringCWModGUI::on_position_valueChanged); + QObject::connect(ui->steeringDegrees, &QSlider::valueChanged, this, &BeamSteeringCWModGUI::on_steeringDegrees_valueChanged); +} diff --git a/plugins/channelmimo/beamsteeringcwmod/beamsteeringcwmodgui.h b/plugins/channelmimo/beamsteeringcwmod/beamsteeringcwmodgui.h index 8e5eaef05..b515573b1 100644 --- a/plugins/channelmimo/beamsteeringcwmod/beamsteeringcwmodgui.h +++ b/plugins/channelmimo/beamsteeringcwmod/beamsteeringcwmodgui.h @@ -48,6 +48,17 @@ public: QByteArray serialize() const; bool deserialize(const QByteArray& data); virtual MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; } + virtual void setWorkspaceIndex(int index) { m_settings.m_workspaceIndex = index; }; + virtual int getWorkspaceIndex() const { return m_settings.m_workspaceIndex; }; + virtual void setGeometryBytes(const QByteArray& blob) { m_settings.m_geometryBytes = blob; }; + virtual QByteArray getGeometryBytes() const { return m_settings.m_geometryBytes; }; + virtual QString getTitle() const { return m_settings.m_title; }; + virtual QColor getTitleColor() const { return m_settings.m_rgbColor; }; + virtual void zetHidden(bool hidden) { m_settings.m_hidden = hidden; } + virtual bool getHidden() const { return m_settings.m_hidden; } + virtual ChannelMarker& getChannelMarker() { return m_channelMarker; } + virtual int getStreamIndex() const { return -1; } + virtual void setStreamIndex(int streamIndex) { (void) streamIndex; } private: Ui::BeamSteeringCWModGUI* ui; @@ -74,6 +85,7 @@ private: void displaySettings(); void displayRateAndShift(); bool handleMessage(const Message& message); + void makeUIConnections(); void leaveEvent(QEvent*); void enterEvent(QEvent*); @@ -81,6 +93,9 @@ private: void applyInterpolation(); void applyPosition(); +protected: + void resizeEvent(QResizeEvent* size); + private slots: void handleSourceMessages(); void on_channelOutput_currentIndexChanged(int index); diff --git a/plugins/channelmimo/beamsteeringcwmod/beamsteeringcwmodgui.ui b/plugins/channelmimo/beamsteeringcwmod/beamsteeringcwmodgui.ui index ec970d077..4872d6abb 100644 --- a/plugins/channelmimo/beamsteeringcwmod/beamsteeringcwmodgui.ui +++ b/plugins/channelmimo/beamsteeringcwmod/beamsteeringcwmodgui.ui @@ -1,13 +1,13 @@ BeamSteeringCWModGUI - + 0 0 - 320 - 102 + 360 + 100 @@ -18,16 +18,10 @@ - 320 + 360 100 - - - 320 - 16777215 - - Liberation Sans @@ -40,12 +34,24 @@ - 10 - 10 - 301 + 0 + 0 + 358 91 + + + 0 + 0 + + + + + 358 + 0 + + Settings @@ -326,9 +332,9 @@ - RollupWidget + RollupContents QWidget -
gui/rollupwidget.h
+
gui/rollupcontents.h
1
diff --git a/plugins/channelmimo/beamsteeringcwmod/beamsteeringcwmodsettings.cpp b/plugins/channelmimo/beamsteeringcwmod/beamsteeringcwmodsettings.cpp index 95df8dab7..fccedcc43 100644 --- a/plugins/channelmimo/beamsteeringcwmod/beamsteeringcwmodsettings.cpp +++ b/plugins/channelmimo/beamsteeringcwmod/beamsteeringcwmodsettings.cpp @@ -43,6 +43,8 @@ void BeamSteeringCWModSettings::resetToDefaults() m_reverseAPIPort = 8888; m_reverseAPIDeviceIndex = 0; m_reverseAPIChannelIndex = 0; + m_workspaceIndex = 0; + m_hidden = false; } QByteArray BeamSteeringCWModSettings::serialize() const @@ -64,6 +66,10 @@ QByteArray BeamSteeringCWModSettings::serialize() const s.writeBlob(15, m_rollupState->serialize()); } + s.writeS32(16, m_workspaceIndex); + s.writeBlob(17, m_geometryBytes); + s.writeBool(18, m_hidden); + return s.final(); } @@ -114,6 +120,10 @@ bool BeamSteeringCWModSettings::deserialize(const QByteArray& data) m_rollupState->deserialize(bytetmp); } + d.readS32(16, &m_workspaceIndex); + d.readBlob(17, &m_geometryBytes); + d.readBool(18, &m_hidden, false); + return true; } else diff --git a/plugins/channelmimo/beamsteeringcwmod/beamsteeringcwmodsettings.h b/plugins/channelmimo/beamsteeringcwmod/beamsteeringcwmodsettings.h index cdac05bea..bb64cb1a2 100644 --- a/plugins/channelmimo/beamsteeringcwmod/beamsteeringcwmodsettings.h +++ b/plugins/channelmimo/beamsteeringcwmod/beamsteeringcwmodsettings.h @@ -36,6 +36,9 @@ struct BeamSteeringCWModSettings uint16_t m_reverseAPIPort; uint16_t m_reverseAPIDeviceIndex; uint16_t m_reverseAPIChannelIndex; + int m_workspaceIndex; + QByteArray m_geometryBytes; + bool m_hidden; Serializable *m_channelMarker; Serializable *m_rollupState; diff --git a/plugins/channelmimo/beamsteeringcwmod/readme.md b/plugins/channelmimo/beamsteeringcwmod/readme.md index ea14d33b3..076525109 100644 --- a/plugins/channelmimo/beamsteeringcwmod/readme.md +++ b/plugins/channelmimo/beamsteeringcwmod/readme.md @@ -8,6 +8,8 @@ This MIMO transmission only (MO) plugin can be used to drive a 2 channel MO devi

Interface

+The top and bottom bars of the channel window are described [here](../../../sdrgui/channel/readme.md) + ![Beam steering CW plugin GUI](../../../doc/img/BeamsteeringCWMod_plugin.png)

1: Channel output

diff --git a/plugins/channelmimo/interferometer/interferometer.cpp b/plugins/channelmimo/interferometer/interferometer.cpp index 17e06f543..82b1ca41a 100644 --- a/plugins/channelmimo/interferometer/interferometer.cpp +++ b/plugins/channelmimo/interferometer/interferometer.cpp @@ -22,6 +22,7 @@ #include #include "SWGChannelSettings.h" +#include "SWGWorkspaceInfo.h" #include "device/deviceapi.h" #include "dsp/hbfilterchainconverter.h" @@ -82,6 +83,18 @@ Interferometer::~Interferometer() delete m_thread; } +void Interferometer::setDeviceAPI(DeviceAPI *deviceAPI) +{ + if (deviceAPI != m_deviceAPI) + { + m_deviceAPI->removeChannelSinkAPI(this); + m_deviceAPI->removeMIMOChannel(this); + m_deviceAPI = deviceAPI; + m_deviceAPI->addMIMOChannel(this); + m_deviceAPI->addChannelSinkAPI(this); + } +} + void Interferometer::startSinks() { if (m_deviceSampleRate != 0) { @@ -293,6 +306,15 @@ int Interferometer::webapiSettingsGet( return 200; } +int Interferometer::webapiWorkspaceGet( + SWGSDRangel::SWGWorkspaceInfo& response, + QString& errorMessage) +{ + (void) errorMessage; + response.setIndex(m_settings.m_workspaceIndex); + return 200; +} + int Interferometer::webapiSettingsPutPatch( bool force, const QStringList& channelSettingsKeys, diff --git a/plugins/channelmimo/interferometer/interferometer.h b/plugins/channelmimo/interferometer/interferometer.h index 9cb6b8118..a6444f397 100644 --- a/plugins/channelmimo/interferometer/interferometer.h +++ b/plugins/channelmimo/interferometer/interferometer.h @@ -88,6 +88,8 @@ public: Interferometer(DeviceAPI *deviceAPI); virtual ~Interferometer(); virtual void destroy() { delete this; } + virtual void setDeviceAPI(DeviceAPI *deviceAPI); + virtual DeviceAPI *getDeviceAPI() { return m_deviceAPI; } virtual void startSinks(); //!< thread start() virtual void stopSinks(); //!< thread exit() and wait() @@ -136,6 +138,10 @@ public: SWGSDRangel::SWGChannelSettings& response, QString& errorMessage); + virtual int webapiWorkspaceGet( + SWGSDRangel::SWGWorkspaceInfo& query, + QString& errorMessage); + static void webapiFormatChannelSettings( SWGSDRangel::SWGChannelSettings& response, const InterferometerSettings& settings); diff --git a/plugins/channelmimo/interferometer/interferometergui.cpp b/plugins/channelmimo/interferometer/interferometergui.cpp index 4930a24e9..d97dfb80d 100644 --- a/plugins/channelmimo/interferometer/interferometergui.cpp +++ b/plugins/channelmimo/interferometer/interferometergui.cpp @@ -106,11 +106,13 @@ InterferometerGUI::InterferometerGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUI m_centerFrequency(435000000), m_tickCount(0) { - ui->setupUi(this); setAttribute(Qt::WA_DeleteOnClose, true); - setStreamIndicator("M"); - - connect(this, SIGNAL(widgetRolled(QWidget*,bool)), this, SLOT(onWidgetRolled(QWidget*,bool))); + m_helpURL = "plugins/channelmimo/interferometer/readme.md"; + RollupContents *rollupContents = getRollupContents(); + ui->setupUi(rollupContents); + setSizePolicy(rollupContents->sizePolicy()); + rollupContents->arrangeRollups(); + connect(rollupContents, SIGNAL(widgetRolled(QWidget*,bool)), this, SLOT(onWidgetRolled(QWidget*,bool))); connect(this, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(onMenuDialogCalled(const QPoint &))); m_interferometer = (Interferometer*) channelMIMO; @@ -146,7 +148,6 @@ InterferometerGUI::InterferometerGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUI m_settings.setSpectrumGUI(ui->spectrumGUI); m_deviceUISet->addChannelMarker(&m_channelMarker); - m_deviceUISet->addRollupWidget(this); ui->spectrumGUI->setBuddies(m_spectrumVis, ui->glSpectrum); ui->scopeGUI->setBuddies(m_scopeVis->getInputMessageQueue(), m_scopeVis, ui->glScope); @@ -157,6 +158,7 @@ InterferometerGUI::InterferometerGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUI connect(getInputMessageQueue(), SIGNAL(messageEnqueued()), this, SLOT(handleSourceMessages())); displaySettings(); + makeUIConnections(); displayRateAndShift(); applySettings(true); } @@ -196,13 +198,14 @@ void InterferometerGUI::displaySettings() setTitleColor(m_settings.m_rgbColor); setWindowTitle(m_channelMarker.getTitle()); + setTitle(m_channelMarker.getTitle()); blockApplySettings(true); ui->decimationFactor->setCurrentIndex(m_settings.m_log2Decim); applyDecimation(); ui->phaseCorrection->setValue(m_settings.m_phase); ui->phaseCorrectionText->setText(tr("%1").arg(m_settings.m_phase)); - restoreState(m_rollupState); + getRollupContents()->restoreState(m_rollupState); blockApplySettings(false); } @@ -247,7 +250,18 @@ void InterferometerGUI::onWidgetRolled(QWidget* widget, bool rollDown) (void) widget; (void) rollDown; - saveState(m_rollupState); + RollupContents *rollupContents = getRollupContents(); + + if (rollupContents->hasExpandableWidgets()) { + setSizePolicy(sizePolicy().horizontalPolicy(), QSizePolicy::Expanding); + } else { + setSizePolicy(sizePolicy().horizontalPolicy(), QSizePolicy::Fixed); + } + + int h = rollupContents->height() + getAdditionalHeight(); + resize(width(), h); + + rollupContents->saveState(m_rollupState); applySettings(); } @@ -261,6 +275,7 @@ void InterferometerGUI::onMenuDialogCalled(const QPoint &p) dialog.setReverseAPIPort(m_settings.m_reverseAPIPort); dialog.setReverseAPIDeviceIndex(m_settings.m_reverseAPIDeviceIndex); dialog.setReverseAPIChannelIndex(m_settings.m_reverseAPIChannelIndex); + dialog.setDefaultTitle(m_displayedName); dialog.move(p); dialog.exec(); @@ -274,6 +289,7 @@ void InterferometerGUI::onMenuDialogCalled(const QPoint &p) m_settings.m_reverseAPIChannelIndex = dialog.getReverseAPIChannelIndex(); setWindowTitle(m_settings.m_title); + setTitle(m_channelMarker.getTitle()); setTitleColor(m_settings.m_rgbColor); applySettings(); @@ -338,3 +354,11 @@ void InterferometerGUI::tick() m_tickCount = 0; } } + +void InterferometerGUI::makeUIConnections() +{ + QObject::connect(ui->decimationFactor, QOverload::of(&QComboBox::currentIndexChanged), this, &InterferometerGUI::on_decimationFactor_currentIndexChanged); + QObject::connect(ui->position, &QSlider::valueChanged, this, &InterferometerGUI::on_position_valueChanged); + QObject::connect(ui->phaseCorrection, &QSlider::valueChanged, this, &InterferometerGUI::on_phaseCorrection_valueChanged); + QObject::connect(ui->correlationType, QOverload::of(&QComboBox::currentIndexChanged), this, &InterferometerGUI::on_correlationType_currentIndexChanged); +} diff --git a/plugins/channelmimo/interferometer/interferometergui.h b/plugins/channelmimo/interferometer/interferometergui.h index 97a4a2b3f..b4b2d6fa2 100644 --- a/plugins/channelmimo/interferometer/interferometergui.h +++ b/plugins/channelmimo/interferometer/interferometergui.h @@ -47,6 +47,17 @@ public: virtual QByteArray serialize() const; virtual bool deserialize(const QByteArray& data); virtual MessageQueue* getInputMessageQueue(); + virtual void setWorkspaceIndex(int index) { m_settings.m_workspaceIndex = index; }; + virtual int getWorkspaceIndex() const { return m_settings.m_workspaceIndex; }; + virtual void setGeometryBytes(const QByteArray& blob) { m_settings.m_geometryBytes = blob; }; + virtual QByteArray getGeometryBytes() const { return m_settings.m_geometryBytes; }; + virtual QString getTitle() const { return m_settings.m_title; }; + virtual QColor getTitleColor() const { return m_settings.m_rgbColor; }; + virtual void zetHidden(bool hidden) { m_settings.m_hidden = hidden; } + virtual bool getHidden() const { return m_settings.m_hidden; } + virtual ChannelMarker& getChannelMarker() { return m_channelMarker; } + virtual int getStreamIndex() const { return -1; } + virtual void setStreamIndex(int streamIndex) { (void) streamIndex; } private: Ui::InterferometerGUI* ui; @@ -76,6 +87,7 @@ private: void displaySettings(); void displayRateAndShift(); bool handleMessage(const Message& message); + void makeUIConnections(); void leaveEvent(QEvent*); void enterEvent(QEvent*); diff --git a/plugins/channelmimo/interferometer/interferometergui.ui b/plugins/channelmimo/interferometer/interferometergui.ui index 51d12c1cb..dc806c9c7 100644 --- a/plugins/channelmimo/interferometer/interferometergui.ui +++ b/plugins/channelmimo/interferometer/interferometergui.ui @@ -1,15 +1,21 @@ InterferometerGUI - + 0 0 - 739 - 778 + 720 + 770 + + + 0 + 0 + + 720 @@ -30,10 +36,16 @@ 0 10 - 631 + 718 81 + + + 718 + 0 + + Settings @@ -352,9 +364,15 @@ 284
+ + + 0 + 0 + + - 716 + 718 0 @@ -379,6 +397,12 @@ + + + 0 + 0 + + 200 @@ -407,9 +431,15 @@ 334 + + + 0 + 0 + + - 716 + 718 0 @@ -434,6 +464,12 @@ + + + 0 + 0 + + 200 @@ -456,9 +492,9 @@ - RollupWidget + RollupContents QWidget -
gui/rollupwidget.h
+
gui/rollupcontents.h
1
diff --git a/plugins/channelmimo/interferometer/interferometersettings.cpp b/plugins/channelmimo/interferometer/interferometersettings.cpp index 128ba8528..013dde031 100644 --- a/plugins/channelmimo/interferometer/interferometersettings.cpp +++ b/plugins/channelmimo/interferometer/interferometersettings.cpp @@ -44,6 +44,8 @@ void InterferometerSettings::resetToDefaults() m_reverseAPIPort = 8888; m_reverseAPIDeviceIndex = 0; m_reverseAPIChannelIndex = 0; + m_workspaceIndex = 0; + m_hidden = false; } QByteArray InterferometerSettings::serialize() const @@ -61,6 +63,9 @@ QByteArray InterferometerSettings::serialize() const s.writeU32(10, m_reverseAPIDeviceIndex); s.writeU32(11, m_reverseAPIChannelIndex); s.writeS32(12, m_phase); + s.writeS32(13,m_workspaceIndex); + s.writeBlob(14, m_geometryBytes); + s.writeBool(15, m_hidden); if (m_spectrumGUI) { s.writeBlob(20, m_spectrumGUI->serialize()); @@ -117,6 +122,9 @@ bool InterferometerSettings::deserialize(const QByteArray& data) m_reverseAPIChannelIndex = utmp > 99 ? 99 : utmp; d.readS32(12, &tmp, 0); m_phase = tmp < -180 ? -180 : tmp > 180 ? 180 : tmp; + d.readS32(13, &m_workspaceIndex); + d.readBlob(14, &m_geometryBytes); + d.readBool(15, &m_hidden, false); if (m_spectrumGUI) { diff --git a/plugins/channelmimo/interferometer/interferometersettings.h b/plugins/channelmimo/interferometer/interferometersettings.h index 387902402..30f2bf64e 100644 --- a/plugins/channelmimo/interferometer/interferometersettings.h +++ b/plugins/channelmimo/interferometer/interferometersettings.h @@ -48,6 +48,9 @@ struct InterferometerSettings uint16_t m_reverseAPIPort; uint16_t m_reverseAPIDeviceIndex; uint16_t m_reverseAPIChannelIndex; + int m_workspaceIndex; + QByteArray m_geometryBytes; + bool m_hidden; Serializable *m_channelMarker; Serializable *m_spectrumGUI; diff --git a/plugins/channelmimo/interferometer/readme.md b/plugins/channelmimo/interferometer/readme.md index d76e038ec..18727bbfe 100644 --- a/plugins/channelmimo/interferometer/readme.md +++ b/plugins/channelmimo/interferometer/readme.md @@ -6,11 +6,13 @@ This MIMO reception only (MI) plugin can be used to study phase difference betwe

Interface

+The top and bottom bars of the channel window are described [here](../../../sdrgui/channel/readme.md) + ![Interferometer plugin GUI](../../../doc/img/Interferometer_plugin.png) The interface is divided in 3 sections that will be detailed next: - A: settings. These are the plugin controls - - B: spectrum (frequency domain). This is a spectrum display analogous to other spectrum displays. Its input varies depending on the correlation function selected + - B: spectrum (frequency domain). This is a spectrum display analogous to other spectrum displays. Its input varies depending on the correlation function selected. Details on the spectrum view and controls can be found [here](../../../sdrgui/gui/spectrum.md) - C: scope (time domain). This is a scope display analogous to other scope displays. Its input varies depending on the correlation function selected. For FFT type correlation this is not a time domain but a frequency domain display transposed to time analogous to a frequency sweep.

A. Settings section

diff --git a/plugins/channelrx/CMakeLists.txt b/plugins/channelrx/CMakeLists.txt index 7c8c51318..b0b6e106e 100644 --- a/plugins/channelrx/CMakeLists.txt +++ b/plugins/channelrx/CMakeLists.txt @@ -2,7 +2,7 @@ project(demod) if (Qt5Quick_FOUND AND Qt5QuickWidgets_FOUND AND Qt5Positioning_FOUND) add_subdirectory(demodadsb) - add_subdirectory(demodvor) + # add_subdirectory(demodvormc) endif() add_subdirectory(demodam) @@ -15,7 +15,7 @@ add_subdirectory(localsink) add_subdirectory(filesink) add_subdirectory(freqtracker) add_subdirectory(demodchirpchat) -add_subdirectory(demodvorsc) +add_subdirectory(demodvor) add_subdirectory(demodpacket) add_subdirectory(demodais) add_subdirectory(demodpager) diff --git a/plugins/channelrx/chanalyzer/chanalyzer.cpp b/plugins/channelrx/chanalyzer/chanalyzer.cpp index d009a329b..59fe9de15 100644 --- a/plugins/channelrx/chanalyzer/chanalyzer.cpp +++ b/plugins/channelrx/chanalyzer/chanalyzer.cpp @@ -25,6 +25,7 @@ #include #include "SWGChannelSettings.h" +#include "SWGWorkspaceInfo.h" #include "SWGChannelAnalyzerSettings.h" #include "device/deviceapi.h" @@ -92,6 +93,23 @@ ChannelAnalyzer::~ChannelAnalyzer() qDebug("ChannelAnalyzer::~ChannelAnalyzer: done"); } +void ChannelAnalyzer::setDeviceAPI(DeviceAPI *deviceAPI) +{ + if (deviceAPI != m_deviceAPI) + { + m_deviceAPI->removeChannelSinkAPI(this); + m_deviceAPI->removeChannelSink(this); + m_deviceAPI = deviceAPI; + m_deviceAPI->addChannelSink(this); + m_deviceAPI->addChannelSinkAPI(this); + } +} + +uint32_t ChannelAnalyzer::getNumberOfDeviceStreams() const +{ + return m_deviceAPI->getNbSourceStreams(); +} + int ChannelAnalyzer::getChannelSampleRate() { DeviceSampleSource *source = m_deviceAPI->getSampleSource(); @@ -100,7 +118,6 @@ int ChannelAnalyzer::getChannelSampleRate() m_basebandSampleRate = source->getSampleRate(); } - qDebug("ChannelAnalyzer::getChannelSampleRate: %d", m_basebandSampleRate); return m_basebandSampleRate; } @@ -317,6 +334,15 @@ int ChannelAnalyzer::webapiSettingsGet( return 200; } +int ChannelAnalyzer::webapiWorkspaceGet( + SWGSDRangel::SWGWorkspaceInfo& response, + QString& errorMessage) +{ + (void) errorMessage; + response.setIndex(m_settings.m_workspaceIndex); + return 200; +} + int ChannelAnalyzer::webapiSettingsPutPatch( bool force, const QStringList& channelSettingsKeys, diff --git a/plugins/channelrx/chanalyzer/chanalyzer.h b/plugins/channelrx/chanalyzer/chanalyzer.h index 5cc6b5542..1074301f8 100644 --- a/plugins/channelrx/chanalyzer/chanalyzer.h +++ b/plugins/channelrx/chanalyzer/chanalyzer.h @@ -64,6 +64,8 @@ public: ChannelAnalyzer(DeviceAPI *deviceAPI); virtual ~ChannelAnalyzer(); virtual void destroy() { delete this; } + virtual void setDeviceAPI(DeviceAPI *deviceAPI); + virtual DeviceAPI *getDeviceAPI() { return m_deviceAPI; } SpectrumVis *getSpectrumVis() { return &m_spectrumVis; } ScopeVis *getScopeVis() { return &m_scopeVis; } void setScopeVis(ScopeVis *scopeVis) { m_basebandSink->setScopeVis(scopeVis); } @@ -94,6 +96,7 @@ public: virtual int getNbSinkStreams() const { return 1; } virtual int getNbSourceStreams() const { return 0; } + uint32_t getNumberOfDeviceStreams() const; virtual qint64 getStreamCenterFrequency(int streamIndex, bool sinkElseSource) const { @@ -106,6 +109,10 @@ public: SWGSDRangel::SWGChannelSettings& response, QString& errorMessage); + virtual int webapiWorkspaceGet( + SWGSDRangel::SWGWorkspaceInfo& response, + QString& errorMessage); + virtual int webapiSettingsPutPatch( bool force, const QStringList& channelSettingsKeys, diff --git a/plugins/channelrx/chanalyzer/chanalyzergui.cpp b/plugins/channelrx/chanalyzer/chanalyzergui.cpp index f3d8fc032..e32fc95e9 100644 --- a/plugins/channelrx/chanalyzer/chanalyzergui.cpp +++ b/plugins/channelrx/chanalyzer/chanalyzergui.cpp @@ -76,6 +76,7 @@ void ChannelAnalyzerGUI::displaySettings() setTitleColor(m_settings.m_rgbColor); setWindowTitle(m_channelMarker.getTitle()); + setTitle(m_channelMarker.getTitle()); blockApplySettings(true); @@ -97,7 +98,8 @@ void ChannelAnalyzerGUI::displaySettings() QString rolloffStr = QString::number(m_settings.m_rrcRolloff/100.0, 'f', 2); ui->rrcRolloffText->setText(rolloffStr); - restoreState(m_rollupState); + getRollupContents()->restoreState(m_rollupState); + updateAbsoluteCenterFrequency(); blockApplySettings(false); } @@ -181,7 +183,7 @@ void ChannelAnalyzerGUI::setPLLVisibility() else ui->pllPskOrder->setCurrentIndex(i); ui->pllPskOrder->blockSignals(false); - arrangeRollups(); + getRollupContents()->arrangeRollups(); } void ChannelAnalyzerGUI::setSpectrumDisplay() @@ -232,6 +234,10 @@ bool ChannelAnalyzerGUI::handleMessage(const Message& message) { DSPSignalNotification& cmd = (DSPSignalNotification&) message; m_basebandSampleRate = cmd.getSampleRate(); + m_deviceCenterFrequency = cmd.getCenterFrequency(); + ui->deltaFrequency->setValueRange(false, 8, -m_basebandSampleRate/2, m_basebandSampleRate/2); + ui->deltaFrequencyLabel->setToolTip(tr("Range %1 %L2 Hz").arg(QChar(0xB1)).arg(m_basebandSampleRate/2)); + updateAbsoluteCenterFrequency(); qDebug("ChannelAnalyzerGUI::handleMessage: DSPSignalNotification: m_basebandSampleRate: %d", m_basebandSampleRate); setSinkSampleRate(); @@ -274,6 +280,7 @@ void ChannelAnalyzerGUI::channelMarkerChangedByCursor() { ui->deltaFrequency->setValue(m_channelMarker.getCenterFrequency()); m_settings.m_inputFrequencyOffset = m_channelMarker.getCenterFrequency(); + updateAbsoluteCenterFrequency(); applySettings(); } @@ -387,6 +394,7 @@ void ChannelAnalyzerGUI::on_deltaFrequency_changed(qint64 value) { m_channelMarker.setCenterFrequency(value); m_settings.m_inputFrequencyOffset = m_channelMarker.getCenterFrequency(); + updateAbsoluteCenterFrequency(); applySettings(); } @@ -450,7 +458,18 @@ void ChannelAnalyzerGUI::onWidgetRolled(QWidget* widget, bool rollDown) (void) widget; (void) rollDown; - saveState(m_rollupState); + RollupContents *rollupContents = getRollupContents(); + + if (rollupContents->hasExpandableWidgets()) { + setSizePolicy(sizePolicy().horizontalPolicy(), QSizePolicy::Expanding); + } else { + setSizePolicy(sizePolicy().horizontalPolicy(), QSizePolicy::Fixed); + } + + int h = rollupContents->height() + getAdditionalHeight(); + resize(width(), h); + + rollupContents->saveState(m_rollupState); applySettings(); } @@ -464,10 +483,17 @@ void ChannelAnalyzerGUI::onMenuDialogCalled(const QPoint& p) dialog.setReverseAPIPort(m_settings.m_reverseAPIPort); dialog.setReverseAPIDeviceIndex(m_settings.m_reverseAPIDeviceIndex); dialog.setReverseAPIChannelIndex(m_settings.m_reverseAPIChannelIndex); + dialog.setDefaultTitle(m_displayedName); + + if (m_deviceUISet->m_deviceMIMOEngine) + { + dialog.setNumberOfStreams(m_channelAnalyzer->getNumberOfDeviceStreams()); + dialog.setStreamIndex(m_settings.m_streamIndex); + } + dialog.move(p); dialog.exec(); - m_settings.m_inputFrequencyOffset = m_channelMarker.getCenterFrequency(); m_settings.m_rgbColor = m_channelMarker.getColor().rgb(); m_settings.m_title = m_channelMarker.getTitle(); m_settings.m_useReverseAPI = dialog.useReverseAPI(); @@ -477,8 +503,17 @@ void ChannelAnalyzerGUI::onMenuDialogCalled(const QPoint& p) m_settings.m_reverseAPIChannelIndex = dialog.getReverseAPIChannelIndex(); setWindowTitle(m_settings.m_title); + setTitle(m_channelMarker.getTitle()); setTitleColor(m_settings.m_rgbColor); + if (m_deviceUISet->m_deviceMIMOEngine) + { + m_settings.m_streamIndex = dialog.getSelectedStreamIndex(); + m_channelMarker.clearStreamIndexes(); + m_channelMarker.addStreamIndex(m_settings.m_streamIndex); + updateIndexLabel(); + } + applySettings(); } @@ -494,11 +529,13 @@ ChannelAnalyzerGUI::ChannelAnalyzerGUI(PluginAPI* pluginAPI, DeviceUISet *device m_doApplySettings(true), m_basebandSampleRate(48000) { - ui->setupUi(this); - m_helpURL = "plugins/channelrx/chanalyzer/readme.md"; setAttribute(Qt::WA_DeleteOnClose, true); - connect(this, SIGNAL(widgetRolled(QWidget*,bool)), this, SLOT(onWidgetRolled(QWidget*,bool))); - + m_helpURL = "plugins/channelrx/chanalyzer/readme.md"; + RollupContents *rollupContents = getRollupContents(); + ui->setupUi(rollupContents); + setSizePolicy(rollupContents->sizePolicy()); + rollupContents->arrangeRollups(); + connect(rollupContents, SIGNAL(widgetRolled(QWidget*,bool)), this, SLOT(onWidgetRolled(QWidget*,bool))); connect(this, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(onMenuDialogCalled(const QPoint &))); m_channelAnalyzer = (ChannelAnalyzer*) rxChannel; @@ -540,7 +577,6 @@ ChannelAnalyzerGUI::ChannelAnalyzerGUI(PluginAPI* pluginAPI, DeviceUISet *device setTitleColor(m_channelMarker.getColor()); m_deviceUISet->addChannelMarker(&m_channelMarker); - m_deviceUISet->addRollupWidget(this); ui->spectrumGUI->setBuddies(m_spectrumVis, ui->glSpectrum); ui->scopeGUI->setBuddies(m_scopeVis->getInputMessageQueue(), m_scopeVis, ui->glScope); @@ -555,6 +591,7 @@ ChannelAnalyzerGUI::ChannelAnalyzerGUI(PluginAPI* pluginAPI, DeviceUISet *device connect(getInputMessageQueue(), SIGNAL(messageEnqueued()), this, SLOT(handleInputMessages())); displaySettings(); + makeUIConnections(); applySettings(true); } @@ -671,13 +708,39 @@ void ChannelAnalyzerGUI::applySettings(bool force) } } -void ChannelAnalyzerGUI::leaveEvent(QEvent*) +void ChannelAnalyzerGUI::leaveEvent(QEvent* event) { m_channelMarker.setHighlighted(false); + ChannelGUI::leaveEvent(event); } -void ChannelAnalyzerGUI::enterEvent(QEvent*) +void ChannelAnalyzerGUI::enterEvent(QEvent* event) { m_channelMarker.setHighlighted(true); + ChannelGUI::enterEvent(event); } +void ChannelAnalyzerGUI::makeUIConnections() +{ + QObject::connect(ui->deltaFrequency, &ValueDialZ::changed, this, &ChannelAnalyzerGUI::on_deltaFrequency_changed); + QObject::connect(ui->rationalDownSamplerRate, &ValueDial::changed, this, &ChannelAnalyzerGUI::on_rationalDownSamplerRate_changed); + QObject::connect(ui->pll, &QToolButton::toggled, this, &ChannelAnalyzerGUI::on_pll_toggled); + QObject::connect(ui->pllType, QOverload::of(&QComboBox::currentIndexChanged), this, &ChannelAnalyzerGUI::on_pllType_currentIndexChanged); + QObject::connect(ui->pllPskOrder, QOverload::of(&QComboBox::currentIndexChanged), this, &ChannelAnalyzerGUI::on_pllPskOrder_currentIndexChanged); + QObject::connect(ui->pllBandwidth, &QDial::valueChanged, this, &ChannelAnalyzerGUI::on_pllBandwidth_valueChanged); + QObject::connect(ui->pllDampingFactor, &QDial::valueChanged, this, &ChannelAnalyzerGUI::on_pllDampingFactor_valueChanged); + QObject::connect(ui->pllLoopGain, &QDial::valueChanged, this, &ChannelAnalyzerGUI::on_pllLoopGain_valueChanged); + QObject::connect(ui->log2Decim, QOverload::of(&QComboBox::currentIndexChanged), this, &ChannelAnalyzerGUI::on_log2Decim_currentIndexChanged); + QObject::connect(ui->useRationalDownsampler, &ButtonSwitch::toggled, this, &ChannelAnalyzerGUI::on_useRationalDownsampler_toggled); + QObject::connect(ui->signalSelect, QOverload::of(&QComboBox::currentIndexChanged), this, &ChannelAnalyzerGUI::on_signalSelect_currentIndexChanged); + QObject::connect(ui->rrcFilter, &ButtonSwitch::toggled, this, &ChannelAnalyzerGUI::on_rrcFilter_toggled); + QObject::connect(ui->rrcRolloff, &QDial::valueChanged, this, &ChannelAnalyzerGUI::on_rrcRolloff_valueChanged); + QObject::connect(ui->BW, &QSlider::valueChanged, this, &ChannelAnalyzerGUI::on_BW_valueChanged); + QObject::connect(ui->lowCut, &QSlider::valueChanged, this, &ChannelAnalyzerGUI::on_lowCut_valueChanged); + QObject::connect(ui->ssb, &QCheckBox::toggled, this, &ChannelAnalyzerGUI::on_ssb_toggled); +} + +void ChannelAnalyzerGUI::updateAbsoluteCenterFrequency() +{ + setStatusFrequency(m_deviceCenterFrequency + m_settings.m_inputFrequencyOffset); +} diff --git a/plugins/channelrx/chanalyzer/chanalyzergui.h b/plugins/channelrx/chanalyzer/chanalyzergui.h index 1e847a84c..1744544b6 100644 --- a/plugins/channelrx/chanalyzer/chanalyzergui.h +++ b/plugins/channelrx/chanalyzer/chanalyzergui.h @@ -49,6 +49,17 @@ public: QByteArray serialize() const; bool deserialize(const QByteArray& data); virtual MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; } + virtual void setWorkspaceIndex(int index) { m_settings.m_workspaceIndex = index; }; + virtual int getWorkspaceIndex() const { return m_settings.m_workspaceIndex; }; + virtual void setGeometryBytes(const QByteArray& blob) { m_settings.m_geometryBytes = blob; }; + virtual QByteArray getGeometryBytes() const { return m_settings.m_geometryBytes; }; + virtual QString getTitle() const { return m_settings.m_title; }; + virtual QColor getTitleColor() const { return m_settings.m_rgbColor; }; + virtual void zetHidden(bool hidden) { m_settings.m_hidden = hidden; } + virtual bool getHidden() const { return m_settings.m_hidden; } + virtual ChannelMarker& getChannelMarker() { return m_channelMarker; } + virtual int getStreamIndex() const { return m_settings.m_streamIndex; } + virtual void setStreamIndex(int streamIndex) { m_settings.m_streamIndex = streamIndex; } public slots: void channelMarkerChangedByCursor(); @@ -61,6 +72,7 @@ private: ChannelMarker m_channelMarker; RollupState m_rollupState; ChannelAnalyzerSettings m_settings; + qint64 m_deviceCenterFrequency; bool m_doApplySettings; int m_basebandSampleRate; //!< sample rate after final in-channel decimation (spanlog2) MovingAverageUtil m_channelPowerAvg; @@ -84,6 +96,8 @@ private: void setPLLVisibility(); void setSpectrumDisplay(); bool handleMessage(const Message& message); + void makeUIConnections(); + void updateAbsoluteCenterFrequency(); void leaveEvent(QEvent*); void enterEvent(QEvent*); diff --git a/plugins/channelrx/chanalyzer/chanalyzergui.ui b/plugins/channelrx/chanalyzer/chanalyzergui.ui index a8c641eb8..13fe10ab3 100644 --- a/plugins/channelrx/chanalyzer/chanalyzergui.ui +++ b/plugins/channelrx/chanalyzer/chanalyzergui.ui @@ -1,12 +1,12 @@ ChannelAnalyzerGUI - + 0 0 - 739 + 720 778 @@ -36,10 +36,16 @@ 0 0 - 524 + 718 101 + + + 718 + 0 + + Settings @@ -861,9 +867,15 @@ 284 + + + 0 + 0 + + - 716 + 718 0 @@ -888,6 +900,12 @@ + + + 0 + 0 + + 200 @@ -916,9 +934,15 @@ 334 + + + 0 + 0 + + - 716 + 718 0 @@ -943,6 +967,12 @@ + + + 0 + 0 + + 200 @@ -965,9 +995,20 @@ - RollupWidget + ValueDial QWidget -
gui/rollupwidget.h
+
gui/valuedial.h
+ 1 +
+ + ButtonSwitch + QToolButton +
gui/buttonswitch.h
+
+ + RollupContents + QWidget +
gui/rollupcontents.h
1
@@ -976,23 +1017,6 @@
gui/valuedialz.h
1
- - GLScope - QWidget -
gui/glscope.h
- 1 -
- - GLScopeGUI - QWidget -
gui/glscopegui.h
- 1 -
- - ButtonSwitch - QToolButton -
gui/buttonswitch.h
-
GLSpectrum QWidget @@ -1006,9 +1030,15 @@ 1 - ValueDial + GLScope QWidget -
gui/valuedial.h
+
gui/glscope.h
+ 1 +
+ + GLScopeGUI + QWidget +
gui/glscopegui.h
1
diff --git a/plugins/channelrx/chanalyzer/chanalyzersettings.cpp b/plugins/channelrx/chanalyzer/chanalyzersettings.cpp index d357c936a..7f3ee49a4 100644 --- a/plugins/channelrx/chanalyzer/chanalyzersettings.cpp +++ b/plugins/channelrx/chanalyzer/chanalyzersettings.cpp @@ -59,6 +59,8 @@ void ChannelAnalyzerSettings::resetToDefaults() m_reverseAPIPort = 8888; m_reverseAPIDeviceIndex = 0; m_reverseAPIChannelIndex = 0; + m_workspaceIndex = 0; + m_hidden = false; } QByteArray ChannelAnalyzerSettings::serialize() const @@ -105,6 +107,9 @@ QByteArray ChannelAnalyzerSettings::serialize() const s.writeU32(26, m_reverseAPIDeviceIndex); s.writeU32(27, m_reverseAPIChannelIndex); s.writeS32(28, m_streamIndex); + s.writeS32(29, m_workspaceIndex); + s.writeBlob(30, m_geometryBytes); + s.writeBool(31, m_hidden); return s.final(); } @@ -179,6 +184,9 @@ bool ChannelAnalyzerSettings::deserialize(const QByteArray& data) d.readU32(27, &utmp, 0); m_reverseAPIChannelIndex = utmp > 99 ? 99 : utmp; d.readS32(28, &m_streamIndex, 0); + d.readS32(29, &m_workspaceIndex, 0); + d.readBlob(30, &m_geometryBytes); + d.readBool(31, &m_hidden, false); return true; } diff --git a/plugins/channelrx/chanalyzer/chanalyzersettings.h b/plugins/channelrx/chanalyzer/chanalyzersettings.h index f0878e489..23865a355 100644 --- a/plugins/channelrx/chanalyzer/chanalyzersettings.h +++ b/plugins/channelrx/chanalyzer/chanalyzersettings.h @@ -60,6 +60,9 @@ struct ChannelAnalyzerSettings uint16_t m_reverseAPIPort; uint16_t m_reverseAPIDeviceIndex; uint16_t m_reverseAPIChannelIndex; + int m_workspaceIndex; + QByteArray m_geometryBytes; + bool m_hidden; ChannelAnalyzerSettings(); void resetToDefaults(); diff --git a/plugins/channelrx/chanalyzer/readme.md b/plugins/channelrx/chanalyzer/readme.md index 954f0e15b..b92fa6296 100644 --- a/plugins/channelrx/chanalyzer/readme.md +++ b/plugins/channelrx/chanalyzer/readme.md @@ -24,6 +24,8 @@ The same waveforms can be used to trigger the scope trace

B. General interface

+The top and bottom bars of the channel window are described [here](../../../sdrgui/channel/readme.md) + ![Channel Analyzer NG plugin GUI](../../../doc/img/ChAnalyzerNG_plugin.png) The interface is essentially divided in the following sections @@ -36,7 +38,7 @@ The interface is essentially divided in the following sections Note 1: the scope trace is updated continuously for sweep times of 1 second or more else the display is refreshed only when the trace finishes. -Note 2: the spectrum view (Channel spectrum) is not presented here. +Note 2: details on the spectrum view and controls can be found [here](../../../sdrgui/gui/spectrum.md)

C. Channel controls

diff --git a/plugins/channelrx/demodadsb/adsbdemod.cpp b/plugins/channelrx/demodadsb/adsbdemod.cpp index 6bf711ab5..f8126e9bd 100644 --- a/plugins/channelrx/demodadsb/adsbdemod.cpp +++ b/plugins/channelrx/demodadsb/adsbdemod.cpp @@ -31,6 +31,7 @@ #include #include "SWGChannelSettings.h" +#include "SWGWorkspaceInfo.h" #include "SWGADSBDemodSettings.h" #include "SWGChannelReport.h" #include "SWGADSBDemodReport.h" @@ -109,6 +110,18 @@ ADSBDemod::~ADSBDemod() delete m_thread; } +void ADSBDemod::setDeviceAPI(DeviceAPI *deviceAPI) +{ + if (deviceAPI != m_deviceAPI) + { + m_deviceAPI->removeChannelSinkAPI(this); + m_deviceAPI->removeChannelSink(this); + m_deviceAPI = deviceAPI; + m_deviceAPI->addChannelSink(this); + m_deviceAPI->addChannelSinkAPI(this); + } +} + uint32_t ADSBDemod::getNumberOfDeviceStreams() const { return m_deviceAPI->getNbSourceStreams(); @@ -362,6 +375,15 @@ int ADSBDemod::webapiSettingsGet( return 200; } +int ADSBDemod::webapiWorkspaceGet( + SWGSDRangel::SWGWorkspaceInfo& response, + QString& errorMessage) +{ + (void) errorMessage; + response.setIndex(m_settings.m_workspaceIndex); + return 200; +} + int ADSBDemod::webapiSettingsPutPatch( bool force, const QStringList& channelSettingsKeys, diff --git a/plugins/channelrx/demodadsb/adsbdemod.h b/plugins/channelrx/demodadsb/adsbdemod.h index db4a80797..c7e7b5c8a 100644 --- a/plugins/channelrx/demodadsb/adsbdemod.h +++ b/plugins/channelrx/demodadsb/adsbdemod.h @@ -65,6 +65,8 @@ public: ADSBDemod(DeviceAPI *deviceAPI); virtual ~ADSBDemod(); virtual void destroy() { delete this; } + virtual void setDeviceAPI(DeviceAPI *deviceAPI); + virtual DeviceAPI *getDeviceAPI() { return m_deviceAPI; } using BasebandSampleSink::feed; virtual void feed(const SampleVector::const_iterator& begin, const SampleVector::const_iterator& end, bool po); @@ -96,6 +98,10 @@ public: SWGSDRangel::SWGChannelSettings& response, QString& errorMessage); + virtual int webapiWorkspaceGet( + SWGSDRangel::SWGWorkspaceInfo& response, + QString& errorMessage); + virtual int webapiSettingsPutPatch( bool force, const QStringList& channelSettingsKeys, diff --git a/plugins/channelrx/demodadsb/adsbdemodgui.cpp b/plugins/channelrx/demodadsb/adsbdemodgui.cpp index 37e8084de..4e6ef181e 100644 --- a/plugins/channelrx/demodadsb/adsbdemodgui.cpp +++ b/plugins/channelrx/demodadsb/adsbdemodgui.cpp @@ -2132,7 +2132,7 @@ QString ADSBDemodGUI::subAircraftString(Aircraft *aircraft, const QString &strin bool ADSBDemodGUI::handleMessage(const Message& message) { -if (DSPSignalNotification::match(message)) + if (DSPSignalNotification::match(message)) { DSPSignalNotification& notif = (DSPSignalNotification&) message; int sr = notif.getSampleRate(); @@ -2143,7 +2143,12 @@ if (DSPSignalNotification::match(message)) } else { ui->warning->setText(""); } - arrangeRollups(); + getRollupContents()->arrangeRollups(); + m_deviceCenterFrequency = notif.getCenterFrequency(); + m_basebandSampleRate = sr; + ui->deltaFrequency->setValueRange(false, 7, -sr/2, sr/2); + ui->deltaFrequencyLabel->setToolTip(tr("Range %1 %L2 Hz").arg(QChar(0xB1)).arg(sr/2)); + updateAbsoluteCenterFrequency(); return true; } else if (ADSBDemodReport::MsgReportADSB::match(message)) @@ -2211,6 +2216,7 @@ void ADSBDemodGUI::on_deltaFrequency_changed(qint64 value) { m_channelMarker.setCenterFrequency(value); m_settings.m_inputFrequencyOffset = m_channelMarker.getCenterFrequency(); + updateAbsoluteCenterFrequency(); applySettings(); } @@ -2759,7 +2765,18 @@ void ADSBDemodGUI::onWidgetRolled(QWidget* widget, bool rollDown) (void) widget; (void) rollDown; - saveState(m_rollupState); + RollupContents *rollupContents = getRollupContents(); + + if (rollupContents->hasExpandableWidgets()) { + setSizePolicy(sizePolicy().horizontalPolicy(), QSizePolicy::Expanding); + } else { + setSizePolicy(sizePolicy().horizontalPolicy(), QSizePolicy::Fixed); + } + + int h = rollupContents->height() + getAdditionalHeight(); + resize(width(), h); + + rollupContents->saveState(m_rollupState); applySettings(); } @@ -2773,10 +2790,17 @@ void ADSBDemodGUI::onMenuDialogCalled(const QPoint &p) dialog.setReverseAPIPort(m_settings.m_reverseAPIPort); dialog.setReverseAPIDeviceIndex(m_settings.m_reverseAPIDeviceIndex); dialog.setReverseAPIChannelIndex(m_settings.m_reverseAPIChannelIndex); + dialog.setDefaultTitle(m_displayedName); + + if (m_deviceUISet->m_deviceMIMOEngine) + { + dialog.setNumberOfStreams(m_adsbDemod->getNumberOfDeviceStreams()); + dialog.setStreamIndex(m_settings.m_streamIndex); + } + dialog.move(p); dialog.exec(); - m_settings.m_inputFrequencyOffset = m_channelMarker.getCenterFrequency(); m_settings.m_rgbColor = m_channelMarker.getColor().rgb(); m_settings.m_title = m_channelMarker.getTitle(); m_settings.m_useReverseAPI = dialog.useReverseAPI(); @@ -2786,22 +2810,17 @@ void ADSBDemodGUI::onMenuDialogCalled(const QPoint &p) m_settings.m_reverseAPIChannelIndex = dialog.getReverseAPIChannelIndex(); setWindowTitle(m_settings.m_title); + setTitle(m_channelMarker.getTitle()); setTitleColor(m_settings.m_rgbColor); - applySettings(); - } - else if ((m_contextMenuType == ContextMenuStreamSettings) && (m_deviceUISet->m_deviceMIMOEngine)) - { - DeviceStreamSelectionDialog dialog(this); - dialog.setNumberOfStreams(m_adsbDemod->getNumberOfDeviceStreams()); - dialog.setStreamIndex(m_settings.m_streamIndex); - dialog.move(p); - dialog.exec(); + if (m_deviceUISet->m_deviceMIMOEngine) + { + m_settings.m_streamIndex = dialog.getSelectedStreamIndex(); + m_channelMarker.clearStreamIndexes(); + m_channelMarker.addStreamIndex(m_settings.m_streamIndex); + updateIndexLabel(); + } - m_settings.m_streamIndex = dialog.getSelectedStreamIndex(); - m_channelMarker.clearStreamIndexes(); - m_channelMarker.addStreamIndex(m_settings.m_streamIndex); - displayStreamIndex(); applySettings(); } @@ -3674,6 +3693,8 @@ ADSBDemodGUI::ADSBDemodGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, Baseb m_pluginAPI(pluginAPI), m_deviceUISet(deviceUISet), m_channelMarker(this), + m_deviceCenterFrequency(0), + m_basebandSampleRate(1), m_basicSettingsShown(false), m_doApplySettings(true), m_tickCount(0), @@ -3684,8 +3705,13 @@ ADSBDemodGUI::ADSBDemodGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, Baseb m_highlightAircraft(nullptr), m_progressDialog(nullptr) { - ui->setupUi(this); + setAttribute(Qt::WA_DeleteOnClose, true); m_helpURL = "plugins/channelrx/demodadsb/readme.md"; + RollupContents *rollupContents = getRollupContents(); + ui->setupUi(rollupContents); + setSizePolicy(rollupContents->sizePolicy()); + rollupContents->arrangeRollups(); + connect(rollupContents, SIGNAL(widgetRolled(QWidget*,bool)), this, SLOT(onWidgetRolled(QWidget*,bool))); m_osmPort = 0; // Pick a free port m_templateServer = new ADSBOSMTemplateServer("q2RVNAe3eFKCH4XsrE3r", m_osmPort); @@ -3696,9 +3722,6 @@ ADSBDemodGUI::ADSBDemodGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, Baseb ui->map->rootContext()->setContextProperty("navAidModel", &m_navAidModel); ui->map->setSource(QUrl(QStringLiteral("qrc:/map/map.qml"))); - 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(&m_dlm, &HttpDownloadManager::downloadComplete, this, &ADSBDemodGUI::downloadFinished); @@ -3731,7 +3754,6 @@ ADSBDemodGUI::ADSBDemodGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, Baseb m_settings.setRollupState(&m_rollupState); m_deviceUISet->addChannelMarker(&m_channelMarker); - m_deviceUISet->addRollupWidget(this); connect(&m_channelMarker, SIGNAL(changedByCursor()), this, SLOT(channelMarkerChangedByCursor())); connect(&m_channelMarker, SIGNAL(highlightedByCursor()), this, SLOT(channelMarkerHighlightedByCursor())); @@ -3829,6 +3851,7 @@ ADSBDemodGUI::ADSBDemodGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, Baseb updateDeviceSetList(); displaySettings(); + makeUIConnections(); applySettings(true); connect(&m_importTimer, &QTimer::timeout, this, &ADSBDemodGUI::import); @@ -3903,6 +3926,7 @@ void ADSBDemodGUI::displaySettings() setTitleColor(m_settings.m_rgbColor); setWindowTitle(m_channelMarker.getTitle()); + setTitle(m_channelMarker.getTitle()); blockApplySettings(true); @@ -3940,7 +3964,7 @@ void ADSBDemodGUI::displaySettings() ui->logFilename->setToolTip(QString(".csv log filename: %1").arg(m_settings.m_logFilename)); ui->logEnable->setChecked(m_settings.m_logEnabled); - displayStreamIndex(); + updateIndexLabel(); QFont font(m_settings.m_tableFontName, m_settings.m_tableFontSize); ui->adsbData->setFont(font); @@ -3989,27 +4013,20 @@ void ADSBDemodGUI::displaySettings() applyMapSettings(); applyImportSettings(); - restoreState(m_rollupState); + getRollupContents()->restoreState(m_rollupState); blockApplySettings(false); } -void ADSBDemodGUI::displayStreamIndex() -{ - if (m_deviceUISet->m_deviceMIMOEngine) { - setStreamIndicator(tr("%1").arg(m_settings.m_streamIndex)); - } else { - setStreamIndicator("S"); // single channel indicator - } -} - -void ADSBDemodGUI::leaveEvent(QEvent*) +void ADSBDemodGUI::leaveEvent(QEvent* event) { m_channelMarker.setHighlighted(false); + ChannelGUI::leaveEvent(event); } -void ADSBDemodGUI::enterEvent(QEvent*) +void ADSBDemodGUI::enterEvent(QEvent* event) { m_channelMarker.setHighlighted(true); + ChannelGUI::enterEvent(event); } void ADSBDemodGUI::blockApplySettings(bool block) @@ -4659,3 +4676,36 @@ void ADSBDemodGUI::preferenceChanged(int elementType) } } } + +void ADSBDemodGUI::makeUIConnections() +{ + QObject::connect(ui->deltaFrequency, &ValueDialZ::changed, this, &ADSBDemodGUI::on_deltaFrequency_changed); + QObject::connect(ui->rfBW, &QSlider::valueChanged, this, &ADSBDemodGUI::on_rfBW_valueChanged); + QObject::connect(ui->threshold, &QDial::valueChanged, this, &ADSBDemodGUI::on_threshold_valueChanged); + QObject::connect(ui->phaseSteps, &QDial::valueChanged, this, &ADSBDemodGUI::on_phaseSteps_valueChanged); + QObject::connect(ui->tapsPerPhase, &QDial::valueChanged, this, &ADSBDemodGUI::on_tapsPerPhase_valueChanged); + QObject::connect(ui->adsbData, &QTableWidget::cellClicked, this, &ADSBDemodGUI::on_adsbData_cellClicked); + QObject::connect(ui->adsbData, &QTableWidget::cellDoubleClicked, this, &ADSBDemodGUI::on_adsbData_cellDoubleClicked); + QObject::connect(ui->spb, QOverload::of(&QComboBox::currentIndexChanged), this, &ADSBDemodGUI::on_spb_currentIndexChanged); + QObject::connect(ui->correlateFullPreamble, &ButtonSwitch::clicked, this, &ADSBDemodGUI::on_correlateFullPreamble_clicked); + QObject::connect(ui->demodModeS, &ButtonSwitch::clicked, this, &ADSBDemodGUI::on_demodModeS_clicked); + QObject::connect(ui->feed, &ButtonSwitch::clicked, this, &ADSBDemodGUI::on_feed_clicked); + QObject::connect(ui->notifications, &QToolButton::clicked, this, &ADSBDemodGUI::on_notifications_clicked); + QObject::connect(ui->flightInfo, &QToolButton::clicked, this, &ADSBDemodGUI::on_flightInfo_clicked); + QObject::connect(ui->findOnMapFeature, &QToolButton::clicked, this, &ADSBDemodGUI::on_findOnMapFeature_clicked); + QObject::connect(ui->getOSNDB, &QToolButton::clicked, this, &ADSBDemodGUI::on_getOSNDB_clicked); + QObject::connect(ui->getAirportDB, &QToolButton::clicked, this, &ADSBDemodGUI::on_getAirportDB_clicked); + QObject::connect(ui->getAirspacesDB, &QToolButton::clicked, this, &ADSBDemodGUI::on_getAirspacesDB_clicked); + QObject::connect(ui->flightPaths, &ButtonSwitch::clicked, this, &ADSBDemodGUI::on_flightPaths_clicked); + QObject::connect(ui->allFlightPaths, &ButtonSwitch::clicked, this, &ADSBDemodGUI::on_allFlightPaths_clicked); + QObject::connect(ui->device, QOverload::of(&QComboBox::currentIndexChanged), this, &ADSBDemodGUI::on_device_currentIndexChanged); + QObject::connect(ui->displaySettings, &QToolButton::clicked, this, &ADSBDemodGUI::on_displaySettings_clicked); + QObject::connect(ui->logEnable, &ButtonSwitch::clicked, this, &ADSBDemodGUI::on_logEnable_clicked); + QObject::connect(ui->logFilename, &QToolButton::clicked, this, &ADSBDemodGUI::on_logFilename_clicked); + QObject::connect(ui->logOpen, &QToolButton::clicked, this, &ADSBDemodGUI::on_logOpen_clicked); +} + +void ADSBDemodGUI::updateAbsoluteCenterFrequency() +{ + setStatusFrequency(m_deviceCenterFrequency + m_settings.m_inputFrequencyOffset); +} diff --git a/plugins/channelrx/demodadsb/adsbdemodgui.h b/plugins/channelrx/demodadsb/adsbdemodgui.h index 8f0aa60f5..f582e02b9 100644 --- a/plugins/channelrx/demodadsb/adsbdemodgui.h +++ b/plugins/channelrx/demodadsb/adsbdemodgui.h @@ -752,6 +752,18 @@ public: QByteArray serialize() const; bool deserialize(const QByteArray& data); virtual MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; } + virtual void setWorkspaceIndex(int index) { m_settings.m_workspaceIndex = index; }; + virtual int getWorkspaceIndex() const { return m_settings.m_workspaceIndex; }; + virtual void setGeometryBytes(const QByteArray& blob) { m_settings.m_geometryBytes = blob; }; + virtual QByteArray getGeometryBytes() const { return m_settings.m_geometryBytes; }; + virtual QString getTitle() const { return m_settings.m_title; }; + virtual QColor getTitleColor() const { return m_settings.m_rgbColor; }; + virtual void zetHidden(bool hidden) { m_settings.m_hidden = hidden; } + virtual bool getHidden() const { return m_settings.m_hidden; } + virtual ChannelMarker& getChannelMarker() { return m_channelMarker; } + virtual int getStreamIndex() const { return m_settings.m_streamIndex; } + virtual void setStreamIndex(int streamIndex) { m_settings.m_streamIndex = streamIndex; } + void highlightAircraft(Aircraft *aircraft); void targetAircraft(Aircraft *aircraft); void target(const QString& name, float az, float el, float range); @@ -776,6 +788,8 @@ private: ChannelMarker m_channelMarker; RollupState m_rollupState; ADSBDemodSettings m_settings; + qint64 m_deviceCenterFrequency; + int m_basebandSampleRate; bool m_basicSettingsShown; bool m_doApplySettings; @@ -836,8 +850,10 @@ private: void blockApplySettings(bool block); void applySettings(bool force = false); void displaySettings(); - void displayStreamIndex(); bool handleMessage(const Message& message); + void makeUIConnections(); + void updateAbsoluteCenterFrequency(); + void updatePosition(Aircraft *aircraft); bool updateLocalPosition(Aircraft *aircraft, double latitude, double longitude, bool surfacePosition); void sendToMap(Aircraft *aircraft, QList *animations); diff --git a/plugins/channelrx/demodadsb/adsbdemodgui.ui b/plugins/channelrx/demodadsb/adsbdemodgui.ui index 3239b18df..a0ea5dc91 100644 --- a/plugins/channelrx/demodadsb/adsbdemodgui.ui +++ b/plugins/channelrx/demodadsb/adsbdemodgui.ui @@ -1,12 +1,12 @@ ADSBDemodGUI - + 0 0 - 604 + 600 1046 @@ -18,7 +18,7 @@ - 350 + 600 0 @@ -35,13 +35,13 @@ 0 0 - 600 + 598 141 - 600 + 598 0 @@ -758,7 +758,7 @@ 0 140 - 600 + 598 600 @@ -770,7 +770,7 @@ - 600 + 598 0 @@ -1269,17 +1269,17 @@ QWidget
QtQuickWidgets/QQuickWidget
- - RollupWidget - QWidget -
gui/rollupwidget.h
- 1 -
ButtonSwitch QToolButton
gui/buttonswitch.h
+ + RollupContents + QWidget +
gui/rollupcontents.h
+ 1 +
ValueDialZ QWidget diff --git a/plugins/channelrx/demodadsb/adsbdemodsettings.cpp b/plugins/channelrx/demodadsb/adsbdemodsettings.cpp index 5790fa66e..b23b0fb67 100644 --- a/plugins/channelrx/demodadsb/adsbdemodsettings.cpp +++ b/plugins/channelrx/demodadsb/adsbdemodsettings.cpp @@ -96,6 +96,8 @@ void ADSBDemodSettings::resetToDefaults() m_displayPhotos = true; m_verboseModelMatching = false; m_airfieldElevation = 0; + m_workspaceIndex = 0; + m_hidden = false; } QByteArray ADSBDemodSettings::serialize() const @@ -172,6 +174,9 @@ QByteArray ADSBDemodSettings::serialize() const s.writeString(56, m_importMaxLatitude); s.writeString(57, m_importMinLongitude); s.writeString(58, m_importMaxLongitude); + s.writeS32(59, m_workspaceIndex); + s.writeBlob(60, m_geometryBytes); + s.writeBool(61, m_hidden); for (int i = 0; i < ADSBDEMOD_COLUMNS; i++) { s.writeS32(100 + i, m_columnIndexes[i]); @@ -298,6 +303,9 @@ bool ADSBDemodSettings::deserialize(const QByteArray& data) d.readString(56, &m_importMaxLatitude, ""); d.readString(57, &m_importMinLongitude, ""); d.readString(58, &m_importMaxLongitude, ""); + d.readS32(59, &m_workspaceIndex, 0); + d.readBlob(60, &m_geometryBytes); + d.readBool(61, &m_hidden, false); for (int i = 0; i < ADSBDEMOD_COLUMNS; i++) { d.readS32(100 + i, &m_columnIndexes[i], i); diff --git a/plugins/channelrx/demodadsb/adsbdemodsettings.h b/plugins/channelrx/demodadsb/adsbdemodsettings.h index 88ae38cc4..8fd12a054 100644 --- a/plugins/channelrx/demodadsb/adsbdemodsettings.h +++ b/plugins/channelrx/demodadsb/adsbdemodsettings.h @@ -116,6 +116,10 @@ struct ADSBDemodSettings uint16_t m_reverseAPIPort; uint16_t m_reverseAPIDeviceIndex; uint16_t m_reverseAPIChannelIndex; + int m_workspaceIndex; + QByteArray m_geometryBytes; + bool m_hidden; + int m_columnIndexes[ADSBDEMOD_COLUMNS];//!< How the columns are ordered in the table int m_columnSizes[ADSBDEMOD_COLUMNS]; //!< Size of the coumns in the table diff --git a/plugins/channelrx/demodadsb/readme.md b/plugins/channelrx/demodadsb/readme.md index 48cc25afb..15fd1f990 100644 --- a/plugins/channelrx/demodadsb/readme.md +++ b/plugins/channelrx/demodadsb/readme.md @@ -2,6 +2,8 @@

Introduction

+The top and bottom bars of the device window are described [here](../../../sdrgui/device/readme.md) + The ADS-B demodulator plugin can be used to receive and display ADS-B aircraft information. This is information about an aircraft, such as position, altitude, heading and speed, broadcast by aircraft on 1090MHz, in the 1090ES (Extended Squitter) format. 1090ES frames have a chip rate of 2Mchip/s, so the baseband sample rate should be set to be greater than 2MSa/s. As well as displaying information received via ADS-B, the plugin can also combine information from a number of databases to display more information about the aircraft and flight. @@ -14,6 +16,8 @@ The ADS-B plugin can send aicraft for display on the [Map Feature](../../feature

Interface

+The top and bottom bars of the channel window are described [here](../../../sdrgui/channel/readme.md) + ![ADS-B Demodulator plugin settings](../../../doc/img/ADSBDemod_plugin_settings.png)

1: Frequency shift from center frequency of reception value

diff --git a/plugins/channelrx/demodais/aisdemod.cpp b/plugins/channelrx/demodais/aisdemod.cpp index c24d3d601..d2fb61529 100644 --- a/plugins/channelrx/demodais/aisdemod.cpp +++ b/plugins/channelrx/demodais/aisdemod.cpp @@ -29,6 +29,7 @@ #include #include "SWGChannelSettings.h" +#include "SWGWorkspaceInfo.h" #include "SWGChannelReport.h" #include "dsp/dspengine.h" @@ -97,6 +98,18 @@ AISDemod::~AISDemod() delete m_basebandSink; } +void AISDemod::setDeviceAPI(DeviceAPI *deviceAPI) +{ + if (deviceAPI != m_deviceAPI) + { + m_deviceAPI->removeChannelSinkAPI(this); + m_deviceAPI->removeChannelSink(this); + m_deviceAPI = deviceAPI; + m_deviceAPI->addChannelSink(this); + m_deviceAPI->addChannelSinkAPI(this); + } +} + uint32_t AISDemod::getNumberOfDeviceStreams() const { return m_deviceAPI->getNbSourceStreams(); @@ -151,6 +164,10 @@ bool AISDemod::handleMessage(const Message& cmd) qDebug() << "AISDemod::handleMessage: DSPSignalNotification"; m_basebandSink->getInputMessageQueue()->push(rep); + if (getMessageQueueToGUI()) { + getMessageQueueToGUI()->push(new DSPSignalNotification(notif)); + } + return true; } else if (MsgMessage::match(cmd)) @@ -402,6 +419,15 @@ int AISDemod::webapiSettingsGet( return 200; } +int AISDemod::webapiWorkspaceGet( + SWGSDRangel::SWGWorkspaceInfo& response, + QString& errorMessage) +{ + (void) errorMessage; + response.setIndex(m_settings.m_workspaceIndex); + return 200; +} + int AISDemod::webapiSettingsPutPatch( bool force, const QStringList& channelSettingsKeys, diff --git a/plugins/channelrx/demodais/aisdemod.h b/plugins/channelrx/demodais/aisdemod.h index 713f05229..3fbc1d0fa 100644 --- a/plugins/channelrx/demodais/aisdemod.h +++ b/plugins/channelrx/demodais/aisdemod.h @@ -93,6 +93,8 @@ public: AISDemod(DeviceAPI *deviceAPI); virtual ~AISDemod(); virtual void destroy() { delete this; } + virtual void setDeviceAPI(DeviceAPI *deviceAPI); + virtual DeviceAPI *getDeviceAPI() { return m_deviceAPI; } using BasebandSampleSink::feed; virtual void feed(const SampleVector::const_iterator& begin, const SampleVector::const_iterator& end, bool po); @@ -125,6 +127,10 @@ public: SWGSDRangel::SWGChannelSettings& response, QString& errorMessage); + virtual int webapiWorkspaceGet( + SWGSDRangel::SWGWorkspaceInfo& response, + QString& errorMessage); + virtual int webapiSettingsPutPatch( bool force, const QStringList& channelSettingsKeys, diff --git a/plugins/channelrx/demodais/aisdemodgui.cpp b/plugins/channelrx/demodais/aisdemodgui.cpp index 0f167d629..0d78263fa 100644 --- a/plugins/channelrx/demodais/aisdemodgui.cpp +++ b/plugins/channelrx/demodais/aisdemodgui.cpp @@ -217,6 +217,16 @@ bool AISDemodGUI::handleMessage(const Message& message) messageReceived(report.getMessage(), report.getDateTime()); return true; } + else if (DSPSignalNotification::match(message)) + { + DSPSignalNotification& notif = (DSPSignalNotification&) message; + m_deviceCenterFrequency = notif.getCenterFrequency(); + m_basebandSampleRate = notif.getSampleRate(); + ui->deltaFrequency->setValueRange(false, 7, -m_basebandSampleRate/2, m_basebandSampleRate/2); + ui->deltaFrequencyLabel->setToolTip(tr("Range %1 %L2 Hz").arg(QChar(0xB1)).arg(m_basebandSampleRate/2)); + updateAbsoluteCenterFrequency(); + return true; + } return false; } @@ -250,6 +260,7 @@ void AISDemodGUI::on_deltaFrequency_changed(qint64 value) { m_channelMarker.setCenterFrequency(value); m_settings.m_inputFrequencyOffset = m_channelMarker.getCenterFrequency(); + updateAbsoluteCenterFrequency(); applySettings(); } @@ -371,7 +382,18 @@ void AISDemodGUI::onWidgetRolled(QWidget* widget, bool rollDown) } } - saveState(m_rollupState); + RollupContents *rollupContents = getRollupContents(); + + if (rollupContents->hasExpandableWidgets()) { + setSizePolicy(sizePolicy().horizontalPolicy(), QSizePolicy::Expanding); + } else { + setSizePolicy(sizePolicy().horizontalPolicy(), QSizePolicy::Fixed); + } + + int h = rollupContents->height() + getAdditionalHeight(); + resize(width(), h); + + rollupContents->saveState(m_rollupState); applySettings(); } @@ -385,6 +407,14 @@ void AISDemodGUI::onMenuDialogCalled(const QPoint &p) dialog.setReverseAPIPort(m_settings.m_reverseAPIPort); dialog.setReverseAPIDeviceIndex(m_settings.m_reverseAPIDeviceIndex); dialog.setReverseAPIChannelIndex(m_settings.m_reverseAPIChannelIndex); + dialog.setDefaultTitle(m_displayedName); + + if (m_deviceUISet->m_deviceMIMOEngine) + { + dialog.setNumberOfStreams(m_aisDemod->getNumberOfDeviceStreams()); + dialog.setStreamIndex(m_settings.m_streamIndex); + } + dialog.move(p); dialog.exec(); @@ -397,22 +427,17 @@ void AISDemodGUI::onMenuDialogCalled(const QPoint &p) m_settings.m_reverseAPIChannelIndex = dialog.getReverseAPIChannelIndex(); setWindowTitle(m_settings.m_title); + setTitle(m_channelMarker.getTitle()); setTitleColor(m_settings.m_rgbColor); - applySettings(); - } - else if ((m_contextMenuType == ContextMenuStreamSettings) && (m_deviceUISet->m_deviceMIMOEngine)) - { - DeviceStreamSelectionDialog dialog(this); - dialog.setNumberOfStreams(m_aisDemod->getNumberOfDeviceStreams()); - dialog.setStreamIndex(m_settings.m_streamIndex); - dialog.move(p); - dialog.exec(); + if (m_deviceUISet->m_deviceMIMOEngine) + { + m_settings.m_streamIndex = dialog.getSelectedStreamIndex(); + m_channelMarker.clearStreamIndexes(); + m_channelMarker.addStreamIndex(m_settings.m_streamIndex); + updateIndexLabel(); + } - m_settings.m_streamIndex = dialog.getSelectedStreamIndex(); - m_channelMarker.clearStreamIndexes(); - m_channelMarker.addStreamIndex(m_settings.m_streamIndex); - displayStreamIndex(); applySettings(); } @@ -425,14 +450,18 @@ AISDemodGUI::AISDemodGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, Baseban m_pluginAPI(pluginAPI), m_deviceUISet(deviceUISet), m_channelMarker(this), + m_deviceCenterFrequency(0), + m_basebandSampleRate(1), m_doApplySettings(true), m_tickCount(0) { - ui->setupUi(this); - m_helpURL = "plugins/channelrx/demodais/readme.md"; - setAttribute(Qt::WA_DeleteOnClose, true); - connect(this, SIGNAL(widgetRolled(QWidget*,bool)), this, SLOT(onWidgetRolled(QWidget*,bool))); + m_helpURL = "plugins/channelrx/demodais/readme.md"; + RollupContents *rollupContents = getRollupContents(); + ui->setupUi(rollupContents); + setSizePolicy(rollupContents->sizePolicy()); + rollupContents->arrangeRollups(); + connect(rollupContents, SIGNAL(widgetRolled(QWidget*,bool)), this, SLOT(onWidgetRolled(QWidget*,bool))); connect(this, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(onMenuDialogCalled(const QPoint &))); m_aisDemod = reinterpret_cast(rxChannel); @@ -488,7 +517,6 @@ AISDemodGUI::AISDemodGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, Baseban m_settings.setRollupState(&m_rollupState); m_deviceUISet->addChannelMarker(&m_channelMarker); - m_deviceUISet->addRollupWidget(this); connect(&m_channelMarker, SIGNAL(changedByCursor()), this, SLOT(channelMarkerChangedByCursor())); connect(&m_channelMarker, SIGNAL(highlightedByCursor()), this, SLOT(channelMarkerHighlightedByCursor())); @@ -518,6 +546,7 @@ AISDemodGUI::AISDemodGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, Baseban ui->scopeContainer->setVisible(false); displaySettings(); + makeUIConnections(); applySettings(true); } @@ -569,6 +598,7 @@ void AISDemodGUI::displaySettings() setTitleColor(m_settings.m_rgbColor); setWindowTitle(m_channelMarker.getTitle()); + setTitle(m_channelMarker.getTitle()); blockApplySettings(true); @@ -583,7 +613,7 @@ void AISDemodGUI::displaySettings() ui->thresholdText->setText(QString("%1").arg(m_settings.m_correlationThreshold)); ui->threshold->setValue(m_settings.m_correlationThreshold); - displayStreamIndex(); + updateIndexLabel(); ui->filterMMSI->setText(m_settings.m_filterMMSI); @@ -612,27 +642,21 @@ void AISDemodGUI::displaySettings() filter(); - restoreState(m_rollupState); + getRollupContents()->restoreState(m_rollupState); + updateAbsoluteCenterFrequency(); blockApplySettings(false); } -void AISDemodGUI::displayStreamIndex() -{ - if (m_deviceUISet->m_deviceMIMOEngine) { - setStreamIndicator(tr("%1").arg(m_settings.m_streamIndex)); - } else { - setStreamIndicator("S"); // single channel indicator - } -} - -void AISDemodGUI::leaveEvent(QEvent*) +void AISDemodGUI::leaveEvent(QEvent* event) { m_channelMarker.setHighlighted(false); + ChannelGUI::leaveEvent(event); } -void AISDemodGUI::enterEvent(QEvent*) +void AISDemodGUI::enterEvent(QEvent* event) { m_channelMarker.setHighlighted(true); + ChannelGUI::enterEvent(event); } void AISDemodGUI::tick() @@ -756,3 +780,26 @@ void AISDemodGUI::on_logOpen_clicked() } } } + +void AISDemodGUI::makeUIConnections() +{ + QObject::connect(ui->deltaFrequency, &ValueDialZ::changed, this, &AISDemodGUI::on_deltaFrequency_changed); + QObject::connect(ui->rfBW, &QSlider::valueChanged, this, &AISDemodGUI::on_rfBW_valueChanged); + QObject::connect(ui->fmDev, &QSlider::valueChanged, this, &AISDemodGUI::on_fmDev_valueChanged); + QObject::connect(ui->threshold, &QDial::valueChanged, this, &AISDemodGUI::on_threshold_valueChanged); + QObject::connect(ui->filterMMSI, &QLineEdit::editingFinished, this, &AISDemodGUI::on_filterMMSI_editingFinished); + QObject::connect(ui->clearTable, &QPushButton::clicked, this, &AISDemodGUI::on_clearTable_clicked); + QObject::connect(ui->udpEnabled, &QCheckBox::clicked, this, &AISDemodGUI::on_udpEnabled_clicked); + QObject::connect(ui->udpAddress, &QLineEdit::editingFinished, this, &AISDemodGUI::on_udpAddress_editingFinished); + QObject::connect(ui->udpPort, &QLineEdit::editingFinished, this, &AISDemodGUI::on_udpPort_editingFinished); + QObject::connect(ui->udpFormat, QOverload::of(&QComboBox::currentIndexChanged), this, &AISDemodGUI::on_udpFormat_currentIndexChanged); + QObject::connect(ui->messages, &QTableWidget::cellDoubleClicked, this, &AISDemodGUI::on_messages_cellDoubleClicked); + QObject::connect(ui->logEnable, &ButtonSwitch::clicked, this, &AISDemodGUI::on_logEnable_clicked); + QObject::connect(ui->logFilename, &QToolButton::clicked, this, &AISDemodGUI::on_logFilename_clicked); + QObject::connect(ui->logOpen, &QToolButton::clicked, this, &AISDemodGUI::on_logOpen_clicked); +} + +void AISDemodGUI::updateAbsoluteCenterFrequency() +{ + setStatusFrequency(m_deviceCenterFrequency + m_settings.m_inputFrequencyOffset); +} diff --git a/plugins/channelrx/demodais/aisdemodgui.h b/plugins/channelrx/demodais/aisdemodgui.h index ac6a329ee..7209daaf1 100644 --- a/plugins/channelrx/demodais/aisdemodgui.h +++ b/plugins/channelrx/demodais/aisdemodgui.h @@ -37,7 +37,6 @@ class PluginAPI; class DeviceUISet; class BasebandSampleSink; class ScopeVis; -class ScopeVisXY; class AISDemod; class AISDemodGUI; @@ -58,6 +57,17 @@ public: QByteArray serialize() const; bool deserialize(const QByteArray& data); virtual MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; } + virtual void setWorkspaceIndex(int index) { m_settings.m_workspaceIndex = index; }; + virtual int getWorkspaceIndex() const { return m_settings.m_workspaceIndex; }; + virtual void setGeometryBytes(const QByteArray& blob) { m_settings.m_geometryBytes = blob; }; + virtual QByteArray getGeometryBytes() const { return m_settings.m_geometryBytes; }; + virtual QString getTitle() const { return m_settings.m_title; }; + virtual QColor getTitleColor() const { return m_settings.m_rgbColor; }; + virtual void zetHidden(bool hidden) { m_settings.m_hidden = hidden; } + virtual bool getHidden() const { return m_settings.m_hidden; } + virtual ChannelMarker& getChannelMarker() { return m_channelMarker; } + virtual int getStreamIndex() const { return m_settings.m_streamIndex; } + virtual void setStreamIndex(int streamIndex) { m_settings.m_streamIndex = streamIndex; } public slots: void channelMarkerChangedByCursor(); @@ -70,6 +80,8 @@ private: ChannelMarker m_channelMarker; RollupState m_rollupState; AISDemodSettings m_settings; + qint64 m_deviceCenterFrequency; + int m_basebandSampleRate; bool m_doApplySettings; ScopeVis* m_scopeVis; @@ -86,9 +98,10 @@ private: void blockApplySettings(bool block); void applySettings(bool force = false); void displaySettings(); - void displayStreamIndex(); void messageReceived(const QByteArray& message, const QDateTime& dateTime); bool handleMessage(const Message& message); + void makeUIConnections(); + void updateAbsoluteCenterFrequency(); void leaveEvent(QEvent*); void enterEvent(QEvent*); diff --git a/plugins/channelrx/demodais/aisdemodgui.ui b/plugins/channelrx/demodais/aisdemodgui.ui index 8645357fe..dce05b852 100644 --- a/plugins/channelrx/demodais/aisdemodgui.ui +++ b/plugins/channelrx/demodais/aisdemodgui.ui @@ -1,13 +1,13 @@ AISDemodGUI - + 0 0 - 404 - 764 + 388 + 446 @@ -487,7 +487,7 @@ - 60 + 66 0 @@ -912,9 +912,14 @@ - RollupWidget + ButtonSwitch + QToolButton +
gui/buttonswitch.h
+
+ + RollupContents QWidget -
gui/rollupwidget.h
+
gui/rollupcontents.h
1
@@ -929,11 +934,6 @@
gui/levelmeter.h
1
- - ButtonSwitch - QToolButton -
gui/buttonswitch.h
-
GLScope QWidget diff --git a/plugins/channelrx/demodais/aisdemodsettings.cpp b/plugins/channelrx/demodais/aisdemodsettings.cpp index 9adad474a..b719dfb0e 100644 --- a/plugins/channelrx/demodais/aisdemodsettings.cpp +++ b/plugins/channelrx/demodais/aisdemodsettings.cpp @@ -55,6 +55,8 @@ void AISDemodSettings::resetToDefaults() m_reverseAPIPort = 8888; m_reverseAPIDeviceIndex = 0; m_reverseAPIChannelIndex = 0; + m_workspaceIndex = 0; + m_hidden = false; for (int i = 0; i < AISDEMOD_MESSAGE_COLUMNS; i++) { @@ -100,6 +102,10 @@ QByteArray AISDemodSettings::serialize() const s.writeBlob(25, m_rollupState->serialize()); } + s.writeS32(26, m_workspaceIndex); + s.writeBlob(27, m_geometryBytes); + s.writeBool(28, m_hidden); + for (int i = 0; i < AISDEMOD_MESSAGE_COLUMNS; i++) s.writeS32(100 + i, m_messageColumnIndexes[i]); for (int i = 0; i < AISDEMOD_MESSAGE_COLUMNS; i++) @@ -183,6 +189,10 @@ bool AISDemodSettings::deserialize(const QByteArray& data) m_rollupState->deserialize(bytetmp); } + d.readS32(26, &m_workspaceIndex, 0); + d.readBlob(27, &m_geometryBytes); + d.readBool(28, &m_hidden, false); + for (int i = 0; i < AISDEMOD_MESSAGE_COLUMNS; i++) { d.readS32(100 + i, &m_messageColumnIndexes[i], i); } diff --git a/plugins/channelrx/demodais/aisdemodsettings.h b/plugins/channelrx/demodais/aisdemodsettings.h index 02fd0396b..2d22273cc 100644 --- a/plugins/channelrx/demodais/aisdemodsettings.h +++ b/plugins/channelrx/demodais/aisdemodsettings.h @@ -61,6 +61,9 @@ struct AISDemodSettings uint16_t m_reverseAPIChannelIndex; Serializable *m_scopeGUI; Serializable *m_rollupState; + int m_workspaceIndex; + QByteArray m_geometryBytes; + bool m_hidden; int m_messageColumnIndexes[AISDEMOD_MESSAGE_COLUMNS];//!< How the columns are ordered in the table int m_messageColumnSizes[AISDEMOD_MESSAGE_COLUMNS]; //!< Size of the columns in the table diff --git a/plugins/channelrx/demodais/readme.md b/plugins/channelrx/demodais/readme.md index cb9104c90..f0b479a5d 100644 --- a/plugins/channelrx/demodais/readme.md +++ b/plugins/channelrx/demodais/readme.md @@ -16,6 +16,8 @@ The AIS specification is ITU-R M.1371-5: https://www.itu.int/dms_pubrec/itu-r/re

Interface

+The top and bottom bars of the channel window are described [here](../../../sdrgui/channel/readme.md) + ![AIS Demodulator plugin GUI](../../../doc/img/AISDemod_plugin.png)

1: Frequency shift from center frequency of reception

diff --git a/plugins/channelrx/demodam/amdemod.cpp b/plugins/channelrx/demodam/amdemod.cpp index 2bbfbd814..dbbdda00c 100644 --- a/plugins/channelrx/demodam/amdemod.cpp +++ b/plugins/channelrx/demodam/amdemod.cpp @@ -28,6 +28,7 @@ #include #include "SWGChannelSettings.h" +#include "SWGWorkspaceInfo.h" #include "SWGAMDemodSettings.h" #include "SWGChannelReport.h" #include "SWGAMDemodReport.h" @@ -113,6 +114,18 @@ AMDemod::~AMDemod() delete m_basebandSink; } +void AMDemod::setDeviceAPI(DeviceAPI *deviceAPI) +{ + if (deviceAPI != m_deviceAPI) + { + m_deviceAPI->removeChannelSinkAPI(this); + m_deviceAPI->removeChannelSink(this); + m_deviceAPI = deviceAPI; + m_deviceAPI->addChannelSink(this); + m_deviceAPI->addChannelSinkAPI(this); + } +} + uint32_t AMDemod::getNumberOfDeviceStreams() const { return m_deviceAPI->getNbSourceStreams(); @@ -167,6 +180,10 @@ bool AMDemod::handleMessage(const Message& cmd) qDebug() << "AMDemod::handleMessage: DSPSignalNotification"; m_basebandSink->getInputMessageQueue()->push(rep); + if (getMessageQueueToGUI()) { + getMessageQueueToGUI()->push(new DSPSignalNotification(notif)); + } + return true; } else if (MainCore::MsgChannelDemodQuery::match(cmd)) @@ -342,6 +359,15 @@ int AMDemod::webapiSettingsGet( return 200; } +int AMDemod::webapiWorkspaceGet( + SWGSDRangel::SWGWorkspaceInfo& response, + QString& errorMessage) +{ + (void) errorMessage; + response.setIndex(m_settings.m_workspaceIndex); + return 200; +} + int AMDemod::webapiSettingsPutPatch( bool force, const QStringList& channelSettingsKeys, diff --git a/plugins/channelrx/demodam/amdemod.h b/plugins/channelrx/demodam/amdemod.h index 145f36748..ed1d49561 100644 --- a/plugins/channelrx/demodam/amdemod.h +++ b/plugins/channelrx/demodam/amdemod.h @@ -64,6 +64,8 @@ public: AMDemod(DeviceAPI *deviceAPI); virtual ~AMDemod(); virtual void destroy() { delete this; } + virtual void setDeviceAPI(DeviceAPI *deviceAPI); + virtual DeviceAPI *getDeviceAPI() { return m_deviceAPI; } using BasebandSampleSink::feed; virtual void feed(const SampleVector::const_iterator& begin, const SampleVector::const_iterator& end, bool po); @@ -95,6 +97,10 @@ public: SWGSDRangel::SWGChannelSettings& response, QString& errorMessage); + virtual int webapiWorkspaceGet( + SWGSDRangel::SWGWorkspaceInfo& response, + QString& errorMessage); + virtual int webapiSettingsPutPatch( bool force, const QStringList& channelSettingsKeys, diff --git a/plugins/channelrx/demodam/amdemodgui.cpp b/plugins/channelrx/demodam/amdemodgui.cpp index c37dfb739..f50ee0de6 100644 --- a/plugins/channelrx/demodam/amdemodgui.cpp +++ b/plugins/channelrx/demodam/amdemodgui.cpp @@ -18,23 +18,24 @@ #include #include #include +#include #include "amdemodgui.h" #include "amdemodssbdialog.h" #include "device/deviceuiset.h" #include "dsp/dspengine.h" -#include "ui_amdemodgui.h" +#include "dsp/dspcommands.h" #include "plugin/pluginapi.h" #include "util/simpleserializer.h" #include "util/db.h" #include "gui/basicchannelsettingsdialog.h" #include "gui/devicestreamselectiondialog.h" -#include "dsp/dspengine.h" #include "gui/crightclickenabler.h" #include "gui/audioselectdialog.h" #include "maincore.h" +#include "ui_amdemodgui.h" #include "amdemod.h" AMDemodGUI* AMDemodGUI::create(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, BasebandSampleSink *rxChannel) @@ -72,6 +73,14 @@ bool AMDemodGUI::deserialize(const QByteArray& data) } } +void AMDemodGUI::resizeEvent(QResizeEvent* size) +{ + int maxWidth = getRollupContents()->maximumWidth(); + int minHeight = getRollupContents()->minimumHeight() + getAdditionalHeight(); + resize(width() < maxWidth ? width() : maxWidth, minHeight); + size->accept(); +} + bool AMDemodGUI::handleMessage(const Message& message) { if (AMDemod::MsgConfigureAMDemod::match(message)) @@ -85,6 +94,17 @@ bool AMDemodGUI::handleMessage(const Message& message) blockApplySettings(false); return true; } + else if (DSPSignalNotification::match(message)) + { + DSPSignalNotification& notif = (DSPSignalNotification&) message; + m_deviceCenterFrequency = notif.getCenterFrequency(); + m_basebandSampleRate = notif.getSampleRate(); + ui->deltaFrequency->setValueRange(false, 7, -m_basebandSampleRate/2, m_basebandSampleRate/2); + ui->deltaFrequencyLabel->setToolTip(tr("Range %1 %L2 Hz").arg(QChar(0xB1)).arg(m_basebandSampleRate/2)); + updateAbsoluteCenterFrequency(); + + return true; + } return false; } @@ -118,6 +138,7 @@ void AMDemodGUI::on_deltaFrequency_changed(qint64 value) { m_channelMarker.setCenterFrequency(value); m_settings.m_inputFrequencyOffset = m_channelMarker.getCenterFrequency(); + updateAbsoluteCenterFrequency(); applySettings(); } @@ -182,7 +203,7 @@ void AMDemodGUI::onWidgetRolled(QWidget* widget, bool rollDown) m_nfmDemod->setSpectrum(m_threadedSampleSink->getMessageQueue(), rollDown); */ - saveState(m_rollupState); + getRollupContents()->saveState(m_rollupState); applySettings(); } @@ -196,10 +217,17 @@ void AMDemodGUI::onMenuDialogCalled(const QPoint &p) dialog.setReverseAPIPort(m_settings.m_reverseAPIPort); dialog.setReverseAPIDeviceIndex(m_settings.m_reverseAPIDeviceIndex); dialog.setReverseAPIChannelIndex(m_settings.m_reverseAPIChannelIndex); + dialog.setDefaultTitle(m_displayedName); + + if (m_deviceUISet->m_deviceMIMOEngine) + { + dialog.setNumberOfStreams(m_amDemod->getNumberOfDeviceStreams()); + dialog.setStreamIndex(m_settings.m_streamIndex); + } + dialog.move(p); dialog.exec(); - m_settings.m_inputFrequencyOffset = m_channelMarker.getCenterFrequency(); m_settings.m_rgbColor = m_channelMarker.getColor().rgb(); m_settings.m_title = m_channelMarker.getTitle(); m_settings.m_useReverseAPI = dialog.useReverseAPI(); @@ -209,22 +237,17 @@ void AMDemodGUI::onMenuDialogCalled(const QPoint &p) m_settings.m_reverseAPIChannelIndex = dialog.getReverseAPIChannelIndex(); setWindowTitle(m_settings.m_title); + setTitle(m_channelMarker.getTitle()); setTitleColor(m_settings.m_rgbColor); - applySettings(); - } - else if ((m_contextMenuType == ContextMenuStreamSettings) && (m_deviceUISet->m_deviceMIMOEngine)) - { - DeviceStreamSelectionDialog dialog(this); - dialog.setNumberOfStreams(m_amDemod->getNumberOfDeviceStreams()); - dialog.setStreamIndex(m_settings.m_streamIndex); - dialog.move(p); - dialog.exec(); + if (m_deviceUISet->m_deviceMIMOEngine) + { + m_settings.m_streamIndex = dialog.getSelectedStreamIndex(); + m_channelMarker.clearStreamIndexes(); + m_channelMarker.addStreamIndex(m_settings.m_streamIndex); + updateIndexLabel(); + } - m_settings.m_streamIndex = dialog.getSelectedStreamIndex(); - m_channelMarker.clearStreamIndexes(); - m_channelMarker.addStreamIndex(m_settings.m_streamIndex); - displayStreamIndex(); applySettings(); } @@ -237,16 +260,21 @@ AMDemodGUI::AMDemodGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, BasebandS m_pluginAPI(pluginAPI), m_deviceUISet(deviceUISet), m_channelMarker(this), + m_deviceCenterFrequency(0), + m_basebandSampleRate(1), m_doApplySettings(true), m_squelchOpen(false), m_audioSampleRate(-1), m_samUSB(true), m_tickCount(0) { - ui->setupUi(this); - m_helpURL = "plugins/channelrx/demodam/readme.md"; setAttribute(Qt::WA_DeleteOnClose, true); - connect(this, SIGNAL(widgetRolled(QWidget*,bool)), this, SLOT(onWidgetRolled(QWidget*,bool))); + m_helpURL = "plugins/channelrx/demodam/readme.md"; + RollupContents *rollupContents = getRollupContents(); + ui->setupUi(rollupContents); + setSizePolicy(rollupContents->sizePolicy()); + rollupContents->arrangeRollups(); + connect(rollupContents, SIGNAL(widgetRolled(QWidget*,bool)), this, SLOT(onWidgetRolled(QWidget*,bool))); connect(this, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(onMenuDialogCalled(const QPoint &))); m_amDemod = reinterpret_cast(rxChannel); @@ -278,7 +306,6 @@ AMDemodGUI::AMDemodGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, BasebandS m_settings.setRollupState(&m_rollupState); m_deviceUISet->addChannelMarker(&m_channelMarker); - m_deviceUISet->addRollupWidget(this); connect(&m_channelMarker, SIGNAL(changedByCursor()), this, SLOT(channelMarkerChangedByCursor())); connect(&m_channelMarker, SIGNAL(highlightedByCursor()), this, SLOT(channelMarkerHighlightedByCursor())); @@ -290,6 +317,7 @@ AMDemodGUI::AMDemodGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, BasebandS m_iconDSBLSB.addPixmap(QPixmap("://lsb.png"), QIcon::Normal, QIcon::On); displaySettings(); + makeUIConnections(); applySettings(true); } @@ -323,6 +351,7 @@ void AMDemodGUI::displaySettings() setTitleColor(m_settings.m_rgbColor); setWindowTitle(m_channelMarker.getTitle()); + setTitle(m_channelMarker.getTitle()); blockApplySettings(true); @@ -371,29 +400,23 @@ void AMDemodGUI::displaySettings() ui->ssb->setIcon(m_iconDSBUSB); } - displayStreamIndex(); + updateIndexLabel(); - restoreState(m_rollupState); + getRollupContents()->restoreState(m_rollupState); + updateAbsoluteCenterFrequency(); blockApplySettings(false); } -void AMDemodGUI::displayStreamIndex() -{ - if (m_deviceUISet->m_deviceMIMOEngine) { - setStreamIndicator(tr("%1").arg(m_settings.m_streamIndex)); - } else { - setStreamIndicator("S"); // single channel indicator - } -} - -void AMDemodGUI::leaveEvent(QEvent*) +void AMDemodGUI::leaveEvent(QEvent* event) { m_channelMarker.setHighlighted(false); + ChannelGUI::leaveEvent(event); } -void AMDemodGUI::enterEvent(QEvent*) +void AMDemodGUI::enterEvent(QEvent* event) { m_channelMarker.setHighlighted(true); + ChannelGUI::enterEvent(event); } void AMDemodGUI::audioSelect() @@ -478,3 +501,19 @@ void AMDemodGUI::tick() m_tickCount++; } +void AMDemodGUI::makeUIConnections() +{ + QObject::connect(ui->deltaFrequency, &ValueDialZ::changed, this, &AMDemodGUI::on_deltaFrequency_changed); + QObject::connect(ui->pll, &QToolButton::toggled, this, &AMDemodGUI::on_pll_toggled); + QObject::connect(ui->ssb, &QToolButton::toggled, this, &AMDemodGUI::on_ssb_toggled); + QObject::connect(ui->bandpassEnable, &ButtonSwitch::toggled, this, &AMDemodGUI::on_bandpassEnable_toggled); + QObject::connect(ui->rfBW, &QSlider::valueChanged, this, &AMDemodGUI::on_rfBW_valueChanged); + QObject::connect(ui->volume, &QSlider::valueChanged, this, &AMDemodGUI::on_volume_valueChanged); + QObject::connect(ui->squelch, &QSlider::valueChanged, this, &AMDemodGUI::on_squelch_valueChanged); + QObject::connect(ui->audioMute, &QToolButton::toggled, this, &AMDemodGUI::on_audioMute_toggled); +} + +void AMDemodGUI::updateAbsoluteCenterFrequency() +{ + setStatusFrequency(m_deviceCenterFrequency + m_settings.m_inputFrequencyOffset); +} diff --git a/plugins/channelrx/demodam/amdemodgui.h b/plugins/channelrx/demodam/amdemodgui.h index 7320227bd..f32db77a2 100644 --- a/plugins/channelrx/demodam/amdemodgui.h +++ b/plugins/channelrx/demodam/amdemodgui.h @@ -31,11 +31,25 @@ public: QByteArray serialize() const; bool deserialize(const QByteArray& data); virtual MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; } + virtual void setWorkspaceIndex(int index) { m_settings.m_workspaceIndex = index; }; + virtual int getWorkspaceIndex() const { return m_settings.m_workspaceIndex; }; + virtual void setGeometryBytes(const QByteArray& blob) { m_settings.m_geometryBytes = blob; }; + virtual QByteArray getGeometryBytes() const { return m_settings.m_geometryBytes; }; + virtual QString getTitle() const { return m_settings.m_title; }; + virtual QColor getTitleColor() const { return m_settings.m_rgbColor; }; + virtual void zetHidden(bool hidden) { m_settings.m_hidden = hidden; } + virtual bool getHidden() const { return m_settings.m_hidden; } + virtual ChannelMarker& getChannelMarker() { return m_channelMarker; } + virtual int getStreamIndex() const { return m_settings.m_streamIndex; } + virtual void setStreamIndex(int streamIndex) { m_settings.m_streamIndex = streamIndex; } public slots: void channelMarkerChangedByCursor(); void channelMarkerHighlightedByCursor(); +protected: + void resizeEvent(QResizeEvent* size); + private: Ui::AMDemodGUI* ui; PluginAPI* m_pluginAPI; @@ -43,6 +57,8 @@ private: ChannelMarker m_channelMarker; RollupState m_rollupState; AMDemodSettings m_settings; + qint64 m_deviceCenterFrequency; + int m_basebandSampleRate; bool m_doApplySettings; AMDemod* m_amDemod; @@ -61,8 +77,9 @@ private: void blockApplySettings(bool block); void applySettings(bool force = false); void displaySettings(); - void displayStreamIndex(); bool handleMessage(const Message& message); + void makeUIConnections(); + void updateAbsoluteCenterFrequency(); void leaveEvent(QEvent*); void enterEvent(QEvent*); diff --git a/plugins/channelrx/demodam/amdemodgui.ui b/plugins/channelrx/demodam/amdemodgui.ui index 2bf40f6b2..a7b361034 100644 --- a/plugins/channelrx/demodam/amdemodgui.ui +++ b/plugins/channelrx/demodam/amdemodgui.ui @@ -1,27 +1,33 @@ AMDemodGUI - + 0 0 - 396 - 170 + 360 + 155 - + 0 0 - 352 + 360 0 + + + 560 + 16777215 + + Liberation Sans @@ -39,13 +45,13 @@ 0 0 - 390 - 131 + 358 + 151 - 350 + 358 0 @@ -428,9 +434,15 @@ - RollupWidget + ValueDialZ QWidget -
gui/rollupwidget.h
+
gui/valuedialz.h
+ 1 +
+ + RollupContents + QWidget +
gui/rollupcontents.h
1
@@ -444,12 +456,6 @@ QToolButton
gui/buttonswitch.h
- - ValueDialZ - QWidget -
gui/valuedialz.h
- 1 -
diff --git a/plugins/channelrx/demodam/amdemodsettings.cpp b/plugins/channelrx/demodam/amdemodsettings.cpp index db6a1950e..8c6de24c9 100644 --- a/plugins/channelrx/demodam/amdemodsettings.cpp +++ b/plugins/channelrx/demodam/amdemodsettings.cpp @@ -49,6 +49,8 @@ void AMDemodSettings::resetToDefaults() m_reverseAPIPort = 8888; m_reverseAPIDeviceIndex = 0; m_reverseAPIChannelIndex = 0; + m_workspaceIndex = 0; + m_hidden = false; } QByteArray AMDemodSettings::serialize() const @@ -80,6 +82,10 @@ QByteArray AMDemodSettings::serialize() const s.writeBlob(19, m_rollupState->serialize()); } + s.writeS32(20, m_workspaceIndex); + s.writeBlob(21, m_geometryBytes); + s.writeBool(22, m_hidden); + return s.final(); } @@ -143,6 +149,10 @@ bool AMDemodSettings::deserialize(const QByteArray& data) m_rollupState->deserialize(bytetmp); } + d.readS32(20, &m_workspaceIndex, 0); + d.readBlob(21, &m_geometryBytes); + d.readBool(22, &m_hidden, false); + return true; } else diff --git a/plugins/channelrx/demodam/amdemodsettings.h b/plugins/channelrx/demodam/amdemodsettings.h index d200eeb06..b925ac596 100644 --- a/plugins/channelrx/demodam/amdemodsettings.h +++ b/plugins/channelrx/demodam/amdemodsettings.h @@ -50,6 +50,9 @@ struct AMDemodSettings uint16_t m_reverseAPIDeviceIndex; uint16_t m_reverseAPIChannelIndex; Serializable *m_rollupState; + int m_workspaceIndex; + QByteArray m_geometryBytes; + bool m_hidden; AMDemodSettings(); void resetToDefaults(); diff --git a/plugins/channelrx/demodam/readme.md b/plugins/channelrx/demodam/readme.md index 418dcce9b..ecd202c03 100644 --- a/plugins/channelrx/demodam/readme.md +++ b/plugins/channelrx/demodam/readme.md @@ -6,6 +6,8 @@ This plugin can be used to listen to a narrowband amplitude modulated signal. "N

Interface

+The top and bottom bars of the channel window are described [here](../../../sdrgui/channel/readme.md) + ![AM Demodulator plugin GUI](../../../doc/img/AMDemod_plugin.png)

1: Frequency shift from center frequency of reception

@@ -40,7 +42,7 @@ If you right click on it it will open a dialog to select the audio output device

7:Bandpass boxcar filter toggle

-Use this button to enable or disable the bandpass boxcar (sharp) filter with low cutoff at 300 Hz and high cutoff at half the RF bandwidth. This may help readability of low signals on air traffic communications but degrades audio on comfortable AM broadcast transmissions. +Use this button to enable or disable the bandpass boxcar (sharp) filter with low cutoff at 300 Hz and high cutoff at half the RF bandwidth. This may help readability of low signals on air traffic communications but degrades audio on comfortable AM broadcast transmissions.

8: RF bandwidth

diff --git a/plugins/channelrx/demodapt/aptdemod.cpp b/plugins/channelrx/demodapt/aptdemod.cpp index 7e0380edb..419fa26bd 100644 --- a/plugins/channelrx/demodapt/aptdemod.cpp +++ b/plugins/channelrx/demodapt/aptdemod.cpp @@ -29,6 +29,7 @@ #include #include "SWGChannelSettings.h" +#include "SWGWorkspaceInfo.h" #include "SWGAPTDemodSettings.h" #include "SWGChannelReport.h" #include "SWGChannelActions.h" @@ -115,6 +116,18 @@ APTDemod::~APTDemod() delete m_basebandSink; } +void APTDemod::setDeviceAPI(DeviceAPI *deviceAPI) +{ + if (deviceAPI != m_deviceAPI) + { + m_deviceAPI->removeChannelSinkAPI(this); + m_deviceAPI->removeChannelSink(this); + m_deviceAPI = deviceAPI; + m_deviceAPI->addChannelSink(this); + m_deviceAPI->addChannelSinkAPI(this); + } +} + uint32_t APTDemod::getNumberOfDeviceStreams() const { return m_deviceAPI->getNbSourceStreams(); @@ -209,8 +222,9 @@ bool APTDemod::handleMessage(const Message& cmd) qDebug() << "APTDemod::handleMessage: DSPSignalNotification"; m_basebandSink->getInputMessageQueue()->push(rep); // Forward to GUI if any - if (m_guiMessageQueue) + if (m_guiMessageQueue) { m_guiMessageQueue->push(new DSPSignalNotification(notif)); + } return true; } @@ -407,6 +421,15 @@ int APTDemod::webapiSettingsGet( return 200; } +int APTDemod::webapiWorkspaceGet( + SWGSDRangel::SWGWorkspaceInfo& response, + QString& errorMessage) +{ + (void) errorMessage; + response.setIndex(m_settings.m_workspaceIndex); + return 200; +} + int APTDemod::webapiSettingsPutPatch( bool force, const QStringList& channelSettingsKeys, diff --git a/plugins/channelrx/demodapt/aptdemod.h b/plugins/channelrx/demodapt/aptdemod.h index 303ade6da..aa580dcc5 100644 --- a/plugins/channelrx/demodapt/aptdemod.h +++ b/plugins/channelrx/demodapt/aptdemod.h @@ -188,6 +188,8 @@ public: APTDemod(DeviceAPI *deviceAPI); virtual ~APTDemod(); virtual void destroy() { delete this; } + virtual void setDeviceAPI(DeviceAPI *deviceAPI); + virtual DeviceAPI *getDeviceAPI() { return m_deviceAPI; } using BasebandSampleSink::feed; virtual void feed(const SampleVector::const_iterator& begin, const SampleVector::const_iterator& end, bool po); @@ -230,6 +232,10 @@ public: SWGSDRangel::SWGChannelSettings& response, QString& errorMessage); + virtual int webapiWorkspaceGet( + SWGSDRangel::SWGWorkspaceInfo& response, + QString& errorMessage); + virtual int webapiSettingsPutPatch( bool force, const QStringList& channelSettingsKeys, diff --git a/plugins/channelrx/demodapt/aptdemodgui.cpp b/plugins/channelrx/demodapt/aptdemodgui.cpp index 7a23c088a..c6d215d0c 100644 --- a/plugins/channelrx/demodapt/aptdemodgui.cpp +++ b/plugins/channelrx/demodapt/aptdemodgui.cpp @@ -274,7 +274,11 @@ bool APTDemodGUI::handleMessage(const Message& message) else if (DSPSignalNotification::match(message)) { DSPSignalNotification& notif = (DSPSignalNotification&) message; + m_deviceCenterFrequency = notif.getCenterFrequency(); m_basebandSampleRate = notif.getSampleRate(); + ui->deltaFrequency->setValueRange(false, 7, -m_basebandSampleRate/2, m_basebandSampleRate/2); + ui->deltaFrequencyLabel->setToolTip(tr("Range %1 %L2 Hz").arg(QChar(0xB1)).arg(m_basebandSampleRate/2)); + updateAbsoluteCenterFrequency(); return true; } @@ -310,6 +314,7 @@ void APTDemodGUI::on_deltaFrequency_changed(qint64 value) { m_channelMarker.setCenterFrequency(value); m_settings.m_inputFrequencyOffset = m_channelMarker.getCenterFrequency(); + updateAbsoluteCenterFrequency(); applySettings(); } @@ -527,7 +532,7 @@ void APTDemodGUI::on_zoomAll_clicked(bool checked) } } -void APTDemodGUI::on_image_zoomed() +void APTDemodGUI::onImageZoomed() { ui->zoomAll->setChecked(false); } @@ -537,7 +542,18 @@ void APTDemodGUI::onWidgetRolled(QWidget* widget, bool rollDown) (void) widget; (void) rollDown; - saveState(m_rollupState); + RollupContents *rollupContents = getRollupContents(); + + if (rollupContents->hasExpandableWidgets()) { + setSizePolicy(sizePolicy().horizontalPolicy(), QSizePolicy::Expanding); + } else { + setSizePolicy(sizePolicy().horizontalPolicy(), QSizePolicy::Fixed); + } + + int h = rollupContents->height() + getAdditionalHeight(); + resize(width(), h); + + rollupContents->saveState(m_rollupState); applySettings(); } @@ -551,6 +567,14 @@ void APTDemodGUI::onMenuDialogCalled(const QPoint &p) dialog.setReverseAPIPort(m_settings.m_reverseAPIPort); dialog.setReverseAPIDeviceIndex(m_settings.m_reverseAPIDeviceIndex); dialog.setReverseAPIChannelIndex(m_settings.m_reverseAPIChannelIndex); + dialog.setDefaultTitle(m_displayedName); + + if (m_deviceUISet->m_deviceMIMOEngine) + { + dialog.setNumberOfStreams(m_aptDemod->getNumberOfDeviceStreams()); + dialog.setStreamIndex(m_settings.m_streamIndex); + } + dialog.move(p); dialog.exec(); @@ -563,22 +587,17 @@ void APTDemodGUI::onMenuDialogCalled(const QPoint &p) m_settings.m_reverseAPIChannelIndex = dialog.getReverseAPIChannelIndex(); setWindowTitle(m_settings.m_title); + setTitle(m_channelMarker.getTitle()); setTitleColor(m_settings.m_rgbColor); - applySettings(); - } - else if ((m_contextMenuType == ContextMenuStreamSettings) && (m_deviceUISet->m_deviceMIMOEngine)) - { - DeviceStreamSelectionDialog dialog(this); - dialog.setNumberOfStreams(m_aptDemod->getNumberOfDeviceStreams()); - dialog.setStreamIndex(m_settings.m_streamIndex); - dialog.move(p); - dialog.exec(); + if (m_deviceUISet->m_deviceMIMOEngine) + { + m_settings.m_streamIndex = dialog.getSelectedStreamIndex(); + m_channelMarker.clearStreamIndexes(); + m_channelMarker.addStreamIndex(m_settings.m_streamIndex); + updateIndexLabel(); + } - m_settings.m_streamIndex = dialog.getSelectedStreamIndex(); - m_channelMarker.clearStreamIndexes(); - m_channelMarker.addStreamIndex(m_settings.m_streamIndex); - displayStreamIndex(); applySettings(); } @@ -591,16 +610,19 @@ APTDemodGUI::APTDemodGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, Baseban m_pluginAPI(pluginAPI), m_deviceUISet(deviceUISet), m_channelMarker(this), + m_deviceCenterFrequency(0), m_doApplySettings(true), m_tickCount(0), m_scene(nullptr), m_pixmapItem(nullptr) { - ui->setupUi(this); - m_helpURL = "plugins/channelrx/demodapt/readme.md"; - setAttribute(Qt::WA_DeleteOnClose, true); - connect(this, SIGNAL(widgetRolled(QWidget*,bool)), this, SLOT(onWidgetRolled(QWidget*,bool))); + m_helpURL = "plugins/channelrx/demodapt/readme.md"; + RollupContents *rollupContents = getRollupContents(); + ui->setupUi(rollupContents); + setSizePolicy(rollupContents->sizePolicy()); + rollupContents->arrangeRollups(); + connect(rollupContents, SIGNAL(widgetRolled(QWidget*,bool)), this, SLOT(onWidgetRolled(QWidget*,bool))); connect(this, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(onMenuDialogCalled(const QPoint &))); m_aptDemod = reinterpret_cast(rxChannel); @@ -626,14 +648,13 @@ APTDemodGUI::APTDemodGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, Baseban m_settings.setRollupState(&m_rollupState); m_deviceUISet->addChannelMarker(&m_channelMarker); - m_deviceUISet->addRollupWidget(this); connect(&m_channelMarker, SIGNAL(changedByCursor()), this, SLOT(channelMarkerChangedByCursor())); connect(&m_channelMarker, SIGNAL(highlightedByCursor()), this, SLOT(channelMarkerHighlightedByCursor())); connect(getInputMessageQueue(), SIGNAL(messageEnqueued()), this, SLOT(handleInputMessages())); m_zoom = new GraphicsViewZoom(ui->image); // Deleted automatically when view is deleted - connect(m_zoom, SIGNAL(zoomed()), this, SLOT(on_image_zoomed())); + connect(m_zoom, SIGNAL(zoomed()), this, SLOT(onImageZoomed())); // Create slightly transparent white background so labels can be seen m_tempScale = new TempScale(); @@ -658,6 +679,7 @@ APTDemodGUI::APTDemodGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, Baseban m_scene->installEventFilter(this); displaySettings(); + makeUIConnections(); applySettings(true); } @@ -740,6 +762,7 @@ void APTDemodGUI::displaySettings() setTitleColor(m_settings.m_rgbColor); setWindowTitle(m_channelMarker.getTitle()); + setTitle(m_channelMarker.getTitle()); blockApplySettings(true); @@ -772,9 +795,10 @@ void APTDemodGUI::displaySettings() displayPalettes(); displayLabels(); - displayStreamIndex(); + updateIndexLabel(); - restoreState(m_rollupState); + getRollupContents()->restoreState(m_rollupState); + updateAbsoluteCenterFrequency(); blockApplySettings(false); } @@ -802,23 +826,16 @@ void APTDemodGUI::displayPalettes() ui->channels->blockSignals(false); } -void APTDemodGUI::displayStreamIndex() -{ - if (m_deviceUISet->m_deviceMIMOEngine) { - setStreamIndicator(tr("%1").arg(m_settings.m_streamIndex)); - } else { - setStreamIndicator("S"); // single channel indicator - } -} - -void APTDemodGUI::leaveEvent(QEvent*) +void APTDemodGUI::leaveEvent(QEvent* event) { m_channelMarker.setHighlighted(false); + ChannelGUI::leaveEvent(event); } -void APTDemodGUI::enterEvent(QEvent*) +void APTDemodGUI::enterEvent(QEvent* event) { m_channelMarker.setHighlighted(true); + ChannelGUI::enterEvent(event); } void APTDemodGUI::tick() @@ -882,3 +899,34 @@ void APTDemodGUI::deleteImageFromMap(const QString &name) messageQueue->push(msg); } } + +void APTDemodGUI::makeUIConnections() +{ + QObject::connect(ui->deltaFrequency, &ValueDialZ::changed, this, &APTDemodGUI::on_deltaFrequency_changed); + QObject::connect(ui->rfBW, &QSlider::valueChanged, this, &APTDemodGUI::on_rfBW_valueChanged); + QObject::connect(ui->fmDev, &QSlider::valueChanged, this, &APTDemodGUI::on_fmDev_valueChanged); + QObject::connect(ui->channels, QOverload::of(&QComboBox::currentIndexChanged), this, &APTDemodGUI::on_channels_currentIndexChanged); + QObject::connect(ui->transparencyThreshold, &QDial::valueChanged, this, &APTDemodGUI::on_transparencyThreshold_valueChanged); + QObject::connect(ui->transparencyThreshold, &QDial::sliderReleased, this, &APTDemodGUI::on_transparencyThreshold_sliderReleased); + QObject::connect(ui->opacityThreshold, &QDial::valueChanged, this, &APTDemodGUI::on_opacityThreshold_valueChanged); + QObject::connect(ui->opacityThreshold, &QDial::sliderReleased, this, &APTDemodGUI::on_opacityThreshold_sliderReleased); + QObject::connect(ui->deleteImageFromMap, &QToolButton::clicked, this, &APTDemodGUI::on_deleteImageFromMap_clicked); + QObject::connect(ui->cropNoise, &ButtonSwitch::clicked, this, &APTDemodGUI::on_cropNoise_clicked); + QObject::connect(ui->denoise, &ButtonSwitch::clicked, this, &APTDemodGUI::on_denoise_clicked); + QObject::connect(ui->linear, &ButtonSwitch::clicked, this, &APTDemodGUI::on_linear_clicked); + QObject::connect(ui->histogram, &ButtonSwitch::clicked, this, &APTDemodGUI::on_histogram_clicked); + QObject::connect(ui->precipitation, &ButtonSwitch::clicked, this, &APTDemodGUI::on_precipitation_clicked); + QObject::connect(ui->flip, &ButtonSwitch::clicked, this, &APTDemodGUI::on_flip_clicked); + QObject::connect(ui->startStop, &ButtonSwitch::clicked, this, &APTDemodGUI::on_startStop_clicked); + QObject::connect(ui->showSettings, &QToolButton::clicked, this, &APTDemodGUI::on_showSettings_clicked); + QObject::connect(ui->resetDecoder, &QToolButton::clicked, this, &APTDemodGUI::on_resetDecoder_clicked); + QObject::connect(ui->saveImage, &QToolButton::clicked, this, &APTDemodGUI::on_saveImage_clicked); + QObject::connect(ui->zoomIn, &QToolButton::clicked, this, &APTDemodGUI::on_zoomIn_clicked); + QObject::connect(ui->zoomOut, &QToolButton::clicked, this, &APTDemodGUI::on_zoomOut_clicked); + QObject::connect(ui->zoomAll, &ButtonSwitch::clicked, this, &APTDemodGUI::on_zoomAll_clicked); +} + +void APTDemodGUI::updateAbsoluteCenterFrequency() +{ + setStatusFrequency(m_deviceCenterFrequency + m_settings.m_inputFrequencyOffset); +} diff --git a/plugins/channelrx/demodapt/aptdemodgui.h b/plugins/channelrx/demodapt/aptdemodgui.h index 368fe4b26..71fc5b2cf 100644 --- a/plugins/channelrx/demodapt/aptdemodgui.h +++ b/plugins/channelrx/demodapt/aptdemodgui.h @@ -75,6 +75,17 @@ public: bool deserialize(const QByteArray& data); virtual MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; } virtual bool eventFilter(QObject *watched, QEvent *event) override; + virtual void setWorkspaceIndex(int index) { m_settings.m_workspaceIndex = index; }; + virtual int getWorkspaceIndex() const { return m_settings.m_workspaceIndex; }; + virtual void setGeometryBytes(const QByteArray& blob) { m_settings.m_geometryBytes = blob; }; + virtual QByteArray getGeometryBytes() const { return m_settings.m_geometryBytes; }; + virtual QString getTitle() const { return m_settings.m_title; }; + virtual QColor getTitleColor() const { return m_settings.m_rgbColor; }; + virtual void zetHidden(bool hidden) { m_settings.m_hidden = hidden; } + virtual bool getHidden() const { return m_settings.m_hidden; } + virtual ChannelMarker& getChannelMarker() { return m_channelMarker; } + virtual int getStreamIndex() const { return m_settings.m_streamIndex; } + virtual void setStreamIndex(int streamIndex) { m_settings.m_streamIndex = streamIndex; } public slots: void channelMarkerChangedByCursor(); @@ -87,6 +98,7 @@ private: ChannelMarker m_channelMarker; RollupState m_rollupState; APTDemodSettings m_settings; + qint64 m_deviceCenterFrequency; bool m_doApplySettings; APTDemod* m_aptDemod; @@ -113,8 +125,10 @@ private: void displaySettings(); void displayPalettes(); void displayLabels(); - void displayStreamIndex(); bool handleMessage(const Message& message); + void makeUIConnections(); + void updateAbsoluteCenterFrequency(); + void deleteImageFromMap(const QString &name); void resetDecoder(); @@ -144,7 +158,7 @@ private slots: void on_zoomIn_clicked(); void on_zoomOut_clicked(); void on_zoomAll_clicked(bool checked=false); - void on_image_zoomed(); + void onImageZoomed(); void onWidgetRolled(QWidget* widget, bool rollDown); void onMenuDialogCalled(const QPoint& p); void handleInputMessages(); diff --git a/plugins/channelrx/demodapt/aptdemodgui.ui b/plugins/channelrx/demodapt/aptdemodgui.ui index e9147bba6..da837aa0a 100644 --- a/plugins/channelrx/demodapt/aptdemodgui.ui +++ b/plugins/channelrx/demodapt/aptdemodgui.ui @@ -1,7 +1,7 @@ APTDemodGUI - + 0 @@ -803,9 +803,9 @@ - RollupWidget + RollupContents QWidget -
gui/rollupwidget.h
+
gui/rollupcontents.h
1
diff --git a/plugins/channelrx/demodapt/aptdemodsettings.cpp b/plugins/channelrx/demodapt/aptdemodsettings.cpp index 36beb2c3b..5e4e9ed6a 100644 --- a/plugins/channelrx/demodapt/aptdemodsettings.cpp +++ b/plugins/channelrx/demodapt/aptdemodsettings.cpp @@ -69,6 +69,8 @@ void APTDemodSettings::resetToDefaults() m_reverseAPIPort = 8888; m_reverseAPIDeviceIndex = 0; m_reverseAPIChannelIndex = 0; + m_workspaceIndex = 0; + m_hidden = false; } QByteArray APTDemodSettings::serialize() const @@ -120,6 +122,9 @@ QByteArray APTDemodSettings::serialize() const s.writeS32(36, m_verticalPixelsPerDegree); s.writeFloat(37, m_satTimeOffset); s.writeFloat(38, m_satYaw); + s.writeS32(39, m_workspaceIndex); + s.writeBlob(40, m_geometryBytes); + s.writeBool(41, m_hidden); return s.final(); } @@ -201,6 +206,9 @@ bool APTDemodSettings::deserialize(const QByteArray& data) d.readS32(36, &m_verticalPixelsPerDegree, 20); d.readFloat(37, &m_satTimeOffset, 0.0f); d.readFloat(38, &m_satYaw, 0.0f); + d.readS32(39, &m_workspaceIndex, 0); + d.readBlob(40, &m_geometryBytes); + d.readBool(41, &m_hidden, false); return true; } diff --git a/plugins/channelrx/demodapt/aptdemodsettings.h b/plugins/channelrx/demodapt/aptdemodsettings.h index 7ed001928..ce42c5e6f 100644 --- a/plugins/channelrx/demodapt/aptdemodsettings.h +++ b/plugins/channelrx/demodapt/aptdemodsettings.h @@ -66,6 +66,9 @@ struct APTDemodSettings uint16_t m_reverseAPIDeviceIndex; uint16_t m_reverseAPIChannelIndex; Serializable *m_rollupState; + int m_workspaceIndex; + QByteArray m_geometryBytes; + bool m_hidden; // The following are really working state, rather than settings QString m_tle; // Satelite two-line elements, from satellite tracker diff --git a/plugins/channelrx/demodapt/readme.md b/plugins/channelrx/demodapt/readme.md index 0a6fcaee0..dc7f5c27c 100644 --- a/plugins/channelrx/demodapt/readme.md +++ b/plugins/channelrx/demodapt/readme.md @@ -18,6 +18,8 @@ The status of the NOAA POES satellites is available at: https://www.ospo.noaa.go

Interface

+The top and bottom bars of the channel window are described [here](../../../sdrgui/channel/readme.md) + ![APT Demodulator plugin GUI](../../../doc/img/APTDemod_plugin_settings.png)

1: Frequency shift from center frequency of reception

@@ -69,7 +71,7 @@ This includes: - Whether to automatically save images on LOS. - Whether a combined image including telemetry should be saved. - Whether separate images of channel A and B, without telemetry, should be saved. - - Whether equidistant cylindrical (plate carrée) project images used for the map, should be saved. + - Whether equidistant cylindrical (plate carr�e) project images used for the map, should be saved. - Path to save automatically saved images in. - The minimum number of scanlines required to be in an image, after noise cropping, for it to be automatically saved. - After how many scanlines image processing is applied and updates sent to the map. Lower values require more CPU power. diff --git a/plugins/channelrx/demodatv/atvdemod.cpp b/plugins/channelrx/demodatv/atvdemod.cpp index 58eddf8b7..28bb15d7c 100644 --- a/plugins/channelrx/demodatv/atvdemod.cpp +++ b/plugins/channelrx/demodatv/atvdemod.cpp @@ -75,6 +75,23 @@ ATVDemod::~ATVDemod() delete m_basebandSink; } +void ATVDemod::setDeviceAPI(DeviceAPI *deviceAPI) +{ + if (deviceAPI != m_deviceAPI) + { + m_deviceAPI->removeChannelSinkAPI(this); + m_deviceAPI->removeChannelSink(this); + m_deviceAPI = deviceAPI; + m_deviceAPI->addChannelSink(this); + m_deviceAPI->addChannelSinkAPI(this); + } +} + +uint32_t ATVDemod::getNumberOfDeviceStreams() const +{ + return m_deviceAPI->getNbSourceStreams(); +} + void ATVDemod::start() { qDebug("ATVDemod::start"); @@ -127,10 +144,8 @@ bool ATVDemod::handleMessage(const Message& cmd) m_basebandSink->getInputMessageQueue()->push(notifToSink); // Forward to GUI - if (getMessageQueueToGUI()) - { - DSPSignalNotification *notifToGUI = new DSPSignalNotification(notif); - getMessageQueueToGUI()->push(notifToGUI); + if (getMessageQueueToGUI()) { + getMessageQueueToGUI()->push(new DSPSignalNotification(notif)); } return true; diff --git a/plugins/channelrx/demodatv/atvdemod.h b/plugins/channelrx/demodatv/atvdemod.h index e8e246c0c..cafcd7722 100644 --- a/plugins/channelrx/demodatv/atvdemod.h +++ b/plugins/channelrx/demodatv/atvdemod.h @@ -63,6 +63,8 @@ public: ATVDemod(DeviceAPI *deviceAPI); virtual ~ATVDemod(); virtual void destroy() { delete this; } + virtual void setDeviceAPI(DeviceAPI *deviceAPI); + virtual DeviceAPI *getDeviceAPI() { return m_deviceAPI; } using BasebandSampleSink::feed; virtual void feed(const SampleVector::const_iterator& begin, const SampleVector::const_iterator& end, bool po); @@ -95,6 +97,7 @@ public: double getMagSq() const { return m_basebandSink->getMagSq(); } //!< Beware this is scaled to 2^30 bool getBFOLocked() { return m_basebandSink->getBFOLocked(); } void setVideoTabIndex(int videoTabIndex) { m_basebandSink->setVideoTabIndex(videoTabIndex); } + uint32_t getNumberOfDeviceStreams() const; static const char* const m_channelIdURI; static const char* const m_channelId; diff --git a/plugins/channelrx/demodatv/atvdemodgui.cpp b/plugins/channelrx/demodatv/atvdemodgui.cpp index f804b197d..31bcd52da 100644 --- a/plugins/channelrx/demodatv/atvdemodgui.cpp +++ b/plugins/channelrx/demodatv/atvdemodgui.cpp @@ -18,12 +18,14 @@ #include #include +#include #include "atvdemodgui.h" #include "device/deviceuiset.h" #include "dsp/scopevis.h" #include "dsp/glscopesettings.h" +#include "gui/basicchannelsettingsdialog.h" #include "ui_atvdemodgui.h" #include "plugin/pluginapi.h" #include "util/simpleserializer.h" @@ -75,6 +77,14 @@ bool ATVDemodGUI::deserialize(const QByteArray& data) } } +void ATVDemodGUI::resizeEvent(QResizeEvent* size) +{ + int maxWidth = getRollupContents()->maximumWidth(); + int minHeight = getRollupContents()->minimumHeight() + getAdditionalHeight(); + resize(width() < maxWidth ? width() : maxWidth, minHeight); + size->accept(); +} + void ATVDemodGUI::displaySettings() { m_channelMarker.blockSignals(true); @@ -86,7 +96,8 @@ void ATVDemodGUI::displaySettings() setTitleColor(m_settings.m_rgbColor); setWindowTitle(m_channelMarker.getTitle()); - displayStreamIndex(); + setTitle(m_channelMarker.getTitle()); + updateIndexLabel(); m_doApplySettings = false; @@ -119,20 +130,12 @@ void ATVDemodGUI::displaySettings() ui->amScaleOffsetText->setText(QString("%1").arg(m_settings.m_amOffsetFactor)); applySampleRate(); - restoreState(m_rollupState); + getRollupContents()->restoreState(m_rollupState); + updateAbsoluteCenterFrequency(); m_doApplySettings = true; } -void ATVDemodGUI::displayStreamIndex() -{ - if (m_deviceUISet->m_deviceMIMOEngine) { - setStreamIndicator(tr("%1").arg(m_settings.m_streamIndex)); - } else { - setStreamIndicator("S"); // single channel indicator - } -} - void ATVDemodGUI::displayRFBandwidths() { int sliderPosition = m_settings.m_fftBandwidth / m_rfSliderDivisor; @@ -167,6 +170,10 @@ bool ATVDemodGUI::handleMessage(const Message& message) { DSPSignalNotification& notif = (DSPSignalNotification&) message; m_basebandSampleRate = notif.getSampleRate(); + m_deviceCenterFrequency = notif.getCenterFrequency(); + ui->deltaFrequency->setValueRange(false, 8, -m_basebandSampleRate/2, m_basebandSampleRate/2); + ui->deltaFrequencyLabel->setToolTip(tr("Range %1 %L2 Hz").arg(QChar(0xB1)).arg(m_basebandSampleRate/2)); + updateAbsoluteCenterFrequency(); applySampleRate(); return true; @@ -203,12 +210,59 @@ void ATVDemodGUI::handleSourceMessages() } } +void ATVDemodGUI::onMenuDialogCalled(const QPoint &p) +{ + if (m_contextMenuType == ContextMenuChannelSettings) + { + BasicChannelSettingsDialog dialog(&m_channelMarker, this); + dialog.setUseReverseAPI(m_settings.m_useReverseAPI); + dialog.setReverseAPIAddress(m_settings.m_reverseAPIAddress); + dialog.setReverseAPIPort(m_settings.m_reverseAPIPort); + dialog.setReverseAPIDeviceIndex(m_settings.m_reverseAPIDeviceIndex); + dialog.setReverseAPIChannelIndex(m_settings.m_reverseAPIChannelIndex); + dialog.setDefaultTitle(m_displayedName); + + if (m_deviceUISet->m_deviceMIMOEngine) + { + dialog.setNumberOfStreams(m_atvDemod->getNumberOfDeviceStreams()); + dialog.setStreamIndex(m_settings.m_streamIndex); + } + + dialog.move(p); + dialog.exec(); + + m_settings.m_rgbColor = m_channelMarker.getColor().rgb(); + m_settings.m_title = m_channelMarker.getTitle(); + m_settings.m_useReverseAPI = dialog.useReverseAPI(); + m_settings.m_reverseAPIAddress = dialog.getReverseAPIAddress(); + m_settings.m_reverseAPIPort = dialog.getReverseAPIPort(); + m_settings.m_reverseAPIDeviceIndex = dialog.getReverseAPIDeviceIndex(); + m_settings.m_reverseAPIChannelIndex = dialog.getReverseAPIChannelIndex(); + + setWindowTitle(m_settings.m_title); + setTitle(m_channelMarker.getTitle()); + setTitleColor(m_settings.m_rgbColor); + + if (m_deviceUISet->m_deviceMIMOEngine) + { + m_settings.m_streamIndex = dialog.getSelectedStreamIndex(); + m_channelMarker.clearStreamIndexes(); + m_channelMarker.addStreamIndex(m_settings.m_streamIndex); + updateIndexLabel(); + } + + applySettings(); + } + + resetContextMenuType(); +} + void ATVDemodGUI::onWidgetRolled(QWidget* widget, bool rollDown) { (void) widget; (void) rollDown; - saveState(m_rollupState); + getRollupContents()->saveState(m_rollupState); applySettings(); } @@ -218,14 +272,19 @@ ATVDemodGUI::ATVDemodGUI(PluginAPI* objPluginAPI, DeviceUISet *deviceUISet, Base m_pluginAPI(objPluginAPI), m_deviceUISet(deviceUISet), m_channelMarker(this), + m_deviceCenterFrequency(0), m_doApplySettings(false), m_intTickCount(0), m_basebandSampleRate(48000) { - ui->setupUi(this); - m_helpURL = "plugins/channelrx/demodatv/readme.md"; setAttribute(Qt::WA_DeleteOnClose, true); - connect(this, SIGNAL(widgetRolled(QWidget*,bool)), this, SLOT(onWidgetRolled(QWidget*,bool))); + m_helpURL = "plugins/channelrx/demodatv/readme.md"; + RollupContents *rollupContents = getRollupContents(); + ui->setupUi(rollupContents); + setSizePolicy(rollupContents->sizePolicy()); + rollupContents->arrangeRollups(); + connect(rollupContents, SIGNAL(widgetRolled(QWidget*,bool)), this, SLOT(onWidgetRolled(QWidget*,bool))); + connect(this, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(onMenuDialogCalled(const QPoint &))); m_atvDemod = (ATVDemod*) rxChannel; m_atvDemod->setMessageQueueToGUI(getInputMessageQueue()); @@ -253,7 +312,6 @@ ATVDemodGUI::ATVDemodGUI(PluginAPI* objPluginAPI, DeviceUISet *deviceUISet, Base setTitleColor(m_channelMarker.getColor()); m_deviceUISet->addChannelMarker(&m_channelMarker); - m_deviceUISet->addRollupWidget(this); ui->scopeGUI->setBuddies(m_scopeVis->getInputMessageQueue(), m_scopeVis, ui->glScope); @@ -278,6 +336,8 @@ ATVDemodGUI::ATVDemodGUI(PluginAPI* objPluginAPI, DeviceUISet *deviceUISet, Base QChar delta = QChar(0x94, 0x03); ui->fmDeviationLabel->setText(delta); + + makeUIConnections(); } ATVDemodGUI::~ATVDemodGUI() @@ -358,14 +418,16 @@ void ATVDemodGUI::setRFFiltersSlidersRange(int sampleRate) ui->rfOppBWText->setText(QString("%1k").arg((ui->rfOppBW->value() * m_rfSliderDivisor) / 1000.0, 0, 'f', 0)); } -void ATVDemodGUI::leaveEvent(QEvent*) +void ATVDemodGUI::leaveEvent(QEvent* event) { m_channelMarker.setHighlighted(false); + ChannelGUI::leaveEvent(event); } -void ATVDemodGUI::enterEvent(QEvent*) +void ATVDemodGUI::enterEvent(QEvent* event) { m_channelMarker.setHighlighted(true); + ChannelGUI::enterEvent(event); } void ATVDemodGUI::tick() @@ -495,6 +557,7 @@ void ATVDemodGUI::on_deltaFrequency_changed(qint64 value) { m_settings.m_inputFrequencyOffset = value; m_channelMarker.setCenterFrequency(value); + updateAbsoluteCenterFrequency(); applySettings(); } @@ -564,3 +627,32 @@ void ATVDemodGUI::topTimeUpdate() else ui->topTimeText->setText(tr("%1 s").arg(nominalTopTime * 1.0, 0, 'f', 2)); } + +void ATVDemodGUI::makeUIConnections() +{ + QObject::connect(ui->synchLevel, &QSlider::valueChanged, this, &ATVDemodGUI::on_synchLevel_valueChanged); + QObject::connect(ui->blackLevel, &QSlider::valueChanged, this, &ATVDemodGUI::on_blackLevel_valueChanged); + QObject::connect(ui->hSync, &QCheckBox::clicked, this, &ATVDemodGUI::on_hSync_clicked); + QObject::connect(ui->vSync, &QCheckBox::clicked, this, &ATVDemodGUI::on_vSync_clicked); + QObject::connect(ui->invertVideo, &QCheckBox::clicked, this, &ATVDemodGUI::on_invertVideo_clicked); + QObject::connect(ui->halfImage, &QCheckBox::clicked, this, &ATVDemodGUI::on_halfImage_clicked); + QObject::connect(ui->modulation, QOverload::of(&QComboBox::currentIndexChanged), this, &ATVDemodGUI::on_modulation_currentIndexChanged); + QObject::connect(ui->nbLines, QOverload::of(&QComboBox::currentIndexChanged), this, &ATVDemodGUI::on_nbLines_currentIndexChanged); + QObject::connect(ui->fps, QOverload::of(&QComboBox::currentIndexChanged), this, &ATVDemodGUI::on_fps_currentIndexChanged); + QObject::connect(ui->standard, QOverload::of(&QComboBox::currentIndexChanged), this, &ATVDemodGUI::on_standard_currentIndexChanged); + QObject::connect(ui->reset, &QPushButton::clicked, this, &ATVDemodGUI::on_reset_clicked); + QObject::connect(ui->rfBW, &QSlider::valueChanged, this, &ATVDemodGUI::on_rfBW_valueChanged); + QObject::connect(ui->rfOppBW, &QSlider::valueChanged, this, &ATVDemodGUI::on_rfOppBW_valueChanged); + QObject::connect(ui->rfFiltering, &ButtonSwitch::toggled, this, &ATVDemodGUI::on_rfFiltering_toggled); + QObject::connect(ui->deltaFrequency, &ValueDialZ::changed, this, &ATVDemodGUI::on_deltaFrequency_changed); + QObject::connect(ui->bfo, &QDial::valueChanged, this, &ATVDemodGUI::on_bfo_valueChanged); + QObject::connect(ui->fmDeviation, &QDial::valueChanged, this, &ATVDemodGUI::on_fmDeviation_valueChanged); + QObject::connect(ui->amScaleFactor, &QDial::valueChanged, this, &ATVDemodGUI::on_amScaleFactor_valueChanged); + QObject::connect(ui->amScaleOffset, &QDial::valueChanged, this, &ATVDemodGUI::on_amScaleOffset_valueChanged); + QObject::connect(ui->screenTabWidget, &QTabWidget::currentChanged, this, &ATVDemodGUI::on_screenTabWidget_currentChanged); +} + +void ATVDemodGUI::updateAbsoluteCenterFrequency() +{ + setStatusFrequency(m_deviceCenterFrequency + m_settings.m_inputFrequencyOffset); +} diff --git a/plugins/channelrx/demodatv/atvdemodgui.h b/plugins/channelrx/demodatv/atvdemodgui.h index cadfa42a0..d950a0b1e 100644 --- a/plugins/channelrx/demodatv/atvdemodgui.h +++ b/plugins/channelrx/demodatv/atvdemodgui.h @@ -50,11 +50,25 @@ public: QByteArray serialize() const; bool deserialize(const QByteArray& arrData); virtual MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; } + virtual void setWorkspaceIndex(int index) { m_settings.m_workspaceIndex = index; }; + virtual int getWorkspaceIndex() const { return m_settings.m_workspaceIndex; }; + virtual void setGeometryBytes(const QByteArray& blob) { m_settings.m_geometryBytes = blob; }; + virtual QByteArray getGeometryBytes() const { return m_settings.m_geometryBytes; }; + virtual QString getTitle() const { return m_settings.m_title; }; + virtual QColor getTitleColor() const { return m_settings.m_rgbColor; }; + virtual void zetHidden(bool hidden) { m_settings.m_hidden = hidden; } + virtual bool getHidden() const { return m_settings.m_hidden; } + virtual ChannelMarker& getChannelMarker() { return m_channelMarker; } + virtual int getStreamIndex() const { return m_settings.m_streamIndex; } + virtual void setStreamIndex(int streamIndex) { m_settings.m_streamIndex = streamIndex; } public slots: void channelMarkerChangedByCursor(); void channelMarkerHighlightedByCursor(); +protected: + void resizeEvent(QResizeEvent* size); + private: Ui::ATVDemodGUI* ui; PluginAPI* m_pluginAPI; @@ -63,6 +77,7 @@ private: RollupState m_rollupState; ATVDemod* m_atvDemod; ATVDemodSettings m_settings; + qint64 m_deviceCenterFrequency; bool m_doApplySettings; @@ -80,7 +95,6 @@ private: void applySettings(bool force = false); void displaySettings(); - void displayStreamIndex(); void displayRFBandwidths(); void applySampleRate(); void setChannelMarkerBandwidth(); @@ -88,6 +102,8 @@ private: void lineTimeUpdate(); void topTimeUpdate(); bool handleMessage(const Message& objMessage); + void makeUIConnections(); + void updateAbsoluteCenterFrequency(); void leaveEvent(QEvent*); void enterEvent(QEvent*); @@ -95,6 +111,7 @@ private: private slots: void handleSourceMessages(); void onWidgetRolled(QWidget* widget, bool rollDown); + void onMenuDialogCalled(const QPoint& p); void tick(); void on_synchLevel_valueChanged(int value); void on_blackLevel_valueChanged(int value); diff --git a/plugins/channelrx/demodatv/atvdemodgui.ui b/plugins/channelrx/demodatv/atvdemodgui.ui index 8590ee373..d0678c3dd 100644 --- a/plugins/channelrx/demodatv/atvdemodgui.ui +++ b/plugins/channelrx/demodatv/atvdemodgui.ui @@ -1,7 +1,7 @@ ATVDemodGUI - + 0 @@ -1155,9 +1155,9 @@ - RollupWidget + RollupContents QWidget -
gui/rollupwidget.h
+
gui/rollupcontents.h
1
diff --git a/plugins/channelrx/demodatv/atvdemodsettings.cpp b/plugins/channelrx/demodatv/atvdemodsettings.cpp index 82b689946..2d914e7ca 100644 --- a/plugins/channelrx/demodatv/atvdemodsettings.cpp +++ b/plugins/channelrx/demodatv/atvdemodsettings.cpp @@ -54,6 +54,13 @@ void ATVDemodSettings::resetToDefaults() m_udpAddress = "127.0.0.1"; m_udpPort = 9999; m_streamIndex = 0; + m_useReverseAPI = false; + m_reverseAPIAddress = "127.0.0.1"; + m_reverseAPIPort = 8888; + m_reverseAPIDeviceIndex = 0; + m_reverseAPIChannelIndex = 0; + m_workspaceIndex = 0; + m_hidden = false; } QByteArray ATVDemodSettings::serialize() const @@ -91,6 +98,15 @@ QByteArray ATVDemodSettings::serialize() const s.writeBlob(25, m_rollupState->serialize()); } + s.writeBool(26, m_useReverseAPI); + s.writeString(27, m_reverseAPIAddress); + s.writeU32(28, m_reverseAPIPort); + s.writeU32(29, m_reverseAPIDeviceIndex); + s.writeU32(30, m_reverseAPIChannelIndex); + s.writeS32(31, m_workspaceIndex); + s.writeBlob(32, m_geometryBytes); + s.writeBool(33, m_hidden); + return s.final(); } @@ -108,6 +124,7 @@ bool ATVDemodSettings::deserialize(const QByteArray& arrData) { QByteArray bytetmp; int tmp; + uint32_t utmp; d.readS64(1, &m_inputFrequencyOffset, 0); // TODO: rgb color @@ -152,6 +169,24 @@ bool ATVDemodSettings::deserialize(const QByteArray& arrData) m_rollupState->deserialize(bytetmp); } + d.readBool(26, &m_useReverseAPI, false); + d.readString(27, &m_reverseAPIAddress, "127.0.0.1"); + d.readU32(28, &utmp, 0); + + if ((utmp > 1023) && (utmp < 65535)) { + m_reverseAPIPort = utmp; + } else { + m_reverseAPIPort = 8888; + } + + d.readU32(29, &utmp, 0); + m_reverseAPIDeviceIndex = utmp > 99 ? 99 : utmp; + d.readU32(30, &utmp, 0); + m_reverseAPIChannelIndex = utmp > 99 ? 99 : utmp; + d.readS32(31, &m_workspaceIndex, 0); + d.readBlob(32, &m_geometryBytes); + d.readBool(33, &m_hidden, false); + return true; } else diff --git a/plugins/channelrx/demodatv/atvdemodsettings.h b/plugins/channelrx/demodatv/atvdemodsettings.h index 64f8f5275..c20afe176 100644 --- a/plugins/channelrx/demodatv/atvdemodsettings.h +++ b/plugins/channelrx/demodatv/atvdemodsettings.h @@ -74,7 +74,15 @@ struct ATVDemodSettings uint16_t m_udpPort; Serializable *m_channelMarker; int m_streamIndex; + bool m_useReverseAPI; + QString m_reverseAPIAddress; + uint16_t m_reverseAPIPort; + uint16_t m_reverseAPIDeviceIndex; + uint16_t m_reverseAPIChannelIndex; Serializable *m_rollupState; + int m_workspaceIndex; + QByteArray m_geometryBytes; + bool m_hidden; ATVDemodSettings(); void resetToDefaults(); diff --git a/plugins/channelrx/demodatv/readme.md b/plugins/channelrx/demodatv/readme.md index 2419d67da..50119b740 100644 --- a/plugins/channelrx/demodatv/readme.md +++ b/plugins/channelrx/demodatv/readme.md @@ -10,6 +10,8 @@ Experimental modes with smaller number of lines and FPS values can be used in co

Interface

+The top and bottom bars of the channel window are described [here](../../../sdrgui/channel/readme.md) + ![ATV Demodulator plugin GUI](../../../doc/img/ATVDemod_plugin.png) The interface is divided into three collapsable sections: diff --git a/plugins/channelrx/demodbfm/bfmdemod.cpp b/plugins/channelrx/demodbfm/bfmdemod.cpp index 64d8fad7c..ee65f9a1f 100644 --- a/plugins/channelrx/demodbfm/bfmdemod.cpp +++ b/plugins/channelrx/demodbfm/bfmdemod.cpp @@ -26,6 +26,7 @@ #include #include "SWGChannelSettings.h" +#include "SWGWorkspaceInfo.h" #include "SWGBFMDemodSettings.h" #include "SWGChannelReport.h" #include "SWGBFMDemodReport.h" @@ -96,6 +97,18 @@ BFMDemod::~BFMDemod() delete m_thread; } +void BFMDemod::setDeviceAPI(DeviceAPI *deviceAPI) +{ + if (deviceAPI != m_deviceAPI) + { + m_deviceAPI->removeChannelSinkAPI(this); + m_deviceAPI->removeChannelSink(this); + m_deviceAPI = deviceAPI; + m_deviceAPI->addChannelSink(this); + m_deviceAPI->addChannelSinkAPI(this); + } +} + uint32_t BFMDemod::getNumberOfDeviceStreams() const { return m_deviceAPI->getNbSourceStreams(); @@ -151,6 +164,10 @@ bool BFMDemod::handleMessage(const Message& cmd) qDebug() << "BFMDemod::handleMessage: DSPSignalNotification"; m_basebandSink->getInputMessageQueue()->push(rep); + if (getMessageQueueToGUI()) { + getMessageQueueToGUI()->push(new DSPSignalNotification(notif)); + } + return true; } else @@ -291,6 +308,15 @@ int BFMDemod::webapiSettingsGet( return 200; } +int BFMDemod::webapiWorkspaceGet( + SWGSDRangel::SWGWorkspaceInfo& response, + QString& errorMessage) +{ + (void) errorMessage; + response.setIndex(m_settings.m_workspaceIndex); + return 200; +} + int BFMDemod::webapiSettingsPutPatch( bool force, const QStringList& channelSettingsKeys, diff --git a/plugins/channelrx/demodbfm/bfmdemod.h b/plugins/channelrx/demodbfm/bfmdemod.h index 0d6b654af..ccead9535 100644 --- a/plugins/channelrx/demodbfm/bfmdemod.h +++ b/plugins/channelrx/demodbfm/bfmdemod.h @@ -70,6 +70,8 @@ public: BFMDemod(DeviceAPI *deviceAPI); virtual ~BFMDemod(); virtual void destroy() { delete this; } + virtual void setDeviceAPI(DeviceAPI *deviceAPI); + virtual DeviceAPI *getDeviceAPI() { return m_deviceAPI; } SpectrumVis *getSpectrumVis() { return &m_spectrumVis; } void setBasebandMessageQueueToGUI(MessageQueue *messageQueue) { m_basebandSink->setMessageQueueToGUI(messageQueue); } @@ -119,6 +121,10 @@ public: SWGSDRangel::SWGChannelSettings& response, QString& errorMessage); + virtual int webapiWorkspaceGet( + SWGSDRangel::SWGWorkspaceInfo& response, + QString& errorMessage); + virtual int webapiSettingsPutPatch( bool force, const QStringList& channelSettingsKeys, diff --git a/plugins/channelrx/demodbfm/bfmdemodgui.cpp b/plugins/channelrx/demodbfm/bfmdemodgui.cpp index 3405b11f2..1eeddc372 100644 --- a/plugins/channelrx/demodbfm/bfmdemodgui.cpp +++ b/plugins/channelrx/demodbfm/bfmdemodgui.cpp @@ -29,6 +29,7 @@ #include "dsp/dspengine.h" #include "dsp/spectrumvis.h" +#include "dsp/dspcommands.h" #include "gui/glspectrum.h" #include "plugin/pluginapi.h" #include "util/simpleserializer.h" @@ -110,6 +111,16 @@ bool BFMDemodGUI::handleMessage(const Message& message) blockApplySettings(false); return true; } + else if (DSPSignalNotification::match(message)) + { + DSPSignalNotification& notif = (DSPSignalNotification&) message; + m_deviceCenterFrequency = notif.getCenterFrequency(); + m_basebandSampleRate = notif.getSampleRate(); + ui->deltaFrequency->setValueRange(false, 8, -m_basebandSampleRate/2, m_basebandSampleRate/2); + ui->deltaFrequencyLabel->setToolTip(tr("Range %1 %L2 Hz").arg(QChar(0xB1)).arg(m_basebandSampleRate/2)); + updateAbsoluteCenterFrequency(); + return true; + } else { return false; @@ -145,6 +156,7 @@ void BFMDemodGUI::on_deltaFrequency_changed(qint64 value) { m_channelMarker.setCenterFrequency(value); m_settings.m_inputFrequencyOffset = m_channelMarker.getCenterFrequency(); + updateAbsoluteCenterFrequency(); applySettings(); } @@ -304,7 +316,18 @@ void BFMDemodGUI::onWidgetRolled(QWidget* widget, bool rollDown) (void) widget; (void) rollDown; - saveState(m_rollupState); + RollupContents *rollupContents = getRollupContents(); + + if (rollupContents->hasExpandableWidgets()) { + setSizePolicy(sizePolicy().horizontalPolicy(), QSizePolicy::Expanding); + } else { + setSizePolicy(sizePolicy().horizontalPolicy(), QSizePolicy::Fixed); + } + + int h = rollupContents->height() + getAdditionalHeight(); + resize(width(), h); + + rollupContents->saveState(m_rollupState); applySettings(); } @@ -318,11 +341,17 @@ void BFMDemodGUI::onMenuDialogCalled(const QPoint &p) dialog.setReverseAPIPort(m_settings.m_reverseAPIPort); dialog.setReverseAPIDeviceIndex(m_settings.m_reverseAPIDeviceIndex); dialog.setReverseAPIChannelIndex(m_settings.m_reverseAPIChannelIndex); + dialog.setDefaultTitle(m_displayedName); + + if (m_deviceUISet->m_deviceMIMOEngine) + { + dialog.setNumberOfStreams(m_bfmDemod->getNumberOfDeviceStreams()); + dialog.setStreamIndex(m_settings.m_streamIndex); + } dialog.move(p); dialog.exec(); - m_settings.m_inputFrequencyOffset = m_channelMarker.getCenterFrequency(); m_settings.m_rgbColor = m_channelMarker.getColor().rgb(); m_settings.m_title = m_channelMarker.getTitle(); m_settings.m_useReverseAPI = dialog.useReverseAPI(); @@ -332,22 +361,17 @@ void BFMDemodGUI::onMenuDialogCalled(const QPoint &p) m_settings.m_reverseAPIChannelIndex = dialog.getReverseAPIChannelIndex(); setWindowTitle(m_settings.m_title); + setTitle(m_channelMarker.getTitle()); setTitleColor(m_settings.m_rgbColor); - applySettings(); - } - else if ((m_contextMenuType == ContextMenuStreamSettings) && (m_deviceUISet->m_deviceMIMOEngine)) - { - DeviceStreamSelectionDialog dialog(this); - dialog.setNumberOfStreams(m_bfmDemod->getNumberOfDeviceStreams()); - dialog.setStreamIndex(m_settings.m_streamIndex); - dialog.move(p); - dialog.exec(); + if (m_deviceUISet->m_deviceMIMOEngine) + { + m_settings.m_streamIndex = dialog.getSelectedStreamIndex(); + m_channelMarker.clearStreamIndexes(); + m_channelMarker.addStreamIndex(m_settings.m_streamIndex); + updateIndexLabel(); + } - m_settings.m_streamIndex = dialog.getSelectedStreamIndex(); - m_channelMarker.clearStreamIndexes(); - m_channelMarker.addStreamIndex(m_settings.m_streamIndex); - displayStreamIndex(); applySettings(); } @@ -360,12 +384,20 @@ BFMDemodGUI::BFMDemodGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, Baseban m_pluginAPI(pluginAPI), m_deviceUISet(deviceUISet), m_channelMarker(this), + m_deviceCenterFrequency(0), + m_basebandSampleRate(1), m_rdsTimerCount(0), m_radiotext_AB_flag(false), m_rate(625000) { - ui->setupUi(this); + setAttribute(Qt::WA_DeleteOnClose, true); m_helpURL = "plugins/channelrx/demodbfm/readme.md"; + RollupContents *rollupContents = getRollupContents(); + ui->setupUi(rollupContents); + setSizePolicy(rollupContents->sizePolicy()); + rollupContents->arrangeRollups(); + connect(rollupContents, SIGNAL(widgetRolled(QWidget*,bool)), this, SLOT(onWidgetRolled(QWidget*,bool))); + ui->deltaFrequencyLabel->setText(QString("%1f").arg(QChar(0x94, 0x03))); ui->deltaFrequency->setColorMapper(ColorMapper(ColorMapper::GrayGold)); ui->deltaFrequency->setValueRange(false, 8, -99999999, 99999999); @@ -374,8 +406,6 @@ BFMDemodGUI::BFMDemodGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, Baseban CRightClickEnabler *audioMuteRightClickEnabler = new CRightClickEnabler(ui->audioStereo); connect(audioMuteRightClickEnabler, SIGNAL(rightClick(const QPoint &)), this, SLOT(audioSelect())); - 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())); @@ -407,7 +437,6 @@ BFMDemodGUI::BFMDemodGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, Baseban m_settings.setRollupState(&m_rollupState); m_deviceUISet->addChannelMarker(&m_channelMarker); - m_deviceUISet->addRollupWidget(this); connect(&m_channelMarker, SIGNAL(changedByCursor()), this, SLOT(channelMarkerChangedByCursor())); connect(&m_channelMarker, SIGNAL(highlightedByCursor()), this, SLOT(channelMarkerHighlightedByCursor())); @@ -421,6 +450,7 @@ BFMDemodGUI::BFMDemodGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, Baseban rdsUpdateFixedFields(); rdsUpdate(true); displaySettings(); + makeUIConnections(); applySettings(true); } @@ -454,6 +484,7 @@ void BFMDemodGUI::displaySettings() setTitleColor(m_settings.m_rgbColor); setWindowTitle(m_channelMarker.getTitle()); + setTitle(m_channelMarker.getTitle()); blockApplySettings(true); @@ -476,29 +507,23 @@ void BFMDemodGUI::displaySettings() ui->showPilot->setChecked(m_settings.m_showPilot); ui->rds->setChecked(m_settings.m_rdsActive); - displayStreamIndex(); + updateIndexLabel(); - restoreState(m_rollupState); + getRollupContents()->restoreState(m_rollupState); + updateAbsoluteCenterFrequency(); blockApplySettings(false); } -void BFMDemodGUI::displayStreamIndex() -{ - if (m_deviceUISet->m_deviceMIMOEngine) { - setStreamIndicator(tr("%1").arg(m_settings.m_streamIndex)); - } else { - setStreamIndicator("S"); // single channel indicator - } -} - -void BFMDemodGUI::leaveEvent(QEvent*) +void BFMDemodGUI::leaveEvent(QEvent* event) { m_channelMarker.setHighlighted(false); + ChannelGUI::leaveEvent(event); } -void BFMDemodGUI::enterEvent(QEvent*) +void BFMDemodGUI::enterEvent(QEvent* event) { m_channelMarker.setHighlighted(true); + ChannelGUI::enterEvent(event); } void BFMDemodGUI::audioSelect() @@ -829,3 +854,22 @@ void BFMDemodGUI::changeFrequency(qint64 f) qint64 df = m_channelMarker.getCenterFrequency(); qDebug() << "BFMDemodGUI::changeFrequency: " << f - df; } + +void BFMDemodGUI::makeUIConnections() +{ + QObject::connect(ui->deltaFrequency, &ValueDialZ::changed, this, &BFMDemodGUI::on_deltaFrequency_changed); + QObject::connect(ui->rfBW, &QSlider::valueChanged, this, &BFMDemodGUI::on_rfBW_valueChanged); + QObject::connect(ui->afBW, &QSlider::valueChanged, this, &BFMDemodGUI::on_afBW_valueChanged); + QObject::connect(ui->volume, &QSlider::valueChanged, this, &BFMDemodGUI::on_volume_valueChanged); + QObject::connect(ui->squelch, &QSlider::valueChanged, this, &BFMDemodGUI::on_squelch_valueChanged); + QObject::connect(ui->audioStereo, &QToolButton::toggled, this, &BFMDemodGUI::on_audioStereo_toggled); + QObject::connect(ui->lsbStereo, &ButtonSwitch::toggled, this, &BFMDemodGUI::on_lsbStereo_toggled); + QObject::connect(ui->showPilot, &ButtonSwitch::clicked, this, &BFMDemodGUI::on_showPilot_clicked); + QObject::connect(ui->rds, &ButtonSwitch::clicked, this, &BFMDemodGUI::on_rds_clicked); + QObject::connect(ui->clearData, &QPushButton::clicked, this, &BFMDemodGUI::on_clearData_clicked); +} + +void BFMDemodGUI::updateAbsoluteCenterFrequency() +{ + setStatusFrequency(m_deviceCenterFrequency + m_settings.m_inputFrequencyOffset); +} diff --git a/plugins/channelrx/demodbfm/bfmdemodgui.h b/plugins/channelrx/demodbfm/bfmdemodgui.h index b5b561726..7b3f441a3 100644 --- a/plugins/channelrx/demodbfm/bfmdemodgui.h +++ b/plugins/channelrx/demodbfm/bfmdemodgui.h @@ -48,6 +48,17 @@ public: QByteArray serialize() const; bool deserialize(const QByteArray& data); virtual MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; } + virtual void setWorkspaceIndex(int index) { m_settings.m_workspaceIndex = index; }; + virtual int getWorkspaceIndex() const { return m_settings.m_workspaceIndex; }; + virtual void setGeometryBytes(const QByteArray& blob) { m_settings.m_geometryBytes = blob; }; + virtual QByteArray getGeometryBytes() const { return m_settings.m_geometryBytes; }; + virtual QString getTitle() const { return m_settings.m_title; }; + virtual QColor getTitleColor() const { return m_settings.m_rgbColor; }; + virtual void zetHidden(bool hidden) { m_settings.m_hidden = hidden; } + virtual bool getHidden() const { return m_settings.m_hidden; } + virtual ChannelMarker& getChannelMarker() { return m_channelMarker; } + virtual int getStreamIndex() const { return m_settings.m_streamIndex; } + virtual void setStreamIndex(int streamIndex) { m_settings.m_streamIndex = streamIndex; } public slots: void channelMarkerChangedByCursor(); @@ -60,6 +71,8 @@ private: ChannelMarker m_channelMarker; RollupState m_rollupState; BFMDemodSettings m_settings; + qint64 m_deviceCenterFrequency; + int m_basebandSampleRate; bool m_doApplySettings; int m_rdsTimerCount; bool m_radiotext_AB_flag; @@ -77,10 +90,11 @@ private: void blockApplySettings(bool block); void applySettings(bool force = false); void displaySettings(); - void displayStreamIndex(); void rdsUpdate(bool force); void rdsUpdateFixedFields(); bool handleMessage(const Message& message); + void makeUIConnections(); + void updateAbsoluteCenterFrequency(); void leaveEvent(QEvent*); void enterEvent(QEvent*); diff --git a/plugins/channelrx/demodbfm/bfmdemodgui.ui b/plugins/channelrx/demodbfm/bfmdemodgui.ui index aff87e627..c4ade4633 100644 --- a/plugins/channelrx/demodbfm/bfmdemodgui.ui +++ b/plugins/channelrx/demodbfm/bfmdemodgui.ui @@ -1,7 +1,7 @@ BFMDemodGUI - + 0 @@ -1884,9 +1884,9 @@ - RollupWidget + RollupContents QWidget -
gui/rollupwidget.h
+
gui/rollupcontents.h
1
diff --git a/plugins/channelrx/demodbfm/bfmdemodsettings.cpp b/plugins/channelrx/demodbfm/bfmdemodsettings.cpp index ee2446627..93dd244ca 100644 --- a/plugins/channelrx/demodbfm/bfmdemodsettings.cpp +++ b/plugins/channelrx/demodbfm/bfmdemodsettings.cpp @@ -56,6 +56,8 @@ void BFMDemodSettings::resetToDefaults() m_reverseAPIPort = 8888; m_reverseAPIDeviceIndex = 0; m_reverseAPIChannelIndex = 0; + m_workspaceIndex = 0; + m_hidden = false; } QByteArray BFMDemodSettings::serialize() const @@ -93,6 +95,9 @@ QByteArray BFMDemodSettings::serialize() const } s.writeBool(21, m_rdsActive); + s.writeS32(22, m_workspaceIndex); + s.writeBlob(23, m_geometryBytes); + s.writeBool(24, m_hidden); return s.final(); } @@ -167,6 +172,9 @@ bool BFMDemodSettings::deserialize(const QByteArray& data) } d.readBool(21, &m_rdsActive, false); + d.readS32(22, &m_workspaceIndex, 0); + d.readBlob(23, &m_geometryBytes); + d.readBool(24, &m_hidden, false); return true; } diff --git a/plugins/channelrx/demodbfm/bfmdemodsettings.h b/plugins/channelrx/demodbfm/bfmdemodsettings.h index b2cdf7003..89237d325 100644 --- a/plugins/channelrx/demodbfm/bfmdemodsettings.h +++ b/plugins/channelrx/demodbfm/bfmdemodsettings.h @@ -42,6 +42,9 @@ struct BFMDemodSettings uint16_t m_reverseAPIPort; uint16_t m_reverseAPIDeviceIndex; uint16_t m_reverseAPIChannelIndex; + int m_workspaceIndex; + QByteArray m_geometryBytes; + bool m_hidden; Serializable *m_channelMarker; Serializable *m_spectrumGUI; diff --git a/plugins/channelrx/demodbfm/readme.md b/plugins/channelrx/demodbfm/readme.md index 5bff97055..df994dde1 100644 --- a/plugins/channelrx/demodbfm/readme.md +++ b/plugins/channelrx/demodbfm/readme.md @@ -6,6 +6,8 @@ This plugin can be used to listen to a Broadcast FM modulated signal (BFM). In a

Interface

+The top and bottom bars of the channel window are described [here](../../../sdrgui/channel/readme.md) + ![BFM Demodulator plugin GUI](../../../doc/img/BFMDemod_plugin.png) The main three areas are: @@ -68,6 +70,10 @@ This is the relative AF volume from 0 to 10. Adjust squelch in dB. +

B: Spectrum

+ +Details on the spectrum view and controls can be found [here](../../../sdrgui/gui/spectrum.md) +

C: RDS display

![BFM Demodulator plugin RDS 1](../../../doc/img/BFMDemod_plugin_rds.png) diff --git a/plugins/channelrx/demodchirpchat/chirpchatdemod.cpp b/plugins/channelrx/demodchirpchat/chirpchatdemod.cpp index c03c26096..36467f9b4 100644 --- a/plugins/channelrx/demodchirpchat/chirpchatdemod.cpp +++ b/plugins/channelrx/demodchirpchat/chirpchatdemod.cpp @@ -28,6 +28,7 @@ #include #include "SWGChannelSettings.h" +#include "SWGWorkspaceInfo.h" #include "SWGChannelReport.h" #include "SWGChirpChatDemodReport.h" @@ -97,6 +98,18 @@ ChirpChatDemod::~ChirpChatDemod() delete m_thread; } +void ChirpChatDemod::setDeviceAPI(DeviceAPI *deviceAPI) +{ + if (deviceAPI != m_deviceAPI) + { + m_deviceAPI->removeChannelSinkAPI(this); + m_deviceAPI->removeChannelSink(this); + m_deviceAPI = deviceAPI; + m_deviceAPI->addChannelSink(this); + m_deviceAPI->addChannelSinkAPI(this); + } +} + uint32_t ChirpChatDemod::getNumberOfDeviceStreams() const { return m_deviceAPI->getNbSourceStreams(); @@ -285,10 +298,8 @@ bool ChirpChatDemod::handleMessage(const Message& cmd) qDebug() << "ChirpChatDemod::handleMessage: DSPSignalNotification: m_basebandSampleRate: " << m_basebandSampleRate; m_basebandSink->getInputMessageQueue()->push(rep); - if (getMessageQueueToGUI()) - { - DSPSignalNotification* repToGUI = new DSPSignalNotification(notif); // make a copy - getMessageQueueToGUI()->push(repToGUI); + if (getMessageQueueToGUI()) { + getMessageQueueToGUI()->push(new DSPSignalNotification(notif)); // make a copy } return true; @@ -500,6 +511,15 @@ int ChirpChatDemod::webapiSettingsGet( return 200; } +int ChirpChatDemod::webapiWorkspaceGet( + SWGSDRangel::SWGWorkspaceInfo& response, + QString& errorMessage) +{ + (void) errorMessage; + response.setIndex(m_settings.m_workspaceIndex); + return 200; +} + int ChirpChatDemod::webapiSettingsPutPatch( bool force, const QStringList& channelSettingsKeys, diff --git a/plugins/channelrx/demodchirpchat/chirpchatdemod.h b/plugins/channelrx/demodchirpchat/chirpchatdemod.h index 618782e9d..9bb87e575 100644 --- a/plugins/channelrx/demodchirpchat/chirpchatdemod.h +++ b/plugins/channelrx/demodchirpchat/chirpchatdemod.h @@ -202,6 +202,8 @@ public: ChirpChatDemod(DeviceAPI* deviceAPI); virtual ~ChirpChatDemod(); virtual void destroy() { delete this; } + virtual void setDeviceAPI(DeviceAPI *deviceAPI); + virtual DeviceAPI *getDeviceAPI() { return m_deviceAPI; } SpectrumVis *getSpectrumVis() { return &m_spectrumVis; } using BasebandSampleSink::feed; @@ -234,6 +236,10 @@ public: SWGSDRangel::SWGChannelSettings& response, QString& errorMessage); + virtual int webapiWorkspaceGet( + SWGSDRangel::SWGWorkspaceInfo& response, + QString& errorMessage); + virtual int webapiSettingsPutPatch( bool force, const QStringList& channelSettingsKeys, diff --git a/plugins/channelrx/demodchirpchat/chirpchatdemodgui.cpp b/plugins/channelrx/demodchirpchat/chirpchatdemodgui.cpp index 6d937002a..0521ef30e 100644 --- a/plugins/channelrx/demodchirpchat/chirpchatdemodgui.cpp +++ b/plugins/channelrx/demodchirpchat/chirpchatdemodgui.cpp @@ -81,6 +81,7 @@ bool ChirpChatDemodGUI::handleMessage(const Message& message) if (DSPSignalNotification::match(message)) { DSPSignalNotification& notif = (DSPSignalNotification&) message; + m_deviceCenterFrequency = notif.getCenterFrequency(); int basebandSampleRate = notif.getSampleRate(); qDebug() << "ChirpChatDemodGUI::handleMessage: DSPSignalNotification: m_basebandSampleRate: " << basebandSampleRate; @@ -90,6 +91,10 @@ bool ChirpChatDemodGUI::handleMessage(const Message& message) setBandwidths(); } + ui->deltaFrequency->setValueRange(false, 7, -m_basebandSampleRate/2, m_basebandSampleRate/2); + ui->deltaFrequencyLabel->setToolTip(tr("Range %1 %L2 Hz").arg(QChar(0xB1)).arg(m_basebandSampleRate/2)); + updateAbsoluteCenterFrequency(); + return true; } else if (ChirpChatDemod::MsgReportDecodeBytes::match(message)) @@ -151,6 +156,7 @@ void ChirpChatDemodGUI::on_deltaFrequency_changed(qint64 value) { m_channelMarker.setCenterFrequency(value); m_settings.m_inputFrequencyOffset = m_channelMarker.getCenterFrequency(); + updateAbsoluteCenterFrequency(); applySettings(); } @@ -323,7 +329,18 @@ void ChirpChatDemodGUI::onWidgetRolled(QWidget* widget, bool rollDown) (void) widget; (void) rollDown; - saveState(m_rollupState); + RollupContents *rollupContents = getRollupContents(); + + if (rollupContents->hasExpandableWidgets()) { + setSizePolicy(sizePolicy().horizontalPolicy(), QSizePolicy::Expanding); + } else { + setSizePolicy(sizePolicy().horizontalPolicy(), QSizePolicy::Fixed); + } + + int h = rollupContents->height() + getAdditionalHeight(); + resize(width(), h); + + rollupContents->saveState(m_rollupState); applySettings(); } @@ -337,10 +354,17 @@ void ChirpChatDemodGUI::onMenuDialogCalled(const QPoint &p) dialog.setReverseAPIPort(m_settings.m_reverseAPIPort); dialog.setReverseAPIDeviceIndex(m_settings.m_reverseAPIDeviceIndex); dialog.setReverseAPIChannelIndex(m_settings.m_reverseAPIChannelIndex); + dialog.setDefaultTitle(m_displayedName); + + if (m_deviceUISet->m_deviceMIMOEngine) + { + dialog.setNumberOfStreams(m_chirpChatDemod->getNumberOfDeviceStreams()); + dialog.setStreamIndex(m_settings.m_streamIndex); + } + dialog.move(p); dialog.exec(); - m_settings.m_inputFrequencyOffset = m_channelMarker.getCenterFrequency(); m_settings.m_rgbColor = m_channelMarker.getColor().rgb(); m_settings.m_title = m_channelMarker.getTitle(); m_settings.m_useReverseAPI = dialog.useReverseAPI(); @@ -350,22 +374,17 @@ void ChirpChatDemodGUI::onMenuDialogCalled(const QPoint &p) m_settings.m_reverseAPIChannelIndex = dialog.getReverseAPIChannelIndex(); setWindowTitle(m_settings.m_title); + setTitle(m_channelMarker.getTitle()); setTitleColor(m_settings.m_rgbColor); - applySettings(); - } - else if ((m_contextMenuType == ContextMenuStreamSettings) && (m_deviceUISet->m_deviceMIMOEngine)) - { - DeviceStreamSelectionDialog dialog(this); - dialog.setNumberOfStreams(m_chirpChatDemod->getNumberOfDeviceStreams()); - dialog.setStreamIndex(m_settings.m_streamIndex); - dialog.move(p); - dialog.exec(); + if (m_deviceUISet->m_deviceMIMOEngine) + { + m_settings.m_streamIndex = dialog.getSelectedStreamIndex(); + m_channelMarker.clearStreamIndexes(); + m_channelMarker.addStreamIndex(m_settings.m_streamIndex); + updateIndexLabel(); + } - m_settings.m_streamIndex = dialog.getSelectedStreamIndex(); - m_channelMarker.clearStreamIndexes(); - m_channelMarker.addStreamIndex(m_settings.m_streamIndex); - displayStreamIndex(); applySettings(); } @@ -378,14 +397,18 @@ ChirpChatDemodGUI::ChirpChatDemodGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUI m_pluginAPI(pluginAPI), m_deviceUISet(deviceUISet), m_channelMarker(this), + m_deviceCenterFrequency(0), m_basebandSampleRate(250000), m_doApplySettings(true), m_tickCount(0) { - ui->setupUi(this); - m_helpURL = "plugins/channelrx/demodchirpchat/readme.md"; setAttribute(Qt::WA_DeleteOnClose, true); - connect(this, SIGNAL(widgetRolled(QWidget*,bool)), this, SLOT(onWidgetRolled(QWidget*,bool))); + m_helpURL = "plugins/channelrx/demodchirpchat/readme.md"; + RollupContents *rollupContents = getRollupContents(); + ui->setupUi(rollupContents); + setSizePolicy(rollupContents->sizePolicy()); + rollupContents->arrangeRollups(); + connect(rollupContents, SIGNAL(widgetRolled(QWidget*,bool)), this, SLOT(onWidgetRolled(QWidget*,bool))); connect(this, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(onMenuDialogCalled(const QPoint &))); m_chirpChatDemod = (ChirpChatDemod*) rxChannel; @@ -412,7 +435,6 @@ ChirpChatDemodGUI::ChirpChatDemodGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUI connect(&m_channelMarker, SIGNAL(highlightedByCursor()), this, SLOT(channelMarkerHighlightedByCursor())); m_deviceUISet->addChannelMarker(&m_channelMarker); - m_deviceUISet->addRollupWidget(this); ui->spectrumGUI->setBuddies(m_spectrumVis, ui->glSpectrum); @@ -424,6 +446,7 @@ ChirpChatDemodGUI::ChirpChatDemodGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUI setBandwidths(); displaySettings(); + makeUIConnections(); resetLoRaStatus(); applySettings(true); } @@ -459,6 +482,7 @@ void ChirpChatDemodGUI::displaySettings() m_channelMarker.blockSignals(false); m_channelMarker.setColor(m_settings.m_rgbColor); setTitleColor(m_settings.m_rgbColor); + setTitle(m_channelMarker.getTitle()); ui->glSpectrum->setSampleRate(thisBW); ui->glSpectrum->setCenterFrequency(thisBW/2); @@ -498,20 +522,13 @@ void ChirpChatDemodGUI::displaySettings() ui->messageLengthAuto->setChecked(m_settings.m_autoNbSymbolsMax); displaySquelch(); + updateIndexLabel(); - restoreState(m_rollupState); + getRollupContents()->restoreState(m_rollupState); + updateAbsoluteCenterFrequency(); blockApplySettings(false); } -void ChirpChatDemodGUI::displayStreamIndex() -{ - if (m_deviceUISet->m_deviceMIMOEngine) { - setStreamIndicator(tr("%1").arg(m_settings.m_streamIndex)); - } else { - setStreamIndicator("S"); // single channel indicator - } -} - void ChirpChatDemodGUI::displaySquelch() { ui->eomSquelch->setValue(m_settings.m_eomSquelchTenths); @@ -767,3 +784,30 @@ void ChirpChatDemodGUI::tick() } } +void ChirpChatDemodGUI::makeUIConnections() +{ + QObject::connect(ui->deltaFrequency, &ValueDialZ::changed, this, &ChirpChatDemodGUI::on_deltaFrequency_changed); + QObject::connect(ui->BW, &QSlider::valueChanged, this, &ChirpChatDemodGUI::on_BW_valueChanged); + QObject::connect(ui->Spread, &QSlider::valueChanged, this, &ChirpChatDemodGUI::on_Spread_valueChanged); + QObject::connect(ui->deBits, &QSlider::valueChanged, this, &ChirpChatDemodGUI::on_deBits_valueChanged); + QObject::connect(ui->fftWindow, QOverload::of(&QComboBox::currentIndexChanged), this, &ChirpChatDemodGUI::on_fftWindow_currentIndexChanged); + QObject::connect(ui->preambleChirps, &QSlider::valueChanged, this, &ChirpChatDemodGUI::on_preambleChirps_valueChanged); + QObject::connect(ui->scheme, QOverload::of(&QComboBox::currentIndexChanged), this, &ChirpChatDemodGUI::on_scheme_currentIndexChanged); + QObject::connect(ui->mute, &QToolButton::toggled, this, &ChirpChatDemodGUI::on_mute_toggled); + QObject::connect(ui->clear, &QPushButton::clicked, this, &ChirpChatDemodGUI::on_clear_clicked); + QObject::connect(ui->eomSquelch, &QDial::valueChanged, this, &ChirpChatDemodGUI::on_eomSquelch_valueChanged); + QObject::connect(ui->messageLength, &QDial::valueChanged, this, &ChirpChatDemodGUI::on_messageLength_valueChanged); + QObject::connect(ui->messageLengthAuto, &QCheckBox::stateChanged, this, &ChirpChatDemodGUI::on_messageLengthAuto_stateChanged); + QObject::connect(ui->header, &QCheckBox::stateChanged, this, &ChirpChatDemodGUI::on_header_stateChanged); + QObject::connect(ui->fecParity, &QDial::valueChanged, this, &ChirpChatDemodGUI::on_fecParity_valueChanged); + QObject::connect(ui->crc, &QCheckBox::stateChanged, this, &ChirpChatDemodGUI::on_crc_stateChanged); + QObject::connect(ui->packetLength, &QDial::valueChanged, this, &ChirpChatDemodGUI::on_packetLength_valueChanged); + QObject::connect(ui->udpSend, &QCheckBox::stateChanged, this, &ChirpChatDemodGUI::on_udpSend_stateChanged); + QObject::connect(ui->udpAddress, &QLineEdit::editingFinished, this, &ChirpChatDemodGUI::on_udpAddress_editingFinished); + QObject::connect(ui->udpPort, &QLineEdit::editingFinished, this, &ChirpChatDemodGUI::on_udpPort_editingFinished); +} + +void ChirpChatDemodGUI::updateAbsoluteCenterFrequency() +{ + setStatusFrequency(m_deviceCenterFrequency + m_settings.m_inputFrequencyOffset); +} diff --git a/plugins/channelrx/demodchirpchat/chirpchatdemodgui.h b/plugins/channelrx/demodchirpchat/chirpchatdemodgui.h index 0dc73f3ba..4678e0868 100644 --- a/plugins/channelrx/demodchirpchat/chirpchatdemodgui.h +++ b/plugins/channelrx/demodchirpchat/chirpchatdemodgui.h @@ -46,6 +46,17 @@ public: QByteArray serialize() const; bool deserialize(const QByteArray& data); virtual MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; } + virtual void setWorkspaceIndex(int index) { m_settings.m_workspaceIndex = index; }; + virtual int getWorkspaceIndex() const { return m_settings.m_workspaceIndex; }; + virtual void setGeometryBytes(const QByteArray& blob) { m_settings.m_geometryBytes = blob; }; + virtual QByteArray getGeometryBytes() const { return m_settings.m_geometryBytes; }; + virtual QString getTitle() const { return m_settings.m_title; }; + virtual QColor getTitleColor() const { return m_settings.m_rgbColor; }; + virtual void zetHidden(bool hidden) { m_settings.m_hidden = hidden; } + virtual bool getHidden() const { return m_settings.m_hidden; } + virtual ChannelMarker& getChannelMarker() { return m_channelMarker; } + virtual int getStreamIndex() const { return m_settings.m_streamIndex; } + virtual void setStreamIndex(int streamIndex) { m_settings.m_streamIndex = streamIndex; } private slots: void channelMarkerChangedByCursor(); @@ -89,6 +100,7 @@ private: ChannelMarker m_channelMarker; RollupState m_rollupState; ChirpChatDemodSettings m_settings; + qint64 m_deviceCenterFrequency; int m_basebandSampleRate; bool m_doApplySettings; @@ -103,7 +115,6 @@ private: void blockApplySettings(bool block); void applySettings(bool force = false); void displaySettings(); - void displayStreamIndex(); void displaySquelch(); void setBandwidths(); void showLoRaMessage(const Message& message); @@ -115,6 +126,8 @@ private: QString getParityStr(int parityStatus); void resetLoRaStatus(); bool handleMessage(const Message& message); + void makeUIConnections(); + void updateAbsoluteCenterFrequency(); }; #endif // INCLUDE_CHIRPCHATDEMODGUI_H diff --git a/plugins/channelrx/demodchirpchat/chirpchatdemodgui.ui b/plugins/channelrx/demodchirpchat/chirpchatdemodgui.ui index 0506899de..4415af525 100644 --- a/plugins/channelrx/demodchirpchat/chirpchatdemodgui.ui +++ b/plugins/channelrx/demodchirpchat/chirpchatdemodgui.ui @@ -1,7 +1,7 @@ ChirpChatDemodGUI - + 0 @@ -1223,9 +1223,9 @@ - RollupWidget + RollupContents QWidget -
gui/rollupwidget.h
+
gui/rollupcontents.h
1
diff --git a/plugins/channelrx/demodchirpchat/chirpchatdemodsettings.cpp b/plugins/channelrx/demodchirpchat/chirpchatdemodsettings.cpp index 4a51c67da..b9b5a9388 100644 --- a/plugins/channelrx/demodchirpchat/chirpchatdemodsettings.cpp +++ b/plugins/channelrx/demodchirpchat/chirpchatdemodsettings.cpp @@ -89,6 +89,8 @@ void ChirpChatDemodSettings::resetToDefaults() m_reverseAPIPort = 8888; m_reverseAPIDeviceIndex = 0; m_reverseAPIChannelIndex = 0; + m_workspaceIndex = 0; + m_hidden = false; } QByteArray ChirpChatDemodSettings::serialize() const @@ -132,6 +134,10 @@ QByteArray ChirpChatDemodSettings::serialize() const s.writeBlob(29, m_rollupState->serialize()); } + s.writeS32(30, m_workspaceIndex); + s.writeBlob(31, m_geometryBytes); + s.writeBool(32, m_hidden); + return s.final(); } @@ -212,6 +218,10 @@ bool ChirpChatDemodSettings::deserialize(const QByteArray& data) m_rollupState->deserialize(bytetmp); } + d.readS32(30, &m_workspaceIndex, 0); + d.readBlob(31, &m_geometryBytes); + d.readBool(32, &m_hidden, false); + return true; } else diff --git a/plugins/channelrx/demodchirpchat/chirpchatdemodsettings.h b/plugins/channelrx/demodchirpchat/chirpchatdemodsettings.h index 93d9ba6b6..71c5c1384 100644 --- a/plugins/channelrx/demodchirpchat/chirpchatdemodsettings.h +++ b/plugins/channelrx/demodchirpchat/chirpchatdemodsettings.h @@ -63,6 +63,9 @@ struct ChirpChatDemodSettings uint16_t m_reverseAPIPort; uint16_t m_reverseAPIDeviceIndex; uint16_t m_reverseAPIChannelIndex; + int m_workspaceIndex; + QByteArray m_geometryBytes; + bool m_hidden; Serializable *m_channelMarker; Serializable *m_spectrumGUI; diff --git a/plugins/channelrx/demodchirpchat/readme.md b/plugins/channelrx/demodchirpchat/readme.md index d4bd871e3..b3adb1322 100644 --- a/plugins/channelrx/demodchirpchat/readme.md +++ b/plugins/channelrx/demodchirpchat/readme.md @@ -23,6 +23,8 @@ Note: this plugin is officially supported since version 6.

Interface

+The top and bottom bars of the channel window are described [here](../../../sdrgui/channel/readme.md) + ![ChirpChat Demodulator plugin GUI](../../../doc/img/ChirpChatDemod_plugin.png)

1: Frequency shift from center frequency of reception

@@ -266,7 +268,7 @@ This is the UDP address and port to where the decoded message is sent when (12)

B: De-chirped spectrum

-This is the spectrum of the de-chirped signal when a ChirpChat signal can be decoded. +This is the spectrum of the de-chirped signal when a ChirpChat signal can be decoded. Details on the spectrum view and controls can be found [here](../../../sdrgui/gui/spectrum.md) The frequency span corresponds to the bandwidth of the ChirpChat signal (3). Default FFT size is 2SF where SF is the spread factor (7). diff --git a/plugins/channelrx/demoddab/dabdemod.cpp b/plugins/channelrx/demoddab/dabdemod.cpp index 245ccfb47..035eb3f35 100644 --- a/plugins/channelrx/demoddab/dabdemod.cpp +++ b/plugins/channelrx/demoddab/dabdemod.cpp @@ -28,6 +28,7 @@ #include #include "SWGChannelSettings.h" +#include "SWGWorkspaceInfo.h" #include "SWGDABDemodSettings.h" #include "SWGChannelReport.h" #include "SWGMapItem.h" @@ -108,6 +109,18 @@ DABDemod::~DABDemod() delete m_basebandSink; } +void DABDemod::setDeviceAPI(DeviceAPI *deviceAPI) +{ + if (deviceAPI != m_deviceAPI) + { + m_deviceAPI->removeChannelSinkAPI(this); + m_deviceAPI->removeChannelSink(this); + m_deviceAPI = deviceAPI; + m_deviceAPI->addChannelSink(this); + m_deviceAPI->addChannelSinkAPI(this); + } +} + uint32_t DABDemod::getNumberOfDeviceStreams() const { return m_deviceAPI->getNbSourceStreams(); @@ -162,10 +175,8 @@ bool DABDemod::handleMessage(const Message& cmd) qDebug() << "DABDemod::handleMessage: DSPSignalNotification"; m_basebandSink->getInputMessageQueue()->push(rep); // Forward to GUI if any - if (m_guiMessageQueue) - { - rep = new DSPSignalNotification(notif); - m_guiMessageQueue->push(rep); + if (m_guiMessageQueue) { + m_guiMessageQueue->push(new DSPSignalNotification(notif)); } return true; @@ -412,6 +423,15 @@ int DABDemod::webapiSettingsGet( return 200; } +int DABDemod::webapiWorkspaceGet( + SWGSDRangel::SWGWorkspaceInfo& response, + QString& errorMessage) +{ + (void) errorMessage; + response.setIndex(m_settings.m_workspaceIndex); + return 200; +} + int DABDemod::webapiSettingsPutPatch( bool force, const QStringList& channelSettingsKeys, diff --git a/plugins/channelrx/demoddab/dabdemod.h b/plugins/channelrx/demoddab/dabdemod.h index a2423a7b9..bae6c38ee 100644 --- a/plugins/channelrx/demoddab/dabdemod.h +++ b/plugins/channelrx/demoddab/dabdemod.h @@ -313,6 +313,8 @@ public: DABDemod(DeviceAPI *deviceAPI); virtual ~DABDemod(); virtual void destroy() { delete this; } + virtual void setDeviceAPI(DeviceAPI *deviceAPI); + virtual DeviceAPI *getDeviceAPI() { return m_deviceAPI; } using BasebandSampleSink::feed; virtual void feed(const SampleVector::const_iterator& begin, const SampleVector::const_iterator& end, bool po); @@ -345,6 +347,10 @@ public: SWGSDRangel::SWGChannelSettings& response, QString& errorMessage); + virtual int webapiWorkspaceGet( + SWGSDRangel::SWGWorkspaceInfo& response, + QString& errorMessage); + virtual int webapiSettingsPutPatch( bool force, const QStringList& channelSettingsKeys, diff --git a/plugins/channelrx/demoddab/dabdemodgui.cpp b/plugins/channelrx/demoddab/dabdemodgui.cpp index 406410d5b..d52f9ebbc 100644 --- a/plugins/channelrx/demoddab/dabdemodgui.cpp +++ b/plugins/channelrx/demoddab/dabdemodgui.cpp @@ -200,15 +200,22 @@ bool DABDemodGUI::handleMessage(const Message& message) else if (DSPSignalNotification::match(message)) { DSPSignalNotification& notif = (DSPSignalNotification&) message; + m_deviceCenterFrequency = notif.getCenterFrequency(); m_basebandSampleRate = notif.getSampleRate(); + ui->deltaFrequency->setValueRange(false, 7, -m_basebandSampleRate/2, m_basebandSampleRate/2); + ui->deltaFrequencyLabel->setToolTip(tr("Range %1 %L2 Hz").arg(QChar(0xB1)).arg(m_basebandSampleRate/2)); bool srTooLow = m_basebandSampleRate < 2048000; ui->warning->setVisible(srTooLow); + if (srTooLow) { ui->warning->setText("Sample rate must be >= 2048000"); } else { ui->warning->setText(""); } - arrangeRollups(); + + getRollupContents()->arrangeRollups(); + updateAbsoluteCenterFrequency(); + return true; } else if (DABDemod::MsgDABEnsembleName::match(message)) @@ -281,7 +288,7 @@ bool DABDemodGUI::handleMessage(const Message& message) ui->motImage->resize(ui->motImage->width(), pixmap.height()); ui->motImage->setVisible(true); ui->motImage->setPixmap(pixmap, pixmap.size()); - arrangeRollups(); + getRollupContents()->arrangeRollups(); } return true; } @@ -318,6 +325,7 @@ void DABDemodGUI::on_deltaFrequency_changed(qint64 value) { m_channelMarker.setCenterFrequency(value); m_settings.m_inputFrequencyOffset = m_channelMarker.getCenterFrequency(); + updateAbsoluteCenterFrequency(); applySettings(); } @@ -384,7 +392,18 @@ void DABDemodGUI::onWidgetRolled(QWidget* widget, bool rollDown) (void) widget; (void) rollDown; - saveState(m_rollupState); + RollupContents *rollupContents = getRollupContents(); + + if (rollupContents->hasExpandableWidgets()) { + setSizePolicy(sizePolicy().horizontalPolicy(), QSizePolicy::Expanding); + } else { + setSizePolicy(sizePolicy().horizontalPolicy(), QSizePolicy::Fixed); + } + + int h = rollupContents->height() + getAdditionalHeight(); + resize(width(), h); + + rollupContents->saveState(m_rollupState); applySettings(); } @@ -398,6 +417,14 @@ void DABDemodGUI::onMenuDialogCalled(const QPoint &p) dialog.setReverseAPIPort(m_settings.m_reverseAPIPort); dialog.setReverseAPIDeviceIndex(m_settings.m_reverseAPIDeviceIndex); dialog.setReverseAPIChannelIndex(m_settings.m_reverseAPIChannelIndex); + dialog.setDefaultTitle(m_displayedName); + + if (m_deviceUISet->m_deviceMIMOEngine) + { + dialog.setNumberOfStreams(m_dabDemod->getNumberOfDeviceStreams()); + dialog.setStreamIndex(m_settings.m_streamIndex); + } + dialog.move(p); dialog.exec(); @@ -410,22 +437,17 @@ void DABDemodGUI::onMenuDialogCalled(const QPoint &p) m_settings.m_reverseAPIChannelIndex = dialog.getReverseAPIChannelIndex(); setWindowTitle(m_settings.m_title); + setTitle(m_channelMarker.getTitle()); setTitleColor(m_settings.m_rgbColor); - applySettings(); - } - else if ((m_contextMenuType == ContextMenuStreamSettings) && (m_deviceUISet->m_deviceMIMOEngine)) - { - DeviceStreamSelectionDialog dialog(this); - dialog.setNumberOfStreams(m_dabDemod->getNumberOfDeviceStreams()); - dialog.setStreamIndex(m_settings.m_streamIndex); - dialog.move(p); - dialog.exec(); + if (m_deviceUISet->m_deviceMIMOEngine) + { + m_settings.m_streamIndex = dialog.getSelectedStreamIndex(); + m_channelMarker.clearStreamIndexes(); + m_channelMarker.addStreamIndex(m_settings.m_streamIndex); + updateIndexLabel(); + } - m_settings.m_streamIndex = dialog.getSelectedStreamIndex(); - m_channelMarker.clearStreamIndexes(); - m_channelMarker.addStreamIndex(m_settings.m_streamIndex); - displayStreamIndex(); applySettings(); } @@ -438,15 +460,18 @@ DABDemodGUI::DABDemodGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, Baseban m_pluginAPI(pluginAPI), m_deviceUISet(deviceUISet), m_channelMarker(this), + m_deviceCenterFrequency(0), m_doApplySettings(true), m_tickCount(0), m_channelFreq(0.0) { - ui->setupUi(this); - m_helpURL = "plugins/channelrx/demoddab/readme.md"; - setAttribute(Qt::WA_DeleteOnClose, true); - connect(this, SIGNAL(widgetRolled(QWidget*,bool)), this, SLOT(onWidgetRolled(QWidget*,bool))); + m_helpURL = "plugins/channelrx/demoddab/readme.md"; + RollupContents *rollupContents = getRollupContents(); + ui->setupUi(rollupContents); + setSizePolicy(rollupContents->sizePolicy()); + rollupContents->arrangeRollups(); + connect(rollupContents, SIGNAL(widgetRolled(QWidget*,bool)), this, SLOT(onWidgetRolled(QWidget*,bool))); connect(this, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(onMenuDialogCalled(const QPoint &))); m_dabDemod = reinterpret_cast(rxChannel); @@ -478,7 +503,6 @@ DABDemodGUI::DABDemodGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, Baseban m_settings.setRollupState(&m_rollupState); m_deviceUISet->addChannelMarker(&m_channelMarker); - m_deviceUISet->addRollupWidget(this); connect(&m_channelMarker, SIGNAL(changedByCursor()), this, SLOT(channelMarkerChangedByCursor())); connect(&m_channelMarker, SIGNAL(highlightedByCursor()), this, SLOT(channelMarkerHighlightedByCursor())); @@ -506,6 +530,7 @@ DABDemodGUI::DABDemodGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, Baseban connect(ui->programs->horizontalHeader(), SIGNAL(sectionResized(int, int, int)), SLOT(programs_sectionResized(int, int, int))); displaySettings(); + makeUIConnections(); applySettings(true); } @@ -539,6 +564,7 @@ void DABDemodGUI::displaySettings() setTitleColor(m_settings.m_rgbColor); setWindowTitle(m_channelMarker.getTitle()); + setTitle(m_channelMarker.getTitle()); blockApplySettings(true); @@ -551,7 +577,7 @@ void DABDemodGUI::displaySettings() ui->rfBWText->setText(QString("%1k").arg(m_settings.m_rfBandwidth / 1000.0, 0, 'f', 1)); ui->rfBW->setValue(m_settings.m_rfBandwidth / 100.0); - displayStreamIndex(); + updateIndexLabel(); ui->filter->setText(m_settings.m_filter); @@ -569,27 +595,21 @@ void DABDemodGUI::displaySettings() filter(); - restoreState(m_rollupState); + getRollupContents()->restoreState(m_rollupState); + updateAbsoluteCenterFrequency(); blockApplySettings(false); } -void DABDemodGUI::displayStreamIndex() -{ - if (m_deviceUISet->m_deviceMIMOEngine) { - setStreamIndicator(tr("%1").arg(m_settings.m_streamIndex)); - } else { - setStreamIndicator("S"); // single channel indicator - } -} - -void DABDemodGUI::leaveEvent(QEvent*) +void DABDemodGUI::leaveEvent(QEvent* event) { m_channelMarker.setHighlighted(false); + ChannelGUI::leaveEvent(event); } -void DABDemodGUI::enterEvent(QEvent*) +void DABDemodGUI::enterEvent(QEvent* event) { m_channelMarker.setHighlighted(true); + ChannelGUI::enterEvent(event); } void DABDemodGUI::clearProgram() @@ -605,7 +625,7 @@ void DABDemodGUI::clearProgram() ui->data->setText(""); ui->motImage->setPixmap(QPixmap()); ui->motImage->setVisible(false); - arrangeRollups(); + getRollupContents()->arrangeRollups(); } void DABDemodGUI::resetService() @@ -692,3 +712,20 @@ void DABDemodGUI::tick() m_tickCount++; } + +void DABDemodGUI::makeUIConnections() +{ + QObject::connect(ui->deltaFrequency, &ValueDialZ::changed, this, &DABDemodGUI::on_deltaFrequency_changed); + QObject::connect(ui->audioMute, &QToolButton::toggled, this, &DABDemodGUI::on_audioMute_toggled); + QObject::connect(ui->volume, &QSlider::valueChanged, this, &DABDemodGUI::on_volume_valueChanged); + QObject::connect(ui->rfBW, &QSlider::valueChanged, this, &DABDemodGUI::on_rfBW_valueChanged); + QObject::connect(ui->filter, &QLineEdit::editingFinished, this, &DABDemodGUI::on_filter_editingFinished); + QObject::connect(ui->clearTable, &QPushButton::clicked, this, &DABDemodGUI::on_clearTable_clicked); + QObject::connect(ui->programs, &QTableWidget::cellDoubleClicked, this, &DABDemodGUI::on_programs_cellDoubleClicked); + QObject::connect(ui->channel, QOverload::of(&QComboBox::currentIndexChanged), this, &DABDemodGUI::on_channel_currentIndexChanged); +} + +void DABDemodGUI::updateAbsoluteCenterFrequency() +{ + setStatusFrequency(m_deviceCenterFrequency + m_settings.m_inputFrequencyOffset); +} diff --git a/plugins/channelrx/demoddab/dabdemodgui.h b/plugins/channelrx/demoddab/dabdemodgui.h index c8ba0270a..b5b4e9681 100644 --- a/plugins/channelrx/demoddab/dabdemodgui.h +++ b/plugins/channelrx/demoddab/dabdemodgui.h @@ -53,6 +53,17 @@ public: QByteArray serialize() const; bool deserialize(const QByteArray& data); virtual MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; } + virtual void setWorkspaceIndex(int index) { m_settings.m_workspaceIndex = index; }; + virtual int getWorkspaceIndex() const { return m_settings.m_workspaceIndex; }; + virtual void setGeometryBytes(const QByteArray& blob) { m_settings.m_geometryBytes = blob; }; + virtual QByteArray getGeometryBytes() const { return m_settings.m_geometryBytes; }; + virtual QString getTitle() const { return m_settings.m_title; }; + virtual QColor getTitleColor() const { return m_settings.m_rgbColor; }; + virtual void zetHidden(bool hidden) { m_settings.m_hidden = hidden; } + virtual bool getHidden() const { return m_settings.m_hidden; } + virtual ChannelMarker& getChannelMarker() { return m_channelMarker; } + virtual int getStreamIndex() const { return m_settings.m_streamIndex; } + virtual void setStreamIndex(int streamIndex) { m_settings.m_streamIndex = streamIndex; } public slots: void channelMarkerChangedByCursor(); @@ -65,6 +76,7 @@ private: ChannelMarker m_channelMarker; RollupState m_rollupState; DABDemodSettings m_settings; + qint64 m_deviceCenterFrequency; bool m_doApplySettings; DABDemod* m_dabDemod; @@ -81,9 +93,11 @@ private: void blockApplySettings(bool block); void applySettings(bool force = false); void displaySettings(); - void displayStreamIndex(); void addProgramName(const DABDemod::MsgDABProgramName& program); bool handleMessage(const Message& message); + void makeUIConnections(); + void updateAbsoluteCenterFrequency(); + void leaveEvent(QEvent*); void enterEvent(QEvent*); void resetService(); diff --git a/plugins/channelrx/demoddab/dabdemodgui.ui b/plugins/channelrx/demoddab/dabdemodgui.ui index c166e5c5a..5367f6909 100644 --- a/plugins/channelrx/demoddab/dabdemodgui.ui +++ b/plugins/channelrx/demoddab/dabdemodgui.ui @@ -1,7 +1,7 @@ DABDemodGUI - + 0 @@ -1009,9 +1009,9 @@ - RollupWidget + RollupContents QWidget -
gui/rollupwidget.h
+
gui/rollupcontents.h
1
diff --git a/plugins/channelrx/demoddab/dabdemodsettings.cpp b/plugins/channelrx/demoddab/dabdemodsettings.cpp index 029729006..14d16ab31 100644 --- a/plugins/channelrx/demoddab/dabdemodsettings.cpp +++ b/plugins/channelrx/demoddab/dabdemodsettings.cpp @@ -47,6 +47,8 @@ void DABDemodSettings::resetToDefaults() m_reverseAPIPort = 8888; m_reverseAPIDeviceIndex = 0; m_reverseAPIChannelIndex = 0; + m_workspaceIndex = 0; + m_hidden = false; for (int i = 0; i < DABDEMOD_COLUMNS; i++) { @@ -82,6 +84,10 @@ QByteArray DABDemodSettings::serialize() const s.writeBlob(16, m_rollupState->serialize()); } + s.writeS32(17, m_workspaceIndex); + s.writeBlob(18, m_geometryBytes); + s.writeBool(19, m_hidden); + for (int i = 0; i < DABDEMOD_COLUMNS; i++) { s.writeS32(100 + i, m_columnIndexes[i]); } @@ -146,6 +152,10 @@ bool DABDemodSettings::deserialize(const QByteArray& data) m_rollupState->deserialize(bytetmp); } + d.readS32(17, &m_workspaceIndex, 0); + d.readBlob(18, &m_geometryBytes); + d.readBool(19, &m_hidden, false); + for (int i = 0; i < DABDEMOD_COLUMNS; i++) { d.readS32(100 + i, &m_columnIndexes[i], i); } diff --git a/plugins/channelrx/demoddab/dabdemodsettings.h b/plugins/channelrx/demoddab/dabdemodsettings.h index 80234e935..c2fa8c979 100644 --- a/plugins/channelrx/demoddab/dabdemodsettings.h +++ b/plugins/channelrx/demoddab/dabdemodsettings.h @@ -46,6 +46,9 @@ struct DABDemodSettings uint16_t m_reverseAPIDeviceIndex; uint16_t m_reverseAPIChannelIndex; Serializable *m_rollupState; + int m_workspaceIndex; + QByteArray m_geometryBytes; + bool m_hidden; int m_columnIndexes[DABDEMOD_COLUMNS];//!< How the columns are ordered in the table int m_columnSizes[DABDEMOD_COLUMNS]; //!< Size of the columns in the table diff --git a/plugins/channelrx/demoddab/readme.md b/plugins/channelrx/demoddab/readme.md index a3085c986..49518887d 100644 --- a/plugins/channelrx/demoddab/readme.md +++ b/plugins/channelrx/demoddab/readme.md @@ -8,6 +8,8 @@ The DAB demodulator uses a sample rate of 2.048MHz.

Interface

+The top and bottom bars of the channel window are described [here](../../../sdrgui/channel/readme.md) + ![DAB Demodulator plugin GUI](../../../doc/img/DABDemod_plugin.png)

1: Frequency shift from center frequency of reception

diff --git a/plugins/channelrx/demoddatv/datvdemod.cpp b/plugins/channelrx/demoddatv/datvdemod.cpp index b1c67c74d..b2f7c68fb 100644 --- a/plugins/channelrx/demoddatv/datvdemod.cpp +++ b/plugins/channelrx/demoddatv/datvdemod.cpp @@ -23,6 +23,7 @@ #include #include "SWGChannelSettings.h" +#include "SWGWorkspaceInfo.h" #include "SWGDATVDemodSettings.h" #include "SWGChannelReport.h" @@ -88,6 +89,18 @@ DATVDemod::~DATVDemod() m_basebandSink->deleteLater(); } +void DATVDemod::setDeviceAPI(DeviceAPI *deviceAPI) +{ + if (deviceAPI != m_deviceAPI) + { + m_deviceAPI->removeChannelSinkAPI(this); + m_deviceAPI->removeChannelSink(this); + m_deviceAPI = deviceAPI; + m_deviceAPI->addChannelSink(this); + m_deviceAPI->addChannelSinkAPI(this); + } +} + void DATVDemod::feed(const SampleVector::const_iterator& begin, const SampleVector::const_iterator& end, bool firstOfBurst) { (void) firstOfBurst; @@ -138,6 +151,11 @@ bool DATVDemod::handleMessage(const Message& cmd) DSPSignalNotification* notifToSink = new DSPSignalNotification(notif); // make a copy m_basebandSink->getInputMessageQueue()->push(notifToSink); + // Forward to GUI if any + if (getMessageQueueToGUI()) { + getMessageQueueToGUI()->push(new DSPSignalNotification(notif)); + } + return true; } else @@ -290,6 +308,15 @@ int DATVDemod::webapiSettingsGet( return 200; } +int DATVDemod::webapiWorkspaceGet( + SWGSDRangel::SWGWorkspaceInfo& response, + QString& errorMessage) +{ + (void) errorMessage; + response.setIndex(m_settings.m_workspaceIndex); + return 200; +} + int DATVDemod::webapiReportGet( SWGSDRangel::SWGChannelReport& response, QString& errorMessage) diff --git a/plugins/channelrx/demoddatv/datvdemod.h b/plugins/channelrx/demoddatv/datvdemod.h index 78befcd87..8c3629767 100644 --- a/plugins/channelrx/demoddatv/datvdemod.h +++ b/plugins/channelrx/demoddatv/datvdemod.h @@ -43,8 +43,10 @@ public: DATVDemod(DeviceAPI *); virtual ~DATVDemod(); - virtual void destroy() { delete this; } + virtual void setDeviceAPI(DeviceAPI *deviceAPI); + virtual DeviceAPI *getDeviceAPI() { return m_deviceAPI; } + virtual void getIdentifier(QString& id) { id = objectName(); } virtual QString getIdentifier() const { return objectName(); } virtual void getTitle(QString& title) { title = objectName(); } @@ -76,6 +78,10 @@ public: SWGSDRangel::SWGChannelSettings& response, QString& errorMessage); + virtual int webapiWorkspaceGet( + SWGSDRangel::SWGWorkspaceInfo& response, + QString& errorMessage); + virtual int webapiSettingsPutPatch( bool force, const QStringList& channelSettingsKeys, diff --git a/plugins/channelrx/demoddatv/datvdemodgui.cpp b/plugins/channelrx/demoddatv/datvdemodgui.cpp index b0863b099..921200494 100644 --- a/plugins/channelrx/demoddatv/datvdemodgui.cpp +++ b/plugins/channelrx/demoddatv/datvdemodgui.cpp @@ -20,19 +20,21 @@ #include #include #include +#include #include "device/deviceuiset.h" #include "dsp/dspengine.h" +#include "dsp/dspcommands.h" #include "plugin/pluginapi.h" #include "util/simpleserializer.h" #include "util/db.h" -#include "ui_datvdemodgui.h" #include "gui/crightclickenabler.h" #include "gui/audioselectdialog.h" #include "gui/basicchannelsettingsdialog.h" #include "gui/devicestreamselectiondialog.h" #include "mainwindow.h" +#include "ui_datvdemodgui.h" #include "datvdemodreport.h" #include "datvdvbs2ldpcdialog.h" #include "datvdemodgui.h" @@ -79,6 +81,14 @@ bool DATVDemodGUI::deserialize(const QByteArray& arrData) } } +void DATVDemodGUI::resizeEvent(QResizeEvent* size) +{ + int maxWidth = getRollupContents()->maximumWidth(); + int minHeight = getRollupContents()->minimumHeight() + getAdditionalHeight(); + resize(width() < maxWidth ? width() : maxWidth, minHeight); + size->accept(); +} + bool DATVDemodGUI::handleMessage(const Message& message) { if (DATVDemodReport::MsgReportModcodCstlnChange::match(message)) @@ -96,10 +106,20 @@ bool DATVDemodGUI::handleMessage(const Message& message) { DATVDemod::MsgConfigureDATVDemod& cfg = (DATVDemod::MsgConfigureDATVDemod&) message; m_settings = cfg.getSettings(); - m_objChannelMarker.updateSettings(static_cast(m_settings.m_channelMarker)); + m_channelMarker.updateSettings(static_cast(m_settings.m_channelMarker)); displaySettings(); return true; } + else if (DSPSignalNotification::match(message)) + { + DSPSignalNotification& notif = (DSPSignalNotification&) message; + m_deviceCenterFrequency = notif.getCenterFrequency(); + m_basebandSampleRate = notif.getSampleRate(); + ui->deltaFrequency->setValueRange(false, 8, -m_basebandSampleRate/2, m_basebandSampleRate/2); + ui->deltaFrequencyLabel->setToolTip(tr("Range %1 %L2 Hz").arg(QChar(0xB1)).arg(m_basebandSampleRate/2)); + updateAbsoluteCenterFrequency(); + return true; + } else { return false; @@ -121,14 +141,14 @@ void DATVDemodGUI::handleInputMessages() void DATVDemodGUI::channelMarkerChangedByCursor() { - ui->deltaFrequency->setValue(m_objChannelMarker.getCenterFrequency()); - m_settings.m_centerFrequency = m_objChannelMarker.getCenterFrequency(); + ui->deltaFrequency->setValue(m_channelMarker.getCenterFrequency()); + m_settings.m_centerFrequency = m_channelMarker.getCenterFrequency(); applySettings(); } void DATVDemodGUI::channelMarkerHighlightedByCursor() { - setHighlighted(m_objChannelMarker.getHighlighted()); + setHighlighted(m_channelMarker.getHighlighted()); } @@ -137,7 +157,7 @@ void DATVDemodGUI::onWidgetRolled(QWidget* widget, bool rollDown) (void) widget; (void) rollDown; - saveState(m_rollupState); + getRollupContents()->saveState(m_rollupState); applySettings(); } @@ -145,18 +165,25 @@ void DATVDemodGUI::onMenuDialogCalled(const QPoint &p) { if (m_contextMenuType == ContextMenuChannelSettings) { - BasicChannelSettingsDialog dialog(&m_objChannelMarker, this); + BasicChannelSettingsDialog dialog(&m_channelMarker, this); dialog.setUseReverseAPI(m_settings.m_useReverseAPI); dialog.setReverseAPIAddress(m_settings.m_reverseAPIAddress); dialog.setReverseAPIPort(m_settings.m_reverseAPIPort); dialog.setReverseAPIDeviceIndex(m_settings.m_reverseAPIDeviceIndex); dialog.setReverseAPIChannelIndex(m_settings.m_reverseAPIChannelIndex); + dialog.setDefaultTitle(m_displayedName); + + if (m_deviceUISet->m_deviceMIMOEngine) + { + dialog.setNumberOfStreams(m_datvDemod->getNumberOfDeviceStreams()); + dialog.setStreamIndex(m_settings.m_streamIndex); + } + dialog.move(p); dialog.exec(); - m_settings.m_centerFrequency = m_objChannelMarker.getCenterFrequency(); - m_settings.m_rgbColor = m_objChannelMarker.getColor().rgb(); - m_settings.m_title = m_objChannelMarker.getTitle(); + m_settings.m_rgbColor = m_channelMarker.getColor().rgb(); + m_settings.m_title = m_channelMarker.getTitle(); m_settings.m_useReverseAPI = dialog.useReverseAPI(); m_settings.m_reverseAPIAddress = dialog.getReverseAPIAddress(); m_settings.m_reverseAPIPort = dialog.getReverseAPIPort(); @@ -164,22 +191,17 @@ void DATVDemodGUI::onMenuDialogCalled(const QPoint &p) m_settings.m_reverseAPIChannelIndex = dialog.getReverseAPIChannelIndex(); setWindowTitle(m_settings.m_title); + setTitle(m_channelMarker.getTitle()); setTitleColor(m_settings.m_rgbColor); - applySettings(); - } - else if ((m_contextMenuType == ContextMenuStreamSettings) && (m_deviceUISet->m_deviceMIMOEngine)) - { - DeviceStreamSelectionDialog dialog(this); - dialog.setNumberOfStreams(m_datvDemod->getNumberOfDeviceStreams()); - dialog.setStreamIndex(m_settings.m_streamIndex); - dialog.move(p); - dialog.exec(); + if (m_deviceUISet->m_deviceMIMOEngine) + { + m_settings.m_streamIndex = dialog.getSelectedStreamIndex(); + m_channelMarker.clearStreamIndexes(); + m_channelMarker.addStreamIndex(m_settings.m_streamIndex); + updateIndexLabel(); + } - m_settings.m_streamIndex = dialog.getSelectedStreamIndex(); - m_objChannelMarker.clearStreamIndexes(); - m_objChannelMarker.addStreamIndex(m_settings.m_streamIndex); - displayStreamIndex(); applySettings(); } @@ -187,23 +209,30 @@ void DATVDemodGUI::onMenuDialogCalled(const QPoint &p) } DATVDemodGUI::DATVDemodGUI(PluginAPI* objPluginAPI, DeviceUISet *deviceUISet, BasebandSampleSink *rxChannel, QWidget* objParent) : - ChannelGUI(objParent), - ui(new Ui::DATVDemodGUI), - m_objPluginAPI(objPluginAPI), - m_deviceUISet(deviceUISet), - m_objChannelMarker(this), - m_blnBasicSettingsShown(false), - m_blnDoApplySettings(true), - m_modcodModulationIndex(-1), - m_modcodCodeRateIndex(-1), - m_cstlnSetByModcod(false) + ChannelGUI(objParent), + ui(new Ui::DATVDemodGUI), + m_objPluginAPI(objPluginAPI), + m_deviceUISet(deviceUISet), + m_channelMarker(this), + m_deviceCenterFrequency(0), + m_basebandSampleRate(1), + m_blnBasicSettingsShown(false), + m_blnDoApplySettings(true), + m_modcodModulationIndex(-1), + m_modcodCodeRateIndex(-1), + m_cstlnSetByModcod(false) { - ui->setupUi(this); + setAttribute(Qt::WA_DeleteOnClose, true); m_helpURL = "plugins/channelrx/demoddatv/readme.md"; + RollupContents *rollupContents = getRollupContents(); + ui->setupUi(rollupContents); + setSizePolicy(rollupContents->sizePolicy()); + rollupContents->arrangeRollups(); + connect(rollupContents, SIGNAL(widgetRolled(QWidget*,bool)), this, SLOT(onWidgetRolled(QWidget*,bool))); + ui->screenTV->setColor(true); ui->screenTV->resizeTVScreen(256,256); - 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())); @@ -227,7 +256,7 @@ DATVDemodGUI::DATVDemodGUI(PluginAPI* objPluginAPI, DeviceUISet *deviceUISet, Ba connect(m_datvDemod->getUDPStream(), &DATVUDPStream::fifoData, this, &DATVDemodGUI::on_StreamDataAvailable); } - m_settings.setChannelMarker(&m_objChannelMarker); + m_settings.setChannelMarker(&m_channelMarker); m_settings.setRollupState(&m_rollupState); connect(ui->screenTV_2, &DATVideoRender::onMetaDataChanged, this, &DATVDemodGUI::on_StreamMetaDataChanged); @@ -250,19 +279,18 @@ DATVDemodGUI::DATVDemodGUI(PluginAPI* objPluginAPI, DeviceUISet *deviceUISet, Ba ui->rfBandwidth->setColorMapper(ColorMapper(ColorMapper::GrayYellow)); ui->rfBandwidth->setValueRange(true, 8, 0, 50000000); - m_objChannelMarker.blockSignals(true); - m_objChannelMarker.setColor(Qt::magenta); - m_objChannelMarker.setBandwidth(6000000); - m_objChannelMarker.setCenterFrequency(0); - m_objChannelMarker.setTitle("DATV Demodulator"); - m_objChannelMarker.blockSignals(false); - m_objChannelMarker.setVisible(true); + m_channelMarker.blockSignals(true); + m_channelMarker.setColor(Qt::magenta); + m_channelMarker.setBandwidth(6000000); + m_channelMarker.setCenterFrequency(0); + m_channelMarker.setTitle("DATV Demodulator"); + m_channelMarker.blockSignals(false); + m_channelMarker.setVisible(true); - connect(&m_objChannelMarker, SIGNAL(changedByCursor()), this, SLOT(channelMarkerChangedByCursor())); - connect(&m_objChannelMarker, SIGNAL(highlightedByCursor()), this, SLOT(channelMarkerHighlightedByCursor())); + connect(&m_channelMarker, SIGNAL(changedByCursor()), this, SLOT(channelMarkerChangedByCursor())); + connect(&m_channelMarker, SIGNAL(highlightedByCursor()), this, SLOT(channelMarkerHighlightedByCursor())); - m_deviceUISet->addChannelMarker(&m_objChannelMarker); - m_deviceUISet->addRollupWidget(this); + m_deviceUISet->addChannelMarker(&m_channelMarker); // QPixmap pixmapTarget = QPixmap(":/film.png"); // pixmapTarget = pixmapTarget.scaled(16, 16, Qt::KeepAspectRatio, Qt::SmoothTransformation); @@ -283,10 +311,12 @@ DATVDemodGUI::DATVDemodGUI(PluginAPI* objPluginAPI, DeviceUISet *deviceUISet, Ba ui->playerIndicator->setStyleSheet("QLabel { background-color: gray; border-radius: 8px; }"); ui->udpIndicator->setStyleSheet("QLabel { background-color: gray; border-radius: 8px; }"); resetToDefaults(); // does applySettings() + makeUIConnections(); } DATVDemodGUI::~DATVDemodGUI() { + ui->screenTV->setParent(nullptr); // Prefer memory leak to core dump... ~TVScreen() is buggy delete ui; } @@ -297,17 +327,18 @@ void DATVDemodGUI::blockApplySettings(bool blnBlock) void DATVDemodGUI::displaySettings() { - m_objChannelMarker.blockSignals(true); - m_objChannelMarker.setCenterFrequency(m_settings.m_centerFrequency); - m_objChannelMarker.setColor(m_settings.m_rgbColor); - m_objChannelMarker.setTitle(m_settings.m_title); - m_objChannelMarker.blockSignals(false); - m_objChannelMarker.setBandwidth(m_settings.m_rfBandwidth); + m_channelMarker.blockSignals(true); + m_channelMarker.setCenterFrequency(m_settings.m_centerFrequency); + m_channelMarker.setColor(m_settings.m_rgbColor); + m_channelMarker.setTitle(m_settings.m_title); + m_channelMarker.blockSignals(false); + m_channelMarker.setBandwidth(m_settings.m_rfBandwidth); blockApplySettings(true); setTitleColor(m_settings.m_rgbColor); - setWindowTitle(m_objChannelMarker.getTitle()); + setWindowTitle(m_channelMarker.getTitle()); + setTitle(m_channelMarker.getTitle()); ui->deltaFrequency->setValue(m_settings.m_centerFrequency); ui->chkAllowDrift->setChecked(m_settings.m_allowDrift); @@ -395,7 +426,9 @@ void DATVDemodGUI::displaySettings() connect(m_datvDemod->getUDPStream(), &DATVUDPStream::fifoData, this, &DATVDemodGUI::on_StreamDataAvailable); } - restoreState(m_rollupState); + getRollupContents()->restoreState(m_rollupState); + updateAbsoluteCenterFrequency(); + updateIndexLabel(); blockApplySettings(false); } @@ -443,22 +476,13 @@ void DATVDemodGUI::displaySystemConfiguration() ui->cmbFEC->blockSignals(false); } -void DATVDemodGUI::displayStreamIndex() -{ - if (m_deviceUISet->m_deviceMIMOEngine) { - setStreamIndicator(tr("%1").arg(m_settings.m_streamIndex)); - } else { - setStreamIndicator("S"); // single channel indicator - } -} - void DATVDemodGUI::applySettings(bool force) { if (m_blnDoApplySettings) { qDebug("DATVDemodGUI::applySettings"); - setTitleColor(m_objChannelMarker.getColor()); + setTitleColor(m_channelMarker.getColor()); QString msg = tr("DATVDemodGUI::applySettings: force: %1").arg(force ? "true" : "false"); m_settings.debug(msg); @@ -468,18 +492,20 @@ void DATVDemodGUI::applySettings(bool force) } } -void DATVDemodGUI::leaveEvent(QEvent*) +void DATVDemodGUI::leaveEvent(QEvent* event) { blockApplySettings(true); - m_objChannelMarker.setHighlighted(false); + m_channelMarker.setHighlighted(false); blockApplySettings(false); + ChannelGUI::leaveEvent(event); } -void DATVDemodGUI::enterEvent(QEvent*) +void DATVDemodGUI::enterEvent(QEvent* event) { blockApplySettings(true); - m_objChannelMarker.setHighlighted(true); + m_channelMarker.setHighlighted(true); blockApplySettings(false); + ChannelGUI::enterEvent(event); } void DATVDemodGUI::audioSelect() @@ -656,7 +682,7 @@ void DATVDemodGUI::on_cmbStandard_currentIndexChanged(int index) applySettings(); } -void DATVDemodGUI::on_cmbModulation_currentIndexChanged(const QString &arg1) +void DATVDemodGUI::on_cmbModulation_currentIndexChanged(int arg1) { (void) arg1; QString strModulation = ui->cmbModulation->currentText(); @@ -674,7 +700,7 @@ void DATVDemodGUI::on_cmbModulation_currentIndexChanged(const QString &arg1) applySettings(); } -void DATVDemodGUI::on_cmbFEC_currentIndexChanged(const QString &arg1) +void DATVDemodGUI::on_cmbFEC_currentIndexChanged(int arg1) { (void) arg1; QString strFEC = ui->cmbFEC->currentText(); @@ -773,15 +799,16 @@ void DATVDemodGUI::on_StreamDataAvailable(int intBytes, int intPercent, qint64 i void DATVDemodGUI::on_deltaFrequency_changed(qint64 value) { - m_objChannelMarker.setCenterFrequency(value); - m_settings.m_centerFrequency = m_objChannelMarker.getCenterFrequency(); + m_channelMarker.setCenterFrequency(value); + m_settings.m_centerFrequency = m_channelMarker.getCenterFrequency(); + updateAbsoluteCenterFrequency(); applySettings(); } void DATVDemodGUI::on_rfBandwidth_changed(qint64 value) { - m_objChannelMarker.setBandwidth(value); - m_settings.m_rfBandwidth = m_objChannelMarker.getBandwidth(); + m_channelMarker.setBandwidth(value); + m_settings.m_rfBandwidth = m_channelMarker.getBandwidth(); applySettings(); } @@ -919,3 +946,37 @@ void DATVDemodGUI::on_udpTSPort_editingFinished() ui->udpTSPort->setText(tr("%1").arg(udpPort)); applySettings(); } + +void DATVDemodGUI::makeUIConnections() +{ + QObject::connect(ui->cmbStandard, QOverload::of(&QComboBox::currentIndexChanged), this, &DATVDemodGUI::on_cmbStandard_currentIndexChanged); + QObject::connect(ui->cmbModulation, QOverload::of(&QComboBox::currentIndexChanged), this, &DATVDemodGUI::on_cmbModulation_currentIndexChanged); + QObject::connect(ui->cmbFEC, QOverload::of(&QComboBox::currentIndexChanged), this, &DATVDemodGUI::on_cmbFEC_currentIndexChanged); + QObject::connect(ui->softLDPC, &QCheckBox::clicked, this, &DATVDemodGUI::on_softLDPC_clicked); + QObject::connect(ui->maxBitflips, QOverload::of(&QSpinBox::valueChanged), this, &DATVDemodGUI::on_maxBitflips_valueChanged); + QObject::connect(ui->chkViterbi, &QCheckBox::clicked, this, &DATVDemodGUI::on_chkViterbi_clicked); + QObject::connect(ui->chkHardMetric, &QCheckBox::clicked, this, &DATVDemodGUI::on_chkHardMetric_clicked); + QObject::connect(ui->resetDefaults, &QPushButton::clicked, this, &DATVDemodGUI::on_resetDefaults_clicked); + QObject::connect(ui->spiSymbolRate, QOverload::of(&QSpinBox::valueChanged), this, &DATVDemodGUI::on_spiSymbolRate_valueChanged); + QObject::connect(ui->spiNotchFilters, QOverload::of(&QSpinBox::valueChanged), this, &DATVDemodGUI::on_spiNotchFilters_valueChanged); + QObject::connect(ui->chkAllowDrift, &QCheckBox::clicked, this, &DATVDemodGUI::on_chkAllowDrift_clicked); + QObject::connect(ui->fullScreen, &QPushButton::clicked, this, &DATVDemodGUI::on_fullScreen_clicked); + QObject::connect(ui->chkFastlock, &QCheckBox::clicked, this, &DATVDemodGUI::on_chkFastlock_clicked); + QObject::connect(ui->cmbFilter, QOverload::of(&QComboBox::currentIndexChanged), this, &DATVDemodGUI::on_cmbFilter_currentIndexChanged); + QObject::connect(ui->spiRollOff, QOverload::of(&QSpinBox::valueChanged), this, &DATVDemodGUI::on_spiRollOff_valueChanged); + QObject::connect(ui->spiExcursion, QOverload::of(&QSpinBox::valueChanged), this, &DATVDemodGUI::on_spiExcursion_valueChanged); + QObject::connect(ui->deltaFrequency, &ValueDialZ::changed, this, &DATVDemodGUI::on_deltaFrequency_changed); + QObject::connect(ui->rfBandwidth, &ValueDialZ::changed, this, &DATVDemodGUI::on_rfBandwidth_changed); + QObject::connect(ui->audioMute, &QToolButton::toggled, this, &DATVDemodGUI::on_audioMute_toggled); + QObject::connect(ui->audioVolume, &QSlider::valueChanged, this, &DATVDemodGUI::on_audioVolume_valueChanged); + QObject::connect(ui->videoMute, &QToolButton::toggled, this, &DATVDemodGUI::on_videoMute_toggled); + QObject::connect(ui->udpTS, &ButtonSwitch::clicked, this, &DATVDemodGUI::on_udpTS_clicked); + QObject::connect(ui->udpTSAddress, &QLineEdit::editingFinished, this, &DATVDemodGUI::on_udpTSAddress_editingFinished); + QObject::connect(ui->udpTSPort, &QLineEdit::editingFinished, this, &DATVDemodGUI::on_udpTSPort_editingFinished); + QObject::connect(ui->playerEnable, &QCheckBox::clicked, this, &DATVDemodGUI::on_playerEnable_clicked); +} + +void DATVDemodGUI::updateAbsoluteCenterFrequency() +{ + setStatusFrequency(m_deviceCenterFrequency + m_settings.m_centerFrequency); +} diff --git a/plugins/channelrx/demoddatv/datvdemodgui.h b/plugins/channelrx/demoddatv/datvdemodgui.h index efd4f6283..c39c5a143 100644 --- a/plugins/channelrx/demoddatv/datvdemodgui.h +++ b/plugins/channelrx/demoddatv/datvdemodgui.h @@ -50,11 +50,24 @@ public: void resetToDefaults(); QByteArray serialize() const; bool deserialize(const QByteArray& arrData); - + virtual void setWorkspaceIndex(int index) { m_settings.m_workspaceIndex = index; }; + virtual int getWorkspaceIndex() const { return m_settings.m_workspaceIndex; }; + virtual void setGeometryBytes(const QByteArray& blob) { m_settings.m_geometryBytes = blob; }; + virtual QByteArray getGeometryBytes() const { return m_settings.m_geometryBytes; }; + virtual QString getTitle() const { return m_settings.m_title; }; + virtual QColor getTitleColor() const { return m_settings.m_rgbColor; }; + virtual void zetHidden(bool hidden) { m_settings.m_hidden = hidden; } + virtual bool getHidden() const { return m_settings.m_hidden; } + virtual ChannelMarker& getChannelMarker() { return m_channelMarker; } virtual MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; } + virtual int getStreamIndex() const { return m_settings.m_streamIndex; } + virtual void setStreamIndex(int streamIndex) { m_settings.m_streamIndex = streamIndex; } static const char* const m_strChannelID; +protected: + void resizeEvent(QResizeEvent* size); + private slots: void channelMarkerChangedByCursor(); void channelMarkerHighlightedByCursor(); @@ -68,8 +81,8 @@ private slots: void tickMeter(); void on_cmbStandard_currentIndexChanged(int index); - void on_cmbModulation_currentIndexChanged(const QString &arg1); - void on_cmbFEC_currentIndexChanged(const QString &arg1); + void on_cmbModulation_currentIndexChanged(int arg1); + void on_cmbFEC_currentIndexChanged(int arg1); void on_softLDPC_clicked(); void on_maxBitflips_valueChanged(int value); void on_chkViterbi_clicked(); @@ -101,11 +114,13 @@ private: PluginAPI* m_objPluginAPI; DeviceUISet* m_deviceUISet; - ChannelMarker m_objChannelMarker; + ChannelMarker m_channelMarker; RollupState m_rollupState; DATVDemod* m_datvDemod; MessageQueue m_inputMessageQueue; DATVDemodSettings m_settings; + qint64 m_deviceCenterFrequency; + int m_basebandSampleRate; QTimer m_objTimer; qint64 m_intPreviousDecodedData; @@ -129,7 +144,6 @@ private: void applySettings(bool force = false); void displaySettings(); void displaySystemConfiguration(); - void displayStreamIndex(); QString formatBytes(qint64 intBytes); void displayRRCParameters(bool blnVisible); @@ -137,6 +151,8 @@ private: void leaveEvent(QEvent*); void enterEvent(QEvent*); bool handleMessage(const Message& objMessage); + void makeUIConnections(); + void updateAbsoluteCenterFrequency(); }; #endif // INCLUDE_DATVDEMODGUI_H diff --git a/plugins/channelrx/demoddatv/datvdemodgui.ui b/plugins/channelrx/demoddatv/datvdemodgui.ui index 976851a62..d4ec6ce0b 100644 --- a/plugins/channelrx/demoddatv/datvdemodgui.ui +++ b/plugins/channelrx/demoddatv/datvdemodgui.ui @@ -1,7 +1,7 @@ DATVDemodGUI - + 0 @@ -1394,9 +1394,9 @@ - RollupWidget + RollupContents QWidget -
gui/rollupwidget.h
+
gui/rollupcontents.h
1
diff --git a/plugins/channelrx/demoddatv/datvdemodsettings.cpp b/plugins/channelrx/demoddatv/datvdemodsettings.cpp index ceb3b4bc5..da1d9773b 100644 --- a/plugins/channelrx/demoddatv/datvdemodsettings.cpp +++ b/plugins/channelrx/demoddatv/datvdemodsettings.cpp @@ -70,6 +70,8 @@ void DATVDemodSettings::resetToDefaults() m_reverseAPIPort = 8888; m_reverseAPIDeviceIndex = 0; m_reverseAPIChannelIndex = 0; + m_workspaceIndex = 0; + m_hidden = false; } QByteArray DATVDemodSettings::serialize() const @@ -119,6 +121,10 @@ QByteArray DATVDemodSettings::serialize() const s.writeBlob(37, m_rollupState->serialize()); } + s.writeS32(38, m_workspaceIndex); + s.writeBlob(39, m_geometryBytes); + s.writeBool(40, m_hidden); + return s.final(); } @@ -213,6 +219,10 @@ bool DATVDemodSettings::deserialize(const QByteArray& data) m_rollupState->deserialize(bytetmp); } + d.readS32(38, &m_workspaceIndex, 0); + d.readBlob(39, &m_geometryBytes); + d.readBool(40, &m_hidden, false); + validateSystemConfiguration(); return true; diff --git a/plugins/channelrx/demoddatv/datvdemodsettings.h b/plugins/channelrx/demoddatv/datvdemodsettings.h index 4d5712d7e..9c72c0a6a 100644 --- a/plugins/channelrx/demoddatv/datvdemodsettings.h +++ b/plugins/channelrx/demoddatv/datvdemodsettings.h @@ -108,6 +108,10 @@ struct DATVDemodSettings uint16_t m_reverseAPIDeviceIndex; uint16_t m_reverseAPIChannelIndex; Serializable *m_rollupState; + int m_workspaceIndex; + QByteArray m_geometryBytes; + bool m_hidden; + static const int m_softLDPCMaxMaxTrials = 50; DATVDemodSettings(); diff --git a/plugins/channelrx/demoddatv/readme.md b/plugins/channelrx/demoddatv/readme.md index d6ab075b5..52d07cd76 100644 --- a/plugins/channelrx/demoddatv/readme.md +++ b/plugins/channelrx/demoddatv/readme.md @@ -18,6 +18,8 @@ The whole bandwidth available to the channel is used. That is it runs at the dev

Interface

+The top and bottom bars of the channel window are described [here](../../../sdrgui/channel/readme.md) + ![DATV Demodulator plugin GUI](../../../doc/img/DATVDemod_plugin.png)

A: RF settings

diff --git a/plugins/channelrx/demoddsd/dsddemod.cpp b/plugins/channelrx/demoddsd/dsddemod.cpp index 05e75178a..00307028b 100644 --- a/plugins/channelrx/demoddsd/dsddemod.cpp +++ b/plugins/channelrx/demoddsd/dsddemod.cpp @@ -29,6 +29,7 @@ #include #include "SWGChannelSettings.h" +#include "SWGWorkspaceInfo.h" #include "SWGDSDDemodSettings.h" #include "SWGChannelReport.h" #include "SWGDSDDemodReport.h" @@ -98,6 +99,18 @@ DSDDemod::~DSDDemod() delete m_thread; } +void DSDDemod::setDeviceAPI(DeviceAPI *deviceAPI) +{ + if (deviceAPI != m_deviceAPI) + { + m_deviceAPI->removeChannelSinkAPI(this); + m_deviceAPI->removeChannelSink(this); + m_deviceAPI = deviceAPI; + m_deviceAPI->addChannelSink(this); + m_deviceAPI->addChannelSinkAPI(this); + } +} + uint32_t DSDDemod::getNumberOfDeviceStreams() const { return m_deviceAPI->getNbSourceStreams(); @@ -149,6 +162,10 @@ bool DSDDemod::handleMessage(const Message& cmd) DSPSignalNotification* rep = new DSPSignalNotification(notif); // make a copy qDebug() << "DSDDemod::handleMessage: DSPSignalNotification"; m_basebandSink->getInputMessageQueue()->push(rep); + // Forward to GUI if any + if (getMessageQueueToGUI()) { + getMessageQueueToGUI()->push(new DSPSignalNotification(notif)); + } return true; } @@ -352,6 +369,15 @@ int DSDDemod::webapiSettingsGet( return 200; } +int DSDDemod::webapiWorkspaceGet( + SWGSDRangel::SWGWorkspaceInfo& response, + QString& errorMessage) +{ + (void) errorMessage; + response.setIndex(m_settings.m_workspaceIndex); + return 200; +} + int DSDDemod::webapiSettingsPutPatch( bool force, const QStringList& channelSettingsKeys, diff --git a/plugins/channelrx/demoddsd/dsddemod.h b/plugins/channelrx/demoddsd/dsddemod.h index e402cad24..dd5584d1d 100644 --- a/plugins/channelrx/demoddsd/dsddemod.h +++ b/plugins/channelrx/demoddsd/dsddemod.h @@ -65,6 +65,8 @@ public: DSDDemod(DeviceAPI *deviceAPI); virtual ~DSDDemod(); virtual void destroy() { delete this; } + virtual void setDeviceAPI(DeviceAPI *deviceAPI); + virtual DeviceAPI *getDeviceAPI() { return m_deviceAPI; } using BasebandSampleSink::feed; virtual void feed(const SampleVector::const_iterator& begin, const SampleVector::const_iterator& end, bool po); @@ -96,6 +98,10 @@ public: SWGSDRangel::SWGChannelSettings& response, QString& errorMessage); + virtual int webapiWorkspaceGet( + SWGSDRangel::SWGWorkspaceInfo& response, + QString& errorMessage); + virtual int webapiSettingsPutPatch( bool force, const QStringList& channelSettingsKeys, diff --git a/plugins/channelrx/demoddsd/dsddemodgui.cpp b/plugins/channelrx/demoddsd/dsddemodgui.cpp index b6f79dea8..fc256d618 100644 --- a/plugins/channelrx/demoddsd/dsddemodgui.cpp +++ b/plugins/channelrx/demoddsd/dsddemodgui.cpp @@ -22,6 +22,7 @@ #include "ui_dsddemodgui.h" #include "dsp/scopevisxy.h" +#include "dsp/dspcommands.h" #include "plugin/pluginapi.h" #include "util/simpleserializer.h" #include "util/db.h" @@ -81,6 +82,14 @@ bool DSDDemodGUI::deserialize(const QByteArray& data) } } +void DSDDemodGUI::resizeEvent(QResizeEvent* size) +{ + int maxWidth = getRollupContents()->maximumWidth(); + int minHeight = getRollupContents()->minimumHeight() + getAdditionalHeight(); + resize(width() < maxWidth ? width() : maxWidth, minHeight); + size->accept(); +} + bool DSDDemodGUI::handleMessage(const Message& message) { if (DSDDemod::MsgConfigureDSDDemod::match(message)) @@ -94,6 +103,16 @@ bool DSDDemodGUI::handleMessage(const Message& message) blockApplySettings(false); return true; } + else if (DSPSignalNotification::match(message)) + { + DSPSignalNotification& notif = (DSPSignalNotification&) message; + m_deviceCenterFrequency = notif.getCenterFrequency(); + m_basebandSampleRate = notif.getSampleRate(); + ui->deltaFrequency->setValueRange(false, 7, -m_basebandSampleRate/2, m_basebandSampleRate/2); + ui->deltaFrequencyLabel->setToolTip(tr("Range %1 %L2 Hz").arg(QChar(0xB1)).arg(m_basebandSampleRate/2)); + updateAbsoluteCenterFrequency(); + return true; + } else { return false; @@ -117,6 +136,7 @@ void DSDDemodGUI::on_deltaFrequency_changed(qint64 value) { m_channelMarker.setCenterFrequency(value); m_settings.m_inputFrequencyOffset = m_channelMarker.getCenterFrequency(); + updateAbsoluteCenterFrequency(); applySettings(); } @@ -248,7 +268,7 @@ void DSDDemodGUI::onWidgetRolled(QWidget* widget, bool rollDown) (void) widget; (void) rollDown; - saveState(m_rollupState); + getRollupContents()->saveState(m_rollupState); applySettings(); } @@ -262,11 +282,17 @@ void DSDDemodGUI::onMenuDialogCalled(const QPoint &p) dialog.setReverseAPIPort(m_settings.m_reverseAPIPort); dialog.setReverseAPIDeviceIndex(m_settings.m_reverseAPIDeviceIndex); dialog.setReverseAPIChannelIndex(m_settings.m_reverseAPIChannelIndex); + dialog.setDefaultTitle(m_displayedName); + + if (m_deviceUISet->m_deviceMIMOEngine) + { + dialog.setNumberOfStreams(m_dsdDemod->getNumberOfDeviceStreams()); + dialog.setStreamIndex(m_settings.m_streamIndex); + } dialog.move(p); dialog.exec(); - m_settings.m_inputFrequencyOffset = m_channelMarker.getCenterFrequency(); m_settings.m_rgbColor = m_channelMarker.getColor().rgb(); m_settings.m_title = m_channelMarker.getTitle(); m_settings.m_useReverseAPI = dialog.useReverseAPI(); @@ -276,22 +302,17 @@ void DSDDemodGUI::onMenuDialogCalled(const QPoint &p) m_settings.m_reverseAPIChannelIndex = dialog.getReverseAPIChannelIndex(); setWindowTitle(m_settings.m_title); + setTitle(m_channelMarker.getTitle()); setTitleColor(m_settings.m_rgbColor); - applySettings(); - } - else if ((m_contextMenuType == ContextMenuStreamSettings) && (m_deviceUISet->m_deviceMIMOEngine)) - { - DeviceStreamSelectionDialog dialog(this); - dialog.setNumberOfStreams(m_dsdDemod->getNumberOfDeviceStreams()); - dialog.setStreamIndex(m_settings.m_streamIndex); - dialog.move(p); - dialog.exec(); + if (m_deviceUISet->m_deviceMIMOEngine) + { + m_settings.m_streamIndex = dialog.getSelectedStreamIndex(); + m_channelMarker.clearStreamIndexes(); + m_channelMarker.addStreamIndex(m_settings.m_streamIndex); + updateIndexLabel(); + } - m_settings.m_streamIndex = dialog.getSelectedStreamIndex(); - m_channelMarker.clearStreamIndexes(); - m_channelMarker.addStreamIndex(m_settings.m_streamIndex); - displayStreamIndex(); applySettings(); } @@ -310,6 +331,8 @@ DSDDemodGUI::DSDDemodGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, Baseban m_pluginAPI(pluginAPI), m_deviceUISet(deviceUISet), m_channelMarker(this), + m_deviceCenterFrequency(0), + m_basebandSampleRate(1), m_doApplySettings(true), m_enableCosineFiltering(false), m_syncOrConstellation(false), @@ -321,13 +344,17 @@ DSDDemodGUI::DSDDemodGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, Baseban m_tickCount(0), m_dsdStatusTextDialog(0) { - ui->setupUi(this); + setAttribute(Qt::WA_DeleteOnClose, true); m_helpURL = "plugins/channelrx/demoddsd/readme.md"; + RollupContents *rollupContents = getRollupContents(); + ui->setupUi(rollupContents); + setSizePolicy(rollupContents->sizePolicy()); + rollupContents->arrangeRollups(); + connect(rollupContents, SIGNAL(widgetRolled(QWidget*,bool)), this, SLOT(onWidgetRolled(QWidget*,bool))); + ui->screenTV->setColor(true); ui->screenTV->resizeTVScreen(200,200); - 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())); @@ -372,7 +399,6 @@ DSDDemodGUI::DSDDemodGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, Baseban m_channelMarker.setVisible(true); // activate signal on the last setting only m_deviceUISet->addChannelMarker(&m_channelMarker); - m_deviceUISet->addRollupWidget(this); connect(&m_channelMarker, SIGNAL(changedByCursor()), this, SLOT(channelMarkerChangedByCursor())); connect(&m_channelMarker, SIGNAL(highlightedByCursor()), this, SLOT(channelMarkerHighlightedByCursor())); @@ -382,12 +408,14 @@ DSDDemodGUI::DSDDemodGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, Baseban updateMyPosition(); displaySettings(); + makeUIConnections(); applySettings(true); } DSDDemodGUI::~DSDDemodGUI() { delete m_scopeVisXY; + ui->screenTV->setParent(nullptr); // Prefer memory leak to core dump... ~TVScreen() is buggy delete ui; } @@ -415,6 +443,7 @@ void DSDDemodGUI::displaySettings() setTitleColor(m_settings.m_rgbColor); setWindowTitle(m_channelMarker.getTitle()); + setTitle(m_channelMarker.getTitle()); blockApplySettings(true); @@ -461,21 +490,13 @@ void DSDDemodGUI::displaySettings() ui->traceDecayText->setText(QString("%1").arg(m_settings.m_traceDecay)); m_scopeVisXY->setDecay(m_settings.m_traceDecay); - displayStreamIndex(); + updateIndexLabel(); - restoreState(m_rollupState); + getRollupContents()->restoreState(m_rollupState); + updateAbsoluteCenterFrequency(); blockApplySettings(false); } -void DSDDemodGUI::displayStreamIndex() -{ - if (m_deviceUISet->m_deviceMIMOEngine) { - setStreamIndicator(tr("%1").arg(m_settings.m_streamIndex)); - } else { - setStreamIndicator("S"); // single channel indicator - } -} - void DSDDemodGUI::applySettings(bool force) { if (m_doApplySettings) @@ -487,14 +508,16 @@ void DSDDemodGUI::applySettings(bool force) } } -void DSDDemodGUI::leaveEvent(QEvent*) +void DSDDemodGUI::leaveEvent(QEvent* event) { m_channelMarker.setHighlighted(false); + ChannelGUI::leaveEvent(event); } -void DSDDemodGUI::enterEvent(QEvent*) +void DSDDemodGUI::enterEvent(QEvent* event) { m_channelMarker.setHighlighted(true); + ChannelGUI::enterEvent(event); } void DSDDemodGUI::blockApplySettings(bool block) @@ -614,3 +637,30 @@ void DSDDemodGUI::tick() m_tickCount++; } + +void DSDDemodGUI::makeUIConnections() +{ + QObject::connect(ui->deltaFrequency, &ValueDialZ::changed, this, &DSDDemodGUI::on_deltaFrequency_changed); + QObject::connect(ui->rfBW, &QSlider::valueChanged, this, &DSDDemodGUI::on_rfBW_valueChanged); + QObject::connect(ui->demodGain, &QSlider::valueChanged, this, &DSDDemodGUI::on_demodGain_valueChanged); + QObject::connect(ui->volume, &QDial::valueChanged, this, &DSDDemodGUI::on_volume_valueChanged); + QObject::connect(ui->baudRate, QOverload::of(&QComboBox::currentIndexChanged), this, &DSDDemodGUI::on_baudRate_currentIndexChanged); + QObject::connect(ui->enableCosineFiltering, &ButtonSwitch::toggled, this, &DSDDemodGUI::on_enableCosineFiltering_toggled); + QObject::connect(ui->syncOrConstellation, &QToolButton::toggled, this, &DSDDemodGUI::on_syncOrConstellation_toggled); + QObject::connect(ui->traceLength, &QDial::valueChanged, this, &DSDDemodGUI::on_traceLength_valueChanged); + QObject::connect(ui->traceStroke, &QDial::valueChanged, this, &DSDDemodGUI::on_traceStroke_valueChanged); + QObject::connect(ui->traceDecay, &QDial::valueChanged, this, &DSDDemodGUI::on_traceDecay_valueChanged); + QObject::connect(ui->tdmaStereoSplit, &QToolButton::toggled, this, &DSDDemodGUI::on_tdmaStereoSplit_toggled); + QObject::connect(ui->fmDeviation, &QSlider::valueChanged, this, &DSDDemodGUI::on_fmDeviation_valueChanged); + QObject::connect(ui->squelchGate, &QDial::valueChanged, this, &DSDDemodGUI::on_squelchGate_valueChanged); + QObject::connect(ui->squelch, &QDial::valueChanged, this, &DSDDemodGUI::on_squelch_valueChanged); + QObject::connect(ui->highPassFilter, &ButtonSwitch::toggled, this, &DSDDemodGUI::on_highPassFilter_toggled); + QObject::connect(ui->audioMute, &QToolButton::toggled, this, &DSDDemodGUI::on_audioMute_toggled); + QObject::connect(ui->symbolPLLLock, &QToolButton::toggled, this, &DSDDemodGUI::on_symbolPLLLock_toggled); + QObject::connect(ui->viewStatusLog, &QPushButton::clicked, this, &DSDDemodGUI::on_viewStatusLog_clicked); +} + +void DSDDemodGUI::updateAbsoluteCenterFrequency() +{ + setStatusFrequency(m_deviceCenterFrequency + m_settings.m_inputFrequencyOffset); +} diff --git a/plugins/channelrx/demoddsd/dsddemodgui.h b/plugins/channelrx/demoddsd/dsddemodgui.h index d72985ae5..e5de1b302 100644 --- a/plugins/channelrx/demoddsd/dsddemodgui.h +++ b/plugins/channelrx/demoddsd/dsddemodgui.h @@ -52,11 +52,25 @@ public: QByteArray serialize() const; bool deserialize(const QByteArray& data); virtual MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; } + virtual void setWorkspaceIndex(int index) { m_settings.m_workspaceIndex = index; }; + virtual int getWorkspaceIndex() const { return m_settings.m_workspaceIndex; }; + virtual void setGeometryBytes(const QByteArray& blob) { m_settings.m_geometryBytes = blob; }; + virtual QByteArray getGeometryBytes() const { return m_settings.m_geometryBytes; }; + virtual QString getTitle() const { return m_settings.m_title; }; + virtual QColor getTitleColor() const { return m_settings.m_rgbColor; }; + virtual void zetHidden(bool hidden) { m_settings.m_hidden = hidden; } + virtual bool getHidden() const { return m_settings.m_hidden; } + virtual ChannelMarker& getChannelMarker() { return m_channelMarker; } + virtual int getStreamIndex() const { return m_settings.m_streamIndex; } + virtual void setStreamIndex(int streamIndex) { m_settings.m_streamIndex = streamIndex; } public slots: void channelMarkerChangedByCursor(); void channelMarkerHighlightedByCursor(); +protected: + void resizeEvent(QResizeEvent* size); + private: // typedef enum // { @@ -73,6 +87,8 @@ private: ChannelMarker m_channelMarker; RollupState m_rollupState; DSDDemodSettings m_settings; + qint64 m_deviceCenterFrequency; + int m_basebandSampleRate; bool m_doApplySettings; ScopeVisXY* m_scopeVisXY; @@ -101,9 +117,10 @@ private: void blockApplySettings(bool block); void applySettings(bool force = false); void displaySettings(); - void displayStreamIndex(); void updateMyPosition(); bool handleMessage(const Message& message); + void makeUIConnections(); + void updateAbsoluteCenterFrequency(); void leaveEvent(QEvent*); void enterEvent(QEvent*); diff --git a/plugins/channelrx/demoddsd/dsddemodgui.ui b/plugins/channelrx/demoddsd/dsddemodgui.ui index 68565f0c5..781d39d68 100644 --- a/plugins/channelrx/demoddsd/dsddemodgui.ui +++ b/plugins/channelrx/demoddsd/dsddemodgui.ui @@ -1,7 +1,7 @@ DSDDemodGUI - + 0 @@ -11,7 +11,7 @@ - + 0 0 @@ -19,7 +19,13 @@ 650 - 0 + 392 + + + + + 750 + 392 @@ -1232,15 +1238,16 @@ - RollupWidget + RollupContents QWidget -
gui/rollupwidget.h
+
gui/rollupcontents.h
1
- ButtonSwitch - QToolButton -
gui/buttonswitch.h
+ ValueDialZ + QWidget +
gui/valuedialz.h
+ 1
LevelMeterSignalDB @@ -1249,10 +1256,9 @@ 1 - ValueDialZ - QWidget -
gui/valuedialz.h
- 1 + ButtonSwitch + QToolButton +
gui/buttonswitch.h
TVScreen diff --git a/plugins/channelrx/demoddsd/dsddemodsettings.cpp b/plugins/channelrx/demoddsd/dsddemodsettings.cpp index 02dd24b33..ed7a6394f 100644 --- a/plugins/channelrx/demoddsd/dsddemodsettings.cpp +++ b/plugins/channelrx/demoddsd/dsddemodsettings.cpp @@ -59,6 +59,8 @@ void DSDDemodSettings::resetToDefaults() m_reverseAPIPort = 8888; m_reverseAPIDeviceIndex = 0; m_reverseAPIChannelIndex = 0; + m_workspaceIndex = 0; + m_hidden = false; } QByteArray DSDDemodSettings::serialize() const @@ -102,6 +104,10 @@ QByteArray DSDDemodSettings::serialize() const s.writeBlob(31, m_rollupState->serialize()); } + s.writeS32(32, m_workspaceIndex); + s.writeBlob(33, m_geometryBytes); + s.writeBool(34, m_hidden); + return s.final(); } @@ -181,6 +187,10 @@ bool DSDDemodSettings::deserialize(const QByteArray& data) m_rollupState->deserialize(bytetmp); } + d.readS32(32, &m_workspaceIndex, 0); + d.readBlob(33, &m_geometryBytes); + d.readBool(34, &m_hidden, false); + return true; } else diff --git a/plugins/channelrx/demoddsd/dsddemodsettings.h b/plugins/channelrx/demoddsd/dsddemodsettings.h index e16dd5d7d..3339be650 100644 --- a/plugins/channelrx/demoddsd/dsddemodsettings.h +++ b/plugins/channelrx/demoddsd/dsddemodsettings.h @@ -52,6 +52,9 @@ struct DSDDemodSettings uint16_t m_reverseAPIPort; uint16_t m_reverseAPIDeviceIndex; uint16_t m_reverseAPIChannelIndex; + int m_workspaceIndex; + QByteArray m_geometryBytes; + bool m_hidden; Serializable *m_channelMarker; Serializable *m_rollupState; diff --git a/plugins/channelrx/demoddsd/readme.md b/plugins/channelrx/demoddsd/readme.md index e4ca43dff..7c8712eaa 100644 --- a/plugins/channelrx/demoddsd/readme.md +++ b/plugins/channelrx/demoddsd/readme.md @@ -52,6 +52,8 @@ For software built from source if you choose to have `mbelib` support you will n

Interface

+The top and bottom bars of the channel window are described [here](../../../sdrgui/channel/readme.md) + ![DSD Demodulator plugin GUI](../../../doc/img/DSDdemod_plugin.png)

A section: settings

diff --git a/plugins/channelrx/demodfreedv/freedvdemod.cpp b/plugins/channelrx/demodfreedv/freedvdemod.cpp index e8e92b373..72e1fab64 100644 --- a/plugins/channelrx/demodfreedv/freedvdemod.cpp +++ b/plugins/channelrx/demodfreedv/freedvdemod.cpp @@ -22,6 +22,7 @@ #include #include "SWGChannelSettings.h" +#include "SWGWorkspaceInfo.h" #include "SWGFreeDVDemodSettings.h" #include "SWGChannelReport.h" #include "SWGFreeDVDemodReport.h" @@ -89,6 +90,18 @@ FreeDVDemod::~FreeDVDemod() delete m_thread; } +void FreeDVDemod::setDeviceAPI(DeviceAPI *deviceAPI) +{ + if (deviceAPI != m_deviceAPI) + { + m_deviceAPI->removeChannelSinkAPI(this); + m_deviceAPI->removeChannelSink(this); + m_deviceAPI = deviceAPI; + m_deviceAPI->addChannelSink(this); + m_deviceAPI->addChannelSinkAPI(this); + } +} + uint32_t FreeDVDemod::getNumberOfDeviceStreams() const { return m_deviceAPI->getNbSourceStreams(); @@ -151,6 +164,10 @@ bool FreeDVDemod::handleMessage(const Message& cmd) DSPSignalNotification* rep = new DSPSignalNotification(notif); // make a copy qDebug() << "FreeDVDemod::handleMessage: DSPSignalNotification"; m_basebandSink->getInputMessageQueue()->push(rep); + // Forward to GUI if any + if (getMessageQueueToGUI()) { + getMessageQueueToGUI()->push(new DSPSignalNotification(notif)); + } return true; } @@ -293,6 +310,15 @@ int FreeDVDemod::webapiSettingsGet( return 200; } +int FreeDVDemod::webapiWorkspaceGet( + SWGSDRangel::SWGWorkspaceInfo& response, + QString& errorMessage) +{ + (void) errorMessage; + response.setIndex(m_settings.m_workspaceIndex); + return 200; +} + int FreeDVDemod::webapiSettingsPutPatch( bool force, const QStringList& channelSettingsKeys, diff --git a/plugins/channelrx/demodfreedv/freedvdemod.h b/plugins/channelrx/demodfreedv/freedvdemod.h index 8404998d8..226b6173c 100644 --- a/plugins/channelrx/demodfreedv/freedvdemod.h +++ b/plugins/channelrx/demodfreedv/freedvdemod.h @@ -77,6 +77,8 @@ public: FreeDVDemod(DeviceAPI *deviceAPI); virtual ~FreeDVDemod(); virtual void destroy() { delete this; } + virtual void setDeviceAPI(DeviceAPI *deviceAPI); + virtual DeviceAPI *getDeviceAPI() { return m_deviceAPI; } SpectrumVis *getSpectrumVis() { return &m_spectrumVis; } using BasebandSampleSink::feed; @@ -123,6 +125,10 @@ public: SWGSDRangel::SWGChannelSettings& response, QString& errorMessage); + virtual int webapiWorkspaceGet( + SWGSDRangel::SWGWorkspaceInfo& response, + QString& errorMessage); + virtual int webapiSettingsPutPatch( bool force, const QStringList& channelSettingsKeys, diff --git a/plugins/channelrx/demodfreedv/freedvdemodgui.cpp b/plugins/channelrx/demodfreedv/freedvdemodgui.cpp index 51138defa..6f534d75b 100644 --- a/plugins/channelrx/demodfreedv/freedvdemodgui.cpp +++ b/plugins/channelrx/demodfreedv/freedvdemodgui.cpp @@ -95,6 +95,16 @@ bool FreeDVDemodGUI::handleMessage(const Message& message) applyBandwidths(5 - ui->spanLog2->value()); // will update spectrum details with new sample rate return true; } + else if (DSPSignalNotification::match(message)) + { + DSPSignalNotification& notif = (DSPSignalNotification&) message; + m_deviceCenterFrequency = notif.getCenterFrequency(); + m_basebandSampleRate = notif.getSampleRate(); + ui->deltaFrequency->setValueRange(false, 7, -m_basebandSampleRate/2, m_basebandSampleRate/2); + ui->deltaFrequencyLabel->setToolTip(tr("Range %1 %L2 Hz").arg(QChar(0xB1)).arg(m_basebandSampleRate/2)); + updateAbsoluteCenterFrequency(); + return true; + } else { return false; @@ -130,6 +140,7 @@ void FreeDVDemodGUI::on_deltaFrequency_changed(qint64 value) { m_channelMarker.setCenterFrequency(value); m_settings.m_inputFrequencyOffset = m_channelMarker.getCenterFrequency(); + updateAbsoluteCenterFrequency(); applySettings(); } @@ -195,11 +206,17 @@ void FreeDVDemodGUI::onMenuDialogCalled(const QPoint &p) dialog.setReverseAPIPort(m_settings.m_reverseAPIPort); dialog.setReverseAPIDeviceIndex(m_settings.m_reverseAPIDeviceIndex); dialog.setReverseAPIChannelIndex(m_settings.m_reverseAPIChannelIndex); + dialog.setDefaultTitle(m_displayedName); + + if (m_deviceUISet->m_deviceMIMOEngine) + { + dialog.setNumberOfStreams(m_freeDVDemod->getNumberOfDeviceStreams()); + dialog.setStreamIndex(m_settings.m_streamIndex); + } dialog.move(p); dialog.exec(); - m_settings.m_inputFrequencyOffset = m_channelMarker.getCenterFrequency(); m_settings.m_rgbColor = m_channelMarker.getColor().rgb(); m_settings.m_title = m_channelMarker.getTitle(); m_settings.m_useReverseAPI = dialog.useReverseAPI(); @@ -209,22 +226,17 @@ void FreeDVDemodGUI::onMenuDialogCalled(const QPoint &p) m_settings.m_reverseAPIChannelIndex = dialog.getReverseAPIChannelIndex(); setWindowTitle(m_settings.m_title); + setTitle(m_channelMarker.getTitle()); setTitleColor(m_settings.m_rgbColor); - applySettings(); - } - else if ((m_contextMenuType == ContextMenuStreamSettings) && (m_deviceUISet->m_deviceMIMOEngine)) - { - DeviceStreamSelectionDialog dialog(this); - dialog.setNumberOfStreams(m_freeDVDemod->getNumberOfDeviceStreams()); - dialog.setStreamIndex(m_settings.m_streamIndex); - dialog.move(p); - dialog.exec(); + if (m_deviceUISet->m_deviceMIMOEngine) + { + m_settings.m_streamIndex = dialog.getSelectedStreamIndex(); + m_channelMarker.clearStreamIndexes(); + m_channelMarker.addStreamIndex(m_settings.m_streamIndex); + updateIndexLabel(); + } - m_settings.m_streamIndex = dialog.getSelectedStreamIndex(); - m_channelMarker.clearStreamIndexes(); - m_channelMarker.addStreamIndex(m_settings.m_streamIndex); - displayStreamIndex(); applySettings(); } @@ -236,7 +248,18 @@ void FreeDVDemodGUI::onWidgetRolled(QWidget* widget, bool rollDown) (void) widget; (void) rollDown; - saveState(m_rollupState); + RollupContents *rollupContents = getRollupContents(); + + if (rollupContents->hasExpandableWidgets()) { + setSizePolicy(sizePolicy().horizontalPolicy(), QSizePolicy::Expanding); + } else { + setSizePolicy(sizePolicy().horizontalPolicy(), QSizePolicy::Fixed); + } + + int h = rollupContents->height() + getAdditionalHeight(); + resize(width(), h); + + rollupContents->saveState(m_rollupState); applySettings(); } @@ -246,6 +269,8 @@ FreeDVDemodGUI::FreeDVDemodGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, B m_pluginAPI(pluginAPI), m_deviceUISet(deviceUISet), m_channelMarker(this), + m_deviceCenterFrequency(0), + m_basebandSampleRate(1), m_doApplySettings(true), m_spectrumRate(6000), m_audioBinaural(false), @@ -254,10 +279,13 @@ FreeDVDemodGUI::FreeDVDemodGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, B m_squelchOpen(false), m_audioSampleRate(-1) { - ui->setupUi(this); - m_helpURL = "plugins/channelrx/demodfreedv/readme.md"; setAttribute(Qt::WA_DeleteOnClose, true); - connect(this, SIGNAL(widgetRolled(QWidget*,bool)), this, SLOT(onWidgetRolled(QWidget*,bool))); + m_helpURL = "plugins/channelrx/demodfreedv/readme.md"; + RollupContents *rollupContents = getRollupContents(); + ui->setupUi(rollupContents); + setSizePolicy(rollupContents->sizePolicy()); + rollupContents->arrangeRollups(); + connect(rollupContents, SIGNAL(widgetRolled(QWidget*,bool)), this, SLOT(onWidgetRolled(QWidget*,bool))); connect(this, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(onMenuDialogCalled(const QPoint &))); m_freeDVDemod = (FreeDVDemod*) rxChannel; @@ -293,7 +321,6 @@ FreeDVDemodGUI::FreeDVDemodGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, B m_settings.setRollupState(&m_rollupState); m_deviceUISet->addChannelMarker(&m_channelMarker); - m_deviceUISet->addRollupWidget(this); connect(&m_channelMarker, SIGNAL(changedByCursor()), this, SLOT(channelMarkerChangedByCursor())); connect(&m_channelMarker, SIGNAL(highlightedByCursor()), this, SLOT(channelMarkerHighlightedByCursor())); @@ -308,6 +335,7 @@ FreeDVDemodGUI::FreeDVDemodGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, B m_iconDSBLSB.addPixmap(QPixmap("://lsb.png"), QIcon::Normal, QIcon::Off); displaySettings(); + makeUIConnections(); applyBandwidths(5 - ui->spanLog2->value(), true); // does applySettings(true) } @@ -371,6 +399,7 @@ void FreeDVDemodGUI::displaySettings() setTitleColor(m_settings.m_rgbColor); setWindowTitle(m_channelMarker.getTitle()); + setTitle(m_channelMarker.getTitle()); blockApplySettings(true); @@ -391,29 +420,23 @@ void FreeDVDemodGUI::displaySettings() ui->volumeIn->setValue(m_settings.m_volumeIn * 10.0); ui->volumeInText->setText(QString("%1").arg(m_settings.m_volumeIn, 0, 'f', 1)); - displayStreamIndex(); + updateIndexLabel(); - restoreState(m_rollupState); + getRollupContents()->restoreState(m_rollupState); + updateAbsoluteCenterFrequency(); blockApplySettings(false); } -void FreeDVDemodGUI::displayStreamIndex() -{ - if (m_deviceUISet->m_deviceMIMOEngine) { - setStreamIndicator(tr("%1").arg(m_settings.m_streamIndex)); - } else { - setStreamIndicator("S"); // single channel indicator - } -} - -void FreeDVDemodGUI::leaveEvent(QEvent*) +void FreeDVDemodGUI::leaveEvent(QEvent* event) { m_channelMarker.setHighlighted(false); + ChannelGUI::leaveEvent(event); } -void FreeDVDemodGUI::enterEvent(QEvent*) +void FreeDVDemodGUI::enterEvent(QEvent* event) { m_channelMarker.setHighlighted(true); + ChannelGUI::enterEvent(event); } void FreeDVDemodGUI::audioSelect() @@ -487,3 +510,19 @@ void FreeDVDemodGUI::tick() m_tickCount++; } + +void FreeDVDemodGUI::makeUIConnections() +{ + QObject::connect(ui->deltaFrequency, &ValueDialZ::changed, this, &FreeDVDemodGUI::on_deltaFrequency_changed); + QObject::connect(ui->reSync, &QPushButton::clicked, this, &FreeDVDemodGUI::on_reSync_clicked); + QObject::connect(ui->freeDVMode, QOverload::of(&QComboBox::currentIndexChanged), this, &FreeDVDemodGUI::on_freeDVMode_currentIndexChanged); + QObject::connect(ui->volume, &QDial::valueChanged, this, &FreeDVDemodGUI::on_volume_valueChanged); + QObject::connect(ui->volumeIn, &QDial::valueChanged, this, &FreeDVDemodGUI::on_volumeIn_valueChanged); + QObject::connect(ui->agc, &ButtonSwitch::toggled, this, &FreeDVDemodGUI::on_agc_toggled); + QObject::connect(ui->audioMute, &QToolButton::toggled, this, &FreeDVDemodGUI::on_audioMute_toggled); +} + +void FreeDVDemodGUI::updateAbsoluteCenterFrequency() +{ + setStatusFrequency(m_deviceCenterFrequency + m_settings.m_inputFrequencyOffset); +} diff --git a/plugins/channelrx/demodfreedv/freedvdemodgui.h b/plugins/channelrx/demodfreedv/freedvdemodgui.h index d36c30436..8d9be693d 100644 --- a/plugins/channelrx/demodfreedv/freedvdemodgui.h +++ b/plugins/channelrx/demodfreedv/freedvdemodgui.h @@ -50,6 +50,17 @@ public: QByteArray serialize() const; bool deserialize(const QByteArray& data); virtual MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; } + virtual void setWorkspaceIndex(int index) { m_settings.m_workspaceIndex = index; }; + virtual int getWorkspaceIndex() const { return m_settings.m_workspaceIndex; }; + virtual void setGeometryBytes(const QByteArray& blob) { m_settings.m_geometryBytes = blob; }; + virtual QByteArray getGeometryBytes() const { return m_settings.m_geometryBytes; }; + virtual QString getTitle() const { return m_settings.m_title; }; + virtual QColor getTitleColor() const { return m_settings.m_rgbColor; }; + virtual void zetHidden(bool hidden) { m_settings.m_hidden = hidden; } + virtual bool getHidden() const { return m_settings.m_hidden; } + virtual ChannelMarker& getChannelMarker() { return m_channelMarker; } + virtual int getStreamIndex() const { return m_settings.m_streamIndex; } + virtual void setStreamIndex(int streamIndex) { m_settings.m_streamIndex = streamIndex; } public slots: void channelMarkerChangedByCursor(); @@ -62,6 +73,8 @@ private: ChannelMarker m_channelMarker; RollupState m_rollupState; FreeDVDemodSettings m_settings; + qint64 m_deviceCenterFrequency; + int m_basebandSampleRate; bool m_doApplySettings; int m_spectrumRate; bool m_audioBinaural; @@ -86,8 +99,9 @@ private: void applyBandwidths(int spanLog2, bool force = false); void displayBandwidths(int spanLog2); void displaySettings(); - void displayStreamIndex(); bool handleMessage(const Message& message); + void makeUIConnections(); + void updateAbsoluteCenterFrequency(); void leaveEvent(QEvent*); void enterEvent(QEvent*); diff --git a/plugins/channelrx/demodfreedv/freedvdemodgui.ui b/plugins/channelrx/demodfreedv/freedvdemodgui.ui index f30eada83..a9f8f818c 100644 --- a/plugins/channelrx/demodfreedv/freedvdemodgui.ui +++ b/plugins/channelrx/demodfreedv/freedvdemodgui.ui @@ -1,17 +1,17 @@ FreeDVDemodGUI - + 0 0 - 442 - 523 + 412 + 478 - + 0 0 @@ -36,7 +36,7 @@ 0 0 - 441 + 410 171 @@ -661,12 +661,24 @@ - 10 + 0 170 - 218 + 410 284 + + + 0 + 0 + + + + + 410 + 0 + + Channel Spectrum @@ -688,6 +700,12 @@
+ + + 0 + 0 + + 200 @@ -710,17 +728,28 @@ - RollupWidget + RollupContents QWidget -
gui/rollupwidget.h
+
gui/rollupcontents.h
1
+ + ButtonSwitch + QToolButton +
gui/buttonswitch.h
+
LevelMeterSignalDB QWidget
gui/levelmeter.h
1
+ + ValueDialZ + QWidget +
gui/valuedialz.h
+ 1 +
GLSpectrum QWidget @@ -733,17 +762,6 @@
gui/glspectrumgui.h
1
- - ValueDialZ - QWidget -
gui/valuedialz.h
- 1 -
- - ButtonSwitch - QToolButton -
gui/buttonswitch.h
-
LevelMeterVU QWidget diff --git a/plugins/channelrx/demodfreedv/freedvdemodsettings.cpp b/plugins/channelrx/demodfreedv/freedvdemodsettings.cpp index f5fea767f..26a2de4b1 100644 --- a/plugins/channelrx/demodfreedv/freedvdemodsettings.cpp +++ b/plugins/channelrx/demodfreedv/freedvdemodsettings.cpp @@ -56,6 +56,8 @@ void FreeDVDemodSettings::resetToDefaults() m_reverseAPIPort = 8888; m_reverseAPIDeviceIndex = 0; m_reverseAPIChannelIndex = 0; + m_workspaceIndex = 0; + m_hidden = false; } QByteArray FreeDVDemodSettings::serialize() const @@ -86,6 +88,10 @@ QByteArray FreeDVDemodSettings::serialize() const s.writeBlob(25, m_rollupState->serialize()); } + s.writeS32(26, m_workspaceIndex); + s.writeBlob(27, m_geometryBytes); + s.writeBool(28, m_hidden); + return s.final(); } @@ -154,6 +160,10 @@ bool FreeDVDemodSettings::deserialize(const QByteArray& data) m_rollupState->deserialize(bytetmp); } + d.readS32(26, &m_workspaceIndex, 0); + d.readBlob(27, &m_geometryBytes); + d.readBool(28, &m_hidden, false); + return true; } else diff --git a/plugins/channelrx/demodfreedv/freedvdemodsettings.h b/plugins/channelrx/demodfreedv/freedvdemodsettings.h index ef3ce36eb..293d94747 100644 --- a/plugins/channelrx/demodfreedv/freedvdemodsettings.h +++ b/plugins/channelrx/demodfreedv/freedvdemodsettings.h @@ -51,6 +51,9 @@ struct FreeDVDemodSettings uint16_t m_reverseAPIPort; uint16_t m_reverseAPIDeviceIndex; uint16_t m_reverseAPIChannelIndex; + int m_workspaceIndex; + QByteArray m_geometryBytes; + bool m_hidden; Serializable *m_channelMarker; Serializable *m_spectrumGUI; diff --git a/plugins/channelrx/demodfreedv/readme.md b/plugins/channelrx/demodfreedv/readme.md index 4d8d13f40..afaac4609 100644 --- a/plugins/channelrx/demodfreedv/readme.md +++ b/plugins/channelrx/demodfreedv/readme.md @@ -8,6 +8,8 @@ This plugin can be used to demodulate a signal following the [FreeDV digital voi

Interface

+The top and bottom bars of the channel window are described [here](../../../sdrgui/channel/readme.md) + ![FreeDV Demodulator plugin GUI](../../../doc/img/FreeDVDemod_plugin.png)

1: Frequency shift from center frequency of reception

@@ -21,7 +23,7 @@ Average total power in dB relative to a +/- 1.0 amplitude signal received in the

3: Manual re-synchronization

This works only for the presently disabled 700D mode. Use this push button to force loosing and re-acquiring synchronisation. - +

4: FreeDV mode

Use this combo box to select which FreeDV standard is used. The following are supported: @@ -30,7 +32,7 @@ Use this combo box to select which FreeDV standard is used. The following are su - `1600`: OFDM (16 QPSK carriers) narrowband (1.4 kHz) with 700 b/s compressed voice - `800XA`: FSK-4 narrowband (2 kHz) with 700 b/s compressed voice - `700C`: Another OFDM (14 QPSK carriers) narrowband (1.5 kHz) mode with 700 b/s compressed voice - +

5: Level meter in dB

- top bar (green): average value @@ -86,7 +88,7 @@ The transmitted signal is further decimated by a power of two before being appli - 4: 6 kHz (2400A) or 1 kHz (other modes) - 8: 3 kHz (2400A) or 0.5 kHz (other modes) - 16: 1.5 kHz (2400A) or 0.25 kHz (other modes) - +

9: Spectrum display

This is the spectrum display of the analog signal that enters the modem before AGC and volume control. Controls on the bottom of the panel are identical to the ones of the main spectrum display. It should be optimally centered using the frequency offset control (1) depending on the expected FreeDV mode: diff --git a/plugins/channelrx/demodnfm/nfmdemod.cpp b/plugins/channelrx/demodnfm/nfmdemod.cpp index b73140806..39c323b6d 100644 --- a/plugins/channelrx/demodnfm/nfmdemod.cpp +++ b/plugins/channelrx/demodnfm/nfmdemod.cpp @@ -27,6 +27,7 @@ #include #include "SWGChannelSettings.h" +#include "SWGWorkspaceInfo.h" #include "SWGNFMDemodSettings.h" #include "SWGChannelReport.h" #include "SWGNFMDemodReport.h" @@ -102,6 +103,18 @@ NFMDemod::~NFMDemod() delete m_thread; } +void NFMDemod::setDeviceAPI(DeviceAPI *deviceAPI) +{ + if (deviceAPI != m_deviceAPI) + { + m_deviceAPI->removeChannelSinkAPI(this); + m_deviceAPI->removeChannelSink(this); + m_deviceAPI = deviceAPI; + m_deviceAPI->addChannelSink(this); + m_deviceAPI->addChannelSinkAPI(this); + } +} + uint32_t NFMDemod::getNumberOfDeviceStreams() const { return m_deviceAPI->getNbSourceStreams(); @@ -151,6 +164,10 @@ bool NFMDemod::handleMessage(const Message& cmd) DSPSignalNotification* rep = new DSPSignalNotification(notif); // make a copy qDebug() << "NFMDemod::handleMessage: DSPSignalNotification"; m_basebandSink->getInputMessageQueue()->push(rep); + // Forward to GUI if any + if (getMessageQueueToGUI()) { + getMessageQueueToGUI()->push(new DSPSignalNotification(notif)); + } return true; } @@ -342,6 +359,15 @@ int NFMDemod::webapiSettingsGet( return 200; } +int NFMDemod::webapiWorkspaceGet( + SWGSDRangel::SWGWorkspaceInfo& response, + QString& errorMessage) +{ + (void) errorMessage; + response.setIndex(m_settings.m_workspaceIndex); + return 200; +} + int NFMDemod::webapiSettingsPutPatch( bool force, const QStringList& channelSettingsKeys, diff --git a/plugins/channelrx/demodnfm/nfmdemod.h b/plugins/channelrx/demodnfm/nfmdemod.h index 6581b053f..4e311d12c 100644 --- a/plugins/channelrx/demodnfm/nfmdemod.h +++ b/plugins/channelrx/demodnfm/nfmdemod.h @@ -64,6 +64,8 @@ public: NFMDemod(DeviceAPI *deviceAPI); virtual ~NFMDemod(); virtual void destroy() { delete this; } + virtual void setDeviceAPI(DeviceAPI *deviceAPI); + virtual DeviceAPI *getDeviceAPI() { return m_deviceAPI; } using BasebandSampleSink::feed; virtual void feed(const SampleVector::const_iterator& begin, const SampleVector::const_iterator& end, bool po); @@ -95,6 +97,10 @@ public: SWGSDRangel::SWGChannelSettings& response, QString& errorMessage); + virtual int webapiWorkspaceGet( + SWGSDRangel::SWGWorkspaceInfo& response, + QString& errorMessage); + virtual int webapiSettingsPutPatch( bool force, const QStringList& channelSettingsKeys, diff --git a/plugins/channelrx/demodnfm/nfmdemodgui.cpp b/plugins/channelrx/demodnfm/nfmdemodgui.cpp index 831ac89ad..56c190aea 100644 --- a/plugins/channelrx/demodnfm/nfmdemodgui.cpp +++ b/plugins/channelrx/demodnfm/nfmdemodgui.cpp @@ -13,6 +13,7 @@ #include "gui/audioselectdialog.h" #include "dsp/dspengine.h" #include "dsp/dcscodes.h" +#include "dsp/dspcommands.h" #include "maincore.h" #include "nfmdemodreport.h" @@ -54,6 +55,14 @@ bool NFMDemodGUI::deserialize(const QByteArray& data) } } +void NFMDemodGUI::resizeEvent(QResizeEvent* size) +{ + int maxWidth = getRollupContents()->maximumWidth(); + int minHeight = getRollupContents()->minimumHeight() + getAdditionalHeight(); + resize(width() < maxWidth ? width() : maxWidth, minHeight); + size->accept(); +} + bool NFMDemodGUI::handleMessage(const Message& message) { if (NFMDemodReport::MsgReportCTCSSFreq::match(message)) @@ -80,6 +89,16 @@ bool NFMDemodGUI::handleMessage(const Message& message) blockApplySettings(false); return true; } + else if (DSPSignalNotification::match(message)) + { + DSPSignalNotification& notif = (DSPSignalNotification&) message; + m_deviceCenterFrequency = notif.getCenterFrequency(); + m_basebandSampleRate = notif.getSampleRate(); + ui->deltaFrequency->setValueRange(false, 7, -m_basebandSampleRate/2, m_basebandSampleRate/2); + ui->deltaFrequencyLabel->setToolTip(tr("Range %1 %L2 Hz").arg(QChar(0xB1)).arg(m_basebandSampleRate/2)); + updateAbsoluteCenterFrequency(); + return true; + } return false; } @@ -113,6 +132,7 @@ void NFMDemodGUI::on_deltaFrequency_changed(qint64 value) { m_channelMarker.setCenterFrequency(value); m_settings.m_inputFrequencyOffset = m_channelMarker.getCenterFrequency(); + updateAbsoluteCenterFrequency(); applySettings(); } @@ -280,7 +300,7 @@ void NFMDemodGUI::onWidgetRolled(QWidget* widget, bool rollDown) m_nfmDemod->setSpectrum(m_threadedSampleSink->getMessageQueue(), rollDown); */ - saveState(m_rollupState); + getRollupContents()->saveState(m_rollupState); applySettings(); } @@ -294,10 +314,17 @@ void NFMDemodGUI::onMenuDialogCalled(const QPoint &p) dialog.setReverseAPIPort(m_settings.m_reverseAPIPort); dialog.setReverseAPIDeviceIndex(m_settings.m_reverseAPIDeviceIndex); dialog.setReverseAPIChannelIndex(m_settings.m_reverseAPIChannelIndex); + dialog.setDefaultTitle(m_displayedName); + + if (m_deviceUISet->m_deviceMIMOEngine) + { + dialog.setNumberOfStreams(m_nfmDemod->getNumberOfDeviceStreams()); + dialog.setStreamIndex(m_settings.m_streamIndex); + } + dialog.move(p); dialog.exec(); - m_settings.m_inputFrequencyOffset = m_channelMarker.getCenterFrequency(); m_settings.m_rgbColor = m_channelMarker.getColor().rgb(); m_settings.m_title = m_channelMarker.getTitle(); m_settings.m_useReverseAPI = dialog.useReverseAPI(); @@ -307,22 +334,17 @@ void NFMDemodGUI::onMenuDialogCalled(const QPoint &p) m_settings.m_reverseAPIChannelIndex = dialog.getReverseAPIChannelIndex(); setWindowTitle(m_settings.m_title); + setTitle(m_channelMarker.getTitle()); setTitleColor(m_settings.m_rgbColor); - applySettings(); - } - else if ((m_contextMenuType == ContextMenuStreamSettings) && (m_deviceUISet->m_deviceMIMOEngine)) - { - DeviceStreamSelectionDialog dialog(this); - dialog.setNumberOfStreams(m_nfmDemod->getNumberOfDeviceStreams()); - dialog.setStreamIndex(m_settings.m_streamIndex); - dialog.move(p); - dialog.exec(); + if (m_deviceUISet->m_deviceMIMOEngine) + { + m_settings.m_streamIndex = dialog.getSelectedStreamIndex(); + m_channelMarker.clearStreamIndexes(); + m_channelMarker.addStreamIndex(m_settings.m_streamIndex); + updateIndexLabel(); + } - m_settings.m_streamIndex = dialog.getSelectedStreamIndex(); - m_channelMarker.clearStreamIndexes(); - m_channelMarker.addStreamIndex(m_settings.m_streamIndex); - displayStreamIndex(); applySettings(); } @@ -335,6 +357,8 @@ NFMDemodGUI::NFMDemodGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, Baseban m_pluginAPI(pluginAPI), m_deviceUISet(deviceUISet), m_channelMarker(this), + m_deviceCenterFrequency(0), + m_basebandSampleRate(1), m_basicSettingsShown(false), m_doApplySettings(true), m_squelchOpen(false), @@ -343,11 +367,13 @@ NFMDemodGUI::NFMDemodGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, Baseban m_dcsShowPositive(false), m_tickCount(0) { - ui->setupUi(this); - m_helpURL = "plugins/channelrx/demodnfm/readme.md"; setAttribute(Qt::WA_DeleteOnClose, true); - - connect(this, SIGNAL(widgetRolled(QWidget*,bool)), this, SLOT(onWidgetRolled(QWidget*,bool))); + m_helpURL = "plugins/channelrx/demodnfm/readme.md"; + RollupContents *rollupContents = getRollupContents(); + ui->setupUi(rollupContents); + setSizePolicy(rollupContents->sizePolicy()); + rollupContents->arrangeRollups(); + connect(rollupContents, SIGNAL(widgetRolled(QWidget*,bool)), this, SLOT(onWidgetRolled(QWidget*,bool))); connect(this, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(onMenuDialogCalled(const QPoint &))); m_nfmDemod = reinterpret_cast(rxChannel); @@ -409,7 +435,6 @@ NFMDemodGUI::NFMDemodGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, Baseban m_settings.setRollupState(&m_rollupState); m_deviceUISet->addChannelMarker(&m_channelMarker); - m_deviceUISet->addRollupWidget(this); connect(&m_channelMarker, SIGNAL(changedByCursor()), this, SLOT(channelMarkerChangedByCursor())); connect(&m_channelMarker, SIGNAL(highlightedByCursor()), this, SLOT(channelMarkerHighlightedByCursor())); @@ -420,6 +445,7 @@ NFMDemodGUI::NFMDemodGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, Baseban connect(getInputMessageQueue(), SIGNAL(messageEnqueued()), this, SLOT(handleInputMessages())); displaySettings(); + makeUIConnections(); applySettings(true); } @@ -450,6 +476,7 @@ void NFMDemodGUI::displaySettings() setTitleColor(m_settings.m_rgbColor); setWindowTitle(m_channelMarker.getTitle()); + setTitle(m_channelMarker.getTitle()); blockApplySettings(true); @@ -507,29 +534,23 @@ void NFMDemodGUI::displaySettings() } setDcsCode(m_reportedDcsCode); - displayStreamIndex(); + updateIndexLabel(); - restoreState(m_rollupState); + getRollupContents()->restoreState(m_rollupState); + updateAbsoluteCenterFrequency(); blockApplySettings(false); } -void NFMDemodGUI::displayStreamIndex() -{ - if (m_deviceUISet->m_deviceMIMOEngine) { - setStreamIndicator(tr("%1").arg(m_settings.m_streamIndex)); - } else { - setStreamIndicator("S"); // single channel indicator - } -} - -void NFMDemodGUI::leaveEvent(QEvent*) +void NFMDemodGUI::leaveEvent(QEvent* event) { m_channelMarker.setHighlighted(false); + ChannelGUI::leaveEvent(event); } -void NFMDemodGUI::enterEvent(QEvent*) +void NFMDemodGUI::enterEvent(QEvent* event) { m_channelMarker.setHighlighted(true); + ChannelGUI::enterEvent(event); } void NFMDemodGUI::setCtcssFreq(Real ctcssFreq) @@ -611,3 +632,27 @@ void NFMDemodGUI::tick() m_tickCount++; } + +void NFMDemodGUI::makeUIConnections() +{ + QObject::connect(ui->deltaFrequency, &ValueDialZ::changed, this, &NFMDemodGUI::on_deltaFrequency_changed); + QObject::connect(ui->channelSpacingApply, &QPushButton::clicked, this, &NFMDemodGUI::on_channelSpacingApply_clicked); + QObject::connect(ui->rfBW, &QSlider::valueChanged, this, &NFMDemodGUI::on_rfBW_valueChanged); + QObject::connect(ui->afBW, &QSlider::valueChanged, this, &NFMDemodGUI::on_afBW_valueChanged); + QObject::connect(ui->fmDev, &QSlider::valueChanged, this, &NFMDemodGUI::on_fmDev_valueChanged); + QObject::connect(ui->volume, &QDial::valueChanged, this, &NFMDemodGUI::on_volume_valueChanged); + QObject::connect(ui->squelchGate, &QDial::valueChanged, this, &NFMDemodGUI::on_squelchGate_valueChanged); + QObject::connect(ui->deltaSquelch, &ButtonSwitch::toggled, this, &NFMDemodGUI::on_deltaSquelch_toggled); + QObject::connect(ui->squelch, &QDial::valueChanged, this, &NFMDemodGUI::on_squelch_valueChanged); + QObject::connect(ui->ctcss, QOverload::of(&QComboBox::currentIndexChanged), this, &NFMDemodGUI::on_ctcss_currentIndexChanged); + QObject::connect(ui->ctcssOn, &QCheckBox::toggled, this, &NFMDemodGUI::on_ctcssOn_toggled); + QObject::connect(ui->dcsOn, &QCheckBox::toggled, this, &NFMDemodGUI::on_dcsOn_toggled); + QObject::connect(ui->dcsCode, QOverload::of(&QComboBox::currentIndexChanged), this, &NFMDemodGUI::on_dcsCode_currentIndexChanged); + QObject::connect(ui->highPassFilter, &ButtonSwitch::toggled, this, &NFMDemodGUI::on_highPassFilter_toggled); + QObject::connect(ui->audioMute, &QToolButton::toggled, this, &NFMDemodGUI::on_audioMute_toggled); +} + +void NFMDemodGUI::updateAbsoluteCenterFrequency() +{ + setStatusFrequency(m_deviceCenterFrequency + m_settings.m_inputFrequencyOffset); +} diff --git a/plugins/channelrx/demodnfm/nfmdemodgui.h b/plugins/channelrx/demodnfm/nfmdemodgui.h index da1ce7d94..a2394ea8f 100644 --- a/plugins/channelrx/demodnfm/nfmdemodgui.h +++ b/plugins/channelrx/demodnfm/nfmdemodgui.h @@ -30,11 +30,25 @@ public: QByteArray serialize() const; bool deserialize(const QByteArray& data); virtual MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; } + virtual void setWorkspaceIndex(int index) { m_settings.m_workspaceIndex = index; }; + virtual int getWorkspaceIndex() const { return m_settings.m_workspaceIndex; }; + virtual void setGeometryBytes(const QByteArray& blob) { m_settings.m_geometryBytes = blob; }; + virtual QByteArray getGeometryBytes() const { return m_settings.m_geometryBytes; }; + virtual QString getTitle() const { return m_settings.m_title; }; + virtual QColor getTitleColor() const { return m_settings.m_rgbColor; }; + virtual void zetHidden(bool hidden) { m_settings.m_hidden = hidden; } + virtual bool getHidden() const { return m_settings.m_hidden; } + virtual ChannelMarker& getChannelMarker() { return m_channelMarker; } + virtual int getStreamIndex() const { return m_settings.m_streamIndex; } + virtual void setStreamIndex(int streamIndex) { m_settings.m_streamIndex = streamIndex; } public slots: void channelMarkerChangedByCursor(); void channelMarkerHighlightedByCursor(); +protected: + void resizeEvent(QResizeEvent* size); + private: Ui::NFMDemodGUI* ui; PluginAPI* m_pluginAPI; @@ -42,6 +56,8 @@ private: ChannelMarker m_channelMarker; RollupState m_rollupState; NFMDemodSettings m_settings; + qint64 m_deviceCenterFrequency; + int m_basebandSampleRate; bool m_basicSettingsShown; bool m_doApplySettings; @@ -59,10 +75,11 @@ private: void blockApplySettings(bool block); void applySettings(bool force = false); void displaySettings(); - void displayStreamIndex(); void setCtcssFreq(Real ctcssFreq); void setDcsCode(unsigned int dcsCode); bool handleMessage(const Message& message); + void makeUIConnections(); + void updateAbsoluteCenterFrequency(); void leaveEvent(QEvent*); void enterEvent(QEvent*); diff --git a/plugins/channelrx/demodnfm/nfmdemodgui.ui b/plugins/channelrx/demodnfm/nfmdemodgui.ui index 9dcac0f01..db0bcd9a9 100644 --- a/plugins/channelrx/demodnfm/nfmdemodgui.ui +++ b/plugins/channelrx/demodnfm/nfmdemodgui.ui @@ -1,25 +1,31 @@ NFMDemodGUI - + 0 0 - 364 - 200 + 360 + 197 - + 0 0 - 364 - 200 + 360 + 0 + + + + + 560 + 16777215 @@ -36,13 +42,13 @@ 0 0 - 362 + 358 191 - 362 + 358 0 @@ -778,29 +784,29 @@ - - RollupWidget - QWidget -
gui/rollupwidget.h
- 1 -
- - ButtonSwitch - QToolButton -
gui/buttonswitch.h
-
ValueDialZ QWidget
gui/valuedialz.h
1
+ + RollupContents + QWidget +
gui/rollupcontents.h
+ 1 +
LevelMeterSignalDB QWidget
gui/levelmeter.h
1
+ + ButtonSwitch + QToolButton +
gui/buttonswitch.h
+
diff --git a/plugins/channelrx/demodnfm/nfmdemodsettings.cpp b/plugins/channelrx/demodnfm/nfmdemodsettings.cpp index 3be041951..a73462ae2 100644 --- a/plugins/channelrx/demodnfm/nfmdemodsettings.cpp +++ b/plugins/channelrx/demodnfm/nfmdemodsettings.cpp @@ -74,6 +74,8 @@ void NFMDemodSettings::resetToDefaults() m_reverseAPIPort = 8888; m_reverseAPIDeviceIndex = 0; m_reverseAPIChannelIndex = 0; + m_workspaceIndex = 0; + m_hidden = false; } QByteArray NFMDemodSettings::serialize() const @@ -113,6 +115,10 @@ QByteArray NFMDemodSettings::serialize() const s.writeBlob(26, m_rollupState->serialize()); } + s.writeS32(27, m_workspaceIndex); + s.writeBlob(28, m_geometryBytes); + s.writeBool(29, m_hidden); + return s.final(); } @@ -182,6 +188,10 @@ bool NFMDemodSettings::deserialize(const QByteArray& data) m_rollupState->deserialize(bytetmp); } + d.readS32(27, &m_workspaceIndex, 0); + d.readBlob(28, &m_geometryBytes); + d.readBool(29, &m_hidden, false); + return true; } else diff --git a/plugins/channelrx/demodnfm/nfmdemodsettings.h b/plugins/channelrx/demodnfm/nfmdemodsettings.h index 3db632a36..b20fa3a2b 100644 --- a/plugins/channelrx/demodnfm/nfmdemodsettings.h +++ b/plugins/channelrx/demodnfm/nfmdemodsettings.h @@ -54,6 +54,9 @@ struct NFMDemodSettings uint16_t m_reverseAPIPort; uint16_t m_reverseAPIDeviceIndex; uint16_t m_reverseAPIChannelIndex; + int m_workspaceIndex; + QByteArray m_geometryBytes; + bool m_hidden; Serializable *m_channelMarker; Serializable *m_rollupState; diff --git a/plugins/channelrx/demodnfm/readme.md b/plugins/channelrx/demodnfm/readme.md index 8307070ce..f32ec1005 100644 --- a/plugins/channelrx/demodnfm/readme.md +++ b/plugins/channelrx/demodnfm/readme.md @@ -6,6 +6,8 @@ This plugin can be used to listen to a narrowband FM modulated signal. "Narrowba

Interface

+The top and bottom bars of the channel window are described [here](../../../sdrgui/channel/readme.md) + ![NFM Demodulator plugin GUI](../../../doc/img/NFMdemod_plugin.png)

1: Frequency shift from center frequency of reception value

diff --git a/plugins/channelrx/demodpacket/packetdemod.cpp b/plugins/channelrx/demodpacket/packetdemod.cpp index d4eafb1d5..eff76d98d 100644 --- a/plugins/channelrx/demodpacket/packetdemod.cpp +++ b/plugins/channelrx/demodpacket/packetdemod.cpp @@ -29,6 +29,7 @@ #include #include "SWGChannelSettings.h" +#include "SWGWorkspaceInfo.h" #include "SWGPacketDemodSettings.h" #include "SWGChannelReport.h" #include "SWGMapItem.h" @@ -99,6 +100,18 @@ PacketDemod::~PacketDemod() delete m_basebandSink; } +void PacketDemod::setDeviceAPI(DeviceAPI *deviceAPI) +{ + if (deviceAPI != m_deviceAPI) + { + m_deviceAPI->removeChannelSinkAPI(this); + m_deviceAPI->removeChannelSink(this); + m_deviceAPI = deviceAPI; + m_deviceAPI->addChannelSink(this); + m_deviceAPI->addChannelSinkAPI(this); + } +} + uint32_t PacketDemod::getNumberOfDeviceStreams() const { return m_deviceAPI->getNbSourceStreams(); @@ -153,10 +166,8 @@ bool PacketDemod::handleMessage(const Message& cmd) qDebug() << "PacketDemod::handleMessage: DSPSignalNotification"; m_basebandSink->getInputMessageQueue()->push(rep); // Forward to GUI if any - if (m_guiMessageQueue) - { - rep = new DSPSignalNotification(notif); - m_guiMessageQueue->push(rep); + if (m_guiMessageQueue) { + m_guiMessageQueue->push(new DSPSignalNotification(notif)); } return true; @@ -397,6 +408,15 @@ int PacketDemod::webapiSettingsGet( return 200; } +int PacketDemod::webapiWorkspaceGet( + SWGSDRangel::SWGWorkspaceInfo& response, + QString& errorMessage) +{ + (void) errorMessage; + response.setIndex(m_settings.m_workspaceIndex); + return 200; +} + int PacketDemod::webapiSettingsPutPatch( bool force, const QStringList& channelSettingsKeys, diff --git a/plugins/channelrx/demodpacket/packetdemod.h b/plugins/channelrx/demodpacket/packetdemod.h index 861ece372..f4c8ca4d5 100644 --- a/plugins/channelrx/demodpacket/packetdemod.h +++ b/plugins/channelrx/demodpacket/packetdemod.h @@ -67,6 +67,8 @@ public: PacketDemod(DeviceAPI *deviceAPI); virtual ~PacketDemod(); virtual void destroy() { delete this; } + virtual void setDeviceAPI(DeviceAPI *deviceAPI); + virtual DeviceAPI *getDeviceAPI() { return m_deviceAPI; } using BasebandSampleSink::feed; virtual void feed(const SampleVector::const_iterator& begin, const SampleVector::const_iterator& end, bool po); @@ -99,6 +101,10 @@ public: SWGSDRangel::SWGChannelSettings& response, QString& errorMessage); + virtual int webapiWorkspaceGet( + SWGSDRangel::SWGWorkspaceInfo& response, + QString& errorMessage); + virtual int webapiSettingsPutPatch( bool force, const QStringList& channelSettingsKeys, diff --git a/plugins/channelrx/demodpacket/packetdemodgui.cpp b/plugins/channelrx/demodpacket/packetdemodgui.cpp index 8b2969a03..45fc8e6d5 100644 --- a/plugins/channelrx/demodpacket/packetdemodgui.cpp +++ b/plugins/channelrx/demodpacket/packetdemodgui.cpp @@ -218,7 +218,11 @@ bool PacketDemodGUI::handleMessage(const Message& message) else if (DSPSignalNotification::match(message)) { DSPSignalNotification& notif = (DSPSignalNotification&) message; + m_deviceCenterFrequency = notif.getCenterFrequency(); m_basebandSampleRate = notif.getSampleRate(); + ui->deltaFrequency->setValueRange(false, 7, -m_basebandSampleRate/2, m_basebandSampleRate/2); + ui->deltaFrequencyLabel->setToolTip(tr("Range %1 %L2 Hz").arg(QChar(0xB1)).arg(m_basebandSampleRate/2)); + updateAbsoluteCenterFrequency(); return true; } else if (MainCore::MsgPacket::match(message)) @@ -260,6 +264,7 @@ void PacketDemodGUI::on_deltaFrequency_changed(qint64 value) { m_channelMarker.setCenterFrequency(value); m_settings.m_inputFrequencyOffset = m_channelMarker.getCenterFrequency(); + updateAbsoluteCenterFrequency(); applySettings(); } @@ -369,7 +374,18 @@ void PacketDemodGUI::onWidgetRolled(QWidget* widget, bool rollDown) (void) widget; (void) rollDown; - saveState(m_rollupState); + RollupContents *rollupContents = getRollupContents(); + + if (rollupContents->hasExpandableWidgets()) { + setSizePolicy(sizePolicy().horizontalPolicy(), QSizePolicy::Expanding); + } else { + setSizePolicy(sizePolicy().horizontalPolicy(), QSizePolicy::Fixed); + } + + int h = rollupContents->height() + getAdditionalHeight(); + resize(width(), h); + + rollupContents->saveState(m_rollupState); applySettings(); } @@ -383,6 +399,14 @@ void PacketDemodGUI::onMenuDialogCalled(const QPoint &p) dialog.setReverseAPIPort(m_settings.m_reverseAPIPort); dialog.setReverseAPIDeviceIndex(m_settings.m_reverseAPIDeviceIndex); dialog.setReverseAPIChannelIndex(m_settings.m_reverseAPIChannelIndex); + dialog.setDefaultTitle(m_displayedName); + + if (m_deviceUISet->m_deviceMIMOEngine) + { + dialog.setNumberOfStreams(m_packetDemod->getNumberOfDeviceStreams()); + dialog.setStreamIndex(m_settings.m_streamIndex); + } + dialog.move(p); dialog.exec(); @@ -395,22 +419,17 @@ void PacketDemodGUI::onMenuDialogCalled(const QPoint &p) m_settings.m_reverseAPIChannelIndex = dialog.getReverseAPIChannelIndex(); setWindowTitle(m_settings.m_title); + setTitle(m_channelMarker.getTitle()); setTitleColor(m_settings.m_rgbColor); - applySettings(); - } - else if ((m_contextMenuType == ContextMenuStreamSettings) && (m_deviceUISet->m_deviceMIMOEngine)) - { - DeviceStreamSelectionDialog dialog(this); - dialog.setNumberOfStreams(m_packetDemod->getNumberOfDeviceStreams()); - dialog.setStreamIndex(m_settings.m_streamIndex); - dialog.move(p); - dialog.exec(); + if (m_deviceUISet->m_deviceMIMOEngine) + { + m_settings.m_streamIndex = dialog.getSelectedStreamIndex(); + m_channelMarker.clearStreamIndexes(); + m_channelMarker.addStreamIndex(m_settings.m_streamIndex); + updateIndexLabel(); + } - m_settings.m_streamIndex = dialog.getSelectedStreamIndex(); - m_channelMarker.clearStreamIndexes(); - m_channelMarker.addStreamIndex(m_settings.m_streamIndex); - displayStreamIndex(); applySettings(); } @@ -423,14 +442,17 @@ PacketDemodGUI::PacketDemodGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, B m_pluginAPI(pluginAPI), m_deviceUISet(deviceUISet), m_channelMarker(this), + m_deviceCenterFrequency(0), m_doApplySettings(true), m_tickCount(0) { - ui->setupUi(this); - m_helpURL = "plugins/channelrx/demodpacket/readme.md"; - setAttribute(Qt::WA_DeleteOnClose, true); - connect(this, SIGNAL(widgetRolled(QWidget*,bool)), this, SLOT(onWidgetRolled(QWidget*,bool))); + m_helpURL = "plugins/channelrx/demodpacket/readme.md"; + RollupContents *rollupContents = getRollupContents(); + ui->setupUi(rollupContents); + setSizePolicy(rollupContents->sizePolicy()); + rollupContents->arrangeRollups(); + connect(rollupContents, SIGNAL(widgetRolled(QWidget*,bool)), this, SLOT(onWidgetRolled(QWidget*,bool))); connect(this, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(onMenuDialogCalled(const QPoint &))); m_packetDemod = reinterpret_cast(rxChannel); @@ -456,7 +478,6 @@ PacketDemodGUI::PacketDemodGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, B m_settings.setRollupState(&m_rollupState); m_deviceUISet->addChannelMarker(&m_channelMarker); - m_deviceUISet->addRollupWidget(this); connect(&m_channelMarker, SIGNAL(changedByCursor()), this, SLOT(channelMarkerChangedByCursor())); connect(&m_channelMarker, SIGNAL(highlightedByCursor()), this, SLOT(channelMarkerHighlightedByCursor())); @@ -482,6 +503,7 @@ PacketDemodGUI::PacketDemodGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, B connect(ui->packets->horizontalHeader(), SIGNAL(sectionResized(int, int, int)), SLOT(packets_sectionResized(int, int, int))); displaySettings(); + makeUIConnections(); applySettings(true); } @@ -515,6 +537,7 @@ void PacketDemodGUI::displaySettings() setTitleColor(m_settings.m_rgbColor); setWindowTitle(m_channelMarker.getTitle()); + setTitle(m_channelMarker.getTitle()); blockApplySettings(true); @@ -526,7 +549,7 @@ void PacketDemodGUI::displaySettings() ui->fmDevText->setText(QString("%1k").arg(m_settings.m_fmDeviation / 1000.0, 0, 'f', 1)); ui->fmDev->setValue(m_settings.m_fmDeviation / 100.0); - displayStreamIndex(); + updateIndexLabel(); ui->filterFrom->setText(m_settings.m_filterFrom); ui->filterTo->setText(m_settings.m_filterTo); @@ -553,27 +576,21 @@ void PacketDemodGUI::displaySettings() filter(); - restoreState(m_rollupState); + getRollupContents()->restoreState(m_rollupState); + updateAbsoluteCenterFrequency(); blockApplySettings(false); } -void PacketDemodGUI::displayStreamIndex() -{ - if (m_deviceUISet->m_deviceMIMOEngine) { - setStreamIndicator(tr("%1").arg(m_settings.m_streamIndex)); - } else { - setStreamIndicator("S"); // single channel indicator - } -} - -void PacketDemodGUI::leaveEvent(QEvent*) +void PacketDemodGUI::leaveEvent(QEvent* event) { m_channelMarker.setHighlighted(false); + ChannelGUI::leaveEvent(event); } -void PacketDemodGUI::enterEvent(QEvent*) +void PacketDemodGUI::enterEvent(QEvent* event) { m_channelMarker.setHighlighted(true); + ChannelGUI::enterEvent(event); } void PacketDemodGUI::tick() @@ -682,3 +699,26 @@ void PacketDemodGUI::on_logOpen_clicked() } } } + +void PacketDemodGUI::makeUIConnections() +{ + QObject::connect(ui->deltaFrequency, &ValueDialZ::changed, this, &PacketDemodGUI::on_deltaFrequency_changed); + QObject::connect(ui->mode, QOverload::of(&QComboBox::currentIndexChanged), this, &PacketDemodGUI::on_mode_currentIndexChanged); + QObject::connect(ui->rfBW, &QSlider::valueChanged, this, &PacketDemodGUI::on_rfBW_valueChanged); + QObject::connect(ui->fmDev, &QSlider::valueChanged, this, &PacketDemodGUI::on_fmDev_valueChanged); + QObject::connect(ui->filterFrom, &QLineEdit::editingFinished, this, &PacketDemodGUI::on_filterFrom_editingFinished); + QObject::connect(ui->filterTo, &QLineEdit::editingFinished, this, &PacketDemodGUI::on_filterTo_editingFinished); + QObject::connect(ui->filterPID, &QCheckBox::stateChanged, this, &PacketDemodGUI::on_filterPID_stateChanged); + QObject::connect(ui->clearTable, &QPushButton::clicked, this, &PacketDemodGUI::on_clearTable_clicked); + QObject::connect(ui->udpEnabled, &QCheckBox::clicked, this, &PacketDemodGUI::on_udpEnabled_clicked); + QObject::connect(ui->udpAddress, &QLineEdit::editingFinished, this, &PacketDemodGUI::on_udpAddress_editingFinished); + QObject::connect(ui->udpPort, &QLineEdit::editingFinished, this, &PacketDemodGUI::on_udpPort_editingFinished); + QObject::connect(ui->logEnable, &ButtonSwitch::clicked, this, &PacketDemodGUI::on_logEnable_clicked); + QObject::connect(ui->logFilename, &QToolButton::clicked, this, &PacketDemodGUI::on_logFilename_clicked); + QObject::connect(ui->logOpen, &QToolButton::clicked, this, &PacketDemodGUI::on_logOpen_clicked); +} + +void PacketDemodGUI::updateAbsoluteCenterFrequency() +{ + setStatusFrequency(m_deviceCenterFrequency + m_settings.m_inputFrequencyOffset); +} diff --git a/plugins/channelrx/demodpacket/packetdemodgui.h b/plugins/channelrx/demodpacket/packetdemodgui.h index 0e4bf46ca..613692a8b 100644 --- a/plugins/channelrx/demodpacket/packetdemodgui.h +++ b/plugins/channelrx/demodpacket/packetdemodgui.h @@ -58,6 +58,17 @@ public: QByteArray serialize() const; bool deserialize(const QByteArray& data); virtual MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; } + virtual void setWorkspaceIndex(int index) { m_settings.m_workspaceIndex = index; }; + virtual int getWorkspaceIndex() const { return m_settings.m_workspaceIndex; }; + virtual void setGeometryBytes(const QByteArray& blob) { m_settings.m_geometryBytes = blob; }; + virtual QByteArray getGeometryBytes() const { return m_settings.m_geometryBytes; }; + virtual QString getTitle() const { return m_settings.m_title; }; + virtual QColor getTitleColor() const { return m_settings.m_rgbColor; }; + virtual void zetHidden(bool hidden) { m_settings.m_hidden = hidden; } + virtual bool getHidden() const { return m_settings.m_hidden; } + virtual ChannelMarker& getChannelMarker() { return m_channelMarker; } + virtual int getStreamIndex() const { return m_settings.m_streamIndex; } + virtual void setStreamIndex(int streamIndex) { m_settings.m_streamIndex = streamIndex; } public slots: void channelMarkerChangedByCursor(); @@ -70,6 +81,7 @@ private: ChannelMarker m_channelMarker; RollupState m_rollupState; PacketDemodSettings m_settings; + qint64 m_deviceCenterFrequency; bool m_doApplySettings; PacketDemod* m_packetDemod; @@ -85,9 +97,10 @@ private: void blockApplySettings(bool block); void applySettings(bool force = false); void displaySettings(); - void displayStreamIndex(); void packetReceived(QByteArray packet); bool handleMessage(const Message& message); + void makeUIConnections(); + void updateAbsoluteCenterFrequency(); void leaveEvent(QEvent*); void enterEvent(QEvent*); diff --git a/plugins/channelrx/demodpacket/packetdemodgui.ui b/plugins/channelrx/demodpacket/packetdemodgui.ui index e38e0856f..2fbce3533 100644 --- a/plugins/channelrx/demodpacket/packetdemodgui.ui +++ b/plugins/channelrx/demodpacket/packetdemodgui.ui @@ -1,7 +1,7 @@ PacketDemodGUI - + 0 @@ -713,9 +713,9 @@ - RollupWidget + RollupContents QWidget -
gui/rollupwidget.h
+
gui/rollupcontents.h
1
diff --git a/plugins/channelrx/demodpacket/packetdemodsettings.cpp b/plugins/channelrx/demodpacket/packetdemodsettings.cpp index a44381513..93abb748e 100644 --- a/plugins/channelrx/demodpacket/packetdemodsettings.cpp +++ b/plugins/channelrx/demodpacket/packetdemodsettings.cpp @@ -53,6 +53,8 @@ void PacketDemodSettings::resetToDefaults() m_reverseAPIPort = 8888; m_reverseAPIDeviceIndex = 0; m_reverseAPIChannelIndex = 0; + m_workspaceIndex = 0; + m_hidden = false; for (int i = 0; i < PACKETDEMOD_COLUMNS; i++) { @@ -95,6 +97,10 @@ QByteArray PacketDemodSettings::serialize() const s.writeBlob(27, m_rollupState->serialize()); } + s.writeS32(28, m_workspaceIndex); + s.writeBlob(29, m_geometryBytes); + s.writeBool(30, m_hidden); + for (int i = 0; i < PACKETDEMOD_COLUMNS; i++) { s.writeS32(100 + i, m_columnIndexes[i]); } @@ -173,6 +179,10 @@ bool PacketDemodSettings::deserialize(const QByteArray& data) m_rollupState->deserialize(bytetmp); } + d.readS32(28, &m_workspaceIndex, 0); + d.readBlob(29, &m_geometryBytes); + d.readBool(30, &m_hidden, false); + for (int i = 0; i < PACKETDEMOD_COLUMNS; i++) { d.readS32(100 + i, &m_columnIndexes[i], i); } diff --git a/plugins/channelrx/demodpacket/packetdemodsettings.h b/plugins/channelrx/demodpacket/packetdemodsettings.h index 76e6efa87..07bd5f2ca 100644 --- a/plugins/channelrx/demodpacket/packetdemodsettings.h +++ b/plugins/channelrx/demodpacket/packetdemodsettings.h @@ -57,6 +57,9 @@ struct PacketDemodSettings QString m_logFilename; bool m_logEnabled; Serializable *m_rollupState; + int m_workspaceIndex; + QByteArray m_geometryBytes; + bool m_hidden; int m_columnIndexes[PACKETDEMOD_COLUMNS];//!< How the columns are ordered in the table int m_columnSizes[PACKETDEMOD_COLUMNS]; //!< Size of the columns in the table diff --git a/plugins/channelrx/demodpacket/readme.md b/plugins/channelrx/demodpacket/readme.md index 0d71dbdd6..2c00e91f1 100644 --- a/plugins/channelrx/demodpacket/readme.md +++ b/plugins/channelrx/demodpacket/readme.md @@ -6,6 +6,8 @@ This plugin can be used to demodulate packet radio (APRS/AX.25) data packets. Re

Interface

+The top and bottom bars of the channel window are described [here](../../../sdrgui/channel/readme.md) + ![Packet Demodulator plugin GUI](../../../doc/img/PacketDemod_plugin.png)

1: Frequency shift from center frequency of reception

diff --git a/plugins/channelrx/demodpager/pagerdemod.cpp b/plugins/channelrx/demodpager/pagerdemod.cpp index 773acc50d..3e0f5a3de 100644 --- a/plugins/channelrx/demodpager/pagerdemod.cpp +++ b/plugins/channelrx/demodpager/pagerdemod.cpp @@ -25,6 +25,7 @@ #include #include "SWGChannelSettings.h" +#include "SWGWorkspaceInfo.h" #include "SWGChannelReport.h" #include "dsp/dspengine.h" @@ -92,6 +93,18 @@ PagerDemod::~PagerDemod() delete m_basebandSink; } +void PagerDemod::setDeviceAPI(DeviceAPI *deviceAPI) +{ + if (deviceAPI != m_deviceAPI) + { + m_deviceAPI->removeChannelSinkAPI(this); + m_deviceAPI->removeChannelSink(this); + m_deviceAPI = deviceAPI; + m_deviceAPI->addChannelSink(this); + m_deviceAPI->addChannelSinkAPI(this); + } +} + uint32_t PagerDemod::getNumberOfDeviceStreams() const { return m_deviceAPI->getNbSourceStreams(); @@ -145,6 +158,10 @@ bool PagerDemod::handleMessage(const Message& cmd) DSPSignalNotification* rep = new DSPSignalNotification(notif); // make a copy qDebug() << "PagerDemod::handleMessage: DSPSignalNotification"; m_basebandSink->getInputMessageQueue()->push(rep); + // Forward to GUI if any + if (getMessageQueueToGUI()) { + getMessageQueueToGUI()->push(new DSPSignalNotification(notif)); + } return true; } @@ -376,6 +393,15 @@ int PagerDemod::webapiSettingsGet( return 200; } +int PagerDemod::webapiWorkspaceGet( + SWGSDRangel::SWGWorkspaceInfo& response, + QString& errorMessage) +{ + (void) errorMessage; + response.setIndex(m_settings.m_workspaceIndex); + return 200; +} + int PagerDemod::webapiSettingsPutPatch( bool force, const QStringList& channelSettingsKeys, diff --git a/plugins/channelrx/demodpager/pagerdemod.h b/plugins/channelrx/demodpager/pagerdemod.h index 3561bf0a4..cc8e1e368 100644 --- a/plugins/channelrx/demodpager/pagerdemod.h +++ b/plugins/channelrx/demodpager/pagerdemod.h @@ -122,6 +122,8 @@ public: PagerDemod(DeviceAPI *deviceAPI); virtual ~PagerDemod(); virtual void destroy() { delete this; } + virtual void setDeviceAPI(DeviceAPI *deviceAPI); + virtual DeviceAPI *getDeviceAPI() { return m_deviceAPI; } using BasebandSampleSink::feed; virtual void feed(const SampleVector::const_iterator& begin, const SampleVector::const_iterator& end, bool po); @@ -154,6 +156,10 @@ public: SWGSDRangel::SWGChannelSettings& response, QString& errorMessage); + virtual int webapiWorkspaceGet( + SWGSDRangel::SWGWorkspaceInfo& response, + QString& errorMessage); + virtual int webapiSettingsPutPatch( bool force, const QStringList& channelSettingsKeys, diff --git a/plugins/channelrx/demodpager/pagerdemodgui.cpp b/plugins/channelrx/demodpager/pagerdemodgui.cpp index a71ff7c93..4e63805ac 100644 --- a/plugins/channelrx/demodpager/pagerdemodgui.cpp +++ b/plugins/channelrx/demodpager/pagerdemodgui.cpp @@ -277,6 +277,16 @@ bool PagerDemodGUI::handleMessage(const Message& message) report.getEvenParityErrors(), report.getBCHParityErrors()); return true; } + else if (DSPSignalNotification::match(message)) + { + DSPSignalNotification& notif = (DSPSignalNotification&) message; + m_deviceCenterFrequency = notif.getCenterFrequency(); + m_basebandSampleRate = notif.getSampleRate(); + ui->deltaFrequency->setValueRange(false, 7, -m_basebandSampleRate/2, m_basebandSampleRate/2); + ui->deltaFrequencyLabel->setToolTip(tr("Range %1 %L2 Hz").arg(QChar(0xB1)).arg(m_basebandSampleRate/2)); + updateAbsoluteCenterFrequency(); + return true; + } return false; } @@ -310,6 +320,7 @@ void PagerDemodGUI::on_deltaFrequency_changed(qint64 value) { m_channelMarker.setCenterFrequency(value); m_settings.m_inputFrequencyOffset = m_channelMarker.getCenterFrequency(); + updateAbsoluteCenterFrequency(); applySettings(); } @@ -420,7 +431,18 @@ void PagerDemodGUI::onWidgetRolled(QWidget* widget, bool rollDown) } } - saveState(m_rollupState); + RollupContents *rollupContents = getRollupContents(); + + if (rollupContents->hasExpandableWidgets()) { + setSizePolicy(sizePolicy().horizontalPolicy(), QSizePolicy::Expanding); + } else { + setSizePolicy(sizePolicy().horizontalPolicy(), QSizePolicy::Fixed); + } + + int h = rollupContents->height() + getAdditionalHeight(); + resize(width(), h); + + rollupContents->saveState(m_rollupState); applySettings(); } @@ -434,6 +456,14 @@ void PagerDemodGUI::onMenuDialogCalled(const QPoint &p) dialog.setReverseAPIPort(m_settings.m_reverseAPIPort); dialog.setReverseAPIDeviceIndex(m_settings.m_reverseAPIDeviceIndex); dialog.setReverseAPIChannelIndex(m_settings.m_reverseAPIChannelIndex); + dialog.setDefaultTitle(m_displayedName); + + if (m_deviceUISet->m_deviceMIMOEngine) + { + dialog.setNumberOfStreams(m_pagerDemod->getNumberOfDeviceStreams()); + dialog.setStreamIndex(m_settings.m_streamIndex); + } + dialog.move(p); dialog.exec(); @@ -446,22 +476,17 @@ void PagerDemodGUI::onMenuDialogCalled(const QPoint &p) m_settings.m_reverseAPIChannelIndex = dialog.getReverseAPIChannelIndex(); setWindowTitle(m_settings.m_title); + setTitle(m_channelMarker.getTitle()); setTitleColor(m_settings.m_rgbColor); - applySettings(); - } - else if ((m_contextMenuType == ContextMenuStreamSettings) && (m_deviceUISet->m_deviceMIMOEngine)) - { - DeviceStreamSelectionDialog dialog(this); - dialog.setNumberOfStreams(m_pagerDemod->getNumberOfDeviceStreams()); - dialog.setStreamIndex(m_settings.m_streamIndex); - dialog.move(p); - dialog.exec(); + if (m_deviceUISet->m_deviceMIMOEngine) + { + m_settings.m_streamIndex = dialog.getSelectedStreamIndex(); + m_channelMarker.clearStreamIndexes(); + m_channelMarker.addStreamIndex(m_settings.m_streamIndex); + updateIndexLabel(); + } - m_settings.m_streamIndex = dialog.getSelectedStreamIndex(); - m_channelMarker.clearStreamIndexes(); - m_channelMarker.addStreamIndex(m_settings.m_streamIndex); - displayStreamIndex(); applySettings(); } @@ -474,14 +499,18 @@ PagerDemodGUI::PagerDemodGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, Bas m_pluginAPI(pluginAPI), m_deviceUISet(deviceUISet), m_channelMarker(this), + m_deviceCenterFrequency(0), + m_basebandSampleRate(1), m_doApplySettings(true), m_tickCount(0) { - ui->setupUi(this); - m_helpURL = "plugins/channelrx/demodpager/readme.md"; - setAttribute(Qt::WA_DeleteOnClose, true); - connect(this, SIGNAL(widgetRolled(QWidget*,bool)), this, SLOT(onWidgetRolled(QWidget*,bool))); + m_helpURL = "plugins/channelrx/demodpager/readme.md"; + RollupContents *rollupContents = getRollupContents(); + ui->setupUi(rollupContents); + setSizePolicy(rollupContents->sizePolicy()); + rollupContents->arrangeRollups(); + connect(rollupContents, SIGNAL(widgetRolled(QWidget*,bool)), this, SLOT(onWidgetRolled(QWidget*,bool))); connect(this, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(onMenuDialogCalled(const QPoint &))); m_pagerDemod = reinterpret_cast(rxChannel); @@ -515,7 +544,6 @@ PagerDemodGUI::PagerDemodGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, Bas m_settings.setRollupState(&m_rollupState); m_deviceUISet->addChannelMarker(&m_channelMarker); - m_deviceUISet->addRollupWidget(this); connect(&m_channelMarker, SIGNAL(changedByCursor()), this, SLOT(channelMarkerChangedByCursor())); connect(&m_channelMarker, SIGNAL(highlightedByCursor()), this, SLOT(channelMarkerHighlightedByCursor())); @@ -545,6 +573,7 @@ PagerDemodGUI::PagerDemodGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, Bas ui->scopeContainer->setVisible(false); displaySettings(); + makeUIConnections(); applySettings(true); } @@ -596,6 +625,7 @@ void PagerDemodGUI::displaySettings() setTitleColor(m_settings.m_rgbColor); setWindowTitle(m_channelMarker.getTitle()); + setTitle(m_channelMarker.getTitle()); blockApplySettings(true); @@ -616,7 +646,7 @@ void PagerDemodGUI::displaySettings() ui->fmDevText->setText(QString("%1k").arg(m_settings.m_fmDeviation / 1000.0, 0, 'f', 1)); ui->fmDev->setValue(m_settings.m_fmDeviation / 100.0); - displayStreamIndex(); + updateIndexLabel(); ui->filterAddress->setText(m_settings.m_filterAddress); @@ -645,27 +675,21 @@ void PagerDemodGUI::displaySettings() filter(); - restoreState(m_rollupState); + getRollupContents()->restoreState(m_rollupState); + updateAbsoluteCenterFrequency(); blockApplySettings(false); } -void PagerDemodGUI::displayStreamIndex() -{ - if (m_deviceUISet->m_deviceMIMOEngine) { - setStreamIndicator(tr("%1").arg(m_settings.m_streamIndex)); - } else { - setStreamIndicator("S"); // single channel indicator - } -} - -void PagerDemodGUI::leaveEvent(QEvent*) +void PagerDemodGUI::leaveEvent(QEvent* event) { m_channelMarker.setHighlighted(false); + ChannelGUI::leaveEvent(event); } -void PagerDemodGUI::enterEvent(QEvent*) +void PagerDemodGUI::enterEvent(QEvent* event) { m_channelMarker.setHighlighted(true); + ChannelGUI::enterEvent(event); } void PagerDemodGUI::tick() @@ -797,3 +821,26 @@ void PagerDemodGUI::on_logOpen_clicked() } } } + +void PagerDemodGUI::makeUIConnections() +{ + QObject::connect(ui->deltaFrequency, &ValueDialZ::changed, this, &PagerDemodGUI::on_deltaFrequency_changed); + QObject::connect(ui->rfBW, &QSlider::valueChanged, this, &PagerDemodGUI::on_rfBW_valueChanged); + QObject::connect(ui->fmDev, &QSlider::valueChanged, this, &PagerDemodGUI::on_fmDev_valueChanged); + QObject::connect(ui->baud, QOverload::of(&QComboBox::currentIndexChanged), this, &PagerDemodGUI::on_baud_currentIndexChanged); + QObject::connect(ui->decode, QOverload::of(&QComboBox::currentIndexChanged), this, &PagerDemodGUI::on_decode_currentIndexChanged); + QObject::connect(ui->charset, &QToolButton::clicked, this, &PagerDemodGUI::on_charset_clicked); + QObject::connect(ui->filterAddress, &QLineEdit::editingFinished, this, &PagerDemodGUI::on_filterAddress_editingFinished); + QObject::connect(ui->clearTable, &QToolButton::clicked, this, &PagerDemodGUI::on_clearTable_clicked); + QObject::connect(ui->udpEnabled, &QCheckBox::clicked, this, &PagerDemodGUI::on_udpEnabled_clicked); + QObject::connect(ui->udpAddress, &QLineEdit::editingFinished, this, &PagerDemodGUI::on_udpAddress_editingFinished); + QObject::connect(ui->udpPort, &QLineEdit::editingFinished, this, &PagerDemodGUI::on_udpPort_editingFinished); + QObject::connect(ui->logEnable, &ButtonSwitch::clicked, this, &PagerDemodGUI::on_logEnable_clicked); + QObject::connect(ui->logFilename, &QToolButton::clicked, this, &PagerDemodGUI::on_logFilename_clicked); + QObject::connect(ui->logOpen, &QToolButton::clicked, this, &PagerDemodGUI::on_logOpen_clicked); +} + +void PagerDemodGUI::updateAbsoluteCenterFrequency() +{ + setStatusFrequency(m_deviceCenterFrequency + m_settings.m_inputFrequencyOffset); +} diff --git a/plugins/channelrx/demodpager/pagerdemodgui.h b/plugins/channelrx/demodpager/pagerdemodgui.h index 1ad9ed1d3..f42f136be 100644 --- a/plugins/channelrx/demodpager/pagerdemodgui.h +++ b/plugins/channelrx/demodpager/pagerdemodgui.h @@ -52,6 +52,17 @@ public: QByteArray serialize() const; bool deserialize(const QByteArray& data); virtual MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; } + virtual void setWorkspaceIndex(int index) { m_settings.m_workspaceIndex = index; }; + virtual int getWorkspaceIndex() const { return m_settings.m_workspaceIndex; }; + virtual void setGeometryBytes(const QByteArray& blob) { m_settings.m_geometryBytes = blob; }; + virtual QByteArray getGeometryBytes() const { return m_settings.m_geometryBytes; }; + virtual QString getTitle() const { return m_settings.m_title; }; + virtual QColor getTitleColor() const { return m_settings.m_rgbColor; }; + virtual void zetHidden(bool hidden) { m_settings.m_hidden = hidden; } + virtual bool getHidden() const { return m_settings.m_hidden; } + virtual ChannelMarker& getChannelMarker() { return m_channelMarker; } + virtual int getStreamIndex() const { return m_settings.m_streamIndex; } + virtual void setStreamIndex(int streamIndex) { m_settings.m_streamIndex = streamIndex; } public slots: void channelMarkerChangedByCursor(); @@ -64,6 +75,8 @@ private: ChannelMarker m_channelMarker; RollupState m_rollupState; PagerDemodSettings m_settings; + qint64 m_deviceCenterFrequency; + int m_basebandSampleRate; bool m_doApplySettings; ScopeVis* m_scopeVis; @@ -79,11 +92,12 @@ private: void blockApplySettings(bool block); void applySettings(bool force = false); void displaySettings(); - void displayStreamIndex(); void messageReceived(const QDateTime dateTime, int address, int functionBits, const QString &numericMessage, const QString &alphaMessage, int evenParityErrors, int bchParityErrors); bool handleMessage(const Message& message); + void makeUIConnections(); + void updateAbsoluteCenterFrequency(); void leaveEvent(QEvent*); void enterEvent(QEvent*); diff --git a/plugins/channelrx/demodpager/pagerdemodgui.ui b/plugins/channelrx/demodpager/pagerdemodgui.ui index d5c370095..be681d34a 100644 --- a/plugins/channelrx/demodpager/pagerdemodgui.ui +++ b/plugins/channelrx/demodpager/pagerdemodgui.ui @@ -1,7 +1,7 @@ PagerDemodGUI - + 0 @@ -1013,9 +1013,9 @@ - RollupWidget + RollupContents QWidget -
gui/rollupwidget.h
+
gui/rollupcontents.h
1
diff --git a/plugins/channelrx/demodpager/pagerdemodsettings.cpp b/plugins/channelrx/demodpager/pagerdemodsettings.cpp index 6556548f8..76e6a5743 100644 --- a/plugins/channelrx/demodpager/pagerdemodsettings.cpp +++ b/plugins/channelrx/demodpager/pagerdemodsettings.cpp @@ -56,6 +56,8 @@ void PagerDemodSettings::resetToDefaults() m_reverseAPIDeviceIndex = 0; m_reverseAPIChannelIndex = 0; m_reverse = false; + m_workspaceIndex = 0; + m_hidden = false; for (int i = 0; i < PAGERDEMOD_MESSAGE_COLUMNS; i++) { @@ -103,6 +105,10 @@ QByteArray PagerDemodSettings::serialize() const s.writeBlob(27, m_rollupState->serialize()); } + s.writeS32(28, m_workspaceIndex); + s.writeBlob(29, m_geometryBytes); + s.writeBool(30, m_hidden); + for (int i = 0; i < PAGERDEMOD_MESSAGE_COLUMNS; i++) { s.writeS32(100 + i, m_messageColumnIndexes[i]); } @@ -194,6 +200,10 @@ bool PagerDemodSettings::deserialize(const QByteArray& data) m_rollupState->deserialize(bytetmp); } + d.readS32(28, &m_workspaceIndex, 0); + d.readBlob(29, &m_geometryBytes); + d.readBool(30, &m_hidden, false); + for (int i = 0; i < PAGERDEMOD_MESSAGE_COLUMNS; i++) { d.readS32(100 + i, &m_messageColumnIndexes[i], i); } diff --git a/plugins/channelrx/demodpager/pagerdemodsettings.h b/plugins/channelrx/demodpager/pagerdemodsettings.h index 819f0092f..430162214 100644 --- a/plugins/channelrx/demodpager/pagerdemodsettings.h +++ b/plugins/channelrx/demodpager/pagerdemodsettings.h @@ -67,6 +67,9 @@ struct PagerDemodSettings QString m_logFilename; bool m_logEnabled; Serializable *m_rollupState; + int m_workspaceIndex; + QByteArray m_geometryBytes; + bool m_hidden; int m_messageColumnIndexes[PAGERDEMOD_MESSAGE_COLUMNS];//!< How the columns are ordered in the table int m_messageColumnSizes[PAGERDEMOD_MESSAGE_COLUMNS]; //!< Size of the columns in the table diff --git a/plugins/channelrx/demodpager/readme.md b/plugins/channelrx/demodpager/readme.md index 2292113d3..e4409fe51 100644 --- a/plugins/channelrx/demodpager/readme.md +++ b/plugins/channelrx/demodpager/readme.md @@ -6,6 +6,8 @@ This plugin can be used to demodulate POCSAG pager messages.

Interface

+The top and bottom bars of the channel window are described [here](../../../sdrgui/channel/readme.md) + ![Pager Demodulator plugin GUI](../../../doc/img/PagerDemod_plugin.png)

1: Frequency shift from center frequency of reception

diff --git a/plugins/channelrx/demodradiosonde/radiosondedemod.cpp b/plugins/channelrx/demodradiosonde/radiosondedemod.cpp index e559c95a4..b9e1f9e8f 100644 --- a/plugins/channelrx/demodradiosonde/radiosondedemod.cpp +++ b/plugins/channelrx/demodradiosonde/radiosondedemod.cpp @@ -29,6 +29,7 @@ #include #include "SWGChannelSettings.h" +#include "SWGWorkspaceInfo.h" #include "SWGChannelReport.h" #include "dsp/dspengine.h" @@ -96,6 +97,18 @@ RadiosondeDemod::~RadiosondeDemod() delete m_basebandSink; } +void RadiosondeDemod::setDeviceAPI(DeviceAPI *deviceAPI) +{ + if (deviceAPI != m_deviceAPI) + { + m_deviceAPI->removeChannelSinkAPI(this); + m_deviceAPI->removeChannelSink(this); + m_deviceAPI = deviceAPI; + m_deviceAPI->addChannelSink(this); + m_deviceAPI->addChannelSinkAPI(this); + } +} + uint32_t RadiosondeDemod::getNumberOfDeviceStreams() const { return m_deviceAPI->getNbSourceStreams(); @@ -149,6 +162,10 @@ bool RadiosondeDemod::handleMessage(const Message& cmd) DSPSignalNotification* rep = new DSPSignalNotification(notif); // make a copy qDebug() << "RadiosondeDemod::handleMessage: DSPSignalNotification"; m_basebandSink->getInputMessageQueue()->push(rep); + // Forward to GUI if any + if (getMessageQueueToGUI()) { + getMessageQueueToGUI()->push(new DSPSignalNotification(notif)); + } return true; } @@ -423,6 +440,15 @@ int RadiosondeDemod::webapiSettingsGet( return 200; } +int RadiosondeDemod::webapiWorkspaceGet( + SWGSDRangel::SWGWorkspaceInfo& response, + QString& errorMessage) +{ + (void) errorMessage; + response.setIndex(m_settings.m_workspaceIndex); + return 200; +} + int RadiosondeDemod::webapiSettingsPutPatch( bool force, const QStringList& channelSettingsKeys, diff --git a/plugins/channelrx/demodradiosonde/radiosondedemod.h b/plugins/channelrx/demodradiosonde/radiosondedemod.h index 5703eac62..bf4e91ae6 100644 --- a/plugins/channelrx/demodradiosonde/radiosondedemod.h +++ b/plugins/channelrx/demodradiosonde/radiosondedemod.h @@ -102,6 +102,8 @@ public: RadiosondeDemod(DeviceAPI *deviceAPI); virtual ~RadiosondeDemod(); virtual void destroy() { delete this; } + virtual void setDeviceAPI(DeviceAPI *deviceAPI); + virtual DeviceAPI *getDeviceAPI() { return m_deviceAPI; } using BasebandSampleSink::feed; virtual void feed(const SampleVector::const_iterator& begin, const SampleVector::const_iterator& end, bool po); @@ -134,6 +136,10 @@ public: SWGSDRangel::SWGChannelSettings& response, QString& errorMessage); + virtual int webapiWorkspaceGet( + SWGSDRangel::SWGWorkspaceInfo& response, + QString& errorMessage); + virtual int webapiSettingsPutPatch( bool force, const QStringList& channelSettingsKeys, diff --git a/plugins/channelrx/demodradiosonde/radiosondedemodgui.cpp b/plugins/channelrx/demodradiosonde/radiosondedemodgui.cpp index 4481ad3ed..ec051fbcc 100644 --- a/plugins/channelrx/demodradiosonde/radiosondedemodgui.cpp +++ b/plugins/channelrx/demodradiosonde/radiosondedemodgui.cpp @@ -324,6 +324,16 @@ bool RadiosondeDemodGUI::handleMessage(const Message& frame) frameReceived(report.getMessage(), report.getDateTime(), report.getErrorsCorrected(), report.getThreshold()); return true; } + else if (DSPSignalNotification::match(frame)) + { + const DSPSignalNotification& notif = (const DSPSignalNotification&) frame; + m_deviceCenterFrequency = notif.getCenterFrequency(); + m_basebandSampleRate = notif.getSampleRate(); + ui->deltaFrequency->setValueRange(false, 7, -m_basebandSampleRate/2, m_basebandSampleRate/2); + ui->deltaFrequencyLabel->setToolTip(tr("Range %1 %L2 Hz").arg(QChar(0xB1)).arg(m_basebandSampleRate/2)); + updateAbsoluteCenterFrequency(); + return true; + } return false; } @@ -357,6 +367,7 @@ void RadiosondeDemodGUI::on_deltaFrequency_changed(qint64 value) { m_channelMarker.setCenterFrequency(value); m_settings.m_inputFrequencyOffset = m_channelMarker.getCenterFrequency(); + updateAbsoluteCenterFrequency(); applySettings(); } @@ -477,7 +488,18 @@ void RadiosondeDemodGUI::onWidgetRolled(QWidget* widget, bool rollDown) } } - saveState(m_rollupState); + RollupContents *rollupContents = getRollupContents(); + + if (rollupContents->hasExpandableWidgets()) { + setSizePolicy(sizePolicy().horizontalPolicy(), QSizePolicy::Expanding); + } else { + setSizePolicy(sizePolicy().horizontalPolicy(), QSizePolicy::Fixed); + } + + int h = rollupContents->height() + getAdditionalHeight(); + resize(width(), h); + + rollupContents->saveState(m_rollupState); applySettings(); } @@ -491,6 +513,14 @@ void RadiosondeDemodGUI::onMenuDialogCalled(const QPoint &p) dialog.setReverseAPIPort(m_settings.m_reverseAPIPort); dialog.setReverseAPIDeviceIndex(m_settings.m_reverseAPIDeviceIndex); dialog.setReverseAPIChannelIndex(m_settings.m_reverseAPIChannelIndex); + dialog.setDefaultTitle(m_displayedName); + + if (m_deviceUISet->m_deviceMIMOEngine) + { + dialog.setNumberOfStreams(m_radiosondeDemod->getNumberOfDeviceStreams()); + dialog.setStreamIndex(m_settings.m_streamIndex); + } + dialog.move(p); dialog.exec(); @@ -503,22 +533,17 @@ void RadiosondeDemodGUI::onMenuDialogCalled(const QPoint &p) m_settings.m_reverseAPIChannelIndex = dialog.getReverseAPIChannelIndex(); setWindowTitle(m_settings.m_title); + setTitle(m_channelMarker.getTitle()); setTitleColor(m_settings.m_rgbColor); - applySettings(); - } - else if ((m_contextMenuType == ContextMenuStreamSettings) && (m_deviceUISet->m_deviceMIMOEngine)) - { - DeviceStreamSelectionDialog dialog(this); - dialog.setNumberOfStreams(m_radiosondeDemod->getNumberOfDeviceStreams()); - dialog.setStreamIndex(m_settings.m_streamIndex); - dialog.move(p); - dialog.exec(); + if (m_deviceUISet->m_deviceMIMOEngine) + { + m_settings.m_streamIndex = dialog.getSelectedStreamIndex(); + m_channelMarker.clearStreamIndexes(); + m_channelMarker.addStreamIndex(m_settings.m_streamIndex); + updateIndexLabel(); + } - m_settings.m_streamIndex = dialog.getSelectedStreamIndex(); - m_channelMarker.clearStreamIndexes(); - m_channelMarker.addStreamIndex(m_settings.m_streamIndex); - displayStreamIndex(); applySettings(); } @@ -531,14 +556,18 @@ RadiosondeDemodGUI::RadiosondeDemodGUI(PluginAPI* pluginAPI, DeviceUISet *device m_pluginAPI(pluginAPI), m_deviceUISet(deviceUISet), m_channelMarker(this), + m_deviceCenterFrequency(0), + m_basebandSampleRate(1), m_doApplySettings(true), m_tickCount(0) { - ui->setupUi(this); - m_helpURL = "plugins/channelrx/demodradiosonde/readme.md"; - setAttribute(Qt::WA_DeleteOnClose, true); - connect(this, SIGNAL(widgetRolled(QWidget*,bool)), this, SLOT(onWidgetRolled(QWidget*,bool))); + m_helpURL = "plugins/channelrx/demodradiosonde/readme.md"; + RollupContents *rollupContents = getRollupContents(); + ui->setupUi(rollupContents); + setSizePolicy(rollupContents->sizePolicy()); + rollupContents->arrangeRollups(); + connect(rollupContents, SIGNAL(widgetRolled(QWidget*,bool)), this, SLOT(onWidgetRolled(QWidget*,bool))); connect(this, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(onMenuDialogCalled(const QPoint &))); m_radiosondeDemod = reinterpret_cast(rxChannel); @@ -594,7 +623,6 @@ RadiosondeDemodGUI::RadiosondeDemodGUI(PluginAPI* pluginAPI, DeviceUISet *device m_settings.setRollupState(&m_rollupState); m_deviceUISet->addChannelMarker(&m_channelMarker); - m_deviceUISet->addRollupWidget(this); connect(&m_channelMarker, SIGNAL(changedByCursor()), this, SLOT(channelMarkerChangedByCursor())); connect(&m_channelMarker, SIGNAL(highlightedByCursor()), this, SLOT(channelMarkerHighlightedByCursor())); @@ -634,6 +662,7 @@ RadiosondeDemodGUI::RadiosondeDemodGUI(PluginAPI* pluginAPI, DeviceUISet *device ui->scopeContainer->setVisible(false); displaySettings(); + makeUIConnections(); applySettings(true); } @@ -707,6 +736,7 @@ void RadiosondeDemodGUI::displaySettings() setTitleColor(m_settings.m_rgbColor); setWindowTitle(m_channelMarker.getTitle()); + setTitle(m_channelMarker.getTitle()); blockApplySettings(true); @@ -721,7 +751,7 @@ void RadiosondeDemodGUI::displaySettings() ui->thresholdText->setText(QString("%1").arg(m_settings.m_correlationThreshold)); ui->threshold->setValue(m_settings.m_correlationThreshold); - displayStreamIndex(); + updateIndexLabel(); ui->filterSerial->setText(m_settings.m_filterSerial); @@ -749,27 +779,21 @@ void RadiosondeDemodGUI::displaySettings() filter(); - restoreState(m_rollupState); + getRollupContents()->restoreState(m_rollupState); + updateAbsoluteCenterFrequency(); blockApplySettings(false); } -void RadiosondeDemodGUI::displayStreamIndex() -{ - if (m_deviceUISet->m_deviceMIMOEngine) { - setStreamIndicator(tr("%1").arg(m_settings.m_streamIndex)); - } else { - setStreamIndicator("S"); // single channel indicator - } -} - -void RadiosondeDemodGUI::leaveEvent(QEvent*) +void RadiosondeDemodGUI::leaveEvent(QEvent* event) { m_channelMarker.setHighlighted(false); + ChannelGUI::leaveEvent(event); } -void RadiosondeDemodGUI::enterEvent(QEvent*) +void RadiosondeDemodGUI::enterEvent(QEvent* event) { m_channelMarker.setHighlighted(true); + ChannelGUI::enterEvent(event); } void RadiosondeDemodGUI::tick() @@ -893,3 +917,25 @@ void RadiosondeDemodGUI::on_logOpen_clicked() } } } + +void RadiosondeDemodGUI::makeUIConnections() +{ + QObject::connect(ui->deltaFrequency, &ValueDialZ::changed, this, &RadiosondeDemodGUI::on_deltaFrequency_changed); + QObject::connect(ui->rfBW, &QSlider::valueChanged, this, &RadiosondeDemodGUI::on_rfBW_valueChanged); + QObject::connect(ui->fmDev, &QSlider::valueChanged, this, &RadiosondeDemodGUI::on_fmDev_valueChanged); + QObject::connect(ui->threshold, &QDial::valueChanged, this, &RadiosondeDemodGUI::on_threshold_valueChanged); + QObject::connect(ui->filterSerial, &QLineEdit::editingFinished, this, &RadiosondeDemodGUI::on_filterSerial_editingFinished); + QObject::connect(ui->clearTable, &QPushButton::clicked, this, &RadiosondeDemodGUI::on_clearTable_clicked); + QObject::connect(ui->udpEnabled, &QCheckBox::clicked, this, &RadiosondeDemodGUI::on_udpEnabled_clicked); + QObject::connect(ui->udpAddress, &QLineEdit::editingFinished, this, &RadiosondeDemodGUI::on_udpAddress_editingFinished); + QObject::connect(ui->udpPort, &QLineEdit::editingFinished, this, &RadiosondeDemodGUI::on_udpPort_editingFinished); + QObject::connect(ui->frames, &QTableWidget::cellDoubleClicked, this, &RadiosondeDemodGUI::on_frames_cellDoubleClicked); + QObject::connect(ui->logEnable, &ButtonSwitch::clicked, this, &RadiosondeDemodGUI::on_logEnable_clicked); + QObject::connect(ui->logFilename, &QToolButton::clicked, this, &RadiosondeDemodGUI::on_logFilename_clicked); + QObject::connect(ui->logOpen, &QToolButton::clicked, this, &RadiosondeDemodGUI::on_logOpen_clicked); +} + +void RadiosondeDemodGUI::updateAbsoluteCenterFrequency() +{ + setStatusFrequency(m_deviceCenterFrequency + m_settings.m_inputFrequencyOffset); +} diff --git a/plugins/channelrx/demodradiosonde/radiosondedemodgui.h b/plugins/channelrx/demodradiosonde/radiosondedemodgui.h index 053802350..ca3879c8b 100644 --- a/plugins/channelrx/demodradiosonde/radiosondedemodgui.h +++ b/plugins/channelrx/demodradiosonde/radiosondedemodgui.h @@ -34,7 +34,6 @@ class PluginAPI; class DeviceUISet; class BasebandSampleSink; class ScopeVis; -class ScopeVisXY; class RadiosondeDemod; class RadiosondeDemodGUI; class RS41Frame; @@ -54,6 +53,17 @@ public: QByteArray serialize() const; bool deserialize(const QByteArray& data); virtual MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; } + virtual void setWorkspaceIndex(int index) { m_settings.m_workspaceIndex = index; }; + virtual int getWorkspaceIndex() const { return m_settings.m_workspaceIndex; }; + virtual void setGeometryBytes(const QByteArray& blob) { m_settings.m_geometryBytes = blob; }; + virtual QByteArray getGeometryBytes() const { return m_settings.m_geometryBytes; }; + virtual QString getTitle() const { return m_settings.m_title; }; + virtual QColor getTitleColor() const { return m_settings.m_rgbColor; }; + virtual void zetHidden(bool hidden) { m_settings.m_hidden = hidden; } + virtual bool getHidden() const { return m_settings.m_hidden; } + virtual ChannelMarker& getChannelMarker() { return m_channelMarker; } + virtual int getStreamIndex() const { return m_settings.m_streamIndex; } + virtual void setStreamIndex(int streamIndex) { m_settings.m_streamIndex = streamIndex; } public slots: void channelMarkerChangedByCursor(); @@ -66,6 +76,8 @@ private: ChannelMarker m_channelMarker; RollupState m_rollupState; RadiosondeDemodSettings m_settings; + qint64 m_deviceCenterFrequency; + int m_basebandSampleRate; bool m_doApplySettings; ScopeVis* m_scopeVis; @@ -84,9 +96,10 @@ private: void blockApplySettings(bool block); void applySettings(bool force = false); void displaySettings(); - void displayStreamIndex(); void frameReceived(const QByteArray& frame, const QDateTime& dateTime, int errorsCorrected, int threshold); bool handleMessage(const Message& message); + void makeUIConnections(); + void updateAbsoluteCenterFrequency(); void leaveEvent(QEvent*); void enterEvent(QEvent*); diff --git a/plugins/channelrx/demodradiosonde/radiosondedemodgui.ui b/plugins/channelrx/demodradiosonde/radiosondedemodgui.ui index f8624865b..3edf4d26c 100644 --- a/plugins/channelrx/demodradiosonde/radiosondedemodgui.ui +++ b/plugins/channelrx/demodradiosonde/radiosondedemodgui.ui @@ -1,7 +1,7 @@ RadiosondeDemodGUI - + 0 @@ -1055,9 +1055,9 @@ - RollupWidget + RollupContents QWidget -
gui/rollupwidget.h
+
gui/rollupcontents.h
1
diff --git a/plugins/channelrx/demodradiosonde/radiosondedemodsettings.cpp b/plugins/channelrx/demodradiosonde/radiosondedemodsettings.cpp index 03d22fb0d..0f97da8dd 100644 --- a/plugins/channelrx/demodradiosonde/radiosondedemodsettings.cpp +++ b/plugins/channelrx/demodradiosonde/radiosondedemodsettings.cpp @@ -54,6 +54,8 @@ void RadiosondeDemodSettings::resetToDefaults() m_reverseAPIPort = 8888; m_reverseAPIDeviceIndex = 0; m_reverseAPIChannelIndex = 0; + m_workspaceIndex = 0; + m_hidden = false; for (int i = 0; i < RADIOSONDEDEMOD_FRAME_COLUMNS; i++) { @@ -98,6 +100,10 @@ QByteArray RadiosondeDemodSettings::serialize() const s.writeBlob(25, m_rollupState->serialize()); } + s.writeS32(26, m_workspaceIndex); + s.writeBlob(27, m_geometryBytes); + s.writeBool(28, m_hidden); + for (int i = 0; i < RADIOSONDEDEMOD_FRAME_COLUMNS; i++) s.writeS32(100 + i, m_frameColumnIndexes[i]); for (int i = 0; i < RADIOSONDEDEMOD_FRAME_COLUMNS; i++) @@ -180,6 +186,10 @@ bool RadiosondeDemodSettings::deserialize(const QByteArray& data) m_rollupState->deserialize(bytetmp); } + d.readS32(26, &m_workspaceIndex, 0); + d.readBlob(27, &m_geometryBytes); + d.readBool(28, &m_hidden, false); + for (int i = 0; i < RADIOSONDEDEMOD_FRAME_COLUMNS; i++) { d.readS32(100 + i, &m_frameColumnIndexes[i], i); } diff --git a/plugins/channelrx/demodradiosonde/radiosondedemodsettings.h b/plugins/channelrx/demodradiosonde/radiosondedemodsettings.h index 76a4fe839..46b5f2142 100644 --- a/plugins/channelrx/demodradiosonde/radiosondedemodsettings.h +++ b/plugins/channelrx/demodradiosonde/radiosondedemodsettings.h @@ -57,6 +57,9 @@ struct RadiosondeDemodSettings uint16_t m_reverseAPIChannelIndex; Serializable *m_scopeGUI; Serializable *m_rollupState; + int m_workspaceIndex; + QByteArray m_geometryBytes; + bool m_hidden; int m_frameColumnIndexes[RADIOSONDEDEMOD_FRAME_COLUMNS];//!< How the columns are ordered in the table int m_frameColumnSizes[RADIOSONDEDEMOD_FRAME_COLUMNS]; //!< Size of the columns in the table diff --git a/plugins/channelrx/demodradiosonde/readme.md b/plugins/channelrx/demodradiosonde/readme.md index 5254b227b..f9941962a 100644 --- a/plugins/channelrx/demodradiosonde/readme.md +++ b/plugins/channelrx/demodradiosonde/readme.md @@ -4,12 +4,14 @@ This plugin can be used to demodulate RS41 radiosonde weather balloon signals. Radiosondes typically transmit on 400-406MHz and are in the sky around the world for around 1 hour around 00:00 UTC. -RS41 radiosondes transmit data frames every second, containing position, velocity and PTU (Pressure, Temperature and Humidity) readings. The radios use GFSK modulation, with ±2.4kHz deviation at 4,800 baud. Reed Solomon encoding is used for ECC (Error Checking and Correction). +RS41 radiosondes transmit data frames every second, containing position, velocity and PTU (Pressure, Temperature and Humidity) readings. The radios use GFSK modulation, with �2.4kHz deviation at 4,800 baud. Reed Solomon encoding is used for ECC (Error Checking and Correction). The Radiosonde demodulator can forward received data to the [Radiosone feature](../../feature/radiosonde/readme.md), which can plot charts showing how altitude and PTU vary over time, and also plot the position of the radiosonde on the 2D and 3D maps.

Interface

+The top and bottom bars of the channel window are described [here](../../../sdrgui/channel/readme.md) + ![Radiosonde Demodulator plugin GUI](../../../doc/img/RadiosondeDemod_plugin.png)

1: Frequency shift from center frequency of reception

@@ -81,18 +83,18 @@ The received frames table displays information about each radiosonde frame recei * Serial - The serial number of the radiosonde. Double clicking on this column will search for the radiosone on https://sondehub.org/ * Frame - Frame number * Phase - Flight phase: On ground, Ascent and Descent. -* Lat (°) - Latitude in degrees, North positive. Double clicking on this column will search for the radiosonde on the Map. -* Lon (°) - Longitude in degrees, East positive. Double clicking on this column will search for the radiosonde on the Map. +* Lat (�) - Latitude in degrees, North positive. Double clicking on this column will search for the radiosonde on the Map. +* Lon (�) - Longitude in degrees, East positive. Double clicking on this column will search for the radiosonde on the Map. * Alt (m) - Altitude in metres. * Spd (km/h) - Speed over ground in kilometres per hour. * VR (m/s) - Vertical climb rate in metres per second. -* Hdg (°) - Heading in degrees. +* Hdg (�) - Heading in degrees. * P (hPA) - Air pressure in hectopascals. Not all RS41s include a pressure sensor. A value ending with 'U' indicates a uncalibrated estimate and may be inaccurate. -* T (°C) - Air temperature in degrees Celsius. A value ending with 'U' indicates a uncalibrated estimate and may be inaccurate. +* T (�C) - Air temperature in degrees Celsius. A value ending with 'U' indicates a uncalibrated estimate and may be inaccurate. * U (%) - Relative humidity in percent. A value ending with 'U' indicates a uncalibrated estimate and may be inaccurate. * Bat (V) - Battery voltage in Volts. * Bat - Battery status: OK or low. -* PCB (°C) - Temperature of PCB. +* PCB (�C) - Temperature of PCB. * PWM (%) - Humidity sensor heater PWM (Pulse Width Modulation) setting, in percent. * TX (%) - Transmit power in percent. * Max SF - Maximum subframe number. diff --git a/plugins/channelrx/demodssb/readme.md b/plugins/channelrx/demodssb/readme.md index ba07e5e46..7be8ff834 100644 --- a/plugins/channelrx/demodssb/readme.md +++ b/plugins/channelrx/demodssb/readme.md @@ -6,6 +6,8 @@ This plugin can be used to listen to a single sideband or double sidebands modul

Interface

+The top and bottom bars of the channel window are described [here](../../../sdrgui/channel/readme.md) + ![SSB Demodulator plugin GUI](../../../doc/img/SSBDemod_plugin.png) ☞ In order to toggle USB or LSB mode in SSB mode you have to set the "BW" in channel filter cutoff control (9) to a positive (USB) or negative (LSB) value. The above screenshot shows a LSB setup. See the (8) to (10) paragraphs below for details. @@ -152,4 +154,4 @@ If you right click on it a dialog will open to select the audio output device. S

14: Spectrum display

-This is the spectrum display of the demodulated signal (SSB) or translated signal (DSB). Controls on the bottom of the panel are identical to the ones of the main spectrum display. +This is the spectrum display of the demodulated signal (SSB) or translated signal (DSB). Controls on the bottom of the panel are identical to the ones of the main spectrum display. Details on the spectrum view and controls can be found [here](../../../sdrgui/gui/spectrum.md) diff --git a/plugins/channelrx/demodssb/ssbdemod.cpp b/plugins/channelrx/demodssb/ssbdemod.cpp index 658b03e2c..67ccc1741 100644 --- a/plugins/channelrx/demodssb/ssbdemod.cpp +++ b/plugins/channelrx/demodssb/ssbdemod.cpp @@ -28,6 +28,7 @@ #include #include "SWGChannelSettings.h" +#include "SWGWorkspaceInfo.h" #include "SWGSSBDemodSettings.h" #include "SWGChannelReport.h" #include "SWGSSBDemodReport.h" @@ -96,6 +97,18 @@ SSBDemod::~SSBDemod() delete m_thread; } +void SSBDemod::setDeviceAPI(DeviceAPI *deviceAPI) +{ + if (deviceAPI != m_deviceAPI) + { + m_deviceAPI->removeChannelSinkAPI(this); + m_deviceAPI->removeChannelSink(this); + m_deviceAPI = deviceAPI; + m_deviceAPI->addChannelSink(this); + m_deviceAPI->addChannelSinkAPI(this); + } +} + uint32_t SSBDemod::getNumberOfDeviceStreams() const { return m_deviceAPI->getNbSourceStreams(); @@ -145,6 +158,10 @@ bool SSBDemod::handleMessage(const Message& cmd) DSPSignalNotification* rep = new DSPSignalNotification(notif); // make a copy qDebug() << "SSBDemod::handleMessage: DSPSignalNotification"; m_basebandSink->getInputMessageQueue()->push(rep); + // Forwatd to GUI if any + if (getMessageQueueToGUI()) { + getMessageQueueToGUI()->push(new DSPSignalNotification(notif)); + } return true; } @@ -351,6 +368,15 @@ int SSBDemod::webapiSettingsGet( return 200; } +int SSBDemod::webapiWorkspaceGet( + SWGSDRangel::SWGWorkspaceInfo& response, + QString& errorMessage) +{ + (void) errorMessage; + response.setIndex(m_settings.m_workspaceIndex); + return 200; +} + int SSBDemod::webapiSettingsPutPatch( bool force, const QStringList& channelSettingsKeys, diff --git a/plugins/channelrx/demodssb/ssbdemod.h b/plugins/channelrx/demodssb/ssbdemod.h index 3345cbb05..5d8489a3c 100644 --- a/plugins/channelrx/demodssb/ssbdemod.h +++ b/plugins/channelrx/demodssb/ssbdemod.h @@ -66,6 +66,8 @@ public: SSBDemod(DeviceAPI *deviceAPI); virtual ~SSBDemod(); virtual void destroy() { delete this; } + virtual void setDeviceAPI(DeviceAPI *deviceAPI); + virtual DeviceAPI *getDeviceAPI() { return m_deviceAPI; } SpectrumVis *getSpectrumVis() { return &m_spectrumVis; } using BasebandSampleSink::feed; @@ -109,6 +111,10 @@ public: SWGSDRangel::SWGChannelSettings& response, QString& errorMessage); + virtual int webapiWorkspaceGet( + SWGSDRangel::SWGWorkspaceInfo& response, + QString& errorMessage); + virtual int webapiSettingsPutPatch( bool force, const QStringList& channelSettingsKeys, diff --git a/plugins/channelrx/demodssb/ssbdemodgui.cpp b/plugins/channelrx/demodssb/ssbdemodgui.cpp index 177a3a6d8..9b12529f4 100644 --- a/plugins/channelrx/demodssb/ssbdemodgui.cpp +++ b/plugins/channelrx/demodssb/ssbdemodgui.cpp @@ -84,6 +84,16 @@ bool SSBDemodGUI::handleMessage(const Message& message) blockApplySettings(false); return true; } + else if (DSPSignalNotification::match(message)) + { + const DSPSignalNotification& notif = (const DSPSignalNotification&) message; + m_deviceCenterFrequency = notif.getCenterFrequency(); + m_basebandSampleRate = notif.getSampleRate(); + ui->deltaFrequency->setValueRange(false, 7, -m_basebandSampleRate/2, m_basebandSampleRate/2); + ui->deltaFrequencyLabel->setToolTip(tr("Range %1 %L2 Hz").arg(QChar(0xB1)).arg(m_basebandSampleRate/2)); + updateAbsoluteCenterFrequency(); + return true; + } else { return false; @@ -139,6 +149,7 @@ void SSBDemodGUI::on_deltaFrequency_changed(qint64 value) { m_channelMarker.setCenterFrequency(value); m_settings.m_inputFrequencyOffset = m_channelMarker.getCenterFrequency(); + updateAbsoluteCenterFrequency(); applySettings(); } @@ -235,11 +246,17 @@ void SSBDemodGUI::onMenuDialogCalled(const QPoint &p) dialog.setReverseAPIPort(m_settings.m_reverseAPIPort); dialog.setReverseAPIDeviceIndex(m_settings.m_reverseAPIDeviceIndex); dialog.setReverseAPIChannelIndex(m_settings.m_reverseAPIChannelIndex); + dialog.setDefaultTitle(m_displayedName); + + if (m_deviceUISet->m_deviceMIMOEngine) + { + dialog.setNumberOfStreams(m_ssbDemod->getNumberOfDeviceStreams()); + dialog.setStreamIndex(m_settings.m_streamIndex); + } dialog.move(p); dialog.exec(); - m_settings.m_inputFrequencyOffset = m_channelMarker.getCenterFrequency(); m_settings.m_rgbColor = m_channelMarker.getColor().rgb(); m_settings.m_title = m_channelMarker.getTitle(); m_settings.m_useReverseAPI = dialog.useReverseAPI(); @@ -249,22 +266,17 @@ void SSBDemodGUI::onMenuDialogCalled(const QPoint &p) m_settings.m_reverseAPIChannelIndex = dialog.getReverseAPIChannelIndex(); setWindowTitle(m_settings.m_title); + setTitle(m_channelMarker.getTitle()); setTitleColor(m_settings.m_rgbColor); - applySettings(); - } - else if ((m_contextMenuType == ContextMenuStreamSettings) && (m_deviceUISet->m_deviceMIMOEngine)) - { - DeviceStreamSelectionDialog dialog(this); - dialog.setNumberOfStreams(m_ssbDemod->getNumberOfDeviceStreams()); - dialog.setStreamIndex(m_settings.m_streamIndex); - dialog.move(p); - dialog.exec(); + if (m_deviceUISet->m_deviceMIMOEngine) + { + m_settings.m_streamIndex = dialog.getSelectedStreamIndex(); + m_channelMarker.clearStreamIndexes(); + m_channelMarker.addStreamIndex(m_settings.m_streamIndex); + updateIndexLabel(); + } - m_settings.m_streamIndex = dialog.getSelectedStreamIndex(); - m_channelMarker.clearStreamIndexes(); - m_channelMarker.addStreamIndex(m_settings.m_streamIndex); - displayStreamIndex(); applySettings(); } @@ -276,7 +288,23 @@ void SSBDemodGUI::onWidgetRolled(QWidget* widget, bool rollDown) (void) widget; (void) rollDown; - saveState(m_rollupState); + RollupContents *rollupContents = getRollupContents(); + + if (rollupContents->hasExpandableWidgets()) + { + qDebug("SSBDemodGUI::onWidgetRolled: set vertical policy expanding"); + setSizePolicy(sizePolicy().horizontalPolicy(), QSizePolicy::Expanding); + } + else + { + qDebug("SSBDemodGUI::onWidgetRolled: set vertical policy fixed"); + setSizePolicy(sizePolicy().horizontalPolicy(), QSizePolicy::Fixed); + } + + int h = rollupContents->height() + getAdditionalHeight(); + resize(width(), h); + + rollupContents->saveState(m_rollupState); applySettings(); } @@ -286,6 +314,8 @@ SSBDemodGUI::SSBDemodGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, Baseban m_pluginAPI(pluginAPI), m_deviceUISet(deviceUISet), m_channelMarker(this), + m_deviceCenterFrequency(0), + m_basebandSampleRate(1), m_doApplySettings(true), m_spectrumRate(6000), m_audioBinaural(false), @@ -294,10 +324,13 @@ SSBDemodGUI::SSBDemodGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, Baseban m_squelchOpen(false), m_audioSampleRate(-1) { - ui->setupUi(this); - m_helpURL = "plugins/channelrx/demodssb/readme.md"; setAttribute(Qt::WA_DeleteOnClose, true); - connect(this, SIGNAL(widgetRolled(QWidget*,bool)), this, SLOT(onWidgetRolled(QWidget*,bool))); + m_helpURL = "plugins/channelrx/demodssb/readme.md"; + RollupContents *rollupContents = getRollupContents(); + ui->setupUi(rollupContents); + setSizePolicy(rollupContents->sizePolicy()); + rollupContents->arrangeRollups(); + connect(rollupContents, SIGNAL(widgetRolled(QWidget*,bool)), this, SLOT(onWidgetRolled(QWidget*,bool))); connect(this, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(onMenuDialogCalled(const QPoint &))); m_ssbDemod = (SSBDemod*) rxChannel; @@ -336,8 +369,6 @@ SSBDemodGUI::SSBDemodGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, Baseban m_settings.setRollupState(&m_rollupState); m_deviceUISet->addChannelMarker(&m_channelMarker); - m_deviceUISet->addRollupWidget(this); - connect(&m_channelMarker, SIGNAL(changedByCursor()), this, SLOT(channelMarkerChangedByCursor())); connect(&m_channelMarker, SIGNAL(highlightedByCursor()), this, SLOT(channelMarkerHighlightedByCursor())); connect(getInputMessageQueue(), SIGNAL(messageEnqueued()), this, SLOT(handleInputMessages())); @@ -352,6 +383,8 @@ SSBDemodGUI::SSBDemodGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, Baseban ui->BW->setMaximum(480); ui->lowCut->setMaximum(480); displaySettings(); + makeUIConnections(); + applyBandwidths(m_settings.m_spanLog2, true); // does applySettings(true) } @@ -520,6 +553,7 @@ void SSBDemodGUI::displaySettings() setTitleColor(m_settings.m_rgbColor); setWindowTitle(m_channelMarker.getTitle()); + setTitle(m_channelMarker.getTitle()); blockApplySettings(true); @@ -573,21 +607,13 @@ void SSBDemodGUI::displaySettings() displayAGCPowerThreshold(ui->agcPowerThreshold->value()); displayAGCThresholdGate(m_settings.m_agcThresholdGate); - displayStreamIndex(); + updateIndexLabel(); - restoreState(m_rollupState); + getRollupContents()->restoreState(m_rollupState); + updateAbsoluteCenterFrequency(); blockApplySettings(false); } -void SSBDemodGUI::displayStreamIndex() -{ - if (m_deviceUISet->m_deviceMIMOEngine) { - setStreamIndicator(tr("%1").arg(m_settings.m_streamIndex)); - } else { - setStreamIndicator("S"); // single channel indicator - } -} - void SSBDemodGUI::displayAGCPowerThreshold(int value) { if (value == SSBDemodSettings::m_minPowerThresholdDB) @@ -614,14 +640,16 @@ void SSBDemodGUI::displayAGCThresholdGate(int value) ui->agcThresholdGate->setValue(dialValue); } -void SSBDemodGUI::leaveEvent(QEvent*) +void SSBDemodGUI::leaveEvent(QEvent* event) { m_channelMarker.setHighlighted(false); + ChannelGUI::leaveEvent(event); } -void SSBDemodGUI::enterEvent(QEvent*) +void SSBDemodGUI::enterEvent(QEvent* event) { m_channelMarker.setHighlighted(true); + ChannelGUI::enterEvent(event); } void SSBDemodGUI::audioSelect() @@ -673,3 +701,27 @@ void SSBDemodGUI::tick() m_tickCount++; } + +void SSBDemodGUI::makeUIConnections() +{ + QObject::connect(ui->deltaFrequency, &ValueDialZ::changed, this, &SSBDemodGUI::on_deltaFrequency_changed); + QObject::connect(ui->audioBinaural, &QToolButton::toggled, this, &SSBDemodGUI::on_audioBinaural_toggled); + QObject::connect(ui->audioFlipChannels, &QToolButton::toggled, this, &SSBDemodGUI::on_audioFlipChannels_toggled); + QObject::connect(ui->dsb, &QToolButton::toggled, this, &SSBDemodGUI::on_dsb_toggled); + QObject::connect(ui->BW, &TickedSlider::valueChanged, this, &SSBDemodGUI::on_BW_valueChanged); + QObject::connect(ui->lowCut, &TickedSlider::valueChanged, this, &SSBDemodGUI::on_lowCut_valueChanged); + QObject::connect(ui->volume, &QDial::valueChanged, this, &SSBDemodGUI::on_volume_valueChanged); + QObject::connect(ui->agc, &ButtonSwitch::toggled, this, &SSBDemodGUI::on_agc_toggled); + QObject::connect(ui->agcClamping, &ButtonSwitch::toggled, this, &SSBDemodGUI::on_agcClamping_toggled); + QObject::connect(ui->agcTimeLog2, &QDial::valueChanged, this, &SSBDemodGUI::on_agcTimeLog2_valueChanged); + QObject::connect(ui->agcPowerThreshold, &QDial::valueChanged, this, &SSBDemodGUI::on_agcPowerThreshold_valueChanged); + QObject::connect(ui->agcThresholdGate, &QDial::valueChanged, this, &SSBDemodGUI::on_agcThresholdGate_valueChanged); + QObject::connect(ui->audioMute, &QToolButton::toggled, this, &SSBDemodGUI::on_audioMute_toggled); + QObject::connect(ui->spanLog2, &QSlider::valueChanged, this, &SSBDemodGUI::on_spanLog2_valueChanged); + QObject::connect(ui->flipSidebands, &QPushButton::clicked, this, &SSBDemodGUI::on_flipSidebands_clicked); +} + +void SSBDemodGUI::updateAbsoluteCenterFrequency() +{ + setStatusFrequency(m_deviceCenterFrequency + m_settings.m_inputFrequencyOffset); +} diff --git a/plugins/channelrx/demodssb/ssbdemodgui.h b/plugins/channelrx/demodssb/ssbdemodgui.h index 2867f51c9..6a193f09e 100644 --- a/plugins/channelrx/demodssb/ssbdemodgui.h +++ b/plugins/channelrx/demodssb/ssbdemodgui.h @@ -33,6 +33,17 @@ public: QByteArray serialize() const; bool deserialize(const QByteArray& data); virtual MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; } + virtual void setWorkspaceIndex(int index) { m_settings.m_workspaceIndex = index; }; + virtual int getWorkspaceIndex() const { return m_settings.m_workspaceIndex; }; + virtual void setGeometryBytes(const QByteArray& blob) { m_settings.m_geometryBytes = blob; }; + virtual QByteArray getGeometryBytes() const { return m_settings.m_geometryBytes; }; + virtual QString getTitle() const { return m_settings.m_title; }; + virtual QColor getTitleColor() const { return m_settings.m_rgbColor; }; + virtual void zetHidden(bool hidden) { m_settings.m_hidden = hidden; } + virtual bool getHidden() const { return m_settings.m_hidden; } + virtual ChannelMarker& getChannelMarker() { return m_channelMarker; } + virtual int getStreamIndex() const { return m_settings.m_streamIndex; } + virtual void setStreamIndex(int streamIndex) { m_settings.m_streamIndex = streamIndex; } public slots: void channelMarkerChangedByCursor(); @@ -45,6 +56,8 @@ private: ChannelMarker m_channelMarker; RollupState m_rollupState; SSBDemodSettings m_settings; + qint64 m_deviceCenterFrequency; + int m_basebandSampleRate; bool m_doApplySettings; int m_spectrumRate; bool m_audioBinaural; @@ -69,10 +82,11 @@ private: void applyBandwidths(unsigned int spanLog2, bool force = false); unsigned int spanLog2Max(); void displaySettings(); - void displayStreamIndex(); void displayAGCPowerThreshold(int value); void displayAGCThresholdGate(int value); bool handleMessage(const Message& message); + void makeUIConnections(); + void updateAbsoluteCenterFrequency(); void leaveEvent(QEvent*); void enterEvent(QEvent*); diff --git a/plugins/channelrx/demodssb/ssbdemodgui.ui b/plugins/channelrx/demodssb/ssbdemodgui.ui index 9eaad6728..6896c617b 100644 --- a/plugins/channelrx/demodssb/ssbdemodgui.ui +++ b/plugins/channelrx/demodssb/ssbdemodgui.ui @@ -1,7 +1,7 @@ SSBDemodGUI - + 0 @@ -11,7 +11,7 @@ - + 0 0 @@ -530,6 +530,7 @@ + Liberation Sans 8 @@ -551,6 +552,7 @@ + Liberation Sans 8 @@ -563,6 +565,7 @@ + Liberation Sans 8 @@ -584,6 +587,7 @@ + Liberation Sans 8 @@ -599,6 +603,7 @@ + Liberation Sans 8 @@ -620,6 +625,7 @@ + Liberation Sans 8 @@ -915,6 +921,12 @@ 284 + + + 0 + 0 + + Channel Spectrum @@ -936,6 +948,12 @@ + + + 0 + 0 + + 200 @@ -951,24 +969,48 @@ - + + + + 0 + 0 + + + + + 0 + 30 + + + - RollupWidget + RollupContents QWidget -
gui/rollupwidget.h
+
gui/rollupcontents.h
1
+ + ButtonSwitch + QToolButton +
gui/buttonswitch.h
+
LevelMeterSignalDB QWidget
gui/levelmeter.h
1
+ + ValueDialZ + QWidget +
gui/valuedialz.h
+ 1 +
GLSpectrum QWidget @@ -981,17 +1023,6 @@
gui/glspectrumgui.h
1
- - ValueDialZ - QWidget -
gui/valuedialz.h
- 1 -
- - ButtonSwitch - QToolButton -
gui/buttonswitch.h
-
TickedSlider QSlider diff --git a/plugins/channelrx/demodssb/ssbdemodsettings.cpp b/plugins/channelrx/demodssb/ssbdemodsettings.cpp index e980a5df3..3eb35e735 100644 --- a/plugins/channelrx/demodssb/ssbdemodsettings.cpp +++ b/plugins/channelrx/demodssb/ssbdemodsettings.cpp @@ -63,6 +63,8 @@ void SSBDemodSettings::resetToDefaults() m_reverseAPIPort = 8888; m_reverseAPIDeviceIndex = 0; m_reverseAPIChannelIndex = 0; + m_workspaceIndex = 0; + m_hidden = false; } QByteArray SSBDemodSettings::serialize() const @@ -100,6 +102,10 @@ QByteArray SSBDemodSettings::serialize() const s.writeBlob(24, m_rollupState->serialize()); } + s.writeS32(25, m_workspaceIndex); + s.writeBlob(26, m_geometryBytes); + s.writeBool(27, m_hidden); + return s.final(); } @@ -168,6 +174,10 @@ bool SSBDemodSettings::deserialize(const QByteArray& data) m_rollupState->deserialize(bytetmp); } + d.readS32(25, &m_workspaceIndex, 0); + d.readBlob(26, &m_geometryBytes); + d.readBool(27, &m_hidden, false); + return true; } else diff --git a/plugins/channelrx/demodssb/ssbdemodsettings.h b/plugins/channelrx/demodssb/ssbdemodsettings.h index 9e9de931a..d1c51695b 100644 --- a/plugins/channelrx/demodssb/ssbdemodsettings.h +++ b/plugins/channelrx/demodssb/ssbdemodsettings.h @@ -47,6 +47,9 @@ struct SSBDemodSettings uint16_t m_reverseAPIPort; uint16_t m_reverseAPIDeviceIndex; uint16_t m_reverseAPIChannelIndex; + int m_workspaceIndex; + QByteArray m_geometryBytes; + bool m_hidden; Serializable *m_channelMarker; Serializable *m_spectrumGUI; diff --git a/plugins/channelrx/demodvor/CMakeLists.txt b/plugins/channelrx/demodvor/CMakeLists.txt index fdd035c46..c488df18f 100644 --- a/plugins/channelrx/demodvor/CMakeLists.txt +++ b/plugins/channelrx/demodvor/CMakeLists.txt @@ -20,7 +20,6 @@ set(vor_HEADERS vordemodreport.h ) - include_directories( ${CMAKE_SOURCE_DIR}/swagger/sdrangel/code/qt5/client ) @@ -30,18 +29,14 @@ if(NOT SERVER_MODE) ${vor_SOURCES} vordemodgui.cpp vordemodgui.ui - map.qrc - icons.qrc ) set(vor_HEADERS ${vor_HEADERS} vordemodgui.h - navaid.h - ../demodadsb/csv.h ) set(TARGET_NAME demodvor) - set(TARGET_LIB "Qt5::Widgets" Qt5::Quick Qt5::QuickWidgets Qt5::Positioning) + set(TARGET_LIB "Qt5::Widgets") set(TARGET_LIB_GUI "sdrgui") set(INSTALL_FOLDER ${INSTALL_PLUGINS_DIR}) else() diff --git a/plugins/channelrx/demodvor/readme.md b/plugins/channelrx/demodvor/readme.md index d037d5930..fb4ad3754 100644 --- a/plugins/channelrx/demodvor/readme.md +++ b/plugins/channelrx/demodvor/readme.md @@ -10,80 +10,66 @@ VORs also transmit a Morse code ident signal at a 1020Hz offset. This is a 2 or Some VORs also transmit an AM voice identification or information signal between 300-3kHz. -This plugin can demodulate all four signals from multiple VORs simultaneously, allowing your position to be determined and plotted on a map. It can also demodulate the Morse code ident signal and and check they are correct for each VOR. The Morse code ident and any voice signal will also be heard as audio. - Note that for aircraft, there is typically a direct line-of-sight to the VOR. This is unlikely to be the case when using an SDR on the ground. To get good results, ideally you want to be on a nice high hill or close to the VOR. +

Using it for localization

+ +Several instances of this plugin can be created to monitor multiple VORs and collate information in the VOR Localizer feature plugin. The VOR Localizer can also perform a round robin on multiple VORs with just one VOR demodulator. Please refer to [VOR Localizer](../../feature/vorlocalizer/readme.md) for more information about this feature plugin +

Interface

-![VOR Demodulator plugin GUI](../../../doc/img/VORDemod_plugin.png) +The top and bottom bars of the channel window are described [here](../../../sdrgui/channel/readme.md) -

1: Level meter in dB

+![VOR Demodulator plugin GUI](../../../doc/img/VORDemodSC_plugin.png) + +

1: Frequency shift from center frequency of reception value

+ +Use the wheels to adjust the frequency shift in Hz from the center frequency of reception. 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 arrows. Pressing shift simultaneously moves digit by 5 and pressing control moves it by 2. Left click on a digit sets the cursor position at this digit. + +

2: Level meter in dB

- top bar (green): average value - bottom bar (blue green): instantaneous peak value - tip vertical bar (bright green): peak hold value -

2: Channel power

+

3: Channel power

Average total power in dB relative to a +/- 1.0 amplitude signal received in the pass band. -

3: Audio mute and audio output select

+

4: Audio mute and audio output select

Left click on this button to toggle audio mute for this channel. The button will light up in green if the squelch is open. This helps identifying which channels are active in a multi-channel configuration. If you right click on it it will open a dialog to select the audio output device. See [audio management documentation](../../../sdrgui/audio.md) for details. -

4: Download VOR Database

- -Pressing this button downloads the OpenAIP.net Navaid database, which contains the details (position, frequencies, name and ident) for each VOR. This needs to be performed at least once. - -

5: Draw Radials Adjusted for Magnetic Declination

- -When checked, radials on the map will drawn adjusted for magnetic declination. For example, if a VOR has a magnetic declination of 5 degrees, and the radial is calculated at 0 degrees, the radial will be drawn to magnetic North, i.e. -5 degress from true North. If not checked, the same radial would be drawn to true North (i.e 0 degrees), which may result in a less accurate position estimate. - -

6: Morse ident threshold

+

5: Morse ident threshold

This is the Morse code ident threshold, expressed as a linear signal to noise (SNR) ratio. This is effectively the signal level required for the Morse demodulator to detect a dot or dash. Setting this to low values will allow the Morse demodulator to detect weak signals, but it also increases the likelyhood that noise will incorrectly be interpreted as a signal, resulting in invalid idents being reported. -

7: Squelch threshold

+

6: Squelch threshold

This is the squelch threshold in dB. The average total power received in the signal bandwidth before demodulation is compared to this value and the squelch input is open above this value. It can be varied continuously in 0.1 dB steps from 0.0 to -100.0 dB using the dial button. -

8: Volume

+

7: Volume

This is the volume of the audio signal from 0.0 (mute) to 10.0 (maximum). It can be varied continuously in 0.1 steps using the dial button. -

VOR Table

+

8: Radial dircetion

-The VOR table displays information about selected VORs. To select or deselect a VOR, double click it on the map. The information displayed includes: +Demodulated radial direction in degrees (unadjusted for magnetic declination). If there is a low confidence the value is correct (due to a weak signal), it will be displayed in red. -![VOR Demodulator Table](../../../doc/img/VORDemod_plugin_table.png) +

9: Reference signal power in dB

-* Name - The name of the VOR. For example: 'LONDON'. -* Freq (MHz) - The center frequency the VOR transmits on in MHz. -* Offset (kHz) - This is the current difference between the VOR's center frequency and SDRangle's device center frequency. If displayed in red, the VOR is out of range and it's signal will not be able to be received. -* Ident - A 2 or 3 character identifier for the VOR. For example: 'LON'. -* Morse - The Morse code identifier for the VOR. For example: '.-.. --- -.' -* RX Ident - This contains the demodulated ident. If it matches the expected ident, it will be displayed in green, if not, it will be displayed in red. If an ident is received that is not 2 or 3 characters, it will not be displayed, but the last received ident will be displayed in yellow. -* RX Morse - This contains the demodulated Morse code ident. Colour coding is as for RX Ident. -* Radial - This contains the demodulated radial direction in degrees (unadjusted for magnetic declination). If there is a low confidence the value is correct (due to a weak signal), it will be displayed in red. -* Ref (dB) - This displays the magnitude of the received 30Hz FM reference signal in dB. -* Var (dB) - This displays the mangitude of the received 30Hz AM variable signal in dB. -* Mute - This button allows you to mute or unmute the audio from the corresponding VOR. +Magnitude of the received 30Hz FM reference signal in dB -

Map

+

10. Variable signal power in dB

-The map displays the locations of each VOR, with an information box containing the information about the VOR, such as it's name, frequency, ident (in text and Morse), range and magnetic declination. +Mangitude of the received 30Hz AM variable signal in dB -To initialise the VORs on the map, first set your position using the Preferences > My position menu, then open the VOR Demodulator channel (close and reopen it, if already open). Then press the Download VOR Database button (This only needs to be performed once). The map should then display VORs in your vicinity. +

11. VOR identifier code (decoded)

-Double clicking on a VOR will select and add it to the list of VORs to demodulate. It will be added to the VOR table and will be highlighted green. Double clicking a selected VOR, will remove it from the list of VORs to demodulate and it will be removed from the VOR table. +Demodulated identifier. If an identifier is received that is not 2 or 3 characters, it will be displayed in yellow else in white. -When a signal from a VOR is correctly being demodulated, a radial line will be drawn on the map, at the angle corresponding to the phase difference between the AM and FM 30Hz signals. Your receiver should be somewhere along this radial line. The length of the radial line is set according to the range of the VOR as recorded in the database, which is valid for aircraft at altitude. Range on the ground will be considerably less. An approximate position for the receiver is where the radial lines from two or more VORs intersect. +

12. VOR identifier code (Morse)

-![VOR Demodulator Map](../../../doc/img/VORDemod_plugin_map.png) - -

Attribution

- -Icons by Denelson83 and mamayer, via Wikimedia Commons and RULI from the Noun Project https://thenounproject.com/ +Demodulated Morse code identifier. Colour coding is the ame as for the decoded identifier. diff --git a/plugins/channelrx/demodvor/vordemod.cpp b/plugins/channelrx/demodvor/vordemod.cpp index e81f613c7..1ac469377 100644 --- a/plugins/channelrx/demodvor/vordemod.cpp +++ b/plugins/channelrx/demodvor/vordemod.cpp @@ -16,8 +16,6 @@ // along with this program. If not, see . // /////////////////////////////////////////////////////////////////////////////////// -#include "vordemod.h" - #include #include #include @@ -29,6 +27,7 @@ #include #include "SWGChannelSettings.h" +#include "SWGWorkspaceInfo.h" #include "SWGVORDemodSettings.h" #include "SWGChannelReport.h" #include "SWGVORDemodReport.h" @@ -41,6 +40,9 @@ #include "util/db.h" #include "maincore.h" +#include "vordemodreport.h" +#include "vordemod.h" + MESSAGE_CLASS_DEFINITION(VORDemod::MsgConfigureVORDemod, Message) const char * const VORDemod::m_channelIdURI = "sdrangel.channel.vordemod"; @@ -54,6 +56,7 @@ VORDemod::VORDemod(DeviceAPI *deviceAPI) : setObjectName(m_channelId); m_basebandSink = new VORDemodBaseband(); + m_basebandSink->setMessageQueueToChannel(getInputMessageQueue()); m_basebandSink->moveToThread(&m_thread); applySettings(m_settings, true); @@ -96,6 +99,18 @@ VORDemod::~VORDemod() delete m_basebandSink; } +void VORDemod::setDeviceAPI(DeviceAPI *deviceAPI) +{ + if (deviceAPI != m_deviceAPI) + { + m_deviceAPI->removeChannelSinkAPI(this); + m_deviceAPI->removeChannelSink(this); + m_deviceAPI = deviceAPI; + m_deviceAPI->addChannelSink(this); + m_deviceAPI->addChannelSinkAPI(this); + } +} + uint32_t VORDemod::getNumberOfDeviceStreams() const { return m_deviceAPI->getNbSourceStreams(); @@ -150,10 +165,52 @@ bool VORDemod::handleMessage(const Message& cmd) qDebug() << "VORDemod::handleMessage: DSPSignalNotification"; m_basebandSink->getInputMessageQueue()->push(rep); // Forward to GUI if any + if (m_guiMessageQueue) { + m_guiMessageQueue->push(new DSPSignalNotification(notif)); + } + + return true; + } + else if (VORDemodReport::MsgReportRadial::match(cmd)) + { + VORDemodReport::MsgReportRadial& report = (VORDemodReport::MsgReportRadial&) cmd; + m_radial = report.getRadial(); + m_refMag = report.getRefMag(); + m_varMag = report.getVarMag(); + if (m_guiMessageQueue) { - rep = new DSPSignalNotification(notif); - m_guiMessageQueue->push(rep); + VORDemodReport::MsgReportRadial *msg = new VORDemodReport::MsgReportRadial(report); + m_guiMessageQueue->push(msg); + } + + MessagePipes& messagePipes = MainCore::instance()->getMessagePipes(); + QList pipes; + messagePipes.getMessagePipes(this, "report", pipes); + + if (pipes.size() > 0) { + sendChannelReport(pipes); + } + + return true; + } + else if (VORDemodReport::MsgReportIdent::match(cmd)) + { + VORDemodReport::MsgReportIdent& report = (VORDemodReport::MsgReportIdent&) cmd; + m_morseIdent = report.getIdent(); + + if (m_guiMessageQueue) + { + VORDemodReport::MsgReportIdent *msg = new VORDemodReport::MsgReportIdent(report); + m_guiMessageQueue->push(msg); + } + + MessagePipes& messagePipes = MainCore::instance()->getMessagePipes(); + QList pipes; + messagePipes.getMessagePipes(this, "report", pipes); + + if (pipes.size() > 0) { + sendChannelReport(pipes); } return true; @@ -164,9 +221,24 @@ bool VORDemod::handleMessage(const Message& cmd) } } +void VORDemod::setCenterFrequency(qint64 frequency) +{ + VORDemodSettings settings = m_settings; + settings.m_inputFrequencyOffset = frequency; + applySettings(settings, false); + + if (m_guiMessageQueue) // forward to GUI if any + { + MsgConfigureVORDemod *msgToGUI = MsgConfigureVORDemod::create(settings, false); + m_guiMessageQueue->push(msgToGUI); + } +} + void VORDemod::applySettings(const VORDemodSettings& settings, bool force) { qDebug() << "VORDemod::applySettings:" + << " m_inputFrequencyOffset: " << settings.m_inputFrequencyOffset + << " m_navId: " << settings.m_navId << " m_volume: " << settings.m_volume << " m_squelch: " << settings.m_squelch << " m_audioMute: " << settings.m_audioMute @@ -181,6 +253,18 @@ void VORDemod::applySettings(const VORDemodSettings& settings, bool force) QList reverseAPIKeys; + if ((m_settings.m_inputFrequencyOffset != settings.m_inputFrequencyOffset) || force) { + reverseAPIKeys.append("inputFrequencyOffset"); + } + if ((m_settings.m_navId != settings.m_navId) || force) { + reverseAPIKeys.append("navId"); + + // Reset state so we don't report old data for new NavId + m_radial = 0.0f; + m_refMag = -200.0f; + m_varMag = -200.0f; + m_morseIdent = ""; + } if ((m_settings.m_squelch != settings.m_squelch) || force) { reverseAPIKeys.append("squelch"); } @@ -213,10 +297,6 @@ void VORDemod::applySettings(const VORDemodSettings& settings, bool force) reverseAPIKeys.append("identThreshold"); } - if ((m_settings.m_magDecAdjust != settings.m_magDecAdjust) || force) { - reverseAPIKeys.append("magDecAdjust"); - } - VORDemodBaseband::MsgConfigureVORDemodBaseband *msg = VORDemodBaseband::MsgConfigureVORDemodBaseband::create(settings, force); m_basebandSink->getInputMessageQueue()->push(msg); @@ -273,6 +353,15 @@ int VORDemod::webapiSettingsGet( return 200; } +int VORDemod::webapiWorkspaceGet( + SWGSDRangel::SWGWorkspaceInfo& response, + QString& errorMessage) +{ + (void) errorMessage; + response.setIndex(m_settings.m_workspaceIndex); + return 200; +} + int VORDemod::webapiSettingsPutPatch( bool force, const QStringList& channelSettingsKeys, @@ -303,6 +392,12 @@ void VORDemod::webapiUpdateChannelSettings( const QStringList& channelSettingsKeys, SWGSDRangel::SWGChannelSettings& response) { + if (channelSettingsKeys.contains("inputFrequencyOffset")) { + settings.m_inputFrequencyOffset = response.getVorDemodSettings()->getInputFrequencyOffset(); + } + if (channelSettingsKeys.contains("navId")) { + settings.m_navId = response.getVorDemodSettings()->getNavId(); + } if (channelSettingsKeys.contains("audioMute")) { settings.m_audioMute = response.getVorDemodSettings()->getAudioMute() != 0; } @@ -321,7 +416,6 @@ void VORDemod::webapiUpdateChannelSettings( if (channelSettingsKeys.contains("audioDeviceName")) { settings.m_audioDeviceName = *response.getVorDemodSettings()->getAudioDeviceName(); } - if (channelSettingsKeys.contains("streamIndex")) { settings.m_streamIndex = response.getVorDemodSettings()->getStreamIndex(); } @@ -343,9 +437,6 @@ void VORDemod::webapiUpdateChannelSettings( if (channelSettingsKeys.contains("identThreshold")) { settings.m_identThreshold = response.getVorDemodSettings()->getIdentThreshold(); } - if (channelSettingsKeys.contains("magDecAdjust")) { - settings.m_magDecAdjust = response.getVorDemodSettings()->getMagDecAdjust() != 0; - } if (settings.m_channelMarker && channelSettingsKeys.contains("channelMarker")) { settings.m_channelMarker->updateFrom(channelSettingsKeys, response.getVorDemodSettings()->getChannelMarker()); } @@ -367,6 +458,8 @@ int VORDemod::webapiReportGet( void VORDemod::webapiFormatChannelSettings(SWGSDRangel::SWGChannelSettings& response, const VORDemodSettings& settings) { + response.getVorDemodSettings()->setInputFrequencyOffset(settings.m_inputFrequencyOffset); + response.getVorDemodSettings()->setNavId(settings.m_navId); response.getVorDemodSettings()->setAudioMute(settings.m_audioMute ? 1 : 0); response.getVorDemodSettings()->setRgbColor(settings.m_rgbColor); response.getVorDemodSettings()->setSquelch(settings.m_squelch); @@ -396,9 +489,7 @@ void VORDemod::webapiFormatChannelSettings(SWGSDRangel::SWGChannelSettings& resp response.getVorDemodSettings()->setReverseApiPort(settings.m_reverseAPIPort); response.getVorDemodSettings()->setReverseApiDeviceIndex(settings.m_reverseAPIDeviceIndex); response.getVorDemodSettings()->setReverseApiChannelIndex(settings.m_reverseAPIChannelIndex); - response.getVorDemodSettings()->setIdentThreshold(settings.m_identThreshold); - response.getVorDemodSettings()->setMagDecAdjust(settings.m_magDecAdjust ? 1 : 0); if (settings.m_channelMarker) { @@ -434,10 +525,26 @@ void VORDemod::webapiFormatChannelReport(SWGSDRangel::SWGChannelReport& response double magsqAvg, magsqPeak; int nbMagsqSamples; getMagSqLevels(magsqAvg, magsqPeak, nbMagsqSamples); - response.getVorDemodReport()->setChannelPowerDb(CalcDb::dbPower(magsqAvg)); response.getVorDemodReport()->setSquelch(m_basebandSink->getSquelchOpen() ? 1 : 0); response.getVorDemodReport()->setAudioSampleRate(m_basebandSink->getAudioSampleRate()); + response.getVorDemodReport()->setNavId(m_settings.m_navId); + response.getVorDemodReport()->setRadial(m_radial); + response.getVorDemodReport()->setRefMag(m_refMag); + response.getVorDemodReport()->setVarMag(m_varMag); + float refMagDB = std::round(20.0*std::log10(m_refMag)); + float varMagDB = std::round(20.0*std::log10(m_varMag)); + bool validRefMag = refMagDB > m_settings.m_refThresholdDB; + bool validVarMag = varMagDB > m_settings.m_varThresholdDB; + response.getVorDemodReport()->setValidRadial(validRefMag && validVarMag ? 1 : 0); + response.getVorDemodReport()->setValidRefMag(validRefMag ? 1 : 0); + response.getVorDemodReport()->setValidVarMag(validVarMag ? 1 : 0); + + if (response.getVorDemodReport()->getMorseIdent()) { + *response.getVorDemodReport()->getMorseIdent() = m_morseIdent; + } else { + response.getVorDemodReport()->setMorseIdent(new QString(m_morseIdent)); + } } void VORDemod::webapiReverseSendSettings(QList& channelSettingsKeys, const VORDemodSettings& settings, bool force) @@ -490,6 +597,25 @@ void VORDemod::sendChannelSettings( } } +void VORDemod::sendChannelReport(QList& messagePipes) +{ + for (const auto& pipe : messagePipes) + { + MessageQueue *messageQueue = qobject_cast(pipe->m_element); + + if (messageQueue) + { + SWGSDRangel::SWGChannelReport *swgChannelReport = new SWGSDRangel::SWGChannelReport(); + swgChannelReport->setDirection(0); + swgChannelReport->setChannelType(new QString(m_channelId)); + swgChannelReport->setVorDemodReport(new SWGSDRangel::SWGVORDemodReport()); + webapiFormatChannelReport(*swgChannelReport); + MainCore::MsgChannelReport *msg = MainCore::MsgChannelReport::create(this, swgChannelReport); + messageQueue->push(msg); + } + } +} + void VORDemod::webapiFormatChannelSettings( QList& channelSettingsKeys, SWGSDRangel::SWGChannelSettings *swgChannelSettings, @@ -506,6 +632,12 @@ void VORDemod::webapiFormatChannelSettings( // transfer data that has been modified. When force is on transfer all data except reverse API data + if (channelSettingsKeys.contains("inputFrequencyOffset") || force) { + swgVORDemodSettings->setInputFrequencyOffset(settings.m_inputFrequencyOffset); + } + if (channelSettingsKeys.contains("navId") || force) { + swgVORDemodSettings->setNavId(settings.m_navId); + } if (channelSettingsKeys.contains("audioMute") || force) { swgVORDemodSettings->setAudioMute(settings.m_audioMute ? 1 : 0); } @@ -528,10 +660,7 @@ void VORDemod::webapiFormatChannelSettings( swgVORDemodSettings->setStreamIndex(settings.m_streamIndex); } if (channelSettingsKeys.contains("identThreshold") || force) { - swgVORDemodSettings->setIdentThreshold(settings.m_identThreshold); - } - if (channelSettingsKeys.contains("magDecAdjust") || force) { - swgVORDemodSettings->setMagDecAdjust(settings.m_magDecAdjust ? 1 : 0); + swgVORDemodSettings->setAudioMute(settings.m_identThreshold); } if (settings.m_channelMarker && (channelSettingsKeys.contains("channelMarker") || force)) @@ -581,4 +710,5 @@ void VORDemod::handleIndexInDeviceSetChanged(int index) .arg(m_deviceAPI->getDeviceSetIndex()) .arg(index); m_basebandSink->setFifoLabel(fifoLabel); + m_basebandSink->setAudioFifoLabel(fifoLabel); } diff --git a/plugins/channelrx/demodvor/vordemod.h b/plugins/channelrx/demodvor/vordemod.h index 8ffd638da..ec4e51a61 100644 --- a/plugins/channelrx/demodvor/vordemod.h +++ b/plugins/channelrx/demodvor/vordemod.h @@ -16,8 +16,8 @@ // along with this program. If not, see . // /////////////////////////////////////////////////////////////////////////////////// -#ifndef INCLUDE_VORDEMOD_H -#define INCLUDE_VORDEMOD_H +#ifndef INCLUDE_VORDEMODSC_H +#define INCLUDE_VORDEMODSC_H #include @@ -65,6 +65,8 @@ public: VORDemod(DeviceAPI *deviceAPI); virtual ~VORDemod(); virtual void destroy() { delete this; } + virtual void setDeviceAPI(DeviceAPI *deviceAPI); + virtual DeviceAPI *getDeviceAPI() { return m_deviceAPI; } using BasebandSampleSink::feed; virtual void feed(const SampleVector::const_iterator& begin, const SampleVector::const_iterator& end, bool po); @@ -77,8 +79,8 @@ public: virtual QString getIdentifier() const { return objectName(); } virtual const QString& getURI() const { return getName(); } virtual void getTitle(QString& title) { title = m_settings.m_title; } - virtual qint64 getCenterFrequency() const { return 0; } - virtual void setCenterFrequency(qint64) {} + virtual qint64 getCenterFrequency() const { return m_settings.m_inputFrequencyOffset; } + virtual void setCenterFrequency(qint64 frequency); virtual QByteArray serialize() const; virtual bool deserialize(const QByteArray& data); @@ -97,6 +99,10 @@ public: SWGSDRangel::SWGChannelSettings& response, QString& errorMessage); + virtual int webapiWorkspaceGet( + SWGSDRangel::SWGWorkspaceInfo& response, + QString& errorMessage); + virtual int webapiSettingsPutPatch( bool force, const QStringList& channelSettingsKeys, @@ -123,10 +129,6 @@ public: void getMagSqLevels(double& avg, double& peak, int& nbSamples) { m_basebandSink->getMagSqLevels(avg, peak, nbSamples); } - void setMessageQueueToGUI(MessageQueue* queue) override { - ChannelAPI::setMessageQueueToGUI(queue); - m_basebandSink->setMessageQueueToGUI(queue); - } uint32_t getNumberOfDeviceStreams() const; @@ -141,6 +143,11 @@ private: int m_basebandSampleRate; //!< stored from device message used when starting baseband sink qint64 m_centerFrequency; + float m_radial; //!< current detected radial + float m_refMag; //!< current reference signal magnitude + float m_varMag; //!< current variable signal magnitude + QString m_morseIdent; //!< identification morse code transcript + QNetworkAccessManager *m_networkManager; QNetworkRequest m_networkRequest; @@ -154,6 +161,7 @@ private: const VORDemodSettings& settings, bool force ); + void sendChannelReport(QList& messagePipes); void webapiFormatChannelSettings( QList& channelSettingsKeys, SWGSDRangel::SWGChannelSettings *swgChannelSettings, @@ -166,4 +174,4 @@ private slots: void handleIndexInDeviceSetChanged(int index); }; -#endif // INCLUDE_VORDEMOD_H +#endif // INCLUDE_VORDEMODSC_H diff --git a/plugins/channelrx/demodvor/vordemodbaseband.cpp b/plugins/channelrx/demodvor/vordemodbaseband.cpp index 41911eb34..a7daed5c3 100644 --- a/plugins/channelrx/demodvor/vordemodbaseband.cpp +++ b/plugins/channelrx/demodvor/vordemodbaseband.cpp @@ -28,36 +28,24 @@ MESSAGE_CLASS_DEFINITION(VORDemodBaseband::MsgConfigureVORDemodBaseband, Message) VORDemodBaseband::VORDemodBaseband() : - m_running(false), - m_mutex(QMutex::Recursive), m_messageQueueToGUI(nullptr), - m_basebandSampleRate(0) + m_running(false), + m_mutex(QMutex::Recursive) { qDebug("VORDemodBaseband::VORDemodBaseband"); - m_sampleFifo.setSize(SampleSinkFifo::getSizePolicy(48000)); + m_channelizer = new DownChannelizer(&m_sink); - // FIXME: If we remove this audio stops working when this demod is closed - DSPEngine::instance()->getAudioDeviceManager()->addAudioSink(&m_audioFifoBug, getInputMessageQueue()); + DSPEngine::instance()->getAudioDeviceManager()->addAudioSink(m_sink.getAudioFifo(), getInputMessageQueue()); + m_sink.applyAudioSampleRate(DSPEngine::instance()->getAudioDeviceManager()->getOutputSampleRate()); + m_channelSampleRate = 0; } VORDemodBaseband::~VORDemodBaseband() { m_inputMessageQueue.clear(); - - for (int i = 0; i < m_sinks.size(); i++) - { - DSPEngine::instance()->getAudioDeviceManager()->removeAudioSink(m_sinks[i]->getAudioFifo()); - delete m_sinks[i]; - } - m_sinks.clear(); - - // FIXME: If we remove this audio stops working when this demod is closed - DSPEngine::instance()->getAudioDeviceManager()->removeAudioSink(&m_audioFifoBug); - - for (int i = 0; i < m_channelizers.size(); i++) - delete m_channelizers[i]; - m_channelizers.clear(); + DSPEngine::instance()->getAudioDeviceManager()->removeAudioSink(m_sink.getAudioFifo()); + delete m_channelizer; } void VORDemodBaseband::reset() @@ -65,6 +53,7 @@ void VORDemodBaseband::reset() QMutexLocker mutexLocker(&m_mutex); m_inputMessageQueue.clear(); m_sampleFifo.reset(); + m_channelSampleRate = 0; } void VORDemodBaseband::startWork() @@ -114,14 +103,12 @@ void VORDemodBaseband::handleData() // first part of FIFO data if (part1begin != part1end) { - for (int i = 0; i < m_channelizers.size(); i++) - m_channelizers[i]->feed(part1begin, part1end); + m_channelizer->feed(part1begin, part1end); } // second part of FIFO data (used when block wraps around) if(part2begin != part2end) { - for (int i = 0; i < m_channelizers.size(); i++) - m_channelizers[i]->feed(part2begin, part2end); + m_channelizer->feed(part2begin, part2end); } m_sampleFifo.readCommit((unsigned int) count); @@ -157,9 +144,15 @@ bool VORDemodBaseband::handleMessage(const Message& cmd) QMutexLocker mutexLocker(&m_mutex); DSPSignalNotification& notif = (DSPSignalNotification&) cmd; qDebug() << "VORDemodBaseband::handleMessage: DSPSignalNotification: basebandSampleRate: " << notif.getSampleRate() << " centerFrequency: " << notif.getCenterFrequency(); - m_centerFrequency = notif.getCenterFrequency(); - setBasebandSampleRate(notif.getSampleRate()); - m_sampleFifo.setSize(SampleSinkFifo::getSizePolicy(m_basebandSampleRate)); + m_sampleFifo.setSize(SampleSinkFifo::getSizePolicy(notif.getSampleRate())); + m_channelizer->setBasebandSampleRate(notif.getSampleRate()); + m_sink.applyChannelSettings(m_channelizer->getChannelSampleRate(), m_channelizer->getChannelFrequencyOffset()); + + if (m_channelSampleRate != m_channelizer->getChannelSampleRate()) + { + m_sink.applyAudioSampleRate(m_sink.getAudioSampleRate()); // reapply when channel sample rate changes + m_channelSampleRate = m_channelizer->getChannelSampleRate(); + } return true; } @@ -169,80 +162,17 @@ bool VORDemodBaseband::handleMessage(const Message& cmd) } } -// Calculate offset of VOR center frequency from sample source center frequency -void VORDemodBaseband::calculateOffset(VORDemodSink *sink) -{ - int frequencyOffset = sink->m_vorFrequencyHz - m_centerFrequency; - bool outOfBand = std::abs(frequencyOffset)+VORDEMOD_CHANNEL_BANDWIDTH > (m_basebandSampleRate/2); - - if (m_messageQueueToGUI != nullptr) - { - VORDemodReport::MsgReportFreqOffset *msg = VORDemodReport::MsgReportFreqOffset::create(sink->m_subChannelId, frequencyOffset, outOfBand); - m_messageQueueToGUI->push(msg); - } - - sink->m_frequencyOffset = frequencyOffset; - sink->m_outOfBand = outOfBand; -} - void VORDemodBaseband::applySettings(const VORDemodSettings& settings, bool force) { - // Remove sub-channels no longer needed - for (int i = 0; i < m_sinks.size(); i++) + if ((settings.m_inputFrequencyOffset != m_settings.m_inputFrequencyOffset) || force) { - if (!settings.m_subChannelSettings.contains(m_sinks[i]->m_subChannelId)) + m_channelizer->setChannelization(m_sink.getAudioSampleRate(), settings.m_inputFrequencyOffset); + m_sink.applyChannelSettings(m_channelizer->getChannelSampleRate(), m_channelizer->getChannelFrequencyOffset()); + + if (m_channelSampleRate != m_channelizer->getChannelSampleRate()) { - qDebug() << "VORDemodBaseband::applySettings: Removing sink " << m_sinks[i]->m_subChannelId; - VORDemodSink *sink = m_sinks[i]; - DSPEngine::instance()->getAudioDeviceManager()->removeAudioSink(m_sinks[i]->getAudioFifo()); - m_sinks.removeAt(i); - delete sink; - DownChannelizer *channelizer = m_channelizers[i]; - m_channelizers.removeAt(i); - delete channelizer; - } - } - - // Add new sub channels - QHash::const_iterator itr = settings.m_subChannelSettings.begin(); - while (itr != settings.m_subChannelSettings.end()) - { - VORDemodSubChannelSettings *subChannelSettings = itr.value(); - int j; - for (j = 0; j < m_sinks.size(); j++) - { - if (subChannelSettings->m_id == m_sinks[j]->m_subChannelId) - break; - } - if (j == m_sinks.size()) - { - // Add a sub-channel sink - qDebug() << "VORDemodBaseband::applySettings: Adding sink " << subChannelSettings->m_id; - VORDemodSink *sink = new VORDemodSink(settings, subChannelSettings->m_id, m_messageQueueToGUI); - DownChannelizer *channelizer = new DownChannelizer(sink); - channelizer->setBasebandSampleRate(m_basebandSampleRate); - DSPEngine::instance()->getAudioDeviceManager()->addAudioSink(sink->getAudioFifo(), getInputMessageQueue()); - sink->applyAudioSampleRate(DSPEngine::instance()->getAudioDeviceManager()->getOutputSampleRate()); - - m_sinks.append(sink); - m_channelizers.append(channelizer); - - calculateOffset(sink); - - channelizer->setChannelization(VORDEMOD_CHANNEL_SAMPLE_RATE, sink->m_frequencyOffset); - sink->applyChannelSettings(channelizer->getChannelSampleRate(), channelizer->getChannelFrequencyOffset(), true); - sink->applyAudioSampleRate(sink->getAudioSampleRate()); - } - ++itr; - } - - if (force) - { - for (int i = 0; i < m_sinks.size(); i++) - { - m_channelizers[i]->setChannelization(VORDEMOD_CHANNEL_SAMPLE_RATE, m_sinks[i]->m_frequencyOffset); - m_sinks[i]->applyChannelSettings(m_channelizers[i]->getChannelSampleRate(), m_channelizers[i]->getChannelFrequencyOffset()); - m_sinks[i]->applyAudioSampleRate(m_sinks[i]->getAudioSampleRate()); // reapply in case of channel sample rate change + m_sink.applyAudioSampleRate(m_sink.getAudioSampleRate()); // reapply when channel sample rate changes + m_channelSampleRate = m_channelizer->getChannelSampleRate(); } } @@ -250,33 +180,20 @@ void VORDemodBaseband::applySettings(const VORDemodSettings& settings, bool forc { AudioDeviceManager *audioDeviceManager = DSPEngine::instance()->getAudioDeviceManager(); int audioDeviceIndex = audioDeviceManager->getOutputDeviceIndex(settings.m_audioDeviceName); - for (int i = 0; i < m_sinks.size(); i++) - { - audioDeviceManager->removeAudioSink(m_sinks[i]->getAudioFifo()); - audioDeviceManager->addAudioSink(m_sinks[i]->getAudioFifo(), getInputMessageQueue(), audioDeviceIndex); - int audioSampleRate = audioDeviceManager->getOutputSampleRate(audioDeviceIndex); + //qDebug("AMDemod::applySettings: audioDeviceName: %s audioDeviceIndex: %d", qPrintable(settings.m_audioDeviceName), audioDeviceIndex); + audioDeviceManager->removeAudioSink(m_sink.getAudioFifo()); + audioDeviceManager->addAudioSink(m_sink.getAudioFifo(), getInputMessageQueue(), audioDeviceIndex); + int audioSampleRate = audioDeviceManager->getOutputSampleRate(audioDeviceIndex); - if (m_sinks[i]->getAudioSampleRate() != audioSampleRate) - { - m_sinks[i]->applyAudioSampleRate(audioSampleRate); - } + if (m_sink.getAudioSampleRate() != audioSampleRate) + { + m_channelizer->setChannelization(audioSampleRate, settings.m_inputFrequencyOffset); + m_sink.applyChannelSettings(m_channelizer->getChannelSampleRate(), m_channelizer->getChannelFrequencyOffset()); + m_sink.applyAudioSampleRate(audioSampleRate); } } - for (int i = 0; i < m_sinks.size(); i++) - m_sinks[i]->applySettings(settings, force); + m_sink.applySettings(settings, force); m_settings = settings; } - -void VORDemodBaseband::setBasebandSampleRate(int sampleRate) -{ - m_basebandSampleRate = sampleRate; - for (int i = 0; i < m_sinks.size(); i++) - { - m_channelizers[i]->setBasebandSampleRate(sampleRate); - calculateOffset(m_sinks[i]); - m_sinks[i]->applyChannelSettings(m_channelizers[i]->getChannelSampleRate(), m_channelizers[i]->getChannelFrequencyOffset()); - m_sinks[i]->applyAudioSampleRate(m_sinks[i]->getAudioSampleRate()); // reapply in case of channel sample rate change - } -} diff --git a/plugins/channelrx/demodvor/vordemodbaseband.h b/plugins/channelrx/demodvor/vordemodbaseband.h index 5dad65a95..39c2f37af 100644 --- a/plugins/channelrx/demodvor/vordemodbaseband.h +++ b/plugins/channelrx/demodvor/vordemodbaseband.h @@ -16,8 +16,8 @@ // along with this program. If not, see . // /////////////////////////////////////////////////////////////////////////////////// -#ifndef INCLUDE_VORDEMODBASEBAND_H -#define INCLUDE_VORDEMODBASEBAND_H +#ifndef INCLUDE_VORDEMODSCBASEBAND_H +#define INCLUDE_VORDEMODSCBASEBAND_H #include #include @@ -64,69 +64,27 @@ public: void stopWork(); void feed(const SampleVector::const_iterator& begin, const SampleVector::const_iterator& end); MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; } //!< Get the queue for asynchronous inbound communication - void getMagSqLevels(double& avg, double& peak, int& nbSamples) { - avg = 0.0; - peak = 0.0; - nbSamples = 0; - for (int i = 0; i < m_sinks.size(); i++) - { - double avg1, peak1; - int nbSamples1; - m_sinks[i]->getMagSqLevels(avg1, peak1, nbSamples1); - if (avg1 > avg) - { - avg = avg1; - nbSamples = nbSamples1; - } - avg += avg1; - if (peak1 > peak) - peak = peak1; - } - } - void setMessageQueueToGUI(MessageQueue *messageQueue) { - m_messageQueueToGUI = messageQueue; - for (int i = 0; i < m_sinks.size(); i++) - m_sinks[i]->setMessageQueueToGUI(messageQueue); - } - bool getSquelchOpen() const { - for (int i = 0; i < m_sinks.size(); i++) - { - if (m_sinks[i]->getSquelchOpen()) - return true; - } - return false; - } - int getAudioSampleRate() const { - if (m_sinks.size() > 0) - return m_sinks[0]->getAudioSampleRate(); - else - return 48000; - } - void setBasebandSampleRate(int sampleRate); - double getMagSq() const { - if (m_sinks.size() > 0) - return m_sinks[0]->getMagSq(); - else - return 0.0; - } + void getMagSqLevels(double& avg, double& peak, int& nbSamples) { m_sink.getMagSqLevels(avg, peak, nbSamples); } + void setMessageQueueToChannel(MessageQueue *messageQueue) { m_sink.setMessageQueueToChannel(messageQueue); } + bool getSquelchOpen() const { return m_sink.getSquelchOpen(); } + int getAudioSampleRate() const { return m_sink.getAudioSampleRate(); } + double getMagSq() const { return m_sink.getMagSq(); } bool isRunning() const { return m_running; } void setFifoLabel(const QString& label) { m_sampleFifo.setLabel(label); } + void setAudioFifoLabel(const QString& label) { m_sink.setAudioFifoLabel(label); } private: SampleSinkFifo m_sampleFifo; - QList m_channelizers; - QList m_sinks; - AudioFifo m_audioFifoBug; // FIXME: Removing this results in audio stopping when demod is closed + DownChannelizer * m_channelizer; + int m_channelSampleRate; + VORDemodSCSink m_sink; MessageQueue m_inputMessageQueue; //!< Queue for asynchronous inbound communication VORDemodSettings m_settings; + MessageQueue *m_messageQueueToGUI; bool m_running; QMutex m_mutex; - MessageQueue *m_messageQueueToGUI; - int m_basebandSampleRate; - int m_centerFrequency; bool handleMessage(const Message& cmd); - void calculateOffset(VORDemodSink *sink); void applySettings(const VORDemodSettings& settings, bool force = false); private slots: @@ -134,4 +92,4 @@ private slots: void handleData(); //!< Handle data when samples have to be processed }; -#endif // INCLUDE_VORDEMODBASEBAND_H +#endif // INCLUDE_VORDEMODSCBASEBAND_H diff --git a/plugins/channelrx/demodvor/vordemodgui.cpp b/plugins/channelrx/demodvor/vordemodgui.cpp index 6cf3bec8a..30835d686 100644 --- a/plugins/channelrx/demodvor/vordemodgui.cpp +++ b/plugins/channelrx/demodvor/vordemodgui.cpp @@ -17,22 +17,14 @@ /////////////////////////////////////////////////////////////////////////////////// #include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "vordemodgui.h" +#include +#include #include "device/deviceuiset.h" #include "dsp/dspengine.h" #include "dsp/dspcommands.h" -#include "ui_vordemodgui.h" +#include "dsp/dspengine.h" #include "plugin/pluginapi.h" #include "util/simpleserializer.h" #include "util/db.h" @@ -40,679 +32,15 @@ #include "util/units.h" #include "gui/basicchannelsettingsdialog.h" #include "gui/devicestreamselectiondialog.h" -#include "dsp/dspengine.h" #include "gui/crightclickenabler.h" #include "gui/audioselectdialog.h" #include "channel/channelwebapiutils.h" #include "maincore.h" +#include "ui_vordemodgui.h" #include "vordemod.h" #include "vordemodreport.h" -#include "vordemodsink.h" - -#define VOR_COL_NAME 0 -#define VOR_COL_FREQUENCY 1 -#define VOR_COL_OFFSET 2 -#define VOR_COL_IDENT 3 -#define VOR_COL_MORSE 4 -#define VOR_COL_RX_IDENT 5 -#define VOR_COL_RX_MORSE 6 -#define VOR_COL_RADIAL 7 -#define VOR_COL_REF_MAG 8 -#define VOR_COL_VAR_MAG 9 -#define VOR_COL_MUTE 10 - -static const char *countryCodes[] = { - "ad", - "ae", - "af", - "ag", - "ai", - "al", - "am", - "an", - "ao", - "aq", - "ar", - "as", - "at", - "au", - "aw", - "ax", - "az", - "ba", - "bb", - "bd", - "be", - "bf", - "bg", - "bh", - "bi", - "bj", - "bl", - "bm", - "bn", - "bo", - "bq", - "br", - "bs", - "bt", - "bv", - "bw", - "by", - "bz", - "ca", - "cc", - "cd", - "cf", - "cg", - "ch", - "ci", - "ck", - "cl", - "cm", - "cn", - "co", - "cr", - "cu", - "cv", - "cw", - "cx", - "cy", - "cz", - "de", - "dj", - "dk", - "dm", - "do", - "dz", - "ec", - "ee", - "eg", - "eh", - "er", - "es", - "et", - "fi", - "fj", - "fk", - "fm", - "fo", - "fr", - "ga", - "gb", - "ge", - "gf", - "gg", - "gh", - "gi", - "gl", - "gm", - "gn", - "gp", - "gq", - "gr", - "gs", - "gt", - "gu", - "gw", - "gy", - "hk", - "hm", - "hn", - "hr", - "hu", - "id", - "ie", - "il", - "im", - "in", - "io", - "iq", - "ir", - "is", - "it", - "je", - "jm", - "jo", - "jp", - "ke", - "kg", - "kh", - "ki", - "km", - "kn", - "kp", - "kr", - "kw", - "ky", - "kz", - "la", - "lb", - "lc", - "li", - "lk", - "lr", - "ls", - "lt", - "lu", - "lv", - "ly", - "ma", - "mc", - "md", - "me", - "mf", - "mg", - "mh", - "mk", - "ml", - "mm", - "mn", - "mo", - "mp", - "mq", - "mr", - "ms", - "mt", - "mu", - "mv", - "mw", - "mx", - "my", - "mz", - "na", - "nc", - "ne", - "nf", - "ng", - "ni", - "nl", - "no", - "np", - "nr", - "nu", - "nz", - "om", - "pa", - "pe", - "pf", - "pg", - "ph", - "pk", - "pl", - "pm", - "pn", - "pr", - "ps", - "pt", - "pw", - "py", - "qa", - "re", - "ro", - "rs", - "ru", - "rw", - "sa", - "sb", - "sc", - "sd", - "se", - "sg", - "sh", - "si", - "sj", - "sk", - "sl", - "sm", - "sn", - "so", - "sr", - "ss", - "st", - "sv", - "sx", - "sy", - "sz", - "tc", - "td", - "tf", - "tg", - "th", - "tj", - "tk", - "tl", - "tm", - "tn", - "to", - "tr", - "tt", - "tv", - "tw", - "tz", - "ua", - "ug", - "um", - "us", - "uy", - "uz", - "va", - "vc", - "ve", - "vg", - "vi", - "vn", - "vu", - "wf", - "ws", - "ye", - "yt", - "za", - "zm", - "zw", - nullptr -}; - -// Lats and longs in decimal degrees. Distance in metres. Bearing in degrees. -// https://www.movable-type.co.uk/scripts/latlong.html -static void calcRadialEndPoint(float startLatitude, float startLongitude, float distance, float bearing, float &endLatitude, float &endLongitude) -{ - double startLatRad = startLatitude*M_PI/180.0; - double startLongRad = startLongitude*M_PI/180.0; - double theta = bearing*M_PI/180.0; - double earthRadius = 6378137.0; // At equator - double delta = distance/earthRadius; - double endLatRad = std::asin(sin(startLatRad)*cos(delta) + cos(startLatRad)*sin(delta)*cos(theta)); - double endLongRad = startLongRad + std::atan2(sin(theta)*sin(delta)*cos(startLatRad), cos(delta) - sin(startLatRad)*sin(endLatRad)); - endLatitude = endLatRad*180.0/M_PI; - endLongitude = endLongRad*180.0/M_PI; -} - -// Calculate intersection point along two radials -// https://www.movable-type.co.uk/scripts/latlong.html -static bool calcIntersectionPoint(float lat1, float lon1, float bearing1, float lat2, float lon2, float bearing2, float &intersectLat, float &intersectLon) -{ - - double lat1Rad = Units::degreesToRadians(lat1); - double lon1Rad = Units::degreesToRadians(lon1); - double lat2Rad = Units::degreesToRadians(lat2); - double lon2Rad = Units::degreesToRadians(lon2); - double theta13 = Units::degreesToRadians(bearing1); - double theta23 = Units::degreesToRadians(bearing2); - - double deltaLat = lat1Rad - lat2Rad; - double deltaLon = lon1Rad - lon2Rad; - double sindlat = sin(deltaLat/2.0); - double sindlon = sin(deltaLon/2.0); - double cosLat1 = cos(lat1Rad); - double cosLat2 = cos(lat2Rad); - double delta12 = 2.0 * asin(sqrt(sindlat*sindlat+cosLat1*cosLat2*sindlon*sindlon)); - if (abs(delta12) < std::numeric_limits::epsilon()) - return false; - - double sinLat1 = sin(lat1Rad); - double sinLat2 = sin(lat2Rad); - double sinDelta12 = sin(delta12); - double cosDelta12 = cos(delta12); - double thetaA = acos((sinLat2-sinLat1*cosDelta12)/(sinDelta12*cosLat1)); - double thetaB = acos((sinLat1-sinLat2*cosDelta12)/(sinDelta12*cosLat2)); - - double theta12, theta21; - if (sin(lon2Rad-lon1Rad) > 0.0) - { - theta12 = thetaA; - theta21 = 2.0*M_PI-thetaB; - } - else - { - theta12 = 2.0*M_PI-thetaA; - theta21 = thetaB; - } - double alpha1 = theta13 - theta12; - double alpha2 = theta21 - theta23; - double sinAlpha1 = sin(alpha1); - double sinAlpha2 = sin(alpha2); - if ((sinAlpha1 == 0.0) && (sinAlpha2 == 0.0)) - return false; - if (sinAlpha1*sinAlpha2 < 0.0) - return false; - double cosAlpha1 = cos(alpha1); - double cosAlpha2 = cos(alpha2); - double cosAlpha3 = -cosAlpha1*cosAlpha2+sinAlpha1*sinAlpha2*cos(delta12); - double delta13 = atan2(sin(delta12)*sinAlpha1*sinAlpha2, cosAlpha2+cosAlpha1*cosAlpha3); - double lat3Rad = asin(sinLat1*cos(delta13)+cosLat1*sin(delta13)*cos(theta13)); - double lon3Rad = lon1Rad + atan2(sin(theta13)*sin(delta13)*cosLat1, cos(delta13)-sinLat1*sin(lat3Rad)); - - intersectLat = Units::radiansToDegrees(lat3Rad); - intersectLon = Units::radiansToDegrees(lon3Rad); - - return true; -} - -VORGUI::VORGUI(NavAid *navAid, VORDemodGUI *gui) : - m_navAid(navAid), - m_gui(gui) -{ - // These are deleted by QTableWidget - m_nameItem = new QTableWidgetItem(); - m_frequencyItem = new QTableWidgetItem(); - m_offsetItem = new QTableWidgetItem(); - m_radialItem = new QTableWidgetItem(); - m_identItem = new QTableWidgetItem(); - m_morseItem = new QTableWidgetItem(); - m_rxIdentItem = new QTableWidgetItem(); - m_rxMorseItem = new QTableWidgetItem(); - m_varMagItem = new QTableWidgetItem(); - m_refMagItem = new QTableWidgetItem(); - - m_muteItem = new QWidget(); - - m_muteButton = new QToolButton(); - m_muteButton->setCheckable(true); - m_muteButton->setChecked(false); - m_muteButton->setToolTip("Mute/unmute audio from this VOR"); - m_muteButton->setIcon(m_gui->m_muteIcon); - - QHBoxLayout* pLayout = new QHBoxLayout(m_muteItem); - pLayout->addWidget(m_muteButton); - pLayout->setAlignment(Qt::AlignCenter); - pLayout->setContentsMargins(0, 0, 0, 0); - m_muteItem->setLayout(pLayout); - - connect(m_muteButton, &QPushButton::toggled, this, &VORGUI::on_audioMute_toggled); - - m_coordinates.push_back(QVariant::fromValue(*new QGeoCoordinate(m_navAid->m_latitude, m_navAid->m_longitude, Units::feetToMetres(m_navAid->m_elevation)))); -} - -void VORGUI::on_audioMute_toggled(bool checked) -{ - m_gui->m_settings.m_subChannelSettings.value(m_navAid->m_id)->m_audioMute = checked; - m_gui->applySettings(); -} - -QVariant VORModel::data(const QModelIndex &index, int role) const -{ - int row = index.row(); - if ((row < 0) || (row >= m_vors.count())) - return QVariant(); - if (role == VORModel::positionRole) - { - // Coordinates to display the VOR icon at - QGeoCoordinate coords; - coords.setLatitude(m_vors[row]->m_latitude); - coords.setLongitude(m_vors[row]->m_longitude); - coords.setAltitude(Units::feetToMetres(m_vors[row]->m_elevation)); - return QVariant::fromValue(coords); - } - else if (role == VORModel::vorDataRole) - { - // Create the text to go in the bubble next to the VOR - QStringList list; - list.append(QString("Name: %1").arg(m_vors[row]->m_name)); - list.append(QString("Frequency: %1 MHz").arg(m_vors[row]->m_frequencykHz / 1000.0f, 0, 'f', 1)); - if (m_vors[row]->m_channel != "") - list.append(QString("Channel: %1").arg(m_vors[row]->m_channel)); - list.append(QString("Ident: %1 %2").arg(m_vors[row]->m_ident).arg(Morse::toSpacedUnicodeMorse(m_vors[row]->m_ident))); - list.append(QString("Range: %1 nm").arg(m_vors[row]->m_range)); - if (m_vors[row]->m_alignedTrueNorth) - list.append(QString("Magnetic declination: Aligned to true North")); - else if (m_vors[row]->m_magneticDeclination != 0.0f) - list.append(QString("Magnetic declination: %1%2").arg(std::round(m_vors[row]->m_magneticDeclination)).arg(QChar(0x00b0))); - QString data = list.join("\n"); - return QVariant::fromValue(data); - } - else if (role == VORModel::vorImageRole) - { - // Select an image to use for the VOR - return QVariant::fromValue(QString("/demodvor/map/%1.png").arg(m_vors[row]->m_type)); - } - else if (role == VORModel::bubbleColourRole) - { - // Select a background colour for the text bubble next to the VOR - if (m_selected[row]) - return QVariant::fromValue(QColor("lightgreen")); - else - return QVariant::fromValue(QColor("lightblue")); - } - else if (role == VORModel::vorRadialRole) - { - // Draw a radial line from centre of VOR outwards at the demodulated angle - if (m_radialsVisible && m_selected[row] && (m_vorGUIs[row] != nullptr) && (m_radials[row] != -1.0f)) - { - QVariantList list; - - list.push_back(m_vorGUIs[row]->m_coordinates[0]); // Centre of VOR - - float endLat, endLong; - float bearing; - if (m_gui->m_settings.m_magDecAdjust && !m_vors[row]->m_alignedTrueNorth) - bearing = m_radials[row] - m_vors[row]->m_magneticDeclination; - else - bearing = m_radials[row]; - calcRadialEndPoint(m_vors[row]->m_latitude, m_vors[row]->m_longitude, m_vors[row]->getRangeMetres(), bearing, endLat, endLong); - list.push_back(QVariant::fromValue(*new QGeoCoordinate(endLat, endLong, Units::feetToMetres(m_vors[row]->m_elevation)))); - - return list; - } - else - return QVariantList(); - } - else if (role == VORModel::selectedRole) - return QVariant::fromValue(m_selected[row]); - return QVariant(); -} - -bool VORModel::setData(const QModelIndex &index, const QVariant& value, int role) -{ - int row = index.row(); - if ((row < 0) || (row >= m_vors.count())) - return false; - if (role == VORModel::selectedRole) - { - bool selected = value.toBool(); - VORGUI *vorGUI; - if (selected == true) - { - vorGUI = new VORGUI(m_vors[row], m_gui); - m_vorGUIs[row] = vorGUI; - } - else - vorGUI = m_vorGUIs[row]; - m_gui->selectVOR(vorGUI, selected); - m_selected[row] = selected; - emit dataChanged(index, index); - if (!selected) - { - delete vorGUI; - m_vorGUIs[row] = nullptr; - } - return true; - } - return true; -} - -// Find intersection between first two selected radials -bool VORModel::findIntersection(float &lat, float &lon) -{ - if (m_vors.count() > 2) - { - float lat1, lon1, bearing1, valid1 = false; - float lat2, lon2, bearing2, valid2 = false; - - for (int i = 0; i < m_vors.count(); i++) - { - if (m_selected[i] && (m_radials[i] >= 0.0)) - { - if (!valid1) - { - lat1 = m_vors[i]->m_latitude; - lon1 = m_vors[i]->m_longitude; - if (m_gui->m_settings.m_magDecAdjust && !m_vors[i]->m_alignedTrueNorth) - bearing1 = m_radials[i] - m_vors[i]->m_magneticDeclination; - else - bearing1 = m_radials[i]; - valid1 = true; - } - else - { - lat2 = m_vors[i]->m_latitude; - lon2 = m_vors[i]->m_longitude; - if (m_gui->m_settings.m_magDecAdjust && !m_vors[i]->m_alignedTrueNorth) - bearing2 = m_radials[i] - m_vors[i]->m_magneticDeclination; - else - bearing2 = m_radials[i]; - valid2 = true; - break; - } - } - } - - if (valid1 && valid2) - { - return calcIntersectionPoint(lat1, lon1, bearing1, lat2, lon2, bearing2, lat, lon); - } - } - - return false; -} - -void VORDemodGUI::resizeTable() -{ - // Fill table with a row of dummy data that will size the columns nicely - // Trailing spaces are for sort arrow - QString morse("---- ---- ----"); - int row = ui->vorData->rowCount(); - ui->vorData->setRowCount(row + 1); - ui->vorData->setItem(row, VOR_COL_NAME, new QTableWidgetItem("White Sulphur Springs")); - ui->vorData->setItem(row, VOR_COL_FREQUENCY, new QTableWidgetItem("Freq (MHz) ")); - ui->vorData->setItem(row, VOR_COL_OFFSET, new QTableWidgetItem("Offset (kHz) ")); - ui->vorData->setItem(row, VOR_COL_IDENT, new QTableWidgetItem("Ident ")); - ui->vorData->setItem(row, VOR_COL_MORSE, new QTableWidgetItem(Morse::toSpacedUnicode(morse))); - ui->vorData->setItem(row, VOR_COL_RADIAL, new QTableWidgetItem("Radial (o) ")); - ui->vorData->setItem(row, VOR_COL_RX_IDENT, new QTableWidgetItem("RX Ident ")); - ui->vorData->setItem(row, VOR_COL_RX_MORSE, new QTableWidgetItem(Morse::toSpacedUnicode(morse))); - ui->vorData->setItem(row, VOR_COL_VAR_MAG, new QTableWidgetItem("Var (dB) ")); - ui->vorData->setItem(row, VOR_COL_REF_MAG, new QTableWidgetItem("Ref (dB) ")); - ui->vorData->setItem(row, VOR_COL_MUTE, new QTableWidgetItem("Mute")); - ui->vorData->resizeColumnsToContents(); - ui->vorData->removeRow(row); -} - -// Columns in table reordered -void VORDemodGUI::vorData_sectionMoved(int logicalIndex, int oldVisualIndex, int newVisualIndex) -{ - (void) oldVisualIndex; - - m_settings.m_columnIndexes[logicalIndex] = newVisualIndex; -} - -// Column in table resized (when hidden size is 0) -void VORDemodGUI::vorData_sectionResized(int logicalIndex, int oldSize, int newSize) -{ - (void) oldSize; - - m_settings.m_columnSizes[logicalIndex] = newSize; -} - -// Right click in table header - show column select menu -void VORDemodGUI::columnSelectMenu(QPoint pos) -{ - menu->popup(ui->vorData->horizontalHeader()->viewport()->mapToGlobal(pos)); -} - -// Hide/show column when menu selected -void VORDemodGUI::columnSelectMenuChecked(bool checked) -{ - (void) checked; - - QAction* action = qobject_cast(sender()); - if (action != nullptr) - { - int idx = action->data().toInt(nullptr); - ui->vorData->setColumnHidden(idx, !action->isChecked()); - } -} - -// Create column select menu item -QAction *VORDemodGUI::createCheckableItem(QString &text, int idx, bool checked) -{ - QAction *action = new QAction(text, this); - action->setCheckable(true); - action->setChecked(checked); - action->setData(QVariant(idx)); - connect(action, SIGNAL(triggered()), this, SLOT(columnSelectMenuChecked())); - return action; -} - -// Called when a VOR is selected on the map -void VORDemodGUI::selectVOR(VORGUI *vorGUI, bool selected) -{ - if (selected) - { - m_selectedVORs.insert(vorGUI->m_navAid->m_id, vorGUI); - ui->vorData->setSortingEnabled(false); - int row = ui->vorData->rowCount(); - ui->vorData->setRowCount(row + 1); - ui->vorData->setItem(row, VOR_COL_NAME, vorGUI->m_nameItem); - ui->vorData->setItem(row, VOR_COL_FREQUENCY, vorGUI->m_frequencyItem); - ui->vorData->setItem(row, VOR_COL_OFFSET, vorGUI->m_offsetItem); - ui->vorData->setItem(row, VOR_COL_IDENT, vorGUI->m_identItem); - ui->vorData->setItem(row, VOR_COL_MORSE, vorGUI->m_morseItem); - ui->vorData->setItem(row, VOR_COL_RADIAL, vorGUI->m_radialItem); - ui->vorData->setItem(row, VOR_COL_RX_IDENT, vorGUI->m_rxIdentItem); - ui->vorData->setItem(row, VOR_COL_RX_MORSE, vorGUI->m_rxMorseItem); - ui->vorData->setItem(row, VOR_COL_VAR_MAG, vorGUI->m_varMagItem); - ui->vorData->setItem(row, VOR_COL_REF_MAG, vorGUI->m_refMagItem); - ui->vorData->setCellWidget(row, VOR_COL_MUTE, vorGUI->m_muteItem); - vorGUI->m_nameItem->setText(vorGUI->m_navAid->m_name); - vorGUI->m_identItem->setText(vorGUI->m_navAid->m_ident); - vorGUI->m_morseItem->setText(Morse::toSpacedUnicodeMorse(vorGUI->m_navAid->m_ident)); - vorGUI->m_frequencyItem->setData(Qt::DisplayRole, vorGUI->m_navAid->m_frequencykHz / 1000.0); - ui->vorData->setSortingEnabled(true); - - // Add to settings to create corresponding demodulator - VORDemodSubChannelSettings *subChannelSettings = new VORDemodSubChannelSettings(); - subChannelSettings->m_id = vorGUI->m_navAid->m_id; - subChannelSettings->m_frequency = vorGUI->m_navAid->m_frequencykHz * 1000; - subChannelSettings->m_audioMute = false; - m_settings.m_subChannelSettings.insert(vorGUI->m_navAid->m_id, subChannelSettings); - applySettings(); - } - else - { - m_selectedVORs.remove(vorGUI->m_navAid->m_id); - ui->vorData->removeRow(vorGUI->m_nameItem->row()); - // Remove from settings to remove corresponding demodulator - VORDemodSubChannelSettings *subChannelSettings = m_settings.m_subChannelSettings.value(vorGUI->m_navAid->m_id); - m_settings.m_subChannelSettings.remove(vorGUI->m_navAid->m_id); - delete subChannelSettings; - applySettings(); - } -} - -void VORDemodGUI::updateVORs() -{ - m_vorModel.removeAllVORs(); - QHash::iterator i = m_vors->begin(); - AzEl azEl = m_azEl; - - while (i != m_vors->end()) - { - NavAid *vor = i.value(); - - // Calculate distance to VOR from My Position - azEl.setTarget(vor->m_latitude, vor->m_longitude, Units::feetToMetres(vor->m_elevation)); - azEl.calculate(); - - // Only display VOR if in range - if (azEl.getDistance() <= 200000) - { - m_vorModel.addVOR(vor); - } - ++i; - } -} +#include "vordemodgui.h" VORDemodGUI* VORDemodGUI::create(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, BasebandSampleSink *rxChannel) { @@ -749,6 +77,14 @@ bool VORDemodGUI::deserialize(const QByteArray& data) } } +void VORDemodGUI::resizeEvent(QResizeEvent* size) +{ + int maxWidth = getRollupContents()->maximumWidth(); + int minHeight = getRollupContents()->minimumHeight() + getAdditionalHeight(); + resize(width() < maxWidth ? width() : maxWidth, minHeight); + size->accept(); +} + bool VORDemodGUI::handleMessage(const Message& message) { if (VORDemod::MsgConfigureVORDemod::match(message)) @@ -764,104 +100,72 @@ bool VORDemodGUI::handleMessage(const Message& message) else if (DSPSignalNotification::match(message)) { DSPSignalNotification& notif = (DSPSignalNotification&) message; + m_deviceCenterFrequency = notif.getCenterFrequency(); m_basebandSampleRate = notif.getSampleRate(); + ui->deltaFrequency->setValueRange(false, 7, -m_basebandSampleRate/2, m_basebandSampleRate/2); + ui->deltaFrequencyLabel->setToolTip(tr("Range %1 %L2 Hz").arg(QChar(0xB1)).arg(m_basebandSampleRate/2)); + updateAbsoluteCenterFrequency(); return true; } else if (VORDemodReport::MsgReportRadial::match(message)) { VORDemodReport::MsgReportRadial& report = (VORDemodReport::MsgReportRadial&) message; - int subChannelId = report.getSubChannelId(); - - VORGUI *vorGUI = m_selectedVORs.value(subChannelId); - - // Display radial and signal magnitudes in table + // Display radial and signal magnitudes Real varMagDB = std::round(20.0*std::log10(report.getVarMag())); Real refMagDB = std::round(20.0*std::log10(report.getRefMag())); bool validRadial = (refMagDB > m_settings.m_refThresholdDB) && (varMagDB > m_settings.m_varThresholdDB); - vorGUI->m_radialItem->setData(Qt::DisplayRole, std::round(report.getRadial())); - if (validRadial) - vorGUI->m_radialItem->setForeground(QBrush(Qt::white)); - else - vorGUI->m_radialItem->setForeground(QBrush(Qt::red)); + ui->radialText->setText(tr("%1°").arg(std::round(report.getRadial()))); - vorGUI->m_refMagItem->setData(Qt::DisplayRole, refMagDB); - if (refMagDB > m_settings.m_refThresholdDB) - vorGUI->m_refMagItem->setForeground(QBrush(Qt::white)); - else - vorGUI->m_refMagItem->setForeground(QBrush(Qt::red)); + if (validRadial) { + ui->radialText->setStyleSheet("QLabel { color: white }"); + } else { + ui->radialText->setStyleSheet("QLabel { color: red }"); + } - vorGUI->m_varMagItem->setData(Qt::DisplayRole, varMagDB); - if (varMagDB > m_settings.m_varThresholdDB) - vorGUI->m_varMagItem->setForeground(QBrush(Qt::white)); - else - vorGUI->m_varMagItem->setForeground(QBrush(Qt::red)); + ui->refText->setText(tr("%1 dB").arg(refMagDB)); - // Update radial on map - m_vorModel.setRadial(subChannelId, validRadial, report.getRadial()); + if (refMagDB > m_settings.m_refThresholdDB) { + ui->refText->setStyleSheet("QLabel { color: white }"); + } else { + ui->refText->setStyleSheet("QLabel { color: red }"); + } + + ui->varText->setText(tr("%1 dB").arg(varMagDB)); + + if (varMagDB > m_settings.m_varThresholdDB) { + ui->varText->setStyleSheet("QLabel { color: white }"); + } else { + ui->varText->setStyleSheet("QLabel { color: red }"); + } return true; } - else if (VORDemodReport::MsgReportFreqOffset::match(message)) - { - VORDemodReport::MsgReportFreqOffset& report = (VORDemodReport::MsgReportFreqOffset&) message; - int subChannelId = report.getSubChannelId(); - - VORGUI *vorGUI = m_selectedVORs.value(subChannelId); - - vorGUI->m_offsetItem->setData(Qt::DisplayRole, report.getFreqOffset() / 1000.0); - if (report.getOutOfBand()) - { - vorGUI->m_offsetItem->setForeground(QBrush(Qt::red)); - // Clear other fields as data is now invalid - vorGUI->m_radialItem->setText(""); - vorGUI->m_refMagItem->setText(""); - vorGUI->m_varMagItem->setText(""); - m_vorModel.setRadial(subChannelId, false, -1.0f); - } - else - vorGUI->m_offsetItem->setForeground(QBrush(Qt::white)); - } else if (VORDemodReport::MsgReportIdent::match(message)) { VORDemodReport::MsgReportIdent& report = (VORDemodReport::MsgReportIdent&) message; - int subChannelId = report.getSubChannelId(); - - VORGUI *vorGUI = m_selectedVORs.value(subChannelId); QString ident = report.getIdent(); - // Convert Morse to a string - QString identString = Morse::toString(ident); + QString identString = Morse::toString(ident); // Convert Morse to a string + + ui->identText->setText(identString); + ui->morseText->setText(Morse::toSpacedUnicode(ident)); + // Idents should only be two or three characters, so filter anything else // other than TEST which indicates a VOR is under maintainance (may also be TST) if (((identString.size() >= 2) && (identString.size() <= 3)) || (identString == "TEST")) { - vorGUI->m_rxIdentItem->setText(identString); - vorGUI->m_rxMorseItem->setText(Morse::toSpacedUnicode(ident)); - if (vorGUI->m_navAid->m_ident == identString) - { - // Set colour to green if matching expected ident - vorGUI->m_rxIdentItem->setForeground(QBrush(Qt::green)); - vorGUI->m_rxMorseItem->setForeground(QBrush(Qt::green)); - } - else - { - // Set colour to green if not matching expected ident - vorGUI->m_rxIdentItem->setForeground(QBrush(Qt::red)); - vorGUI->m_rxMorseItem->setForeground(QBrush(Qt::red)); - } + ui->identText->setStyleSheet("QLabel { color: white }"); + ui->morseText->setStyleSheet("QLabel { color: white }"); } else { - // Set yellow to indicate we've filtered something (unless red) - if (vorGUI->m_rxIdentItem->foreground().color() != Qt::red) - { - vorGUI->m_rxIdentItem->setForeground(QBrush(Qt::yellow)); - vorGUI->m_rxMorseItem->setForeground(QBrush(Qt::yellow)); - } + ui->identText->setStyleSheet("QLabel { color: yellow }"); + ui->morseText->setStyleSheet("QLabel { color: yellow }"); } + return true; } @@ -883,6 +187,9 @@ void VORDemodGUI::handleInputMessages() void VORDemodGUI::channelMarkerChangedByCursor() { + ui->deltaFrequency->setValue(m_channelMarker.getCenterFrequency()); + m_settings.m_inputFrequencyOffset = m_channelMarker.getCenterFrequency(); + applySettings(); } void VORDemodGUI::channelMarkerHighlightedByCursor() @@ -890,6 +197,14 @@ void VORDemodGUI::channelMarkerHighlightedByCursor() setHighlighted(m_channelMarker.getHighlighted()); } +void VORDemodGUI::on_deltaFrequency_changed(qint64 value) +{ + m_channelMarker.setCenterFrequency(value); + m_settings.m_inputFrequencyOffset = m_channelMarker.getCenterFrequency(); + updateAbsoluteCenterFrequency(); + applySettings(); +} + void VORDemodGUI::on_thresh_valueChanged(int value) { ui->threshText->setText(QString("%1").arg(value / 10.0, 0, 'f', 1)); @@ -917,195 +232,12 @@ void VORDemodGUI::on_audioMute_toggled(bool checked) applySettings(); } -qint64 VORDemodGUI::fileAgeInDays(QString filename) -{ - QFile file(filename); - if (file.exists()) - { - QDateTime modified = file.fileTime(QFileDevice::FileModificationTime); - if (modified.isValid()) - return modified.daysTo(QDateTime::currentDateTime()); - else - return -1; - } - return -1; -} - -bool VORDemodGUI::confirmDownload(QString filename) -{ - qint64 age = fileAgeInDays(filename); - if ((age == -1) || (age > 100)) - return true; - else - { - QMessageBox::StandardButton reply; - if (age == 0) - reply = QMessageBox::question(this, "Confirm download", "This file was last downloaded today. Are you sure you wish to redownload it?", QMessageBox::Yes|QMessageBox::No); - else if (age == 1) - reply = QMessageBox::question(this, "Confirm download", "This file was last downloaded yesterday. Are you sure you wish to redownload it?", QMessageBox::Yes|QMessageBox::No); - else - reply = QMessageBox::question(this, "Confirm download", QString("This file was last downloaded %1 days ago. Are you sure you wish to redownload this file?").arg(age), QMessageBox::Yes|QMessageBox::No); - return reply == QMessageBox::Yes; - } -} - -QString VORDemodGUI::getDataDir() -{ - // Get directory to store app data in - QStringList locations = QStandardPaths::standardLocations(QStandardPaths::AppDataLocation); - // First dir is writable - return locations[0]; -} - -QString VORDemodGUI::getOpenAIPVORDBFilename(int i) -{ - if (countryCodes[i] != nullptr) - return getDataDir() + "/" + countryCodes[i] + "_nav.aip"; - else - return ""; -} - -QString VORDemodGUI::getOpenAIPVORDBURL(int i) -{ - if (countryCodes[i] != nullptr) - return QString(OPENAIP_NAVAIDS_URL).arg(countryCodes[i]); - else - return ""; -} - -QString VORDemodGUI::getVORDBFilename() -{ - return getDataDir() + "/vorDatabase.csv"; -} - -void VORDemodGUI::updateDownloadProgress(qint64 bytesRead, qint64 totalBytes) -{ - if (m_progressDialog) - { - m_progressDialog->setMaximum(totalBytes); - m_progressDialog->setValue(bytesRead); - } -} - -void VORDemodGUI::downloadFinished(const QString& filename, bool success) -{ - bool closeDialog = true; - if (success) - { - if (filename == getVORDBFilename()) - { - m_vors = NavAid::readNavAidsDB(filename); - if (m_vors != nullptr) - updateVORs(); - } - else if (filename == getOpenAIPVORDBFilename(m_countryIndex)) - { - m_countryIndex++; - if (countryCodes[m_countryIndex] != nullptr) - { - QString vorDBFile = getOpenAIPVORDBFilename(m_countryIndex); - QString urlString = getOpenAIPVORDBURL(m_countryIndex); - QUrl dbURL(urlString); - m_progressDialog->setLabelText(QString("Downloading %1.").arg(urlString)); - m_progressDialog->setValue(m_countryIndex); - m_dlm.download(dbURL, vorDBFile); - closeDialog = false; - } - else - { - readNavAids(); - if (m_vors != nullptr) - updateVORs(); - } - } - else - { - qDebug() << "VORDemodGUI::downloadFinished: Unexpected filename: " << filename; - } - } - else - { - qDebug() << "VORDemodGUI::downloadFinished: Failed: " << filename; - QMessageBox::warning(this, "Download failed", QString("Failed to download %1").arg(filename)); - } - if (closeDialog && m_progressDialog) - { - m_progressDialog->close(); - delete m_progressDialog; - m_progressDialog = nullptr; - } -} - -void VORDemodGUI::on_getOurAirportsVORDB_clicked(bool checked) -{ - (void) checked; - - // Don't try to download while already in progress - if (m_progressDialog == nullptr) - { - QString vorDBFile = getVORDBFilename(); - if (confirmDownload(vorDBFile)) - { - // Download OurAirports navaid database to disk - QUrl dbURL(QString(OURAIRPORTS_NAVAIDS_URL)); - m_progressDialog = new QProgressDialog(this); - m_progressDialog->setCancelButton(nullptr); - m_progressDialog->setMinimumDuration(500); - m_progressDialog->setLabelText(QString("Downloading %1.").arg(OURAIRPORTS_NAVAIDS_URL)); - QNetworkReply *reply = m_dlm.download(dbURL, vorDBFile); - connect(reply, SIGNAL(downloadProgress(qint64,qint64)), this, SLOT(updateDownloadProgress(qint64,qint64))); - } - } -} - -void VORDemodGUI::on_getOpenAIPVORDB_clicked(bool checked) -{ - (void) checked; - - // Don't try to download while already in progress - if (m_progressDialog == nullptr) - { - m_countryIndex = 0; - QString vorDBFile = getOpenAIPVORDBFilename(m_countryIndex); - if (confirmDownload(vorDBFile)) - { - // Download OpenAIP XML to disk - QString urlString = getOpenAIPVORDBURL(m_countryIndex); - QUrl dbURL(urlString); - m_progressDialog = new QProgressDialog(this); - m_progressDialog->setCancelButton(nullptr); - m_progressDialog->setMinimumDuration(500); - m_progressDialog->setMaximum(sizeof(countryCodes)/sizeof(countryCodes[0])); - m_progressDialog->setValue(0); - m_progressDialog->setLabelText(QString("Downloading %1.").arg(urlString)); - m_dlm.download(dbURL, vorDBFile); - } - } -} - -void VORDemodGUI::readNavAids() -{ - m_vors = new QHash(); - for (int countryIndex = 0; countryCodes[countryIndex] != nullptr; countryIndex++) - { - QString vorDBFile = getOpenAIPVORDBFilename(countryIndex); - NavAid::readNavAidsXML(m_vors, vorDBFile); - } -} - -void VORDemodGUI::on_magDecAdjust_clicked(bool checked) -{ - m_settings.m_magDecAdjust = checked; - m_vorModel.allVORUpdated(); - applySettings(); -} - void VORDemodGUI::onWidgetRolled(QWidget* widget, bool rollDown) { (void) widget; (void) rollDown; - saveState(m_rollupState); + getRollupContents()->saveState(m_rollupState); applySettings(); } @@ -1119,6 +251,14 @@ void VORDemodGUI::onMenuDialogCalled(const QPoint &p) dialog.setReverseAPIPort(m_settings.m_reverseAPIPort); dialog.setReverseAPIDeviceIndex(m_settings.m_reverseAPIDeviceIndex); dialog.setReverseAPIChannelIndex(m_settings.m_reverseAPIChannelIndex); + dialog.setDefaultTitle(m_displayedName); + + if (m_deviceUISet->m_deviceMIMOEngine) + { + dialog.setNumberOfStreams(m_vorDemod->getNumberOfDeviceStreams()); + dialog.setStreamIndex(m_settings.m_streamIndex); + } + dialog.move(p); dialog.exec(); @@ -1131,22 +271,17 @@ void VORDemodGUI::onMenuDialogCalled(const QPoint &p) m_settings.m_reverseAPIChannelIndex = dialog.getReverseAPIChannelIndex(); setWindowTitle(m_settings.m_title); + setTitle(m_channelMarker.getTitle()); setTitleColor(m_settings.m_rgbColor); - applySettings(); - } - else if ((m_contextMenuType == ContextMenuStreamSettings) && (m_deviceUISet->m_deviceMIMOEngine)) - { - DeviceStreamSelectionDialog dialog(this); - dialog.setNumberOfStreams(m_vorDemod->getNumberOfDeviceStreams()); - dialog.setStreamIndex(m_settings.m_streamIndex); - dialog.move(p); - dialog.exec(); + if (m_deviceUISet->m_deviceMIMOEngine) + { + m_settings.m_streamIndex = dialog.getSelectedStreamIndex(); + m_channelMarker.clearStreamIndexes(); + m_channelMarker.addStreamIndex(m_settings.m_streamIndex); + updateIndexLabel(); + } - m_settings.m_streamIndex = dialog.getSelectedStreamIndex(); - m_channelMarker.clearStreamIndexes(); - m_channelMarker.addStreamIndex(m_settings.m_streamIndex); - displayStreamIndex(); applySettings(); } @@ -1159,26 +294,19 @@ VORDemodGUI::VORDemodGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, Baseban m_pluginAPI(pluginAPI), m_deviceUISet(deviceUISet), m_channelMarker(this), + m_deviceCenterFrequency(0), m_doApplySettings(true), m_squelchOpen(false), - m_tickCount(0), - m_progressDialog(nullptr), - m_vorModel(this), - m_vors(nullptr) + m_tickCount(0) { - ui->setupUi(this); - m_helpURL = "plugins/channelrx/demodvor/readme.md"; - - ui->map->rootContext()->setContextProperty("vorModel", &m_vorModel); - ui->map->setSource(QUrl(QStringLiteral("qrc:/demodvor/map/map.qml"))); - - m_muteIcon.addPixmap(QPixmap("://sound_off.png"), QIcon::Normal, QIcon::On); - m_muteIcon.addPixmap(QPixmap("://sound_on.png"), QIcon::Normal, QIcon::Off); - setAttribute(Qt::WA_DeleteOnClose, true); - connect(this, SIGNAL(widgetRolled(QWidget*,bool)), this, SLOT(onWidgetRolled(QWidget*,bool))); + m_helpURL = "plugins/channelrx/demodvorsc/readme.md"; + RollupContents *rollupContents = getRollupContents(); + ui->setupUi(rollupContents); + setSizePolicy(rollupContents->sizePolicy()); + rollupContents->arrangeRollups(); + connect(rollupContents, SIGNAL(widgetRolled(QWidget*,bool)), this, SLOT(onWidgetRolled(QWidget*,bool))); connect(this, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(onMenuDialogCalled(const QPoint &))); - connect(&m_dlm, &HttpDownloadManager::downloadComplete, this, &VORDemodGUI::downloadFinished); m_vorDemod = reinterpret_cast(rxChannel); m_vorDemod->setMessageQueueToGUI(getInputMessageQueue()); @@ -1188,12 +316,15 @@ VORDemodGUI::VORDemodGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, Baseban CRightClickEnabler *audioMuteRightClickEnabler = new CRightClickEnabler(ui->audioMute); connect(audioMuteRightClickEnabler, SIGNAL(rightClick(const QPoint &)), this, SLOT(audioSelect())); + ui->deltaFrequencyLabel->setText(QString("%1f").arg(QChar(0x94, 0x03))); + ui->deltaFrequency->setColorMapper(ColorMapper(ColorMapper::GrayGold)); + ui->deltaFrequency->setValueRange(false, 7, -9999999, 9999999); ui->channelPowerMeter->setColorTheme(LevelMeterSignalDB::ColorGreenAndBlue); - m_channelMarker.blockSignals(true); - m_channelMarker.setColor(Qt::yellow); - m_channelMarker.setBandwidth(2*48000); - m_channelMarker.setCenterFrequency(0); + m_channelMarker.blockSignals(true); + m_channelMarker.setColor(Qt::yellow); + m_channelMarker.setBandwidth(2*VORDemodSettings::VORDEMOD_CHANNEL_BANDWIDTH); + m_channelMarker.setCenterFrequency(0); m_channelMarker.setTitle("VOR Demodulator"); m_channelMarker.blockSignals(false); m_channelMarker.setVisible(true); // activate signal on the last setting only @@ -1203,75 +334,13 @@ VORDemodGUI::VORDemodGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, Baseban m_settings.setRollupState(&m_rollupState); m_deviceUISet->addChannelMarker(&m_channelMarker); - m_deviceUISet->addRollupWidget(this); connect(&m_channelMarker, SIGNAL(changedByCursor()), this, SLOT(channelMarkerChangedByCursor())); connect(&m_channelMarker, SIGNAL(highlightedByCursor()), this, SLOT(channelMarkerHighlightedByCursor())); connect(getInputMessageQueue(), SIGNAL(messageEnqueued()), this, SLOT(handleInputMessages())); - // Get station position - Real stationLatitude = MainCore::instance()->getSettings().getLatitude(); - Real stationLongitude = MainCore::instance()->getSettings().getLongitude(); - Real stationAltitude = MainCore::instance()->getSettings().getAltitude(); - m_azEl.setLocation(stationLatitude, stationLongitude, stationAltitude); - - // Centre map at My Position - QQuickItem *item = ui->map->rootObject(); - QObject *object = item->findChild("map"); - if(object != NULL) - { - QGeoCoordinate coords = object->property("center").value(); - coords.setLatitude(stationLatitude); - coords.setLongitude(stationLongitude); - object->setProperty("center", QVariant::fromValue(coords)); - } - // Move antenna icon to My Position to start with - QObject *stationObject = item->findChild("station"); - if(stationObject != NULL) - { - QGeoCoordinate coords = stationObject->property("coordinate").value(); - coords.setLatitude(stationLatitude); - coords.setLongitude(stationLongitude); - coords.setAltitude(stationAltitude); - stationObject->setProperty("coordinate", QVariant::fromValue(coords)); - stationObject->setProperty("stationName", QVariant::fromValue(MainCore::instance()->getSettings().getStationName())); - } - - // Read in VOR information if it exists - bool useOurAirports = false; - if (useOurAirports) - { - m_vors = NavAid::readNavAidsDB(getVORDBFilename()); - ui->getOpenAIPVORDB->setVisible(false); - } - else - { - readNavAids(); - ui->getOurAirportsVORDB->setVisible(false); - } - if (m_vors != nullptr) - updateVORs(); - - // Resize the table using dummy data - resizeTable(); - // Allow user to reorder columns - ui->vorData->horizontalHeader()->setSectionsMovable(true); - // Allow user to sort table by clicking on headers - ui->vorData->setSortingEnabled(true); - // Add context menu to allow hiding/showing of columns - menu = new QMenu(ui->vorData); - for (int i = 0; i < ui->vorData->horizontalHeader()->count(); i++) - { - QString text = ui->vorData->horizontalHeaderItem(i)->text(); - menu->addAction(createCheckableItem(text, i, true)); - } - ui->vorData->horizontalHeader()->setContextMenuPolicy(Qt::CustomContextMenu); - connect(ui->vorData->horizontalHeader(), SIGNAL(customContextMenuRequested(QPoint)), SLOT(columnSelectMenu(QPoint))); - // Get signals when columns change - connect(ui->vorData->horizontalHeader(), SIGNAL(sectionMoved(int, int, int)), SLOT(vorData_sectionMoved(int, int, int))); - connect(ui->vorData->horizontalHeader(), SIGNAL(sectionResized(int, int, int)), SLOT(vorData_sectionResized(int, int, int))); - displaySettings(); + makeUIConnections(); applySettings(true); } @@ -1297,17 +366,20 @@ void VORDemodGUI::applySettings(bool force) void VORDemodGUI::displaySettings() { m_channelMarker.blockSignals(true); - m_channelMarker.setCenterFrequency(0); - m_channelMarker.setBandwidth(m_basebandSampleRate > 0 ? m_basebandSampleRate : 2*48000); + m_channelMarker.setCenterFrequency(m_settings.m_inputFrequencyOffset); + m_channelMarker.setBandwidth(2*VORDemodSettings::VORDEMOD_CHANNEL_BANDWIDTH); m_channelMarker.setTitle(m_settings.m_title); m_channelMarker.blockSignals(false); m_channelMarker.setColor(m_settings.m_rgbColor); // activate signal on the last setting only setTitleColor(m_settings.m_rgbColor); setWindowTitle(m_channelMarker.getTitle()); + setTitle(m_channelMarker.getTitle()); blockApplySettings(true); + ui->deltaFrequency->setValue(m_channelMarker.getCenterFrequency()); + ui->thresh->setValue(m_settings.m_identThreshold * 10.0); ui->threshText->setText(QString("%1").arg(m_settings.m_identThreshold, 0, 'f', 1)); @@ -1319,41 +391,23 @@ void VORDemodGUI::displaySettings() ui->audioMute->setChecked(m_settings.m_audioMute); - displayStreamIndex(); + updateIndexLabel(); - // Order and size columns - QHeaderView *header = ui->vorData->horizontalHeader(); - for (int i = 0; i < VORDEMOD_COLUMNS; i++) - { - bool hidden = m_settings.m_columnSizes[i] == 0; - header->setSectionHidden(i, hidden); - menu->actions().at(i)->setChecked(!hidden); - if (m_settings.m_columnSizes[i] > 0) - ui->vorData->setColumnWidth(i, m_settings.m_columnSizes[i]); - header->moveSection(header->visualIndex(i), m_settings.m_columnIndexes[i]); - } - - restoreState(m_rollupState); + getRollupContents()->restoreState(m_rollupState); + updateAbsoluteCenterFrequency(); blockApplySettings(false); } -void VORDemodGUI::displayStreamIndex() -{ - if (m_deviceUISet->m_deviceMIMOEngine) { - setStreamIndicator(tr("%1").arg(m_settings.m_streamIndex)); - } else { - setStreamIndicator("S"); // single channel indicator - } -} - -void VORDemodGUI::leaveEvent(QEvent*) +void VORDemodGUI::leaveEvent(QEvent* event) { m_channelMarker.setHighlighted(false); + ChannelGUI::leaveEvent(event); } -void VORDemodGUI::enterEvent(QEvent*) +void VORDemodGUI::enterEvent(QEvent* event) { m_channelMarker.setHighlighted(true); + ChannelGUI::enterEvent(event); } void VORDemodGUI::audioSelect() @@ -1402,26 +456,19 @@ void VORDemodGUI::tick() m_squelchOpen = squelchOpen; } - // Try to determine position, based on intersection of two radials - if (m_tickCount % 50) - { - float lat, lon; - - if (m_vorModel.findIntersection(lat, lon)) - { - // Move antenna icon to estimated position - QQuickItem *item = ui->map->rootObject(); - QObject *stationObject = item->findChild("station"); - if(stationObject != NULL) - { - QGeoCoordinate coords = stationObject->property("coordinate").value(); - coords.setLatitude(lat); - coords.setLongitude(lon); - stationObject->setProperty("coordinate", QVariant::fromValue(coords)); - stationObject->setProperty("stationName", QVariant::fromValue(MainCore::instance()->getSettings().getStationName())); - } - } - } - m_tickCount++; } + +void VORDemodGUI::makeUIConnections() +{ + QObject::connect(ui->deltaFrequency, &ValueDialZ::changed, this, &VORDemodGUI::on_deltaFrequency_changed); + QObject::connect(ui->thresh, &QDial::valueChanged, this, &VORDemodGUI::on_thresh_valueChanged); + QObject::connect(ui->volume, &QDial::valueChanged, this, &VORDemodGUI::on_volume_valueChanged); + QObject::connect(ui->squelch, &QDial::valueChanged, this, &VORDemodGUI::on_squelch_valueChanged); + QObject::connect(ui->audioMute, &QToolButton::toggled, this, &VORDemodGUI::on_audioMute_toggled); +} + +void VORDemodGUI::updateAbsoluteCenterFrequency() +{ + setStatusFrequency(m_deviceCenterFrequency + m_settings.m_inputFrequencyOffset); +} diff --git a/plugins/channelrx/demodvor/vordemodgui.h b/plugins/channelrx/demodvor/vordemodgui.h index 4d3238204..44bced0fa 100644 --- a/plugins/channelrx/demodvor/vordemodgui.h +++ b/plugins/channelrx/demodvor/vordemodgui.h @@ -16,30 +16,15 @@ // along with this program. If not, see . // /////////////////////////////////////////////////////////////////////////////////// -#ifndef INCLUDE_VORDEMODGUI_H -#define INCLUDE_VORDEMODGUI_H - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#ifndef INCLUDE_VORDEMODSCGUI_H +#define INCLUDE_VORDEMODSCGUI_H #include "channel/channelgui.h" #include "dsp/channelmarker.h" #include "dsp/movingaverage.h" #include "util/messagequeue.h" -#include "util/httpdownloadmanager.h" -#include "util/azel.h" #include "settings/rollupstate.h" #include "vordemodsettings.h" -#include "navaid.h" class PluginAPI; class DeviceUISet; @@ -52,154 +37,6 @@ namespace Ui { } class VORDemodGUI; -// Table items for each VOR -class VORGUI : public QObject { - Q_OBJECT -public: - NavAid *m_navAid; - QVariantList m_coordinates; - VORDemodGUI *m_gui; - - QTableWidgetItem *m_nameItem; - QTableWidgetItem *m_frequencyItem; - QTableWidgetItem *m_offsetItem; - QTableWidgetItem *m_identItem; - QTableWidgetItem *m_morseItem; - QTableWidgetItem *m_radialItem; - QTableWidgetItem *m_rxIdentItem; - QTableWidgetItem *m_rxMorseItem; - QTableWidgetItem *m_varMagItem; - QTableWidgetItem *m_refMagItem; - QWidget *m_muteItem; - QToolButton *m_muteButton; - - VORGUI(NavAid *navAid, VORDemodGUI *gui); -private slots: - void on_audioMute_toggled(bool checked); -}; - -// VOR model used for each VOR on the map -class VORModel : public QAbstractListModel { - Q_OBJECT - -public: - using QAbstractListModel::QAbstractListModel; - enum MarkerRoles{ - positionRole = Qt::UserRole + 1, - vorDataRole = Qt::UserRole + 2, - vorImageRole = Qt::UserRole + 3, - vorRadialRole = Qt::UserRole + 4, - bubbleColourRole = Qt::UserRole + 5, - selectedRole = Qt::UserRole + 6 - }; - - VORModel(VORDemodGUI *gui) : - m_gui(gui), - m_radialsVisible(true) - { - } - - Q_INVOKABLE void addVOR(NavAid *vor) { - beginInsertRows(QModelIndex(), rowCount(), rowCount()); - m_vors.append(vor); - m_selected.append(false); - m_radials.append(-1.0f); - m_vorGUIs.append(nullptr); - endInsertRows(); - } - - int rowCount(const QModelIndex &parent = QModelIndex()) const override { - Q_UNUSED(parent) - return m_vors.count(); - } - - QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; - - bool setData(const QModelIndex &index, const QVariant& value, int role = Qt::EditRole) override; - - Qt::ItemFlags flags(const QModelIndex &index) const override { - (void) index; - return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsEditable; - } - - void allVORUpdated() { - for (int i = 0; i < m_vors.count(); i++) - { - QModelIndex idx = index(i); - emit dataChanged(idx, idx); - } - } - - void removeVOR(NavAid *vor) { - int row = m_vors.indexOf(vor); - if (row >= 0) - { - beginRemoveRows(QModelIndex(), row, row); - m_vors.removeAt(row); - m_selected.removeAt(row); - m_radials.removeAt(row); - m_vorGUIs.removeAt(row); - endRemoveRows(); - } - } - - void removeAllVORs() { - if (m_vors.count() > 0) - { - beginRemoveRows(QModelIndex(), 0, m_vors.count() - 1); - m_vors.clear(); - m_selected.clear(); - m_radials.clear(); - m_vorGUIs.clear(); - endRemoveRows(); - } - } - - QHash roleNames() const { - QHash roles; - roles[positionRole] = "position"; - roles[vorDataRole] = "vorData"; - roles[vorImageRole] = "vorImage"; - roles[vorRadialRole] = "vorRadial"; - roles[bubbleColourRole] = "bubbleColour"; - roles[selectedRole] = "selected"; - return roles; - } - - void setRadialsVisible(bool radialsVisible) - { - m_radialsVisible = radialsVisible; - allVORUpdated(); - } - - void setRadial(int id, bool valid, Real radial) - { - for (int i = 0; i < m_vors.count(); i++) - { - if (m_vors[i]->m_id == id) - { - if (valid) - m_radials[i] = radial; - else - m_radials[i] = -1; // -1 to indicate invalid - QModelIndex idx = index(i); - emit dataChanged(idx, idx); - break; - } - } - } - - bool findIntersection(float &lat, float &lon); - -private: - VORDemodGUI *m_gui; - bool m_radialsVisible; - QList m_vors; - QList m_selected; - QList m_radials; - QList m_vorGUIs; -}; - class VORDemodGUI : public ChannelGUI { Q_OBJECT @@ -211,22 +48,33 @@ public: QByteArray serialize() const; bool deserialize(const QByteArray& data); virtual MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; } - void selectVOR(VORGUI *vorGUI, bool selected); + virtual void setWorkspaceIndex(int index) { m_settings.m_workspaceIndex = index; }; + virtual int getWorkspaceIndex() const { return m_settings.m_workspaceIndex; }; + virtual void setGeometryBytes(const QByteArray& blob) { m_settings.m_geometryBytes = blob; }; + virtual QByteArray getGeometryBytes() const { return m_settings.m_geometryBytes; }; + virtual QString getTitle() const { return m_settings.m_title; }; + virtual QColor getTitleColor() const { return m_settings.m_rgbColor; }; + virtual void zetHidden(bool hidden) { m_settings.m_hidden = hidden; } + virtual bool getHidden() const { return m_settings.m_hidden; } + virtual ChannelMarker& getChannelMarker() { return m_channelMarker; } + virtual int getStreamIndex() const { return m_settings.m_streamIndex; } + virtual void setStreamIndex(int streamIndex) { m_settings.m_streamIndex = streamIndex; } public slots: void channelMarkerChangedByCursor(); void channelMarkerHighlightedByCursor(); -private: - friend class VORGUI; - friend class VORModel; +protected: + void resizeEvent(QResizeEvent* size); +private: Ui::VORDemodGUI* ui; PluginAPI* m_pluginAPI; DeviceUISet* m_deviceUISet; ChannelMarker m_channelMarker; RollupState m_rollupState; VORDemodSettings m_settings; + qint64 m_deviceCenterFrequency; bool m_doApplySettings; VORDemod* m_vorDemod; @@ -235,62 +83,30 @@ private: uint32_t m_tickCount; MessageQueue m_inputMessageQueue; - QMenu *menu; // Column select context menu - HttpDownloadManager m_dlm; - QProgressDialog *m_progressDialog; - int m_countryIndex; - VORModel m_vorModel; - QHash *m_vors; - QHash m_selectedVORs; - AzEl m_azEl; // Position of station - QIcon m_muteIcon; - explicit VORDemodGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, BasebandSampleSink *rxChannel, QWidget* parent = 0); virtual ~VORDemodGUI(); void blockApplySettings(bool block); void applySettings(bool force = false); void displaySettings(); - void displayStreamIndex(); bool handleMessage(const Message& message); + void makeUIConnections(); + void updateAbsoluteCenterFrequency(); void leaveEvent(QEvent*); void enterEvent(QEvent*); - void resizeTable(); - QAction *createCheckableItem(QString& text, int idx, bool checked); - - void calculateFreqOffset(VORGUI *vorGUI); - void calculateFreqOffsets(); - void updateVORs(); - QString getOpenAIPVORDBURL(int i); - QString getOpenAIPVORDBFilename(int i); - QString getVORDBFilename(); - void readNavAids(); - // Move to util - QString getDataDir(); - qint64 fileAgeInDays(QString filename); - bool confirmDownload(QString filename); - private slots: + void on_deltaFrequency_changed(qint64 value); void on_thresh_valueChanged(int value); void on_volume_valueChanged(int value); void on_squelch_valueChanged(int value); void on_audioMute_toggled(bool checked); - void on_getOurAirportsVORDB_clicked(bool checked = false); - void on_getOpenAIPVORDB_clicked(bool checked = false); - void on_magDecAdjust_clicked(bool checked = false); - void vorData_sectionMoved(int logicalIndex, int oldVisualIndex, int newVisualIndex); - void vorData_sectionResized(int logicalIndex, int oldSize, int newSize); - void columnSelectMenu(QPoint pos); - void columnSelectMenuChecked(bool checked = false); void onWidgetRolled(QWidget* widget, bool rollDown); void onMenuDialogCalled(const QPoint& p); - void updateDownloadProgress(qint64 bytesRead, qint64 totalBytes); - void downloadFinished(const QString& filename, bool success); void handleInputMessages(); void audioSelect(); void tick(); }; -#endif // INCLUDE_VORDEMODGUI_H +#endif // INCLUDE_VORDEMODSCGUI_H diff --git a/plugins/channelrx/demodvor/vordemodgui.ui b/plugins/channelrx/demodvor/vordemodgui.ui index d93557091..c1dd647e0 100644 --- a/plugins/channelrx/demodvor/vordemodgui.ui +++ b/plugins/channelrx/demodvor/vordemodgui.ui @@ -1,17 +1,17 @@ VORDemodGUI - + 0 0 - 398 - 893 + 402 + 138 - + 0 0 @@ -19,7 +19,13 @@ 352 - 0 + 110 + + + + + 560 + 16777215 @@ -40,7 +46,7 @@ 0 0 390 - 61 + 131 @@ -68,6 +74,81 @@ 2 + + + + 2 + + + + + + + + 16 + 0 + + + + Df + + + + + + + + 0 + 0 + + + + + 32 + 16 + + + + + Liberation Mono + 12 + + + + PointingHandCursor + + + Qt::StrongFocus + + + Demod shift frequency from center in Hz + + + + + + + Hz + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + @@ -120,6 +201,12 @@ + + + 40 + 0 + + Channel power @@ -127,7 +214,10 @@ Qt::RightToLeft - 0.0 + -100.0 + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
@@ -162,70 +252,6 @@
- - - - true - - - Download OurAirports VOR database - - - - - - - :/demodvor/icons/vor.png:/demodvor/icons/vor.png - - - - - - - Download OpenAIP VOR database - - - - - - - :/demodvor/icons/vor.png:/demodvor/icons/vor.png - - - - - - - Draw radials adjusted for magnetic declination - - - - - - - :/demodvor/icons/compass.png:/demodvor/icons/compass.png - - - true - - - true - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - @@ -256,6 +282,9 @@ 100 + + 1 + 0 @@ -284,11 +313,17 @@ - + - Qt::Vertical + Qt::Horizontal - + + + 40 + 20 + + + @@ -314,6 +349,9 @@ 0 + + 1 + -40 @@ -363,6 +401,9 @@ 100 + + 1 + @@ -383,219 +424,211 @@ - -
- - - - 0 - 80 - 391 - 141 - - - - - 0 - 0 - - - - VORs - - - - 2 - - - 3 - - - 3 - - - 3 - - - 3 - - - - - 0 - 140 - - - - QAbstractItemView::NoEditTriggers - - - - Name - - - Name of the VOR - - - - - Freq (MHz) - - - Frequency of the VOR in MHz - - - - - Offset (kHz) - - - Offset of the VOR's frequency from the current center frequency. Red indicates out of range. - - - - - Ident - - - Ident for the VOR - - - - - Morse - - - Morse code ident for the VOR - - - - - RX Ident - - - Received ident - - - - - RX Morse - - - Received Morse code ident - - - - - Radial (°) - - - Calculated radial from the VOR - - - - - Ref (dB) - - - Magnitude of received reference signal in dB - - - - - Var (dB) - - - Magnitude of received variable signal in dB - - - - - Mute - - - Mute/unmute audio from selected VORs - - - + + + + + + 20 + 0 + + + + Rad + + + + + + + + 0 + 0 + + + + + 30 + 0 + + + + Radial direction (degrees) red if low confidence + + + 359d + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + Qt::Vertical + + + + + + + Ref + + + + + + + + 50 + 0 + + + + Magnitude of the received 30Hz FM reference signal in dB + + + -100 dB + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + Qt::Vertical + + + + + + + Var + + + + + + + + 50 + 0 + + + + Magnitude of the received 30Hz AM variable signal in dB + + + -100 dB + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + - - - - - - 0 - 260 - 391 - 581 - - - - - 0 - 0 - - - - Map - - - - 2 - - - 3 - - - 3 - - - 3 - - - 3 - - - - - 0 - 0 - - - - - 100 - 500 - - - - VOR map - - - QQuickWidget::SizeRootObjectToView - - - - - - - + + + + + Ident + + + + + + + + 50 + 0 + + + + Decoded identity code yellow if not matching rules + + + XXX + + + + + + + Qt::Vertical + + + + + + + Morse + + + + + + + + 120 + 0 + + + + Morse identity decoded yellow if not matching rules + + + --- --- --- + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + +
- QQuickWidget + RollupContents QWidget -
QtQuickWidgets/QQuickWidget
+
gui/rollupcontents.h
+ 1
- RollupWidget + ValueDialZ QWidget -
gui/rollupwidget.h
+
gui/valuedialz.h
1
@@ -607,14 +640,10 @@
audioMute - getOurAirportsVORDB - vorData - map - - +
diff --git a/plugins/channelrx/demodvor/vordemodplugin.cpp b/plugins/channelrx/demodvor/vordemodplugin.cpp index cca086822..df9737680 100644 --- a/plugins/channelrx/demodvor/vordemodplugin.cpp +++ b/plugins/channelrx/demodvor/vordemodplugin.cpp @@ -88,5 +88,5 @@ ChannelGUI* VORDemodPlugin::createRxChannelGUI(DeviceUISet *deviceUISet, Baseban ChannelWebAPIAdapter* VORDemodPlugin::createChannelWebAPIAdapter() const { - return new VORDemodWebAPIAdapter(); + return new VORDemodSCWebAPIAdapter(); } diff --git a/plugins/channelrx/demodvor/vordemodplugin.h b/plugins/channelrx/demodvor/vordemodplugin.h index a43c13c99..1519a9067 100644 --- a/plugins/channelrx/demodvor/vordemodplugin.h +++ b/plugins/channelrx/demodvor/vordemodplugin.h @@ -16,8 +16,8 @@ // along with this program. If not, see . // /////////////////////////////////////////////////////////////////////////////////// -#ifndef INCLUDE_VORDEMODPLUGIN_H -#define INCLUDE_VORDEMODPLUGIN_H +#ifndef INCLUDE_VORDEMODSCPLUGIN_H +#define INCLUDE_VORDEMODSCPLUGIN_H #include #include "plugin/plugininterface.h" @@ -46,4 +46,4 @@ private: PluginAPI* m_pluginAPI; }; -#endif // INCLUDE_VORDEMODPLUGIN_H +#endif // INCLUDE_VORDEMODSCPLUGIN_H diff --git a/plugins/channelrx/demodvor/vordemodreport.cpp b/plugins/channelrx/demodvor/vordemodreport.cpp index 6ac03f99a..96fcbc7f6 100644 --- a/plugins/channelrx/demodvor/vordemodreport.cpp +++ b/plugins/channelrx/demodvor/vordemodreport.cpp @@ -17,6 +17,5 @@ #include "vordemodreport.h" -MESSAGE_CLASS_DEFINITION(VORDemodReport::MsgReportFreqOffset, Message) MESSAGE_CLASS_DEFINITION(VORDemodReport::MsgReportRadial, Message) MESSAGE_CLASS_DEFINITION(VORDemodReport::MsgReportIdent, Message) diff --git a/plugins/channelrx/demodvor/vordemodreport.h b/plugins/channelrx/demodvor/vordemodreport.h index 88a067d4e..8a053620d 100644 --- a/plugins/channelrx/demodvor/vordemodreport.h +++ b/plugins/channelrx/demodvor/vordemodreport.h @@ -16,8 +16,8 @@ // along with this program. If not, see . // /////////////////////////////////////////////////////////////////////////////////// -#ifndef INCLUDE_VORDEMODREPORT_H -#define INCLUDE_VORDEMODREPORT_H +#ifndef INCLUDE_VORDEMODSCREPORT_H +#define INCLUDE_VORDEMODSCREPORT_H #include @@ -31,25 +31,21 @@ public: MESSAGE_CLASS_DECLARATION public: - int getSubChannelId() const { return m_subChannelId; } float getRadial() const { return m_radial; } float getRefMag() const { return m_refMag; } float getVarMag() const { return m_varMag; } - static MsgReportRadial* create(int subChannelId, float radial, float refMag, float varMag) - { - return new MsgReportRadial(subChannelId, radial, refMag, varMag); + static MsgReportRadial* create(float radial, float refMag, float varMag) { + return new MsgReportRadial(radial, refMag, varMag); } private: - int m_subChannelId; float m_radial; float m_refMag; float m_varMag; - MsgReportRadial(int subChannelId, float radial, float refMag, float varMag) : + MsgReportRadial(float radial, float refMag, float varMag) : Message(), - m_subChannelId(subChannelId), m_radial(radial), m_refMag(refMag), m_varMag(varMag) @@ -57,52 +53,22 @@ public: } }; - class MsgReportFreqOffset : public Message { - MESSAGE_CLASS_DECLARATION - - public: - int getSubChannelId() const { return m_subChannelId; } - int getFreqOffset() const { return m_freqOffset; } - bool getOutOfBand() const { return m_outOfBand; } - - static MsgReportFreqOffset* create(int subChannelId, int freqOffset, bool outOfBand) - { - return new MsgReportFreqOffset(subChannelId, freqOffset, outOfBand); - } - - private: - int m_subChannelId; - int m_freqOffset; - bool m_outOfBand; - - MsgReportFreqOffset(int subChannelId, int freqOffset, bool outOfBand) : - Message(), - m_subChannelId(subChannelId), - m_freqOffset(freqOffset), - m_outOfBand(outOfBand) - { - } - }; - class MsgReportIdent : public Message { MESSAGE_CLASS_DECLARATION public: - int getSubChannelId() const { return m_subChannelId; } QString getIdent() const { return m_ident; } - static MsgReportIdent* create(int subChannelId, QString ident) + static MsgReportIdent* create(QString ident) { - return new MsgReportIdent(subChannelId, ident); + return new MsgReportIdent(ident); } private: - int m_subChannelId; QString m_ident; - MsgReportIdent(int subChannelId, QString ident) : + MsgReportIdent(QString ident) : Message(), - m_subChannelId(subChannelId), m_ident(ident) { } @@ -113,4 +79,4 @@ public: ~VORDemodReport() {} }; -#endif // INCLUDE_VORDEMODREPORT_H +#endif // INCLUDE_VORDEMODSCREPORT_H diff --git a/plugins/channelrx/demodvor/vordemodsettings.cpp b/plugins/channelrx/demodvor/vordemodsettings.cpp index 0c181bdc5..d48fdd93f 100644 --- a/plugins/channelrx/demodvor/vordemodsettings.cpp +++ b/plugins/channelrx/demodvor/vordemodsettings.cpp @@ -32,6 +32,8 @@ VORDemodSettings::VORDemodSettings() : void VORDemodSettings::resetToDefaults() { + m_inputFrequencyOffset = 0; + m_navId = -1; m_squelch = -60.0; m_volume = 2.0; m_audioMute = false; @@ -44,22 +46,18 @@ void VORDemodSettings::resetToDefaults() m_reverseAPIPort = 8888; m_reverseAPIDeviceIndex = 0; m_reverseAPIChannelIndex = 0; + m_workspaceIndex = 0; + m_hidden = false; m_identThreshold = 2.0; m_refThresholdDB = -45.0; m_varThresholdDB = -90.0; - m_magDecAdjust = true; - - for (int i = 0; i < VORDEMOD_COLUMNS; i++) - { - m_columnIndexes[i] = i; - m_columnSizes[i] = -1; // Autosize - } } QByteArray VORDemodSettings::serialize() const { SimpleSerializer s(1); + s.writeS32(1, m_inputFrequencyOffset); s.writeS32(3, m_streamIndex); s.writeS32(4, m_volume*10); s.writeS32(5, m_squelch); @@ -79,19 +77,14 @@ QByteArray VORDemodSettings::serialize() const s.writeReal(20, m_identThreshold); s.writeReal(21, m_refThresholdDB); s.writeReal(22, m_varThresholdDB); - s.writeBool(23, m_magDecAdjust); if (m_rollupState) { - s.writeBlob(24, m_rollupState->serialize()); + s.writeBlob(23, m_rollupState->serialize()); } - for (int i = 0; i < VORDEMOD_COLUMNS; i++) { - s.writeS32(100 + i, m_columnIndexes[i]); - } - - for (int i = 0; i < VORDEMOD_COLUMNS; i++) { - s.writeS32(200 + i, m_columnSizes[i]); - } + s.writeS32(24, m_workspaceIndex); + s.writeBlob(25, m_geometryBytes); + s.writeBool(26, m_hidden); return s.final(); } @@ -113,6 +106,7 @@ bool VORDemodSettings::deserialize(const QByteArray& data) uint32_t utmp; QString strtmp; + d.readS32(1, &m_inputFrequencyOffset, 0); d.readS32(3, &m_streamIndex, 0); d.readS32(4, &tmp, 20); m_volume = tmp * 0.1; @@ -145,21 +139,16 @@ bool VORDemodSettings::deserialize(const QByteArray& data) d.readReal(20, &m_identThreshold, 2.0); d.readReal(21, &m_refThresholdDB, -45.0); d.readReal(22, &m_varThresholdDB, -90.0); - d.readBool(23, &m_magDecAdjust, true); if (m_rollupState) { - d.readBlob(24, &bytetmp); + d.readBlob(23, &bytetmp); m_rollupState->deserialize(bytetmp); } - for (int i = 0; i < VORDEMOD_COLUMNS; i++) { - d.readS32(100 + i, &m_columnIndexes[i], i); - } - - for (int i = 0; i < VORDEMOD_COLUMNS; i++) { - d.readS32(200 + i, &m_columnSizes[i], -1); - } + d.readS32(24, &m_workspaceIndex, 0); + d.readBlob(25, &m_geometryBytes); + d.readBool(26, &m_hidden, false); return true; } diff --git a/plugins/channelrx/demodvor/vordemodsettings.h b/plugins/channelrx/demodvor/vordemodsettings.h index 0855dde72..b26650a02 100644 --- a/plugins/channelrx/demodvor/vordemodsettings.h +++ b/plugins/channelrx/demodvor/vordemodsettings.h @@ -16,25 +16,18 @@ // along with this program. If not, see . // /////////////////////////////////////////////////////////////////////////////////// -#ifndef INCLUDE_VORDEMODSETTINGS_H -#define INCLUDE_VORDEMODSETTINGS_H +#ifndef INCLUDE_VORDEMODSCSETTINGS_H +#define INCLUDE_VORDEMODSCSETTINGS_H #include #include class Serializable; -// Number of columns in the table -#define VORDEMOD_COLUMNS 11 - -struct VORDemodSubChannelSettings { - int m_id; //!< Unique VOR identifier (from database) - int m_frequency; //!< Frequency the VOR is on - bool m_audioMute; //!< Mute the audio from this VOR -}; - struct VORDemodSettings { + qint32 m_inputFrequencyOffset; + int m_navId; //!< VOR unique identifier when set by VOR localizer feature Real m_squelch; Real m_volume; bool m_audioMute; @@ -52,13 +45,18 @@ struct VORDemodSettings Real m_identThreshold; //!< Linear SNR threshold for Morse demodulator Real m_refThresholdDB; //!< Threshold in dB for valid VOR reference signal Real m_varThresholdDB; //!< Threshold in dB for valid VOR variable signal - bool m_magDecAdjust; //!< Adjust for magnetic declination when drawing radials on the map Serializable *m_rollupState; + int m_workspaceIndex; + QByteArray m_geometryBytes; + bool m_hidden; - int m_columnIndexes[VORDEMOD_COLUMNS];//!< How the columns are ordered in the table - int m_columnSizes[VORDEMOD_COLUMNS]; //!< Size of the coumns in the table - - QHash m_subChannelSettings; + // Highest frequency is the FM subcarrier at up to ~11kHz + // However, old VORs can have 0.005% frequency offset, which is 6kHz + static const int VORDEMOD_CHANNEL_BANDWIDTH = 18000; + // Sample rate needs to be at least twice the above + // Also need to consider impact frequency resolution of Goertzel filters + // May as well make it a common audio rate, to possibly avoid decimation + static const int VORDEMOD_CHANNEL_SAMPLE_RATE = 48000; VORDemodSettings(); void resetToDefaults(); @@ -68,4 +66,4 @@ struct VORDemodSettings bool deserialize(const QByteArray& data); }; -#endif /* INCLUDE_VORDEMODSETTINGS_H */ +#endif /* INCLUDE_VORDEMODSCSETTINGS_H */ diff --git a/plugins/channelrx/demodvor/vordemodsink.cpp b/plugins/channelrx/demodvor/vordemodsink.cpp index b7f046dad..5c05b51a8 100644 --- a/plugins/channelrx/demodvor/vordemodsink.cpp +++ b/plugins/channelrx/demodvor/vordemodsink.cpp @@ -27,14 +27,13 @@ #include "util/morse.h" #include "util/units.h" -#include "vordemodsink.h" #include "vordemodreport.h" +#include "vordemodsettings.h" +#include "vordemodsink.h" -VORDemodSink::VORDemodSink(const VORDemodSettings& settings, int subChannel, - MessageQueue *messageQueueToGUI) : +VORDemodSCSink::VORDemodSCSink() : m_channelFrequencyOffset(0), - m_outOfBand(true), - m_channelSampleRate(VORDEMOD_CHANNEL_SAMPLE_RATE), + m_channelSampleRate(VORDemodSettings::VORDEMOD_CHANNEL_SAMPLE_RATE), m_audioSampleRate(48000), m_squelchCount(0), m_squelchOpen(false), @@ -42,42 +41,32 @@ VORDemodSink::VORDemodSink(const VORDemodSettings& settings, int subChannel, m_magsqSum(0.0f), m_magsqPeak(0.0f), m_magsqCount(0), - m_messageQueueToGUI(messageQueueToGUI), m_volumeAGC(0.003), m_audioFifo(48000), m_refPrev(0.0f), m_movingAverageIdent(5000), m_prevBit(0), m_bitTime(0), - m_varGoertzel(30, VORDEMOD_CHANNEL_SAMPLE_RATE), - m_refGoertzel(30, VORDEMOD_CHANNEL_SAMPLE_RATE) + m_varGoertzel(30, VORDemodSettings::VORDEMOD_CHANNEL_SAMPLE_RATE), + m_refGoertzel(30, VORDemodSettings::VORDEMOD_CHANNEL_SAMPLE_RATE) { - m_audioBuffer.resize(1<<14); - m_audioBufferFill = 0; + m_audioBuffer.resize(1<<14); + m_audioBufferFill = 0; - m_magsq = 0.0; + m_magsq = 0.0; - qDebug() << "Sink " << subChannel; - if (subChannel >= 0) - { - m_subChannelId = subChannel; - m_vorFrequencyHz = settings.m_subChannelSettings[subChannel]->m_frequency; - - applySettings(settings, true); - } + applySettings(m_settings, true); + applyChannelSettings(m_channelSampleRate, m_channelFrequencyOffset, true); } -VORDemodSink::~VORDemodSink() +VORDemodSCSink::~VORDemodSCSink() { } -void VORDemodSink::feed(const SampleVector::const_iterator& begin, const SampleVector::const_iterator& end) +void VORDemodSCSink::feed(const SampleVector::const_iterator& begin, const SampleVector::const_iterator& end) { Complex ci; - if (m_outOfBand) - return; - for (SampleVector::const_iterator it = begin; it != end; ++it) { Complex c(it->real(), it->imag()); @@ -102,7 +91,7 @@ void VORDemodSink::feed(const SampleVector::const_iterator& begin, const SampleV } } -void VORDemodSink::processOneAudioSample(Complex &ci) +void VORDemodSCSink::processOneAudioSample(Complex &ci) { Real re = ci.real() / SDR_RX_SCALEF; Real im = ci.imag() / SDR_RX_SCALEF; @@ -137,7 +126,7 @@ void VORDemodSink::processOneAudioSample(Complex &ci) m_squelchOpen = (m_squelchCount >= (unsigned int)m_audioSampleRate / 20); - if (m_squelchOpen && !m_settings.m_audioMute && !m_settings.m_subChannelSettings.value(m_subChannelId)->m_audioMute) + if (m_squelchOpen && !m_settings.m_audioMute) { Real demod; @@ -167,7 +156,7 @@ void VORDemodSink::processOneAudioSample(Complex &ci) if (res != m_audioBufferFill) { - qDebug("VORDemodSink::processOneAudioSample: %u/%u audio samples written", res, m_audioBufferFill); + qDebug("VORDemodSCSink::processOneAudioSample: %u/%u audio samples written", res, m_audioBufferFill); m_audioFifo.clear(); } @@ -176,7 +165,7 @@ void VORDemodSink::processOneAudioSample(Complex &ci) } -void VORDemodSink::processOneSample(Complex &ci) +void VORDemodSCSink::processOneSample(Complex &ci) { Complex ca; @@ -208,7 +197,7 @@ void VORDemodSink::processOneSample(Complex &ci) // Calculate phase of 30Hz variable AM signal double varPhase; double varMag; - if (m_varGoertzel.size() == VORDEMOD_CHANNEL_SAMPLE_RATE - 1) + if (m_varGoertzel.size() == VORDemodSettings::VORDEMOD_CHANNEL_SAMPLE_RATE - 1) { m_varGoertzel.goertzel(mag); varPhase = Units::radiansToDegrees(m_varGoertzel.phase()); @@ -231,13 +220,13 @@ void VORDemodSink::processOneSample(Complex &ci) m_refPrev = fmfilt; // Calculate phase of 30Hz reference FM signal - if (m_refGoertzel.size() == VORDEMOD_CHANNEL_SAMPLE_RATE - 1) + if (m_refGoertzel.size() == VORDemodSettings::VORDEMOD_CHANNEL_SAMPLE_RATE - 1) { m_refGoertzel.goertzel(phi); float phaseDeg = Units::radiansToDegrees(m_refGoertzel.phase()); double refMag = m_refGoertzel.mag(); int groupDelay = (301-1)/2; - float filterPhaseShift = 360.0*30.0*groupDelay/VORDEMOD_CHANNEL_SAMPLE_RATE; + float filterPhaseShift = 360.0*30.0*groupDelay/VORDemodSettings::VORDEMOD_CHANNEL_SAMPLE_RATE; float shiftedPhase = phaseDeg + filterPhaseShift; // Calculate difference in phase, which is the radial @@ -249,10 +238,10 @@ void VORDemodSink::processOneSample(Complex &ci) // qDebug() << "Ref phase: " << phaseDeg << " var phase " << varPhase; - if (getMessageQueueToGUI()) + if (getMessageQueueToChannel()) { - VORDemodReport::MsgReportRadial *msg = VORDemodReport::MsgReportRadial::create(m_subChannelId, phaseDifference, refMag, varMag); - getMessageQueueToGUI()->push(msg); + VORDemodReport::MsgReportRadial *msg = VORDemodReport::MsgReportRadial::create(phaseDifference, refMag, varMag); + getMessageQueueToChannel()->push(msg); } m_refGoertzel.reset(); @@ -302,12 +291,14 @@ void VORDemodSink::processOneSample(Complex &ci) { if (m_ident != "") { - qDebug() << m_ident << " " << Morse::toString(m_ident); - if (getMessageQueueToGUI()) + qDebug() << "VORDemodSCSink::processOneSample:" << m_ident << " " << Morse::toString(m_ident); + + if (getMessageQueueToChannel()) { - VORDemodReport::MsgReportIdent *msg = VORDemodReport::MsgReportIdent::create(m_subChannelId, m_ident); - getMessageQueueToGUI()->push(msg); + VORDemodReport::MsgReportIdent *msg = VORDemodReport::MsgReportIdent::create(m_ident); + getMessageQueueToChannel()->push(msg); } + m_ident = ""; } } @@ -341,12 +332,14 @@ void VORDemodSink::processOneSample(Complex &ci) m_ident = m_ident.simplified(); if (m_ident != "") { - qDebug() << m_ident << " " << Morse::toString(m_ident); - if (getMessageQueueToGUI()) + qDebug() << "VORDemodSCSink::processOneSample:" << m_ident << " " << Morse::toString(m_ident); + + if (getMessageQueueToChannel()) { - VORDemodReport::MsgReportIdent *msg = VORDemodReport::MsgReportIdent::create(m_subChannelId, m_ident); - getMessageQueueToGUI()->push(msg); + VORDemodReport::MsgReportIdent *msg = VORDemodReport::MsgReportIdent::create(m_ident); + getMessageQueueToChannel()->push(msg); } + m_ident = ""; } m_bitTime = 0; @@ -355,9 +348,9 @@ void VORDemodSink::processOneSample(Complex &ci) m_prevBit = bit; } -void VORDemodSink::applyChannelSettings(int channelSampleRate, int channelFrequencyOffset, bool force) +void VORDemodSCSink::applyChannelSettings(int channelSampleRate, int channelFrequencyOffset, bool force) { - qDebug() << "VORDemodSink::applyChannelSettings:" + qDebug() << "VORDemodSCSink::applyChannelSettings:" << " channelSampleRate: " << channelSampleRate << " channelFrequencyOffset: " << channelFrequencyOffset; @@ -369,17 +362,17 @@ void VORDemodSink::applyChannelSettings(int channelSampleRate, int channelFreque if ((m_channelSampleRate != channelSampleRate) || force) { - m_interpolator.create(16, channelSampleRate, VORDEMOD_CHANNEL_BANDWIDTH); + m_interpolator.create(16, channelSampleRate, VORDemodSettings::VORDEMOD_CHANNEL_BANDWIDTH); m_interpolatorDistanceRemain = 0; - m_interpolatorDistance = (Real) channelSampleRate / (Real) VORDEMOD_CHANNEL_SAMPLE_RATE; + m_interpolatorDistance = (Real) channelSampleRate / (Real) VORDemodSettings::VORDEMOD_CHANNEL_SAMPLE_RATE; - m_samplesPerDot7wpm = VORDEMOD_CHANNEL_SAMPLE_RATE*60/(50*7); - m_samplesPerDot10wpm = VORDEMOD_CHANNEL_SAMPLE_RATE*60/(50*10); + m_samplesPerDot7wpm = VORDemodSettings::VORDEMOD_CHANNEL_SAMPLE_RATE*60/(50*7); + m_samplesPerDot10wpm = VORDemodSettings::VORDEMOD_CHANNEL_SAMPLE_RATE*60/(50*10); - m_ncoIdent.setFreq(-1020, VORDEMOD_CHANNEL_SAMPLE_RATE); // +-50Hz source offset allowed - m_ncoRef.setFreq(-9960, VORDEMOD_CHANNEL_SAMPLE_RATE); - m_lowpassIdent.create(301, VORDEMOD_CHANNEL_SAMPLE_RATE, 100.0f); - m_lowpassRef.create(301, VORDEMOD_CHANNEL_SAMPLE_RATE, 600.0f); // Max deviation is 480Hz + m_ncoIdent.setFreq(-1020, VORDemodSettings::VORDEMOD_CHANNEL_SAMPLE_RATE); // +-50Hz source offset allowed + m_ncoRef.setFreq(-9960, VORDemodSettings::VORDEMOD_CHANNEL_SAMPLE_RATE); + m_lowpassIdent.create(301, VORDemodSettings::VORDEMOD_CHANNEL_SAMPLE_RATE, 100.0f); + m_lowpassRef.create(301, VORDemodSettings::VORDEMOD_CHANNEL_SAMPLE_RATE, 600.0f); // Max deviation is 480Hz m_movingAverageIdent.resize(m_samplesPerDot10wpm/5); // Needs to be short enough for noise floor calculation m_binSampleCnt = 0; @@ -395,9 +388,9 @@ void VORDemodSink::applyChannelSettings(int channelSampleRate, int channelFreque m_channelFrequencyOffset = channelFrequencyOffset; } -void VORDemodSink::applySettings(const VORDemodSettings& settings, bool force) +void VORDemodSCSink::applySettings(const VORDemodSettings& settings, bool force) { - qDebug() << "VORDemodSink::applySettings:" + qDebug() << "VORDemodSCSink::applySettings:" << " m_volume: " << settings.m_volume << " m_squelch: " << settings.m_squelch << " m_audioMute: " << settings.m_audioMute @@ -408,23 +401,38 @@ void VORDemodSink::applySettings(const VORDemodSettings& settings, bool force) m_squelchLevel = CalcDb::powerFromdB(settings.m_squelch); } + if (m_settings.m_navId != settings.m_navId) + { + // Reset state when navId changes, so we don't report old ident for new navId + m_binSampleCnt = 0; + m_binCnt = 0; + m_identNoise = 0.0001f; + for (int i = 0; i < m_identBins; i++) + { + m_identMaxs[i] = 0.0f; + } + m_ident = ""; + m_refGoertzel.reset(); + m_varGoertzel.reset(); + } + m_settings = settings; } -void VORDemodSink::applyAudioSampleRate(int sampleRate) +void VORDemodSCSink::applyAudioSampleRate(int sampleRate) { if (sampleRate < 0) { - qWarning("VORDemodSink::applyAudioSampleRate: invalid sample rate: %d", sampleRate); + qWarning("VORDemodSCSink::applyAudioSampleRate: invalid sample rate: %d", sampleRate); return; } - qDebug("VORDemodSink::applyAudioSampleRate: sampleRate: %d m_channelSampleRate: %d", sampleRate, m_channelSampleRate); + qDebug("VORDemodSCSink::applyAudioSampleRate: sampleRate: %d m_channelSampleRate: %d", sampleRate, m_channelSampleRate); // (ICAO Annex 10 3.3.6.3) - Optional voice audio is 300Hz to 3kHz - m_audioInterpolator.create(16, VORDEMOD_CHANNEL_SAMPLE_RATE, 3000.0f); + m_audioInterpolator.create(16, VORDemodSettings::VORDEMOD_CHANNEL_SAMPLE_RATE, 3000.0f); m_audioInterpolatorDistanceRemain = 0; - m_audioInterpolatorDistance = (Real) VORDEMOD_CHANNEL_SAMPLE_RATE / (Real) sampleRate; + m_audioInterpolatorDistance = (Real) VORDemodSettings::VORDEMOD_CHANNEL_SAMPLE_RATE / (Real) sampleRate; m_bandpass.create(301, sampleRate, 300.0f, 3000.0f); m_audioFifo.setSize(sampleRate); m_squelchDelayLine.resize(sampleRate/5); diff --git a/plugins/channelrx/demodvor/vordemodsink.h b/plugins/channelrx/demodvor/vordemodsink.h index d6243b4e7..1086f628d 100644 --- a/plugins/channelrx/demodvor/vordemodsink.h +++ b/plugins/channelrx/demodvor/vordemodsink.h @@ -16,8 +16,8 @@ // along with this program. If not, see . // /////////////////////////////////////////////////////////////////////////////////// -#ifndef INCLUDE_VORDEMODSINK_H -#define INCLUDE_VORDEMODSINK_H +#ifndef INCLUDE_VORDEMODSCSINK_H +#define INCLUDE_VORDEMODSCSINK_H #include "dsp/channelsamplesink.h" #include "dsp/nco.h" @@ -34,31 +34,23 @@ #include -// Highest frequency is the FM subcarrier at up to ~11kHz -// However, old VORs can have 0.005% frequency offset, which is 6kHz -#define VORDEMOD_CHANNEL_BANDWIDTH 18000 -// Sample rate needs to be at least twice the above -// Also need to consider impact frequency resolution of Goertzel filters -// May as well make it a common audio rate, to possibly avoid decimation -#define VORDEMOD_CHANNEL_SAMPLE_RATE 48000 - -class VORDemodSink : public ChannelSampleSink { +class VORDemodSCSink : public ChannelSampleSink { public: - VORDemodSink(const VORDemodSettings& settings, int subChannel, - MessageQueue *messageQueueToGUI); - ~VORDemodSink(); + VORDemodSCSink(); + ~VORDemodSCSink(); virtual void feed(const SampleVector::const_iterator& begin, const SampleVector::const_iterator& end); void applyChannelSettings(int channelSampleRate, int channelFrequencyOffset, bool force = false); void applySettings(const VORDemodSettings& settings, bool force = false); - void setMessageQueueToGUI(MessageQueue *messageQueue) { m_messageQueueToGUI = messageQueue; } + void setMessageQueueToChannel(MessageQueue *messageQueue) { m_messageQueueToChannel = messageQueue; } void applyAudioSampleRate(int sampleRate); int getAudioSampleRate() const { return m_audioSampleRate; } double getMagSq() const { return m_magsq; } bool getSquelchOpen() const { return m_squelchOpen; } AudioFifo *getAudioFifo() { return &m_audioFifo; } + void setAudioFifoLabel(const QString& label) { m_audioFifo.setLabel(label); } void getMagSqLevels(double& avg, double& peak, int& nbSamples) { @@ -78,11 +70,7 @@ public: m_magsqCount = 0; } - int m_subChannelId; // The id for the VOR this demod sink was created for - int m_vorFrequencyHz; // The VORs frequency - int m_frequencyOffset; // Different between sample source center frequeny and VOR center frequency int m_channelFrequencyOffset; - bool m_outOfBand; private: struct MagSqLevelsStore @@ -114,6 +102,7 @@ private: int m_magsqCount; MagSqLevelsStore m_magSqLevelStore; + MessageQueue *m_messageQueueToChannel; MessageQueue *m_messageQueueToGUI; MovingAverageUtil m_movingAverage; @@ -150,7 +139,7 @@ private: void processOneSample(Complex &ci); void processOneAudioSample(Complex &ci); - MessageQueue *getMessageQueueToGUI() { return m_messageQueueToGUI; } + MessageQueue *getMessageQueueToChannel() { return m_messageQueueToChannel; } }; -#endif // INCLUDE_VORDEMODSINK_H +#endif // INCLUDE_VORDEMODSCSINK_H diff --git a/plugins/channelrx/demodvor/vordemodwebapiadapter.cpp b/plugins/channelrx/demodvor/vordemodwebapiadapter.cpp index 79be603db..9b699cacd 100644 --- a/plugins/channelrx/demodvor/vordemodwebapiadapter.cpp +++ b/plugins/channelrx/demodvor/vordemodwebapiadapter.cpp @@ -20,13 +20,13 @@ #include "vordemod.h" #include "vordemodwebapiadapter.h" -VORDemodWebAPIAdapter::VORDemodWebAPIAdapter() +VORDemodSCWebAPIAdapter::VORDemodSCWebAPIAdapter() {} -VORDemodWebAPIAdapter::~VORDemodWebAPIAdapter() +VORDemodSCWebAPIAdapter::~VORDemodSCWebAPIAdapter() {} -int VORDemodWebAPIAdapter::webapiSettingsGet( +int VORDemodSCWebAPIAdapter::webapiSettingsGet( SWGSDRangel::SWGChannelSettings& response, QString& errorMessage) { @@ -38,7 +38,7 @@ int VORDemodWebAPIAdapter::webapiSettingsGet( return 200; } -int VORDemodWebAPIAdapter::webapiSettingsPutPatch( +int VORDemodSCWebAPIAdapter::webapiSettingsPutPatch( bool force, const QStringList& channelSettingsKeys, SWGSDRangel::SWGChannelSettings& response, diff --git a/plugins/channelrx/demodvor/vordemodwebapiadapter.h b/plugins/channelrx/demodvor/vordemodwebapiadapter.h index 94a1513d6..c2b7b60c3 100644 --- a/plugins/channelrx/demodvor/vordemodwebapiadapter.h +++ b/plugins/channelrx/demodvor/vordemodwebapiadapter.h @@ -16,8 +16,8 @@ // along with this program. If not, see . // /////////////////////////////////////////////////////////////////////////////////// -#ifndef INCLUDE_VORDEMOD_WEBAPIADAPTER_H -#define INCLUDE_VORDEMOD_WEBAPIADAPTER_H +#ifndef INCLUDE_VORDEMODSC_WEBAPIADAPTER_H +#define INCLUDE_VORDEMODSC_WEBAPIADAPTER_H #include "channel/channelwebapiadapter.h" #include "vordemodsettings.h" @@ -25,10 +25,10 @@ /** * Standalone API adapter only for the settings */ -class VORDemodWebAPIAdapter : public ChannelWebAPIAdapter { +class VORDemodSCWebAPIAdapter : public ChannelWebAPIAdapter { public: - VORDemodWebAPIAdapter(); - virtual ~VORDemodWebAPIAdapter(); + VORDemodSCWebAPIAdapter(); + virtual ~VORDemodSCWebAPIAdapter(); virtual QByteArray serialize() const { return m_settings.serialize(); } virtual bool deserialize(const QByteArray& data) { return m_settings.deserialize(data); } @@ -47,4 +47,4 @@ private: VORDemodSettings m_settings; }; -#endif // INCLUDE_VORDEMOD_WEBAPIADAPTER_H +#endif // INCLUDE_VORDEMODSC_WEBAPIADAPTER_H diff --git a/plugins/channelrx/demodvormc/CMakeLists.txt b/plugins/channelrx/demodvormc/CMakeLists.txt new file mode 100644 index 000000000..46490ec17 --- /dev/null +++ b/plugins/channelrx/demodvormc/CMakeLists.txt @@ -0,0 +1,70 @@ +project(vormc) + +set(vormc_SOURCES + vordemodmc.cpp + vordemodmcsettings.cpp + vordemodmcbaseband.cpp + vordemodmcsink.cpp + vordemodmcplugin.cpp + vordemodmcwebapiadapter.cpp + vordemodmcreport.cpp +) + +set(vormc_HEADERS + vordemodmc.h + vordemodmcsettings.h + vordemodmcbaseband.h + vordemodmcsink.h + vordemodmcplugin.h + vordemodmcwebapiadapter.h + vordemodmcreport.h +) + + +include_directories( + ${CMAKE_SOURCE_DIR}/swagger/sdrangel/code/qt5/client +) + +if(NOT SERVER_MODE) + set(vormc_SOURCES + ${vormc_SOURCES} + vordemodmcgui.cpp + vordemodmcgui.ui + map.qrc + icons.qrc + ) + set(vormc_HEADERS + ${vormc_HEADERS} + vordemodmcgui.h + navaid.h + ../demodadsb/csv.h + ) + + set(TARGET_NAME demodvormc) + set(TARGET_LIB "Qt5::Widgets" Qt5::Quick Qt5::QuickWidgets Qt5::Positioning) + set(TARGET_LIB_GUI "sdrgui") + set(INSTALL_FOLDER ${INSTALL_PLUGINS_DIR}) +else() + set(TARGET_NAME demodvormcsrv) + set(TARGET_LIB "") + set(TARGET_LIB_GUI "") + set(INSTALL_FOLDER ${INSTALL_PLUGINSSRV_DIR}) +endif() + +add_library(${TARGET_NAME} SHARED + ${vormc_SOURCES} +) + +target_link_libraries(${TARGET_NAME} + Qt5::Core + ${TARGET_LIB} + sdrbase + ${TARGET_LIB_GUI} +) + +install(TARGETS ${TARGET_NAME} DESTINATION ${INSTALL_FOLDER}) + +# Install debug symbols +if (WIN32) + install(FILES $ CONFIGURATIONS Debug RelWithDebInfo DESTINATION ${INSTALL_FOLDER} ) +endif() diff --git a/plugins/channelrx/demodvor/icons.qrc b/plugins/channelrx/demodvormc/icons.qrc similarity index 100% rename from plugins/channelrx/demodvor/icons.qrc rename to plugins/channelrx/demodvormc/icons.qrc diff --git a/plugins/channelrx/demodvor/icons/compass.png b/plugins/channelrx/demodvormc/icons/compass.png similarity index 100% rename from plugins/channelrx/demodvor/icons/compass.png rename to plugins/channelrx/demodvormc/icons/compass.png diff --git a/plugins/channelrx/demodvor/icons/vor.png b/plugins/channelrx/demodvormc/icons/vor.png similarity index 100% rename from plugins/channelrx/demodvor/icons/vor.png rename to plugins/channelrx/demodvormc/icons/vor.png diff --git a/plugins/channelrx/demodvor/map.qrc b/plugins/channelrx/demodvormc/map.qrc similarity index 100% rename from plugins/channelrx/demodvor/map.qrc rename to plugins/channelrx/demodvormc/map.qrc diff --git a/plugins/channelrx/demodvor/map/MapStation.qml b/plugins/channelrx/demodvormc/map/MapStation.qml similarity index 100% rename from plugins/channelrx/demodvor/map/MapStation.qml rename to plugins/channelrx/demodvormc/map/MapStation.qml diff --git a/plugins/channelrx/demodvor/map/VOR-DME.png b/plugins/channelrx/demodvormc/map/VOR-DME.png similarity index 100% rename from plugins/channelrx/demodvor/map/VOR-DME.png rename to plugins/channelrx/demodvormc/map/VOR-DME.png diff --git a/plugins/channelrx/demodvor/map/VOR.png b/plugins/channelrx/demodvormc/map/VOR.png similarity index 100% rename from plugins/channelrx/demodvor/map/VOR.png rename to plugins/channelrx/demodvormc/map/VOR.png diff --git a/plugins/channelrx/demodvor/map/VORTAC.png b/plugins/channelrx/demodvormc/map/VORTAC.png similarity index 100% rename from plugins/channelrx/demodvor/map/VORTAC.png rename to plugins/channelrx/demodvormc/map/VORTAC.png diff --git a/plugins/channelrx/demodvor/map/antenna.png b/plugins/channelrx/demodvormc/map/antenna.png similarity index 100% rename from plugins/channelrx/demodvor/map/antenna.png rename to plugins/channelrx/demodvormc/map/antenna.png diff --git a/plugins/channelrx/demodvor/map/map.qml b/plugins/channelrx/demodvormc/map/map.qml similarity index 100% rename from plugins/channelrx/demodvor/map/map.qml rename to plugins/channelrx/demodvormc/map/map.qml diff --git a/plugins/channelrx/demodvor/navaid.h b/plugins/channelrx/demodvormc/navaid.h similarity index 100% rename from plugins/channelrx/demodvor/navaid.h rename to plugins/channelrx/demodvormc/navaid.h diff --git a/plugins/channelrx/demodvormc/readme.md b/plugins/channelrx/demodvormc/readme.md new file mode 100644 index 000000000..de46fb5e0 --- /dev/null +++ b/plugins/channelrx/demodvormc/readme.md @@ -0,0 +1,91 @@ +

VOR demodulator plugin

+ +

Introduction

+ +This plugin can be used to demodulate VOR (VHF omnidirectional range) navaids (navigation aids). VORs are radio naviation aids in the VHF 108 - 117.975MHz band commonly used for aircraft navigation. + +VORs transmit two 30Hz signals, one AM at the VOR center frequency and one FM on a 9960Hz sub-carrier. The FM reference signal's phase is set so 0 degrees corresponds to magnetic north from the VOR (Some VORs at high latitudes use true North). The phase of the AM variable signal is such that the phase difference to the reference signal corresponds to the bearing from the VOR to the receiver. For example, if a receiver is North from the VOR, the AM and FM 30Hz signals will be received in phase. If a receiver is East from the VOR, the phase difference will be 90 degrees. + +VORs also transmit a Morse code ident signal at a 1020Hz offset. This is a 2 or 3 character identifier used to identify the VOR, as multiple VORs can be transmitted on the same frequency. For example, the VOR at London Heathrow transmits .-.. --- -. for LON. The Morse code ident is typically transmitted at 10 seconds intervals at between 7 and 10 wpm. VORs that are under maintainance may transmit TST. + +Some VORs also transmit an AM voice identification or information signal between 300-3kHz. + +This plugin can demodulate all four signals from multiple VORs simultaneously, allowing your position to be determined and plotted on a map. It can also demodulate the Morse code ident signal and and check they are correct for each VOR. The Morse code ident and any voice signal will also be heard as audio. + +Note that for aircraft, there is typically a direct line-of-sight to the VOR. This is unlikely to be the case when using an SDR on the ground. To get good results, ideally you want to be on a nice high hill or close to the VOR. + +

Interface

+ +The top and bottom bars of the channel window are described [here](../../../sdrgui/channel/readme.md) + +![VOR Demodulator plugin GUI](../../../doc/img/VORDemod_plugin.png) + +

1: Level meter in dB

+ + - top bar (green): average value + - bottom bar (blue green): instantaneous peak value + - tip vertical bar (bright green): peak hold value + +

2: Channel power

+ +Average total power in dB relative to a +/- 1.0 amplitude signal received in the pass band. + +

3: Audio mute and audio output select

+ +Left click on this button to toggle audio mute for this channel. The button will light up in green if the squelch is open. This helps identifying which channels are active in a multi-channel configuration. + +If you right click on it it will open a dialog to select the audio output device. See [audio management documentation](../../../sdrgui/audio.md) for details. + +

4: Download VOR Database

+ +Pressing this button downloads the OpenAIP.net Navaid database, which contains the details (position, frequencies, name and ident) for each VOR. This needs to be performed at least once. + +

5: Draw Radials Adjusted for Magnetic Declination

+ +When checked, radials on the map will drawn adjusted for magnetic declination. For example, if a VOR has a magnetic declination of 5 degrees, and the radial is calculated at 0 degrees, the radial will be drawn to magnetic North, i.e. -5 degress from true North. If not checked, the same radial would be drawn to true North (i.e 0 degrees), which may result in a less accurate position estimate. + +

6: Morse ident threshold

+ +This is the Morse code ident threshold, expressed as a linear signal to noise (SNR) ratio. This is effectively the signal level required for the Morse demodulator to detect a dot or dash. Setting this to low values will allow the Morse demodulator to detect weak signals, but it also increases the likelyhood that noise will incorrectly be interpreted as a signal, resulting in invalid idents being reported. + +

7: Squelch threshold

+ +This is the squelch threshold in dB. The average total power received in the signal bandwidth before demodulation is compared to this value and the squelch input is open above this value. It can be varied continuously in 0.1 dB steps from 0.0 to -100.0 dB using the dial button. + +

8: Volume

+ +This is the volume of the audio signal from 0.0 (mute) to 10.0 (maximum). It can be varied continuously in 0.1 steps using the dial button. + +

VOR Table

+ +The VOR table displays information about selected VORs. To select or deselect a VOR, double click it on the map. The information displayed includes: + +![VOR Demodulator Table](../../../doc/img/VORDemod_plugin_table.png) + +* Name - The name of the VOR. For example: 'LONDON'. +* Freq (MHz) - The center frequency the VOR transmits on in MHz. +* Offset (kHz) - This is the current difference between the VOR's center frequency and SDRangle's device center frequency. If displayed in red, the VOR is out of range and it's signal will not be able to be received. +* Ident - A 2 or 3 character identifier for the VOR. For example: 'LON'. +* Morse - The Morse code identifier for the VOR. For example: '.-.. --- -.' +* RX Ident - This contains the demodulated ident. If it matches the expected ident, it will be displayed in green, if not, it will be displayed in red. If an ident is received that is not 2 or 3 characters, it will not be displayed, but the last received ident will be displayed in yellow. +* RX Morse - This contains the demodulated Morse code ident. Colour coding is as for RX Ident. +* Radial - This contains the demodulated radial direction in degrees (unadjusted for magnetic declination). If there is a low confidence the value is correct (due to a weak signal), it will be displayed in red. +* Ref (dB) - This displays the magnitude of the received 30Hz FM reference signal in dB. +* Var (dB) - This displays the mangitude of the received 30Hz AM variable signal in dB. +* Mute - This button allows you to mute or unmute the audio from the corresponding VOR. + +

Map

+ +The map displays the locations of each VOR, with an information box containing the information about the VOR, such as it's name, frequency, ident (in text and Morse), range and magnetic declination. + +To initialise the VORs on the map, first set your position using the Preferences > My position menu, then open the VOR Demodulator channel (close and reopen it, if already open). Then press the Download VOR Database button (This only needs to be performed once). The map should then display VORs in your vicinity. + +Double clicking on a VOR will select and add it to the list of VORs to demodulate. It will be added to the VOR table and will be highlighted green. Double clicking a selected VOR, will remove it from the list of VORs to demodulate and it will be removed from the VOR table. + +When a signal from a VOR is correctly being demodulated, a radial line will be drawn on the map, at the angle corresponding to the phase difference between the AM and FM 30Hz signals. Your receiver should be somewhere along this radial line. The length of the radial line is set according to the range of the VOR as recorded in the database, which is valid for aircraft at altitude. Range on the ground will be considerably less. An approximate position for the receiver is where the radial lines from two or more VORs intersect. + +![VOR Demodulator Map](../../../doc/img/VORDemod_plugin_map.png) + +

Attribution

+ +Icons by Denelson83 and mamayer, via Wikimedia Commons and RULI from the Noun Project https://thenounproject.com/ diff --git a/plugins/channelrx/demodvorsc/vordemodsc.cpp b/plugins/channelrx/demodvormc/vordemodmc.cpp similarity index 57% rename from plugins/channelrx/demodvorsc/vordemodsc.cpp rename to plugins/channelrx/demodvormc/vordemodmc.cpp index a373394ba..ff6f1a972 100644 --- a/plugins/channelrx/demodvorsc/vordemodsc.cpp +++ b/plugins/channelrx/demodvormc/vordemodmc.cpp @@ -16,6 +16,8 @@ // along with this program. If not, see . // /////////////////////////////////////////////////////////////////////////////////// +#include "vordemodmc.h" + #include #include #include @@ -39,23 +41,19 @@ #include "util/db.h" #include "maincore.h" -#include "vordemodscreport.h" -#include "vordemodsc.h" +MESSAGE_CLASS_DEFINITION(VORDemodMC::MsgConfigureVORDemod, Message) -MESSAGE_CLASS_DEFINITION(VORDemodSC::MsgConfigureVORDemod, Message) +const char * const VORDemodMC::m_channelIdURI = "sdrangel.channel.vordemodmc"; +const char * const VORDemodMC::m_channelId = "VORDemodMC"; -const char * const VORDemodSC::m_channelIdURI = "sdrangel.channel.vordemodsc"; -const char * const VORDemodSC::m_channelId = "VORDemodSC"; - -VORDemodSC::VORDemodSC(DeviceAPI *deviceAPI) : +VORDemodMC::VORDemodMC(DeviceAPI *deviceAPI) : ChannelAPI(m_channelIdURI, ChannelAPI::StreamSingleSink), m_deviceAPI(deviceAPI), m_basebandSampleRate(0) { setObjectName(m_channelId); - m_basebandSink = new VORDemodSCBaseband(); - m_basebandSink->setMessageQueueToChannel(getInputMessageQueue()); + m_basebandSink = new VORDemodMCBaseband(); m_basebandSink->moveToThread(&m_thread); applySettings(m_settings, true); @@ -68,24 +66,24 @@ VORDemodSC::VORDemodSC(DeviceAPI *deviceAPI) : m_networkManager, &QNetworkAccessManager::finished, this, - &VORDemodSC::networkManagerFinished + &VORDemodMC::networkManagerFinished ); QObject::connect( this, &ChannelAPI::indexInDeviceSetChanged, this, - &VORDemodSC::handleIndexInDeviceSetChanged + &VORDemodMC::handleIndexInDeviceSetChanged ); } -VORDemodSC::~VORDemodSC() +VORDemodMC::~VORDemodMC() { - qDebug("VORDemodSC::~VORDemodSC"); + qDebug("VORDemodMC::~VORDemodMC"); QObject::disconnect( m_networkManager, &QNetworkAccessManager::finished, this, - &VORDemodSC::networkManagerFinished + &VORDemodMC::networkManagerFinished ); delete m_networkManager; m_deviceAPI->removeChannelSinkAPI(this); @@ -98,20 +96,32 @@ VORDemodSC::~VORDemodSC() delete m_basebandSink; } -uint32_t VORDemodSC::getNumberOfDeviceStreams() const +void VORDemodMC::setDeviceAPI(DeviceAPI *deviceAPI) +{ + if (deviceAPI != m_deviceAPI) + { + m_deviceAPI->removeChannelSinkAPI(this); + m_deviceAPI->removeChannelSink(this); + m_deviceAPI = deviceAPI; + m_deviceAPI->addChannelSink(this); + m_deviceAPI->addChannelSinkAPI(this); + } +} + +uint32_t VORDemodMC::getNumberOfDeviceStreams() const { return m_deviceAPI->getNbSourceStreams(); } -void VORDemodSC::feed(const SampleVector::const_iterator& begin, const SampleVector::const_iterator& end, bool firstOfBurst) +void VORDemodMC::feed(const SampleVector::const_iterator& begin, const SampleVector::const_iterator& end, bool firstOfBurst) { (void) firstOfBurst; m_basebandSink->feed(begin, end); } -void VORDemodSC::start() +void VORDemodMC::start() { - qDebug("VORDemodSC::start"); + qDebug("VORDemodMC::start"); m_basebandSink->reset(); m_basebandSink->startWork(); @@ -120,24 +130,24 @@ void VORDemodSC::start() DSPSignalNotification *dspMsg = new DSPSignalNotification(m_basebandSampleRate, m_centerFrequency); m_basebandSink->getInputMessageQueue()->push(dspMsg); - VORDemodSCBaseband::MsgConfigureVORDemodBaseband *msg = VORDemodSCBaseband::MsgConfigureVORDemodBaseband::create(m_settings, true); + VORDemodMCBaseband::MsgConfigureVORDemodBaseband *msg = VORDemodMCBaseband::MsgConfigureVORDemodBaseband::create(m_settings, true); m_basebandSink->getInputMessageQueue()->push(msg); } -void VORDemodSC::stop() +void VORDemodMC::stop() { - qDebug("VORDemodSC::stop"); + qDebug("VORDemodMC::stop"); m_basebandSink->stopWork(); m_thread.quit(); m_thread.wait(); } -bool VORDemodSC::handleMessage(const Message& cmd) +bool VORDemodMC::handleMessage(const Message& cmd) { if (MsgConfigureVORDemod::match(cmd)) { MsgConfigureVORDemod& cfg = (MsgConfigureVORDemod&) cmd; - qDebug() << "VORDemodSC::handleMessage: MsgConfigureVORDemod"; + qDebug() << "VORDemodMC::handleMessage: MsgConfigureVORDemod"; applySettings(cfg.getSettings(), cfg.getForce()); return true; @@ -149,57 +159,11 @@ bool VORDemodSC::handleMessage(const Message& cmd) m_centerFrequency = notif.getCenterFrequency(); // Forward to the sink DSPSignalNotification* rep = new DSPSignalNotification(notif); // make a copy - qDebug() << "VORDemodSC::handleMessage: DSPSignalNotification"; + qDebug() << "VORDemodMC::handleMessage: DSPSignalNotification"; m_basebandSink->getInputMessageQueue()->push(rep); // Forward to GUI if any - if (m_guiMessageQueue) - { - rep = new DSPSignalNotification(notif); - m_guiMessageQueue->push(rep); - } - - return true; - } - else if (VORDemodSCReport::MsgReportRadial::match(cmd)) - { - VORDemodSCReport::MsgReportRadial& report = (VORDemodSCReport::MsgReportRadial&) cmd; - m_radial = report.getRadial(); - m_refMag = report.getRefMag(); - m_varMag = report.getVarMag(); - - if (m_guiMessageQueue) - { - VORDemodSCReport::MsgReportRadial *msg = new VORDemodSCReport::MsgReportRadial(report); - m_guiMessageQueue->push(msg); - } - - MessagePipes& messagePipes = MainCore::instance()->getMessagePipes(); - QList pipes; - messagePipes.getMessagePipes(this, "report", pipes); - - if (pipes.size() > 0) { - sendChannelReport(pipes); - } - - return true; - } - else if (VORDemodSCReport::MsgReportIdent::match(cmd)) - { - VORDemodSCReport::MsgReportIdent& report = (VORDemodSCReport::MsgReportIdent&) cmd; - m_morseIdent = report.getIdent(); - - if (m_guiMessageQueue) - { - VORDemodSCReport::MsgReportIdent *msg = new VORDemodSCReport::MsgReportIdent(report); - m_guiMessageQueue->push(msg); - } - - MessagePipes& messagePipes = MainCore::instance()->getMessagePipes(); - QList pipes; - messagePipes.getMessagePipes(this, "report", pipes); - - if (pipes.size() > 0) { - sendChannelReport(pipes); + if (m_guiMessageQueue) { + m_guiMessageQueue->push(new DSPSignalNotification(notif)); } return true; @@ -210,24 +174,9 @@ bool VORDemodSC::handleMessage(const Message& cmd) } } -void VORDemodSC::setCenterFrequency(qint64 frequency) +void VORDemodMC::applySettings(const VORDemodMCSettings& settings, bool force) { - VORDemodSCSettings settings = m_settings; - settings.m_inputFrequencyOffset = frequency; - applySettings(settings, false); - - if (m_guiMessageQueue) // forward to GUI if any - { - MsgConfigureVORDemod *msgToGUI = MsgConfigureVORDemod::create(settings, false); - m_guiMessageQueue->push(msgToGUI); - } -} - -void VORDemodSC::applySettings(const VORDemodSCSettings& settings, bool force) -{ - qDebug() << "VORDemodSC::applySettings:" - << " m_inputFrequencyOffset: " << settings.m_inputFrequencyOffset - << " m_navId: " << settings.m_navId + qDebug() << "VORDemodMC::applySettings:" << " m_volume: " << settings.m_volume << " m_squelch: " << settings.m_squelch << " m_audioMute: " << settings.m_audioMute @@ -242,12 +191,6 @@ void VORDemodSC::applySettings(const VORDemodSCSettings& settings, bool force) QList reverseAPIKeys; - if ((m_settings.m_inputFrequencyOffset != settings.m_inputFrequencyOffset) || force) { - reverseAPIKeys.append("inputFrequencyOffset"); - } - if ((m_settings.m_navId != settings.m_navId) || force) { - reverseAPIKeys.append("navId"); - } if ((m_settings.m_squelch != settings.m_squelch) || force) { reverseAPIKeys.append("squelch"); } @@ -280,7 +223,11 @@ void VORDemodSC::applySettings(const VORDemodSCSettings& settings, bool force) reverseAPIKeys.append("identThreshold"); } - VORDemodSCBaseband::MsgConfigureVORDemodBaseband *msg = VORDemodSCBaseband::MsgConfigureVORDemodBaseband::create(settings, force); + if ((m_settings.m_magDecAdjust != settings.m_magDecAdjust) || force) { + reverseAPIKeys.append("magDecAdjust"); + } + + VORDemodMCBaseband::MsgConfigureVORDemodBaseband *msg = VORDemodMCBaseband::MsgConfigureVORDemodBaseband::create(settings, force); m_basebandSink->getInputMessageQueue()->push(msg); if (settings.m_useReverseAPI) @@ -303,12 +250,12 @@ void VORDemodSC::applySettings(const VORDemodSCSettings& settings, bool force) m_settings = settings; } -QByteArray VORDemodSC::serialize() const +QByteArray VORDemodMC::serialize() const { return m_settings.serialize(); } -bool VORDemodSC::deserialize(const QByteArray& data) +bool VORDemodMC::deserialize(const QByteArray& data) { if (m_settings.deserialize(data)) { @@ -325,31 +272,31 @@ bool VORDemodSC::deserialize(const QByteArray& data) } } -int VORDemodSC::webapiSettingsGet( +int VORDemodMC::webapiSettingsGet( SWGSDRangel::SWGChannelSettings& response, QString& errorMessage) { (void) errorMessage; - response.setVorDemodScSettings(new SWGSDRangel::SWGVORDemodSCSettings()); - response.getVorDemodScSettings()->init(); + response.setVorDemodMcSettings(new SWGSDRangel::SWGVORDemodMCSettings()); + response.getVorDemodMcSettings()->init(); webapiFormatChannelSettings(response, m_settings); return 200; } -int VORDemodSC::webapiSettingsPutPatch( +int VORDemodMC::webapiSettingsPutPatch( bool force, const QStringList& channelSettingsKeys, SWGSDRangel::SWGChannelSettings& response, QString& errorMessage) { (void) errorMessage; - VORDemodSCSettings settings = m_settings; + VORDemodMCSettings settings = m_settings; webapiUpdateChannelSettings(settings, channelSettingsKeys, response); MsgConfigureVORDemod *msg = MsgConfigureVORDemod::create(settings, force); m_inputMessageQueue.push(msg); - qDebug("VORDemodSC::webapiSettingsPutPatch: forward to GUI: %p", m_guiMessageQueue); + qDebug("VORDemodMC::webapiSettingsPutPatch: forward to GUI: %p", m_guiMessageQueue); if (m_guiMessageQueue) // forward to GUI if any { MsgConfigureVORDemod *msgToGUI = MsgConfigureVORDemod::create(settings, force); @@ -361,168 +308,149 @@ int VORDemodSC::webapiSettingsPutPatch( return 200; } -void VORDemodSC::webapiUpdateChannelSettings( - VORDemodSCSettings& settings, +void VORDemodMC::webapiUpdateChannelSettings( + VORDemodMCSettings& settings, const QStringList& channelSettingsKeys, SWGSDRangel::SWGChannelSettings& response) { - if (channelSettingsKeys.contains("inputFrequencyOffset")) { - settings.m_inputFrequencyOffset = response.getVorDemodScSettings()->getInputFrequencyOffset(); - } - if (channelSettingsKeys.contains("navId")) { - settings.m_navId = response.getVorDemodScSettings()->getNavId(); - } if (channelSettingsKeys.contains("audioMute")) { - settings.m_audioMute = response.getVorDemodScSettings()->getAudioMute() != 0; + settings.m_audioMute = response.getVorDemodMcSettings()->getAudioMute() != 0; } if (channelSettingsKeys.contains("rgbColor")) { - settings.m_rgbColor = response.getVorDemodScSettings()->getRgbColor(); + settings.m_rgbColor = response.getVorDemodMcSettings()->getRgbColor(); } if (channelSettingsKeys.contains("squelch")) { - settings.m_squelch = response.getVorDemodScSettings()->getSquelch(); + settings.m_squelch = response.getVorDemodMcSettings()->getSquelch(); } if (channelSettingsKeys.contains("title")) { - settings.m_title = *response.getVorDemodScSettings()->getTitle(); + settings.m_title = *response.getVorDemodMcSettings()->getTitle(); } if (channelSettingsKeys.contains("volume")) { - settings.m_volume = response.getVorDemodScSettings()->getVolume(); + settings.m_volume = response.getVorDemodMcSettings()->getVolume(); } if (channelSettingsKeys.contains("audioDeviceName")) { - settings.m_audioDeviceName = *response.getVorDemodScSettings()->getAudioDeviceName(); + settings.m_audioDeviceName = *response.getVorDemodMcSettings()->getAudioDeviceName(); } + if (channelSettingsKeys.contains("streamIndex")) { - settings.m_streamIndex = response.getVorDemodScSettings()->getStreamIndex(); + settings.m_streamIndex = response.getVorDemodMcSettings()->getStreamIndex(); } if (channelSettingsKeys.contains("useReverseAPI")) { - settings.m_useReverseAPI = response.getVorDemodScSettings()->getUseReverseApi() != 0; + settings.m_useReverseAPI = response.getVorDemodMcSettings()->getUseReverseApi() != 0; } if (channelSettingsKeys.contains("reverseAPIAddress")) { - settings.m_reverseAPIAddress = *response.getVorDemodScSettings()->getReverseApiAddress(); + settings.m_reverseAPIAddress = *response.getVorDemodMcSettings()->getReverseApiAddress(); } if (channelSettingsKeys.contains("reverseAPIPort")) { - settings.m_reverseAPIPort = response.getVorDemodScSettings()->getReverseApiPort(); + settings.m_reverseAPIPort = response.getVorDemodMcSettings()->getReverseApiPort(); } if (channelSettingsKeys.contains("reverseAPIDeviceIndex")) { - settings.m_reverseAPIDeviceIndex = response.getVorDemodScSettings()->getReverseApiDeviceIndex(); + settings.m_reverseAPIDeviceIndex = response.getVorDemodMcSettings()->getReverseApiDeviceIndex(); } if (channelSettingsKeys.contains("reverseAPIChannelIndex")) { - settings.m_reverseAPIChannelIndex = response.getVorDemodScSettings()->getReverseApiChannelIndex(); + settings.m_reverseAPIChannelIndex = response.getVorDemodMcSettings()->getReverseApiChannelIndex(); } if (channelSettingsKeys.contains("identThreshold")) { - settings.m_identThreshold = response.getVorDemodScSettings()->getIdentThreshold(); + settings.m_identThreshold = response.getVorDemodMcSettings()->getIdentThreshold(); + } + if (channelSettingsKeys.contains("magDecAdjust")) { + settings.m_magDecAdjust = response.getVorDemodMcSettings()->getMagDecAdjust() != 0; } if (settings.m_channelMarker && channelSettingsKeys.contains("channelMarker")) { - settings.m_channelMarker->updateFrom(channelSettingsKeys, response.getVorDemodScSettings()->getChannelMarker()); + settings.m_channelMarker->updateFrom(channelSettingsKeys, response.getVorDemodMcSettings()->getChannelMarker()); } if (settings.m_rollupState && channelSettingsKeys.contains("rollupState")) { - settings.m_rollupState->updateFrom(channelSettingsKeys, response.getVorDemodScSettings()->getRollupState()); + settings.m_rollupState->updateFrom(channelSettingsKeys, response.getVorDemodMcSettings()->getRollupState()); } } -int VORDemodSC::webapiReportGet( +int VORDemodMC::webapiReportGet( SWGSDRangel::SWGChannelReport& response, QString& errorMessage) { (void) errorMessage; - response.setVorDemodScReport(new SWGSDRangel::SWGVORDemodSCReport()); - response.getVorDemodScReport()->init(); + response.setVorDemodMcReport(new SWGSDRangel::SWGVORDemodMCReport()); + response.getVorDemodMcReport()->init(); webapiFormatChannelReport(response); return 200; } -void VORDemodSC::webapiFormatChannelSettings(SWGSDRangel::SWGChannelSettings& response, const VORDemodSCSettings& settings) +void VORDemodMC::webapiFormatChannelSettings(SWGSDRangel::SWGChannelSettings& response, const VORDemodMCSettings& settings) { - response.getVorDemodScSettings()->setInputFrequencyOffset(settings.m_inputFrequencyOffset); - response.getVorDemodScSettings()->setNavId(settings.m_navId); - response.getVorDemodScSettings()->setAudioMute(settings.m_audioMute ? 1 : 0); - response.getVorDemodScSettings()->setRgbColor(settings.m_rgbColor); - response.getVorDemodScSettings()->setSquelch(settings.m_squelch); - response.getVorDemodScSettings()->setVolume(settings.m_volume); + response.getVorDemodMcSettings()->setAudioMute(settings.m_audioMute ? 1 : 0); + response.getVorDemodMcSettings()->setRgbColor(settings.m_rgbColor); + response.getVorDemodMcSettings()->setSquelch(settings.m_squelch); + response.getVorDemodMcSettings()->setVolume(settings.m_volume); - if (response.getVorDemodScSettings()->getTitle()) { - *response.getVorDemodScSettings()->getTitle() = settings.m_title; + if (response.getVorDemodMcSettings()->getTitle()) { + *response.getVorDemodMcSettings()->getTitle() = settings.m_title; } else { - response.getVorDemodScSettings()->setTitle(new QString(settings.m_title)); + response.getVorDemodMcSettings()->setTitle(new QString(settings.m_title)); } - if (response.getVorDemodScSettings()->getAudioDeviceName()) { - *response.getVorDemodScSettings()->getAudioDeviceName() = settings.m_audioDeviceName; + if (response.getVorDemodMcSettings()->getAudioDeviceName()) { + *response.getVorDemodMcSettings()->getAudioDeviceName() = settings.m_audioDeviceName; } else { - response.getVorDemodScSettings()->setAudioDeviceName(new QString(settings.m_audioDeviceName)); + response.getVorDemodMcSettings()->setAudioDeviceName(new QString(settings.m_audioDeviceName)); } - response.getVorDemodScSettings()->setStreamIndex(settings.m_streamIndex); - response.getVorDemodScSettings()->setUseReverseApi(settings.m_useReverseAPI ? 1 : 0); + response.getVorDemodMcSettings()->setStreamIndex(settings.m_streamIndex); + response.getVorDemodMcSettings()->setUseReverseApi(settings.m_useReverseAPI ? 1 : 0); - if (response.getVorDemodScSettings()->getReverseApiAddress()) { - *response.getVorDemodScSettings()->getReverseApiAddress() = settings.m_reverseAPIAddress; + if (response.getVorDemodMcSettings()->getReverseApiAddress()) { + *response.getVorDemodMcSettings()->getReverseApiAddress() = settings.m_reverseAPIAddress; } else { - response.getVorDemodScSettings()->setReverseApiAddress(new QString(settings.m_reverseAPIAddress)); + response.getVorDemodMcSettings()->setReverseApiAddress(new QString(settings.m_reverseAPIAddress)); } - response.getVorDemodScSettings()->setReverseApiPort(settings.m_reverseAPIPort); - response.getVorDemodScSettings()->setReverseApiDeviceIndex(settings.m_reverseAPIDeviceIndex); - response.getVorDemodScSettings()->setReverseApiChannelIndex(settings.m_reverseAPIChannelIndex); - response.getVorDemodScSettings()->setIdentThreshold(settings.m_identThreshold); + response.getVorDemodMcSettings()->setReverseApiPort(settings.m_reverseAPIPort); + response.getVorDemodMcSettings()->setReverseApiDeviceIndex(settings.m_reverseAPIDeviceIndex); + response.getVorDemodMcSettings()->setReverseApiChannelIndex(settings.m_reverseAPIChannelIndex); + + response.getVorDemodMcSettings()->setIdentThreshold(settings.m_identThreshold); + response.getVorDemodMcSettings()->setMagDecAdjust(settings.m_magDecAdjust ? 1 : 0); if (settings.m_channelMarker) { - if (response.getVorDemodScSettings()->getChannelMarker()) + if (response.getVorDemodMcSettings()->getChannelMarker()) { - settings.m_channelMarker->formatTo(response.getVorDemodScSettings()->getChannelMarker()); + settings.m_channelMarker->formatTo(response.getVorDemodMcSettings()->getChannelMarker()); } else { SWGSDRangel::SWGChannelMarker *swgChannelMarker = new SWGSDRangel::SWGChannelMarker(); settings.m_channelMarker->formatTo(swgChannelMarker); - response.getVorDemodScSettings()->setChannelMarker(swgChannelMarker); + response.getVorDemodMcSettings()->setChannelMarker(swgChannelMarker); } } if (settings.m_rollupState) { - if (response.getVorDemodScSettings()->getRollupState()) + if (response.getVorDemodMcSettings()->getRollupState()) { - settings.m_rollupState->formatTo(response.getVorDemodScSettings()->getRollupState()); + settings.m_rollupState->formatTo(response.getVorDemodMcSettings()->getRollupState()); } else { SWGSDRangel::SWGRollupState *swgRollupState = new SWGSDRangel::SWGRollupState(); settings.m_rollupState->formatTo(swgRollupState); - response.getVorDemodScSettings()->setRollupState(swgRollupState); + response.getVorDemodMcSettings()->setRollupState(swgRollupState); } } } -void VORDemodSC::webapiFormatChannelReport(SWGSDRangel::SWGChannelReport& response) +void VORDemodMC::webapiFormatChannelReport(SWGSDRangel::SWGChannelReport& response) { double magsqAvg, magsqPeak; int nbMagsqSamples; getMagSqLevels(magsqAvg, magsqPeak, nbMagsqSamples); - response.getVorDemodScReport()->setChannelPowerDb(CalcDb::dbPower(magsqAvg)); - response.getVorDemodScReport()->setSquelch(m_basebandSink->getSquelchOpen() ? 1 : 0); - response.getVorDemodScReport()->setAudioSampleRate(m_basebandSink->getAudioSampleRate()); - response.getVorDemodScReport()->setNavId(m_settings.m_navId); - response.getVorDemodScReport()->setRadial(m_radial); - response.getVorDemodScReport()->setRefMag(m_refMag); - response.getVorDemodScReport()->setVarMag(m_varMag); - float refMagDB = std::round(20.0*std::log10(m_refMag)); - float varMagDB = std::round(20.0*std::log10(m_varMag)); - bool validRefMag = refMagDB > m_settings.m_refThresholdDB; - bool validVarMag = varMagDB > m_settings.m_varThresholdDB; - response.getVorDemodScReport()->setValidRadial(validRefMag && validVarMag ? 1 : 0); - response.getVorDemodScReport()->setValidRefMag(validRefMag ? 1 : 0); - response.getVorDemodScReport()->setValidVarMag(validVarMag ? 1 : 0); - - if (response.getVorDemodScReport()->getMorseIdent()) { - *response.getVorDemodScReport()->getMorseIdent() = m_morseIdent; - } else { - response.getVorDemodScReport()->setMorseIdent(new QString(m_morseIdent)); - } + response.getVorDemodMcReport()->setChannelPowerDb(CalcDb::dbPower(magsqAvg)); + response.getVorDemodMcReport()->setSquelch(m_basebandSink->getSquelchOpen() ? 1 : 0); + response.getVorDemodMcReport()->setAudioSampleRate(m_basebandSink->getAudioSampleRate()); } -void VORDemodSC::webapiReverseSendSettings(QList& channelSettingsKeys, const VORDemodSCSettings& settings, bool force) +void VORDemodMC::webapiReverseSendSettings(QList& channelSettingsKeys, const VORDemodMCSettings& settings, bool force) { SWGSDRangel::SWGChannelSettings *swgChannelSettings = new SWGSDRangel::SWGChannelSettings(); webapiFormatChannelSettings(channelSettingsKeys, swgChannelSettings, settings, force); @@ -547,10 +475,10 @@ void VORDemodSC::webapiReverseSendSettings(QList& channelSettingsKeys, delete swgChannelSettings; } -void VORDemodSC::sendChannelSettings( +void VORDemodMC::sendChannelSettings( const QList& pipes, QList& channelSettingsKeys, - const VORDemodSCSettings& settings, + const VORDemodMCSettings& settings, bool force) { for (const auto& pipe : pipes) @@ -572,94 +500,72 @@ void VORDemodSC::sendChannelSettings( } } -void VORDemodSC::sendChannelReport(QList& messagePipes) -{ - for (const auto& pipe : messagePipes) - { - MessageQueue *messageQueue = qobject_cast(pipe->m_element); - - if (messageQueue) - { - SWGSDRangel::SWGChannelReport *swgChannelReport = new SWGSDRangel::SWGChannelReport(); - swgChannelReport->setDirection(0); - swgChannelReport->setChannelType(new QString(m_channelId)); - swgChannelReport->setVorDemodScReport(new SWGSDRangel::SWGVORDemodSCReport()); - webapiFormatChannelReport(*swgChannelReport); - MainCore::MsgChannelReport *msg = MainCore::MsgChannelReport::create(this, swgChannelReport); - messageQueue->push(msg); - } - } -} - -void VORDemodSC::webapiFormatChannelSettings( +void VORDemodMC::webapiFormatChannelSettings( QList& channelSettingsKeys, SWGSDRangel::SWGChannelSettings *swgChannelSettings, - const VORDemodSCSettings& settings, + const VORDemodMCSettings& settings, bool force ) { swgChannelSettings->setDirection(0); // Single sink (Rx) swgChannelSettings->setOriginatorChannelIndex(getIndexInDeviceSet()); swgChannelSettings->setOriginatorDeviceSetIndex(getDeviceSetIndex()); - swgChannelSettings->setChannelType(new QString("VORDemodSC")); - swgChannelSettings->setVorDemodScSettings(new SWGSDRangel::SWGVORDemodSCSettings()); - SWGSDRangel::SWGVORDemodSCSettings *swgVORDemodSCSettings = swgChannelSettings->getVorDemodScSettings(); + swgChannelSettings->setChannelType(new QString("VORDemodMC")); + swgChannelSettings->setVorDemodMcSettings(new SWGSDRangel::SWGVORDemodMCSettings()); + SWGSDRangel::SWGVORDemodMCSettings *swgVORDemodSettings = swgChannelSettings->getVorDemodMcSettings(); // transfer data that has been modified. When force is on transfer all data except reverse API data - if (channelSettingsKeys.contains("inputFrequencyOffset") || force) { - swgVORDemodSCSettings->setInputFrequencyOffset(settings.m_inputFrequencyOffset); - } - if (channelSettingsKeys.contains("navId") || force) { - swgVORDemodSCSettings->setNavId(settings.m_navId); - } if (channelSettingsKeys.contains("audioMute") || force) { - swgVORDemodSCSettings->setAudioMute(settings.m_audioMute ? 1 : 0); + swgVORDemodSettings->setAudioMute(settings.m_audioMute ? 1 : 0); } if (channelSettingsKeys.contains("rgbColor") || force) { - swgVORDemodSCSettings->setRgbColor(settings.m_rgbColor); + swgVORDemodSettings->setRgbColor(settings.m_rgbColor); } if (channelSettingsKeys.contains("squelch") || force) { - swgVORDemodSCSettings->setSquelch(settings.m_squelch); + swgVORDemodSettings->setSquelch(settings.m_squelch); } if (channelSettingsKeys.contains("title") || force) { - swgVORDemodSCSettings->setTitle(new QString(settings.m_title)); + swgVORDemodSettings->setTitle(new QString(settings.m_title)); } if (channelSettingsKeys.contains("volume") || force) { - swgVORDemodSCSettings->setVolume(settings.m_volume); + swgVORDemodSettings->setVolume(settings.m_volume); } if (channelSettingsKeys.contains("audioDeviceName") || force) { - swgVORDemodSCSettings->setAudioDeviceName(new QString(settings.m_audioDeviceName)); + swgVORDemodSettings->setAudioDeviceName(new QString(settings.m_audioDeviceName)); } if (channelSettingsKeys.contains("streamIndex") || force) { - swgVORDemodSCSettings->setStreamIndex(settings.m_streamIndex); + swgVORDemodSettings->setStreamIndex(settings.m_streamIndex); } if (channelSettingsKeys.contains("identThreshold") || force) { - swgVORDemodSCSettings->setAudioMute(settings.m_identThreshold); + swgVORDemodSettings->setIdentThreshold(settings.m_identThreshold); + } + if (channelSettingsKeys.contains("magDecAdjust") || force) { + swgVORDemodSettings->setMagDecAdjust(settings.m_magDecAdjust ? 1 : 0); } if (settings.m_channelMarker && (channelSettingsKeys.contains("channelMarker") || force)) { SWGSDRangel::SWGChannelMarker *swgChannelMarker = new SWGSDRangel::SWGChannelMarker(); settings.m_channelMarker->formatTo(swgChannelMarker); - swgVORDemodSCSettings->setChannelMarker(swgChannelMarker); + swgVORDemodSettings->setChannelMarker(swgChannelMarker); } if (settings.m_rollupState && (channelSettingsKeys.contains("rollupState") || force)) { SWGSDRangel::SWGRollupState *swgRollupState = new SWGSDRangel::SWGRollupState(); settings.m_rollupState->formatTo(swgRollupState); - swgVORDemodSCSettings->setRollupState(swgRollupState); + swgVORDemodSettings->setRollupState(swgRollupState); } } -void VORDemodSC::networkManagerFinished(QNetworkReply *reply) +void VORDemodMC::networkManagerFinished(QNetworkReply *reply) { QNetworkReply::NetworkError replyError = reply->error(); if (replyError) { - qWarning() << "VORDemodSC::networkManagerFinished:" + qWarning() << "VORDemodMC::networkManagerFinished:" << " error(" << (int) replyError << "): " << replyError << ": " << reply->errorString(); @@ -668,13 +574,13 @@ void VORDemodSC::networkManagerFinished(QNetworkReply *reply) { QString answer = reply->readAll(); answer.chop(1); // remove last \n - qDebug("VORDemodSC::networkManagerFinished: reply:\n%s", answer.toStdString().c_str()); + qDebug("VORDemodMC::networkManagerFinished: reply:\n%s", answer.toStdString().c_str()); } reply->deleteLater(); } -void VORDemodSC::handleIndexInDeviceSetChanged(int index) +void VORDemodMC::handleIndexInDeviceSetChanged(int index) { if (index < 0) { return; @@ -685,5 +591,4 @@ void VORDemodSC::handleIndexInDeviceSetChanged(int index) .arg(m_deviceAPI->getDeviceSetIndex()) .arg(index); m_basebandSink->setFifoLabel(fifoLabel); - m_basebandSink->setAudioFifoLabel(fifoLabel); } diff --git a/plugins/channelrx/demodvorsc/vordemodsc.h b/plugins/channelrx/demodvormc/vordemodmc.h similarity index 79% rename from plugins/channelrx/demodvorsc/vordemodsc.h rename to plugins/channelrx/demodvormc/vordemodmc.h index 5bca0a6df..20799a1d4 100644 --- a/plugins/channelrx/demodvorsc/vordemodsc.h +++ b/plugins/channelrx/demodvormc/vordemodmc.h @@ -16,8 +16,8 @@ // along with this program. If not, see . // /////////////////////////////////////////////////////////////////////////////////// -#ifndef INCLUDE_VORDEMODSC_H -#define INCLUDE_VORDEMODSC_H +#ifndef INCLUDE_VORDEMOD_H +#define INCLUDE_VORDEMOD_H #include @@ -28,8 +28,8 @@ #include "channel/channelapi.h" #include "util/message.h" -#include "vordemodscbaseband.h" -#include "vordemodscsettings.h" +#include "vordemodmcbaseband.h" +#include "vordemodmcsettings.h" class QNetworkAccessManager; class QNetworkReply; @@ -37,34 +37,36 @@ class QThread; class DeviceAPI; class ObjectPipe; -class VORDemodSC : public BasebandSampleSink, public ChannelAPI { +class VORDemodMC : public BasebandSampleSink, public ChannelAPI { public: class MsgConfigureVORDemod : public Message { MESSAGE_CLASS_DECLARATION public: - const VORDemodSCSettings& getSettings() const { return m_settings; } + const VORDemodMCSettings& getSettings() const { return m_settings; } bool getForce() const { return m_force; } - static MsgConfigureVORDemod* create(const VORDemodSCSettings& settings, bool force) + static MsgConfigureVORDemod* create(const VORDemodMCSettings& settings, bool force) { return new MsgConfigureVORDemod(settings, force); } private: - VORDemodSCSettings m_settings; + VORDemodMCSettings m_settings; bool m_force; - MsgConfigureVORDemod(const VORDemodSCSettings& settings, bool force) : + MsgConfigureVORDemod(const VORDemodMCSettings& settings, bool force) : Message(), m_settings(settings), m_force(force) { } }; - VORDemodSC(DeviceAPI *deviceAPI); - virtual ~VORDemodSC(); + VORDemodMC(DeviceAPI *deviceAPI); + virtual ~VORDemodMC(); virtual void destroy() { delete this; } + virtual void setDeviceAPI(DeviceAPI *deviceAPI); + virtual DeviceAPI *getDeviceAPI() { return m_deviceAPI; } using BasebandSampleSink::feed; virtual void feed(const SampleVector::const_iterator& begin, const SampleVector::const_iterator& end, bool po); @@ -77,8 +79,8 @@ public: virtual QString getIdentifier() const { return objectName(); } virtual const QString& getURI() const { return getName(); } virtual void getTitle(QString& title) { title = m_settings.m_title; } - virtual qint64 getCenterFrequency() const { return m_settings.m_inputFrequencyOffset; } - virtual void setCenterFrequency(qint64 frequency); + virtual qint64 getCenterFrequency() const { return 0; } + virtual void setCenterFrequency(qint64) {} virtual QByteArray serialize() const; virtual bool deserialize(const QByteArray& data); @@ -109,10 +111,10 @@ public: static void webapiFormatChannelSettings( SWGSDRangel::SWGChannelSettings& response, - const VORDemodSCSettings& settings); + const VORDemodMCSettings& settings); static void webapiUpdateChannelSettings( - VORDemodSCSettings& settings, + VORDemodMCSettings& settings, const QStringList& channelSettingsKeys, SWGSDRangel::SWGChannelSettings& response); @@ -123,6 +125,10 @@ public: void getMagSqLevels(double& avg, double& peak, int& nbSamples) { m_basebandSink->getMagSqLevels(avg, peak, nbSamples); } + void setMessageQueueToGUI(MessageQueue* queue) override { + ChannelAPI::setMessageQueueToGUI(queue); + m_basebandSink->setMessageQueueToGUI(queue); + } uint32_t getNumberOfDeviceStreams() const; @@ -132,34 +138,28 @@ public: private: DeviceAPI *m_deviceAPI; QThread m_thread; - VORDemodSCBaseband* m_basebandSink; - VORDemodSCSettings m_settings; + VORDemodMCBaseband* m_basebandSink; + VORDemodMCSettings m_settings; int m_basebandSampleRate; //!< stored from device message used when starting baseband sink qint64 m_centerFrequency; - float m_radial; //!< current detected radial - float m_refMag; //!< current reference signal magnitude - float m_varMag; //!< current variable signal magnitude - QString m_morseIdent; //!< identification morse code transcript - QNetworkAccessManager *m_networkManager; QNetworkRequest m_networkRequest; virtual bool handleMessage(const Message& cmd); - void applySettings(const VORDemodSCSettings& settings, bool force = false); + void applySettings(const VORDemodMCSettings& settings, bool force = false); void webapiFormatChannelReport(SWGSDRangel::SWGChannelReport& response); - void webapiReverseSendSettings(QList& channelSettingsKeys, const VORDemodSCSettings& settings, bool force); + void webapiReverseSendSettings(QList& channelSettingsKeys, const VORDemodMCSettings& settings, bool force); void sendChannelSettings( const QList& pipes, QList& channelSettingsKeys, - const VORDemodSCSettings& settings, + const VORDemodMCSettings& settings, bool force ); - void sendChannelReport(QList& messagePipes); void webapiFormatChannelSettings( QList& channelSettingsKeys, SWGSDRangel::SWGChannelSettings *swgChannelSettings, - const VORDemodSCSettings& settings, + const VORDemodMCSettings& settings, bool force ); @@ -168,4 +168,4 @@ private slots: void handleIndexInDeviceSetChanged(int index); }; -#endif // INCLUDE_VORDEMODSC_H +#endif // INCLUDE_VORDEMOD_H diff --git a/plugins/channelrx/demodvormc/vordemodmcbaseband.cpp b/plugins/channelrx/demodvormc/vordemodmcbaseband.cpp new file mode 100644 index 000000000..063ffa34f --- /dev/null +++ b/plugins/channelrx/demodvormc/vordemodmcbaseband.cpp @@ -0,0 +1,282 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2019 Edouard Griffiths, F4EXB // +// Copyright (C) 2020 Jon Beniston, M7RCE // +// // +// This program is free software; you can redistribute it and/or modify // +// it under the terms of the GNU General Public License as published by // +// the Free Software Foundation as version 3 of the License, or // +// (at your option) any later version. // +// // +// This program is distributed in the hope that it will be useful, // +// but WITHOUT ANY WARRANTY; without even the implied warranty of // +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // +// GNU General Public License V3 for more details. // +// // +// You should have received a copy of the GNU General Public License // +// along with this program. If not, see . // +/////////////////////////////////////////////////////////////////////////////////// + +#include + +#include "dsp/dspengine.h" +#include "dsp/dspcommands.h" +#include "dsp/downchannelizer.h" + +#include "vordemodmcbaseband.h" +#include "vordemodmcreport.h" + +MESSAGE_CLASS_DEFINITION(VORDemodMCBaseband::MsgConfigureVORDemodBaseband, Message) + +VORDemodMCBaseband::VORDemodMCBaseband() : + m_running(false), + m_mutex(QMutex::Recursive), + m_messageQueueToGUI(nullptr), + m_basebandSampleRate(0) +{ + qDebug("VORDemodMCBaseband::VORDemodMCBaseband"); + + m_sampleFifo.setSize(SampleSinkFifo::getSizePolicy(48000)); + + // FIXME: If we remove this audio stops working when this demod is closed + DSPEngine::instance()->getAudioDeviceManager()->addAudioSink(&m_audioFifoBug, getInputMessageQueue()); +} + +VORDemodMCBaseband::~VORDemodMCBaseband() +{ + m_inputMessageQueue.clear(); + + for (int i = 0; i < m_sinks.size(); i++) + { + DSPEngine::instance()->getAudioDeviceManager()->removeAudioSink(m_sinks[i]->getAudioFifo()); + delete m_sinks[i]; + } + m_sinks.clear(); + + // FIXME: If we remove this audio stops working when this demod is closed + DSPEngine::instance()->getAudioDeviceManager()->removeAudioSink(&m_audioFifoBug); + + for (int i = 0; i < m_channelizers.size(); i++) + delete m_channelizers[i]; + m_channelizers.clear(); +} + +void VORDemodMCBaseband::reset() +{ + QMutexLocker mutexLocker(&m_mutex); + m_inputMessageQueue.clear(); + m_sampleFifo.reset(); +} + +void VORDemodMCBaseband::startWork() +{ + QMutexLocker mutexLocker(&m_mutex); + QObject::connect( + &m_sampleFifo, + &SampleSinkFifo::dataReady, + this, + &VORDemodMCBaseband::handleData, + Qt::QueuedConnection + ); + connect(&m_inputMessageQueue, SIGNAL(messageEnqueued()), this, SLOT(handleInputMessages())); + m_running = true; +} + +void VORDemodMCBaseband::stopWork() +{ + QMutexLocker mutexLocker(&m_mutex); + disconnect(&m_inputMessageQueue, SIGNAL(messageEnqueued()), this, SLOT(handleInputMessages())); + QObject::disconnect( + &m_sampleFifo, + &SampleSinkFifo::dataReady, + this, + &VORDemodMCBaseband::handleData + ); + m_running = false; +} + +void VORDemodMCBaseband::feed(const SampleVector::const_iterator& begin, const SampleVector::const_iterator& end) +{ + m_sampleFifo.write(begin, end); +} + +void VORDemodMCBaseband::handleData() +{ + QMutexLocker mutexLocker(&m_mutex); + + while ((m_sampleFifo.fill() > 0) && (m_inputMessageQueue.size() == 0)) + { + SampleVector::iterator part1begin; + SampleVector::iterator part1end; + SampleVector::iterator part2begin; + SampleVector::iterator part2end; + + std::size_t count = m_sampleFifo.readBegin(m_sampleFifo.fill(), &part1begin, &part1end, &part2begin, &part2end); + + // first part of FIFO data + if (part1begin != part1end) { + for (int i = 0; i < m_channelizers.size(); i++) + m_channelizers[i]->feed(part1begin, part1end); + } + + // second part of FIFO data (used when block wraps around) + if(part2begin != part2end) { + for (int i = 0; i < m_channelizers.size(); i++) + m_channelizers[i]->feed(part2begin, part2end); + } + + m_sampleFifo.readCommit((unsigned int) count); + } +} + +void VORDemodMCBaseband::handleInputMessages() +{ + Message* message; + + while ((message = m_inputMessageQueue.pop()) != nullptr) + { + if (handleMessage(*message)) { + delete message; + } + } +} + +bool VORDemodMCBaseband::handleMessage(const Message& cmd) +{ + if (MsgConfigureVORDemodBaseband::match(cmd)) + { + QMutexLocker mutexLocker(&m_mutex); + MsgConfigureVORDemodBaseband& cfg = (MsgConfigureVORDemodBaseband&) cmd; + qDebug() << "VORDemodMCBaseband::handleMessage: MsgConfigureVORDemodBaseband"; + + applySettings(cfg.getSettings(), cfg.getForce()); + + return true; + } + else if (DSPSignalNotification::match(cmd)) + { + QMutexLocker mutexLocker(&m_mutex); + DSPSignalNotification& notif = (DSPSignalNotification&) cmd; + qDebug() << "VORDemodMCBaseband::handleMessage: DSPSignalNotification: basebandSampleRate: " << notif.getSampleRate() << " centerFrequency: " << notif.getCenterFrequency(); + m_centerFrequency = notif.getCenterFrequency(); + setBasebandSampleRate(notif.getSampleRate()); + m_sampleFifo.setSize(SampleSinkFifo::getSizePolicy(m_basebandSampleRate)); + + return true; + } + else + { + return false; + } +} + +// Calculate offset of VOR center frequency from sample source center frequency +void VORDemodMCBaseband::calculateOffset(VORDemodMCSink *sink) +{ + int frequencyOffset = sink->m_vorFrequencyHz - m_centerFrequency; + bool outOfBand = std::abs(frequencyOffset)+VORDEMOD_CHANNEL_BANDWIDTH > (m_basebandSampleRate/2); + + if (m_messageQueueToGUI != nullptr) + { + VORDemodMCReport::MsgReportFreqOffset *msg = VORDemodMCReport::MsgReportFreqOffset::create(sink->m_subChannelId, frequencyOffset, outOfBand); + m_messageQueueToGUI->push(msg); + } + + sink->m_frequencyOffset = frequencyOffset; + sink->m_outOfBand = outOfBand; +} + +void VORDemodMCBaseband::applySettings(const VORDemodMCSettings& settings, bool force) +{ + // Remove sub-channels no longer needed + for (int i = 0; i < m_sinks.size(); i++) + { + if (!settings.m_subChannelSettings.contains(m_sinks[i]->m_subChannelId)) + { + qDebug() << "VORDemodMCBaseband::applySettings: Removing sink " << m_sinks[i]->m_subChannelId; + VORDemodMCSink *sink = m_sinks[i]; + DSPEngine::instance()->getAudioDeviceManager()->removeAudioSink(m_sinks[i]->getAudioFifo()); + m_sinks.removeAt(i); + delete sink; + DownChannelizer *channelizer = m_channelizers[i]; + m_channelizers.removeAt(i); + delete channelizer; + } + } + + // Add new sub channels + QHash::const_iterator itr = settings.m_subChannelSettings.begin(); + while (itr != settings.m_subChannelSettings.end()) + { + VORDemodSubChannelSettings *subChannelSettings = itr.value(); + int j; + for (j = 0; j < m_sinks.size(); j++) + { + if (subChannelSettings->m_id == m_sinks[j]->m_subChannelId) + break; + } + if (j == m_sinks.size()) + { + // Add a sub-channel sink + qDebug() << "VORDemodMCBaseband::applySettings: Adding sink " << subChannelSettings->m_id; + VORDemodMCSink *sink = new VORDemodMCSink(settings, subChannelSettings->m_id, m_messageQueueToGUI); + DownChannelizer *channelizer = new DownChannelizer(sink); + channelizer->setBasebandSampleRate(m_basebandSampleRate); + DSPEngine::instance()->getAudioDeviceManager()->addAudioSink(sink->getAudioFifo(), getInputMessageQueue()); + sink->applyAudioSampleRate(DSPEngine::instance()->getAudioDeviceManager()->getOutputSampleRate()); + + m_sinks.append(sink); + m_channelizers.append(channelizer); + + calculateOffset(sink); + + channelizer->setChannelization(VORDEMOD_CHANNEL_SAMPLE_RATE, sink->m_frequencyOffset); + sink->applyChannelSettings(channelizer->getChannelSampleRate(), channelizer->getChannelFrequencyOffset(), true); + sink->applyAudioSampleRate(sink->getAudioSampleRate()); + } + ++itr; + } + + if (force) + { + for (int i = 0; i < m_sinks.size(); i++) + { + m_channelizers[i]->setChannelization(VORDEMOD_CHANNEL_SAMPLE_RATE, m_sinks[i]->m_frequencyOffset); + m_sinks[i]->applyChannelSettings(m_channelizers[i]->getChannelSampleRate(), m_channelizers[i]->getChannelFrequencyOffset()); + m_sinks[i]->applyAudioSampleRate(m_sinks[i]->getAudioSampleRate()); // reapply in case of channel sample rate change + } + } + + if ((settings.m_audioDeviceName != m_settings.m_audioDeviceName) || force) + { + AudioDeviceManager *audioDeviceManager = DSPEngine::instance()->getAudioDeviceManager(); + int audioDeviceIndex = audioDeviceManager->getOutputDeviceIndex(settings.m_audioDeviceName); + for (int i = 0; i < m_sinks.size(); i++) + { + audioDeviceManager->removeAudioSink(m_sinks[i]->getAudioFifo()); + audioDeviceManager->addAudioSink(m_sinks[i]->getAudioFifo(), getInputMessageQueue(), audioDeviceIndex); + int audioSampleRate = audioDeviceManager->getOutputSampleRate(audioDeviceIndex); + + if (m_sinks[i]->getAudioSampleRate() != audioSampleRate) + { + m_sinks[i]->applyAudioSampleRate(audioSampleRate); + } + } + } + + for (int i = 0; i < m_sinks.size(); i++) + m_sinks[i]->applySettings(settings, force); + + m_settings = settings; +} + +void VORDemodMCBaseband::setBasebandSampleRate(int sampleRate) +{ + m_basebandSampleRate = sampleRate; + for (int i = 0; i < m_sinks.size(); i++) + { + m_channelizers[i]->setBasebandSampleRate(sampleRate); + calculateOffset(m_sinks[i]); + m_sinks[i]->applyChannelSettings(m_channelizers[i]->getChannelSampleRate(), m_channelizers[i]->getChannelFrequencyOffset()); + m_sinks[i]->applyAudioSampleRate(m_sinks[i]->getAudioSampleRate()); // reapply in case of channel sample rate change + } +} diff --git a/plugins/channelrx/demodvorsc/vordemodscbaseband.h b/plugins/channelrx/demodvormc/vordemodmcbaseband.h similarity index 59% rename from plugins/channelrx/demodvorsc/vordemodscbaseband.h rename to plugins/channelrx/demodvormc/vordemodmcbaseband.h index 1fab48b7b..dac1f9ae3 100644 --- a/plugins/channelrx/demodvorsc/vordemodscbaseband.h +++ b/plugins/channelrx/demodvormc/vordemodmcbaseband.h @@ -16,8 +16,8 @@ // along with this program. If not, see . // /////////////////////////////////////////////////////////////////////////////////// -#ifndef INCLUDE_VORDEMODSCBASEBAND_H -#define INCLUDE_VORDEMODSCBASEBAND_H +#ifndef INCLUDE_VORDEMODBASEBAND_H +#define INCLUDE_VORDEMODBASEBAND_H #include #include @@ -26,11 +26,11 @@ #include "util/message.h" #include "util/messagequeue.h" -#include "vordemodscsink.h" +#include "vordemodmcsink.h" class DownChannelizer; -class VORDemodSCBaseband : public QObject +class VORDemodMCBaseband : public QObject { Q_OBJECT public: @@ -38,58 +38,100 @@ public: MESSAGE_CLASS_DECLARATION public: - const VORDemodSCSettings& getSettings() const { return m_settings; } + const VORDemodMCSettings& getSettings() const { return m_settings; } bool getForce() const { return m_force; } - static MsgConfigureVORDemodBaseband* create(const VORDemodSCSettings& settings, bool force) + static MsgConfigureVORDemodBaseband* create(const VORDemodMCSettings& settings, bool force) { return new MsgConfigureVORDemodBaseband(settings, force); } private: - VORDemodSCSettings m_settings; + VORDemodMCSettings m_settings; bool m_force; - MsgConfigureVORDemodBaseband(const VORDemodSCSettings& settings, bool force) : + MsgConfigureVORDemodBaseband(const VORDemodMCSettings& settings, bool force) : Message(), m_settings(settings), m_force(force) { } }; - VORDemodSCBaseband(); - ~VORDemodSCBaseband(); + VORDemodMCBaseband(); + ~VORDemodMCBaseband(); void reset(); void startWork(); void stopWork(); void feed(const SampleVector::const_iterator& begin, const SampleVector::const_iterator& end); MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; } //!< Get the queue for asynchronous inbound communication - void getMagSqLevels(double& avg, double& peak, int& nbSamples) { m_sink.getMagSqLevels(avg, peak, nbSamples); } - void setMessageQueueToChannel(MessageQueue *messageQueue) { m_sink.setMessageQueueToChannel(messageQueue); } - bool getSquelchOpen() const { return m_sink.getSquelchOpen(); } - int getAudioSampleRate() const { return m_sink.getAudioSampleRate(); } - double getMagSq() const { return m_sink.getMagSq(); } + void getMagSqLevels(double& avg, double& peak, int& nbSamples) { + avg = 0.0; + peak = 0.0; + nbSamples = 0; + for (int i = 0; i < m_sinks.size(); i++) + { + double avg1, peak1; + int nbSamples1; + m_sinks[i]->getMagSqLevels(avg1, peak1, nbSamples1); + if (avg1 > avg) + { + avg = avg1; + nbSamples = nbSamples1; + } + avg += avg1; + if (peak1 > peak) + peak = peak1; + } + } + void setMessageQueueToGUI(MessageQueue *messageQueue) { + m_messageQueueToGUI = messageQueue; + for (int i = 0; i < m_sinks.size(); i++) + m_sinks[i]->setMessageQueueToGUI(messageQueue); + } + bool getSquelchOpen() const { + for (int i = 0; i < m_sinks.size(); i++) + { + if (m_sinks[i]->getSquelchOpen()) + return true; + } + return false; + } + int getAudioSampleRate() const { + if (m_sinks.size() > 0) + return m_sinks[0]->getAudioSampleRate(); + else + return 48000; + } + void setBasebandSampleRate(int sampleRate); + double getMagSq() const { + if (m_sinks.size() > 0) + return m_sinks[0]->getMagSq(); + else + return 0.0; + } bool isRunning() const { return m_running; } void setFifoLabel(const QString& label) { m_sampleFifo.setLabel(label); } - void setAudioFifoLabel(const QString& label) { m_sink.setAudioFifoLabel(label); } private: SampleSinkFifo m_sampleFifo; - DownChannelizer * m_channelizer; - int m_channelSampleRate; - VORDemodSCSink m_sink; + QList m_channelizers; + QList m_sinks; + AudioFifo m_audioFifoBug; // FIXME: Removing this results in audio stopping when demod is closed MessageQueue m_inputMessageQueue; //!< Queue for asynchronous inbound communication - VORDemodSCSettings m_settings; - MessageQueue *m_messageQueueToGUI; + VORDemodMCSettings m_settings; bool m_running; QMutex m_mutex; + MessageQueue *m_messageQueueToGUI; + int m_basebandSampleRate; + int m_centerFrequency; bool handleMessage(const Message& cmd); - void applySettings(const VORDemodSCSettings& settings, bool force = false); + void calculateOffset(VORDemodMCSink *sink); + void applySettings(const VORDemodMCSettings& settings, bool force = false); private slots: void handleInputMessages(); void handleData(); //!< Handle data when samples have to be processed }; -#endif // INCLUDE_VORDEMODSCBASEBAND_H +#endif // INCLUDE_VORDEMODBASEBAND_H diff --git a/plugins/channelrx/demodvormc/vordemodmcgui.cpp b/plugins/channelrx/demodvormc/vordemodmcgui.cpp new file mode 100644 index 000000000..c86912709 --- /dev/null +++ b/plugins/channelrx/demodvormc/vordemodmcgui.cpp @@ -0,0 +1,1458 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2016 Edouard Griffiths, F4EXB // +// Copyright (C) 2020 Jon Beniston, M7RCE // +// // +// This program is free software; you can redistribute it and/or modify // +// it under the terms of the GNU General Public License as published by // +// the Free Software Foundation as version 3 of the License, or // +// (at your option) any later version. // +// // +// This program is distributed in the hope that it will be useful, // +// but WITHOUT ANY WARRANTY; without even the implied warranty of // +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // +// GNU General Public License V3 for more details. // +// // +// You should have received a copy of the GNU General Public License // +// along with this program. If not, see . // +/////////////////////////////////////////////////////////////////////////////////// + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "vordemodmcgui.h" + +#include "device/deviceuiset.h" +#include "dsp/dspengine.h" +#include "dsp/dspcommands.h" +#include "ui_vordemodmcgui.h" +#include "plugin/pluginapi.h" +#include "util/simpleserializer.h" +#include "util/db.h" +#include "util/morse.h" +#include "util/units.h" +#include "gui/basicchannelsettingsdialog.h" +#include "gui/devicestreamselectiondialog.h" +#include "dsp/dspengine.h" +#include "gui/crightclickenabler.h" +#include "gui/audioselectdialog.h" +#include "channel/channelwebapiutils.h" +#include "maincore.h" + +#include "vordemodmc.h" +#include "vordemodmcreport.h" +#include "vordemodmcsink.h" + +#define VOR_COL_NAME 0 +#define VOR_COL_FREQUENCY 1 +#define VOR_COL_OFFSET 2 +#define VOR_COL_IDENT 3 +#define VOR_COL_MORSE 4 +#define VOR_COL_RX_IDENT 5 +#define VOR_COL_RX_MORSE 6 +#define VOR_COL_RADIAL 7 +#define VOR_COL_REF_MAG 8 +#define VOR_COL_VAR_MAG 9 +#define VOR_COL_MUTE 10 + +static const char *countryCodes[] = { + "ad", + "ae", + "af", + "ag", + "ai", + "al", + "am", + "an", + "ao", + "aq", + "ar", + "as", + "at", + "au", + "aw", + "ax", + "az", + "ba", + "bb", + "bd", + "be", + "bf", + "bg", + "bh", + "bi", + "bj", + "bl", + "bm", + "bn", + "bo", + "bq", + "br", + "bs", + "bt", + "bv", + "bw", + "by", + "bz", + "ca", + "cc", + "cd", + "cf", + "cg", + "ch", + "ci", + "ck", + "cl", + "cm", + "cn", + "co", + "cr", + "cu", + "cv", + "cw", + "cx", + "cy", + "cz", + "de", + "dj", + "dk", + "dm", + "do", + "dz", + "ec", + "ee", + "eg", + "eh", + "er", + "es", + "et", + "fi", + "fj", + "fk", + "fm", + "fo", + "fr", + "ga", + "gb", + "ge", + "gf", + "gg", + "gh", + "gi", + "gl", + "gm", + "gn", + "gp", + "gq", + "gr", + "gs", + "gt", + "gu", + "gw", + "gy", + "hk", + "hm", + "hn", + "hr", + "hu", + "id", + "ie", + "il", + "im", + "in", + "io", + "iq", + "ir", + "is", + "it", + "je", + "jm", + "jo", + "jp", + "ke", + "kg", + "kh", + "ki", + "km", + "kn", + "kp", + "kr", + "kw", + "ky", + "kz", + "la", + "lb", + "lc", + "li", + "lk", + "lr", + "ls", + "lt", + "lu", + "lv", + "ly", + "ma", + "mc", + "md", + "me", + "mf", + "mg", + "mh", + "mk", + "ml", + "mm", + "mn", + "mo", + "mp", + "mq", + "mr", + "ms", + "mt", + "mu", + "mv", + "mw", + "mx", + "my", + "mz", + "na", + "nc", + "ne", + "nf", + "ng", + "ni", + "nl", + "no", + "np", + "nr", + "nu", + "nz", + "om", + "pa", + "pe", + "pf", + "pg", + "ph", + "pk", + "pl", + "pm", + "pn", + "pr", + "ps", + "pt", + "pw", + "py", + "qa", + "re", + "ro", + "rs", + "ru", + "rw", + "sa", + "sb", + "sc", + "sd", + "se", + "sg", + "sh", + "si", + "sj", + "sk", + "sl", + "sm", + "sn", + "so", + "sr", + "ss", + "st", + "sv", + "sx", + "sy", + "sz", + "tc", + "td", + "tf", + "tg", + "th", + "tj", + "tk", + "tl", + "tm", + "tn", + "to", + "tr", + "tt", + "tv", + "tw", + "tz", + "ua", + "ug", + "um", + "us", + "uy", + "uz", + "va", + "vc", + "ve", + "vg", + "vi", + "vn", + "vu", + "wf", + "ws", + "ye", + "yt", + "za", + "zm", + "zw", + nullptr +}; + +// Lats and longs in decimal degrees. Distance in metres. Bearing in degrees. +// https://www.movable-type.co.uk/scripts/latlong.html +static void calcRadialEndPoint(float startLatitude, float startLongitude, float distance, float bearing, float &endLatitude, float &endLongitude) +{ + double startLatRad = startLatitude*M_PI/180.0; + double startLongRad = startLongitude*M_PI/180.0; + double theta = bearing*M_PI/180.0; + double earthRadius = 6378137.0; // At equator + double delta = distance/earthRadius; + double endLatRad = std::asin(sin(startLatRad)*cos(delta) + cos(startLatRad)*sin(delta)*cos(theta)); + double endLongRad = startLongRad + std::atan2(sin(theta)*sin(delta)*cos(startLatRad), cos(delta) - sin(startLatRad)*sin(endLatRad)); + endLatitude = endLatRad*180.0/M_PI; + endLongitude = endLongRad*180.0/M_PI; +} + +// Calculate intersection point along two radials +// https://www.movable-type.co.uk/scripts/latlong.html +static bool calcIntersectionPoint(float lat1, float lon1, float bearing1, float lat2, float lon2, float bearing2, float &intersectLat, float &intersectLon) +{ + + double lat1Rad = Units::degreesToRadians(lat1); + double lon1Rad = Units::degreesToRadians(lon1); + double lat2Rad = Units::degreesToRadians(lat2); + double lon2Rad = Units::degreesToRadians(lon2); + double theta13 = Units::degreesToRadians(bearing1); + double theta23 = Units::degreesToRadians(bearing2); + + double deltaLat = lat1Rad - lat2Rad; + double deltaLon = lon1Rad - lon2Rad; + double sindlat = sin(deltaLat/2.0); + double sindlon = sin(deltaLon/2.0); + double cosLat1 = cos(lat1Rad); + double cosLat2 = cos(lat2Rad); + double delta12 = 2.0 * asin(sqrt(sindlat*sindlat+cosLat1*cosLat2*sindlon*sindlon)); + if (abs(delta12) < std::numeric_limits::epsilon()) + return false; + + double sinLat1 = sin(lat1Rad); + double sinLat2 = sin(lat2Rad); + double sinDelta12 = sin(delta12); + double cosDelta12 = cos(delta12); + double thetaA = acos((sinLat2-sinLat1*cosDelta12)/(sinDelta12*cosLat1)); + double thetaB = acos((sinLat1-sinLat2*cosDelta12)/(sinDelta12*cosLat2)); + + double theta12, theta21; + if (sin(lon2Rad-lon1Rad) > 0.0) + { + theta12 = thetaA; + theta21 = 2.0*M_PI-thetaB; + } + else + { + theta12 = 2.0*M_PI-thetaA; + theta21 = thetaB; + } + double alpha1 = theta13 - theta12; + double alpha2 = theta21 - theta23; + double sinAlpha1 = sin(alpha1); + double sinAlpha2 = sin(alpha2); + if ((sinAlpha1 == 0.0) && (sinAlpha2 == 0.0)) + return false; + if (sinAlpha1*sinAlpha2 < 0.0) + return false; + double cosAlpha1 = cos(alpha1); + double cosAlpha2 = cos(alpha2); + double cosAlpha3 = -cosAlpha1*cosAlpha2+sinAlpha1*sinAlpha2*cos(delta12); + double delta13 = atan2(sin(delta12)*sinAlpha1*sinAlpha2, cosAlpha2+cosAlpha1*cosAlpha3); + double lat3Rad = asin(sinLat1*cos(delta13)+cosLat1*sin(delta13)*cos(theta13)); + double lon3Rad = lon1Rad + atan2(sin(theta13)*sin(delta13)*cosLat1, cos(delta13)-sinLat1*sin(lat3Rad)); + + intersectLat = Units::radiansToDegrees(lat3Rad); + intersectLon = Units::radiansToDegrees(lon3Rad); + + return true; +} + +VORGUI::VORGUI(NavAid *navAid, VORDemodMCGUI *gui) : + m_navAid(navAid), + m_gui(gui) +{ + // These are deleted by QTableWidget + m_nameItem = new QTableWidgetItem(); + m_frequencyItem = new QTableWidgetItem(); + m_offsetItem = new QTableWidgetItem(); + m_radialItem = new QTableWidgetItem(); + m_identItem = new QTableWidgetItem(); + m_morseItem = new QTableWidgetItem(); + m_rxIdentItem = new QTableWidgetItem(); + m_rxMorseItem = new QTableWidgetItem(); + m_varMagItem = new QTableWidgetItem(); + m_refMagItem = new QTableWidgetItem(); + + m_muteItem = new QWidget(); + + m_muteButton = new QToolButton(); + m_muteButton->setCheckable(true); + m_muteButton->setChecked(false); + m_muteButton->setToolTip("Mute/unmute audio from this VOR"); + m_muteButton->setIcon(m_gui->m_muteIcon); + + QHBoxLayout* pLayout = new QHBoxLayout(m_muteItem); + pLayout->addWidget(m_muteButton); + pLayout->setAlignment(Qt::AlignCenter); + pLayout->setContentsMargins(0, 0, 0, 0); + m_muteItem->setLayout(pLayout); + + connect(m_muteButton, &QPushButton::toggled, this, &VORGUI::on_audioMute_toggled); + + m_coordinates.push_back(QVariant::fromValue(*new QGeoCoordinate(m_navAid->m_latitude, m_navAid->m_longitude, Units::feetToMetres(m_navAid->m_elevation)))); +} + +void VORGUI::on_audioMute_toggled(bool checked) +{ + m_gui->m_settings.m_subChannelSettings.value(m_navAid->m_id)->m_audioMute = checked; + m_gui->applySettings(); +} + +QVariant VORModel::data(const QModelIndex &index, int role) const +{ + int row = index.row(); + if ((row < 0) || (row >= m_vors.count())) + return QVariant(); + if (role == VORModel::positionRole) + { + // Coordinates to display the VOR icon at + QGeoCoordinate coords; + coords.setLatitude(m_vors[row]->m_latitude); + coords.setLongitude(m_vors[row]->m_longitude); + coords.setAltitude(Units::feetToMetres(m_vors[row]->m_elevation)); + return QVariant::fromValue(coords); + } + else if (role == VORModel::vorDataRole) + { + // Create the text to go in the bubble next to the VOR + QStringList list; + list.append(QString("Name: %1").arg(m_vors[row]->m_name)); + list.append(QString("Frequency: %1 MHz").arg(m_vors[row]->m_frequencykHz / 1000.0f, 0, 'f', 1)); + if (m_vors[row]->m_channel != "") + list.append(QString("Channel: %1").arg(m_vors[row]->m_channel)); + list.append(QString("Ident: %1 %2").arg(m_vors[row]->m_ident).arg(Morse::toSpacedUnicodeMorse(m_vors[row]->m_ident))); + list.append(QString("Range: %1 nm").arg(m_vors[row]->m_range)); + if (m_vors[row]->m_alignedTrueNorth) + list.append(QString("Magnetic declination: Aligned to true North")); + else if (m_vors[row]->m_magneticDeclination != 0.0f) + list.append(QString("Magnetic declination: %1%2").arg(std::round(m_vors[row]->m_magneticDeclination)).arg(QChar(0x00b0))); + QString data = list.join("\n"); + return QVariant::fromValue(data); + } + else if (role == VORModel::vorImageRole) + { + // Select an image to use for the VOR + return QVariant::fromValue(QString("/demodvor/map/%1.png").arg(m_vors[row]->m_type)); + } + else if (role == VORModel::bubbleColourRole) + { + // Select a background colour for the text bubble next to the VOR + if (m_selected[row]) + return QVariant::fromValue(QColor("lightgreen")); + else + return QVariant::fromValue(QColor("lightblue")); + } + else if (role == VORModel::vorRadialRole) + { + // Draw a radial line from centre of VOR outwards at the demodulated angle + if (m_radialsVisible && m_selected[row] && (m_vorGUIs[row] != nullptr) && (m_radials[row] != -1.0f)) + { + QVariantList list; + + list.push_back(m_vorGUIs[row]->m_coordinates[0]); // Centre of VOR + + float endLat, endLong; + float bearing; + if (m_gui->m_settings.m_magDecAdjust && !m_vors[row]->m_alignedTrueNorth) + bearing = m_radials[row] - m_vors[row]->m_magneticDeclination; + else + bearing = m_radials[row]; + calcRadialEndPoint(m_vors[row]->m_latitude, m_vors[row]->m_longitude, m_vors[row]->getRangeMetres(), bearing, endLat, endLong); + list.push_back(QVariant::fromValue(*new QGeoCoordinate(endLat, endLong, Units::feetToMetres(m_vors[row]->m_elevation)))); + + return list; + } + else + return QVariantList(); + } + else if (role == VORModel::selectedRole) + return QVariant::fromValue(m_selected[row]); + return QVariant(); +} + +bool VORModel::setData(const QModelIndex &index, const QVariant& value, int role) +{ + int row = index.row(); + if ((row < 0) || (row >= m_vors.count())) + return false; + if (role == VORModel::selectedRole) + { + bool selected = value.toBool(); + VORGUI *vorGUI; + if (selected == true) + { + vorGUI = new VORGUI(m_vors[row], m_gui); + m_vorGUIs[row] = vorGUI; + } + else + vorGUI = m_vorGUIs[row]; + m_gui->selectVOR(vorGUI, selected); + m_selected[row] = selected; + emit dataChanged(index, index); + if (!selected) + { + delete vorGUI; + m_vorGUIs[row] = nullptr; + } + return true; + } + return true; +} + +// Find intersection between first two selected radials +bool VORModel::findIntersection(float &lat, float &lon) +{ + if (m_vors.count() > 2) + { + float lat1, lon1, bearing1, valid1 = false; + float lat2, lon2, bearing2, valid2 = false; + + for (int i = 0; i < m_vors.count(); i++) + { + if (m_selected[i] && (m_radials[i] >= 0.0)) + { + if (!valid1) + { + lat1 = m_vors[i]->m_latitude; + lon1 = m_vors[i]->m_longitude; + if (m_gui->m_settings.m_magDecAdjust && !m_vors[i]->m_alignedTrueNorth) + bearing1 = m_radials[i] - m_vors[i]->m_magneticDeclination; + else + bearing1 = m_radials[i]; + valid1 = true; + } + else + { + lat2 = m_vors[i]->m_latitude; + lon2 = m_vors[i]->m_longitude; + if (m_gui->m_settings.m_magDecAdjust && !m_vors[i]->m_alignedTrueNorth) + bearing2 = m_radials[i] - m_vors[i]->m_magneticDeclination; + else + bearing2 = m_radials[i]; + valid2 = true; + break; + } + } + } + + if (valid1 && valid2) + { + return calcIntersectionPoint(lat1, lon1, bearing1, lat2, lon2, bearing2, lat, lon); + } + } + + return false; +} + +void VORDemodMCGUI::resizeTable() +{ + // Fill table with a row of dummy data that will size the columns nicely + // Trailing spaces are for sort arrow + QString morse("---- ---- ----"); + int row = ui->vorData->rowCount(); + ui->vorData->setRowCount(row + 1); + ui->vorData->setItem(row, VOR_COL_NAME, new QTableWidgetItem("White Sulphur Springs")); + ui->vorData->setItem(row, VOR_COL_FREQUENCY, new QTableWidgetItem("Freq (MHz) ")); + ui->vorData->setItem(row, VOR_COL_OFFSET, new QTableWidgetItem("Offset (kHz) ")); + ui->vorData->setItem(row, VOR_COL_IDENT, new QTableWidgetItem("Ident ")); + ui->vorData->setItem(row, VOR_COL_MORSE, new QTableWidgetItem(Morse::toSpacedUnicode(morse))); + ui->vorData->setItem(row, VOR_COL_RADIAL, new QTableWidgetItem("Radial (o) ")); + ui->vorData->setItem(row, VOR_COL_RX_IDENT, new QTableWidgetItem("RX Ident ")); + ui->vorData->setItem(row, VOR_COL_RX_MORSE, new QTableWidgetItem(Morse::toSpacedUnicode(morse))); + ui->vorData->setItem(row, VOR_COL_VAR_MAG, new QTableWidgetItem("Var (dB) ")); + ui->vorData->setItem(row, VOR_COL_REF_MAG, new QTableWidgetItem("Ref (dB) ")); + ui->vorData->setItem(row, VOR_COL_MUTE, new QTableWidgetItem("Mute")); + ui->vorData->resizeColumnsToContents(); + ui->vorData->removeRow(row); +} + +// Columns in table reordered +void VORDemodMCGUI::vorData_sectionMoved(int logicalIndex, int oldVisualIndex, int newVisualIndex) +{ + (void) oldVisualIndex; + + m_settings.m_columnIndexes[logicalIndex] = newVisualIndex; +} + +// Column in table resized (when hidden size is 0) +void VORDemodMCGUI::vorData_sectionResized(int logicalIndex, int oldSize, int newSize) +{ + (void) oldSize; + + m_settings.m_columnSizes[logicalIndex] = newSize; +} + +// Right click in table header - show column select menu +void VORDemodMCGUI::columnSelectMenu(QPoint pos) +{ + menu->popup(ui->vorData->horizontalHeader()->viewport()->mapToGlobal(pos)); +} + +// Hide/show column when menu selected +void VORDemodMCGUI::columnSelectMenuChecked(bool checked) +{ + (void) checked; + + QAction* action = qobject_cast(sender()); + if (action != nullptr) + { + int idx = action->data().toInt(nullptr); + ui->vorData->setColumnHidden(idx, !action->isChecked()); + } +} + +// Create column select menu item +QAction *VORDemodMCGUI::createCheckableItem(QString &text, int idx, bool checked) +{ + QAction *action = new QAction(text, this); + action->setCheckable(true); + action->setChecked(checked); + action->setData(QVariant(idx)); + connect(action, SIGNAL(triggered()), this, SLOT(columnSelectMenuChecked())); + return action; +} + +// Called when a VOR is selected on the map +void VORDemodMCGUI::selectVOR(VORGUI *vorGUI, bool selected) +{ + if (selected) + { + m_selectedVORs.insert(vorGUI->m_navAid->m_id, vorGUI); + ui->vorData->setSortingEnabled(false); + int row = ui->vorData->rowCount(); + ui->vorData->setRowCount(row + 1); + ui->vorData->setItem(row, VOR_COL_NAME, vorGUI->m_nameItem); + ui->vorData->setItem(row, VOR_COL_FREQUENCY, vorGUI->m_frequencyItem); + ui->vorData->setItem(row, VOR_COL_OFFSET, vorGUI->m_offsetItem); + ui->vorData->setItem(row, VOR_COL_IDENT, vorGUI->m_identItem); + ui->vorData->setItem(row, VOR_COL_MORSE, vorGUI->m_morseItem); + ui->vorData->setItem(row, VOR_COL_RADIAL, vorGUI->m_radialItem); + ui->vorData->setItem(row, VOR_COL_RX_IDENT, vorGUI->m_rxIdentItem); + ui->vorData->setItem(row, VOR_COL_RX_MORSE, vorGUI->m_rxMorseItem); + ui->vorData->setItem(row, VOR_COL_VAR_MAG, vorGUI->m_varMagItem); + ui->vorData->setItem(row, VOR_COL_REF_MAG, vorGUI->m_refMagItem); + ui->vorData->setCellWidget(row, VOR_COL_MUTE, vorGUI->m_muteItem); + vorGUI->m_nameItem->setText(vorGUI->m_navAid->m_name); + vorGUI->m_identItem->setText(vorGUI->m_navAid->m_ident); + vorGUI->m_morseItem->setText(Morse::toSpacedUnicodeMorse(vorGUI->m_navAid->m_ident)); + vorGUI->m_frequencyItem->setData(Qt::DisplayRole, vorGUI->m_navAid->m_frequencykHz / 1000.0); + ui->vorData->setSortingEnabled(true); + + // Add to settings to create corresponding demodulator + VORDemodSubChannelSettings *subChannelSettings = new VORDemodSubChannelSettings(); + subChannelSettings->m_id = vorGUI->m_navAid->m_id; + subChannelSettings->m_frequency = vorGUI->m_navAid->m_frequencykHz * 1000; + subChannelSettings->m_audioMute = false; + m_settings.m_subChannelSettings.insert(vorGUI->m_navAid->m_id, subChannelSettings); + applySettings(); + } + else + { + m_selectedVORs.remove(vorGUI->m_navAid->m_id); + ui->vorData->removeRow(vorGUI->m_nameItem->row()); + // Remove from settings to remove corresponding demodulator + VORDemodSubChannelSettings *subChannelSettings = m_settings.m_subChannelSettings.value(vorGUI->m_navAid->m_id); + m_settings.m_subChannelSettings.remove(vorGUI->m_navAid->m_id); + delete subChannelSettings; + applySettings(); + } +} + +void VORDemodMCGUI::updateVORs() +{ + m_vorModel.removeAllVORs(); + QHash::iterator i = m_vors->begin(); + AzEl azEl = m_azEl; + + while (i != m_vors->end()) + { + NavAid *vor = i.value(); + + // Calculate distance to VOR from My Position + azEl.setTarget(vor->m_latitude, vor->m_longitude, Units::feetToMetres(vor->m_elevation)); + azEl.calculate(); + + // Only display VOR if in range + if (azEl.getDistance() <= 200000) + { + m_vorModel.addVOR(vor); + } + ++i; + } +} + +VORDemodMCGUI* VORDemodMCGUI::create(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, BasebandSampleSink *rxChannel) +{ + VORDemodMCGUI* gui = new VORDemodMCGUI(pluginAPI, deviceUISet, rxChannel); + return gui; +} + +void VORDemodMCGUI::destroy() +{ + delete this; +} + +void VORDemodMCGUI::resetToDefaults() +{ + m_settings.resetToDefaults(); + displaySettings(); + applySettings(true); +} + +QByteArray VORDemodMCGUI::serialize() const +{ + return m_settings.serialize(); +} + +bool VORDemodMCGUI::deserialize(const QByteArray& data) +{ + if(m_settings.deserialize(data)) { + displaySettings(); + applySettings(true); + return true; + } else { + resetToDefaults(); + return false; + } +} + +bool VORDemodMCGUI::handleMessage(const Message& message) +{ + if (VORDemodMC::MsgConfigureVORDemod::match(message)) + { + qDebug("VORDemodMCGUI::handleMessage: VORDemodMC::MsgConfigureVORDemod"); + const VORDemodMC::MsgConfigureVORDemod& cfg = (VORDemodMC::MsgConfigureVORDemod&) message; + m_settings = cfg.getSettings(); + blockApplySettings(true); + displaySettings(); + blockApplySettings(false); + return true; + } + else if (DSPSignalNotification::match(message)) + { + DSPSignalNotification& notif = (DSPSignalNotification&) message; + m_deviceCenterFrequency = notif.getCenterFrequency(); + m_basebandSampleRate = notif.getSampleRate(); + updateAbsoluteCenterFrequency(); + return true; + } + else if (VORDemodMCReport::MsgReportRadial::match(message)) + { + VORDemodMCReport::MsgReportRadial& report = (VORDemodMCReport::MsgReportRadial&) message; + int subChannelId = report.getSubChannelId(); + + VORGUI *vorGUI = m_selectedVORs.value(subChannelId); + + // Display radial and signal magnitudes in table + + Real varMagDB = std::round(20.0*std::log10(report.getVarMag())); + Real refMagDB = std::round(20.0*std::log10(report.getRefMag())); + + bool validRadial = (refMagDB > m_settings.m_refThresholdDB) && (varMagDB > m_settings.m_varThresholdDB); + + vorGUI->m_radialItem->setData(Qt::DisplayRole, std::round(report.getRadial())); + if (validRadial) + vorGUI->m_radialItem->setForeground(QBrush(Qt::white)); + else + vorGUI->m_radialItem->setForeground(QBrush(Qt::red)); + + vorGUI->m_refMagItem->setData(Qt::DisplayRole, refMagDB); + if (refMagDB > m_settings.m_refThresholdDB) + vorGUI->m_refMagItem->setForeground(QBrush(Qt::white)); + else + vorGUI->m_refMagItem->setForeground(QBrush(Qt::red)); + + vorGUI->m_varMagItem->setData(Qt::DisplayRole, varMagDB); + if (varMagDB > m_settings.m_varThresholdDB) + vorGUI->m_varMagItem->setForeground(QBrush(Qt::white)); + else + vorGUI->m_varMagItem->setForeground(QBrush(Qt::red)); + + // Update radial on map + m_vorModel.setRadial(subChannelId, validRadial, report.getRadial()); + + return true; + } + else if (VORDemodMCReport::MsgReportFreqOffset::match(message)) + { + VORDemodMCReport::MsgReportFreqOffset& report = (VORDemodMCReport::MsgReportFreqOffset&) message; + int subChannelId = report.getSubChannelId(); + + VORGUI *vorGUI = m_selectedVORs.value(subChannelId); + + vorGUI->m_offsetItem->setData(Qt::DisplayRole, report.getFreqOffset() / 1000.0); + if (report.getOutOfBand()) + { + vorGUI->m_offsetItem->setForeground(QBrush(Qt::red)); + // Clear other fields as data is now invalid + vorGUI->m_radialItem->setText(""); + vorGUI->m_refMagItem->setText(""); + vorGUI->m_varMagItem->setText(""); + m_vorModel.setRadial(subChannelId, false, -1.0f); + } + else + vorGUI->m_offsetItem->setForeground(QBrush(Qt::white)); + } + else if (VORDemodMCReport::MsgReportIdent::match(message)) + { + VORDemodMCReport::MsgReportIdent& report = (VORDemodMCReport::MsgReportIdent&) message; + int subChannelId = report.getSubChannelId(); + + VORGUI *vorGUI = m_selectedVORs.value(subChannelId); + + QString ident = report.getIdent(); + // Convert Morse to a string + QString identString = Morse::toString(ident); + // Idents should only be two or three characters, so filter anything else + // other than TEST which indicates a VOR is under maintainance (may also be TST) + if (((identString.size() >= 2) && (identString.size() <= 3)) || (identString == "TEST")) + { + vorGUI->m_rxIdentItem->setText(identString); + vorGUI->m_rxMorseItem->setText(Morse::toSpacedUnicode(ident)); + if (vorGUI->m_navAid->m_ident == identString) + { + // Set colour to green if matching expected ident + vorGUI->m_rxIdentItem->setForeground(QBrush(Qt::green)); + vorGUI->m_rxMorseItem->setForeground(QBrush(Qt::green)); + } + else + { + // Set colour to green if not matching expected ident + vorGUI->m_rxIdentItem->setForeground(QBrush(Qt::red)); + vorGUI->m_rxMorseItem->setForeground(QBrush(Qt::red)); + } + } + else + { + // Set yellow to indicate we've filtered something (unless red) + if (vorGUI->m_rxIdentItem->foreground().color() != Qt::red) + { + vorGUI->m_rxIdentItem->setForeground(QBrush(Qt::yellow)); + vorGUI->m_rxMorseItem->setForeground(QBrush(Qt::yellow)); + } + } + return true; + } + + return false; +} + +void VORDemodMCGUI::handleInputMessages() +{ + Message* message; + + while ((message = getInputMessageQueue()->pop()) != 0) + { + if (handleMessage(*message)) + { + delete message; + } + } +} + +void VORDemodMCGUI::channelMarkerChangedByCursor() +{ +} + +void VORDemodMCGUI::channelMarkerHighlightedByCursor() +{ + setHighlighted(m_channelMarker.getHighlighted()); +} + +void VORDemodMCGUI::on_thresh_valueChanged(int value) +{ + ui->threshText->setText(QString("%1").arg(value / 10.0, 0, 'f', 1)); + m_settings.m_identThreshold = value / 10.0; + applySettings(); +} + +void VORDemodMCGUI::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 VORDemodMCGUI::on_squelch_valueChanged(int value) +{ + ui->squelchText->setText(QString("%1 dB").arg(value)); + m_settings.m_squelch = value; + applySettings(); +} + +void VORDemodMCGUI::on_audioMute_toggled(bool checked) +{ + m_settings.m_audioMute = checked; + applySettings(); +} + +qint64 VORDemodMCGUI::fileAgeInDays(QString filename) +{ + QFile file(filename); + if (file.exists()) + { + QDateTime modified = file.fileTime(QFileDevice::FileModificationTime); + if (modified.isValid()) + return modified.daysTo(QDateTime::currentDateTime()); + else + return -1; + } + return -1; +} + +bool VORDemodMCGUI::confirmDownload(QString filename) +{ + qint64 age = fileAgeInDays(filename); + if ((age == -1) || (age > 100)) + return true; + else + { + QMessageBox::StandardButton reply; + if (age == 0) + reply = QMessageBox::question(this, "Confirm download", "This file was last downloaded today. Are you sure you wish to redownload it?", QMessageBox::Yes|QMessageBox::No); + else if (age == 1) + reply = QMessageBox::question(this, "Confirm download", "This file was last downloaded yesterday. Are you sure you wish to redownload it?", QMessageBox::Yes|QMessageBox::No); + else + reply = QMessageBox::question(this, "Confirm download", QString("This file was last downloaded %1 days ago. Are you sure you wish to redownload this file?").arg(age), QMessageBox::Yes|QMessageBox::No); + return reply == QMessageBox::Yes; + } +} + +QString VORDemodMCGUI::getDataDir() +{ + // Get directory to store app data in + QStringList locations = QStandardPaths::standardLocations(QStandardPaths::AppDataLocation); + // First dir is writable + return locations[0]; +} + +QString VORDemodMCGUI::getOpenAIPVORDBFilename(int i) +{ + if (countryCodes[i] != nullptr) + return getDataDir() + "/" + countryCodes[i] + "_nav.aip"; + else + return ""; +} + +QString VORDemodMCGUI::getOpenAIPVORDBURL(int i) +{ + if (countryCodes[i] != nullptr) + return QString(OPENAIP_NAVAIDS_URL).arg(countryCodes[i]); + else + return ""; +} + +QString VORDemodMCGUI::getVORDBFilename() +{ + return getDataDir() + "/vorDatabase.csv"; +} + +void VORDemodMCGUI::updateDownloadProgress(qint64 bytesRead, qint64 totalBytes) +{ + if (m_progressDialog) + { + m_progressDialog->setMaximum(totalBytes); + m_progressDialog->setValue(bytesRead); + } +} + +void VORDemodMCGUI::downloadFinished(const QString& filename, bool success) +{ + bool closeDialog = true; + if (success) + { + if (filename == getVORDBFilename()) + { + m_vors = NavAid::readNavAidsDB(filename); + if (m_vors != nullptr) + updateVORs(); + } + else if (filename == getOpenAIPVORDBFilename(m_countryIndex)) + { + m_countryIndex++; + if (countryCodes[m_countryIndex] != nullptr) + { + QString vorDBFile = getOpenAIPVORDBFilename(m_countryIndex); + QString urlString = getOpenAIPVORDBURL(m_countryIndex); + QUrl dbURL(urlString); + m_progressDialog->setLabelText(QString("Downloading %1.").arg(urlString)); + m_progressDialog->setValue(m_countryIndex); + m_dlm.download(dbURL, vorDBFile); + closeDialog = false; + } + else + { + readNavAids(); + if (m_vors != nullptr) + updateVORs(); + } + } + else + { + qDebug() << "VORDemodMCGUI::downloadFinished: Unexpected filename: " << filename; + } + } + else + { + qDebug() << "VORDemodMCGUI::downloadFinished: Failed: " << filename; + QMessageBox::warning(this, "Download failed", QString("Failed to download %1").arg(filename)); + } + if (closeDialog && m_progressDialog) + { + m_progressDialog->close(); + delete m_progressDialog; + m_progressDialog = nullptr; + } +} + +void VORDemodMCGUI::on_getOurAirportsVORDB_clicked(bool checked) +{ + (void) checked; + + // Don't try to download while already in progress + if (m_progressDialog == nullptr) + { + QString vorDBFile = getVORDBFilename(); + if (confirmDownload(vorDBFile)) + { + // Download OurAirports navaid database to disk + QUrl dbURL(QString(OURAIRPORTS_NAVAIDS_URL)); + m_progressDialog = new QProgressDialog(this); + m_progressDialog->setCancelButton(nullptr); + m_progressDialog->setMinimumDuration(500); + m_progressDialog->setLabelText(QString("Downloading %1.").arg(OURAIRPORTS_NAVAIDS_URL)); + QNetworkReply *reply = m_dlm.download(dbURL, vorDBFile); + connect(reply, SIGNAL(downloadProgress(qint64,qint64)), this, SLOT(updateDownloadProgress(qint64,qint64))); + } + } +} + +void VORDemodMCGUI::on_getOpenAIPVORDB_clicked(bool checked) +{ + (void) checked; + + // Don't try to download while already in progress + if (m_progressDialog == nullptr) + { + m_countryIndex = 0; + QString vorDBFile = getOpenAIPVORDBFilename(m_countryIndex); + if (confirmDownload(vorDBFile)) + { + // Download OpenAIP XML to disk + QString urlString = getOpenAIPVORDBURL(m_countryIndex); + QUrl dbURL(urlString); + m_progressDialog = new QProgressDialog(this); + m_progressDialog->setCancelButton(nullptr); + m_progressDialog->setMinimumDuration(500); + m_progressDialog->setMaximum(sizeof(countryCodes)/sizeof(countryCodes[0])); + m_progressDialog->setValue(0); + m_progressDialog->setLabelText(QString("Downloading %1.").arg(urlString)); + m_dlm.download(dbURL, vorDBFile); + } + } +} + +void VORDemodMCGUI::readNavAids() +{ + m_vors = new QHash(); + for (int countryIndex = 0; countryCodes[countryIndex] != nullptr; countryIndex++) + { + QString vorDBFile = getOpenAIPVORDBFilename(countryIndex); + NavAid::readNavAidsXML(m_vors, vorDBFile); + } +} + +void VORDemodMCGUI::on_magDecAdjust_clicked(bool checked) +{ + m_settings.m_magDecAdjust = checked; + m_vorModel.allVORUpdated(); + applySettings(); +} + +void VORDemodMCGUI::onWidgetRolled(QWidget* widget, bool rollDown) +{ + (void) widget; + (void) rollDown; + + RollupContents *rollupContents = getRollupContents(); + + if (rollupContents->hasExpandableWidgets()) { + setSizePolicy(sizePolicy().horizontalPolicy(), QSizePolicy::Expanding); + } else { + setSizePolicy(sizePolicy().horizontalPolicy(), QSizePolicy::Fixed); + } + + int h = rollupContents->height() + getAdditionalHeight(); + resize(width(), h); + + rollupContents->saveState(m_rollupState); + applySettings(); +} + +void VORDemodMCGUI::onMenuDialogCalled(const QPoint &p) +{ + if (m_contextMenuType == ContextMenuChannelSettings) + { + BasicChannelSettingsDialog dialog(&m_channelMarker, this); + dialog.setUseReverseAPI(m_settings.m_useReverseAPI); + dialog.setReverseAPIAddress(m_settings.m_reverseAPIAddress); + dialog.setReverseAPIPort(m_settings.m_reverseAPIPort); + dialog.setReverseAPIDeviceIndex(m_settings.m_reverseAPIDeviceIndex); + dialog.setReverseAPIChannelIndex(m_settings.m_reverseAPIChannelIndex); + dialog.setDefaultTitle(m_displayedName); + + if (m_deviceUISet->m_deviceMIMOEngine) + { + dialog.setNumberOfStreams(m_vorDemod->getNumberOfDeviceStreams()); + dialog.setStreamIndex(m_settings.m_streamIndex); + } + + dialog.move(p); + dialog.exec(); + + m_settings.m_rgbColor = m_channelMarker.getColor().rgb(); + m_settings.m_title = m_channelMarker.getTitle(); + m_settings.m_useReverseAPI = dialog.useReverseAPI(); + m_settings.m_reverseAPIAddress = dialog.getReverseAPIAddress(); + m_settings.m_reverseAPIPort = dialog.getReverseAPIPort(); + m_settings.m_reverseAPIDeviceIndex = dialog.getReverseAPIDeviceIndex(); + m_settings.m_reverseAPIChannelIndex = dialog.getReverseAPIChannelIndex(); + + setWindowTitle(m_settings.m_title); + setTitle(m_channelMarker.getTitle()); + setTitleColor(m_settings.m_rgbColor); + + if (m_deviceUISet->m_deviceMIMOEngine) + { + m_settings.m_streamIndex = dialog.getSelectedStreamIndex(); + m_channelMarker.clearStreamIndexes(); + m_channelMarker.addStreamIndex(m_settings.m_streamIndex); + updateIndexLabel(); + } + + applySettings(); + } + + resetContextMenuType(); +} + +VORDemodMCGUI::VORDemodMCGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, BasebandSampleSink *rxChannel, QWidget* parent) : + ChannelGUI(parent), + ui(new Ui::VORDemodMCGUI), + m_pluginAPI(pluginAPI), + m_deviceUISet(deviceUISet), + m_channelMarker(this), + m_deviceCenterFrequency(0), + m_doApplySettings(true), + m_squelchOpen(false), + m_tickCount(0), + m_progressDialog(nullptr), + m_vorModel(this), + m_vors(nullptr) +{ + setAttribute(Qt::WA_DeleteOnClose, true); + m_helpURL = "plugins/channelrx/demodvor/readme.md"; + RollupContents *rollupContents = getRollupContents(); + ui->setupUi(rollupContents); + setSizePolicy(rollupContents->sizePolicy()); + rollupContents->arrangeRollups(); + connect(rollupContents, SIGNAL(widgetRolled(QWidget*,bool)), this, SLOT(onWidgetRolled(QWidget*,bool))); + + ui->map->rootContext()->setContextProperty("vorModel", &m_vorModel); + ui->map->setSource(QUrl(QStringLiteral("qrc:/demodvor/map/map.qml"))); + + m_muteIcon.addPixmap(QPixmap("://sound_off.png"), QIcon::Normal, QIcon::On); + m_muteIcon.addPixmap(QPixmap("://sound_on.png"), QIcon::Normal, QIcon::Off); + + connect(this, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(onMenuDialogCalled(const QPoint &))); + connect(&m_dlm, &HttpDownloadManager::downloadComplete, this, &VORDemodMCGUI::downloadFinished); + + m_vorDemod = reinterpret_cast(rxChannel); + m_vorDemod->setMessageQueueToGUI(getInputMessageQueue()); + + connect(&MainCore::instance()->getMasterTimer(), SIGNAL(timeout()), this, SLOT(tick())); // 50 ms + + CRightClickEnabler *audioMuteRightClickEnabler = new CRightClickEnabler(ui->audioMute); + connect(audioMuteRightClickEnabler, SIGNAL(rightClick(const QPoint &)), this, SLOT(audioSelect())); + + ui->channelPowerMeter->setColorTheme(LevelMeterSignalDB::ColorGreenAndBlue); + + m_channelMarker.blockSignals(true); + m_channelMarker.setColor(Qt::yellow); + m_channelMarker.setBandwidth(2*48000); + m_channelMarker.setCenterFrequency(0); + m_channelMarker.setTitle("VOR Demodulator"); + m_channelMarker.blockSignals(false); + m_channelMarker.setVisible(true); // activate signal on the last setting only + + setTitleColor(m_channelMarker.getColor()); + m_settings.setChannelMarker(&m_channelMarker); + m_settings.setRollupState(&m_rollupState); + + m_deviceUISet->addChannelMarker(&m_channelMarker); + + connect(&m_channelMarker, SIGNAL(changedByCursor()), this, SLOT(channelMarkerChangedByCursor())); + connect(&m_channelMarker, SIGNAL(highlightedByCursor()), this, SLOT(channelMarkerHighlightedByCursor())); + connect(getInputMessageQueue(), SIGNAL(messageEnqueued()), this, SLOT(handleInputMessages())); + + // Get station position + Real stationLatitude = MainCore::instance()->getSettings().getLatitude(); + Real stationLongitude = MainCore::instance()->getSettings().getLongitude(); + Real stationAltitude = MainCore::instance()->getSettings().getAltitude(); + m_azEl.setLocation(stationLatitude, stationLongitude, stationAltitude); + + // Centre map at My Position + QQuickItem *item = ui->map->rootObject(); + QObject *object = item->findChild("map"); + if(object != NULL) + { + QGeoCoordinate coords = object->property("center").value(); + coords.setLatitude(stationLatitude); + coords.setLongitude(stationLongitude); + object->setProperty("center", QVariant::fromValue(coords)); + } + // Move antenna icon to My Position to start with + QObject *stationObject = item->findChild("station"); + if(stationObject != NULL) + { + QGeoCoordinate coords = stationObject->property("coordinate").value(); + coords.setLatitude(stationLatitude); + coords.setLongitude(stationLongitude); + coords.setAltitude(stationAltitude); + stationObject->setProperty("coordinate", QVariant::fromValue(coords)); + stationObject->setProperty("stationName", QVariant::fromValue(MainCore::instance()->getSettings().getStationName())); + } + + // Read in VOR information if it exists + bool useOurAirports = false; + if (useOurAirports) + { + m_vors = NavAid::readNavAidsDB(getVORDBFilename()); + ui->getOpenAIPVORDB->setVisible(false); + } + else + { + readNavAids(); + ui->getOurAirportsVORDB->setVisible(false); + } + if (m_vors != nullptr) + updateVORs(); + + // Resize the table using dummy data + resizeTable(); + // Allow user to reorder columns + ui->vorData->horizontalHeader()->setSectionsMovable(true); + // Allow user to sort table by clicking on headers + ui->vorData->setSortingEnabled(true); + // Add context menu to allow hiding/showing of columns + menu = new QMenu(ui->vorData); + for (int i = 0; i < ui->vorData->horizontalHeader()->count(); i++) + { + QString text = ui->vorData->horizontalHeaderItem(i)->text(); + menu->addAction(createCheckableItem(text, i, true)); + } + ui->vorData->horizontalHeader()->setContextMenuPolicy(Qt::CustomContextMenu); + connect(ui->vorData->horizontalHeader(), SIGNAL(customContextMenuRequested(QPoint)), SLOT(columnSelectMenu(QPoint))); + // Get signals when columns change + connect(ui->vorData->horizontalHeader(), SIGNAL(sectionMoved(int, int, int)), SLOT(vorData_sectionMoved(int, int, int))); + connect(ui->vorData->horizontalHeader(), SIGNAL(sectionResized(int, int, int)), SLOT(vorData_sectionResized(int, int, int))); + + displaySettings(); + makeUIConnections(); + applySettings(true); +} + +VORDemodMCGUI::~VORDemodMCGUI() +{ + delete ui; +} + +void VORDemodMCGUI::blockApplySettings(bool block) +{ + m_doApplySettings = !block; +} + +void VORDemodMCGUI::applySettings(bool force) +{ + if (m_doApplySettings) + { + VORDemodMC::MsgConfigureVORDemod* message = VORDemodMC::MsgConfigureVORDemod::create( m_settings, force); + m_vorDemod->getInputMessageQueue()->push(message); + } +} + +void VORDemodMCGUI::displaySettings() +{ + m_channelMarker.blockSignals(true); + m_channelMarker.setCenterFrequency(0); + m_channelMarker.setBandwidth(m_basebandSampleRate > 0 ? m_basebandSampleRate : 2*48000); + m_channelMarker.setTitle(m_settings.m_title); + m_channelMarker.blockSignals(false); + m_channelMarker.setColor(m_settings.m_rgbColor); // activate signal on the last setting only + + setTitleColor(m_settings.m_rgbColor); + setWindowTitle(m_channelMarker.getTitle()); + setTitle(m_channelMarker.getTitle()); + + blockApplySettings(true); + + ui->thresh->setValue(m_settings.m_identThreshold * 10.0); + ui->threshText->setText(QString("%1").arg(m_settings.m_identThreshold, 0, 'f', 1)); + + 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); + + updateIndexLabel(); + + // Order and size columns + QHeaderView *header = ui->vorData->horizontalHeader(); + for (int i = 0; i < VORDEMOD_COLUMNS; i++) + { + bool hidden = m_settings.m_columnSizes[i] == 0; + header->setSectionHidden(i, hidden); + menu->actions().at(i)->setChecked(!hidden); + if (m_settings.m_columnSizes[i] > 0) + ui->vorData->setColumnWidth(i, m_settings.m_columnSizes[i]); + header->moveSection(header->visualIndex(i), m_settings.m_columnIndexes[i]); + } + + getRollupContents()->restoreState(m_rollupState); + blockApplySettings(false); +} + +void VORDemodMCGUI::leaveEvent(QEvent* event) +{ + m_channelMarker.setHighlighted(false); + ChannelGUI::leaveEvent(event); +} + +void VORDemodMCGUI::enterEvent(QEvent* event) +{ + m_channelMarker.setHighlighted(true); + ChannelGUI::enterEvent(event); +} + +void VORDemodMCGUI::audioSelect() +{ + qDebug("VORDemodMCGUI::audioSelect"); + AudioSelectDialog audioSelect(DSPEngine::instance()->getAudioDeviceManager(), m_settings.m_audioDeviceName); + audioSelect.exec(); + + if (audioSelect.m_selected) + { + m_settings.m_audioDeviceName = audioSelect.m_audioDeviceName; + applySettings(); + } +} + +void VORDemodMCGUI::tick() +{ + double magsqAvg, magsqPeak; + int nbMagsqSamples; + m_vorDemod->getMagSqLevels(magsqAvg, magsqPeak, nbMagsqSamples); + double powDbAvg = CalcDb::dbPower(magsqAvg); + double powDbPeak = CalcDb::dbPower(magsqPeak); + + ui->channelPowerMeter->levelChanged( + (100.0f + powDbAvg) / 100.0f, + (100.0f + powDbPeak) / 100.0f, + nbMagsqSamples); + + if (m_tickCount % 4 == 0) { + ui->channelPower->setText(QString::number(powDbAvg, 'f', 1)); + } + + int audioSampleRate = m_vorDemod->getAudioSampleRate(); + bool squelchOpen = m_vorDemod->getSquelchOpen(); + + if (squelchOpen != m_squelchOpen) + { + if (audioSampleRate < 0) { + ui->audioMute->setStyleSheet("QToolButton { background-color : red; }"); + } else if (squelchOpen) { + ui->audioMute->setStyleSheet("QToolButton { background-color : green; }"); + } else { + ui->audioMute->setStyleSheet("QToolButton { background:rgb(79,79,79); }"); + } + + m_squelchOpen = squelchOpen; + } + + // Try to determine position, based on intersection of two radials + if (m_tickCount % 50) + { + float lat, lon; + + if (m_vorModel.findIntersection(lat, lon)) + { + // Move antenna icon to estimated position + QQuickItem *item = ui->map->rootObject(); + QObject *stationObject = item->findChild("station"); + if(stationObject != NULL) + { + QGeoCoordinate coords = stationObject->property("coordinate").value(); + coords.setLatitude(lat); + coords.setLongitude(lon); + stationObject->setProperty("coordinate", QVariant::fromValue(coords)); + stationObject->setProperty("stationName", QVariant::fromValue(MainCore::instance()->getSettings().getStationName())); + } + } + } + + m_tickCount++; +} + +void VORDemodMCGUI::makeUIConnections() +{ + QObject::connect(ui->audioMute, &QToolButton::toggled, this, &VORDemodMCGUI::on_audioMute_toggled); + QObject::connect(ui->thresh, &QDial::valueChanged, this, &VORDemodMCGUI::on_thresh_valueChanged); + QObject::connect(ui->volume, &QDial::valueChanged, this, &VORDemodMCGUI::on_volume_valueChanged); + QObject::connect(ui->squelch, &QDial::valueChanged, this, &VORDemodMCGUI::on_squelch_valueChanged); + QObject::connect(ui->audioMute, &QToolButton::toggled, this, &VORDemodMCGUI::on_audioMute_toggled); + QObject::connect(ui->getOurAirportsVORDB, &QPushButton::clicked, this, &VORDemodMCGUI::on_getOurAirportsVORDB_clicked); + QObject::connect(ui->getOpenAIPVORDB, &QPushButton::clicked, this, &VORDemodMCGUI::on_getOpenAIPVORDB_clicked); + QObject::connect(ui->magDecAdjust, &QPushButton::clicked, this, &VORDemodMCGUI::on_magDecAdjust_clicked); +} + +void VORDemodMCGUI::updateAbsoluteCenterFrequency() +{ + setStatusFrequency(m_deviceCenterFrequency); +} diff --git a/plugins/channelrx/demodvormc/vordemodmcgui.h b/plugins/channelrx/demodvormc/vordemodmcgui.h new file mode 100644 index 000000000..4a08a14a1 --- /dev/null +++ b/plugins/channelrx/demodvormc/vordemodmcgui.h @@ -0,0 +1,310 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2016 Edouard Griffiths, F4EXB // +// Copyright (C) 2020 Jon Beniston, M7RCE // +// // +// This program is free software; you can redistribute it and/or modify // +// it under the terms of the GNU General Public License as published by // +// the Free Software Foundation as version 3 of the License, or // +// (at your option) any later version. // +// // +// This program is distributed in the hope that it will be useful, // +// but WITHOUT ANY WARRANTY; without even the implied warranty of // +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // +// GNU General Public License V3 for more details. // +// // +// You should have received a copy of the GNU General Public License // +// along with this program. If not, see . // +/////////////////////////////////////////////////////////////////////////////////// + +#ifndef INCLUDE_VORDEMODGUI_H +#define INCLUDE_VORDEMODGUI_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "channel/channelgui.h" +#include "dsp/channelmarker.h" +#include "dsp/movingaverage.h" +#include "util/messagequeue.h" +#include "util/httpdownloadmanager.h" +#include "util/azel.h" +#include "settings/rollupstate.h" +#include "vordemodmcsettings.h" +#include "navaid.h" + +class PluginAPI; +class DeviceUISet; +class BasebandSampleSink; +class VORDemodMC; +class VORDemodMCGUI; + +namespace Ui { + class VORDemodMCGUI; +} +class VORDemodMCGUI; + +// Table items for each VOR +class VORGUI : public QObject { + Q_OBJECT +public: + NavAid *m_navAid; + QVariantList m_coordinates; + VORDemodMCGUI *m_gui; + + QTableWidgetItem *m_nameItem; + QTableWidgetItem *m_frequencyItem; + QTableWidgetItem *m_offsetItem; + QTableWidgetItem *m_identItem; + QTableWidgetItem *m_morseItem; + QTableWidgetItem *m_radialItem; + QTableWidgetItem *m_rxIdentItem; + QTableWidgetItem *m_rxMorseItem; + QTableWidgetItem *m_varMagItem; + QTableWidgetItem *m_refMagItem; + QWidget *m_muteItem; + QToolButton *m_muteButton; + + VORGUI(NavAid *navAid, VORDemodMCGUI *gui); +private slots: + void on_audioMute_toggled(bool checked); +}; + +// VOR model used for each VOR on the map +class VORModel : public QAbstractListModel { + Q_OBJECT + +public: + using QAbstractListModel::QAbstractListModel; + enum MarkerRoles{ + positionRole = Qt::UserRole + 1, + vorDataRole = Qt::UserRole + 2, + vorImageRole = Qt::UserRole + 3, + vorRadialRole = Qt::UserRole + 4, + bubbleColourRole = Qt::UserRole + 5, + selectedRole = Qt::UserRole + 6 + }; + + VORModel(VORDemodMCGUI *gui) : + m_gui(gui), + m_radialsVisible(true) + { + } + + Q_INVOKABLE void addVOR(NavAid *vor) { + beginInsertRows(QModelIndex(), rowCount(), rowCount()); + m_vors.append(vor); + m_selected.append(false); + m_radials.append(-1.0f); + m_vorGUIs.append(nullptr); + endInsertRows(); + } + + int rowCount(const QModelIndex &parent = QModelIndex()) const override { + Q_UNUSED(parent) + return m_vors.count(); + } + + QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; + + bool setData(const QModelIndex &index, const QVariant& value, int role = Qt::EditRole) override; + + Qt::ItemFlags flags(const QModelIndex &index) const override { + (void) index; + return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsEditable; + } + + void allVORUpdated() { + for (int i = 0; i < m_vors.count(); i++) + { + QModelIndex idx = index(i); + emit dataChanged(idx, idx); + } + } + + void removeVOR(NavAid *vor) { + int row = m_vors.indexOf(vor); + if (row >= 0) + { + beginRemoveRows(QModelIndex(), row, row); + m_vors.removeAt(row); + m_selected.removeAt(row); + m_radials.removeAt(row); + m_vorGUIs.removeAt(row); + endRemoveRows(); + } + } + + void removeAllVORs() { + if (m_vors.count() > 0) + { + beginRemoveRows(QModelIndex(), 0, m_vors.count() - 1); + m_vors.clear(); + m_selected.clear(); + m_radials.clear(); + m_vorGUIs.clear(); + endRemoveRows(); + } + } + + QHash roleNames() const { + QHash roles; + roles[positionRole] = "position"; + roles[vorDataRole] = "vorData"; + roles[vorImageRole] = "vorImage"; + roles[vorRadialRole] = "vorRadial"; + roles[bubbleColourRole] = "bubbleColour"; + roles[selectedRole] = "selected"; + return roles; + } + + void setRadialsVisible(bool radialsVisible) + { + m_radialsVisible = radialsVisible; + allVORUpdated(); + } + + void setRadial(int id, bool valid, Real radial) + { + for (int i = 0; i < m_vors.count(); i++) + { + if (m_vors[i]->m_id == id) + { + if (valid) + m_radials[i] = radial; + else + m_radials[i] = -1; // -1 to indicate invalid + QModelIndex idx = index(i); + emit dataChanged(idx, idx); + break; + } + } + } + + bool findIntersection(float &lat, float &lon); + +private: + VORDemodMCGUI *m_gui; + bool m_radialsVisible; + QList m_vors; + QList m_selected; + QList m_radials; + QList m_vorGUIs; +}; + +class VORDemodMCGUI : public ChannelGUI { + Q_OBJECT + +public: + static VORDemodMCGUI* create(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, BasebandSampleSink *rxChannel); + virtual void destroy(); + + void resetToDefaults(); + QByteArray serialize() const; + bool deserialize(const QByteArray& data); + virtual MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; } + virtual void setWorkspaceIndex(int index) { m_settings.m_workspaceIndex = index; }; + virtual int getWorkspaceIndex() const { return m_settings.m_workspaceIndex; }; + virtual void setGeometryBytes(const QByteArray& blob) { m_settings.m_geometryBytes = blob; }; + virtual QByteArray getGeometryBytes() const { return m_settings.m_geometryBytes; }; + virtual QString getTitle() const { return m_settings.m_title; }; + virtual QColor getTitleColor() const { return m_settings.m_rgbColor; }; + virtual void zetHidden(bool hidden) { m_settings.m_hidden = hidden; } + virtual bool getHidden() const { return m_settings.m_hidden; } + virtual ChannelMarker& getChannelMarker() { return m_channelMarker; } + virtual int getStreamIndex() const { return m_settings.m_streamIndex; } + virtual void setStreamIndex(int streamIndex) { m_settings.m_streamIndex = streamIndex; } + + void selectVOR(VORGUI *vorGUI, bool selected); + +public slots: + void channelMarkerChangedByCursor(); + void channelMarkerHighlightedByCursor(); + +private: + friend class VORGUI; + friend class VORModel; + + Ui::VORDemodMCGUI* ui; + PluginAPI* m_pluginAPI; + DeviceUISet* m_deviceUISet; + ChannelMarker m_channelMarker; + RollupState m_rollupState; + VORDemodMCSettings m_settings; + qint64 m_deviceCenterFrequency; + bool m_doApplySettings; + + VORDemodMC* m_vorDemod; + bool m_squelchOpen; + int m_basebandSampleRate; + uint32_t m_tickCount; + MessageQueue m_inputMessageQueue; + + QMenu *menu; // Column select context menu + HttpDownloadManager m_dlm; + QProgressDialog *m_progressDialog; + int m_countryIndex; + VORModel m_vorModel; + QHash *m_vors; + QHash m_selectedVORs; + AzEl m_azEl; // Position of station + QIcon m_muteIcon; + + explicit VORDemodMCGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, BasebandSampleSink *rxChannel, QWidget* parent = 0); + virtual ~VORDemodMCGUI(); + + void blockApplySettings(bool block); + void applySettings(bool force = false); + void displaySettings(); + bool handleMessage(const Message& message); + void makeUIConnections(); + void updateAbsoluteCenterFrequency(); + + void leaveEvent(QEvent*); + void enterEvent(QEvent*); + + void resizeTable(); + QAction *createCheckableItem(QString& text, int idx, bool checked); + + void calculateFreqOffset(VORGUI *vorGUI); + void calculateFreqOffsets(); + void updateVORs(); + QString getOpenAIPVORDBURL(int i); + QString getOpenAIPVORDBFilename(int i); + QString getVORDBFilename(); + void readNavAids(); + // Move to util + QString getDataDir(); + qint64 fileAgeInDays(QString filename); + bool confirmDownload(QString filename); + +private slots: + void on_thresh_valueChanged(int value); + void on_volume_valueChanged(int value); + void on_squelch_valueChanged(int value); + void on_audioMute_toggled(bool checked); + void on_getOurAirportsVORDB_clicked(bool checked = false); + void on_getOpenAIPVORDB_clicked(bool checked = false); + void on_magDecAdjust_clicked(bool checked = false); + void vorData_sectionMoved(int logicalIndex, int oldVisualIndex, int newVisualIndex); + void vorData_sectionResized(int logicalIndex, int oldSize, int newSize); + void columnSelectMenu(QPoint pos); + void columnSelectMenuChecked(bool checked = false); + void onWidgetRolled(QWidget* widget, bool rollDown); + void onMenuDialogCalled(const QPoint& p); + void updateDownloadProgress(qint64 bytesRead, qint64 totalBytes); + void downloadFinished(const QString& filename, bool success); + void handleInputMessages(); + void audioSelect(); + void tick(); +}; + +#endif // INCLUDE_VORDEMODGUI_H diff --git a/plugins/channelrx/demodvorsc/vordemodscgui.ui b/plugins/channelrx/demodvormc/vordemodmcgui.ui similarity index 56% rename from plugins/channelrx/demodvorsc/vordemodscgui.ui rename to plugins/channelrx/demodvormc/vordemodmcgui.ui index 979ba148e..264377ed6 100644 --- a/plugins/channelrx/demodvorsc/vordemodscgui.ui +++ b/plugins/channelrx/demodvormc/vordemodmcgui.ui @@ -1,17 +1,17 @@ - VORDemodSCGUI - + VORDemodMCGUI + 0 0 - 402 - 189 + 398 + 893 - + 0 0 @@ -19,7 +19,7 @@ 352 - 110 + 0 @@ -32,7 +32,7 @@ Qt::StrongFocus - VOR Demodulator + VOR MC Demodulator @@ -40,7 +40,7 @@ 0 0 390 - 131 + 61 @@ -68,81 +68,6 @@ 2 - - - - 2 - - - - - - - - 16 - 0 - - - - Df - - - - - - - - 0 - 0 - - - - - 32 - 16 - - - - - Liberation Mono - 12 - - - - PointingHandCursor - - - Qt::StrongFocus - - - Demod shift frequency from center in Hz - - - - - - - Hz - - - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - @@ -195,12 +120,6 @@ - - - 40 - 0 - - Channel power @@ -208,10 +127,7 @@ Qt::RightToLeft - -100.0 - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + 0.0 @@ -246,6 +162,70 @@ + + + + true + + + Download OurAirports VOR database + + + + + + + :/demodvor/icons/vor.png:/demodvor/icons/vor.png + + + + + + + Download OpenAIP VOR database + + + + + + + :/demodvor/icons/vor.png:/demodvor/icons/vor.png + + + + + + + Draw radials adjusted for magnetic declination + + + + + + + :/demodvor/icons/compass.png:/demodvor/icons/compass.png + + + true + + + true + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + @@ -276,9 +256,6 @@ 100 - - 1 - 0 @@ -307,17 +284,11 @@ - + - Qt::Horizontal + Qt::Vertical - - - 40 - 20 - - - + @@ -343,9 +314,6 @@ 0 - - 1 - -40 @@ -395,9 +363,6 @@ 100 - - 1 - @@ -418,205 +383,219 @@ + + + + + + 0 + 80 + 391 + 141 + + + + + 0 + 0 + + + + VORs + + + + 2 + + + 3 + + + 3 + + + 3 + + + 3 + - - - - - - 20 - 0 - - - - Rad - - - - - - - - 0 - 0 - - - - - 30 - 0 - - - - Radial direction (degrees) red if low confidence - - - 359d - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - Qt::Vertical - - - - - - - Ref - - - - - - - - 50 - 0 - - - - Magnitude of the received 30Hz FM reference signal in dB - - - -100 dB - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - Qt::Vertical - - - - - - - Var - - - - - - - - 50 - 0 - - - - Magnitude of the received 30Hz AM variable signal in dB - - - -100 dB - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - + + + + 0 + 140 + + + + QAbstractItemView::NoEditTriggers + + + + Name + + + Name of the VOR + + + + + Freq (MHz) + + + Frequency of the VOR in MHz + + + + + Offset (kHz) + + + Offset of the VOR's frequency from the current center frequency. Red indicates out of range. + + + + + Ident + + + Ident for the VOR + + + + + Morse + + + Morse code ident for the VOR + + + + + RX Ident + + + Received ident + + + + + RX Morse + + + Received Morse code ident + + + + + Radial (°) + + + Calculated radial from the VOR + + + + + Ref (dB) + + + Magnitude of received reference signal in dB + + + + + Var (dB) + + + Magnitude of received variable signal in dB + + + + + Mute + + + Mute/unmute audio from selected VORs + + + + + + + + + 0 + 260 + 391 + 581 + + + + + 0 + 0 + + + + Map + + + + 2 + + + 3 + + + 3 + + + 3 + + + 3 + - - - - - Ident - - - - - - - - 50 - 0 - - - - Decoded identity code yellow if not matching rules - - - XXX - - - - - - - Qt::Vertical - - - - - - - Morse - - - - - - - - 120 - 0 - - - - Morse identity decoded yellow if not matching rules - - - --- --- --- - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - + + + + 0 + 0 + + + + + 100 + 500 + + + + VOR map + + + QQuickWidget::SizeRootObjectToView + + + + + + + - RollupWidget + QQuickWidget QWidget -
gui/rollupwidget.h
+
QtQuickWidgets/QQuickWidget
+
+ + RollupContents + QWidget +
gui/rollupcontents.h
1
@@ -625,18 +604,16 @@
gui/levelmeter.h
1
- - ValueDialZ - QWidget -
gui/valuedialz.h
- 1 -
audioMute + getOurAirportsVORDB + vorData + map + diff --git a/plugins/channelrx/demodvorsc/vordemodscplugin.cpp b/plugins/channelrx/demodvormc/vordemodmcplugin.cpp similarity index 70% rename from plugins/channelrx/demodvorsc/vordemodscplugin.cpp rename to plugins/channelrx/demodvormc/vordemodmcplugin.cpp index 7794fbc66..8027a177a 100644 --- a/plugins/channelrx/demodvorsc/vordemodscplugin.cpp +++ b/plugins/channelrx/demodvormc/vordemodmcplugin.cpp @@ -20,15 +20,15 @@ #include "plugin/pluginapi.h" #ifndef SERVER_MODE -#include "vordemodscgui.h" +#include "vordemodmcgui.h" #endif -#include "vordemodsc.h" -#include "vordemodscwebapiadapter.h" -#include "vordemodscplugin.h" +#include "vordemodmc.h" +#include "vordemodmcwebapiadapter.h" +#include "vordemodmcplugin.h" -const PluginDescriptor VORDemodSCPlugin::m_pluginDescriptor = { - VORDemodSC::m_channelId, - QStringLiteral("VOR Single Channel Demodulator"), +const PluginDescriptor VORDemodMCPlugin::m_pluginDescriptor = { + VORDemodMC::m_channelId, + QStringLiteral("VOR Multi Channel Demodulator"), QStringLiteral("6.20.2"), QStringLiteral("(c) Jon Beniston, M7RCE"), QStringLiteral("https://github.com/f4exb/sdrangel"), @@ -36,29 +36,29 @@ const PluginDescriptor VORDemodSCPlugin::m_pluginDescriptor = { QStringLiteral("https://github.com/f4exb/sdrangel") }; -VORDemodSCPlugin::VORDemodSCPlugin(QObject* parent) : +VORDemodMCPlugin::VORDemodMCPlugin(QObject* parent) : QObject(parent), m_pluginAPI(0) { } -const PluginDescriptor& VORDemodSCPlugin::getPluginDescriptor() const +const PluginDescriptor& VORDemodMCPlugin::getPluginDescriptor() const { return m_pluginDescriptor; } -void VORDemodSCPlugin::initPlugin(PluginAPI* pluginAPI) +void VORDemodMCPlugin::initPlugin(PluginAPI* pluginAPI) { m_pluginAPI = pluginAPI; - m_pluginAPI->registerRxChannel(VORDemodSC::m_channelIdURI, VORDemodSC::m_channelId, this); + m_pluginAPI->registerRxChannel(VORDemodMC::m_channelIdURI, VORDemodMC::m_channelId, this); } -void VORDemodSCPlugin::createRxChannel(DeviceAPI *deviceAPI, BasebandSampleSink **bs, ChannelAPI **cs) const +void VORDemodMCPlugin::createRxChannel(DeviceAPI *deviceAPI, BasebandSampleSink **bs, ChannelAPI **cs) const { if (bs || cs) { - VORDemodSC *instance = new VORDemodSC(deviceAPI); + VORDemodMC *instance = new VORDemodMC(deviceAPI); if (bs) { *bs = instance; @@ -71,7 +71,7 @@ void VORDemodSCPlugin::createRxChannel(DeviceAPI *deviceAPI, BasebandSampleSink } #ifdef SERVER_MODE -ChannelGUI* VORDemodSCPlugin::createRxChannelGUI( +ChannelGUI* VORDemodMCPlugin::createRxChannelGUI( DeviceUISet *deviceUISet, BasebandSampleSink *rxChannel) const { @@ -80,13 +80,13 @@ ChannelGUI* VORDemodSCPlugin::createRxChannelGUI( return 0; } #else -ChannelGUI* VORDemodSCPlugin::createRxChannelGUI(DeviceUISet *deviceUISet, BasebandSampleSink *rxChannel) const +ChannelGUI* VORDemodMCPlugin::createRxChannelGUI(DeviceUISet *deviceUISet, BasebandSampleSink *rxChannel) const { - return VORDemodSCGUI::create(m_pluginAPI, deviceUISet, rxChannel); + return VORDemodMCGUI::create(m_pluginAPI, deviceUISet, rxChannel); } #endif -ChannelWebAPIAdapter* VORDemodSCPlugin::createChannelWebAPIAdapter() const +ChannelWebAPIAdapter* VORDemodMCPlugin::createChannelWebAPIAdapter() const { - return new VORDemodSCWebAPIAdapter(); + return new VORDemodMCWebAPIAdapter(); } diff --git a/plugins/channelrx/demodvorsc/vordemodscplugin.h b/plugins/channelrx/demodvormc/vordemodmcplugin.h similarity index 88% rename from plugins/channelrx/demodvorsc/vordemodscplugin.h rename to plugins/channelrx/demodvormc/vordemodmcplugin.h index 7bbb55c86..49f3bf0b8 100644 --- a/plugins/channelrx/demodvorsc/vordemodscplugin.h +++ b/plugins/channelrx/demodvormc/vordemodmcplugin.h @@ -16,8 +16,8 @@ // along with this program. If not, see . // /////////////////////////////////////////////////////////////////////////////////// -#ifndef INCLUDE_VORDEMODSCPLUGIN_H -#define INCLUDE_VORDEMODSCPLUGIN_H +#ifndef INCLUDE_VORDEMODPLUGIN_H +#define INCLUDE_VORDEMODPLUGIN_H #include #include "plugin/plugininterface.h" @@ -25,13 +25,13 @@ class DeviceUISet; class BasebandSampleSink; -class VORDemodSCPlugin : public QObject, PluginInterface { +class VORDemodMCPlugin : public QObject, PluginInterface { Q_OBJECT Q_INTERFACES(PluginInterface) - Q_PLUGIN_METADATA(IID "sdrangel.channel.vordemodsc") + Q_PLUGIN_METADATA(IID "sdrangel.channel.vordemodmc") public: - explicit VORDemodSCPlugin(QObject* parent = NULL); + explicit VORDemodMCPlugin(QObject* parent = NULL); const PluginDescriptor& getPluginDescriptor() const; void initPlugin(PluginAPI* pluginAPI); @@ -46,4 +46,4 @@ private: PluginAPI* m_pluginAPI; }; -#endif // INCLUDE_VORDEMODSCPLUGIN_H +#endif // INCLUDE_VORDEMODPLUGIN_H diff --git a/plugins/channelrx/demodvorsc/vordemodscreport.cpp b/plugins/channelrx/demodvormc/vordemodmcreport.cpp similarity index 85% rename from plugins/channelrx/demodvorsc/vordemodscreport.cpp rename to plugins/channelrx/demodvormc/vordemodmcreport.cpp index 1bc6842c8..524713e44 100644 --- a/plugins/channelrx/demodvorsc/vordemodscreport.cpp +++ b/plugins/channelrx/demodvormc/vordemodmcreport.cpp @@ -15,7 +15,8 @@ // along with this program. If not, see . // /////////////////////////////////////////////////////////////////////////////////// -#include "vordemodscreport.h" +#include "vordemodmcreport.h" -MESSAGE_CLASS_DEFINITION(VORDemodSCReport::MsgReportRadial, Message) -MESSAGE_CLASS_DEFINITION(VORDemodSCReport::MsgReportIdent, Message) +MESSAGE_CLASS_DEFINITION(VORDemodMCReport::MsgReportFreqOffset, Message) +MESSAGE_CLASS_DEFINITION(VORDemodMCReport::MsgReportRadial, Message) +MESSAGE_CLASS_DEFINITION(VORDemodMCReport::MsgReportIdent, Message) diff --git a/plugins/channelrx/demodvorsc/vordemodscreport.h b/plugins/channelrx/demodvormc/vordemodmcreport.h similarity index 56% rename from plugins/channelrx/demodvorsc/vordemodscreport.h rename to plugins/channelrx/demodvormc/vordemodmcreport.h index 1da87bf76..58849c63c 100644 --- a/plugins/channelrx/demodvorsc/vordemodscreport.h +++ b/plugins/channelrx/demodvormc/vordemodmcreport.h @@ -16,14 +16,14 @@ // along with this program. If not, see . // /////////////////////////////////////////////////////////////////////////////////// -#ifndef INCLUDE_VORDEMODSCREPORT_H -#define INCLUDE_VORDEMODSCREPORT_H +#ifndef INCLUDE_VORDEMODREPORT_H +#define INCLUDE_VORDEMODREPORT_H #include #include "util/message.h" -class VORDemodSCReport : public QObject +class VORDemodMCReport : public QObject { Q_OBJECT public: @@ -31,21 +31,25 @@ public: MESSAGE_CLASS_DECLARATION public: + int getSubChannelId() const { return m_subChannelId; } float getRadial() const { return m_radial; } float getRefMag() const { return m_refMag; } float getVarMag() const { return m_varMag; } - static MsgReportRadial* create(float radial, float refMag, float varMag) { - return new MsgReportRadial(radial, refMag, varMag); + static MsgReportRadial* create(int subChannelId, float radial, float refMag, float varMag) + { + return new MsgReportRadial(subChannelId, radial, refMag, varMag); } private: + int m_subChannelId; float m_radial; float m_refMag; float m_varMag; - MsgReportRadial(float radial, float refMag, float varMag) : + MsgReportRadial(int subChannelId, float radial, float refMag, float varMag) : Message(), + m_subChannelId(subChannelId), m_radial(radial), m_refMag(refMag), m_varMag(varMag) @@ -53,30 +57,60 @@ public: } }; + class MsgReportFreqOffset : public Message { + MESSAGE_CLASS_DECLARATION + + public: + int getSubChannelId() const { return m_subChannelId; } + int getFreqOffset() const { return m_freqOffset; } + bool getOutOfBand() const { return m_outOfBand; } + + static MsgReportFreqOffset* create(int subChannelId, int freqOffset, bool outOfBand) + { + return new MsgReportFreqOffset(subChannelId, freqOffset, outOfBand); + } + + private: + int m_subChannelId; + int m_freqOffset; + bool m_outOfBand; + + MsgReportFreqOffset(int subChannelId, int freqOffset, bool outOfBand) : + Message(), + m_subChannelId(subChannelId), + m_freqOffset(freqOffset), + m_outOfBand(outOfBand) + { + } + }; + class MsgReportIdent : public Message { MESSAGE_CLASS_DECLARATION public: + int getSubChannelId() const { return m_subChannelId; } QString getIdent() const { return m_ident; } - static MsgReportIdent* create(QString ident) + static MsgReportIdent* create(int subChannelId, QString ident) { - return new MsgReportIdent(ident); + return new MsgReportIdent(subChannelId, ident); } private: + int m_subChannelId; QString m_ident; - MsgReportIdent(QString ident) : + MsgReportIdent(int subChannelId, QString ident) : Message(), + m_subChannelId(subChannelId), m_ident(ident) { } }; public: - VORDemodSCReport() {} - ~VORDemodSCReport() {} + VORDemodMCReport() {} + ~VORDemodMCReport() {} }; -#endif // INCLUDE_VORDEMODSCREPORT_H +#endif // INCLUDE_VORDEMODREPORT_H diff --git a/plugins/channelrx/demodvorsc/vordemodscsettings.cpp b/plugins/channelrx/demodvormc/vordemodmcsettings.cpp similarity index 77% rename from plugins/channelrx/demodvorsc/vordemodscsettings.cpp rename to plugins/channelrx/demodvormc/vordemodmcsettings.cpp index 3d4dab2b6..fbcfcf6ee 100644 --- a/plugins/channelrx/demodvorsc/vordemodscsettings.cpp +++ b/plugins/channelrx/demodvormc/vordemodmcsettings.cpp @@ -21,19 +21,17 @@ #include "dsp/dspengine.h" #include "util/simpleserializer.h" #include "settings/serializable.h" -#include "vordemodscsettings.h" +#include "vordemodmcsettings.h" -VORDemodSCSettings::VORDemodSCSettings() : +VORDemodMCSettings::VORDemodMCSettings() : m_channelMarker(nullptr), m_rollupState(nullptr) { resetToDefaults(); } -void VORDemodSCSettings::resetToDefaults() +void VORDemodMCSettings::resetToDefaults() { - m_inputFrequencyOffset = 0; - m_navId = -1; m_squelch = -60.0; m_volume = 2.0; m_audioMute = false; @@ -46,16 +44,24 @@ void VORDemodSCSettings::resetToDefaults() m_reverseAPIPort = 8888; m_reverseAPIDeviceIndex = 0; m_reverseAPIChannelIndex = 0; + m_workspaceIndex = 0; + m_hidden = false; m_identThreshold = 2.0; m_refThresholdDB = -45.0; m_varThresholdDB = -90.0; + m_magDecAdjust = true; + + for (int i = 0; i < VORDEMOD_COLUMNS; i++) + { + m_columnIndexes[i] = i; + m_columnSizes[i] = -1; // Autosize + } } -QByteArray VORDemodSCSettings::serialize() const +QByteArray VORDemodMCSettings::serialize() const { SimpleSerializer s(1); - s.writeS32(1, m_inputFrequencyOffset); s.writeS32(3, m_streamIndex); s.writeS32(4, m_volume*10); s.writeS32(5, m_squelch); @@ -75,15 +81,28 @@ QByteArray VORDemodSCSettings::serialize() const s.writeReal(20, m_identThreshold); s.writeReal(21, m_refThresholdDB); s.writeReal(22, m_varThresholdDB); + s.writeBool(23, m_magDecAdjust); if (m_rollupState) { - s.writeBlob(23, m_rollupState->serialize()); + s.writeBlob(24, m_rollupState->serialize()); + } + + s.writeS32(25, m_workspaceIndex); + s.writeBlob(26, m_geometryBytes); + s.writeBool(27, m_hidden); + + for (int i = 0; i < VORDEMOD_COLUMNS; i++) { + s.writeS32(100 + i, m_columnIndexes[i]); + } + + for (int i = 0; i < VORDEMOD_COLUMNS; i++) { + s.writeS32(200 + i, m_columnSizes[i]); } return s.final(); } -bool VORDemodSCSettings::deserialize(const QByteArray& data) +bool VORDemodMCSettings::deserialize(const QByteArray& data) { SimpleDeserializer d(data); @@ -100,7 +119,6 @@ bool VORDemodSCSettings::deserialize(const QByteArray& data) uint32_t utmp; QString strtmp; - d.readS32(1, &m_inputFrequencyOffset, 0); d.readS32(3, &m_streamIndex, 0); d.readS32(4, &tmp, 20); m_volume = tmp * 0.1; @@ -133,13 +151,26 @@ bool VORDemodSCSettings::deserialize(const QByteArray& data) d.readReal(20, &m_identThreshold, 2.0); d.readReal(21, &m_refThresholdDB, -45.0); d.readReal(22, &m_varThresholdDB, -90.0); + d.readBool(23, &m_magDecAdjust, true); if (m_rollupState) { - d.readBlob(23, &bytetmp); + d.readBlob(24, &bytetmp); m_rollupState->deserialize(bytetmp); } + d.readS32(25, &m_workspaceIndex, 0); + d.readBlob(26, &m_geometryBytes); + d.readBool(27, &m_hidden, false); + + for (int i = 0; i < VORDEMOD_COLUMNS; i++) { + d.readS32(100 + i, &m_columnIndexes[i], i); + } + + for (int i = 0; i < VORDEMOD_COLUMNS; i++) { + d.readS32(200 + i, &m_columnSizes[i], -1); + } + return true; } else diff --git a/plugins/channelrx/demodvorsc/vordemodscsettings.h b/plugins/channelrx/demodvormc/vordemodmcsettings.h similarity index 73% rename from plugins/channelrx/demodvorsc/vordemodscsettings.h rename to plugins/channelrx/demodvormc/vordemodmcsettings.h index 5a9a6f898..907a1fa7d 100644 --- a/plugins/channelrx/demodvorsc/vordemodscsettings.h +++ b/plugins/channelrx/demodvormc/vordemodmcsettings.h @@ -16,18 +16,25 @@ // along with this program. If not, see . // /////////////////////////////////////////////////////////////////////////////////// -#ifndef INCLUDE_VORDEMODSCSETTINGS_H -#define INCLUDE_VORDEMODSCSETTINGS_H +#ifndef INCLUDE_VORDEMODSETTINGS_H +#define INCLUDE_VORDEMODSETTINGS_H #include #include class Serializable; -struct VORDemodSCSettings +// Number of columns in the table +#define VORDEMOD_COLUMNS 11 + +struct VORDemodSubChannelSettings { + int m_id; //!< Unique VOR identifier (from database) + int m_frequency; //!< Frequency the VOR is on + bool m_audioMute; //!< Mute the audio from this VOR +}; + +struct VORDemodMCSettings { - qint32 m_inputFrequencyOffset; - int m_navId; //!< VOR unique identifier when set by VOR localizer feature Real m_squelch; Real m_volume; bool m_audioMute; @@ -45,17 +52,18 @@ struct VORDemodSCSettings Real m_identThreshold; //!< Linear SNR threshold for Morse demodulator Real m_refThresholdDB; //!< Threshold in dB for valid VOR reference signal Real m_varThresholdDB; //!< Threshold in dB for valid VOR variable signal + bool m_magDecAdjust; //!< Adjust for magnetic declination when drawing radials on the map Serializable *m_rollupState; + int m_workspaceIndex; + QByteArray m_geometryBytes; + bool m_hidden; - // Highest frequency is the FM subcarrier at up to ~11kHz - // However, old VORs can have 0.005% frequency offset, which is 6kHz - static const int VORDEMOD_CHANNEL_BANDWIDTH = 18000; - // Sample rate needs to be at least twice the above - // Also need to consider impact frequency resolution of Goertzel filters - // May as well make it a common audio rate, to possibly avoid decimation - static const int VORDEMOD_CHANNEL_SAMPLE_RATE = 48000; + int m_columnIndexes[VORDEMOD_COLUMNS];//!< How the columns are ordered in the table + int m_columnSizes[VORDEMOD_COLUMNS]; //!< Size of the coumns in the table - VORDemodSCSettings(); + QHash m_subChannelSettings; + + VORDemodMCSettings(); void resetToDefaults(); void setChannelMarker(Serializable *channelMarker) { m_channelMarker = channelMarker; } void setRollupState(Serializable *rollupState) { m_rollupState = rollupState; } @@ -63,4 +71,4 @@ struct VORDemodSCSettings bool deserialize(const QByteArray& data); }; -#endif /* INCLUDE_VORDEMODSCSETTINGS_H */ +#endif /* INCLUDE_VORDEMODSETTINGS_H */ diff --git a/plugins/channelrx/demodvorsc/vordemodscsink.cpp b/plugins/channelrx/demodvormc/vordemodmcsink.cpp similarity index 75% rename from plugins/channelrx/demodvorsc/vordemodscsink.cpp rename to plugins/channelrx/demodvormc/vordemodmcsink.cpp index 0ca67c9d1..ab84286c1 100644 --- a/plugins/channelrx/demodvorsc/vordemodscsink.cpp +++ b/plugins/channelrx/demodvormc/vordemodmcsink.cpp @@ -27,13 +27,14 @@ #include "util/morse.h" #include "util/units.h" -#include "vordemodscreport.h" -#include "vordemodscsettings.h" -#include "vordemodscsink.h" +#include "vordemodmcsink.h" +#include "vordemodmcreport.h" -VORDemodSCSink::VORDemodSCSink() : +VORDemodMCSink::VORDemodMCSink(const VORDemodMCSettings& settings, int subChannel, + MessageQueue *messageQueueToGUI) : m_channelFrequencyOffset(0), - m_channelSampleRate(VORDemodSCSettings::VORDEMOD_CHANNEL_SAMPLE_RATE), + m_outOfBand(true), + m_channelSampleRate(VORDEMOD_CHANNEL_SAMPLE_RATE), m_audioSampleRate(48000), m_squelchCount(0), m_squelchOpen(false), @@ -41,32 +42,42 @@ VORDemodSCSink::VORDemodSCSink() : m_magsqSum(0.0f), m_magsqPeak(0.0f), m_magsqCount(0), + m_messageQueueToGUI(messageQueueToGUI), m_volumeAGC(0.003), m_audioFifo(48000), m_refPrev(0.0f), m_movingAverageIdent(5000), m_prevBit(0), m_bitTime(0), - m_varGoertzel(30, VORDemodSCSettings::VORDEMOD_CHANNEL_SAMPLE_RATE), - m_refGoertzel(30, VORDemodSCSettings::VORDEMOD_CHANNEL_SAMPLE_RATE) + m_varGoertzel(30, VORDEMOD_CHANNEL_SAMPLE_RATE), + m_refGoertzel(30, VORDEMOD_CHANNEL_SAMPLE_RATE) { - m_audioBuffer.resize(1<<14); - m_audioBufferFill = 0; + m_audioBuffer.resize(1<<14); + m_audioBufferFill = 0; - m_magsq = 0.0; + m_magsq = 0.0; - applySettings(m_settings, true); - applyChannelSettings(m_channelSampleRate, m_channelFrequencyOffset, true); + qDebug() << "Sink " << subChannel; + if (subChannel >= 0) + { + m_subChannelId = subChannel; + m_vorFrequencyHz = settings.m_subChannelSettings[subChannel]->m_frequency; + + applySettings(settings, true); + } } -VORDemodSCSink::~VORDemodSCSink() +VORDemodMCSink::~VORDemodMCSink() { } -void VORDemodSCSink::feed(const SampleVector::const_iterator& begin, const SampleVector::const_iterator& end) +void VORDemodMCSink::feed(const SampleVector::const_iterator& begin, const SampleVector::const_iterator& end) { Complex ci; + if (m_outOfBand) + return; + for (SampleVector::const_iterator it = begin; it != end; ++it) { Complex c(it->real(), it->imag()); @@ -91,7 +102,7 @@ void VORDemodSCSink::feed(const SampleVector::const_iterator& begin, const Sampl } } -void VORDemodSCSink::processOneAudioSample(Complex &ci) +void VORDemodMCSink::processOneAudioSample(Complex &ci) { Real re = ci.real() / SDR_RX_SCALEF; Real im = ci.imag() / SDR_RX_SCALEF; @@ -126,7 +137,7 @@ void VORDemodSCSink::processOneAudioSample(Complex &ci) m_squelchOpen = (m_squelchCount >= (unsigned int)m_audioSampleRate / 20); - if (m_squelchOpen && !m_settings.m_audioMute) + if (m_squelchOpen && !m_settings.m_audioMute && !m_settings.m_subChannelSettings.value(m_subChannelId)->m_audioMute) { Real demod; @@ -156,7 +167,7 @@ void VORDemodSCSink::processOneAudioSample(Complex &ci) if (res != m_audioBufferFill) { - qDebug("VORDemodSCSink::processOneAudioSample: %u/%u audio samples written", res, m_audioBufferFill); + qDebug("VORDemodMCSink::processOneAudioSample: %u/%u audio samples written", res, m_audioBufferFill); m_audioFifo.clear(); } @@ -165,7 +176,7 @@ void VORDemodSCSink::processOneAudioSample(Complex &ci) } -void VORDemodSCSink::processOneSample(Complex &ci) +void VORDemodMCSink::processOneSample(Complex &ci) { Complex ca; @@ -197,7 +208,7 @@ void VORDemodSCSink::processOneSample(Complex &ci) // Calculate phase of 30Hz variable AM signal double varPhase; double varMag; - if (m_varGoertzel.size() == VORDemodSCSettings::VORDEMOD_CHANNEL_SAMPLE_RATE - 1) + if (m_varGoertzel.size() == VORDEMOD_CHANNEL_SAMPLE_RATE - 1) { m_varGoertzel.goertzel(mag); varPhase = Units::radiansToDegrees(m_varGoertzel.phase()); @@ -220,13 +231,13 @@ void VORDemodSCSink::processOneSample(Complex &ci) m_refPrev = fmfilt; // Calculate phase of 30Hz reference FM signal - if (m_refGoertzel.size() == VORDemodSCSettings::VORDEMOD_CHANNEL_SAMPLE_RATE - 1) + if (m_refGoertzel.size() == VORDEMOD_CHANNEL_SAMPLE_RATE - 1) { m_refGoertzel.goertzel(phi); float phaseDeg = Units::radiansToDegrees(m_refGoertzel.phase()); double refMag = m_refGoertzel.mag(); int groupDelay = (301-1)/2; - float filterPhaseShift = 360.0*30.0*groupDelay/VORDemodSCSettings::VORDEMOD_CHANNEL_SAMPLE_RATE; + float filterPhaseShift = 360.0*30.0*groupDelay/VORDEMOD_CHANNEL_SAMPLE_RATE; float shiftedPhase = phaseDeg + filterPhaseShift; // Calculate difference in phase, which is the radial @@ -238,10 +249,10 @@ void VORDemodSCSink::processOneSample(Complex &ci) // qDebug() << "Ref phase: " << phaseDeg << " var phase " << varPhase; - if (getMessageQueueToChannel()) + if (getMessageQueueToGUI()) { - VORDemodSCReport::MsgReportRadial *msg = VORDemodSCReport::MsgReportRadial::create(phaseDifference, refMag, varMag); - getMessageQueueToChannel()->push(msg); + VORDemodMCReport::MsgReportRadial *msg = VORDemodMCReport::MsgReportRadial::create(m_subChannelId, phaseDifference, refMag, varMag); + getMessageQueueToGUI()->push(msg); } m_refGoertzel.reset(); @@ -291,14 +302,12 @@ void VORDemodSCSink::processOneSample(Complex &ci) { if (m_ident != "") { - qDebug() << "VORDemodSCSink::processOneSample:" << m_ident << " " << Morse::toString(m_ident); - - if (getMessageQueueToChannel()) + qDebug() << m_ident << " " << Morse::toString(m_ident); + if (getMessageQueueToGUI()) { - VORDemodSCReport::MsgReportIdent *msg = VORDemodSCReport::MsgReportIdent::create(m_ident); - getMessageQueueToChannel()->push(msg); + VORDemodMCReport::MsgReportIdent *msg = VORDemodMCReport::MsgReportIdent::create(m_subChannelId, m_ident); + getMessageQueueToGUI()->push(msg); } - m_ident = ""; } } @@ -332,14 +341,12 @@ void VORDemodSCSink::processOneSample(Complex &ci) m_ident = m_ident.simplified(); if (m_ident != "") { - qDebug() << "VORDemodSCSink::processOneSample:" << m_ident << " " << Morse::toString(m_ident); - - if (getMessageQueueToChannel()) + qDebug() << m_ident << " " << Morse::toString(m_ident); + if (getMessageQueueToGUI()) { - VORDemodSCReport::MsgReportIdent *msg = VORDemodSCReport::MsgReportIdent::create(m_ident); - getMessageQueueToChannel()->push(msg); + VORDemodMCReport::MsgReportIdent *msg = VORDemodMCReport::MsgReportIdent::create(m_subChannelId, m_ident); + getMessageQueueToGUI()->push(msg); } - m_ident = ""; } m_bitTime = 0; @@ -348,9 +355,9 @@ void VORDemodSCSink::processOneSample(Complex &ci) m_prevBit = bit; } -void VORDemodSCSink::applyChannelSettings(int channelSampleRate, int channelFrequencyOffset, bool force) +void VORDemodMCSink::applyChannelSettings(int channelSampleRate, int channelFrequencyOffset, bool force) { - qDebug() << "VORDemodSCSink::applyChannelSettings:" + qDebug() << "VORDemodMCSink::applyChannelSettings:" << " channelSampleRate: " << channelSampleRate << " channelFrequencyOffset: " << channelFrequencyOffset; @@ -362,17 +369,17 @@ void VORDemodSCSink::applyChannelSettings(int channelSampleRate, int channelFreq if ((m_channelSampleRate != channelSampleRate) || force) { - m_interpolator.create(16, channelSampleRate, VORDemodSCSettings::VORDEMOD_CHANNEL_BANDWIDTH); + m_interpolator.create(16, channelSampleRate, VORDEMOD_CHANNEL_BANDWIDTH); m_interpolatorDistanceRemain = 0; - m_interpolatorDistance = (Real) channelSampleRate / (Real) VORDemodSCSettings::VORDEMOD_CHANNEL_SAMPLE_RATE; + m_interpolatorDistance = (Real) channelSampleRate / (Real) VORDEMOD_CHANNEL_SAMPLE_RATE; - m_samplesPerDot7wpm = VORDemodSCSettings::VORDEMOD_CHANNEL_SAMPLE_RATE*60/(50*7); - m_samplesPerDot10wpm = VORDemodSCSettings::VORDEMOD_CHANNEL_SAMPLE_RATE*60/(50*10); + m_samplesPerDot7wpm = VORDEMOD_CHANNEL_SAMPLE_RATE*60/(50*7); + m_samplesPerDot10wpm = VORDEMOD_CHANNEL_SAMPLE_RATE*60/(50*10); - m_ncoIdent.setFreq(-1020, VORDemodSCSettings::VORDEMOD_CHANNEL_SAMPLE_RATE); // +-50Hz source offset allowed - m_ncoRef.setFreq(-9960, VORDemodSCSettings::VORDEMOD_CHANNEL_SAMPLE_RATE); - m_lowpassIdent.create(301, VORDemodSCSettings::VORDEMOD_CHANNEL_SAMPLE_RATE, 100.0f); - m_lowpassRef.create(301, VORDemodSCSettings::VORDEMOD_CHANNEL_SAMPLE_RATE, 600.0f); // Max deviation is 480Hz + m_ncoIdent.setFreq(-1020, VORDEMOD_CHANNEL_SAMPLE_RATE); // +-50Hz source offset allowed + m_ncoRef.setFreq(-9960, VORDEMOD_CHANNEL_SAMPLE_RATE); + m_lowpassIdent.create(301, VORDEMOD_CHANNEL_SAMPLE_RATE, 100.0f); + m_lowpassRef.create(301, VORDEMOD_CHANNEL_SAMPLE_RATE, 600.0f); // Max deviation is 480Hz m_movingAverageIdent.resize(m_samplesPerDot10wpm/5); // Needs to be short enough for noise floor calculation m_binSampleCnt = 0; @@ -388,9 +395,9 @@ void VORDemodSCSink::applyChannelSettings(int channelSampleRate, int channelFreq m_channelFrequencyOffset = channelFrequencyOffset; } -void VORDemodSCSink::applySettings(const VORDemodSCSettings& settings, bool force) +void VORDemodMCSink::applySettings(const VORDemodMCSettings& settings, bool force) { - qDebug() << "VORDemodSCSink::applySettings:" + qDebug() << "VORDemodMCSink::applySettings:" << " m_volume: " << settings.m_volume << " m_squelch: " << settings.m_squelch << " m_audioMute: " << settings.m_audioMute @@ -404,20 +411,20 @@ void VORDemodSCSink::applySettings(const VORDemodSCSettings& settings, bool forc m_settings = settings; } -void VORDemodSCSink::applyAudioSampleRate(int sampleRate) +void VORDemodMCSink::applyAudioSampleRate(int sampleRate) { if (sampleRate < 0) { - qWarning("VORDemodSCSink::applyAudioSampleRate: invalid sample rate: %d", sampleRate); + qWarning("VORDemodMCSink::applyAudioSampleRate: invalid sample rate: %d", sampleRate); return; } - qDebug("VORDemodSCSink::applyAudioSampleRate: sampleRate: %d m_channelSampleRate: %d", sampleRate, m_channelSampleRate); + qDebug("VORDemodMCSink::applyAudioSampleRate: sampleRate: %d m_channelSampleRate: %d", sampleRate, m_channelSampleRate); // (ICAO Annex 10 3.3.6.3) - Optional voice audio is 300Hz to 3kHz - m_audioInterpolator.create(16, VORDemodSCSettings::VORDEMOD_CHANNEL_SAMPLE_RATE, 3000.0f); + m_audioInterpolator.create(16, VORDEMOD_CHANNEL_SAMPLE_RATE, 3000.0f); m_audioInterpolatorDistanceRemain = 0; - m_audioInterpolatorDistance = (Real) VORDemodSCSettings::VORDEMOD_CHANNEL_SAMPLE_RATE / (Real) sampleRate; + m_audioInterpolatorDistance = (Real) VORDEMOD_CHANNEL_SAMPLE_RATE / (Real) sampleRate; m_bandpass.create(301, sampleRate, 300.0f, 3000.0f); m_audioFifo.setSize(sampleRate); m_squelchDelayLine.resize(sampleRate/5); diff --git a/plugins/channelrx/demodvorsc/vordemodscsink.h b/plugins/channelrx/demodvormc/vordemodmcsink.h similarity index 78% rename from plugins/channelrx/demodvorsc/vordemodscsink.h rename to plugins/channelrx/demodvormc/vordemodmcsink.h index 79abd6c39..fb6228b87 100644 --- a/plugins/channelrx/demodvorsc/vordemodscsink.h +++ b/plugins/channelrx/demodvormc/vordemodmcsink.h @@ -16,8 +16,8 @@ // along with this program. If not, see . // /////////////////////////////////////////////////////////////////////////////////// -#ifndef INCLUDE_VORDEMODSCSINK_H -#define INCLUDE_VORDEMODSCSINK_H +#ifndef INCLUDE_VORDEMODSINK_H +#define INCLUDE_VORDEMODSINK_H #include "dsp/channelsamplesink.h" #include "dsp/nco.h" @@ -30,27 +30,35 @@ #include "util/doublebufferfifo.h" #include "util/messagequeue.h" -#include "vordemodscsettings.h" +#include "vordemodmcsettings.h" #include -class VORDemodSCSink : public ChannelSampleSink { +// Highest frequency is the FM subcarrier at up to ~11kHz +// However, old VORs can have 0.005% frequency offset, which is 6kHz +#define VORDEMOD_CHANNEL_BANDWIDTH 18000 +// Sample rate needs to be at least twice the above +// Also need to consider impact frequency resolution of Goertzel filters +// May as well make it a common audio rate, to possibly avoid decimation +#define VORDEMOD_CHANNEL_SAMPLE_RATE 48000 + +class VORDemodMCSink : public ChannelSampleSink { public: - VORDemodSCSink(); - ~VORDemodSCSink(); + VORDemodMCSink(const VORDemodMCSettings& settings, int subChannel, + MessageQueue *messageQueueToGUI); + ~VORDemodMCSink(); virtual void feed(const SampleVector::const_iterator& begin, const SampleVector::const_iterator& end); void applyChannelSettings(int channelSampleRate, int channelFrequencyOffset, bool force = false); - void applySettings(const VORDemodSCSettings& settings, bool force = false); - void setMessageQueueToChannel(MessageQueue *messageQueue) { m_messageQueueToChannel = messageQueue; } + void applySettings(const VORDemodMCSettings& settings, bool force = false); + void setMessageQueueToGUI(MessageQueue *messageQueue) { m_messageQueueToGUI = messageQueue; } void applyAudioSampleRate(int sampleRate); int getAudioSampleRate() const { return m_audioSampleRate; } double getMagSq() const { return m_magsq; } bool getSquelchOpen() const { return m_squelchOpen; } AudioFifo *getAudioFifo() { return &m_audioFifo; } - void setAudioFifoLabel(const QString& label) { m_audioFifo.setLabel(label); } void getMagSqLevels(double& avg, double& peak, int& nbSamples) { @@ -70,7 +78,11 @@ public: m_magsqCount = 0; } + int m_subChannelId; // The id for the VOR this demod sink was created for + int m_vorFrequencyHz; // The VORs frequency + int m_frequencyOffset; // Different between sample source center frequeny and VOR center frequency int m_channelFrequencyOffset; + bool m_outOfBand; private: struct MagSqLevelsStore @@ -83,7 +95,7 @@ private: double m_magsqPeak; }; - VORDemodSCSettings m_settings; + VORDemodMCSettings m_settings; int m_channelSampleRate; int m_audioSampleRate; @@ -102,7 +114,6 @@ private: int m_magsqCount; MagSqLevelsStore m_magSqLevelStore; - MessageQueue *m_messageQueueToChannel; MessageQueue *m_messageQueueToGUI; MovingAverageUtil m_movingAverage; @@ -139,7 +150,7 @@ private: void processOneSample(Complex &ci); void processOneAudioSample(Complex &ci); - MessageQueue *getMessageQueueToChannel() { return m_messageQueueToChannel; } + MessageQueue *getMessageQueueToGUI() { return m_messageQueueToGUI; } }; -#endif // INCLUDE_VORDEMODSCSINK_H +#endif // INCLUDE_VORDEMODSINK_H diff --git a/plugins/channelrx/demodvorsc/vordemodscwebapiadapter.cpp b/plugins/channelrx/demodvormc/vordemodmcwebapiadapter.cpp similarity index 78% rename from plugins/channelrx/demodvorsc/vordemodscwebapiadapter.cpp rename to plugins/channelrx/demodvormc/vordemodmcwebapiadapter.cpp index 67ab13f0d..467ae651a 100644 --- a/plugins/channelrx/demodvorsc/vordemodscwebapiadapter.cpp +++ b/plugins/channelrx/demodvormc/vordemodmcwebapiadapter.cpp @@ -17,28 +17,28 @@ /////////////////////////////////////////////////////////////////////////////////// #include "SWGChannelSettings.h" -#include "vordemodsc.h" -#include "vordemodscwebapiadapter.h" +#include "vordemodmc.h" +#include "vordemodmcwebapiadapter.h" -VORDemodSCWebAPIAdapter::VORDemodSCWebAPIAdapter() +VORDemodMCWebAPIAdapter::VORDemodMCWebAPIAdapter() {} -VORDemodSCWebAPIAdapter::~VORDemodSCWebAPIAdapter() +VORDemodMCWebAPIAdapter::~VORDemodMCWebAPIAdapter() {} -int VORDemodSCWebAPIAdapter::webapiSettingsGet( +int VORDemodMCWebAPIAdapter::webapiSettingsGet( SWGSDRangel::SWGChannelSettings& response, QString& errorMessage) { (void) errorMessage; - response.setVorDemodSettings(new SWGSDRangel::SWGVORDemodSettings()); - response.getVorDemodSettings()->init(); - VORDemodSC::webapiFormatChannelSettings(response, m_settings); + response.setVorDemodMcSettings(new SWGSDRangel::SWGVORDemodMCSettings()); + response.getVorDemodMcSettings()->init(); + VORDemodMC::webapiFormatChannelSettings(response, m_settings); return 200; } -int VORDemodSCWebAPIAdapter::webapiSettingsPutPatch( +int VORDemodMCWebAPIAdapter::webapiSettingsPutPatch( bool force, const QStringList& channelSettingsKeys, SWGSDRangel::SWGChannelSettings& response, @@ -46,7 +46,7 @@ int VORDemodSCWebAPIAdapter::webapiSettingsPutPatch( { (void) force; (void) errorMessage; - VORDemodSC::webapiUpdateChannelSettings(m_settings, channelSettingsKeys, response); + VORDemodMC::webapiUpdateChannelSettings(m_settings, channelSettingsKeys, response); return 200; } diff --git a/plugins/channelrx/demodvorsc/vordemodscwebapiadapter.h b/plugins/channelrx/demodvormc/vordemodmcwebapiadapter.h similarity index 86% rename from plugins/channelrx/demodvorsc/vordemodscwebapiadapter.h rename to plugins/channelrx/demodvormc/vordemodmcwebapiadapter.h index 285c768aa..f2cbb378c 100644 --- a/plugins/channelrx/demodvorsc/vordemodscwebapiadapter.h +++ b/plugins/channelrx/demodvormc/vordemodmcwebapiadapter.h @@ -16,19 +16,19 @@ // along with this program. If not, see . // /////////////////////////////////////////////////////////////////////////////////// -#ifndef INCLUDE_VORDEMODSC_WEBAPIADAPTER_H -#define INCLUDE_VORDEMODSC_WEBAPIADAPTER_H +#ifndef INCLUDE_VORDEMOD_WEBAPIADAPTER_H +#define INCLUDE_VORDEMOD_WEBAPIADAPTER_H #include "channel/channelwebapiadapter.h" -#include "vordemodscsettings.h" +#include "vordemodmcsettings.h" /** * Standalone API adapter only for the settings */ -class VORDemodSCWebAPIAdapter : public ChannelWebAPIAdapter { +class VORDemodMCWebAPIAdapter : public ChannelWebAPIAdapter { public: - VORDemodSCWebAPIAdapter(); - virtual ~VORDemodSCWebAPIAdapter(); + VORDemodMCWebAPIAdapter(); + virtual ~VORDemodMCWebAPIAdapter(); virtual QByteArray serialize() const { return m_settings.serialize(); } virtual bool deserialize(const QByteArray& data) { return m_settings.deserialize(data); } @@ -44,7 +44,7 @@ public: QString& errorMessage); private: - VORDemodSCSettings m_settings; + VORDemodMCSettings m_settings; }; -#endif // INCLUDE_VORDEMODSC_WEBAPIADAPTER_H +#endif // INCLUDE_VORDEMOD_WEBAPIADAPTER_H diff --git a/plugins/channelrx/demodvorsc/CMakeLists.txt b/plugins/channelrx/demodvorsc/CMakeLists.txt deleted file mode 100644 index d4f15de64..000000000 --- a/plugins/channelrx/demodvorsc/CMakeLists.txt +++ /dev/null @@ -1,65 +0,0 @@ -project(vorsc) - -set(vorsc_SOURCES - vordemodsc.cpp - vordemodscsettings.cpp - vordemodscbaseband.cpp - vordemodscsink.cpp - vordemodscplugin.cpp - vordemodscwebapiadapter.cpp - vordemodscreport.cpp -) - -set(vorsc_HEADERS - vordemodsc.h - vordemodscsettings.h - vordemodscbaseband.h - vordemodscsink.h - vordemodscplugin.h - vordemodscwebapiadapter.h - vordemodscreport.h -) - -include_directories( - ${CMAKE_SOURCE_DIR}/swagger/sdrangel/code/qt5/client -) - -if(NOT SERVER_MODE) - set(vorsc_SOURCES - ${vorsc_SOURCES} - vordemodscgui.cpp - vordemodscgui.ui - ) - set(vorsc_HEADERS - ${vorsc_HEADERS} - vordemodscgui.h - ) - - set(TARGET_NAME demodvorsc) - set(TARGET_LIB "Qt5::Widgets") - set(TARGET_LIB_GUI "sdrgui") - set(INSTALL_FOLDER ${INSTALL_PLUGINS_DIR}) -else() - set(TARGET_NAME demodvorscsrv) - set(TARGET_LIB "") - set(TARGET_LIB_GUI "") - set(INSTALL_FOLDER ${INSTALL_PLUGINSSRV_DIR}) -endif() - -add_library(${TARGET_NAME} SHARED - ${vorsc_SOURCES} -) - -target_link_libraries(${TARGET_NAME} - Qt5::Core - ${TARGET_LIB} - sdrbase - ${TARGET_LIB_GUI} -) - -install(TARGETS ${TARGET_NAME} DESTINATION ${INSTALL_FOLDER}) - -# Install debug symbols -if (WIN32) - install(FILES $ CONFIGURATIONS Debug RelWithDebInfo DESTINATION ${INSTALL_FOLDER} ) -endif() diff --git a/plugins/channelrx/demodvorsc/readme.md b/plugins/channelrx/demodvorsc/readme.md deleted file mode 100644 index d929eb957..000000000 --- a/plugins/channelrx/demodvorsc/readme.md +++ /dev/null @@ -1,73 +0,0 @@ -

VOR demodulator plugin - Single channel version

- -

Introduction

- -This plugin can be used to demodulate VOR (VHF omnidirectional range) navaids (navigation aids). VORs are radio naviation aids in the VHF 108 - 117.975MHz band commonly used for aircraft navigation. - -VORs transmit two 30Hz signals, one AM at the VOR center frequency and one FM on a 9960Hz sub-carrier. The FM reference signal's phase is set so 0 degrees corresponds to magnetic north from the VOR (Some VORs at high latitudes use true North). The phase of the AM variable signal is such that the phase difference to the reference signal corresponds to the bearing from the VOR to the receiver. For example, if a receiver is North from the VOR, the AM and FM 30Hz signals will be received in phase. If a receiver is East from the VOR, the phase difference will be 90 degrees. - -VORs also transmit a Morse code ident signal at a 1020Hz offset. This is a 2 or 3 character identifier used to identify the VOR, as multiple VORs can be transmitted on the same frequency. For example, the VOR at London Heathrow transmits .-.. --- -. for LON. The Morse code ident is typically transmitted at 10 seconds intervals at between 7 and 10 wpm. VORs that are under maintainance may transmit TST. - -Some VORs also transmit an AM voice identification or information signal between 300-3kHz. - -Note that for aircraft, there is typically a direct line-of-sight to the VOR. This is unlikely to be the case when using an SDR on the ground. To get good results, ideally you want to be on a nice high hill or close to the VOR. - -

Using it for localization

- -Several instances of this plugin can be created to monitor multiple VORs and collate information in the VOR Localizer feature plugin. The VOR Localizer can also perform a round robin on multiple VORs with just one VOR demodulator. Please refer to [VOR Localizer](../../feature/vorlocalizer/readme.md) for more information about this feature plugin - -

Interface

- -![VOR Demodulator plugin GUI](../../../doc/img/VORDemodSC_plugin.png) - -

1: Frequency shift from center frequency of reception value

- -Use the wheels to adjust the frequency shift in Hz from the center frequency of reception. 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 arrows. Pressing shift simultaneously moves digit by 5 and pressing control moves it by 2. Left click on a digit sets the cursor position at this digit. - -

2: Level meter in dB

- - - top bar (green): average value - - bottom bar (blue green): instantaneous peak value - - tip vertical bar (bright green): peak hold value - -

3: Channel power

- -Average total power in dB relative to a +/- 1.0 amplitude signal received in the pass band. - -

4: Audio mute and audio output select

- -Left click on this button to toggle audio mute for this channel. The button will light up in green if the squelch is open. This helps identifying which channels are active in a multi-channel configuration. - -If you right click on it it will open a dialog to select the audio output device. See [audio management documentation](../../../sdrgui/audio.md) for details. - -

5: Morse ident threshold

- -This is the Morse code ident threshold, expressed as a linear signal to noise (SNR) ratio. This is effectively the signal level required for the Morse demodulator to detect a dot or dash. Setting this to low values will allow the Morse demodulator to detect weak signals, but it also increases the likelyhood that noise will incorrectly be interpreted as a signal, resulting in invalid idents being reported. - -

6: Squelch threshold

- -This is the squelch threshold in dB. The average total power received in the signal bandwidth before demodulation is compared to this value and the squelch input is open above this value. It can be varied continuously in 0.1 dB steps from 0.0 to -100.0 dB using the dial button. - -

7: Volume

- -This is the volume of the audio signal from 0.0 (mute) to 10.0 (maximum). It can be varied continuously in 0.1 steps using the dial button. - -

8: Radial dircetion

- -Demodulated radial direction in degrees (unadjusted for magnetic declination). If there is a low confidence the value is correct (due to a weak signal), it will be displayed in red. - -

9: Reference signal power in dB

- -Magnitude of the received 30Hz FM reference signal in dB - -

10. Variable signal power in dB

- -Mangitude of the received 30Hz AM variable signal in dB - -

11. VOR identifier code (decoded)

- -Demodulated identifier. If an identifier is received that is not 2 or 3 characters, it will be displayed in yellow else in white. - -

12. VOR identifier code (Morse)

- -Demodulated Morse code identifier. Colour coding is the ame as for the decoded identifier. diff --git a/plugins/channelrx/demodvorsc/vordemodscbaseband.cpp b/plugins/channelrx/demodvorsc/vordemodscbaseband.cpp deleted file mode 100644 index a5715cd97..000000000 --- a/plugins/channelrx/demodvorsc/vordemodscbaseband.cpp +++ /dev/null @@ -1,199 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////////// -// Copyright (C) 2019 Edouard Griffiths, F4EXB // -// Copyright (C) 2020 Jon Beniston, M7RCE // -// // -// This program is free software; you can redistribute it and/or modify // -// it under the terms of the GNU General Public License as published by // -// the Free Software Foundation as version 3 of the License, or // -// (at your option) any later version. // -// // -// This program is distributed in the hope that it will be useful, // -// but WITHOUT ANY WARRANTY; without even the implied warranty of // -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // -// GNU General Public License V3 for more details. // -// // -// You should have received a copy of the GNU General Public License // -// along with this program. If not, see . // -/////////////////////////////////////////////////////////////////////////////////// - -#include - -#include "dsp/dspengine.h" -#include "dsp/dspcommands.h" -#include "dsp/downchannelizer.h" - -#include "vordemodscbaseband.h" -#include "vordemodscreport.h" - -MESSAGE_CLASS_DEFINITION(VORDemodSCBaseband::MsgConfigureVORDemodBaseband, Message) - -VORDemodSCBaseband::VORDemodSCBaseband() : - m_messageQueueToGUI(nullptr), - m_running(false), - m_mutex(QMutex::Recursive) -{ - qDebug("VORDemodSCBaseband::VORDemodSCBaseband"); - m_sampleFifo.setSize(SampleSinkFifo::getSizePolicy(48000)); - m_channelizer = new DownChannelizer(&m_sink); - - DSPEngine::instance()->getAudioDeviceManager()->addAudioSink(m_sink.getAudioFifo(), getInputMessageQueue()); - m_sink.applyAudioSampleRate(DSPEngine::instance()->getAudioDeviceManager()->getOutputSampleRate()); - m_channelSampleRate = 0; -} - -VORDemodSCBaseband::~VORDemodSCBaseband() -{ - m_inputMessageQueue.clear(); - DSPEngine::instance()->getAudioDeviceManager()->removeAudioSink(m_sink.getAudioFifo()); - delete m_channelizer; -} - -void VORDemodSCBaseband::reset() -{ - QMutexLocker mutexLocker(&m_mutex); - m_inputMessageQueue.clear(); - m_sampleFifo.reset(); - m_channelSampleRate = 0; -} - -void VORDemodSCBaseband::startWork() -{ - QMutexLocker mutexLocker(&m_mutex); - QObject::connect( - &m_sampleFifo, - &SampleSinkFifo::dataReady, - this, - &VORDemodSCBaseband::handleData, - Qt::QueuedConnection - ); - connect(&m_inputMessageQueue, SIGNAL(messageEnqueued()), this, SLOT(handleInputMessages())); - m_running = true; -} - -void VORDemodSCBaseband::stopWork() -{ - QMutexLocker mutexLocker(&m_mutex); - disconnect(&m_inputMessageQueue, SIGNAL(messageEnqueued()), this, SLOT(handleInputMessages())); - QObject::disconnect( - &m_sampleFifo, - &SampleSinkFifo::dataReady, - this, - &VORDemodSCBaseband::handleData - ); - m_running = false; -} - -void VORDemodSCBaseband::feed(const SampleVector::const_iterator& begin, const SampleVector::const_iterator& end) -{ - m_sampleFifo.write(begin, end); -} - -void VORDemodSCBaseband::handleData() -{ - QMutexLocker mutexLocker(&m_mutex); - - while ((m_sampleFifo.fill() > 0) && (m_inputMessageQueue.size() == 0)) - { - SampleVector::iterator part1begin; - SampleVector::iterator part1end; - SampleVector::iterator part2begin; - SampleVector::iterator part2end; - - std::size_t count = m_sampleFifo.readBegin(m_sampleFifo.fill(), &part1begin, &part1end, &part2begin, &part2end); - - // first part of FIFO data - if (part1begin != part1end) { - m_channelizer->feed(part1begin, part1end); - } - - // second part of FIFO data (used when block wraps around) - if(part2begin != part2end) { - m_channelizer->feed(part2begin, part2end); - } - - m_sampleFifo.readCommit((unsigned int) count); - } -} - -void VORDemodSCBaseband::handleInputMessages() -{ - Message* message; - - while ((message = m_inputMessageQueue.pop()) != nullptr) - { - if (handleMessage(*message)) { - delete message; - } - } -} - -bool VORDemodSCBaseband::handleMessage(const Message& cmd) -{ - if (MsgConfigureVORDemodBaseband::match(cmd)) - { - QMutexLocker mutexLocker(&m_mutex); - MsgConfigureVORDemodBaseband& cfg = (MsgConfigureVORDemodBaseband&) cmd; - qDebug() << "VORDemodSCBaseband::handleMessage: MsgConfigureVORDemodBaseband"; - - applySettings(cfg.getSettings(), cfg.getForce()); - - return true; - } - else if (DSPSignalNotification::match(cmd)) - { - QMutexLocker mutexLocker(&m_mutex); - DSPSignalNotification& notif = (DSPSignalNotification&) cmd; - qDebug() << "VORDemodSCBaseband::handleMessage: DSPSignalNotification: basebandSampleRate: " << notif.getSampleRate() << " centerFrequency: " << notif.getCenterFrequency(); - m_sampleFifo.setSize(SampleSinkFifo::getSizePolicy(notif.getSampleRate())); - m_channelizer->setBasebandSampleRate(notif.getSampleRate()); - m_sink.applyChannelSettings(m_channelizer->getChannelSampleRate(), m_channelizer->getChannelFrequencyOffset()); - - if (m_channelSampleRate != m_channelizer->getChannelSampleRate()) - { - m_sink.applyAudioSampleRate(m_sink.getAudioSampleRate()); // reapply when channel sample rate changes - m_channelSampleRate = m_channelizer->getChannelSampleRate(); - } - - return true; - } - else - { - return false; - } -} - -void VORDemodSCBaseband::applySettings(const VORDemodSCSettings& settings, bool force) -{ - if ((settings.m_inputFrequencyOffset != m_settings.m_inputFrequencyOffset) || force) - { - m_channelizer->setChannelization(m_sink.getAudioSampleRate(), settings.m_inputFrequencyOffset); - m_sink.applyChannelSettings(m_channelizer->getChannelSampleRate(), m_channelizer->getChannelFrequencyOffset()); - - if (m_channelSampleRate != m_channelizer->getChannelSampleRate()) - { - m_sink.applyAudioSampleRate(m_sink.getAudioSampleRate()); // reapply when channel sample rate changes - m_channelSampleRate = m_channelizer->getChannelSampleRate(); - } - } - - if ((settings.m_audioDeviceName != m_settings.m_audioDeviceName) || force) - { - AudioDeviceManager *audioDeviceManager = DSPEngine::instance()->getAudioDeviceManager(); - int audioDeviceIndex = audioDeviceManager->getOutputDeviceIndex(settings.m_audioDeviceName); - //qDebug("AMDemod::applySettings: audioDeviceName: %s audioDeviceIndex: %d", qPrintable(settings.m_audioDeviceName), audioDeviceIndex); - audioDeviceManager->removeAudioSink(m_sink.getAudioFifo()); - audioDeviceManager->addAudioSink(m_sink.getAudioFifo(), getInputMessageQueue(), audioDeviceIndex); - int audioSampleRate = audioDeviceManager->getOutputSampleRate(audioDeviceIndex); - - if (m_sink.getAudioSampleRate() != audioSampleRate) - { - m_channelizer->setChannelization(audioSampleRate, settings.m_inputFrequencyOffset); - m_sink.applyChannelSettings(m_channelizer->getChannelSampleRate(), m_channelizer->getChannelFrequencyOffset()); - m_sink.applyAudioSampleRate(audioSampleRate); - } - } - - m_sink.applySettings(settings, force); - - m_settings = settings; -} diff --git a/plugins/channelrx/demodvorsc/vordemodscgui.cpp b/plugins/channelrx/demodvorsc/vordemodscgui.cpp deleted file mode 100644 index ffaf706a4..000000000 --- a/plugins/channelrx/demodvorsc/vordemodscgui.cpp +++ /dev/null @@ -1,445 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////////// -// Copyright (C) 2016 Edouard Griffiths, F4EXB // -// Copyright (C) 2020 Jon Beniston, M7RCE // -// // -// This program is free software; you can redistribute it and/or modify // -// it under the terms of the GNU General Public License as published by // -// the Free Software Foundation as version 3 of the License, or // -// (at your option) any later version. // -// // -// This program is distributed in the hope that it will be useful, // -// but WITHOUT ANY WARRANTY; without even the implied warranty of // -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // -// GNU General Public License V3 for more details. // -// // -// You should have received a copy of the GNU General Public License // -// along with this program. If not, see . // -/////////////////////////////////////////////////////////////////////////////////// - -#include - -#include - -#include "device/deviceuiset.h" -#include "dsp/dspengine.h" -#include "dsp/dspcommands.h" -#include "dsp/dspengine.h" -#include "plugin/pluginapi.h" -#include "util/simpleserializer.h" -#include "util/db.h" -#include "util/morse.h" -#include "util/units.h" -#include "gui/basicchannelsettingsdialog.h" -#include "gui/devicestreamselectiondialog.h" -#include "gui/crightclickenabler.h" -#include "gui/audioselectdialog.h" -#include "channel/channelwebapiutils.h" -#include "maincore.h" - -#include "ui_vordemodscgui.h" -#include "vordemodsc.h" -#include "vordemodscreport.h" -#include "vordemodscgui.h" - -VORDemodSCGUI* VORDemodSCGUI::create(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, BasebandSampleSink *rxChannel) -{ - VORDemodSCGUI* gui = new VORDemodSCGUI(pluginAPI, deviceUISet, rxChannel); - return gui; -} - -void VORDemodSCGUI::destroy() -{ - delete this; -} - -void VORDemodSCGUI::resetToDefaults() -{ - m_settings.resetToDefaults(); - displaySettings(); - applySettings(true); -} - -QByteArray VORDemodSCGUI::serialize() const -{ - return m_settings.serialize(); -} - -bool VORDemodSCGUI::deserialize(const QByteArray& data) -{ - if(m_settings.deserialize(data)) { - displaySettings(); - applySettings(true); - return true; - } else { - resetToDefaults(); - return false; - } -} - -bool VORDemodSCGUI::handleMessage(const Message& message) -{ - if (VORDemodSC::MsgConfigureVORDemod::match(message)) - { - qDebug("VORDemodSCGUI::handleMessage: VORDemodSC::MsgConfigureVORDemod"); - const VORDemodSC::MsgConfigureVORDemod& cfg = (VORDemodSC::MsgConfigureVORDemod&) message; - m_settings = cfg.getSettings(); - blockApplySettings(true); - displaySettings(); - blockApplySettings(false); - return true; - } - else if (DSPSignalNotification::match(message)) - { - DSPSignalNotification& notif = (DSPSignalNotification&) message; - m_basebandSampleRate = notif.getSampleRate(); - return true; - } - else if (VORDemodSCReport::MsgReportRadial::match(message)) - { - VORDemodSCReport::MsgReportRadial& report = (VORDemodSCReport::MsgReportRadial&) message; - - // Display radial and signal magnitudes - Real varMagDB = std::round(20.0*std::log10(report.getVarMag())); - Real refMagDB = std::round(20.0*std::log10(report.getRefMag())); - - bool validRadial = (refMagDB > m_settings.m_refThresholdDB) && (varMagDB > m_settings.m_varThresholdDB); - - ui->radialText->setText(tr("%1°").arg(std::round(report.getRadial()))); - - if (validRadial) { - ui->radialText->setStyleSheet("QLabel { color: white }"); - } else { - ui->radialText->setStyleSheet("QLabel { color: red }"); - } - - ui->refText->setText(tr("%1 dB").arg(refMagDB)); - - if (refMagDB > m_settings.m_refThresholdDB) { - ui->refText->setStyleSheet("QLabel { color: white }"); - } else { - ui->refText->setStyleSheet("QLabel { color: red }"); - } - - ui->varText->setText(tr("%1 dB").arg(varMagDB)); - - if (varMagDB > m_settings.m_varThresholdDB) { - ui->varText->setStyleSheet("QLabel { color: white }"); - } else { - ui->varText->setStyleSheet("QLabel { color: red }"); - } - - return true; - } - else if (VORDemodSCReport::MsgReportIdent::match(message)) - { - VORDemodSCReport::MsgReportIdent& report = (VORDemodSCReport::MsgReportIdent&) message; - - QString ident = report.getIdent(); - QString identString = Morse::toString(ident); // Convert Morse to a string - - ui->identText->setText(identString); - ui->morseText->setText(Morse::toSpacedUnicode(ident)); - - // Idents should only be two or three characters, so filter anything else - // other than TEST which indicates a VOR is under maintainance (may also be TST) - if (((identString.size() >= 2) && (identString.size() <= 3)) || (identString == "TEST")) - { - ui->identText->setStyleSheet("QLabel { color: white }"); - ui->morseText->setStyleSheet("QLabel { color: white }"); - } - else - { - ui->identText->setStyleSheet("QLabel { color: yellow }"); - ui->morseText->setStyleSheet("QLabel { color: yellow }"); - } - - return true; - } - - return false; -} - -void VORDemodSCGUI::handleInputMessages() -{ - Message* message; - - while ((message = getInputMessageQueue()->pop()) != 0) - { - if (handleMessage(*message)) - { - delete message; - } - } -} - -void VORDemodSCGUI::channelMarkerChangedByCursor() -{ - ui->deltaFrequency->setValue(m_channelMarker.getCenterFrequency()); - m_settings.m_inputFrequencyOffset = m_channelMarker.getCenterFrequency(); - applySettings(); -} - -void VORDemodSCGUI::channelMarkerHighlightedByCursor() -{ - setHighlighted(m_channelMarker.getHighlighted()); -} - -void VORDemodSCGUI::on_deltaFrequency_changed(qint64 value) -{ - m_channelMarker.setCenterFrequency(value); - m_settings.m_inputFrequencyOffset = m_channelMarker.getCenterFrequency(); - applySettings(); -} - -void VORDemodSCGUI::on_thresh_valueChanged(int value) -{ - ui->threshText->setText(QString("%1").arg(value / 10.0, 0, 'f', 1)); - m_settings.m_identThreshold = value / 10.0; - applySettings(); -} - -void VORDemodSCGUI::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 VORDemodSCGUI::on_squelch_valueChanged(int value) -{ - ui->squelchText->setText(QString("%1 dB").arg(value)); - m_settings.m_squelch = value; - applySettings(); -} - -void VORDemodSCGUI::on_audioMute_toggled(bool checked) -{ - m_settings.m_audioMute = checked; - applySettings(); -} - -void VORDemodSCGUI::onWidgetRolled(QWidget* widget, bool rollDown) -{ - (void) widget; - (void) rollDown; - - saveState(m_rollupState); - applySettings(); -} - -void VORDemodSCGUI::onMenuDialogCalled(const QPoint &p) -{ - if (m_contextMenuType == ContextMenuChannelSettings) - { - BasicChannelSettingsDialog dialog(&m_channelMarker, this); - dialog.setUseReverseAPI(m_settings.m_useReverseAPI); - dialog.setReverseAPIAddress(m_settings.m_reverseAPIAddress); - dialog.setReverseAPIPort(m_settings.m_reverseAPIPort); - dialog.setReverseAPIDeviceIndex(m_settings.m_reverseAPIDeviceIndex); - dialog.setReverseAPIChannelIndex(m_settings.m_reverseAPIChannelIndex); - dialog.move(p); - dialog.exec(); - - m_settings.m_rgbColor = m_channelMarker.getColor().rgb(); - m_settings.m_title = m_channelMarker.getTitle(); - m_settings.m_useReverseAPI = dialog.useReverseAPI(); - m_settings.m_reverseAPIAddress = dialog.getReverseAPIAddress(); - m_settings.m_reverseAPIPort = dialog.getReverseAPIPort(); - m_settings.m_reverseAPIDeviceIndex = dialog.getReverseAPIDeviceIndex(); - m_settings.m_reverseAPIChannelIndex = dialog.getReverseAPIChannelIndex(); - - setWindowTitle(m_settings.m_title); - setTitleColor(m_settings.m_rgbColor); - - applySettings(); - } - else if ((m_contextMenuType == ContextMenuStreamSettings) && (m_deviceUISet->m_deviceMIMOEngine)) - { - DeviceStreamSelectionDialog dialog(this); - dialog.setNumberOfStreams(m_vorDemod->getNumberOfDeviceStreams()); - dialog.setStreamIndex(m_settings.m_streamIndex); - dialog.move(p); - dialog.exec(); - - m_settings.m_streamIndex = dialog.getSelectedStreamIndex(); - m_channelMarker.clearStreamIndexes(); - m_channelMarker.addStreamIndex(m_settings.m_streamIndex); - displayStreamIndex(); - applySettings(); - } - - resetContextMenuType(); -} - -VORDemodSCGUI::VORDemodSCGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, BasebandSampleSink *rxChannel, QWidget* parent) : - ChannelGUI(parent), - ui(new Ui::VORDemodSCGUI), - m_pluginAPI(pluginAPI), - m_deviceUISet(deviceUISet), - m_channelMarker(this), - m_doApplySettings(true), - m_squelchOpen(false), - m_tickCount(0) -{ - ui->setupUi(this); - m_helpURL = "plugins/channelrx/demodvorsc/readme.md"; - - 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 &))); - - m_vorDemod = reinterpret_cast(rxChannel); - m_vorDemod->setMessageQueueToGUI(getInputMessageQueue()); - - connect(&MainCore::instance()->getMasterTimer(), SIGNAL(timeout()), this, SLOT(tick())); // 50 ms - - CRightClickEnabler *audioMuteRightClickEnabler = new CRightClickEnabler(ui->audioMute); - connect(audioMuteRightClickEnabler, SIGNAL(rightClick(const QPoint &)), this, SLOT(audioSelect())); - - ui->deltaFrequencyLabel->setText(QString("%1f").arg(QChar(0x94, 0x03))); - ui->deltaFrequency->setColorMapper(ColorMapper(ColorMapper::GrayGold)); - ui->deltaFrequency->setValueRange(false, 7, -9999999, 9999999); - ui->channelPowerMeter->setColorTheme(LevelMeterSignalDB::ColorGreenAndBlue); - - m_channelMarker.blockSignals(true); - m_channelMarker.setColor(Qt::yellow); - m_channelMarker.setBandwidth(2*VORDemodSCSettings::VORDEMOD_CHANNEL_BANDWIDTH); - m_channelMarker.setCenterFrequency(0); - m_channelMarker.setTitle("VOR Demodulator"); - m_channelMarker.blockSignals(false); - m_channelMarker.setVisible(true); // activate signal on the last setting only - - setTitleColor(m_channelMarker.getColor()); - m_settings.setChannelMarker(&m_channelMarker); - m_settings.setRollupState(&m_rollupState); - - m_deviceUISet->addChannelMarker(&m_channelMarker); - m_deviceUISet->addRollupWidget(this); - - connect(&m_channelMarker, SIGNAL(changedByCursor()), this, SLOT(channelMarkerChangedByCursor())); - connect(&m_channelMarker, SIGNAL(highlightedByCursor()), this, SLOT(channelMarkerHighlightedByCursor())); - connect(getInputMessageQueue(), SIGNAL(messageEnqueued()), this, SLOT(handleInputMessages())); - - displaySettings(); - applySettings(true); -} - -VORDemodSCGUI::~VORDemodSCGUI() -{ - delete ui; -} - -void VORDemodSCGUI::blockApplySettings(bool block) -{ - m_doApplySettings = !block; -} - -void VORDemodSCGUI::applySettings(bool force) -{ - if (m_doApplySettings) - { - VORDemodSC::MsgConfigureVORDemod* message = VORDemodSC::MsgConfigureVORDemod::create( m_settings, force); - m_vorDemod->getInputMessageQueue()->push(message); - } -} - -void VORDemodSCGUI::displaySettings() -{ - m_channelMarker.blockSignals(true); - m_channelMarker.setCenterFrequency(m_settings.m_inputFrequencyOffset); - m_channelMarker.setBandwidth(2*VORDemodSCSettings::VORDEMOD_CHANNEL_BANDWIDTH); - m_channelMarker.setTitle(m_settings.m_title); - m_channelMarker.blockSignals(false); - m_channelMarker.setColor(m_settings.m_rgbColor); // activate signal on the last setting only - - setTitleColor(m_settings.m_rgbColor); - setWindowTitle(m_channelMarker.getTitle()); - - blockApplySettings(true); - - ui->deltaFrequency->setValue(m_channelMarker.getCenterFrequency()); - - ui->thresh->setValue(m_settings.m_identThreshold * 10.0); - ui->threshText->setText(QString("%1").arg(m_settings.m_identThreshold, 0, 'f', 1)); - - 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); - - displayStreamIndex(); - - restoreState(m_rollupState); - blockApplySettings(false); -} - -void VORDemodSCGUI::displayStreamIndex() -{ - if (m_deviceUISet->m_deviceMIMOEngine) { - setStreamIndicator(tr("%1").arg(m_settings.m_streamIndex)); - } else { - setStreamIndicator("S"); // single channel indicator - } -} - -void VORDemodSCGUI::leaveEvent(QEvent*) -{ - m_channelMarker.setHighlighted(false); -} - -void VORDemodSCGUI::enterEvent(QEvent*) -{ - m_channelMarker.setHighlighted(true); -} - -void VORDemodSCGUI::audioSelect() -{ - qDebug("VORDemodSCGUI::audioSelect"); - AudioSelectDialog audioSelect(DSPEngine::instance()->getAudioDeviceManager(), m_settings.m_audioDeviceName); - audioSelect.exec(); - - if (audioSelect.m_selected) - { - m_settings.m_audioDeviceName = audioSelect.m_audioDeviceName; - applySettings(); - } -} - -void VORDemodSCGUI::tick() -{ - double magsqAvg, magsqPeak; - int nbMagsqSamples; - m_vorDemod->getMagSqLevels(magsqAvg, magsqPeak, nbMagsqSamples); - double powDbAvg = CalcDb::dbPower(magsqAvg); - double powDbPeak = CalcDb::dbPower(magsqPeak); - - ui->channelPowerMeter->levelChanged( - (100.0f + powDbAvg) / 100.0f, - (100.0f + powDbPeak) / 100.0f, - nbMagsqSamples); - - if (m_tickCount % 4 == 0) { - ui->channelPower->setText(QString::number(powDbAvg, 'f', 1)); - } - - int audioSampleRate = m_vorDemod->getAudioSampleRate(); - bool squelchOpen = m_vorDemod->getSquelchOpen(); - - if (squelchOpen != m_squelchOpen) - { - if (audioSampleRate < 0) { - ui->audioMute->setStyleSheet("QToolButton { background-color : red; }"); - } else if (squelchOpen) { - ui->audioMute->setStyleSheet("QToolButton { background-color : green; }"); - } else { - ui->audioMute->setStyleSheet("QToolButton { background:rgb(79,79,79); }"); - } - - m_squelchOpen = squelchOpen; - } - - m_tickCount++; -} diff --git a/plugins/channelrx/demodvorsc/vordemodscgui.h b/plugins/channelrx/demodvorsc/vordemodscgui.h deleted file mode 100644 index 97ac65a13..000000000 --- a/plugins/channelrx/demodvorsc/vordemodscgui.h +++ /dev/null @@ -1,96 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////////// -// Copyright (C) 2016 Edouard Griffiths, F4EXB // -// Copyright (C) 2020 Jon Beniston, M7RCE // -// // -// This program is free software; you can redistribute it and/or modify // -// it under the terms of the GNU General Public License as published by // -// the Free Software Foundation as version 3 of the License, or // -// (at your option) any later version. // -// // -// This program is distributed in the hope that it will be useful, // -// but WITHOUT ANY WARRANTY; without even the implied warranty of // -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // -// GNU General Public License V3 for more details. // -// // -// You should have received a copy of the GNU General Public License // -// along with this program. If not, see . // -/////////////////////////////////////////////////////////////////////////////////// - -#ifndef INCLUDE_VORDEMODSCGUI_H -#define INCLUDE_VORDEMODSCGUI_H - -#include "channel/channelgui.h" -#include "dsp/channelmarker.h" -#include "dsp/movingaverage.h" -#include "util/messagequeue.h" -#include "settings/rollupstate.h" -#include "vordemodscsettings.h" - -class PluginAPI; -class DeviceUISet; -class BasebandSampleSink; -class VORDemodSC; -class VORDemodSCGUI; - -namespace Ui { - class VORDemodSCGUI; -} -class VORDemodSCGUI; - -class VORDemodSCGUI : public ChannelGUI { - Q_OBJECT - -public: - static VORDemodSCGUI* create(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, BasebandSampleSink *rxChannel); - virtual void destroy(); - - void resetToDefaults(); - QByteArray serialize() const; - bool deserialize(const QByteArray& data); - virtual MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; } - -public slots: - void channelMarkerChangedByCursor(); - void channelMarkerHighlightedByCursor(); - -private: - Ui::VORDemodSCGUI* ui; - PluginAPI* m_pluginAPI; - DeviceUISet* m_deviceUISet; - ChannelMarker m_channelMarker; - RollupState m_rollupState; - VORDemodSCSettings m_settings; - bool m_doApplySettings; - - VORDemodSC* m_vorDemod; - bool m_squelchOpen; - int m_basebandSampleRate; - uint32_t m_tickCount; - MessageQueue m_inputMessageQueue; - - explicit VORDemodSCGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, BasebandSampleSink *rxChannel, QWidget* parent = 0); - virtual ~VORDemodSCGUI(); - - void blockApplySettings(bool block); - void applySettings(bool force = false); - void displaySettings(); - void displayStreamIndex(); - bool handleMessage(const Message& message); - - void leaveEvent(QEvent*); - void enterEvent(QEvent*); - -private slots: - void on_deltaFrequency_changed(qint64 value); - void on_thresh_valueChanged(int value); - void on_volume_valueChanged(int value); - void on_squelch_valueChanged(int value); - void on_audioMute_toggled(bool checked); - void onWidgetRolled(QWidget* widget, bool rollDown); - void onMenuDialogCalled(const QPoint& p); - void handleInputMessages(); - void audioSelect(); - void tick(); -}; - -#endif // INCLUDE_VORDEMODSCGUI_H diff --git a/plugins/channelrx/demodwfm/readme.md b/plugins/channelrx/demodwfm/readme.md index 67ad663f4..27e3cbb82 100644 --- a/plugins/channelrx/demodwfm/readme.md +++ b/plugins/channelrx/demodwfm/readme.md @@ -6,6 +6,8 @@ This plugin can be used to listen to a wideband or narrowband FM modulated signa

Interface

+The top and bottom bars of the channel window are described [here](../../../sdrgui/channel/readme.md) + ![WFM Demodulator plugin GUI](../../../doc/img/WFMDemod_plugin.png)

1: Frequency shift from center frequency of reception

diff --git a/plugins/channelrx/demodwfm/wfmdemod.cpp b/plugins/channelrx/demodwfm/wfmdemod.cpp index c6c824f49..719353708 100644 --- a/plugins/channelrx/demodwfm/wfmdemod.cpp +++ b/plugins/channelrx/demodwfm/wfmdemod.cpp @@ -28,6 +28,7 @@ #include #include "SWGChannelSettings.h" +#include "SWGWorkspaceInfo.h" #include "SWGWFMDemodSettings.h" #include "SWGChannelReport.h" #include "SWGWFMDemodReport.h" @@ -99,6 +100,18 @@ WFMDemod::~WFMDemod() delete m_thread; } +void WFMDemod::setDeviceAPI(DeviceAPI *deviceAPI) +{ + if (deviceAPI != m_deviceAPI) + { + m_deviceAPI->removeChannelSinkAPI(this); + m_deviceAPI->removeChannelSink(this); + m_deviceAPI = deviceAPI; + m_deviceAPI->addChannelSink(this); + m_deviceAPI->addChannelSinkAPI(this); + } +} + uint32_t WFMDemod::getNumberOfDeviceStreams() const { return m_deviceAPI->getNbSourceStreams(); @@ -148,6 +161,10 @@ bool WFMDemod::handleMessage(const Message& cmd) DSPSignalNotification* rep = new DSPSignalNotification(notif); // make a copy qDebug() << "WFMDemod::handleMessage: DSPSignalNotification"; m_basebandSink->getInputMessageQueue()->push(rep); + // Forwatd to GUI if any + if (getMessageQueueToGUI()) { + getMessageQueueToGUI()->push(new DSPSignalNotification(notif)); + } return true; } @@ -314,6 +331,15 @@ int WFMDemod::webapiSettingsGet( return 200; } +int WFMDemod::webapiWorkspaceGet( + SWGSDRangel::SWGWorkspaceInfo& response, + QString& errorMessage) +{ + (void) errorMessage; + response.setIndex(m_settings.m_workspaceIndex); + return 200; +} + int WFMDemod::webapiSettingsPutPatch( bool force, const QStringList& channelSettingsKeys, diff --git a/plugins/channelrx/demodwfm/wfmdemod.h b/plugins/channelrx/demodwfm/wfmdemod.h index beef2586b..73f407a5b 100644 --- a/plugins/channelrx/demodwfm/wfmdemod.h +++ b/plugins/channelrx/demodwfm/wfmdemod.h @@ -63,6 +63,8 @@ public: WFMDemod(DeviceAPI *deviceAPI); virtual ~WFMDemod(); virtual void destroy() { delete this; } + virtual void setDeviceAPI(DeviceAPI *deviceAPI); + virtual DeviceAPI *getDeviceAPI() { return m_deviceAPI; } using BasebandSampleSink::feed; virtual void feed(const SampleVector::const_iterator& begin, const SampleVector::const_iterator& end, bool po); @@ -100,6 +102,10 @@ public: SWGSDRangel::SWGChannelSettings& response, QString& errorMessage); + virtual int webapiWorkspaceGet( + SWGSDRangel::SWGWorkspaceInfo& response, + QString& errorMessage); + virtual int webapiSettingsPutPatch( bool force, const QStringList& channelSettingsKeys, diff --git a/plugins/channelrx/demodwfm/wfmdemodgui.cpp b/plugins/channelrx/demodwfm/wfmdemodgui.cpp index 0781bbbd0..47237c6f7 100644 --- a/plugins/channelrx/demodwfm/wfmdemodgui.cpp +++ b/plugins/channelrx/demodwfm/wfmdemodgui.cpp @@ -8,6 +8,7 @@ #include "ui_wfmdemodgui.h" #include "dsp/dspengine.h" +#include "dsp/dspcommands.h" #include "plugin/pluginapi.h" #include "util/simpleserializer.h" #include "util/db.h" @@ -54,9 +55,16 @@ bool WFMDemodGUI::deserialize(const QByteArray& data) } } +void WFMDemodGUI::resizeEvent(QResizeEvent* size) +{ + int maxWidth = getRollupContents()->maximumWidth(); + int minHeight = getRollupContents()->minimumHeight() + getAdditionalHeight(); + resize(width() < maxWidth ? width() : maxWidth, minHeight); + size->accept(); +} + bool WFMDemodGUI::handleMessage(const Message& message) { - (void) message; if (WFMDemod::MsgConfigureWFMDemod::match(message)) { qDebug("WFMDemodGUI::handleMessage: WFMDemod::MsgConfigureWFMDemod"); @@ -67,6 +75,16 @@ bool WFMDemodGUI::handleMessage(const Message& message) blockApplySettings(false); return true; } + else if (DSPSignalNotification::match(message)) + { + const DSPSignalNotification& notif = (const DSPSignalNotification&) message; + m_deviceCenterFrequency = notif.getCenterFrequency(); + m_basebandSampleRate = notif.getSampleRate(); + ui->deltaFrequency->setValueRange(false, 8, -m_basebandSampleRate/2, m_basebandSampleRate/2); + ui->deltaFrequencyLabel->setToolTip(tr("Range %1 %L2 Hz").arg(QChar(0xB1)).arg(m_basebandSampleRate/2)); + updateAbsoluteCenterFrequency(); + return true; + } else { return false; @@ -102,6 +120,7 @@ void WFMDemodGUI::on_deltaFrequency_changed(qint64 value) { m_channelMarker.setCenterFrequency(value); m_settings.m_inputFrequencyOffset = m_channelMarker.getCenterFrequency(); + updateAbsoluteCenterFrequency(); applySettings(); } @@ -144,7 +163,7 @@ void WFMDemodGUI::onWidgetRolled(QWidget* widget, bool rollDown) (void) widget; (void) rollDown; - saveState(m_rollupState); + getRollupContents()->saveState(m_rollupState); applySettings(); } @@ -158,11 +177,17 @@ void WFMDemodGUI::onMenuDialogCalled(const QPoint &p) dialog.setReverseAPIPort(m_settings.m_reverseAPIPort); dialog.setReverseAPIDeviceIndex(m_settings.m_reverseAPIDeviceIndex); dialog.setReverseAPIChannelIndex(m_settings.m_reverseAPIChannelIndex); + dialog.setDefaultTitle(m_displayedName); + + if (m_deviceUISet->m_deviceMIMOEngine) + { + dialog.setNumberOfStreams(m_wfmDemod->getNumberOfDeviceStreams()); + dialog.setStreamIndex(m_settings.m_streamIndex); + } dialog.move(p); dialog.exec(); - m_settings.m_inputFrequencyOffset = m_channelMarker.getCenterFrequency(); m_settings.m_rgbColor = m_channelMarker.getColor().rgb(); m_settings.m_title = m_channelMarker.getTitle(); m_settings.m_useReverseAPI = dialog.useReverseAPI(); @@ -172,22 +197,17 @@ void WFMDemodGUI::onMenuDialogCalled(const QPoint &p) m_settings.m_reverseAPIChannelIndex = dialog.getReverseAPIChannelIndex(); setWindowTitle(m_settings.m_title); + setTitle(m_channelMarker.getTitle()); setTitleColor(m_settings.m_rgbColor); - applySettings(); - } - else if ((m_contextMenuType == ContextMenuStreamSettings) && (m_deviceUISet->m_deviceMIMOEngine)) - { - DeviceStreamSelectionDialog dialog(this); - dialog.setNumberOfStreams(m_wfmDemod->getNumberOfDeviceStreams()); - dialog.setStreamIndex(m_settings.m_streamIndex); - dialog.move(p); - dialog.exec(); + if (m_deviceUISet->m_deviceMIMOEngine) + { + m_settings.m_streamIndex = dialog.getSelectedStreamIndex(); + m_channelMarker.clearStreamIndexes(); + m_channelMarker.addStreamIndex(m_settings.m_streamIndex); + updateIndexLabel(); + } - m_settings.m_streamIndex = dialog.getSelectedStreamIndex(); - m_channelMarker.clearStreamIndexes(); - m_channelMarker.addStreamIndex(m_settings.m_streamIndex); - displayStreamIndex(); applySettings(); } @@ -200,14 +220,19 @@ WFMDemodGUI::WFMDemodGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, Baseban m_pluginAPI(pluginAPI), m_deviceUISet(deviceUISet), m_channelMarker(this), + m_deviceCenterFrequency(0), + m_basebandSampleRate(1), m_basicSettingsShown(false), m_squelchOpen(false), m_audioSampleRate(-1) { - ui->setupUi(this); - m_helpURL = "plugins/channelrx/demodwfm/readme.md"; setAttribute(Qt::WA_DeleteOnClose, true); - connect(this, SIGNAL(widgetRolled(QWidget*,bool)), this, SLOT(onWidgetRolled(QWidget*,bool))); + m_helpURL = "plugins/channelrx/demodwfm/readme.md"; + RollupContents *rollupContents = getRollupContents(); + ui->setupUi(rollupContents); + setSizePolicy(rollupContents->sizePolicy()); + rollupContents->arrangeRollups(); + connect(rollupContents, 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())); @@ -240,12 +265,12 @@ WFMDemodGUI::WFMDemodGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, Baseban m_settings.setRollupState(&m_rollupState); m_deviceUISet->addChannelMarker(&m_channelMarker); - m_deviceUISet->addRollupWidget(this); connect(&m_channelMarker, SIGNAL(changedByCursor()), this, SLOT(channelMarkerChangedByCursor())); connect(&m_channelMarker, SIGNAL(highlightedByCursor()), this, SLOT(channelMarkerHighlightedByCursor())); displaySettings(); + makeUIConnections(); applySettings(true); } @@ -279,6 +304,7 @@ void WFMDemodGUI::displaySettings() setTitleColor(m_settings.m_rgbColor); setWindowTitle(m_channelMarker.getTitle()); + setTitle(m_channelMarker.getTitle()); blockApplySettings(true); @@ -292,29 +318,23 @@ void WFMDemodGUI::displaySettings() ui->squelchText->setText(QString("%1 dB").arg(m_settings.m_squelch)); ui->audioMute->setChecked(m_settings.m_audioMute); - displayStreamIndex(); + updateIndexLabel(); - restoreState(m_rollupState); + getRollupContents()->restoreState(m_rollupState); + updateAbsoluteCenterFrequency(); blockApplySettings(false); } -void WFMDemodGUI::displayStreamIndex() -{ - if (m_deviceUISet->m_deviceMIMOEngine) { - setStreamIndicator(tr("%1").arg(m_settings.m_streamIndex)); - } else { - setStreamIndicator("S"); // single channel indicator - } -} - -void WFMDemodGUI::leaveEvent(QEvent*) +void WFMDemodGUI::leaveEvent(QEvent* event) { m_channelMarker.setHighlighted(false); + ChannelGUI::leaveEvent(event); } -void WFMDemodGUI::enterEvent(QEvent*) +void WFMDemodGUI::enterEvent(QEvent* event) { m_channelMarker.setHighlighted(true); + ChannelGUI::enterEvent(event); } void WFMDemodGUI::audioSelect() @@ -361,3 +381,18 @@ void WFMDemodGUI::tick() m_squelchOpen = squelchOpen; } } + +void WFMDemodGUI::makeUIConnections() +{ + QObject::connect(ui->deltaFrequency, &ValueDialZ::changed, this, &WFMDemodGUI::on_deltaFrequency_changed); + QObject::connect(ui->rfBW, &ValueDial::changed, this, &WFMDemodGUI::on_rfBW_changed); + QObject::connect(ui->afBW, &QSlider::valueChanged, this, &WFMDemodGUI::on_afBW_valueChanged); + QObject::connect(ui->volume, &QSlider::valueChanged, this, &WFMDemodGUI::on_volume_valueChanged); + QObject::connect(ui->squelch, &QSlider::valueChanged, this, &WFMDemodGUI::on_squelch_valueChanged); + QObject::connect(ui->audioMute, &QToolButton::toggled, this, &WFMDemodGUI::on_audioMute_toggled); +} + +void WFMDemodGUI::updateAbsoluteCenterFrequency() +{ + setStatusFrequency(m_deviceCenterFrequency + m_settings.m_inputFrequencyOffset); +} diff --git a/plugins/channelrx/demodwfm/wfmdemodgui.h b/plugins/channelrx/demodwfm/wfmdemodgui.h index e8205df57..ad4442667 100644 --- a/plugins/channelrx/demodwfm/wfmdemodgui.h +++ b/plugins/channelrx/demodwfm/wfmdemodgui.h @@ -28,11 +28,25 @@ public: QByteArray serialize() const; bool deserialize(const QByteArray& data); virtual MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; } + virtual void setWorkspaceIndex(int index) { m_settings.m_workspaceIndex = index; }; + virtual int getWorkspaceIndex() const { return m_settings.m_workspaceIndex; }; + virtual void setGeometryBytes(const QByteArray& blob) { m_settings.m_geometryBytes = blob; }; + virtual QByteArray getGeometryBytes() const { return m_settings.m_geometryBytes; }; + virtual QString getTitle() const { return m_settings.m_title; }; + virtual QColor getTitleColor() const { return m_settings.m_rgbColor; }; + virtual void zetHidden(bool hidden) { m_settings.m_hidden = hidden; } + virtual bool getHidden() const { return m_settings.m_hidden; } + virtual ChannelMarker& getChannelMarker() { return m_channelMarker; } + virtual int getStreamIndex() const { return m_settings.m_streamIndex; } + virtual void setStreamIndex(int streamIndex) { m_settings.m_streamIndex = streamIndex; } public slots: void channelMarkerChangedByCursor(); void channelMarkerHighlightedByCursor(); +protected: + void resizeEvent(QResizeEvent* size); + private: Ui::WFMDemodGUI* ui; PluginAPI* m_pluginAPI; @@ -40,6 +54,8 @@ private: ChannelMarker m_channelMarker; RollupState m_rollupState; WFMDemodSettings m_settings; + qint64 m_deviceCenterFrequency; + int m_basebandSampleRate; bool m_basicSettingsShown; bool m_doApplySettings; bool m_audioMute; @@ -55,8 +71,9 @@ private: void blockApplySettings(bool block); void applySettings(bool force = false); void displaySettings(); - void displayStreamIndex(); bool handleMessage(const Message& message); + void makeUIConnections(); + void updateAbsoluteCenterFrequency(); void leaveEvent(QEvent*); void enterEvent(QEvent*); diff --git a/plugins/channelrx/demodwfm/wfmdemodgui.ui b/plugins/channelrx/demodwfm/wfmdemodgui.ui index 05e404bed..7d6e85e69 100644 --- a/plugins/channelrx/demodwfm/wfmdemodgui.ui +++ b/plugins/channelrx/demodwfm/wfmdemodgui.ui @@ -1,7 +1,7 @@ WFMDemodGUI - + 0 @@ -10,16 +10,22 @@ 170 + + + 0 + 0 + + 302 - 0 + 170 - 302 - 16777215 + 560 + 170 @@ -46,12 +52,6 @@ 0 - - - 300 - 16777215 - - Settings @@ -436,15 +436,9 @@ - RollupWidget + ValueDial QWidget -
gui/rollupwidget.h
- 1 -
- - LevelMeterSignalDB - QWidget -
gui/levelmeter.h
+
gui/valuedial.h
1
@@ -454,9 +448,15 @@ 1 - ValueDial + RollupContents QWidget -
gui/valuedial.h
+
gui/rollupcontents.h
+ 1 +
+ + LevelMeterSignalDB + QWidget +
gui/levelmeter.h
1
diff --git a/plugins/channelrx/demodwfm/wfmdemodsettings.cpp b/plugins/channelrx/demodwfm/wfmdemodsettings.cpp index 077f4fe5a..f0b778616 100644 --- a/plugins/channelrx/demodwfm/wfmdemodsettings.cpp +++ b/plugins/channelrx/demodwfm/wfmdemodsettings.cpp @@ -52,6 +52,8 @@ void WFMDemodSettings::resetToDefaults() m_reverseAPIPort = 8888; m_reverseAPIDeviceIndex = 0; m_reverseAPIChannelIndex = 0; + m_workspaceIndex = 0; + m_hidden = false; } QByteArray WFMDemodSettings::serialize() const @@ -81,6 +83,10 @@ QByteArray WFMDemodSettings::serialize() const s.writeBlob(18, m_rollupState->serialize()); } + s.writeS32(19, m_workspaceIndex); + s.writeBlob(20, m_geometryBytes); + s.writeBool(21, m_hidden); + return s.final(); } @@ -143,6 +149,10 @@ bool WFMDemodSettings::deserialize(const QByteArray& data) m_rollupState->deserialize(bytetmp); } + d.readS32(19, &m_workspaceIndex, 0); + d.readBlob(20, &m_geometryBytes); + d.readBool(21, &m_hidden, false); + return true; } else diff --git a/plugins/channelrx/demodwfm/wfmdemodsettings.h b/plugins/channelrx/demodwfm/wfmdemodsettings.h index 3c7651f66..e839fc124 100644 --- a/plugins/channelrx/demodwfm/wfmdemodsettings.h +++ b/plugins/channelrx/demodwfm/wfmdemodsettings.h @@ -40,6 +40,9 @@ struct WFMDemodSettings uint16_t m_reverseAPIPort; uint16_t m_reverseAPIDeviceIndex; uint16_t m_reverseAPIChannelIndex; + int m_workspaceIndex; + QByteArray m_geometryBytes; + bool m_hidden; Serializable *m_channelMarker; Serializable *m_rollupState; diff --git a/plugins/channelrx/filesink/filesink.cpp b/plugins/channelrx/filesink/filesink.cpp index cc7c17a23..ed91febae 100644 --- a/plugins/channelrx/filesink/filesink.cpp +++ b/plugins/channelrx/filesink/filesink.cpp @@ -24,6 +24,7 @@ #include #include "SWGChannelSettings.h" +#include "SWGWorkspaceInfo.h" #include "SWGChannelReport.h" #include "SWGChannelActions.h" @@ -101,6 +102,18 @@ FileSink::~FileSink() delete m_basebandSink; } +void FileSink::setDeviceAPI(DeviceAPI *deviceAPI) +{ + if (deviceAPI != m_deviceAPI) + { + m_deviceAPI->removeChannelSinkAPI(this); + m_deviceAPI->removeChannelSink(this); + m_deviceAPI = deviceAPI; + m_deviceAPI->addChannelSink(this); + m_deviceAPI->addChannelSinkAPI(this); + } +} + void FileSink::setMessageQueueToGUI(MessageQueue* queue) { ChannelAPI::setMessageQueueToGUI(queue); @@ -170,10 +183,8 @@ bool FileSink::handleMessage(const Message& cmd) DSPSignalNotification *notif = new DSPSignalNotification(cfg); m_basebandSink->getInputMessageQueue()->push(notif); - if (getMessageQueueToGUI()) - { - DSPSignalNotification *notifToGUI = new DSPSignalNotification(cfg); - getMessageQueueToGUI()->push(notifToGUI); + if (getMessageQueueToGUI()) { + getMessageQueueToGUI()->push(new DSPSignalNotification(cfg)); } return true; @@ -384,6 +395,15 @@ int FileSink::webapiSettingsGet( return 200; } +int FileSink::webapiWorkspaceGet( + SWGSDRangel::SWGWorkspaceInfo& response, + QString& errorMessage) +{ + (void) errorMessage; + response.setIndex(m_settings.m_workspaceIndex); + return 200; +} + int FileSink::webapiSettingsPutPatch( bool force, const QStringList& channelSettingsKeys, diff --git a/plugins/channelrx/filesink/filesink.h b/plugins/channelrx/filesink/filesink.h index 679d2a04a..95ec66ffb 100644 --- a/plugins/channelrx/filesink/filesink.h +++ b/plugins/channelrx/filesink/filesink.h @@ -84,6 +84,8 @@ public: FileSink(DeviceAPI *deviceAPI); virtual ~FileSink(); virtual void destroy() { delete this; } + virtual void setDeviceAPI(DeviceAPI *deviceAPI); + virtual DeviceAPI *getDeviceAPI() { return m_deviceAPI; } using BasebandSampleSink::feed; virtual void feed(const SampleVector::const_iterator& begin, const SampleVector::const_iterator& end, bool po); @@ -115,6 +117,10 @@ public: SWGSDRangel::SWGChannelSettings& response, QString& errorMessage); + virtual int webapiWorkspaceGet( + SWGSDRangel::SWGWorkspaceInfo& response, + QString& errorMessage); + virtual int webapiSettingsPutPatch( bool force, const QStringList& channelSettingsKeys, diff --git a/plugins/channelrx/filesink/filesinkgui.cpp b/plugins/channelrx/filesink/filesinkgui.cpp index ab6122984..b4127e18f 100644 --- a/plugins/channelrx/filesink/filesinkgui.cpp +++ b/plugins/channelrx/filesink/filesinkgui.cpp @@ -76,7 +76,11 @@ bool FileSinkGUI::handleMessage(const Message& message) if (DSPSignalNotification::match(message)) { DSPSignalNotification notif = (const DSPSignalNotification&) message; + m_deviceCenterFrequency = notif.getCenterFrequency(); m_basebandSampleRate = notif.getSampleRate(); + ui->deltaFrequency->setValueRange(false, 8, -m_basebandSampleRate/2, m_basebandSampleRate/2); + ui->deltaFrequencyLabel->setToolTip(tr("Range %1 %L2 Hz").arg(QChar(0xB1)).arg(m_basebandSampleRate/2)); + updateAbsoluteCenterFrequency(); displayRate(); if (m_fixedPosition) @@ -178,16 +182,20 @@ FileSinkGUI::FileSinkGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, Baseban m_pluginAPI(pluginAPI), m_deviceUISet(deviceUISet), m_channelMarker(this), + m_deviceCenterFrequency(0), m_running(false), m_fixedShiftIndex(0), m_basebandSampleRate(0), m_fixedPosition(false), m_tickCount(0) { - ui->setupUi(this); - m_helpURL = "plugins/channelrx/filesink/readme.md"; setAttribute(Qt::WA_DeleteOnClose, true); - connect(this, SIGNAL(widgetRolled(QWidget*,bool)), this, SLOT(onWidgetRolled(QWidget*,bool))); + m_helpURL = "plugins/channelrx/filesink/readme.md"; + RollupContents *rollupContents = getRollupContents(); + ui->setupUi(rollupContents); + setSizePolicy(rollupContents->sizePolicy()); + rollupContents->arrangeRollups(); + connect(rollupContents, SIGNAL(widgetRolled(QWidget*,bool)), this, SLOT(onWidgetRolled(QWidget*,bool))); connect(this, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(onMenuDialogCalled(const QPoint &))); m_fileSink = (FileSink*) channelrx; @@ -214,7 +222,6 @@ FileSinkGUI::FileSinkGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, Baseban m_settings.setRollupState(&m_rollupState); m_deviceUISet->addChannelMarker(&m_channelMarker); - m_deviceUISet->addRollupWidget(this); connect(&m_channelMarker, SIGNAL(changedByCursor()), this, SLOT(channelMarkerChangedByCursor())); connect(&m_channelMarker, SIGNAL(highlightedByCursor()), this, SLOT(channelMarkerHighlightedByCursor())); @@ -222,6 +229,7 @@ FileSinkGUI::FileSinkGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, Baseban connect(&(m_deviceUISet->m_deviceAPI->getMasterTimer()), SIGNAL(timeout()), this, SLOT(tick())); displaySettings(); + makeUIConnections(); applySettings(true); } @@ -257,6 +265,7 @@ void FileSinkGUI::displaySettings() setTitleColor(m_settings.m_rgbColor); setWindowTitle(m_channelMarker.getTitle()); + setTitle(m_channelMarker.getTitle()); blockApplySettings(true); @@ -277,22 +286,14 @@ void FileSinkGUI::displaySettings() ui->squelchLevel->setStyleSheet("QDial { background:rgb(79,79,79); }"); } - displayStreamIndex(); + updateIndexLabel(); setPosFromFrequency(); - restoreState(m_rollupState); + getRollupContents()->restoreState(m_rollupState); + updateAbsoluteCenterFrequency(); blockApplySettings(false); } -void FileSinkGUI::displayStreamIndex() -{ - if (m_deviceUISet->m_deviceMIMOEngine) { - setStreamIndicator(tr("%1").arg(m_settings.m_streamIndex)); - } else { - setStreamIndicator("S"); // single channel indicator - } -} - void FileSinkGUI::displayRate() { double channelSampleRate = ((double) m_basebandSampleRate) / (1<filterChainIndex->setText(tr("%1").arg(m_fixedShiftIndex)); } -void FileSinkGUI::leaveEvent(QEvent*) +void FileSinkGUI::leaveEvent(QEvent* event) { m_channelMarker.setHighlighted(false); + ChannelGUI::leaveEvent(event); } -void FileSinkGUI::enterEvent(QEvent*) +void FileSinkGUI::enterEvent(QEvent* event) { m_channelMarker.setHighlighted(true); + ChannelGUI::enterEvent(event); } void FileSinkGUI::channelMarkerChangedByCursor() @@ -351,7 +354,18 @@ void FileSinkGUI::onWidgetRolled(QWidget* widget, bool rollDown) (void) widget; (void) rollDown; - saveState(m_rollupState); + RollupContents *rollupContents = getRollupContents(); + + if (rollupContents->hasExpandableWidgets()) { + setSizePolicy(sizePolicy().horizontalPolicy(), QSizePolicy::Expanding); + } else { + setSizePolicy(sizePolicy().horizontalPolicy(), QSizePolicy::Fixed); + } + + int h = rollupContents->height() + getAdditionalHeight(); + resize(width(), h); + + rollupContents->saveState(m_rollupState); applySettings(); } @@ -365,6 +379,13 @@ void FileSinkGUI::onMenuDialogCalled(const QPoint &p) dialog.setReverseAPIPort(m_settings.m_reverseAPIPort); dialog.setReverseAPIDeviceIndex(m_settings.m_reverseAPIDeviceIndex); dialog.setReverseAPIChannelIndex(m_settings.m_reverseAPIChannelIndex); + dialog.setDefaultTitle(m_displayedName); + + if (m_deviceUISet->m_deviceMIMOEngine) + { + dialog.setNumberOfStreams(m_fileSink->getNumberOfDeviceStreams()); + dialog.setStreamIndex(m_settings.m_streamIndex); + } dialog.move(p); dialog.exec(); @@ -378,22 +399,17 @@ void FileSinkGUI::onMenuDialogCalled(const QPoint &p) m_settings.m_reverseAPIChannelIndex = dialog.getReverseAPIChannelIndex(); setWindowTitle(m_settings.m_title); + setTitle(m_channelMarker.getTitle()); setTitleColor(m_settings.m_rgbColor); - applySettings(); - } - else if ((m_contextMenuType == ContextMenuStreamSettings) && (m_deviceUISet->m_deviceMIMOEngine)) - { - DeviceStreamSelectionDialog dialog(this); - dialog.setNumberOfStreams(m_fileSink->getNumberOfDeviceStreams()); - dialog.setStreamIndex(m_settings.m_streamIndex); - dialog.move(p); - dialog.exec(); + if (m_deviceUISet->m_deviceMIMOEngine) + { + m_settings.m_streamIndex = dialog.getSelectedStreamIndex(); + m_channelMarker.clearStreamIndexes(); + m_channelMarker.addStreamIndex(m_settings.m_streamIndex); + updateIndexLabel(); + } - m_settings.m_streamIndex = dialog.getSelectedStreamIndex(); - m_channelMarker.clearStreamIndexes(); - m_channelMarker.addStreamIndex(m_settings.m_streamIndex); - displayStreamIndex(); applySettings(); } @@ -406,6 +422,7 @@ void FileSinkGUI::on_deltaFrequency_changed(qint64 value) { m_channelMarker.setCenterFrequency(value); m_settings.m_inputFrequencyOffset = m_channelMarker.getCenterFrequency(); + updateAbsoluteCenterFrequency(); setPosFromFrequency(); applySettings(); } @@ -538,6 +555,7 @@ void FileSinkGUI::setFrequencyFromPos() m_channelMarker.setCenterFrequency(inputFrequencyOffset); ui->deltaFrequency->setValue(m_channelMarker.getCenterFrequency()); m_settings.m_inputFrequencyOffset = m_channelMarker.getCenterFrequency(); + updateAbsoluteCenterFrequency(); } void FileSinkGUI::setPosFromFrequency() @@ -591,3 +609,22 @@ QString FileSinkGUI::displayScaled(uint64_t value, int precision) } } +void FileSinkGUI::makeUIConnections() +{ + QObject::connect(ui->deltaFrequency, &ValueDialZ::changed, this, &FileSinkGUI::on_deltaFrequency_changed); + QObject::connect(ui->decimationFactor, QOverload::of(&QComboBox::currentIndexChanged), this, &FileSinkGUI::on_decimationFactor_currentIndexChanged); + QObject::connect(ui->fixedPosition, &QCheckBox::toggled, this, &FileSinkGUI::on_fixedPosition_toggled); + QObject::connect(ui->position, &QSlider::valueChanged, this, &FileSinkGUI::on_position_valueChanged); + QObject::connect(ui->spectrumSquelch, &ButtonSwitch::toggled, this, &FileSinkGUI::on_spectrumSquelch_toggled); + QObject::connect(ui->squelchLevel, &QDial::valueChanged, this, &FileSinkGUI::on_squelchLevel_valueChanged); + QObject::connect(ui->preRecordTime, &QDial::valueChanged, this, &FileSinkGUI::on_preRecordTime_valueChanged); + QObject::connect(ui->postSquelchTime, &QDial::valueChanged, this, &FileSinkGUI::on_postSquelchTime_valueChanged); + QObject::connect(ui->squelchedRecording, &ButtonSwitch::toggled, this, &FileSinkGUI::on_squelchedRecording_toggled); + QObject::connect(ui->record, &ButtonSwitch::toggled, this, &FileSinkGUI::on_record_toggled); + QObject::connect(ui->showFileDialog, &QPushButton::clicked, this, &FileSinkGUI::on_showFileDialog_clicked); +} + +void FileSinkGUI::updateAbsoluteCenterFrequency() +{ + setStatusFrequency(m_deviceCenterFrequency + m_settings.m_inputFrequencyOffset); +} diff --git a/plugins/channelrx/filesink/filesinkgui.h b/plugins/channelrx/filesink/filesinkgui.h index 2c86a0c50..f38d0cbda 100644 --- a/plugins/channelrx/filesink/filesinkgui.h +++ b/plugins/channelrx/filesink/filesinkgui.h @@ -49,6 +49,17 @@ public: QByteArray serialize() const; bool deserialize(const QByteArray& data); virtual MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; } + virtual void setWorkspaceIndex(int index) { m_settings.m_workspaceIndex = index; }; + virtual int getWorkspaceIndex() const { return m_settings.m_workspaceIndex; }; + virtual void setGeometryBytes(const QByteArray& blob) { m_settings.m_geometryBytes = blob; }; + virtual QByteArray getGeometryBytes() const { return m_settings.m_geometryBytes; }; + virtual QString getTitle() const { return m_settings.m_title; }; + virtual QColor getTitleColor() const { return m_settings.m_rgbColor; }; + virtual void zetHidden(bool hidden) { m_settings.m_hidden = hidden; } + virtual bool getHidden() const { return m_settings.m_hidden; } + virtual ChannelMarker& getChannelMarker() { return m_channelMarker; } + virtual int getStreamIndex() const { return m_settings.m_streamIndex; } + virtual void setStreamIndex(int streamIndex) { m_settings.m_streamIndex = streamIndex; } public slots: void channelMarkerChangedByCursor(); @@ -61,6 +72,7 @@ private: ChannelMarker m_channelMarker; RollupState m_rollupState; FileSinkSettings m_settings; + qint64 m_deviceCenterFrequency; bool m_running; int m_fixedShiftIndex; int m_basebandSampleRate; @@ -81,13 +93,14 @@ private: void applySettings(bool force = false); void applyDecimation(); void displaySettings(); - void displayStreamIndex(); void displayRate(); void displayPos(); void setFrequencyFromPos(); void setPosFromFrequency(); QString displayScaled(uint64_t value, int precision); bool handleMessage(const Message& message); + void makeUIConnections(); + void updateAbsoluteCenterFrequency(); void leaveEvent(QEvent*); void enterEvent(QEvent*); diff --git a/plugins/channelrx/filesink/filesinkgui.ui b/plugins/channelrx/filesink/filesinkgui.ui index 67388a521..55ba0b170 100644 --- a/plugins/channelrx/filesink/filesinkgui.ui +++ b/plugins/channelrx/filesink/filesinkgui.ui @@ -1,7 +1,7 @@ FileSinkGUI - + 0 @@ -10,6 +10,12 @@ 458 + + + 0 + 0 + + 552 @@ -508,7 +514,7 @@ - + 0 @@ -517,8 +523,11 @@ 351 - - Channel Spectrum + + + 0 + 0 + @@ -526,9 +535,15 @@ + + + 0 + 0 + + - 0 + 300 300 @@ -548,20 +563,9 @@ - RollupWidget + RollupContents QWidget -
gui/rollupwidget.h
- 1 -
- - ButtonSwitch - QToolButton -
gui/buttonswitch.h
-
- - ValueDialZ - QWidget -
gui/valuedialz.h
+
gui/rollupcontents.h
1
@@ -576,6 +580,17 @@
gui/glspectrumgui.h
1
+ + ValueDialZ + QWidget +
gui/valuedialz.h
+ 1 +
+ + ButtonSwitch + QToolButton +
gui/buttonswitch.h
+
diff --git a/plugins/channelrx/filesink/filesinksettings.cpp b/plugins/channelrx/filesink/filesinksettings.cpp index 74eb15bdf..8726054a7 100644 --- a/plugins/channelrx/filesink/filesinksettings.cpp +++ b/plugins/channelrx/filesink/filesinksettings.cpp @@ -49,6 +49,8 @@ void FileSinkSettings::resetToDefaults() m_reverseAPIPort = 8888; m_reverseAPIDeviceIndex = 0; m_reverseAPIChannelIndex = 0; + m_workspaceIndex = 0; + m_hidden = false; } QByteArray FileSinkSettings::serialize() const @@ -85,6 +87,10 @@ QByteArray FileSinkSettings::serialize() const s.writeBlob(19, m_rollupState->serialize()); } + s.writeS32(20, m_workspaceIndex); + s.writeBlob(21, m_geometryBytes); + s.writeBool(22, m_hidden); + return s.final(); } @@ -153,6 +159,10 @@ bool FileSinkSettings::deserialize(const QByteArray& data) m_rollupState->deserialize(bytetmp); } + d.readS32(20, &m_workspaceIndex, 0); + d.readBlob(21, &m_geometryBytes); + d.readBool(22, &m_hidden, false); + return true; } else diff --git a/plugins/channelrx/filesink/filesinksettings.h b/plugins/channelrx/filesink/filesinksettings.h index aa76798f2..4c43d43fb 100644 --- a/plugins/channelrx/filesink/filesinksettings.h +++ b/plugins/channelrx/filesink/filesinksettings.h @@ -41,6 +41,9 @@ struct FileSinkSettings uint16_t m_reverseAPIPort; uint16_t m_reverseAPIDeviceIndex; uint16_t m_reverseAPIChannelIndex; + int m_workspaceIndex; + QByteArray m_geometryBytes; + bool m_hidden; Serializable *m_spectrumGUI; Serializable *m_channelMarker; diff --git a/plugins/channelrx/filesink/readme.md b/plugins/channelrx/filesink/readme.md index e1c4b4e25..0b62906eb 100644 --- a/plugins/channelrx/filesink/readme.md +++ b/plugins/channelrx/filesink/readme.md @@ -18,6 +18,8 @@ If a filename is given with an extension different of `.sdriq` or `.wav` then th

Interface

+The top and bottom bars of the channel window are described [here](../../../sdrgui/channel/readme.md) + ![File Sink plugin GUI](../../../doc/img/FileSink_plugin.png)

1: Frequency shift from center frequency of reception

@@ -99,4 +101,4 @@ The file path currently being written (or last closed) appears at the right of t

15: Channel spectrum

-This is the spectrum display of the IQ stream seen by the channel. It is the same as all spectrum displays in the program and is identical to the [main window](../../../sdrgui/readme.md#) spectrum display. +This is the spectrum display of the IQ stream seen by the channel. Details on the spectrum view and controls can be found [here](../../../sdrgui/gui/spectrum.md) diff --git a/plugins/channelrx/freqtracker/freqtracker.cpp b/plugins/channelrx/freqtracker/freqtracker.cpp index d885a4c29..8f0f0e07e 100644 --- a/plugins/channelrx/freqtracker/freqtracker.cpp +++ b/plugins/channelrx/freqtracker/freqtracker.cpp @@ -29,6 +29,7 @@ #include #include "SWGChannelSettings.h" +#include "SWGWorkspaceInfo.h" #include "SWGFreqTrackerSettings.h" #include "SWGChannelReport.h" #include "SWGFreqTrackerReport.h" @@ -101,6 +102,18 @@ FreqTracker::~FreqTracker() delete m_thread; } +void FreqTracker::setDeviceAPI(DeviceAPI *deviceAPI) +{ + if (deviceAPI != m_deviceAPI) + { + m_deviceAPI->removeChannelSinkAPI(this); + m_deviceAPI->removeChannelSink(this); + m_deviceAPI = deviceAPI; + m_deviceAPI->addChannelSink(this); + m_deviceAPI->addChannelSinkAPI(this); + } +} + uint32_t FreqTracker::getNumberOfDeviceStreams() const { return m_deviceAPI->getNbSourceStreams(); @@ -142,10 +155,8 @@ bool FreqTracker::handleMessage(const Message& cmd) qDebug() << "FreqTracker::handleMessage: DSPSignalNotification"; m_basebandSink->getInputMessageQueue()->push(rep); - if (getMessageQueueToGUI()) - { - DSPSignalNotification *msg = new DSPSignalNotification(notif); - getMessageQueueToGUI()->push(msg); + if (getMessageQueueToGUI()) { + getMessageQueueToGUI()->push(new DSPSignalNotification(notif)); } return true; @@ -334,6 +345,15 @@ int FreqTracker::webapiSettingsGet( return 200; } +int FreqTracker::webapiWorkspaceGet( + SWGSDRangel::SWGWorkspaceInfo& response, + QString& errorMessage) +{ + (void) errorMessage; + response.setIndex(m_settings.m_workspaceIndex); + return 200; +} + int FreqTracker::webapiSettingsPutPatch( bool force, const QStringList& channelSettingsKeys, diff --git a/plugins/channelrx/freqtracker/freqtracker.h b/plugins/channelrx/freqtracker/freqtracker.h index e77c60dd5..5a0a2e7eb 100644 --- a/plugins/channelrx/freqtracker/freqtracker.h +++ b/plugins/channelrx/freqtracker/freqtracker.h @@ -63,6 +63,8 @@ public: FreqTracker(DeviceAPI *deviceAPI); virtual ~FreqTracker(); virtual void destroy() { delete this; } + virtual void setDeviceAPI(DeviceAPI *deviceAPI); + virtual DeviceAPI *getDeviceAPI() { return m_deviceAPI; } using BasebandSampleSink::feed; virtual void feed(const SampleVector::const_iterator& begin, const SampleVector::const_iterator& end, bool po); @@ -94,6 +96,10 @@ public: SWGSDRangel::SWGChannelSettings& response, QString& errorMessage); + virtual int webapiWorkspaceGet( + SWGSDRangel::SWGWorkspaceInfo& response, + QString& errorMessage); + virtual int webapiSettingsPutPatch( bool force, const QStringList& channelSettingsKeys, diff --git a/plugins/channelrx/freqtracker/freqtrackergui.cpp b/plugins/channelrx/freqtracker/freqtrackergui.cpp index 8afe85d48..c1ebd541d 100644 --- a/plugins/channelrx/freqtracker/freqtrackergui.cpp +++ b/plugins/channelrx/freqtracker/freqtrackergui.cpp @@ -90,7 +90,11 @@ bool FreqTrackerGUI::handleMessage(const Message& message) else if (DSPSignalNotification::match(message)) { DSPSignalNotification& cfg = (DSPSignalNotification&) message; + m_deviceCenterFrequency = cfg.getCenterFrequency(); m_basebandSampleRate = cfg.getSampleRate(); + ui->deltaFrequency->setValueRange(false, 7, -m_basebandSampleRate/2, m_basebandSampleRate/2); + ui->deltaFrequencyLabel->setToolTip(tr("Range %1 %L2 Hz").arg(QChar(0xB1)).arg(m_basebandSampleRate/2)); + updateAbsoluteCenterFrequency(); int sinkSampleRate = m_basebandSampleRate / (1<channelSampleRateText->setText(tr("%1k").arg(QString::number(sinkSampleRate / 1000.0f, 'g', 5))); displaySpectrumBandwidth(m_settings.m_spanLog2); @@ -147,6 +151,7 @@ void FreqTrackerGUI::on_deltaFrequency_changed(qint64 value) { m_channelMarker.setCenterFrequency(value); m_settings.m_inputFrequencyOffset = m_channelMarker.getCenterFrequency(); + updateAbsoluteCenterFrequency(); applySettings(); } @@ -251,7 +256,7 @@ void FreqTrackerGUI::onWidgetRolled(QWidget* widget, bool rollDown) (void) widget; (void) rollDown; - saveState(m_rollupState); + getRollupContents()->saveState(m_rollupState); applySettings(); } @@ -265,10 +270,17 @@ void FreqTrackerGUI::onMenuDialogCalled(const QPoint &p) dialog.setReverseAPIPort(m_settings.m_reverseAPIPort); dialog.setReverseAPIDeviceIndex(m_settings.m_reverseAPIDeviceIndex); dialog.setReverseAPIChannelIndex(m_settings.m_reverseAPIChannelIndex); + dialog.setDefaultTitle(m_displayedName); + + if (m_deviceUISet->m_deviceMIMOEngine) + { + dialog.setNumberOfStreams(m_freqTracker->getNumberOfDeviceStreams()); + dialog.setStreamIndex(m_settings.m_streamIndex); + } + dialog.move(p); dialog.exec(); - m_settings.m_inputFrequencyOffset = m_channelMarker.getCenterFrequency(); m_settings.m_rgbColor = m_channelMarker.getColor().rgb(); m_settings.m_title = m_channelMarker.getTitle(); m_settings.m_useReverseAPI = dialog.useReverseAPI(); @@ -278,22 +290,17 @@ void FreqTrackerGUI::onMenuDialogCalled(const QPoint &p) m_settings.m_reverseAPIChannelIndex = dialog.getReverseAPIChannelIndex(); setWindowTitle(m_settings.m_title); + setTitle(m_channelMarker.getTitle()); setTitleColor(m_settings.m_rgbColor); - applySettings(); - } - else if ((m_contextMenuType == ContextMenuStreamSettings) && (m_deviceUISet->m_deviceMIMOEngine)) - { - DeviceStreamSelectionDialog dialog(this); - dialog.setNumberOfStreams(m_freqTracker->getNumberOfDeviceStreams()); - dialog.setStreamIndex(m_settings.m_streamIndex); - dialog.move(p); - dialog.exec(); + if (m_deviceUISet->m_deviceMIMOEngine) + { + m_settings.m_streamIndex = dialog.getSelectedStreamIndex(); + m_channelMarker.clearStreamIndexes(); + m_channelMarker.addStreamIndex(m_settings.m_streamIndex); + updateIndexLabel(); + } - m_settings.m_streamIndex = dialog.getSelectedStreamIndex(); - m_channelMarker.clearStreamIndexes(); - m_channelMarker.addStreamIndex(m_settings.m_streamIndex); - displayStreamIndex(); applySettings(); } @@ -307,15 +314,17 @@ FreqTrackerGUI::FreqTrackerGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, B m_deviceUISet(deviceUISet), m_channelMarker(this), m_pllChannelMarker(this), + m_deviceCenterFrequency(0), m_basebandSampleRate(0), m_doApplySettings(true), m_squelchOpen(false), m_tickCount(0) { - ui->setupUi(this); + ui->setupUi(getRollupContents()); + getRollupContents()->arrangeRollups(); m_helpURL = "plugins/channelrx/freqtracker/readme.md"; setAttribute(Qt::WA_DeleteOnClose, true); - connect(this, SIGNAL(widgetRolled(QWidget*,bool)), this, SLOT(onWidgetRolled(QWidget*,bool))); + connect(getRollupContents(), SIGNAL(widgetRolled(QWidget*,bool)), this, SLOT(onWidgetRolled(QWidget*,bool))); connect(this, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(onMenuDialogCalled(const QPoint &))); m_freqTracker = reinterpret_cast(rxChannel); @@ -344,7 +353,6 @@ FreqTrackerGUI::FreqTrackerGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, B m_settings.setRollupState(&m_rollupState); m_deviceUISet->addChannelMarker(&m_channelMarker); - m_deviceUISet->addRollupWidget(this); ui->glSpectrum->setCenterFrequency(0); m_pllChannelMarker.blockSignals(true); @@ -363,6 +371,7 @@ FreqTrackerGUI::FreqTrackerGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, B connect(getInputMessageQueue(), SIGNAL(messageEnqueued()), this, SLOT(handleInputMessages())); displaySettings(); + makeUIConnections(); applySettings(true); } @@ -403,6 +412,7 @@ void FreqTrackerGUI::displaySettings() setTitleColor(m_settings.m_rgbColor); setWindowTitle(m_channelMarker.getTitle()); + setTitle(m_channelMarker.getTitle()); blockApplySettings(true); @@ -431,9 +441,10 @@ void FreqTrackerGUI::displaySettings() ui->squelchGate->setValue(m_settings.m_squelchGate); displaySpectrumBandwidth(m_settings.m_spanLog2); - displayStreamIndex(); + updateIndexLabel(); - restoreState(m_rollupState); + getRollupContents()->restoreState(m_rollupState); + updateAbsoluteCenterFrequency(); blockApplySettings(false); } @@ -454,23 +465,16 @@ void FreqTrackerGUI::displaySpectrumBandwidth(int spanLog2) ui->glSpectrum->setSampleRate(spectrumRate); } -void FreqTrackerGUI::displayStreamIndex() -{ - if (m_deviceUISet->m_deviceMIMOEngine) { - setStreamIndicator(tr("%1").arg(m_settings.m_streamIndex)); - } else { - setStreamIndicator("S"); // single channel indicator - } -} - -void FreqTrackerGUI::leaveEvent(QEvent*) +void FreqTrackerGUI::leaveEvent(QEvent* event) { m_channelMarker.setHighlighted(false); + ChannelGUI::leaveEvent(event); } -void FreqTrackerGUI::enterEvent(QEvent*) +void FreqTrackerGUI::enterEvent(QEvent* event) { m_channelMarker.setHighlighted(true); + ChannelGUI::enterEvent(event); } void FreqTrackerGUI::tick() @@ -518,3 +522,21 @@ void FreqTrackerGUI::tick() m_tickCount++; } +void FreqTrackerGUI::makeUIConnections() +{ + QObject::connect(ui->deltaFrequency, &ValueDialZ::changed, this, &FreqTrackerGUI::on_deltaFrequency_changed); + QObject::connect(ui->rfBW, &QSlider::valueChanged, this, &FreqTrackerGUI::on_rfBW_valueChanged); + QObject::connect(ui->tracking, &QToolButton::toggled, this, &FreqTrackerGUI::on_tracking_toggled); + QObject::connect(ui->alphaEMA, &QDial::valueChanged, this, &FreqTrackerGUI::on_alphaEMA_valueChanged); + QObject::connect(ui->trackerType, QOverload::of(&QComboBox::currentIndexChanged), this, &FreqTrackerGUI::on_trackerType_currentIndexChanged); + QObject::connect(ui->pllPskOrder, QOverload::of(&QComboBox::currentIndexChanged), this, &FreqTrackerGUI::on_pllPskOrder_currentIndexChanged); + QObject::connect(ui->rrc, &ButtonSwitch::toggled, this, &FreqTrackerGUI::on_rrc_toggled); + QObject::connect(ui->rrcRolloff, &QDial::valueChanged, this, &FreqTrackerGUI::on_rrcRolloff_valueChanged); + QObject::connect(ui->squelch, &QSlider::valueChanged, this, &FreqTrackerGUI::on_squelch_valueChanged); + QObject::connect(ui->squelchGate, &QDial::valueChanged, this, &FreqTrackerGUI::on_squelchGate_valueChanged); +} + +void FreqTrackerGUI::updateAbsoluteCenterFrequency() +{ + setStatusFrequency(m_deviceCenterFrequency + m_settings.m_inputFrequencyOffset); +} diff --git a/plugins/channelrx/freqtracker/freqtrackergui.h b/plugins/channelrx/freqtracker/freqtrackergui.h index 5af7178ee..5f590ac81 100644 --- a/plugins/channelrx/freqtracker/freqtrackergui.h +++ b/plugins/channelrx/freqtracker/freqtrackergui.h @@ -49,6 +49,17 @@ public: QByteArray serialize() const; bool deserialize(const QByteArray& data); virtual MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; } + virtual void setWorkspaceIndex(int index) { m_settings.m_workspaceIndex = index; }; + virtual int getWorkspaceIndex() const { return m_settings.m_workspaceIndex; }; + virtual void setGeometryBytes(const QByteArray& blob) { m_settings.m_geometryBytes = blob; }; + virtual QByteArray getGeometryBytes() const { return m_settings.m_geometryBytes; }; + virtual QString getTitle() const { return m_settings.m_title; }; + virtual QColor getTitleColor() const { return m_settings.m_rgbColor; }; + virtual void zetHidden(bool hidden) { m_settings.m_hidden = hidden; } + virtual bool getHidden() const { return m_settings.m_hidden; } + virtual ChannelMarker& getChannelMarker() { return m_channelMarker; } + virtual int getStreamIndex() const { return m_settings.m_streamIndex; } + virtual void setStreamIndex(int streamIndex) { m_settings.m_streamIndex = streamIndex; } public slots: void channelMarkerChangedByCursor(); @@ -62,6 +73,7 @@ private: ChannelMarker m_pllChannelMarker; RollupState m_rollupState; FreqTrackerSettings m_settings; + qint64 m_deviceCenterFrequency; int m_basebandSampleRate; bool m_doApplySettings; @@ -79,8 +91,9 @@ private: void applySpectrumBandwidth(int spanLog2, bool force = false); void displaySettings(); void displaySpectrumBandwidth(int spanLog2); - void displayStreamIndex(); bool handleMessage(const Message& message); + void makeUIConnections(); + void updateAbsoluteCenterFrequency(); void leaveEvent(QEvent*); void enterEvent(QEvent*); diff --git a/plugins/channelrx/freqtracker/freqtrackergui.ui b/plugins/channelrx/freqtracker/freqtrackergui.ui index 93b964f15..cc5d7a76f 100644 --- a/plugins/channelrx/freqtracker/freqtrackergui.ui +++ b/plugins/channelrx/freqtracker/freqtrackergui.ui @@ -1,7 +1,7 @@ FreqTrackerGUI - + 0 @@ -11,7 +11,7 @@ - + 0 0 @@ -754,6 +754,12 @@ 161 + + + 0 + 0 + + Channel Spectrum @@ -775,6 +781,18 @@
+ + + 0 + 0 + + + + + 300 + 300 + + Liberation Mono @@ -791,26 +809,9 @@ - RollupWidget + RollupContents QWidget -
gui/rollupwidget.h
- 1 -
- - ButtonSwitch - QToolButton -
gui/buttonswitch.h
-
- - LevelMeterSignalDB - QWidget -
gui/levelmeter.h
- 1 -
- - ValueDialZ - QWidget -
gui/valuedialz.h
+
gui/rollupcontents.h
1
@@ -825,6 +826,23 @@
gui/glspectrumgui.h
1
+ + ValueDialZ + QWidget +
gui/valuedialz.h
+ 1 +
+ + LevelMeterSignalDB + QWidget +
gui/levelmeter.h
+ 1 +
+ + ButtonSwitch + QToolButton +
gui/buttonswitch.h
+
diff --git a/plugins/channelrx/freqtracker/freqtrackersettings.cpp b/plugins/channelrx/freqtracker/freqtrackersettings.cpp index 58c0338b8..300e1282e 100644 --- a/plugins/channelrx/freqtracker/freqtrackersettings.cpp +++ b/plugins/channelrx/freqtracker/freqtrackersettings.cpp @@ -52,6 +52,8 @@ void FreqTrackerSettings::resetToDefaults() m_reverseAPIPort = 8888; m_reverseAPIDeviceIndex = 0; m_reverseAPIChannelIndex = 0; + m_workspaceIndex = 0; + m_hidden = false; } QByteArray FreqTrackerSettings::serialize() const @@ -91,6 +93,10 @@ QByteArray FreqTrackerSettings::serialize() const s.writeBlob(23, m_rollupState->serialize()); } + s.writeS32(24, m_workspaceIndex); + s.writeBlob(25, m_geometryBytes); + s.writeBool(26, m_hidden); + return s.final(); } @@ -170,6 +176,10 @@ bool FreqTrackerSettings::deserialize(const QByteArray& data) m_rollupState->deserialize(bytetmp); } + d.readS32(24, &m_workspaceIndex, 0); + d.readBlob(25, &m_geometryBytes); + d.readBool(26, &m_hidden, false); + return true; } else diff --git a/plugins/channelrx/freqtracker/freqtrackersettings.h b/plugins/channelrx/freqtracker/freqtrackersettings.h index b2d4e6f95..1129aa3ea 100644 --- a/plugins/channelrx/freqtracker/freqtrackersettings.h +++ b/plugins/channelrx/freqtracker/freqtrackersettings.h @@ -57,6 +57,9 @@ struct FreqTrackerSettings uint16_t m_reverseAPIDeviceIndex; uint16_t m_reverseAPIChannelIndex; Serializable *m_rollupState; + int m_workspaceIndex; + QByteArray m_geometryBytes; + bool m_hidden; FreqTrackerSettings(); void resetToDefaults(); diff --git a/plugins/channelrx/freqtracker/readme.md b/plugins/channelrx/freqtracker/readme.md index 6457b9bb3..a6832d6aa 100644 --- a/plugins/channelrx/freqtracker/readme.md +++ b/plugins/channelrx/freqtracker/readme.md @@ -8,6 +8,8 @@ This plugin can be used to track the center frequency of a carrier. It will try

Interface

+The top and bottom bars of the channel window are described [here](../../../sdrgui/channel/readme.md) + ![Frequency Tracker plugin GUI](../../../doc/img/FreqTracker_plugin.png)

1: Frequency shift from center frequency of reception

@@ -106,4 +108,4 @@ The channel signal is decimated by a power of two before being applied to the ch

12: Channel spectrum

-This is the spectrum display of the tracker channel. When the tracker is locked to the signal the center of the channel should fall almost in the middle of the signal spectrum (ideally in the middle when the tracker error is zero). Thus the locking can be followed dynamically and it can be more reliable than the lock indicator. A channel marker shows the tracker offset from the channel center frequency (tracker error). Its width is the tracker error tolerance and is ±1/1000th of the channel width. Controls on the bottom of the panel are identical to the ones of the main spectrum display. +This is the spectrum display of the tracker channel. When the tracker is locked to the signal the center of the channel should fall almost in the middle of the signal spectrum (ideally in the middle when the tracker error is zero). Thus the locking can be followed dynamically and it can be more reliable than the lock indicator. A channel marker shows the tracker offset from the channel center frequency (tracker error). Its width is the tracker error tolerance and is ±1/1000th of the channel width. Details on the spectrum view and controls can be found [here](../../../sdrgui/gui/spectrum.md) diff --git a/plugins/channelrx/localsink/localsink.cpp b/plugins/channelrx/localsink/localsink.cpp index dd0db8cba..3eb87911b 100644 --- a/plugins/channelrx/localsink/localsink.cpp +++ b/plugins/channelrx/localsink/localsink.cpp @@ -24,6 +24,7 @@ #include #include "SWGChannelSettings.h" +#include "SWGWorkspaceInfo.h" #include "util/simpleserializer.h" #include "dsp/dspcommands.h" @@ -41,7 +42,6 @@ #include "localsink.h" MESSAGE_CLASS_DEFINITION(LocalSink::MsgConfigureLocalSink, Message) -MESSAGE_CLASS_DEFINITION(LocalSink::MsgBasebandSampleRateNotification, Message) const char* const LocalSink::m_channelIdURI = "sdrangel.channel.localsink"; const char* const LocalSink::m_channelId = "LocalSink"; @@ -94,6 +94,18 @@ LocalSink::~LocalSink() delete m_thread; } +void LocalSink::setDeviceAPI(DeviceAPI *deviceAPI) +{ + if (deviceAPI != m_deviceAPI) + { + m_deviceAPI->removeChannelSinkAPI(this); + m_deviceAPI->removeChannelSink(this); + m_deviceAPI = deviceAPI; + m_deviceAPI->addChannelSink(this); + m_deviceAPI->addChannelSinkAPI(this); + } +} + uint32_t LocalSink::getNumberOfDeviceStreams() const { return m_deviceAPI->getNbSourceStreams(); @@ -138,10 +150,8 @@ bool LocalSink::handleMessage(const Message& cmd) DSPSignalNotification *msg = new DSPSignalNotification(notif.getSampleRate(), notif.getCenterFrequency()); m_basebandSink->getInputMessageQueue()->push(msg); - if (getMessageQueueToGUI()) - { - MsgBasebandSampleRateNotification *msg = MsgBasebandSampleRateNotification::create(notif.getSampleRate()); - getMessageQueueToGUI()->push(msg); + if (getMessageQueueToGUI()) { + getMessageQueueToGUI()->push(new DSPSignalNotification(notif)); } return true; @@ -359,6 +369,15 @@ int LocalSink::webapiSettingsGet( return 200; } +int LocalSink::webapiWorkspaceGet( + SWGSDRangel::SWGWorkspaceInfo& response, + QString& errorMessage) +{ + (void) errorMessage; + response.setIndex(m_settings.m_workspaceIndex); + return 200; +} + int LocalSink::webapiSettingsPutPatch( bool force, const QStringList& channelSettingsKeys, diff --git a/plugins/channelrx/localsink/localsink.h b/plugins/channelrx/localsink/localsink.h index 41cc56a77..d5ac97f47 100644 --- a/plugins/channelrx/localsink/localsink.h +++ b/plugins/channelrx/localsink/localsink.h @@ -61,29 +61,11 @@ public: { } }; - class MsgBasebandSampleRateNotification : public Message { - MESSAGE_CLASS_DECLARATION - - public: - static MsgBasebandSampleRateNotification* create(int sampleRate) { - return new MsgBasebandSampleRateNotification(sampleRate); - } - - int getSampleRate() const { return m_sampleRate; } - - private: - - MsgBasebandSampleRateNotification(int sampleRate) : - Message(), - m_sampleRate(sampleRate) - { } - - int m_sampleRate; - }; - LocalSink(DeviceAPI *deviceAPI); virtual ~LocalSink(); virtual void destroy() { delete this; } + virtual void setDeviceAPI(DeviceAPI *deviceAPI); + virtual DeviceAPI *getDeviceAPI() { return m_deviceAPI; } using BasebandSampleSink::feed; virtual void feed(const SampleVector::const_iterator& begin, const SampleVector::const_iterator& end, bool po); @@ -115,6 +97,10 @@ public: SWGSDRangel::SWGChannelSettings& response, QString& errorMessage); + virtual int webapiWorkspaceGet( + SWGSDRangel::SWGWorkspaceInfo& response, + QString& errorMessage); + virtual int webapiSettingsPutPatch( bool force, const QStringList& channelSettingsKeys, diff --git a/plugins/channelrx/localsink/localsinkgui.cpp b/plugins/channelrx/localsink/localsinkgui.cpp index 7af286f66..24230a796 100644 --- a/plugins/channelrx/localsink/localsinkgui.cpp +++ b/plugins/channelrx/localsink/localsinkgui.cpp @@ -16,11 +16,13 @@ /////////////////////////////////////////////////////////////////////////////////// #include +#include #include "device/deviceuiset.h" #include "gui/basicchannelsettingsdialog.h" #include "gui/devicestreamselectiondialog.h" #include "dsp/hbfilterchainconverter.h" +#include "dsp/dspcommands.h" #include "mainwindow.h" #include "localsinkgui.h" @@ -67,13 +69,23 @@ bool LocalSinkGUI::deserialize(const QByteArray& data) } } +void LocalSinkGUI::resizeEvent(QResizeEvent* size) +{ + int maxWidth = getRollupContents()->maximumWidth(); + int minHeight = getRollupContents()->minimumHeight() + getAdditionalHeight(); + resize(width() < maxWidth ? width() : maxWidth, minHeight); + size->accept(); +} + bool LocalSinkGUI::handleMessage(const Message& message) { - if (LocalSink::MsgBasebandSampleRateNotification::match(message)) + if (DSPSignalNotification::match(message)) { - LocalSink::MsgBasebandSampleRateNotification& notif = (LocalSink::MsgBasebandSampleRateNotification&) message; + DSPSignalNotification& notif = (DSPSignalNotification&) message; //m_channelMarker.setBandwidth(notif.getSampleRate()); + m_deviceCenterFrequency = notif.getCenterFrequency(); m_basebandSampleRate = notif.getSampleRate(); + updateAbsoluteCenterFrequency(); displayRateAndShift(); return true; } @@ -98,13 +110,17 @@ LocalSinkGUI::LocalSinkGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, Baseb ui(new Ui::LocalSinkGUI), m_pluginAPI(pluginAPI), m_deviceUISet(deviceUISet), + m_deviceCenterFrequency(0), m_basebandSampleRate(0), m_tickCount(0) { - ui->setupUi(this); - m_helpURL = "plugins/channelrx/localsink/readme.md"; setAttribute(Qt::WA_DeleteOnClose, true); - connect(this, SIGNAL(widgetRolled(QWidget*,bool)), this, SLOT(onWidgetRolled(QWidget*,bool))); + m_helpURL = "plugins/channelrx/localsink/readme.md"; + RollupContents *rollupContents = getRollupContents(); + ui->setupUi(rollupContents); + setSizePolicy(rollupContents->sizePolicy()); + rollupContents->arrangeRollups(); + connect(rollupContents, SIGNAL(widgetRolled(QWidget*,bool)), this, SLOT(onWidgetRolled(QWidget*,bool))); connect(this, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(onMenuDialogCalled(const QPoint &))); m_localSink = (LocalSink*) channelrx; @@ -121,12 +137,12 @@ LocalSinkGUI::LocalSinkGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, Baseb m_settings.setRollupState(&m_rollupState); m_deviceUISet->addChannelMarker(&m_channelMarker); - m_deviceUISet->addRollupWidget(this); connect(getInputMessageQueue(), SIGNAL(messageEnqueued()), this, SLOT(handleSourceMessages())); updateLocalDevices(); displaySettings(); + makeUIConnections(); applySettings(true); } @@ -163,6 +179,7 @@ void LocalSinkGUI::displaySettings() setTitleColor(m_settings.m_rgbColor); setWindowTitle(m_channelMarker.getTitle()); + setTitle(m_channelMarker.getTitle()); blockApplySettings(true); int index = getLocalDeviceIndexInCombo(m_settings.m_localDeviceIndex); @@ -174,21 +191,12 @@ void LocalSinkGUI::displaySettings() ui->localDevicePlay->setChecked(m_settings.m_play); ui->decimationFactor->setCurrentIndex(m_settings.m_log2Decim); applyDecimation(); - displayStreamIndex(); + updateIndexLabel(); - restoreState(m_rollupState); + getRollupContents()->restoreState(m_rollupState); blockApplySettings(false); } -void LocalSinkGUI::displayStreamIndex() -{ - if (m_deviceUISet->m_deviceMIMOEngine) { - setStreamIndicator(tr("%1").arg(m_settings.m_streamIndex)); - } else { - setStreamIndicator("S"); // single channel indicator - } -} - void LocalSinkGUI::displayRateAndShift() { int shift = m_shiftFrequencyFactor * m_basebandSampleRate; @@ -226,14 +234,16 @@ int LocalSinkGUI::getLocalDeviceIndexInCombo(int localDeviceIndex) return -1; } -void LocalSinkGUI::leaveEvent(QEvent*) +void LocalSinkGUI::leaveEvent(QEvent* event) { m_channelMarker.setHighlighted(false); + ChannelGUI::leaveEvent(event); } -void LocalSinkGUI::enterEvent(QEvent*) +void LocalSinkGUI::enterEvent(QEvent* event) { m_channelMarker.setHighlighted(true); + ChannelGUI::enterEvent(event); } void LocalSinkGUI::handleSourceMessages() @@ -254,7 +264,7 @@ void LocalSinkGUI::onWidgetRolled(QWidget* widget, bool rollDown) (void) widget; (void) rollDown; - saveState(m_rollupState); + getRollupContents()->saveState(m_rollupState); applySettings(); } @@ -268,6 +278,13 @@ void LocalSinkGUI::onMenuDialogCalled(const QPoint &p) dialog.setReverseAPIPort(m_settings.m_reverseAPIPort); dialog.setReverseAPIDeviceIndex(m_settings.m_reverseAPIDeviceIndex); dialog.setReverseAPIChannelIndex(m_settings.m_reverseAPIChannelIndex); + dialog.setDefaultTitle(m_displayedName); + + if (m_deviceUISet->m_deviceMIMOEngine) + { + dialog.setNumberOfStreams(m_localSink->getNumberOfDeviceStreams()); + dialog.setStreamIndex(m_settings.m_streamIndex); + } dialog.move(p); dialog.exec(); @@ -281,22 +298,17 @@ void LocalSinkGUI::onMenuDialogCalled(const QPoint &p) m_settings.m_reverseAPIChannelIndex = dialog.getReverseAPIChannelIndex(); setWindowTitle(m_settings.m_title); + setTitle(m_channelMarker.getTitle()); setTitleColor(m_settings.m_rgbColor); - applySettings(); - } - else if ((m_contextMenuType == ContextMenuStreamSettings) && (m_deviceUISet->m_deviceMIMOEngine)) - { - DeviceStreamSelectionDialog dialog(this); - dialog.setNumberOfStreams(m_localSink->getNumberOfDeviceStreams()); - dialog.setStreamIndex(m_settings.m_streamIndex); - dialog.move(p); - dialog.exec(); + if (m_deviceUISet->m_deviceMIMOEngine) + { + m_settings.m_streamIndex = dialog.getSelectedStreamIndex(); + m_channelMarker.clearStreamIndexes(); + m_channelMarker.addStreamIndex(m_settings.m_streamIndex); + updateIndexLabel(); + } - m_settings.m_streamIndex = dialog.getSelectedStreamIndex(); - m_channelMarker.clearStreamIndexes(); - m_channelMarker.addStreamIndex(m_settings.m_streamIndex); - displayStreamIndex(); applySettings(); } @@ -359,6 +371,7 @@ void LocalSinkGUI::applyPosition() m_shiftFrequencyFactor = HBFilterChainConverter::convertToString(m_settings.m_log2Decim, m_settings.m_filterChainHash, s); ui->filterChainText->setText(s); + updateAbsoluteCenterFrequency(); displayRateAndShift(); applySettings(); } @@ -369,3 +382,18 @@ void LocalSinkGUI::tick() m_tickCount = 0; } } + +void LocalSinkGUI::makeUIConnections() +{ + QObject::connect(ui->decimationFactor, QOverload::of(&QComboBox::currentIndexChanged), this, &LocalSinkGUI::on_decimationFactor_currentIndexChanged); + QObject::connect(ui->position, &QSlider::valueChanged, this, &LocalSinkGUI::on_position_valueChanged); + QObject::connect(ui->localDevice, QOverload::of(&QComboBox::currentIndexChanged), this, &LocalSinkGUI::on_localDevice_currentIndexChanged); + QObject::connect(ui->localDevicesRefresh, &QPushButton::clicked, this, &LocalSinkGUI::on_localDevicesRefresh_clicked); + QObject::connect(ui->localDevicePlay, &ButtonSwitch::toggled, this, &LocalSinkGUI::on_localDevicePlay_toggled); +} + +void LocalSinkGUI::updateAbsoluteCenterFrequency() +{ + int shift = m_shiftFrequencyFactor * m_basebandSampleRate; + setStatusFrequency(m_deviceCenterFrequency + shift); +} diff --git a/plugins/channelrx/localsink/localsinkgui.h b/plugins/channelrx/localsink/localsinkgui.h index 07f6c8c09..201615245 100644 --- a/plugins/channelrx/localsink/localsinkgui.h +++ b/plugins/channelrx/localsink/localsinkgui.h @@ -48,6 +48,20 @@ public: QByteArray serialize() const; bool deserialize(const QByteArray& data); virtual MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; } + virtual void setWorkspaceIndex(int index) { m_settings.m_workspaceIndex = index; }; + virtual int getWorkspaceIndex() const { return m_settings.m_workspaceIndex; }; + virtual void setGeometryBytes(const QByteArray& blob) { m_settings.m_geometryBytes = blob; }; + virtual QByteArray getGeometryBytes() const { return m_settings.m_geometryBytes; }; + virtual QString getTitle() const { return m_settings.m_title; }; + virtual QColor getTitleColor() const { return m_settings.m_rgbColor; }; + virtual void zetHidden(bool hidden) { m_settings.m_hidden = hidden; } + virtual bool getHidden() const { return m_settings.m_hidden; } + virtual ChannelMarker& getChannelMarker() { return m_channelMarker; } + virtual int getStreamIndex() const { return m_settings.m_streamIndex; } + virtual void setStreamIndex(int streamIndex) { m_settings.m_streamIndex = streamIndex; } + +protected: + void resizeEvent(QResizeEvent* size); private: Ui::LocalSinkGUI* ui; @@ -56,6 +70,7 @@ private: ChannelMarker m_channelMarker; RollupState m_rollupState; LocalSinkSettings m_settings; + qint64 m_deviceCenterFrequency; int m_basebandSampleRate; double m_shiftFrequencyFactor; //!< Channel frequency shift factor bool m_doApplySettings; @@ -71,11 +86,12 @@ private: void blockApplySettings(bool block); void applySettings(bool force = false); void displaySettings(); - void displayStreamIndex(); void displayRateAndShift(); void updateLocalDevices(); int getLocalDeviceIndexInCombo(int localDeviceIndex); bool handleMessage(const Message& message); + void makeUIConnections(); + void updateAbsoluteCenterFrequency(); void leaveEvent(QEvent*); void enterEvent(QEvent*); diff --git a/plugins/channelrx/localsink/localsinkgui.ui b/plugins/channelrx/localsink/localsinkgui.ui index 25ed63a74..8ebd37b1b 100644 --- a/plugins/channelrx/localsink/localsinkgui.ui +++ b/plugins/channelrx/localsink/localsinkgui.ui @@ -1,7 +1,7 @@ LocalSinkGUI - + 0 @@ -11,7 +11,7 @@ - + 0 0 @@ -24,7 +24,7 @@ - 320 + 560 16777215 @@ -330,9 +330,9 @@ - RollupWidget + RollupContents QWidget -
gui/rollupwidget.h
+
gui/rollupcontents.h
1
diff --git a/plugins/channelrx/localsink/localsinksettings.cpp b/plugins/channelrx/localsink/localsinksettings.cpp index dfa674910..ecf2f9a48 100644 --- a/plugins/channelrx/localsink/localsinksettings.cpp +++ b/plugins/channelrx/localsink/localsinksettings.cpp @@ -44,6 +44,8 @@ void LocalSinkSettings::resetToDefaults() m_reverseAPIPort = 8888; m_reverseAPIDeviceIndex = 0; m_reverseAPIChannelIndex = 0; + m_workspaceIndex = 0; + m_hidden = false; } QByteArray LocalSinkSettings::serialize() const @@ -70,6 +72,10 @@ QByteArray LocalSinkSettings::serialize() const s.writeBlob(15, m_rollupState->serialize()); } + s.writeS32(16, m_workspaceIndex); + s.writeBlob(17, m_geometryBytes); + s.writeBool(18, m_hidden); + return s.final(); } @@ -124,6 +130,10 @@ bool LocalSinkSettings::deserialize(const QByteArray& data) m_rollupState->deserialize(bytetmp); } + d.readS32(16, &m_workspaceIndex, 0); + d.readBlob(17, &m_geometryBytes); + d.readBool(18, &m_hidden, false); + return true; } else diff --git a/plugins/channelrx/localsink/localsinksettings.h b/plugins/channelrx/localsink/localsinksettings.h index 02b9cf680..48a52beaa 100644 --- a/plugins/channelrx/localsink/localsinksettings.h +++ b/plugins/channelrx/localsink/localsinksettings.h @@ -37,6 +37,9 @@ struct LocalSinkSettings uint16_t m_reverseAPIPort; uint16_t m_reverseAPIDeviceIndex; uint16_t m_reverseAPIChannelIndex; + int m_workspaceIndex; + QByteArray m_geometryBytes; + bool m_hidden; Serializable *m_channelMarker; Serializable *m_rollupState; diff --git a/plugins/channelrx/localsink/readme.md b/plugins/channelrx/localsink/readme.md index 9a161ef75..498cd2d75 100644 --- a/plugins/channelrx/localsink/readme.md +++ b/plugins/channelrx/localsink/readme.md @@ -16,6 +16,8 @@ Note that because it uses only the channelizer half band filter chain to achieve

Interface

+The top and bottom bars of the channel window are described [here](../../../sdrgui/channel/readme.md) + ![Local sink channel plugin GUI](../../../doc/img/LocalSink.png)

1: Decimation factor

diff --git a/plugins/channelrx/noisefigure/noisefigure.cpp b/plugins/channelrx/noisefigure/noisefigure.cpp index 4c6851bf0..c5aa2a23f 100644 --- a/plugins/channelrx/noisefigure/noisefigure.cpp +++ b/plugins/channelrx/noisefigure/noisefigure.cpp @@ -31,6 +31,7 @@ #include #include "SWGChannelSettings.h" +#include "SWGWorkspaceInfo.h" #include "SWGChannelReport.h" #include "dsp/dspengine.h" @@ -110,6 +111,18 @@ NoiseFigure::~NoiseFigure() delete m_basebandSink; } +void NoiseFigure::setDeviceAPI(DeviceAPI *deviceAPI) +{ + if (deviceAPI != m_deviceAPI) + { + m_deviceAPI->removeChannelSinkAPI(this); + m_deviceAPI->removeChannelSink(this); + m_deviceAPI = deviceAPI; + m_deviceAPI->addChannelSink(this); + m_deviceAPI->addChannelSinkAPI(this); + } +} + uint32_t NoiseFigure::getNumberOfDeviceStreams() const { return m_deviceAPI->getNbSourceStreams(); @@ -445,10 +458,8 @@ bool NoiseFigure::handleMessage(const Message& cmd) qDebug() << "NoiseFigure::handleMessage: DSPSignalNotification"; m_basebandSink->getInputMessageQueue()->push(rep); // Forward to GUI if any - if (m_guiMessageQueue) - { - rep = new DSPSignalNotification(notif); - m_guiMessageQueue->push(rep); + if (m_guiMessageQueue) { + m_guiMessageQueue->push(new DSPSignalNotification(notif)); } return true; @@ -598,6 +609,15 @@ int NoiseFigure::webapiSettingsGet( return 200; } +int NoiseFigure::webapiWorkspaceGet( + SWGSDRangel::SWGWorkspaceInfo& response, + QString& errorMessage) +{ + (void) errorMessage; + response.setIndex(m_settings.m_workspaceIndex); + return 200; +} + int NoiseFigure::webapiSettingsPutPatch( bool force, const QStringList& channelSettingsKeys, diff --git a/plugins/channelrx/noisefigure/noisefigure.h b/plugins/channelrx/noisefigure/noisefigure.h index 65cbb3c41..57f042ba8 100644 --- a/plugins/channelrx/noisefigure/noisefigure.h +++ b/plugins/channelrx/noisefigure/noisefigure.h @@ -172,6 +172,8 @@ public: NoiseFigure(DeviceAPI *deviceAPI); virtual ~NoiseFigure(); virtual void destroy() { delete this; } + virtual void setDeviceAPI(DeviceAPI *deviceAPI); + virtual DeviceAPI *getDeviceAPI() { return m_deviceAPI; } using BasebandSampleSink::feed; virtual void feed(const SampleVector::const_iterator& begin, const SampleVector::const_iterator& end, bool po); @@ -204,6 +206,10 @@ public: SWGSDRangel::SWGChannelSettings& response, QString& errorMessage); + virtual int webapiWorkspaceGet( + SWGSDRangel::SWGWorkspaceInfo& response, + QString& errorMessage); + virtual int webapiSettingsPutPatch( bool force, const QStringList& channelSettingsKeys, diff --git a/plugins/channelrx/noisefigure/noisefiguregui.cpp b/plugins/channelrx/noisefigure/noisefiguregui.cpp index 81235801a..703f69ebc 100644 --- a/plugins/channelrx/noisefigure/noisefiguregui.cpp +++ b/plugins/channelrx/noisefigure/noisefiguregui.cpp @@ -269,7 +269,11 @@ bool NoiseFigureGUI::handleMessage(const Message& message) else if (DSPSignalNotification::match(message)) { DSPSignalNotification& notif = (DSPSignalNotification&) message; + m_deviceCenterFrequency = notif.getSampleRate(); m_basebandSampleRate = notif.getSampleRate(); + ui->deltaFrequency->setValueRange(false, 7, -m_basebandSampleRate/2, m_basebandSampleRate/2); + ui->deltaFrequencyLabel->setToolTip(tr("Range %1 %L2 Hz").arg(QChar(0xB1)).arg(m_basebandSampleRate/2)); + updateAbsoluteCenterFrequency(); updateBW(); return true; } @@ -323,6 +327,7 @@ void NoiseFigureGUI::on_deltaFrequency_changed(qint64 value) { m_channelMarker.setCenterFrequency(value); m_settings.m_inputFrequencyOffset = m_channelMarker.getCenterFrequency(); + updateAbsoluteCenterFrequency(); applySettings(); } @@ -532,7 +537,18 @@ void NoiseFigureGUI::onWidgetRolled(QWidget* widget, bool rollDown) (void) widget; (void) rollDown; - saveState(m_rollupState); + RollupContents *rollupContents = getRollupContents(); + + if (rollupContents->hasExpandableWidgets()) { + setSizePolicy(sizePolicy().horizontalPolicy(), QSizePolicy::Expanding); + } else { + setSizePolicy(sizePolicy().horizontalPolicy(), QSizePolicy::Fixed); + } + + int h = rollupContents->height() + getAdditionalHeight(); + resize(width(), h); + + rollupContents->saveState(m_rollupState); applySettings(); } @@ -546,6 +562,14 @@ void NoiseFigureGUI::onMenuDialogCalled(const QPoint &p) dialog.setReverseAPIPort(m_settings.m_reverseAPIPort); dialog.setReverseAPIDeviceIndex(m_settings.m_reverseAPIDeviceIndex); dialog.setReverseAPIChannelIndex(m_settings.m_reverseAPIChannelIndex); + dialog.setDefaultTitle(m_displayedName); + + if (m_deviceUISet->m_deviceMIMOEngine) + { + dialog.setNumberOfStreams(m_noiseFigure->getNumberOfDeviceStreams()); + dialog.setStreamIndex(m_settings.m_streamIndex); + } + dialog.move(p); dialog.exec(); @@ -558,22 +582,17 @@ void NoiseFigureGUI::onMenuDialogCalled(const QPoint &p) m_settings.m_reverseAPIChannelIndex = dialog.getReverseAPIChannelIndex(); setWindowTitle(m_settings.m_title); + setTitle(m_channelMarker.getTitle()); setTitleColor(m_settings.m_rgbColor); - applySettings(); - } - else if ((m_contextMenuType == ContextMenuStreamSettings) && (m_deviceUISet->m_deviceMIMOEngine)) - { - DeviceStreamSelectionDialog dialog(this); - dialog.setNumberOfStreams(m_noiseFigure->getNumberOfDeviceStreams()); - dialog.setStreamIndex(m_settings.m_streamIndex); - dialog.move(p); - dialog.exec(); + if (m_deviceUISet->m_deviceMIMOEngine) + { + m_settings.m_streamIndex = dialog.getSelectedStreamIndex(); + m_channelMarker.clearStreamIndexes(); + m_channelMarker.addStreamIndex(m_settings.m_streamIndex); + updateIndexLabel(); + } - m_settings.m_streamIndex = dialog.getSelectedStreamIndex(); - m_channelMarker.clearStreamIndexes(); - m_channelMarker.addStreamIndex(m_settings.m_streamIndex); - displayStreamIndex(); applySettings(); } @@ -586,17 +605,20 @@ NoiseFigureGUI::NoiseFigureGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, B m_pluginAPI(pluginAPI), m_deviceUISet(deviceUISet), m_channelMarker(this), + m_deviceCenterFrequency(0), m_doApplySettings(true), m_basebandSampleRate(1000000), m_tickCount(0), m_runningTest(false), m_chart(nullptr) { - ui->setupUi(this); - m_helpURL = "plugins/channelrx/noisefigure/readme.md"; - setAttribute(Qt::WA_DeleteOnClose, true); - connect(this, SIGNAL(widgetRolled(QWidget*,bool)), this, SLOT(onWidgetRolled(QWidget*,bool))); + m_helpURL = "plugins/channelrx/noisefigure/readme.md"; + RollupContents *rollupContents = getRollupContents(); + ui->setupUi(rollupContents); + setSizePolicy(rollupContents->sizePolicy()); + rollupContents->arrangeRollups(); + connect(rollupContents, SIGNAL(widgetRolled(QWidget*,bool)), this, SLOT(onWidgetRolled(QWidget*,bool))); connect(this, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(onMenuDialogCalled(const QPoint &))); m_noiseFigure = reinterpret_cast(rxChannel); @@ -622,7 +644,6 @@ NoiseFigureGUI::NoiseFigureGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, B m_settings.setRollupState(&m_rollupState); m_deviceUISet->addChannelMarker(&m_channelMarker); - m_deviceUISet->addRollupWidget(this); connect(&m_channelMarker, SIGNAL(changedByCursor()), this, SLOT(channelMarkerChangedByCursor())); connect(&m_channelMarker, SIGNAL(highlightedByCursor()), this, SLOT(channelMarkerHighlightedByCursor())); @@ -656,6 +677,7 @@ NoiseFigureGUI::NoiseFigureGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, B ui->results->setItemDelegateForColumn(RESULTS_COL_FLOOR, new DecimalDelegate(1)); displaySettings(); + makeUIConnections(); applySettings(true); } @@ -706,6 +728,7 @@ void NoiseFigureGUI::displaySettings() setTitleColor(m_settings.m_rgbColor); setWindowTitle(m_channelMarker.getTitle()); + setTitle(m_channelMarker.getTitle()); blockApplySettings(true); @@ -727,7 +750,7 @@ void NoiseFigureGUI::displaySettings() ui->fftSize->setCurrentIndex(log2(m_settings.m_fftSize) - 6); updateBW(); - displayStreamIndex(); + updateIndexLabel(); // Order and size columns QHeaderView *header = ui->results->horizontalHeader(); @@ -742,27 +765,21 @@ void NoiseFigureGUI::displaySettings() header->moveSection(header->visualIndex(i), m_settings.m_resultsColumnIndexes[i]); } - restoreState(m_rollupState); + getRollupContents()->restoreState(m_rollupState); + updateAbsoluteCenterFrequency(); blockApplySettings(false); } -void NoiseFigureGUI::displayStreamIndex() -{ - if (m_deviceUISet->m_deviceMIMOEngine) { - setStreamIndicator(tr("%1").arg(m_settings.m_streamIndex)); - } else { - setStreamIndicator("S"); // single channel indicator - } -} - -void NoiseFigureGUI::leaveEvent(QEvent*) +void NoiseFigureGUI::leaveEvent(QEvent* event) { m_channelMarker.setHighlighted(false); + ChannelGUI::leaveEvent(event); } -void NoiseFigureGUI::enterEvent(QEvent*) +void NoiseFigureGUI::enterEvent(QEvent* event) { m_channelMarker.setHighlighted(true); + ChannelGUI::enterEvent(event); } void NoiseFigureGUI::tick() @@ -784,3 +801,30 @@ void NoiseFigureGUI::tick() m_tickCount++; } + +void NoiseFigureGUI::makeUIConnections() +{ + QObject::connect(ui->deltaFrequency, &ValueDialZ::changed, this, &NoiseFigureGUI::on_deltaFrequency_changed); + QObject::connect(ui->fftCount, &QSlider::valueChanged, this, &NoiseFigureGUI::on_fftCount_valueChanged); + QObject::connect(ui->setting, &QComboBox::currentTextChanged, this, &NoiseFigureGUI::on_setting_currentTextChanged); + QObject::connect(ui->frequencySpec, QOverload::of(&QComboBox::currentIndexChanged), this, &NoiseFigureGUI::on_frequencySpec_currentIndexChanged); + QObject::connect(ui->start, QOverload::of(&QDoubleSpinBox::valueChanged), this, &NoiseFigureGUI::on_start_valueChanged); + QObject::connect(ui->stop, QOverload::of(&QDoubleSpinBox::valueChanged), this, &NoiseFigureGUI::on_stop_valueChanged); + QObject::connect(ui->steps, QOverload::of(&QSpinBox::valueChanged), this, &NoiseFigureGUI::on_steps_valueChanged); + QObject::connect(ui->step, QOverload::of(&QDoubleSpinBox::valueChanged), this, &NoiseFigureGUI::on_step_valueChanged); + QObject::connect(ui->list, &QLineEdit::editingFinished, this, &NoiseFigureGUI::on_list_editingFinished); + QObject::connect(ui->fftSize, QOverload::of(&QComboBox::currentIndexChanged), this, &NoiseFigureGUI::on_fftSize_currentIndexChanged); + QObject::connect(ui->startStop, &ButtonSwitch::clicked, this, &NoiseFigureGUI::on_startStop_clicked); + QObject::connect(ui->saveResults, &QToolButton::clicked, this, &NoiseFigureGUI::on_saveResults_clicked); + QObject::connect(ui->clearResults, &QToolButton::clicked, this, &NoiseFigureGUI::on_clearResults_clicked); + QObject::connect(ui->enr, &QToolButton::clicked, this, &NoiseFigureGUI::on_enr_clicked); + QObject::connect(ui->control, &QToolButton::clicked, this, &NoiseFigureGUI::on_control_clicked); + QObject::connect(ui->chartSelect, QOverload::of(&QComboBox::currentIndexChanged), this, &NoiseFigureGUI::on_chartSelect_currentIndexChanged); + QObject::connect(ui->openReference, &QToolButton::clicked, this, &NoiseFigureGUI::on_openReference_clicked); + QObject::connect(ui->clearReference, &QToolButton::clicked, this, &NoiseFigureGUI::on_clearReference_clicked); +} + +void NoiseFigureGUI::updateAbsoluteCenterFrequency() +{ + setStatusFrequency(m_deviceCenterFrequency + m_settings.m_inputFrequencyOffset); +} diff --git a/plugins/channelrx/noisefigure/noisefiguregui.h b/plugins/channelrx/noisefigure/noisefiguregui.h index 9d2e9ad8c..100350faa 100644 --- a/plugins/channelrx/noisefigure/noisefiguregui.h +++ b/plugins/channelrx/noisefigure/noisefiguregui.h @@ -55,6 +55,17 @@ public: QByteArray serialize() const; bool deserialize(const QByteArray& data); virtual MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; } + virtual void setWorkspaceIndex(int index) { m_settings.m_workspaceIndex = index; }; + virtual int getWorkspaceIndex() const { return m_settings.m_workspaceIndex; }; + virtual void setGeometryBytes(const QByteArray& blob) { m_settings.m_geometryBytes = blob; }; + virtual QByteArray getGeometryBytes() const { return m_settings.m_geometryBytes; }; + virtual QString getTitle() const { return m_settings.m_title; }; + virtual QColor getTitleColor() const { return m_settings.m_rgbColor; }; + virtual void zetHidden(bool hidden) { m_settings.m_hidden = hidden; } + virtual bool getHidden() const { return m_settings.m_hidden; } + virtual ChannelMarker& getChannelMarker() { return m_channelMarker; } + virtual int getStreamIndex() const { return m_settings.m_streamIndex; } + virtual void setStreamIndex(int streamIndex) { m_settings.m_streamIndex = streamIndex; } public slots: void channelMarkerChangedByCursor(); @@ -67,6 +78,7 @@ private: ChannelMarker m_channelMarker; RollupState m_rollupState; NoiseFigureSettings m_settings; + qint64 m_deviceCenterFrequency; bool m_doApplySettings; NoiseFigure* m_noiseFigure; @@ -90,8 +102,9 @@ private: void blockApplySettings(bool block); void applySettings(bool force = false); void displaySettings(); - void displayStreamIndex(); bool handleMessage(const Message& message); + void makeUIConnections(); + void updateAbsoluteCenterFrequency(); void leaveEvent(QEvent*); void enterEvent(QEvent*); diff --git a/plugins/channelrx/noisefigure/noisefiguregui.ui b/plugins/channelrx/noisefigure/noisefiguregui.ui index 7125e60f0..eee1aab46 100644 --- a/plugins/channelrx/noisefigure/noisefiguregui.ui +++ b/plugins/channelrx/noisefigure/noisefiguregui.ui @@ -1,7 +1,7 @@ NoiseFigureGUI - + 0 @@ -890,9 +890,9 @@ - RollupWidget + RollupContents QWidget -
gui/rollupwidget.h
+
gui/rollupcontents.h
1
diff --git a/plugins/channelrx/noisefigure/noisefiguresettings.cpp b/plugins/channelrx/noisefigure/noisefiguresettings.cpp index 53f2b36a1..27dccc40f 100644 --- a/plugins/channelrx/noisefigure/noisefiguresettings.cpp +++ b/plugins/channelrx/noisefigure/noisefiguresettings.cpp @@ -65,6 +65,8 @@ void NoiseFigureSettings::resetToDefaults() m_reverseAPIPort = 8888; m_reverseAPIDeviceIndex = 0; m_reverseAPIChannelIndex = 0; + m_workspaceIndex = 0; + m_hidden = false; for (int i = 0; i < NOISEFIGURE_COLUMNS; i++) { @@ -117,6 +119,10 @@ QByteArray NoiseFigureSettings::serialize() const s.writeBlob(28, m_rollupState->serialize()); } + s.writeS32(29, m_workspaceIndex); + s.writeBlob(30, m_geometryBytes); + s.writeBool(31, m_hidden); + for (int i = 0; i < NOISEFIGURE_COLUMNS; i++) { s.writeS32(100 + i, m_resultsColumnIndexes[i]); } @@ -197,6 +203,10 @@ bool NoiseFigureSettings::deserialize(const QByteArray& data) m_rollupState->deserialize(bytetmp); } + d.readS32(29, &m_workspaceIndex, 0); + d.readBlob(30, &m_geometryBytes); + d.readBool(31, &m_hidden, false); + for (int i = 0; i < NOISEFIGURE_COLUMNS; i++) { d.readS32(100 + i, &m_resultsColumnIndexes[i], i); } diff --git a/plugins/channelrx/noisefigure/noisefiguresettings.h b/plugins/channelrx/noisefigure/noisefiguresettings.h index 8ad3dbdd4..a57b444f7 100644 --- a/plugins/channelrx/noisefigure/noisefiguresettings.h +++ b/plugins/channelrx/noisefigure/noisefiguresettings.h @@ -86,6 +86,9 @@ struct NoiseFigureSettings uint16_t m_reverseAPIDeviceIndex; uint16_t m_reverseAPIChannelIndex; Serializable *m_rollupState; + int m_workspaceIndex; + QByteArray m_geometryBytes; + bool m_hidden; int m_resultsColumnIndexes[NOISEFIGURE_COLUMNS];//!< How the columns are ordered in the table int m_resultsColumnSizes[NOISEFIGURE_COLUMNS]; //!< Size of the columns in the table diff --git a/plugins/channelrx/noisefigure/readme.md b/plugins/channelrx/noisefigure/readme.md index b204906e6..1bfb50e03 100644 --- a/plugins/channelrx/noisefigure/readme.md +++ b/plugins/channelrx/noisefigure/readme.md @@ -10,6 +10,8 @@ The noise figure will vary with frequency and gain settings. Typically, the nois

Interface

+The top and bottom bars of the channel window are described [here](../../../sdrgui/channel/readme.md) + ![Noise figure plugin GUI](../../../doc/img/NoiseFigure_plugin.png)

1: Measurement frequency shift from center

diff --git a/plugins/channelrx/radioastronomy/radioastronomy.cpp b/plugins/channelrx/radioastronomy/radioastronomy.cpp index cf06ca0dd..9b0ad59c2 100644 --- a/plugins/channelrx/radioastronomy/radioastronomy.cpp +++ b/plugins/channelrx/radioastronomy/radioastronomy.cpp @@ -31,6 +31,7 @@ #include #include "SWGChannelSettings.h" +#include "SWGWorkspaceInfo.h" #include "SWGChannelReport.h" #include "SWGChannelActions.h" #include "SWGRadioAstronomyActions.h" @@ -154,6 +155,18 @@ RadioAstronomy::~RadioAstronomy() delete m_worker; } +void RadioAstronomy::setDeviceAPI(DeviceAPI *deviceAPI) +{ + if (deviceAPI != m_deviceAPI) + { + m_deviceAPI->removeChannelSinkAPI(this); + m_deviceAPI->removeChannelSink(this); + m_deviceAPI = deviceAPI; + m_deviceAPI->addChannelSink(this); + m_deviceAPI->addChannelSinkAPI(this); + } +} + uint32_t RadioAstronomy::getNumberOfDeviceStreams() const { return m_deviceAPI->getNbSourceStreams(); @@ -828,6 +841,15 @@ int RadioAstronomy::webapiSettingsGet( return 200; } +int RadioAstronomy::webapiWorkspaceGet( + SWGSDRangel::SWGWorkspaceInfo& response, + QString& errorMessage) +{ + (void) errorMessage; + response.setIndex(m_settings.m_workspaceIndex); + return 200; +} + int RadioAstronomy::webapiSettingsPutPatch( bool force, const QStringList& channelSettingsKeys, diff --git a/plugins/channelrx/radioastronomy/radioastronomy.h b/plugins/channelrx/radioastronomy/radioastronomy.h index 59b3a1420..7a2e5ac93 100644 --- a/plugins/channelrx/radioastronomy/radioastronomy.h +++ b/plugins/channelrx/radioastronomy/radioastronomy.h @@ -346,6 +346,8 @@ public: RadioAstronomy(DeviceAPI *deviceAPI); virtual ~RadioAstronomy(); virtual void destroy() { delete this; } + virtual void setDeviceAPI(DeviceAPI *deviceAPI); + virtual DeviceAPI *getDeviceAPI() { return m_deviceAPI; } using BasebandSampleSink::feed; virtual void feed(const SampleVector::const_iterator& begin, const SampleVector::const_iterator& end, bool po); @@ -378,6 +380,10 @@ public: SWGSDRangel::SWGChannelSettings& response, QString& errorMessage) override; + virtual int webapiWorkspaceGet( + SWGSDRangel::SWGWorkspaceInfo& response, + QString& errorMessage); + virtual int webapiSettingsPutPatch( bool force, const QStringList& channelSettingsKeys, diff --git a/plugins/channelrx/radioastronomy/radioastronomygui.cpp b/plugins/channelrx/radioastronomy/radioastronomygui.cpp index 13de963f1..77070dd1a 100644 --- a/plugins/channelrx/radioastronomy/radioastronomygui.cpp +++ b/plugins/channelrx/radioastronomy/radioastronomygui.cpp @@ -973,10 +973,16 @@ bool RadioAstronomyGUI::handleMessage(const Message& message) DSPSignalNotification& notif = (DSPSignalNotification&) message; m_basebandSampleRate = notif.getSampleRate(); m_centerFrequency = notif.getCenterFrequency(); + ui->deltaFrequency->setValueRange(false, 7, -m_basebandSampleRate/2, m_basebandSampleRate/2); + ui->deltaFrequencyLabel->setToolTip(tr("Range %1 %L2 Hz").arg(QChar(0xB1)).arg(m_basebandSampleRate/2)); + updateAbsoluteCenterFrequency(); + if (m_settings.m_tempGalLink) { calcGalacticBackgroundTemp(); } + updateTSys0(); + return true; } else if (RadioAstronomy::MsgReportAvailableFeatures::match(message)) @@ -1199,6 +1205,7 @@ void RadioAstronomyGUI::on_deltaFrequency_changed(qint64 value) { m_channelMarker.setCenterFrequency(value); m_settings.m_inputFrequencyOffset = m_channelMarker.getCenterFrequency(); + updateAbsoluteCenterFrequency(); applySettings(); } @@ -1942,7 +1949,18 @@ void RadioAstronomyGUI::onWidgetRolled(QWidget* widget, bool rollDown) (void) widget; (void) rollDown; - saveState(m_rollupState); + RollupContents *rollupContents = getRollupContents(); + + if (rollupContents->hasExpandableWidgets()) { + setSizePolicy(sizePolicy().horizontalPolicy(), QSizePolicy::Expanding); + } else { + setSizePolicy(sizePolicy().horizontalPolicy(), QSizePolicy::Fixed); + } + + int h = rollupContents->height() + getAdditionalHeight(); + resize(width(), h); + + rollupContents->saveState(m_rollupState); applySettings(); } @@ -1956,6 +1974,14 @@ void RadioAstronomyGUI::onMenuDialogCalled(const QPoint &p) dialog.setReverseAPIPort(m_settings.m_reverseAPIPort); dialog.setReverseAPIDeviceIndex(m_settings.m_reverseAPIDeviceIndex); dialog.setReverseAPIChannelIndex(m_settings.m_reverseAPIChannelIndex); + dialog.setDefaultTitle(m_displayedName); + + if (m_deviceUISet->m_deviceMIMOEngine) + { + dialog.setNumberOfStreams(m_radioAstronomy->getNumberOfDeviceStreams()); + dialog.setStreamIndex(m_settings.m_streamIndex); + } + dialog.move(p); dialog.exec(); @@ -1968,22 +1994,17 @@ void RadioAstronomyGUI::onMenuDialogCalled(const QPoint &p) m_settings.m_reverseAPIChannelIndex = dialog.getReverseAPIChannelIndex(); setWindowTitle(m_settings.m_title); + setTitle(m_channelMarker.getTitle()); setTitleColor(m_settings.m_rgbColor); - applySettings(); - } - else if ((m_contextMenuType == ContextMenuStreamSettings) && (m_deviceUISet->m_deviceMIMOEngine)) - { - DeviceStreamSelectionDialog dialog(this); - dialog.setNumberOfStreams(m_radioAstronomy->getNumberOfDeviceStreams()); - dialog.setStreamIndex(m_settings.m_streamIndex); - dialog.move(p); - dialog.exec(); + if (m_deviceUISet->m_deviceMIMOEngine) + { + m_settings.m_streamIndex = dialog.getSelectedStreamIndex(); + m_channelMarker.clearStreamIndexes(); + m_channelMarker.addStreamIndex(m_settings.m_streamIndex); + updateIndexLabel(); + } - m_settings.m_streamIndex = dialog.getSelectedStreamIndex(); - m_channelMarker.clearStreamIndexes(); - m_channelMarker.addStreamIndex(m_settings.m_streamIndex); - displayStreamIndex(); applySettings(); } @@ -1996,6 +2017,7 @@ RadioAstronomyGUI::RadioAstronomyGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUI m_pluginAPI(pluginAPI), m_deviceUISet(deviceUISet), m_channelMarker(this), + m_deviceCenterFrequency(0), m_doApplySettings(true), m_basebandSampleRate(0), m_centerFrequency(0), @@ -2052,10 +2074,13 @@ RadioAstronomyGUI::RadioAstronomyGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUI m_downloadingLAB(false) { qDebug("RadioAstronomyGUI::RadioAstronomyGUI"); - ui->setupUi(this); - setAttribute(Qt::WA_DeleteOnClose, true); - connect(this, SIGNAL(widgetRolled(QWidget*,bool)), this, SLOT(onWidgetRolled(QWidget*,bool))); + m_helpURL = "plugins/channelrx/radioastronomy/readme.md"; + RollupContents *rollupContents = getRollupContents(); + ui->setupUi(rollupContents); + setSizePolicy(rollupContents->sizePolicy()); + rollupContents->arrangeRollups(); + connect(rollupContents, SIGNAL(widgetRolled(QWidget*,bool)), this, SLOT(onWidgetRolled(QWidget*,bool))); connect(this, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(onMenuDialogCalled(const QPoint &))); m_radioAstronomy = reinterpret_cast(rxChannel); @@ -2102,7 +2127,6 @@ RadioAstronomyGUI::RadioAstronomyGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUI m_settings.setRollupState(&m_rollupState); m_deviceUISet->addChannelMarker(&m_channelMarker); - m_deviceUISet->addRollupWidget(this); connect(&m_channelMarker, SIGNAL(changedByCursor()), this, SLOT(channelMarkerChangedByCursor())); connect(&m_channelMarker, SIGNAL(highlightedByCursor()), this, SLOT(channelMarkerHighlightedByCursor())); @@ -2217,6 +2241,7 @@ RadioAstronomyGUI::RadioAstronomyGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUI ui->startStop->setStyleSheet("QToolButton { background-color : blue; }"); displaySettings(); + makeUIConnections(); applySettings(true); create2DImage(); @@ -2354,6 +2379,7 @@ void RadioAstronomyGUI::displaySettings() setTitleColor(m_settings.m_rgbColor); setWindowTitle(m_channelMarker.getTitle()); + setTitle(m_channelMarker.getTitle()); blockApplySettings(true); ui->deltaFrequency->setValue(m_channelMarker.getCenterFrequency()); @@ -2536,7 +2562,7 @@ void RadioAstronomyGUI::displaySettings() ui->sweep2Delay->setValue(m_settings.m_sweep2Delay); displayRunModeSettings(); - displayStreamIndex(); + updateIndexLabel(); // Order and size columns QHeaderView *header = ui->powerTable->horizontalHeader(); @@ -2550,28 +2576,22 @@ void RadioAstronomyGUI::displaySettings() header->moveSection(header->visualIndex(i), m_settings.m_powerTableColumnIndexes[i]); } - restoreState(m_rollupState); + getRollupContents()->restoreState(m_rollupState); + updateAbsoluteCenterFrequency(); blockApplySettings(false); - arrangeRollups(); + getRollupContents()->arrangeRollups(); } -void RadioAstronomyGUI::displayStreamIndex() -{ - if (m_deviceUISet->m_deviceMIMOEngine) { - setStreamIndicator(tr("%1").arg(m_settings.m_streamIndex)); - } else { - setStreamIndicator("S"); // single channel indicator - } -} - -void RadioAstronomyGUI::leaveEvent(QEvent*) +void RadioAstronomyGUI::leaveEvent(QEvent* event) { m_channelMarker.setHighlighted(false); + ChannelGUI::leaveEvent(event); } -void RadioAstronomyGUI::enterEvent(QEvent*) +void RadioAstronomyGUI::enterEvent(QEvent* event) { m_channelMarker.setHighlighted(true); + ChannelGUI::enterEvent(event); } void RadioAstronomyGUI::tick() @@ -2796,7 +2816,7 @@ void RadioAstronomyGUI::updatePowerChartWidgetsVisibility() ui->powerMarkerTableWidgets->setVisible(powerChart && (m_settings.m_powerPeaks || m_settings.m_powerMarkers)); ui->power2DScaleWidgets->setVisible(!powerChart); ui->power2DColourScaleWidgets->setVisible(!powerChart); - arrangeRollups(); + getRollupContents()->arrangeRollups(); } int RadioAstronomyGUI::powerYUnitsToIndex(RadioAstronomySettings::PowerYUnits units) @@ -2915,7 +2935,7 @@ void RadioAstronomyGUI::updateSpectrumChartWidgetsVisibility() ui->spectrumPeak->setVisible(fft); ui->saveSpectrumChartImages->setVisible(fft); - arrangeRollups(); + getRollupContents()->arrangeRollups(); } // Calulate mean, RMS and standard deviation @@ -5130,7 +5150,7 @@ void RadioAstronomyGUI::on_powerShowPeak_toggled(bool checked) m_powerChart->legend()->markers(m_powerPeakSeries)[0]->setVisible(false); } } - arrangeRollups(); + getRollupContents()->arrangeRollups(); } void RadioAstronomyGUI::on_spectrumPeak_toggled(bool checked) @@ -5148,7 +5168,7 @@ void RadioAstronomyGUI::on_spectrumPeak_toggled(bool checked) clearLoSMarker("Max"); } } - arrangeRollups(); + getRollupContents()->arrangeRollups(); } void RadioAstronomyGUI::on_powerShowMarker_toggled(bool checked) @@ -5164,7 +5184,7 @@ void RadioAstronomyGUI::on_powerShowMarker_toggled(bool checked) } } updatePowerSelect(); - arrangeRollups(); + getRollupContents()->arrangeRollups(); } void RadioAstronomyGUI::on_powerShowAvg_toggled(bool checked) @@ -5172,7 +5192,7 @@ void RadioAstronomyGUI::on_powerShowAvg_toggled(bool checked) m_settings.m_powerAvg = checked; applySettings(); ui->powerChartAvgWidgets->setVisible(checked); - arrangeRollups(); + getRollupContents()->arrangeRollups(); if (checked) { calcAverages(); } @@ -5291,7 +5311,7 @@ void RadioAstronomyGUI::on_spectrumMarker_toggled(bool checked) clearLoSMarker("M2"); } updateSpectrumSelect(); - arrangeRollups(); + getRollupContents()->arrangeRollups(); } void RadioAstronomyGUI::on_spectrumTemp_toggled(bool checked) @@ -5301,7 +5321,7 @@ void RadioAstronomyGUI::on_spectrumTemp_toggled(bool checked) ui->spectrumGaussianWidgets->setVisible(checked); m_fftGaussianSeries->setVisible(checked); updateSpectrumSelect(); - arrangeRollups(); + getRollupContents()->arrangeRollups(); } void RadioAstronomyGUI::on_spectrumShowLegend_toggled(bool checked) @@ -5326,7 +5346,7 @@ void RadioAstronomyGUI::on_spectrumShowRefLine_toggled(bool checked) m_fftDopplerAxis->setVisible(m_settings.m_spectrumRefLine); } updateDistanceColumns(); - arrangeRollups(); + getRollupContents()->arrangeRollups(); } void RadioAstronomyGUI::on_spectrumShowLAB_toggled(bool checked) @@ -5650,7 +5670,7 @@ void RadioAstronomyGUI::on_powerShowGaussian_clicked(bool checked) ui->powerGaussianWidgets->setVisible(checked); m_powerGaussianSeries->setVisible(checked); updatePowerSelect(); - arrangeRollups(); + getRollupContents()->arrangeRollups(); } void RadioAstronomyGUI::plotPowerGaussian() @@ -5896,7 +5916,7 @@ void RadioAstronomyGUI::displayRunModeSettings() ui->sweepStatus->setVisible(sweep); ui->runLayout->activate(); // Needed otherwise height of rollup doesn't seem to be reduced ui->statusLayout->activate(); // going from sweep to single/continuous - arrangeRollups(); + getRollupContents()->arrangeRollups(); } void RadioAstronomyGUI::on_runMode_currentIndexChanged(int index) @@ -5973,7 +5993,7 @@ void RadioAstronomyGUI::on_sweepStartAtTime_currentIndexChanged(int index) { m_settings.m_sweepStartAtTime = ui->sweepStartAtTime->currentIndex() == 1; ui->sweepStartDateTime->setVisible(index == 1); - arrangeRollups(); + getRollupContents()->arrangeRollups(); applySettings(); } @@ -6033,3 +6053,116 @@ void RadioAstronomyGUI::resizeEvent(QResizeEvent* size) calcSpectrumChartTickCount(m_calXAxis, width); ChannelGUI::resizeEvent(size); } + +void RadioAstronomyGUI::makeUIConnections() +{ + QObject::connect(ui->deltaFrequency, &ValueDialZ::changed, this, &RadioAstronomyGUI::on_deltaFrequency_changed); + QObject::connect(ui->sampleRate, &ValueDialZ::changed, this, &RadioAstronomyGUI::on_sampleRate_changed); + QObject::connect(ui->rfBW, &ValueDialZ::changed, this, &RadioAstronomyGUI::on_rfBW_changed); + QObject::connect(ui->integration, &ValueDialZ::changed, this, &RadioAstronomyGUI::on_integration_changed); + QObject::connect(ui->fftSize, QOverload::of(&QComboBox::currentIndexChanged), this, &RadioAstronomyGUI::on_fftSize_currentIndexChanged); + QObject::connect(ui->fftWindow, QOverload::of(&QComboBox::currentIndexChanged), this, &RadioAstronomyGUI::on_fftWindow_currentIndexChanged); + QObject::connect(ui->filterFreqs, &QLineEdit::editingFinished, this, &RadioAstronomyGUI::on_filterFreqs_editingFinished); + QObject::connect(ui->starTracker, &QComboBox::currentTextChanged, this, &RadioAstronomyGUI::on_starTracker_currentTextChanged); + QObject::connect(ui->rotator, &QComboBox::currentTextChanged, this, &RadioAstronomyGUI::on_rotator_currentTextChanged); + QObject::connect(ui->showSensors, &QToolButton::clicked, this, &RadioAstronomyGUI::on_showSensors_clicked); + QObject::connect(ui->tempRXSelect, QOverload::of(&QComboBox::currentIndexChanged), this, &RadioAstronomyGUI::on_tempRXSelect_currentIndexChanged); + QObject::connect(ui->tempRX, QOverload::of(&QDoubleSpinBox::valueChanged), this, &RadioAstronomyGUI::on_tempRX_valueChanged); + QObject::connect(ui->tempCMB, QOverload::of(&QDoubleSpinBox::valueChanged), this, &RadioAstronomyGUI::on_tempCMB_valueChanged); + QObject::connect(ui->tempGal, QOverload::of(&QDoubleSpinBox::valueChanged), this, &RadioAstronomyGUI::on_tempGal_valueChanged); + QObject::connect(ui->tempSP, QOverload::of(&QDoubleSpinBox::valueChanged), this, &RadioAstronomyGUI::on_tempSP_valueChanged); + QObject::connect(ui->tempAtm, QOverload::of(&QDoubleSpinBox::valueChanged), this, &RadioAstronomyGUI::on_tempAtm_valueChanged); + QObject::connect(ui->tempAir, QOverload::of(&QDoubleSpinBox::valueChanged), this, &RadioAstronomyGUI::on_tempAir_valueChanged); + QObject::connect(ui->zenithOpacity, QOverload::of(&QDoubleSpinBox::valueChanged), this, &RadioAstronomyGUI::on_zenithOpacity_valueChanged); + QObject::connect(ui->elevation, QOverload::of(&QDoubleSpinBox::valueChanged), this, &RadioAstronomyGUI::on_elevation_valueChanged); + QObject::connect(ui->tempAtmLink, &ButtonSwitch::toggled, this, &RadioAstronomyGUI::on_tempAtmLink_toggled); + QObject::connect(ui->tempAirLink, &ButtonSwitch::toggled, this, &RadioAstronomyGUI::on_tempAirLink_toggled); + QObject::connect(ui->tempGalLink, &ButtonSwitch::toggled, this, &RadioAstronomyGUI::on_tempGalLink_toggled); + QObject::connect(ui->elevationLink, &ButtonSwitch::toggled, this, &RadioAstronomyGUI::on_elevationLink_toggled); + QObject::connect(ui->gainVariation, QOverload::of(&QDoubleSpinBox::valueChanged), this, &RadioAstronomyGUI::on_gainVariation_valueChanged); + QObject::connect(ui->omegaAUnits, QOverload::of(&QComboBox::currentIndexChanged), this, &RadioAstronomyGUI::on_omegaAUnits_currentIndexChanged); + QObject::connect(ui->sourceType, QOverload::of(&QComboBox::currentIndexChanged), this, &RadioAstronomyGUI::on_sourceType_currentIndexChanged); + QObject::connect(ui->omegaS, QOverload::of(&QDoubleSpinBox::valueChanged), this, &RadioAstronomyGUI::on_omegaS_valueChanged); + QObject::connect(ui->omegaSUnits, QOverload::of(&QComboBox::currentIndexChanged), this, &RadioAstronomyGUI::on_omegaSUnits_currentIndexChanged); + QObject::connect(ui->spectrumChartSelect, QOverload::of(&QComboBox::currentIndexChanged), this, &RadioAstronomyGUI::on_spectrumChartSelect_currentIndexChanged); + QObject::connect(ui->showCalSettings, &QToolButton::clicked, this, &RadioAstronomyGUI::on_showCalSettings_clicked); + QObject::connect(ui->startCalHot, &QToolButton::clicked, this, &RadioAstronomyGUI::on_startCalHot_clicked); + QObject::connect(ui->startCalCold, &QToolButton::clicked, this, &RadioAstronomyGUI::on_startCalCold_clicked); + QObject::connect(ui->recalibrate, &ButtonSwitch::toggled, this, &RadioAstronomyGUI::on_recalibrate_toggled); + QObject::connect(ui->spectrumShowLegend, &ButtonSwitch::toggled, this, &RadioAstronomyGUI::on_spectrumShowLegend_toggled); + QObject::connect(ui->spectrumShowRefLine, &ButtonSwitch::toggled, this, &RadioAstronomyGUI::on_spectrumShowRefLine_toggled); + QObject::connect(ui->spectrumTemp, &ButtonSwitch::toggled, this, &RadioAstronomyGUI::on_spectrumTemp_toggled); + QObject::connect(ui->spectrumMarker, &ButtonSwitch::toggled, this, &RadioAstronomyGUI::on_spectrumMarker_toggled); + QObject::connect(ui->spectrumPeak, &ButtonSwitch::toggled, this, &RadioAstronomyGUI::on_spectrumPeak_toggled); + QObject::connect(ui->spectrumReverseXAxis, &ButtonSwitch::toggled, this, &RadioAstronomyGUI::on_spectrumReverseXAxis_toggled); + QObject::connect(ui->savePowerData, &QToolButton::clicked, this, &RadioAstronomyGUI::on_savePowerData_clicked); + QObject::connect(ui->savePowerChartImage, &QToolButton::clicked, this, &RadioAstronomyGUI::on_savePowerChartImage_clicked); + QObject::connect(ui->saveSpectrumData, &QToolButton::clicked, this, &RadioAstronomyGUI::on_saveSpectrumData_clicked); + QObject::connect(ui->loadSpectrumData, &QToolButton::clicked, this, &RadioAstronomyGUI::on_loadSpectrumData_clicked); + QObject::connect(ui->saveSpectrumChartImage, &QToolButton::clicked, this, &RadioAstronomyGUI::on_saveSpectrumChartImage_clicked); + QObject::connect(ui->saveSpectrumChartImages, &QToolButton::clicked, this, &RadioAstronomyGUI::on_saveSpectrumChartImages_clicked); + QObject::connect(ui->clearData, &QToolButton::clicked, this, &RadioAstronomyGUI::on_clearData_clicked); + QObject::connect(ui->clearCal, &QToolButton::clicked, this, &RadioAstronomyGUI::on_clearCal_clicked); + QObject::connect(ui->spectrumAutoscale, &QToolButton::toggled, this, &RadioAstronomyGUI::on_spectrumAutoscale_toggled); + QObject::connect(ui->spectrumAutoscaleX, &QToolButton::clicked, this, &RadioAstronomyGUI::on_spectrumAutoscaleX_clicked); + QObject::connect(ui->spectrumAutoscaleY, &QToolButton::clicked, this, &RadioAstronomyGUI::on_spectrumAutoscaleY_clicked); + QObject::connect(ui->spectrumReference, QOverload::of(&QDoubleSpinBox::valueChanged), this, &RadioAstronomyGUI::on_spectrumReference_valueChanged); + QObject::connect(ui->spectrumRange, QOverload::of(&QDoubleSpinBox::valueChanged), this, &RadioAstronomyGUI::on_spectrumRange_valueChanged); + QObject::connect(ui->spectrumCenterFreq, QOverload::of(&QDoubleSpinBox::valueChanged), this, &RadioAstronomyGUI::on_spectrumCenterFreq_valueChanged); + QObject::connect(ui->spectrumSpan, QOverload::of(&QDoubleSpinBox::valueChanged), this, &RadioAstronomyGUI::on_spectrumSpan_valueChanged); + QObject::connect(ui->spectrumYUnits, QOverload::of(&QComboBox::currentIndexChanged), this, &RadioAstronomyGUI::on_spectrumYUnits_currentIndexChanged); + QObject::connect(ui->spectrumBaseline, QOverload::of(&QComboBox::currentIndexChanged), this, &RadioAstronomyGUI::on_spectrumBaseline_currentIndexChanged); + QObject::connect(ui->spectrumIndex, &QSlider::valueChanged, this, &RadioAstronomyGUI::on_spectrumIndex_valueChanged); + QObject::connect(ui->spectrumLine, QOverload::of(&QComboBox::currentIndexChanged), this, &RadioAstronomyGUI::on_spectrumLine_currentIndexChanged); + QObject::connect(ui->spectrumLineFrequency, QOverload::of(&QDoubleSpinBox::valueChanged), this, &RadioAstronomyGUI::on_spectrumLineFrequency_valueChanged); + QObject::connect(ui->refFrame, QOverload::of(&QComboBox::currentIndexChanged), this, &RadioAstronomyGUI::on_refFrame_currentIndexChanged); + QObject::connect(ui->sunDistanceToGC, QOverload::of(&QDoubleSpinBox::valueChanged), this, &RadioAstronomyGUI::on_sunDistanceToGC_valueChanged); + QObject::connect(ui->sunOrbitalVelocity, QOverload::of(&QDoubleSpinBox::valueChanged), this, &RadioAstronomyGUI::on_sunOrbitalVelocity_valueChanged); + QObject::connect(ui->spectrumGaussianFreq, QOverload::of(&QDoubleSpinBox::valueChanged), this, &RadioAstronomyGUI::on_spectrumGaussianFreq_valueChanged); + QObject::connect(ui->spectrumGaussianAmp, QOverload::of(&QDoubleSpinBox::valueChanged), this, &RadioAstronomyGUI::on_spectrumGaussianAmp_valueChanged); + QObject::connect(ui->spectrumGaussianFloor, QOverload::of(&QDoubleSpinBox::valueChanged), this, &RadioAstronomyGUI::on_spectrumGaussianFloor_valueChanged); + QObject::connect(ui->spectrumGaussianFWHM, QOverload::of(&QDoubleSpinBox::valueChanged), this, &RadioAstronomyGUI::on_spectrumGaussianFWHM_valueChanged); + QObject::connect(ui->spectrumGaussianTurb, QOverload::of(&QDoubleSpinBox::valueChanged), this, &RadioAstronomyGUI::on_spectrumGaussianTurb_valueChanged); + QObject::connect(ui->spectrumTemperature, QOverload::of(&QDoubleSpinBox::valueChanged), this, &RadioAstronomyGUI::on_spectrumTemperature_valueChanged); + QObject::connect(ui->spectrumShowLAB, &ButtonSwitch::toggled, this, &RadioAstronomyGUI::on_spectrumShowLAB_toggled); + QObject::connect(ui->spectrumShowDistance, &ButtonSwitch::toggled, this, &RadioAstronomyGUI::on_spectrumShowDistance_toggled); + QObject::connect(ui->tCalHotSelect, QOverload::of(&QComboBox::currentIndexChanged), this, &RadioAstronomyGUI::on_tCalHotSelect_currentIndexChanged); + QObject::connect(ui->tCalHot, QOverload::of(&QDoubleSpinBox::valueChanged), this, &RadioAstronomyGUI::on_tCalHot_valueChanged); + QObject::connect(ui->tCalColdSelect, QOverload::of(&QComboBox::currentIndexChanged), this, &RadioAstronomyGUI::on_tCalColdSelect_currentIndexChanged); + QObject::connect(ui->tCalCold, QOverload::of(&QDoubleSpinBox::valueChanged), this, &RadioAstronomyGUI::on_tCalCold_valueChanged); + QObject::connect(ui->powerChartSelect, QOverload::of(&QComboBox::currentIndexChanged), this, &RadioAstronomyGUI::on_powerChartSelect_currentIndexChanged); + QObject::connect(ui->powerYUnits, QOverload::of(&QComboBox::currentIndexChanged), this, &RadioAstronomyGUI::on_powerYUnits_currentIndexChanged); + QObject::connect(ui->powerShowMarker, &ButtonSwitch::toggled, this, &RadioAstronomyGUI::on_powerShowMarker_toggled); + QObject::connect(ui->powerShowAirTemp, &ButtonSwitch::toggled, this, &RadioAstronomyGUI::on_powerShowAirTemp_toggled); + QObject::connect(ui->powerShowPeak, &ButtonSwitch::toggled, this, &RadioAstronomyGUI::on_powerShowPeak_toggled); + QObject::connect(ui->powerShowAvg, &ButtonSwitch::toggled, this, &RadioAstronomyGUI::on_powerShowAvg_toggled); + QObject::connect(ui->powerShowLegend, &ButtonSwitch::toggled, this, &RadioAstronomyGUI::on_powerShowLegend_toggled); + QObject::connect(ui->powerAutoscale, &QToolButton::toggled, this, &RadioAstronomyGUI::on_powerAutoscale_toggled); + QObject::connect(ui->powerAutoscaleY, &QToolButton::clicked, this, &RadioAstronomyGUI::on_powerAutoscaleY_clicked); + QObject::connect(ui->powerAutoscaleX, &QToolButton::clicked, this, &RadioAstronomyGUI::on_powerAutoscaleX_clicked); + QObject::connect(ui->powerReference, QOverload::of(&QDoubleSpinBox::valueChanged), this, &RadioAstronomyGUI::on_powerReference_valueChanged); + QObject::connect(ui->powerRange, QOverload::of(&QDoubleSpinBox::valueChanged), this, &RadioAstronomyGUI::on_powerRange_valueChanged); + QObject::connect(ui->powerStartTime, &WrappingDateTimeEdit::dateTimeChanged, this, &RadioAstronomyGUI::on_powerStartTime_dateTimeChanged); + QObject::connect(ui->powerEndTime, &WrappingDateTimeEdit::dateTimeChanged, this, &RadioAstronomyGUI::on_powerEndTime_dateTimeChanged); + QObject::connect(ui->powerShowGaussian, &ButtonSwitch::clicked, this, &RadioAstronomyGUI::on_powerShowGaussian_clicked); + QObject::connect(ui->powerGaussianCenter, &WrappingDateTimeEdit::dateTimeChanged, this, &RadioAstronomyGUI::on_powerGaussianCenter_dateTimeChanged); + QObject::connect(ui->powerGaussianAmp, QOverload::of(&QDoubleSpinBox::valueChanged), this, &RadioAstronomyGUI::on_powerGaussianAmp_valueChanged); + QObject::connect(ui->powerGaussianFloor, QOverload::of(&QDoubleSpinBox::valueChanged), this, &RadioAstronomyGUI::on_powerGaussianFloor_valueChanged); + QObject::connect(ui->powerGaussianFWHM, QOverload::of(&QDoubleSpinBox::valueChanged), this, &RadioAstronomyGUI::on_powerGaussianFWHM_valueChanged); + QObject::connect(ui->powerGaussianHPBW, QOverload::of(&QDoubleSpinBox::valueChanged), this, &RadioAstronomyGUI::on_powerGaussianHPBW_valueChanged); + QObject::connect(ui->runMode, QOverload::of(&QComboBox::currentIndexChanged), this, &RadioAstronomyGUI::on_runMode_currentIndexChanged); + QObject::connect(ui->sweepType, QOverload::of(&QComboBox::currentIndexChanged), this, &RadioAstronomyGUI::on_sweepType_currentIndexChanged); + QObject::connect(ui->startStop, &ButtonSwitch::clicked, this, &RadioAstronomyGUI::on_startStop_clicked); + QObject::connect(ui->sweepStartAtTime, QOverload::of(&QComboBox::currentIndexChanged), this, &RadioAstronomyGUI::on_sweepStartAtTime_currentIndexChanged); + QObject::connect(ui->sweepStartDateTime, &QDateTimeEdit::dateTimeChanged, this, &RadioAstronomyGUI::on_sweepStartDateTime_dateTimeChanged); + QObject::connect(ui->powerColourAutoscale, &QToolButton::toggled, this, &RadioAstronomyGUI::on_powerColourAutoscale_toggled); + QObject::connect(ui->powerColourScaleMin, QOverload::of(&QDoubleSpinBox::valueChanged), this, &RadioAstronomyGUI::on_powerColourScaleMin_valueChanged); + QObject::connect(ui->powerColourScaleMax, QOverload::of(&QDoubleSpinBox::valueChanged), this, &RadioAstronomyGUI::on_powerColourScaleMax_valueChanged); + QObject::connect(ui->powerColourPalette, QOverload::of(&QComboBox::currentIndexChanged), this, &RadioAstronomyGUI::on_powerColourPalette_currentIndexChanged); + QObject::connect(ui->powerTable, &QTableWidget::cellDoubleClicked, this, &RadioAstronomyGUI::on_powerTable_cellDoubleClicked); +} + +void RadioAstronomyGUI::updateAbsoluteCenterFrequency() +{ + setStatusFrequency(m_deviceCenterFrequency + m_settings.m_inputFrequencyOffset); +} diff --git a/plugins/channelrx/radioastronomy/radioastronomygui.h b/plugins/channelrx/radioastronomy/radioastronomygui.h index 8007378b2..b4a736ade 100644 --- a/plugins/channelrx/radioastronomy/radioastronomygui.h +++ b/plugins/channelrx/radioastronomy/radioastronomygui.h @@ -198,6 +198,17 @@ public: QByteArray serialize() const; bool deserialize(const QByteArray& data); virtual MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; } + virtual void setWorkspaceIndex(int index) { m_settings.m_workspaceIndex = index; }; + virtual int getWorkspaceIndex() const { return m_settings.m_workspaceIndex; }; + virtual void setGeometryBytes(const QByteArray& blob) { m_settings.m_geometryBytes = blob; }; + virtual QByteArray getGeometryBytes() const { return m_settings.m_geometryBytes; }; + virtual QString getTitle() const { return m_settings.m_title; }; + virtual QColor getTitleColor() const { return m_settings.m_rgbColor; }; + virtual void zetHidden(bool hidden) { m_settings.m_hidden = hidden; } + virtual bool getHidden() const { return m_settings.m_hidden; } + virtual ChannelMarker& getChannelMarker() { return m_channelMarker; } + virtual int getStreamIndex() const { return m_settings.m_streamIndex; } + virtual void setStreamIndex(int streamIndex) { m_settings.m_streamIndex = streamIndex; } public slots: void channelMarkerChangedByCursor(); @@ -210,6 +221,7 @@ private: ChannelMarker m_channelMarker; RollupState m_rollupState; RadioAstronomySettings m_settings; + qint64 m_deviceCenterFrequency; bool m_doApplySettings; QList m_availableFeatures; @@ -318,12 +330,14 @@ private: void blockApplySettings(bool block); void applySettings(bool force = false); void displaySettings(); - void displayStreamIndex(); void displaySpectrumLineFrequency(); void displayRunModeSettings(); void updateAvailableFeatures(); void updateRotatorList(const QList& rotators); bool handleMessage(const Message& message); + void makeUIConnections(); + void updateAbsoluteCenterFrequency(); + double degreesToSteradian(double deg) const; double hpbwToSteradians(double hpbw) const; double calcOmegaA() const; diff --git a/plugins/channelrx/radioastronomy/radioastronomygui.ui b/plugins/channelrx/radioastronomy/radioastronomygui.ui index ff821830a..d95f34841 100644 --- a/plugins/channelrx/radioastronomy/radioastronomygui.ui +++ b/plugins/channelrx/radioastronomy/radioastronomygui.ui @@ -1,7 +1,7 @@ RadioAstronomyGUI - + 0 @@ -5010,9 +5010,9 @@ This should be close to the expected difference in power between hot and cold ca - RollupWidget + RollupContents QWidget -
gui/rollupwidget.h
+
gui/rollupcontents.h
1
diff --git a/plugins/channelrx/radioastronomy/radioastronomysettings.cpp b/plugins/channelrx/radioastronomy/radioastronomysettings.cpp index 19c2802d2..66473becd 100644 --- a/plugins/channelrx/radioastronomy/radioastronomysettings.cpp +++ b/plugins/channelrx/radioastronomy/radioastronomysettings.cpp @@ -163,6 +163,8 @@ void RadioAstronomySettings::resetToDefaults() m_reverseAPIPort = 8888; m_reverseAPIDeviceIndex = 0; m_reverseAPIChannelIndex = 0; + m_workspaceIndex = 0; + m_hidden = false; for (int i = 0; i < RADIOASTRONOMY_POWERTABLE_COLUMNS; i++) { @@ -305,6 +307,9 @@ QByteArray RadioAstronomySettings::serialize() const s.writeU32(186, m_reverseAPIPort); s.writeU32(187, m_reverseAPIDeviceIndex); s.writeU32(188, m_reverseAPIChannelIndex); + s.writeS32(189, m_workspaceIndex); + s.writeBlob(190, m_geometryBytes); + s.writeBool(191, m_hidden); for (int i = 0; i < RADIOASTRONOMY_POWERTABLE_COLUMNS; i++) { s.writeS32(400 + i, m_powerTableColumnIndexes[i]); @@ -472,6 +477,9 @@ bool RadioAstronomySettings::deserialize(const QByteArray& data) m_reverseAPIDeviceIndex = utmp > 99 ? 99 : utmp; d.readU32(188, &utmp, 0); m_reverseAPIChannelIndex = utmp > 99 ? 99 : utmp; + d.readS32(189, &m_workspaceIndex, 0); + d.readBlob(190, &m_geometryBytes); + d.readBool(191, &m_hidden, false); for (int i = 0; i < RADIOASTRONOMY_POWERTABLE_COLUMNS; i++) { d.readS32(400 + i, &m_powerTableColumnIndexes[i], i); diff --git a/plugins/channelrx/radioastronomy/radioastronomysettings.h b/plugins/channelrx/radioastronomy/radioastronomysettings.h index 82b3b193e..f10ab2bd6 100644 --- a/plugins/channelrx/radioastronomy/radioastronomysettings.h +++ b/plugins/channelrx/radioastronomy/radioastronomysettings.h @@ -223,6 +223,9 @@ struct RadioAstronomySettings uint16_t m_reverseAPIPort; uint16_t m_reverseAPIDeviceIndex; uint16_t m_reverseAPIChannelIndex; + int m_workspaceIndex; + QByteArray m_geometryBytes; + bool m_hidden; int m_powerTableColumnIndexes[RADIOASTRONOMY_POWERTABLE_COLUMNS];//!< How the columns are ordered in the table int m_powerTableColumnSizes[RADIOASTRONOMY_POWERTABLE_COLUMNS]; //!< Size of the columns in the table diff --git a/plugins/channelrx/radioastronomy/readme.md b/plugins/channelrx/radioastronomy/readme.md index f9756d2a5..a63583f95 100644 --- a/plugins/channelrx/radioastronomy/readme.md +++ b/plugins/channelrx/radioastronomy/readme.md @@ -90,6 +90,8 @@ Where:

1: Settings

+The top and bottom bars of the channel window are described [here](../../../sdrgui/channel/readme.md) + ![Settings GUI](../../../doc/img/RadioAstronomy_Settings.png)

1.1: Frequency shift from center frequency of reception

diff --git a/plugins/channelrx/radioclock/radioclock.cpp b/plugins/channelrx/radioclock/radioclock.cpp index f4c56359d..ad93c8dac 100644 --- a/plugins/channelrx/radioclock/radioclock.cpp +++ b/plugins/channelrx/radioclock/radioclock.cpp @@ -29,6 +29,7 @@ #include #include "SWGChannelSettings.h" +#include "SWGWorkspaceInfo.h" #include "SWGChannelReport.h" #include "dsp/dspengine.h" @@ -99,6 +100,18 @@ RadioClock::~RadioClock() delete m_basebandSink; } +void RadioClock::setDeviceAPI(DeviceAPI *deviceAPI) +{ + if (deviceAPI != m_deviceAPI) + { + m_deviceAPI->removeChannelSinkAPI(this); + m_deviceAPI->removeChannelSink(this); + m_deviceAPI = deviceAPI; + m_deviceAPI->addChannelSink(this); + m_deviceAPI->addChannelSinkAPI(this); + } +} + uint32_t RadioClock::getNumberOfDeviceStreams() const { return m_deviceAPI->getNbSourceStreams(); @@ -165,6 +178,10 @@ bool RadioClock::handleMessage(const Message& cmd) DSPSignalNotification* rep = new DSPSignalNotification(notif); // make a copy qDebug() << "RadioClock::handleMessage: DSPSignalNotification"; m_basebandSink->getInputMessageQueue()->push(rep); + // Forward to GUI if any + if (getMessageQueueToGUI()) { + getMessageQueueToGUI()->push(new DSPSignalNotification(notif)); + } return true; } @@ -293,6 +310,15 @@ int RadioClock::webapiSettingsGet( return 200; } +int RadioClock::webapiWorkspaceGet( + SWGSDRangel::SWGWorkspaceInfo& response, + QString& errorMessage) +{ + (void) errorMessage; + response.setIndex(m_settings.m_workspaceIndex); + return 200; +} + int RadioClock::webapiSettingsPutPatch( bool force, const QStringList& channelSettingsKeys, diff --git a/plugins/channelrx/radioclock/radioclock.h b/plugins/channelrx/radioclock/radioclock.h index 2a8714b78..9ed1b3b50 100644 --- a/plugins/channelrx/radioclock/radioclock.h +++ b/plugins/channelrx/radioclock/radioclock.h @@ -112,6 +112,8 @@ public: RadioClock(DeviceAPI *deviceAPI); virtual ~RadioClock(); virtual void destroy() { delete this; } + virtual void setDeviceAPI(DeviceAPI *deviceAPI); + virtual DeviceAPI *getDeviceAPI() { return m_deviceAPI; } using BasebandSampleSink::feed; virtual void feed(const SampleVector::const_iterator& begin, const SampleVector::const_iterator& end, bool po); @@ -144,6 +146,10 @@ public: SWGSDRangel::SWGChannelSettings& response, QString& errorMessage); + virtual int webapiWorkspaceGet( + SWGSDRangel::SWGWorkspaceInfo& response, + QString& errorMessage); + virtual int webapiSettingsPutPatch( bool force, const QStringList& channelSettingsKeys, diff --git a/plugins/channelrx/radioclock/radioclockgui.cpp b/plugins/channelrx/radioclock/radioclockgui.cpp index 5e544cff7..6e98b8dc6 100644 --- a/plugins/channelrx/radioclock/radioclockgui.cpp +++ b/plugins/channelrx/radioclock/radioclockgui.cpp @@ -132,6 +132,16 @@ bool RadioClockGUI::handleMessage(const Message& message) ui->status->setText(report.getStatus()); return true; } + else if (DSPSignalNotification::match(message)) + { + const DSPSignalNotification& notif = (const DSPSignalNotification&) message; + m_deviceCenterFrequency = notif.getCenterFrequency(); + m_basebandSampleRate = notif.getSampleRate(); + ui->deltaFrequency->setValueRange(false, 7, -m_basebandSampleRate/2, m_basebandSampleRate/2); + ui->deltaFrequencyLabel->setToolTip(tr("Range %1 %L2 Hz").arg(QChar(0xB1)).arg(m_basebandSampleRate/2)); + updateAbsoluteCenterFrequency(); + return true; + } return false; } @@ -165,6 +175,7 @@ void RadioClockGUI::on_deltaFrequency_changed(qint64 value) { m_channelMarker.setCenterFrequency(value); m_settings.m_inputFrequencyOffset = m_channelMarker.getCenterFrequency(); + updateAbsoluteCenterFrequency(); applySettings(); } @@ -211,7 +222,18 @@ void RadioClockGUI::onWidgetRolled(QWidget* widget, bool rollDown) } } - saveState(m_rollupState); + RollupContents *rollupContents = getRollupContents(); + + if (rollupContents->hasExpandableWidgets()) { + setSizePolicy(sizePolicy().horizontalPolicy(), QSizePolicy::Expanding); + } else { + setSizePolicy(sizePolicy().horizontalPolicy(), QSizePolicy::Fixed); + } + + int h = rollupContents->height() + getAdditionalHeight(); + resize(width(), h); + + rollupContents->saveState(m_rollupState); applySettings(); } @@ -225,6 +247,14 @@ void RadioClockGUI::onMenuDialogCalled(const QPoint &p) dialog.setReverseAPIPort(m_settings.m_reverseAPIPort); dialog.setReverseAPIDeviceIndex(m_settings.m_reverseAPIDeviceIndex); dialog.setReverseAPIChannelIndex(m_settings.m_reverseAPIChannelIndex); + dialog.setDefaultTitle(m_displayedName); + + if (m_deviceUISet->m_deviceMIMOEngine) + { + dialog.setNumberOfStreams(m_radioClock->getNumberOfDeviceStreams()); + dialog.setStreamIndex(m_settings.m_streamIndex); + } + dialog.move(p); dialog.exec(); @@ -237,22 +267,17 @@ void RadioClockGUI::onMenuDialogCalled(const QPoint &p) m_settings.m_reverseAPIChannelIndex = dialog.getReverseAPIChannelIndex(); setWindowTitle(m_settings.m_title); + setTitle(m_channelMarker.getTitle()); setTitleColor(m_settings.m_rgbColor); - applySettings(); - } - else if ((m_contextMenuType == ContextMenuStreamSettings) && (m_deviceUISet->m_deviceMIMOEngine)) - { - DeviceStreamSelectionDialog dialog(this); - dialog.setNumberOfStreams(m_radioClock->getNumberOfDeviceStreams()); - dialog.setStreamIndex(m_settings.m_streamIndex); - dialog.move(p); - dialog.exec(); + if (m_deviceUISet->m_deviceMIMOEngine) + { + m_settings.m_streamIndex = dialog.getSelectedStreamIndex(); + m_channelMarker.clearStreamIndexes(); + m_channelMarker.addStreamIndex(m_settings.m_streamIndex); + updateIndexLabel(); + } - m_settings.m_streamIndex = dialog.getSelectedStreamIndex(); - m_channelMarker.clearStreamIndexes(); - m_channelMarker.addStreamIndex(m_settings.m_streamIndex); - displayStreamIndex(); applySettings(); } @@ -265,14 +290,18 @@ RadioClockGUI::RadioClockGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, Bas m_pluginAPI(pluginAPI), m_deviceUISet(deviceUISet), m_channelMarker(this), + m_deviceCenterFrequency(0), + m_basebandSampleRate(1), m_doApplySettings(true), m_tickCount(0) { - ui->setupUi(this); - m_helpURL = "plugins/channelrx/radioclock/readme.md"; - setAttribute(Qt::WA_DeleteOnClose, true); - connect(this, SIGNAL(widgetRolled(QWidget*,bool)), this, SLOT(onWidgetRolled(QWidget*,bool))); + m_helpURL = "plugins/channelrx/radioclock/readme.md"; + RollupContents *rollupContents = getRollupContents(); + ui->setupUi(rollupContents); + setSizePolicy(rollupContents->sizePolicy()); + rollupContents->arrangeRollups(); + connect(rollupContents, SIGNAL(widgetRolled(QWidget*,bool)), this, SLOT(onWidgetRolled(QWidget*,bool))); m_radioClock = reinterpret_cast(rxChannel); m_radioClock->setMessageQueueToGUI(getInputMessageQueue()); @@ -309,7 +338,6 @@ RadioClockGUI::RadioClockGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, Bas m_settings.setScopeGUI(ui->scopeGUI); m_deviceUISet->addChannelMarker(&m_channelMarker); - m_deviceUISet->addRollupWidget(this); connect(&m_channelMarker, SIGNAL(changedByCursor()), this, SLOT(channelMarkerChangedByCursor())); connect(&m_channelMarker, SIGNAL(highlightedByCursor()), this, SLOT(channelMarkerHighlightedByCursor())); @@ -318,6 +346,7 @@ RadioClockGUI::RadioClockGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, Bas ui->scopeContainer->setVisible(false); displaySettings(); + makeUIConnections(); applySettings(true); } @@ -351,6 +380,7 @@ void RadioClockGUI::displaySettings() setTitleColor(m_settings.m_rgbColor); setWindowTitle(m_channelMarker.getTitle()); + setTitle(m_channelMarker.getTitle()); blockApplySettings(true); @@ -365,29 +395,23 @@ void RadioClockGUI::displaySettings() ui->modulation->setCurrentIndex((int)m_settings.m_modulation); ui->timezone->setCurrentIndex((int)m_settings.m_timezone); - displayStreamIndex(); + updateIndexLabel(); - restoreState(m_rollupState); + getRollupContents()->restoreState(m_rollupState); + updateAbsoluteCenterFrequency(); blockApplySettings(false); } -void RadioClockGUI::displayStreamIndex() -{ - if (m_deviceUISet->m_deviceMIMOEngine) { - setStreamIndicator(tr("%1").arg(m_settings.m_streamIndex)); - } else { - setStreamIndicator("S"); // single channel indicator - } -} - -void RadioClockGUI::leaveEvent(QEvent*) +void RadioClockGUI::leaveEvent(QEvent* event) { m_channelMarker.setHighlighted(false); + ChannelGUI::leaveEvent(event); } -void RadioClockGUI::enterEvent(QEvent*) +void RadioClockGUI::enterEvent(QEvent* event) { m_channelMarker.setHighlighted(true); + ChannelGUI::enterEvent(event); } void RadioClockGUI::tick() @@ -409,3 +433,17 @@ void RadioClockGUI::tick() m_tickCount++; } + +void RadioClockGUI::makeUIConnections() +{ + QObject::connect(ui->deltaFrequency, &ValueDialZ::changed, this, &RadioClockGUI::on_deltaFrequency_changed); + QObject::connect(ui->rfBW, &QSlider::valueChanged, this, &RadioClockGUI::on_rfBW_valueChanged); + QObject::connect(ui->threshold, &QDial::valueChanged, this, &RadioClockGUI::on_threshold_valueChanged); + QObject::connect(ui->modulation, QOverload::of(&QComboBox::currentIndexChanged), this, &RadioClockGUI::on_modulation_currentIndexChanged); + QObject::connect(ui->timezone, QOverload::of(&QComboBox::currentIndexChanged), this, &RadioClockGUI::on_timezone_currentIndexChanged); +} + +void RadioClockGUI::updateAbsoluteCenterFrequency() +{ + setStatusFrequency(m_deviceCenterFrequency + m_settings.m_inputFrequencyOffset); +} diff --git a/plugins/channelrx/radioclock/radioclockgui.h b/plugins/channelrx/radioclock/radioclockgui.h index 827a6340c..2d855e054 100644 --- a/plugins/channelrx/radioclock/radioclockgui.h +++ b/plugins/channelrx/radioclock/radioclockgui.h @@ -31,7 +31,6 @@ class PluginAPI; class DeviceUISet; class BasebandSampleSink; class ScopeVis; -class ScopeVisXY; class RadioClock; class RadioClockGUI; @@ -51,6 +50,17 @@ public: QByteArray serialize() const; bool deserialize(const QByteArray& data); virtual MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; } + virtual void setWorkspaceIndex(int index) { m_settings.m_workspaceIndex = index; }; + virtual int getWorkspaceIndex() const { return m_settings.m_workspaceIndex; }; + virtual void setGeometryBytes(const QByteArray& blob) { m_settings.m_geometryBytes = blob; }; + virtual QByteArray getGeometryBytes() const { return m_settings.m_geometryBytes; }; + virtual QString getTitle() const { return m_settings.m_title; }; + virtual QColor getTitleColor() const { return m_settings.m_rgbColor; }; + virtual void zetHidden(bool hidden) { m_settings.m_hidden = hidden; } + virtual bool getHidden() const { return m_settings.m_hidden; } + virtual ChannelMarker& getChannelMarker() { return m_channelMarker; } + virtual int getStreamIndex() const { return m_settings.m_streamIndex; } + virtual void setStreamIndex(int streamIndex) { m_settings.m_streamIndex = streamIndex; } public slots: void channelMarkerChangedByCursor(); @@ -63,6 +73,8 @@ private: ChannelMarker m_channelMarker; RollupState m_rollupState; RadioClockSettings m_settings; + qint64 m_deviceCenterFrequency; + int m_basebandSampleRate; bool m_doApplySettings; ScopeVis* m_scopeVis; @@ -78,8 +90,10 @@ private: void blockApplySettings(bool block); void applySettings(bool force = false); void displaySettings(); - void displayStreamIndex(); bool handleMessage(const Message& message); + void makeUIConnections(); + void updateAbsoluteCenterFrequency(); + void displayDateTime(); void leaveEvent(QEvent*); diff --git a/plugins/channelrx/radioclock/radioclockgui.ui b/plugins/channelrx/radioclock/radioclockgui.ui index 82c5952ef..4f3d6cd2d 100644 --- a/plugins/channelrx/radioclock/radioclockgui.ui +++ b/plugins/channelrx/radioclock/radioclockgui.ui @@ -1,7 +1,7 @@ RadioClockGUI - + 0 @@ -638,9 +638,9 @@ - RollupWidget + RollupContents QWidget -
gui/rollupwidget.h
+
gui/rollupcontents.h
1
diff --git a/plugins/channelrx/radioclock/radioclocksettings.cpp b/plugins/channelrx/radioclock/radioclocksettings.cpp index 1cca135e8..6d39d78be 100644 --- a/plugins/channelrx/radioclock/radioclocksettings.cpp +++ b/plugins/channelrx/radioclock/radioclocksettings.cpp @@ -46,6 +46,8 @@ void RadioClockSettings::resetToDefaults() m_reverseAPIPort = 8888; m_reverseAPIDeviceIndex = 0; m_reverseAPIChannelIndex = 0; + m_workspaceIndex = 0; + m_hidden = false; } QByteArray RadioClockSettings::serialize() const @@ -79,6 +81,10 @@ QByteArray RadioClockSettings::serialize() const s.writeBlob(22, m_rollupState->serialize()); } + s.writeS32(23, m_workspaceIndex); + s.writeBlob(24, m_geometryBytes); + s.writeBool(25, m_hidden); + return s.final(); } @@ -140,6 +146,10 @@ bool RadioClockSettings::deserialize(const QByteArray& data) m_rollupState->deserialize(bytetmp); } + d.readS32(23, &m_workspaceIndex, 0); + d.readBlob(24, &m_geometryBytes); + d.readBool(25, &m_hidden, false); + return true; } else diff --git a/plugins/channelrx/radioclock/radioclocksettings.h b/plugins/channelrx/radioclock/radioclocksettings.h index 317be4503..8fde86bd0 100644 --- a/plugins/channelrx/radioclock/radioclocksettings.h +++ b/plugins/channelrx/radioclock/radioclocksettings.h @@ -54,6 +54,10 @@ struct RadioClockSettings uint16_t m_reverseAPIChannelIndex; Serializable *m_scopeGUI; Serializable *m_rollupState; + int m_workspaceIndex; + QByteArray m_geometryBytes; + bool m_hidden; + static const int RADIOCLOCK_CHANNEL_SAMPLE_RATE = 1000; static const int m_scopeStreams = 8; diff --git a/plugins/channelrx/radioclock/readme.md b/plugins/channelrx/radioclock/readme.md index 58c7f7755..987d03032 100644 --- a/plugins/channelrx/radioclock/readme.md +++ b/plugins/channelrx/radioclock/readme.md @@ -17,6 +17,8 @@ Although the atomic clocks used to transmit the timecode are extremely accurate,

Interface

+The top and bottom bars of the channel window are described [here](../../../sdrgui/channel/readme.md) + ![Radio clock plugin GUI](../../../doc/img/RadioClock_plugin.png)

1: Frequency shift from center frequency of reception

diff --git a/plugins/channelrx/remotesink/readme.md b/plugins/channelrx/remotesink/readme.md index aa7509aa7..4aeb8c8ce 100644 --- a/plugins/channelrx/remotesink/readme.md +++ b/plugins/channelrx/remotesink/readme.md @@ -10,6 +10,8 @@ The plugin will be built only if the [CM256cc library](https://github.com/f4exb/

Interface

+The top and bottom bars of the channel window are described [here](../../../sdrgui/channel/readme.md) + ![Remote sink channel plugin GUI](../../../doc/img/RemoteSink.png)

1: Decimation factor

diff --git a/plugins/channelrx/remotesink/remotesink.cpp b/plugins/channelrx/remotesink/remotesink.cpp index 232b35a0f..d5eaf261c 100644 --- a/plugins/channelrx/remotesink/remotesink.cpp +++ b/plugins/channelrx/remotesink/remotesink.cpp @@ -29,6 +29,7 @@ #include #include "SWGChannelSettings.h" +#include "SWGWorkspaceInfo.h" #include "util/simpleserializer.h" #include "dsp/dspcommands.h" @@ -99,6 +100,18 @@ RemoteSink::~RemoteSink() delete m_basebandSink; } +void RemoteSink::setDeviceAPI(DeviceAPI *deviceAPI) +{ + if (deviceAPI != m_deviceAPI) + { + m_deviceAPI->removeChannelSinkAPI(this); + m_deviceAPI->removeChannelSink(this); + m_deviceAPI = deviceAPI; + m_deviceAPI->addChannelSink(this); + m_deviceAPI->addChannelSinkAPI(this); + } +} + uint32_t RemoteSink::getNumberOfDeviceStreams() const { return m_deviceAPI->getNbSourceStreams(); @@ -155,10 +168,8 @@ bool RemoteSink::handleMessage(const Message& cmd) m_basebandSink->getInputMessageQueue()->push(msgToBaseband); // Forward to the GUI - if (getMessageQueueToGUI()) - { - DSPSignalNotification* msgToGUI = new DSPSignalNotification(notif); // make a copy - getMessageQueueToGUI()->push(msgToGUI); + if (getMessageQueueToGUI()) { + getMessageQueueToGUI()->push(new DSPSignalNotification(notif)); } return true; @@ -328,6 +339,15 @@ int RemoteSink::webapiSettingsGet( return 200; } +int RemoteSink::webapiWorkspaceGet( + SWGSDRangel::SWGWorkspaceInfo& response, + QString& errorMessage) +{ + (void) errorMessage; + response.setIndex(m_settings.m_workspaceIndex); + return 200; +} + int RemoteSink::webapiSettingsPutPatch( bool force, const QStringList& channelSettingsKeys, diff --git a/plugins/channelrx/remotesink/remotesink.h b/plugins/channelrx/remotesink/remotesink.h index 0764449da..13debfd79 100644 --- a/plugins/channelrx/remotesink/remotesink.h +++ b/plugins/channelrx/remotesink/remotesink.h @@ -65,6 +65,8 @@ public: RemoteSink(DeviceAPI *deviceAPI); virtual ~RemoteSink(); virtual void destroy() { delete this; } + virtual void setDeviceAPI(DeviceAPI *deviceAPI); + virtual DeviceAPI *getDeviceAPI() { return m_deviceAPI; } using BasebandSampleSink::feed; virtual void feed(const SampleVector::const_iterator& begin, const SampleVector::const_iterator& end, bool po); @@ -96,6 +98,10 @@ public: SWGSDRangel::SWGChannelSettings& response, QString& errorMessage); + virtual int webapiWorkspaceGet( + SWGSDRangel::SWGWorkspaceInfo& response, + QString& errorMessage); + virtual int webapiSettingsPutPatch( bool force, const QStringList& channelSettingsKeys, diff --git a/plugins/channelrx/remotesink/remotesinkgui.cpp b/plugins/channelrx/remotesink/remotesinkgui.cpp index 01e5f4600..fb2a1df70 100644 --- a/plugins/channelrx/remotesink/remotesinkgui.cpp +++ b/plugins/channelrx/remotesink/remotesinkgui.cpp @@ -16,6 +16,7 @@ /////////////////////////////////////////////////////////////////////////////////// #include +#include #include "device/deviceuiset.h" #include "gui/basicchannelsettingsdialog.h" @@ -63,6 +64,14 @@ bool RemoteSinkGUI::deserialize(const QByteArray& data) } } +void RemoteSinkGUI::resizeEvent(QResizeEvent* size) +{ + int maxWidth = getRollupContents()->maximumWidth(); + int minHeight = getRollupContents()->minimumHeight() + getAdditionalHeight(); + resize(width() < maxWidth ? width() : maxWidth, minHeight); + size->accept(); +} + bool RemoteSinkGUI::handleMessage(const Message& message) { if (RemoteSink::MsgConfigureRemoteSink::match(message)) @@ -79,6 +88,7 @@ bool RemoteSinkGUI::handleMessage(const Message& message) else if (DSPSignalNotification::match(message)) { DSPSignalNotification& cfg = (DSPSignalNotification&) message; + m_deviceCenterFrequency = cfg.getCenterFrequency(); m_basebandSampleRate = cfg.getSampleRate(); qDebug("RemoteSinkGUI::handleMessage: DSPSignalNotification: m_basebandSampleRate: %d", m_basebandSampleRate); displayRateAndShift(); @@ -97,12 +107,16 @@ RemoteSinkGUI::RemoteSinkGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, Bas m_pluginAPI(pluginAPI), m_deviceUISet(deviceUISet), m_basebandSampleRate(0), + m_deviceCenterFrequency(0), m_tickCount(0) { - ui->setupUi(this); - m_helpURL = "plugins/channelrx/remotesink/readme.md"; setAttribute(Qt::WA_DeleteOnClose, true); - connect(this, SIGNAL(widgetRolled(QWidget*,bool)), this, SLOT(onWidgetRolled(QWidget*,bool))); + m_helpURL = "plugins/channelrx/remotesink/readme.md"; + RollupContents *rollupContents = getRollupContents(); + ui->setupUi(rollupContents); + setSizePolicy(rollupContents->sizePolicy()); + rollupContents->arrangeRollups(); + connect(rollupContents, SIGNAL(widgetRolled(QWidget*,bool)), this, SLOT(onWidgetRolled(QWidget*,bool))); connect(this, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(onMenuDialogCalled(const QPoint &))); m_remoteSink = (RemoteSink*) channelrx; @@ -120,11 +134,11 @@ RemoteSinkGUI::RemoteSinkGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, Bas m_settings.setRollupState(&m_rollupState); m_deviceUISet->addChannelMarker(&m_channelMarker); - m_deviceUISet->addRollupWidget(this); connect(getInputMessageQueue(), SIGNAL(messageEnqueued()), this, SLOT(handleSourceMessages())); displaySettings(); + makeUIConnections(); applySettings(true); } @@ -161,6 +175,7 @@ void RemoteSinkGUI::displaySettings() setTitleColor(m_settings.m_rgbColor); setWindowTitle(m_channelMarker.getTitle()); + setTitle(m_channelMarker.getTitle()); blockApplySettings(true); ui->decimationFactor->setCurrentIndex(m_settings.m_log2Decim); @@ -171,20 +186,12 @@ void RemoteSinkGUI::displaySettings() ui->nominalNbBlocksText->setText(tr("%1/%2").arg(s).arg(s1)); ui->nbTxBytes->setCurrentIndex(log2(m_settings.m_nbTxBytes)); applyDecimation(); - displayStreamIndex(); - restoreState(m_rollupState); + updateIndexLabel(); + getRollupContents()->restoreState(m_rollupState); + updateAbsoluteCenterFrequency(); blockApplySettings(false); } -void RemoteSinkGUI::displayStreamIndex() -{ - if (m_deviceUISet->m_deviceMIMOEngine) { - setStreamIndicator(tr("%1").arg(m_settings.m_streamIndex)); - } else { - setStreamIndicator("S"); // single channel indicator - } -} - void RemoteSinkGUI::displayRateAndShift() { int shift = m_shiftFrequencyFactor * m_basebandSampleRate; @@ -196,14 +203,16 @@ void RemoteSinkGUI::displayRateAndShift() m_channelMarker.setBandwidth(channelSampleRate); } -void RemoteSinkGUI::leaveEvent(QEvent*) +void RemoteSinkGUI::leaveEvent(QEvent* event) { m_channelMarker.setHighlighted(false); + ChannelGUI::leaveEvent(event); } -void RemoteSinkGUI::enterEvent(QEvent*) +void RemoteSinkGUI::enterEvent(QEvent* event) { m_channelMarker.setHighlighted(true); + ChannelGUI::enterEvent(event); } void RemoteSinkGUI::handleSourceMessages() @@ -224,7 +233,7 @@ void RemoteSinkGUI::onWidgetRolled(QWidget* widget, bool rollDown) (void) widget; (void) rollDown; - saveState(m_rollupState); + getRollupContents()->saveState(m_rollupState); applySettings(); } @@ -238,6 +247,13 @@ void RemoteSinkGUI::onMenuDialogCalled(const QPoint &p) dialog.setReverseAPIPort(m_settings.m_reverseAPIPort); dialog.setReverseAPIDeviceIndex(m_settings.m_reverseAPIDeviceIndex); dialog.setReverseAPIChannelIndex(m_settings.m_reverseAPIChannelIndex); + dialog.setDefaultTitle(m_displayedName); + + if (m_deviceUISet->m_deviceMIMOEngine) + { + dialog.setNumberOfStreams(m_remoteSink->getNumberOfDeviceStreams()); + dialog.setStreamIndex(m_settings.m_streamIndex); + } dialog.move(p); dialog.exec(); @@ -251,22 +267,17 @@ void RemoteSinkGUI::onMenuDialogCalled(const QPoint &p) m_settings.m_reverseAPIChannelIndex = dialog.getReverseAPIChannelIndex(); setWindowTitle(m_settings.m_title); + setTitle(m_channelMarker.getTitle()); setTitleColor(m_settings.m_rgbColor); - applySettings(); - } - else if ((m_contextMenuType == ContextMenuStreamSettings) && (m_deviceUISet->m_deviceMIMOEngine)) - { - DeviceStreamSelectionDialog dialog(this); - dialog.setNumberOfStreams(m_remoteSink->getNumberOfDeviceStreams()); - dialog.setStreamIndex(m_settings.m_streamIndex); - dialog.move(p); - dialog.exec(); + if (m_deviceUISet->m_deviceMIMOEngine) + { + m_settings.m_streamIndex = dialog.getSelectedStreamIndex(); + m_channelMarker.clearStreamIndexes(); + m_channelMarker.addStreamIndex(m_settings.m_streamIndex); + updateIndexLabel(); + } - m_settings.m_streamIndex = dialog.getSelectedStreamIndex(); - m_channelMarker.clearStreamIndexes(); - m_channelMarker.addStreamIndex(m_settings.m_streamIndex); - displayStreamIndex(); applySettings(); } @@ -362,6 +373,7 @@ void RemoteSinkGUI::applyPosition() m_shiftFrequencyFactor = HBFilterChainConverter::convertToString(m_settings.m_log2Decim, m_settings.m_filterChainHash, s); ui->filterChainText->setText(s); + updateAbsoluteCenterFrequency(); displayRateAndShift(); applySettings(); } @@ -372,3 +384,20 @@ void RemoteSinkGUI::tick() m_tickCount = 0; } } + +void RemoteSinkGUI::makeUIConnections() +{ + QObject::connect(ui->decimationFactor, QOverload::of(&QComboBox::currentIndexChanged), this, &RemoteSinkGUI::on_decimationFactor_currentIndexChanged); + QObject::connect(ui->position, &QSlider::valueChanged, this, &RemoteSinkGUI::on_position_valueChanged); + QObject::connect(ui->dataAddress, &QLineEdit::returnPressed, this, &RemoteSinkGUI::on_dataAddress_returnPressed); + QObject::connect(ui->dataPort, &QLineEdit::returnPressed, this, &RemoteSinkGUI::on_dataPort_returnPressed); + QObject::connect(ui->dataApplyButton, &QPushButton::clicked, this, &RemoteSinkGUI::on_dataApplyButton_clicked); + QObject::connect(ui->nbFECBlocks, &QDial::valueChanged, this, &RemoteSinkGUI::on_nbFECBlocks_valueChanged); + QObject::connect(ui->nbTxBytes, QOverload::of(&QComboBox::currentIndexChanged), this, &RemoteSinkGUI::on_nbTxBytes_currentIndexChanged); +} + +void RemoteSinkGUI::updateAbsoluteCenterFrequency() +{ + int shift = m_shiftFrequencyFactor * m_basebandSampleRate; + setStatusFrequency(m_deviceCenterFrequency + shift); +} diff --git a/plugins/channelrx/remotesink/remotesinkgui.h b/plugins/channelrx/remotesink/remotesinkgui.h index b0361fa82..39287de17 100644 --- a/plugins/channelrx/remotesink/remotesinkgui.h +++ b/plugins/channelrx/remotesink/remotesinkgui.h @@ -48,6 +48,20 @@ public: QByteArray serialize() const; bool deserialize(const QByteArray& data); virtual MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; } + virtual void setWorkspaceIndex(int index) { m_settings.m_workspaceIndex = index; } + virtual int getWorkspaceIndex() const { return m_settings.m_workspaceIndex; } + virtual void setGeometryBytes(const QByteArray& blob) { m_settings.m_geometryBytes = blob; } + virtual QByteArray getGeometryBytes() const { return m_settings.m_geometryBytes; } + virtual QString getTitle() const { return m_settings.m_title; } + virtual QColor getTitleColor() const { return m_settings.m_rgbColor; } + virtual void zetHidden(bool hidden) { m_settings.m_hidden = hidden; } + virtual bool getHidden() const { return m_settings.m_hidden; } + virtual ChannelMarker& getChannelMarker() { return m_channelMarker; } + virtual int getStreamIndex() const { return m_settings.m_streamIndex; } + virtual void setStreamIndex(int streamIndex) { m_settings.m_streamIndex = streamIndex; } + +protected: + void resizeEvent(QResizeEvent* size); private: Ui::RemoteSinkGUI* ui; @@ -72,9 +86,10 @@ private: void blockApplySettings(bool block); void applySettings(bool force = false); void displaySettings(); - void displayStreamIndex(); void displayRateAndShift(); bool handleMessage(const Message& message); + void makeUIConnections(); + void updateAbsoluteCenterFrequency(); void leaveEvent(QEvent*); void enterEvent(QEvent*); diff --git a/plugins/channelrx/remotesink/remotesinkgui.ui b/plugins/channelrx/remotesink/remotesinkgui.ui index ec163ad0b..8cdbf64a0 100644 --- a/plugins/channelrx/remotesink/remotesinkgui.ui +++ b/plugins/channelrx/remotesink/remotesinkgui.ui @@ -1,7 +1,7 @@ RemoteSinkGUI - + 0 @@ -11,7 +11,7 @@ - + 0 0 @@ -24,7 +24,7 @@ - 320 + 360 16777215 @@ -40,8 +40,8 @@ - 10 - 10 + 0 + 0 301 141 @@ -450,9 +450,9 @@ - RollupWidget + RollupContents QWidget -
gui/rollupwidget.h
+
gui/rollupcontents.h
1
diff --git a/plugins/channelrx/remotesink/remotesinksettings.cpp b/plugins/channelrx/remotesink/remotesinksettings.cpp index 1181a41ce..69c507638 100644 --- a/plugins/channelrx/remotesink/remotesinksettings.cpp +++ b/plugins/channelrx/remotesink/remotesinksettings.cpp @@ -53,6 +53,8 @@ void RemoteSinkSettings::resetToDefaults() m_reverseAPIPort = 8888; m_reverseAPIDeviceIndex = 0; m_reverseAPIChannelIndex = 0; + m_workspaceIndex = 0; + m_hidden = false; } QByteArray RemoteSinkSettings::serialize() const @@ -83,6 +85,10 @@ QByteArray RemoteSinkSettings::serialize() const s.writeBlob(17, m_channelMarker->serialize()); } + s.writeS32(18, m_workspaceIndex); + s.writeBlob(19, m_geometryBytes); + s.writeBool(20, m_hidden); + return s.final(); } @@ -155,6 +161,10 @@ bool RemoteSinkSettings::deserialize(const QByteArray& data) m_channelMarker->deserialize(bytetmp); } + d.readS32(18, &m_workspaceIndex, 0); + d.readBlob(19, &m_geometryBytes); + d.readBool(20, &m_hidden, false); + return true; } else diff --git a/plugins/channelrx/remotesink/remotesinksettings.h b/plugins/channelrx/remotesink/remotesinksettings.h index 2828ba48d..6284d41f3 100644 --- a/plugins/channelrx/remotesink/remotesinksettings.h +++ b/plugins/channelrx/remotesink/remotesinksettings.h @@ -46,6 +46,9 @@ struct RemoteSinkSettings uint16_t m_reverseAPIPort; uint16_t m_reverseAPIDeviceIndex; uint16_t m_reverseAPIChannelIndex; + int m_workspaceIndex; + QByteArray m_geometryBytes; + bool m_hidden; Serializable *m_channelMarker; Serializable *m_rollupState; diff --git a/plugins/channelrx/sigmffilesink/readme.md b/plugins/channelrx/sigmffilesink/readme.md index f5e1690ef..2759e780b 100644 --- a/plugins/channelrx/sigmffilesink/readme.md +++ b/plugins/channelrx/sigmffilesink/readme.md @@ -19,6 +19,8 @@ It adds a dependency to the [libsigmf library](https://github.com/f4exb/libsigmf

Interface

+The top and bottom bars of the channel window are described [here](../../../sdrgui/channel/readme.md) + ![SigMF File Sink plugin GUI](../../../doc/img/SigMFFileSink_plugin.png)

1: Frequency shift from center frequency of reception

@@ -100,4 +102,4 @@ The path of the selected meta file appears at the right of the button. If it is

15: Channel spectrum

-This is the spectrum display of the IQ stream seen by the channel. It is the same as all spectrum displays in the program and is identical to the [main window](../../../sdrgui/readme.md#) spectrum display. +This is the spectrum display of the IQ stream seen by the channel. Details on the spectrum view and controls can be found [here](../../../sdrgui/gui/spectrum.md) diff --git a/plugins/channelrx/sigmffilesink/sigmffilesink.cpp b/plugins/channelrx/sigmffilesink/sigmffilesink.cpp index 5f1bb3828..6057e16f2 100644 --- a/plugins/channelrx/sigmffilesink/sigmffilesink.cpp +++ b/plugins/channelrx/sigmffilesink/sigmffilesink.cpp @@ -24,6 +24,7 @@ #include #include "SWGChannelSettings.h" +#include "SWGWorkspaceInfo.h" #include "SWGChannelReport.h" #include "SWGChannelActions.h" @@ -101,6 +102,18 @@ SigMFFileSink::~SigMFFileSink() delete m_basebandSink; } +void SigMFFileSink::setDeviceAPI(DeviceAPI *deviceAPI) +{ + if (deviceAPI != m_deviceAPI) + { + m_deviceAPI->removeChannelSinkAPI(this); + m_deviceAPI->removeChannelSink(this); + m_deviceAPI = deviceAPI; + m_deviceAPI->addChannelSink(this); + m_deviceAPI->addChannelSinkAPI(this); + } +} + void SigMFFileSink::setMessageQueueToGUI(MessageQueue* queue) { ChannelAPI::setMessageQueueToGUI(queue); @@ -170,10 +183,8 @@ bool SigMFFileSink::handleMessage(const Message& cmd) DSPSignalNotification *notif = new DSPSignalNotification(cfg); m_basebandSink->getInputMessageQueue()->push(notif); - if (getMessageQueueToGUI()) - { - DSPSignalNotification *notifToGUI = new DSPSignalNotification(cfg); - getMessageQueueToGUI()->push(notifToGUI); + if (getMessageQueueToGUI()) { + getMessageQueueToGUI()->push(new DSPSignalNotification(cfg)); } return true; @@ -384,6 +395,15 @@ int SigMFFileSink::webapiSettingsGet( return 200; } +int SigMFFileSink::webapiWorkspaceGet( + SWGSDRangel::SWGWorkspaceInfo& response, + QString& errorMessage) +{ + (void) errorMessage; + response.setIndex(m_settings.m_workspaceIndex); + return 200; +} + int SigMFFileSink::webapiSettingsPutPatch( bool force, const QStringList& channelSettingsKeys, diff --git a/plugins/channelrx/sigmffilesink/sigmffilesink.h b/plugins/channelrx/sigmffilesink/sigmffilesink.h index 3d8b4e82c..75b1785ee 100644 --- a/plugins/channelrx/sigmffilesink/sigmffilesink.h +++ b/plugins/channelrx/sigmffilesink/sigmffilesink.h @@ -84,6 +84,8 @@ public: SigMFFileSink(DeviceAPI *deviceAPI); virtual ~SigMFFileSink(); virtual void destroy() { delete this; } + virtual void setDeviceAPI(DeviceAPI *deviceAPI); + virtual DeviceAPI *getDeviceAPI() { return m_deviceAPI; } using BasebandSampleSink::feed; virtual void feed(const SampleVector::const_iterator& begin, const SampleVector::const_iterator& end, bool po); @@ -115,6 +117,10 @@ public: SWGSDRangel::SWGChannelSettings& response, QString& errorMessage); + virtual int webapiWorkspaceGet( + SWGSDRangel::SWGWorkspaceInfo& response, + QString& errorMessage); + virtual int webapiSettingsPutPatch( bool force, const QStringList& channelSettingsKeys, diff --git a/plugins/channelrx/sigmffilesink/sigmffilesinkgui.cpp b/plugins/channelrx/sigmffilesink/sigmffilesinkgui.cpp index 0a279d12f..c88796bf9 100644 --- a/plugins/channelrx/sigmffilesink/sigmffilesinkgui.cpp +++ b/plugins/channelrx/sigmffilesink/sigmffilesinkgui.cpp @@ -75,7 +75,10 @@ bool SigMFFileSinkGUI::handleMessage(const Message& message) if (DSPSignalNotification::match(message)) { DSPSignalNotification notif = (const DSPSignalNotification&) message; + m_deviceCenterFrequency = notif.getCenterFrequency(); m_basebandSampleRate = notif.getSampleRate(); + ui->deltaFrequency->setValueRange(false, 8, -m_basebandSampleRate/2, m_basebandSampleRate/2); + ui->deltaFrequencyLabel->setToolTip(tr("Range %1 %L2 Hz").arg(QChar(0xB1)).arg(m_basebandSampleRate/2)); displayRate(); if (m_fixedPosition) @@ -165,16 +168,20 @@ SigMFFileSinkGUI::SigMFFileSinkGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISe m_pluginAPI(pluginAPI), m_deviceUISet(deviceUISet), m_channelMarker(this), + m_deviceCenterFrequency(0), m_running(false), m_fixedShiftIndex(0), m_basebandSampleRate(0), m_fixedPosition(false), m_tickCount(0) { - ui->setupUi(this); - m_helpURL = "plugins/channelrx/sigmffilesink/readme.md"; setAttribute(Qt::WA_DeleteOnClose, true); - connect(this, SIGNAL(widgetRolled(QWidget*,bool)), this, SLOT(onWidgetRolled(QWidget*,bool))); + m_helpURL = "plugins/channelrx/sigmffilesink/readme.md"; + RollupContents *rollupContents = getRollupContents(); + ui->setupUi(rollupContents); + setSizePolicy(rollupContents->sizePolicy()); + rollupContents->arrangeRollups(); + connect(rollupContents, SIGNAL(widgetRolled(QWidget*,bool)), this, SLOT(onWidgetRolled(QWidget*,bool))); connect(this, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(onMenuDialogCalled(const QPoint &))); m_sigMFFileSink = (SigMFFileSink*) channelrx; @@ -201,7 +208,6 @@ SigMFFileSinkGUI::SigMFFileSinkGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISe m_settings.setRollupState(&m_rollupState); m_deviceUISet->addChannelMarker(&m_channelMarker); - m_deviceUISet->addRollupWidget(this); connect(&m_channelMarker, SIGNAL(changedByCursor()), this, SLOT(channelMarkerChangedByCursor())); connect(&m_channelMarker, SIGNAL(highlightedByCursor()), this, SLOT(channelMarkerHighlightedByCursor())); @@ -209,6 +215,7 @@ SigMFFileSinkGUI::SigMFFileSinkGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISe connect(&(m_deviceUISet->m_deviceAPI->getMasterTimer()), SIGNAL(timeout()), this, SLOT(tick())); displaySettings(); + makeUIConnections(); applySettings(true); } @@ -244,6 +251,7 @@ void SigMFFileSinkGUI::displaySettings() setTitleColor(m_settings.m_rgbColor); setWindowTitle(m_channelMarker.getTitle()); + setTitle(m_channelMarker.getTitle()); blockApplySettings(true); @@ -270,22 +278,14 @@ void SigMFFileSinkGUI::displaySettings() ui->squelchedRecording->blockSignals(false); } - displayStreamIndex(); + updateIndexLabel(); setPosFromFrequency(); - restoreState(m_rollupState); + getRollupContents()->restoreState(m_rollupState); + updateAbsoluteCenterFrequency(); blockApplySettings(false); } -void SigMFFileSinkGUI::displayStreamIndex() -{ - if (m_deviceUISet->m_deviceMIMOEngine) { - setStreamIndicator(tr("%1").arg(m_settings.m_streamIndex)); - } else { - setStreamIndicator("S"); // single channel indicator - } -} - void SigMFFileSinkGUI::displayRate() { double channelSampleRate = ((double) m_basebandSampleRate) / (1<filterChainIndex->setText(tr("%1").arg(m_fixedShiftIndex)); } -void SigMFFileSinkGUI::leaveEvent(QEvent*) +void SigMFFileSinkGUI::leaveEvent(QEvent* event) { m_channelMarker.setHighlighted(false); + ChannelGUI::leaveEvent(event); } -void SigMFFileSinkGUI::enterEvent(QEvent*) +void SigMFFileSinkGUI::enterEvent(QEvent* event) { m_channelMarker.setHighlighted(true); + ChannelGUI::enterEvent(event); } void SigMFFileSinkGUI::channelMarkerChangedByCursor() @@ -344,7 +346,18 @@ void SigMFFileSinkGUI::onWidgetRolled(QWidget* widget, bool rollDown) (void) widget; (void) rollDown; - saveState(m_rollupState); + RollupContents *rollupContents = getRollupContents(); + + if (rollupContents->hasExpandableWidgets()) { + setSizePolicy(sizePolicy().horizontalPolicy(), QSizePolicy::Expanding); + } else { + setSizePolicy(sizePolicy().horizontalPolicy(), QSizePolicy::Fixed); + } + + int h = rollupContents->height() + getAdditionalHeight(); + resize(width(), h); + + rollupContents->saveState(m_rollupState); applySettings(); } @@ -358,6 +371,13 @@ void SigMFFileSinkGUI::onMenuDialogCalled(const QPoint &p) dialog.setReverseAPIPort(m_settings.m_reverseAPIPort); dialog.setReverseAPIDeviceIndex(m_settings.m_reverseAPIDeviceIndex); dialog.setReverseAPIChannelIndex(m_settings.m_reverseAPIChannelIndex); + dialog.setDefaultTitle(m_displayedName); + + if (m_deviceUISet->m_deviceMIMOEngine) + { + dialog.setNumberOfStreams(m_sigMFFileSink->getNumberOfDeviceStreams()); + dialog.setStreamIndex(m_settings.m_streamIndex); + } dialog.move(p); dialog.exec(); @@ -371,22 +391,17 @@ void SigMFFileSinkGUI::onMenuDialogCalled(const QPoint &p) m_settings.m_reverseAPIChannelIndex = dialog.getReverseAPIChannelIndex(); setWindowTitle(m_settings.m_title); + setTitle(m_channelMarker.getTitle()); setTitleColor(m_settings.m_rgbColor); - applySettings(); - } - else if ((m_contextMenuType == ContextMenuStreamSettings) && (m_deviceUISet->m_deviceMIMOEngine)) - { - DeviceStreamSelectionDialog dialog(this); - dialog.setNumberOfStreams(m_sigMFFileSink->getNumberOfDeviceStreams()); - dialog.setStreamIndex(m_settings.m_streamIndex); - dialog.move(p); - dialog.exec(); + if (m_deviceUISet->m_deviceMIMOEngine) + { + m_settings.m_streamIndex = dialog.getSelectedStreamIndex(); + m_channelMarker.clearStreamIndexes(); + m_channelMarker.addStreamIndex(m_settings.m_streamIndex); + updateIndexLabel(); + } - m_settings.m_streamIndex = dialog.getSelectedStreamIndex(); - m_channelMarker.clearStreamIndexes(); - m_channelMarker.addStreamIndex(m_settings.m_streamIndex); - displayStreamIndex(); applySettings(); } @@ -399,6 +414,7 @@ void SigMFFileSinkGUI::on_deltaFrequency_changed(qint64 value) { m_channelMarker.setCenterFrequency(value); m_settings.m_inputFrequencyOffset = m_channelMarker.getCenterFrequency(); + updateAbsoluteCenterFrequency(); setPosFromFrequency(); applySettings(); } @@ -533,6 +549,7 @@ void SigMFFileSinkGUI::setFrequencyFromPos() m_channelMarker.setCenterFrequency(inputFrequencyOffset); ui->deltaFrequency->setValue(m_channelMarker.getCenterFrequency()); m_settings.m_inputFrequencyOffset = m_channelMarker.getCenterFrequency(); + updateAbsoluteCenterFrequency(); } void SigMFFileSinkGUI::setPosFromFrequency() @@ -586,3 +603,22 @@ QString SigMFFileSinkGUI::displayScaled(uint64_t value, int precision) } } +void SigMFFileSinkGUI::makeUIConnections() +{ + QObject::connect(ui->deltaFrequency, &ValueDialZ::changed, this, &SigMFFileSinkGUI::on_deltaFrequency_changed); + QObject::connect(ui->decimationFactor, QOverload::of(&QComboBox::currentIndexChanged), this, &SigMFFileSinkGUI::on_decimationFactor_currentIndexChanged); + QObject::connect(ui->fixedPosition, &QCheckBox::toggled, this, &SigMFFileSinkGUI::on_fixedPosition_toggled); + QObject::connect(ui->position, &QSlider::valueChanged, this, &SigMFFileSinkGUI::on_position_valueChanged); + QObject::connect(ui->spectrumSquelch, &ButtonSwitch::toggled, this, &SigMFFileSinkGUI::on_spectrumSquelch_toggled); + QObject::connect(ui->squelchLevel, &QDial::valueChanged, this, &SigMFFileSinkGUI::on_squelchLevel_valueChanged); + QObject::connect(ui->preRecordTime, &QDial::valueChanged, this, &SigMFFileSinkGUI::on_preRecordTime_valueChanged); + QObject::connect(ui->postSquelchTime, &QDial::valueChanged, this, &SigMFFileSinkGUI::on_postSquelchTime_valueChanged); + QObject::connect(ui->squelchedRecording, &ButtonSwitch::toggled, this, &SigMFFileSinkGUI::on_squelchedRecording_toggled); + QObject::connect(ui->record, &ButtonSwitch::toggled, this, &SigMFFileSinkGUI::on_record_toggled); + QObject::connect(ui->showFileDialog, &QPushButton::clicked, this, &SigMFFileSinkGUI::on_showFileDialog_clicked); +} + +void SigMFFileSinkGUI::updateAbsoluteCenterFrequency() +{ + setStatusFrequency(m_deviceCenterFrequency + m_settings.m_inputFrequencyOffset); +} diff --git a/plugins/channelrx/sigmffilesink/sigmffilesinkgui.h b/plugins/channelrx/sigmffilesink/sigmffilesinkgui.h index 654b53124..eb18bc049 100644 --- a/plugins/channelrx/sigmffilesink/sigmffilesinkgui.h +++ b/plugins/channelrx/sigmffilesink/sigmffilesinkgui.h @@ -49,6 +49,17 @@ public: QByteArray serialize() const; bool deserialize(const QByteArray& data); virtual MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; } + virtual void setWorkspaceIndex(int index) { m_settings.m_workspaceIndex = index; }; + virtual int getWorkspaceIndex() const { return m_settings.m_workspaceIndex; }; + virtual void setGeometryBytes(const QByteArray& blob) { m_settings.m_geometryBytes = blob; }; + virtual QByteArray getGeometryBytes() const { return m_settings.m_geometryBytes; }; + virtual QString getTitle() const { return m_settings.m_title; }; + virtual QColor getTitleColor() const { return m_settings.m_rgbColor; }; + virtual void zetHidden(bool hidden) { m_settings.m_hidden = hidden; } + virtual bool getHidden() const { return m_settings.m_hidden; } + virtual ChannelMarker& getChannelMarker() { return m_channelMarker; } + virtual int getStreamIndex() const { return m_settings.m_streamIndex; } + virtual void setStreamIndex(int streamIndex) { m_settings.m_streamIndex = streamIndex; } public slots: void channelMarkerChangedByCursor(); @@ -61,6 +72,7 @@ private: ChannelMarker m_channelMarker; RollupState m_rollupState; SigMFFileSinkSettings m_settings; + qint64 m_deviceCenterFrequency; bool m_running; int m_fixedShiftIndex; int m_basebandSampleRate; @@ -81,13 +93,14 @@ private: void applySettings(bool force = false); void applyDecimation(); void displaySettings(); - void displayStreamIndex(); void displayRate(); void displayPos(); void setFrequencyFromPos(); void setPosFromFrequency(); QString displayScaled(uint64_t value, int precision); bool handleMessage(const Message& message); + void makeUIConnections(); + void updateAbsoluteCenterFrequency(); void leaveEvent(QEvent*); void enterEvent(QEvent*); diff --git a/plugins/channelrx/sigmffilesink/sigmffilesinkgui.ui b/plugins/channelrx/sigmffilesink/sigmffilesinkgui.ui index dcba5229a..a12c65b03 100644 --- a/plugins/channelrx/sigmffilesink/sigmffilesinkgui.ui +++ b/plugins/channelrx/sigmffilesink/sigmffilesinkgui.ui @@ -1,7 +1,7 @@ SigMFFileSinkGUI - + 0 @@ -10,6 +10,12 @@ 458 + + + 0 + 0 + + 552 @@ -505,7 +511,7 @@
- + 0 @@ -514,8 +520,11 @@ 351 - - Channel Spectrum + + + 0 + 0 + @@ -523,9 +532,15 @@ + + + 0 + 0 + + - 0 + 300 300 @@ -545,20 +560,9 @@ - RollupWidget + RollupContents QWidget -
gui/rollupwidget.h
- 1 -
- - ButtonSwitch - QToolButton -
gui/buttonswitch.h
-
- - ValueDialZ - QWidget -
gui/valuedialz.h
+
gui/rollupcontents.h
1
@@ -573,6 +577,17 @@
gui/glspectrumgui.h
1
+ + ValueDialZ + QWidget +
gui/valuedialz.h
+ 1 +
+ + ButtonSwitch + QToolButton +
gui/buttonswitch.h
+
diff --git a/plugins/channelrx/sigmffilesink/sigmffilesinksettings.cpp b/plugins/channelrx/sigmffilesink/sigmffilesinksettings.cpp index aa785a33b..3bbf9060b 100644 --- a/plugins/channelrx/sigmffilesink/sigmffilesinksettings.cpp +++ b/plugins/channelrx/sigmffilesink/sigmffilesinksettings.cpp @@ -49,6 +49,8 @@ void SigMFFileSinkSettings::resetToDefaults() m_reverseAPIPort = 8888; m_reverseAPIDeviceIndex = 0; m_reverseAPIChannelIndex = 0; + m_workspaceIndex = 0; + m_hidden = false; } QByteArray SigMFFileSinkSettings::serialize() const @@ -85,6 +87,10 @@ QByteArray SigMFFileSinkSettings::serialize() const s.writeBlob(20, m_channelMarker->serialize()); } + s.writeS32(21, m_workspaceIndex); + s.writeBlob(22, m_geometryBytes); + s.writeBool(23, m_hidden); + return s.final(); } @@ -153,6 +159,10 @@ bool SigMFFileSinkSettings::deserialize(const QByteArray& data) m_channelMarker->deserialize(bytetmp); } + d.readS32(21, &m_workspaceIndex, 0); + d.readBlob(22, &m_geometryBytes); + d.readBool(23, &m_hidden, false); + return true; } else diff --git a/plugins/channelrx/sigmffilesink/sigmffilesinksettings.h b/plugins/channelrx/sigmffilesink/sigmffilesinksettings.h index dea649745..4d3075dde 100644 --- a/plugins/channelrx/sigmffilesink/sigmffilesinksettings.h +++ b/plugins/channelrx/sigmffilesink/sigmffilesinksettings.h @@ -42,6 +42,9 @@ struct SigMFFileSinkSettings uint16_t m_reverseAPIPort; uint16_t m_reverseAPIDeviceIndex; uint16_t m_reverseAPIChannelIndex; + int m_workspaceIndex; + QByteArray m_geometryBytes; + bool m_hidden; Serializable *m_spectrumGUI; Serializable *m_channelMarker; diff --git a/plugins/channelrx/udpsink/readme.md b/plugins/channelrx/udpsink/readme.md index b98dbe43b..0e4edd359 100644 --- a/plugins/channelrx/udpsink/readme.md +++ b/plugins/channelrx/udpsink/readme.md @@ -12,6 +12,8 @@ This plugin is available for Linux and Mac O/S only.

Interface

+The top and bottom bars of the channel window are described [here](../../../sdrgui/channel/readme.md) + ![UDP Sink plugin GUI](../../../doc/img/UDPsink_plugin.png)

1: Frequency shift from center frequency of reception

@@ -30,7 +32,7 @@ Total power in dB relative to a +/- 1.0 amplitude signal sent over UDP. These parameters are set with the basic channel settings dialog. See: [here](https://github.com/f4exb/sdrangel/blob/master/sdrgui/readme.md#6-channels) -The display is in the format `address:audio port/data port` +The display is in the format `address:audio port/data port`

5: Signal sample rate

@@ -48,14 +50,14 @@ Left: combo box to specify the type of samples that are sent over UDP: - `LSB Mono`: AF of the LSB part of a SSB demodulated signal as "mono" (I+Q)*0.7 samples that is one sample per demodulator output sample. This can be used with software that accepts mono type of input. - `USB Mono`: AF of the USB part of a SSB demodulated signal as "mono" (I+Q)*0.7 samples that is one sample per demodulator output sample. This can be used with software that accepts mono type of input. - `AM Mono`: AF of the envelope demodulated signal i.e. channel magnitude or sqrt(I² + Q²) as "mono" samples that is one sample per demodulator output sample. This can be used with software that accepts mono type of input. - - `AM !DC Mono`: Same as above but with a DC block based on magnitude average over a 5 ms period - - `AM BPF Mono`: Same as AM Mono but raw magnitude signal is passed through a bandpass filter with lower cutoff at 300 Hz and higher cutoff at RF bandwidth frequency - + - `AM !DC Mono`: Same as above but with a DC block based on magnitude average over a 5 ms period + - `AM BPF Mono`: Same as AM Mono but raw magnitude signal is passed through a bandpass filter with lower cutoff at 300 Hz and higher cutoff at RF bandwidth frequency + Right: Sample size in bits: - `16 bits`: samples are 16 bit signed with little endian layout (S16LE) - `24 bits`: samples are 32 bit signed with little endian layout (S32LE) using only the 3 less significant bytes. This means that the range is -2²³ to 2²³ - 1 - +

7: Signal bandwidth

The signal is bandpass filtered to this bandwidth (zero frequency centered) before being sent out as raw I/Q samples or before being demodulated for SSB and FM outputs. Thus a 20000 Hz bandwidth for example means +/-10000 Hz around center channel frequency. @@ -64,7 +66,7 @@ When SSB formats are used only the lower half (LSB) or upper half (USB) of the b

8: FM deviation

-This is the maximum expected FM deviation in Hz for NFM demodulated samples. Therefore it is active only for `NFM` types of sample formats. A positive deviation of this amount from the central carrier will result in a sample output value of 32767 (0x7FFF) corresponding to a +1.0 real value. A negative deviation of this amount from the central carrier will result in a sample output value of -32768 (0x8000) corresponding to a -1.0 real value. +This is the maximum expected FM deviation in Hz for NFM demodulated samples. Therefore it is active only for `NFM` types of sample formats. A positive deviation of this amount from the central carrier will result in a sample output value of 32767 (0x7FFF) corresponding to a +1.0 real value. A negative deviation of this amount from the central carrier will result in a sample output value of -32768 (0x8000) corresponding to a -1.0 real value.

9: AGC and audio feedback control

@@ -72,7 +74,7 @@ This is the maximum expected FM deviation in Hz for NFM demodulated samples. The

9.1: Toggle AGC

-It is effective only for AM and SSB. Signal is normalized to +/- 0.5 times the maximum amplitude with a time constant (averaging) of 200 ms. When engaged the squelch gate is fixed at 50 ms. The release time controlled by (15.3) can be increased from the 50 ms default for SSB signals to prevent accidental signal drops due to drops in the voice. +It is effective only for AM and SSB. Signal is normalized to +/- 0.5 times the maximum amplitude with a time constant (averaging) of 200 ms. When engaged the squelch gate is fixed at 50 ms. The release time controlled by (15.3) can be increased from the 50 ms default for SSB signals to prevent accidental signal drops due to drops in the voice.

9.2: Toggle audio feedback

@@ -94,7 +96,7 @@ The changes in the following items only become effective when this button is pre - Audio port (9) - FM deviation (11) -When any item of these items is changed the button is lit in green until it is pressed. +When any item of these items is changed the button is lit in green until it is pressed.

11: Audio volume

@@ -120,11 +122,11 @@ Use the slider to set the squelch power threshold based on channel input power ( Sets the delay after which a signal constantly above the squelch threshold effectively opens the squelch. The same delay is used for squelch release except for SSB where the gate is fixed at 50 ms and this controls the release time only. -The delay in milliseconds is displayed at the right of the button. +The delay in milliseconds is displayed at the right of the button.

14: Spectrum display

-This is the spectrum display of the channel signal after bandpass filtering. Please refer to the Spectrum display description for details. +This is the spectrum display of the channel signal after bandpass filtering. Details on the spectrum view and controls can be found [here](../../../sdrgui/gui/spectrum.md) -This spectrum is centered on the center frequency of the channel (center frequency of reception + channel shift) and is that of a complex signal i.e. there are positive and negative frequencies. The width of the spectrum is proportional of the sample rate. That is for a sample rate of S samples per seconds the spectrum spans from -S/2 to +S/2 Hz. +This spectrum is centered on the center frequency of the channel (center frequency of reception + channel shift) and is that of a complex signal i.e. there are positive and negative frequencies. The width of the spectrum is proportional of the sample rate. That is for a sample rate of S samples per seconds the spectrum spans from -S/2 to +S/2 Hz. diff --git a/plugins/channelrx/udpsink/udpsink.cpp b/plugins/channelrx/udpsink/udpsink.cpp index 223e9b6e4..86b7df320 100644 --- a/plugins/channelrx/udpsink/udpsink.cpp +++ b/plugins/channelrx/udpsink/udpsink.cpp @@ -24,6 +24,7 @@ #include #include "SWGChannelSettings.h" +#include "SWGWorkspaceInfo.h" #include "SWGUDPSinkSettings.h" #include "SWGChannelReport.h" #include "SWGUDPSinkReport.h" @@ -92,6 +93,18 @@ UDPSink::~UDPSink() delete m_thread; } +void UDPSink::setDeviceAPI(DeviceAPI *deviceAPI) +{ + if (deviceAPI != m_deviceAPI) + { + m_deviceAPI->removeChannelSinkAPI(this); + m_deviceAPI->removeChannelSink(this); + m_deviceAPI = deviceAPI; + m_deviceAPI->addChannelSink(this); + m_deviceAPI->addChannelSinkAPI(this); + } +} + uint32_t UDPSink::getNumberOfDeviceStreams() const { return m_deviceAPI->getNbSourceStreams(); @@ -141,6 +154,10 @@ bool UDPSink::handleMessage(const Message& cmd) DSPSignalNotification* rep = new DSPSignalNotification(notif); // make a copy qDebug() << "UDPSink::handleMessage: DSPSignalNotification"; m_basebandSink->getInputMessageQueue()->push(rep); + // Forward to GUI if any + if (getMessageQueueToGUI()) { + getMessageQueueToGUI()->push(new DSPSignalNotification(notif)); + } return true; } @@ -310,6 +327,15 @@ int UDPSink::webapiSettingsGet( return 200; } +int UDPSink::webapiWorkspaceGet( + SWGSDRangel::SWGWorkspaceInfo& response, + QString& errorMessage) +{ + (void) errorMessage; + response.setIndex(m_settings.m_workspaceIndex); + return 200; +} + int UDPSink::webapiSettingsPutPatch( bool force, const QStringList& channelSettingsKeys, diff --git a/plugins/channelrx/udpsink/udpsink.h b/plugins/channelrx/udpsink/udpsink.h index c70f6bd43..14b09b877 100644 --- a/plugins/channelrx/udpsink/udpsink.h +++ b/plugins/channelrx/udpsink/udpsink.h @@ -63,6 +63,8 @@ public: UDPSink(DeviceAPI *deviceAPI); virtual ~UDPSink(); virtual void destroy() { delete this; } + virtual void setDeviceAPI(DeviceAPI *deviceAPI); + virtual DeviceAPI *getDeviceAPI() { return m_deviceAPI; } SpectrumVis *getSpectrumVis() { return &m_spectrumVis; } void enableSpectrum(bool enable); @@ -101,6 +103,10 @@ public: SWGSDRangel::SWGChannelSettings& response, QString& errorMessage); + virtual int webapiWorkspaceGet( + SWGSDRangel::SWGWorkspaceInfo& response, + QString& errorMessage); + virtual int webapiSettingsPutPatch( bool force, const QStringList& channelSettingsKeys, diff --git a/plugins/channelrx/udpsink/udpsinkgui.cpp b/plugins/channelrx/udpsink/udpsinkgui.cpp index f64f517c3..3043c2a1c 100644 --- a/plugins/channelrx/udpsink/udpsinkgui.cpp +++ b/plugins/channelrx/udpsink/udpsinkgui.cpp @@ -20,6 +20,7 @@ #include "plugin/pluginapi.h" #include "dsp/spectrumvis.h" #include "dsp/dspengine.h" +#include "dsp/dspcommands.h" #include "util/simpleserializer.h" #include "util/db.h" #include "gui/basicchannelsettingsdialog.h" @@ -81,6 +82,16 @@ bool UDPSinkGUI::handleMessage(const Message& message ) blockApplySettings(false); return true; } + else if (DSPSignalNotification::match(message)) + { + const DSPSignalNotification& notif = (const DSPSignalNotification&) message; + m_deviceCenterFrequency = notif.getCenterFrequency(); + m_basebandSampleRate = notif.getSampleRate(); + ui->deltaFrequency->setValueRange(false, 8, -m_basebandSampleRate/2, m_basebandSampleRate/2); + ui->deltaFrequencyLabel->setToolTip(tr("Range %1 %L2 Hz").arg(QChar(0xB1)).arg(m_basebandSampleRate/2)); + updateAbsoluteCenterFrequency(); + return true; + } else { return false; @@ -139,7 +150,9 @@ UDPSinkGUI::UDPSinkGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, BasebandS ui(new Ui::UDPSinkGUI), m_pluginAPI(pluginAPI), m_deviceUISet(deviceUISet), - m_udpSink(0), + m_udpSink(nullptr), + m_deviceCenterFrequency(0), + m_basebandSampleRate(1), m_channelMarker(this), m_channelPowerAvg(4, 1e-10), m_inPowerAvg(4, 1e-10), @@ -147,11 +160,14 @@ UDPSinkGUI::UDPSinkGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, BasebandS m_doApplySettings(true), m_rfBandwidthChanged(false) { - ui->setupUi(this); - m_helpURL = "plugins/channelrx/udpsink/readme.md"; - connect(this, SIGNAL(widgetRolled(QWidget*,bool)), this, SLOT(onWidgetRolled(QWidget*,bool))); - connect(this, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(onMenuDialogCalled(const QPoint &))); setAttribute(Qt::WA_DeleteOnClose, true); + m_helpURL = "plugins/channelrx/udpsink/readme.md"; + RollupContents *rollupContents = getRollupContents(); + ui->setupUi(rollupContents); + setSizePolicy(rollupContents->sizePolicy()); + rollupContents->arrangeRollups(); + connect(rollupContents, SIGNAL(widgetRolled(QWidget*,bool)), this, SLOT(onWidgetRolled(QWidget*,bool))); + connect(this, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(onMenuDialogCalled(const QPoint &))); m_udpSink = (UDPSink*) rxChannel; m_spectrumVis = m_udpSink->getSpectrumVis(); @@ -187,7 +203,6 @@ UDPSinkGUI::UDPSinkGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, BasebandS m_settings.setRollupState(&m_rollupState); m_deviceUISet->addChannelMarker(&m_channelMarker); - m_deviceUISet->addRollupWidget(this); connect(&m_channelMarker, SIGNAL(changedByCursor()), this, SLOT(channelMarkerChangedByCursor())); connect(&m_channelMarker, SIGNAL(highlightedByCursor()), this, SLOT(channelMarkerHighlightedByCursor())); @@ -196,6 +211,7 @@ UDPSinkGUI::UDPSinkGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, BasebandS ui->spectrumGUI->setBuddies(m_spectrumVis, ui->glSpectrum); displaySettings(); + makeUIConnections(); applySettingsImmediate(true); applySettings(true); } @@ -221,6 +237,7 @@ void UDPSinkGUI::displaySettings() setTitleColor(m_settings.m_rgbColor); setWindowTitle(m_channelMarker.getTitle()); + setTitle(m_channelMarker.getTitle()); blockApplySettings(true); @@ -256,23 +273,15 @@ void UDPSinkGUI::displaySettings() ui->applyBtn->setEnabled(false); ui->applyBtn->setStyleSheet("QPushButton { background:rgb(79,79,79); }"); - displayStreamIndex(); + updateIndexLabel(); - restoreState(m_rollupState); + getRollupContents()->restoreState(m_rollupState); + updateAbsoluteCenterFrequency(); blockApplySettings(false); ui->glSpectrum->setSampleRate(m_settings.m_outputSampleRate); } -void UDPSinkGUI::displayStreamIndex() -{ - if (m_deviceUISet->m_deviceMIMOEngine) { - setStreamIndicator(tr("%1").arg(m_settings.m_streamIndex)); - } else { - setStreamIndicator("S"); // single channel indicator - } -} - void UDPSinkGUI::setSampleFormatIndex(const UDPSinkSettings::SampleFormat& sampleFormat) { switch(sampleFormat) @@ -396,6 +405,7 @@ void UDPSinkGUI::on_deltaFrequency_changed(qint64 value) { m_channelMarker.setCenterFrequency(value); m_settings.m_inputFrequencyOffset = m_channelMarker.getCenterFrequency(); + updateAbsoluteCenterFrequency(); applySettings(); } @@ -590,7 +600,18 @@ void UDPSinkGUI::onWidgetRolled(QWidget* widget, bool rollDown) m_udpSink->enableSpectrum(rollDown); } - saveState(m_rollupState); + RollupContents *rollupContents = getRollupContents(); + + if (rollupContents->hasExpandableWidgets()) { + setSizePolicy(sizePolicy().horizontalPolicy(), QSizePolicy::Expanding); + } else { + setSizePolicy(sizePolicy().horizontalPolicy(), QSizePolicy::Fixed); + } + + int h = rollupContents->height() + getAdditionalHeight(); + resize(width(), h); + + rollupContents->saveState(m_rollupState); applySettings(); } @@ -604,11 +625,17 @@ void UDPSinkGUI::onMenuDialogCalled(const QPoint &p) dialog.setReverseAPIPort(m_settings.m_reverseAPIPort); dialog.setReverseAPIDeviceIndex(m_settings.m_reverseAPIDeviceIndex); dialog.setReverseAPIChannelIndex(m_settings.m_reverseAPIChannelIndex); + dialog.setDefaultTitle(m_displayedName); + + if (m_deviceUISet->m_deviceMIMOEngine) + { + dialog.setNumberOfStreams(m_udpSink->getNumberOfDeviceStreams()); + dialog.setStreamIndex(m_settings.m_streamIndex); + } dialog.move(p); dialog.exec(); - m_settings.m_inputFrequencyOffset = m_channelMarker.getCenterFrequency(); m_settings.m_rgbColor = m_channelMarker.getColor().rgb(); m_settings.m_title = m_channelMarker.getTitle(); m_settings.m_useReverseAPI = dialog.useReverseAPI(); @@ -618,36 +645,56 @@ void UDPSinkGUI::onMenuDialogCalled(const QPoint &p) m_settings.m_reverseAPIChannelIndex = dialog.getReverseAPIChannelIndex(); setWindowTitle(m_settings.m_title); + setTitle(m_channelMarker.getTitle()); setTitleColor(m_settings.m_rgbColor); - applySettingsImmediate(); - } - else if ((m_contextMenuType == ContextMenuStreamSettings) && (m_deviceUISet->m_deviceMIMOEngine)) - { - DeviceStreamSelectionDialog dialog(this); - dialog.setNumberOfStreams(m_udpSink->getNumberOfDeviceStreams()); - dialog.setStreamIndex(m_settings.m_streamIndex); - dialog.move(p); - dialog.exec(); + if (m_deviceUISet->m_deviceMIMOEngine) + { + m_settings.m_streamIndex = dialog.getSelectedStreamIndex(); + m_channelMarker.clearStreamIndexes(); + m_channelMarker.addStreamIndex(m_settings.m_streamIndex); + updateIndexLabel(); + } - m_settings.m_streamIndex = dialog.getSelectedStreamIndex(); - m_channelMarker.clearStreamIndexes(); - m_channelMarker.addStreamIndex(m_settings.m_streamIndex); - displayStreamIndex(); - applySettings(); + applySettingsImmediate(); } resetContextMenuType(); } -void UDPSinkGUI::leaveEvent(QEvent*) +void UDPSinkGUI::leaveEvent(QEvent* event) { m_channelMarker.setHighlighted(false); + ChannelGUI::leaveEvent(event); } -void UDPSinkGUI::enterEvent(QEvent*) +void UDPSinkGUI::enterEvent(QEvent* event) { m_channelMarker.setHighlighted(true); + ChannelGUI::enterEvent(event); } +void UDPSinkGUI::makeUIConnections() +{ + QObject::connect(ui->deltaFrequency, &ValueDialZ::changed, this, &UDPSinkGUI::on_deltaFrequency_changed); + QObject::connect(ui->sampleFormat, QOverload::of(&QComboBox::currentIndexChanged), this, &UDPSinkGUI::on_sampleFormat_currentIndexChanged); + QObject::connect(ui->outputUDPAddress, &QLineEdit::editingFinished, this, &UDPSinkGUI::on_outputUDPAddress_editingFinished); + QObject::connect(ui->outputUDPPort, &QLineEdit::editingFinished, this, &UDPSinkGUI::on_outputUDPPort_editingFinished); + QObject::connect(ui->inputUDPAudioPort, &QLineEdit::editingFinished, this, &UDPSinkGUI::on_inputUDPAudioPort_editingFinished); + QObject::connect(ui->sampleRate, &QLineEdit::textEdited, this, &UDPSinkGUI::on_sampleRate_textEdited); + QObject::connect(ui->rfBandwidth, &QLineEdit::textEdited, this, &UDPSinkGUI::on_rfBandwidth_textEdited); + QObject::connect(ui->fmDeviation, &QLineEdit::textEdited, this, &UDPSinkGUI::on_fmDeviation_textEdited); + QObject::connect(ui->audioActive, &QToolButton::toggled, this, &UDPSinkGUI::on_audioActive_toggled); + QObject::connect(ui->audioStereo, &QToolButton::toggled, this, &UDPSinkGUI::on_audioStereo_toggled); + QObject::connect(ui->applyBtn, &QPushButton::clicked, this, &UDPSinkGUI::on_applyBtn_clicked); + QObject::connect(ui->gain, &QSlider::valueChanged, this, &UDPSinkGUI::on_gain_valueChanged); + QObject::connect(ui->volume, &QSlider::valueChanged, this, &UDPSinkGUI::on_volume_valueChanged); + QObject::connect(ui->squelch, &QSlider::valueChanged, this, &UDPSinkGUI::on_squelch_valueChanged); + QObject::connect(ui->squelchGate, &QDial::valueChanged, this, &UDPSinkGUI::on_squelchGate_valueChanged); + QObject::connect(ui->agc, &ButtonSwitch::toggled, this, &UDPSinkGUI::on_agc_toggled); +} +void UDPSinkGUI::updateAbsoluteCenterFrequency() +{ + setStatusFrequency(m_deviceCenterFrequency + m_settings.m_inputFrequencyOffset); +} diff --git a/plugins/channelrx/udpsink/udpsinkgui.h b/plugins/channelrx/udpsink/udpsinkgui.h index dd2fd6828..d08e5dd4a 100644 --- a/plugins/channelrx/udpsink/udpsinkgui.h +++ b/plugins/channelrx/udpsink/udpsinkgui.h @@ -49,6 +49,17 @@ public: QByteArray serialize() const; bool deserialize(const QByteArray& data); virtual MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; } + virtual void setWorkspaceIndex(int index) { m_settings.m_workspaceIndex = index; }; + virtual int getWorkspaceIndex() const { return m_settings.m_workspaceIndex; }; + virtual void setGeometryBytes(const QByteArray& blob) { m_settings.m_geometryBytes = blob; }; + virtual QByteArray getGeometryBytes() const { return m_settings.m_geometryBytes; }; + virtual QString getTitle() const { return m_settings.m_title; }; + virtual QColor getTitleColor() const { return m_settings.m_rgbColor; }; + virtual void zetHidden(bool hidden) { m_settings.m_hidden = hidden; } + virtual bool getHidden() const { return m_settings.m_hidden; } + virtual ChannelMarker& getChannelMarker() { return m_channelMarker; } + virtual int getStreamIndex() const { return m_settings.m_streamIndex; } + virtual void setStreamIndex(int streamIndex) { m_settings.m_streamIndex = streamIndex; } public slots: void channelMarkerChangedByCursor(); @@ -60,6 +71,8 @@ private: DeviceUISet* m_deviceUISet; UDPSink* m_udpSink; UDPSinkSettings m_settings; + qint64 m_deviceCenterFrequency; + int m_basebandSampleRate; ChannelMarker m_channelMarker; RollupState m_rollupState; MovingAverage m_channelPowerAvg; @@ -81,10 +94,11 @@ private: void applySettings(bool force = false); void applySettingsImmediate(bool force = false); void displaySettings(); - void displayStreamIndex(); void setSampleFormat(int index); void setSampleFormatIndex(const UDPSinkSettings::SampleFormat& sampleFormat); bool handleMessage(const Message& message); + void makeUIConnections(); + void updateAbsoluteCenterFrequency(); void leaveEvent(QEvent*); void enterEvent(QEvent*); diff --git a/plugins/channelrx/udpsink/udpsinkgui.ui b/plugins/channelrx/udpsink/udpsinkgui.ui index 1bd129907..037195b5c 100644 --- a/plugins/channelrx/udpsink/udpsinkgui.ui +++ b/plugins/channelrx/udpsink/udpsinkgui.ui @@ -1,7 +1,7 @@ UDPSinkGUI - + 0 @@ -10,18 +10,18 @@ 355 + + + 0 + 0 + + - 342 + 382 0 - - - 400 - 16777215 - - Liberation Sans @@ -183,6 +183,15 @@ + + + + 26 + 26 + 26 + + + @@ -203,6 +212,15 @@ + + + + 26 + 26 + 26 + + + @@ -223,11 +241,21 @@ + + + + 26 + 26 + 26 + + + + Liberation Sans 8 @@ -821,10 +849,16 @@ 15 160 - 231 + 361 156
+ + + 0 + 0 + + Channel Spectrum @@ -846,6 +880,18 @@ + + + 0 + 0 + + + + + 300 + 300 + + Liberation Mono @@ -862,9 +908,9 @@ - RollupWidget + RollupContents QWidget -
gui/rollupwidget.h
+
gui/rollupcontents.h
1
diff --git a/plugins/channelrx/udpsink/udpsinksettings.cpp b/plugins/channelrx/udpsink/udpsinksettings.cpp index 169fc129f..ea6e1eee0 100644 --- a/plugins/channelrx/udpsink/udpsinksettings.cpp +++ b/plugins/channelrx/udpsink/udpsinksettings.cpp @@ -57,6 +57,8 @@ void UDPSinkSettings::resetToDefaults() m_reverseAPIPort = 8888; m_reverseAPIDeviceIndex = 0; m_reverseAPIChannelIndex = 0; + m_workspaceIndex = 0; + m_hidden = false; } QByteArray UDPSinkSettings::serialize() const @@ -99,6 +101,10 @@ QByteArray UDPSinkSettings::serialize() const s.writeBlob(29, m_rollupState->serialize()); } + s.writeS32(30, m_workspaceIndex); + s.writeBlob(31, m_geometryBytes); + s.writeBool(32, m_hidden); + return s.final(); } @@ -197,6 +203,10 @@ bool UDPSinkSettings::deserialize(const QByteArray& data) m_rollupState->deserialize(bytetmp); } + d.readS32(30, &m_workspaceIndex, 0); + d.readBlob(31, &m_geometryBytes); + d.readBool(32, &m_hidden, false); + return true; } else diff --git a/plugins/channelrx/udpsink/udpsinksettings.h b/plugins/channelrx/udpsink/udpsinksettings.h index b24e23385..3f0b869a6 100644 --- a/plugins/channelrx/udpsink/udpsinksettings.h +++ b/plugins/channelrx/udpsink/udpsinksettings.h @@ -69,6 +69,9 @@ struct UDPSinkSettings uint16_t m_reverseAPIPort; uint16_t m_reverseAPIDeviceIndex; uint16_t m_reverseAPIChannelIndex; + int m_workspaceIndex; + QByteArray m_geometryBytes; + bool m_hidden; Serializable *m_channelMarker; Serializable *m_spectrumGUI; diff --git a/plugins/channeltx/filesource/filesource.cpp b/plugins/channeltx/filesource/filesource.cpp index c2035b8e7..9830cb0f9 100644 --- a/plugins/channeltx/filesource/filesource.cpp +++ b/plugins/channeltx/filesource/filesource.cpp @@ -24,6 +24,7 @@ #include #include "SWGChannelSettings.h" +#include "SWGWorkspaceInfo.h" #include "SWGChannelReport.h" #include "SWGChannelActions.h" #include "SWGFileSourceReport.h" @@ -40,7 +41,6 @@ #include "filesourcebaseband.h" -MESSAGE_CLASS_DEFINITION(FileSource::MsgSampleRateNotification, Message) MESSAGE_CLASS_DEFINITION(FileSource::MsgConfigureFileSource, Message) MESSAGE_CLASS_DEFINITION(FileSource::MsgConfigureFileSourceWork, Message) MESSAGE_CLASS_DEFINITION(FileSource::MsgConfigureFileSourceStreamTiming, Message) @@ -93,6 +93,18 @@ FileSource::~FileSource() delete m_thread; } +void FileSource::setDeviceAPI(DeviceAPI *deviceAPI) +{ + if (deviceAPI != m_deviceAPI) + { + m_deviceAPI->removeChannelSourceAPI(this); + m_deviceAPI->removeChannelSource(this); + m_deviceAPI = deviceAPI; + m_deviceAPI->addChannelSource(this); + m_deviceAPI->addChannelSinkAPI(this); + } +} + void FileSource::start() { qDebug("FileSource::start"); @@ -134,8 +146,7 @@ bool FileSource::handleMessage(const Message& cmd) if (m_guiMessageQueue) { qDebug() << "FileSource::handleMessage: DSPSignalNotification: push to GUI"; - MsgSampleRateNotification *msg = MsgSampleRateNotification::create(notif.getSampleRate()); - m_guiMessageQueue->push(msg); + m_guiMessageQueue->push(new DSPSignalNotification(notif)); } return true; @@ -312,6 +323,15 @@ int FileSource::webapiSettingsGet( return 200; } +int FileSource::webapiWorkspaceGet( + SWGSDRangel::SWGWorkspaceInfo& response, + QString& errorMessage) +{ + (void) errorMessage; + response.setIndex(m_settings.m_workspaceIndex); + return 200; +} + int FileSource::webapiSettingsPutPatch( bool force, const QStringList& channelSettingsKeys, diff --git a/plugins/channeltx/filesource/filesource.h b/plugins/channeltx/filesource/filesource.h index 0695b3af4..b3e101122 100644 --- a/plugins/channeltx/filesource/filesource.h +++ b/plugins/channeltx/filesource/filesource.h @@ -67,26 +67,6 @@ public: { } }; - class MsgSampleRateNotification : public Message { - MESSAGE_CLASS_DECLARATION - - public: - static MsgSampleRateNotification* create(int sampleRate) { - return new MsgSampleRateNotification(sampleRate); - } - - int getSampleRate() const { return m_sampleRate; } - - private: - - MsgSampleRateNotification(int sampleRate) : - Message(), - m_sampleRate(sampleRate) - { } - - int m_sampleRate; - }; - class MsgConfigureFileSourceWork : public Message { MESSAGE_CLASS_DECLARATION @@ -167,6 +147,8 @@ public: FileSource(DeviceAPI *deviceAPI); virtual ~FileSource(); virtual void destroy() { delete this; } + virtual void setDeviceAPI(DeviceAPI *deviceAPI); + virtual DeviceAPI *getDeviceAPI() { return m_deviceAPI; } virtual void start(); virtual void stop(); @@ -197,6 +179,10 @@ public: SWGSDRangel::SWGChannelSettings& response, QString& errorMessage); + virtual int webapiWorkspaceGet( + SWGSDRangel::SWGWorkspaceInfo& response, + QString& errorMessage); + virtual int webapiSettingsPutPatch( bool force, const QStringList& channelSettingsKeys, diff --git a/plugins/channeltx/filesource/filesourcegui.cpp b/plugins/channeltx/filesource/filesourcegui.cpp index fd2cf66f6..eb2b26d06 100644 --- a/plugins/channeltx/filesource/filesourcegui.cpp +++ b/plugins/channeltx/filesource/filesourcegui.cpp @@ -18,10 +18,12 @@ #include #include #include +#include #include "device/deviceapi.h" #include "device/deviceuiset.h" #include "dsp/hbfilterchainconverter.h" +#include "dsp/dspcommands.h" #include "gui/basicchannelsettingsdialog.h" #include "gui/devicestreamselectiondialog.h" #include "util/db.h" @@ -68,12 +70,22 @@ bool FileSourceGUI::deserialize(const QByteArray& data) } } +void FileSourceGUI::resizeEvent(QResizeEvent* size) +{ + int maxWidth = getRollupContents()->maximumWidth(); + int minHeight = getRollupContents()->minimumHeight() + getAdditionalHeight(); + resize(width() < maxWidth ? width() : maxWidth, minHeight); + size->accept(); +} + bool FileSourceGUI::handleMessage(const Message& message) { - if (FileSource::MsgSampleRateNotification::match(message)) + if (DSPSignalNotification::match(message)) { - FileSource::MsgSampleRateNotification& notif = (FileSource::MsgSampleRateNotification&) message; + DSPSignalNotification& notif = (DSPSignalNotification&) message; + m_deviceCenterFrequency = notif.getCenterFrequency(); m_sampleRate = notif.getSampleRate(); + updateAbsoluteCenterFrequency(); displayRateAndShift(); return true; } @@ -165,6 +177,7 @@ FileSourceGUI::FileSourceGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, Bas ui(new Ui::FileSourceGUI), m_pluginAPI(pluginAPI), m_deviceUISet(deviceUISet), + m_deviceCenterFrequency(0), m_sampleRate(0), m_shiftFrequencyFactor(0.0), m_fileSampleRate(0), @@ -177,16 +190,17 @@ FileSourceGUI::FileSourceGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, Bas m_doApplySettings(true), m_tickCount(0) { - (void) channelTx; - - ui->setupUi(this); - m_helpURL = "plugins/channeltx/filesource/readme.md"; - ui->channelPowerMeter->setColorTheme(LevelMeterSignalDB::ColorGreenAndBlue); - setAttribute(Qt::WA_DeleteOnClose, true); - connect(this, SIGNAL(widgetRolled(QWidget*,bool)), this, SLOT(onWidgetRolled(QWidget*,bool))); + m_helpURL = "plugins/channeltx/filesource/readme.md"; + RollupContents *rollupContents = getRollupContents(); + ui->setupUi(rollupContents); + setSizePolicy(rollupContents->sizePolicy()); + rollupContents->arrangeRollups(); + connect(rollupContents, SIGNAL(widgetRolled(QWidget*,bool)), this, SLOT(onWidgetRolled(QWidget*,bool))); connect(this, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(onMenuDialogCalled(const QPoint &))); + ui->channelPowerMeter->setColorTheme(LevelMeterSignalDB::ColorGreenAndBlue); + m_fileSource = (FileSource*) channelTx; m_fileSource->setMessageQueueToGUI(getInputMessageQueue()); @@ -205,12 +219,12 @@ FileSourceGUI::FileSourceGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, Bas m_settings.setRollupState(&m_rollupState); m_deviceUISet->addChannelMarker(&m_channelMarker); - m_deviceUISet->addRollupWidget(this); connect(&m_channelMarker, SIGNAL(changedByCursor()), this, SLOT(channelMarkerChangedByCursor())); connect(getInputMessageQueue(), SIGNAL(messageEnqueued()), this, SLOT(handleSourceMessages())); displaySettings(); + makeUIConnections(); applySettings(true); } @@ -302,7 +316,9 @@ void FileSourceGUI::displaySettings() setTitleColor(m_settings.m_rgbColor); setWindowTitle(m_channelMarker.getTitle()); - displayStreamIndex(); + setTitle(m_channelMarker.getTitle()); + + updateIndexLabel(); blockApplySettings(true); ui->fileNameText->setText(m_settings.m_fileName); @@ -310,7 +326,8 @@ void FileSourceGUI::displaySettings() ui->gainText->setText(tr("%1 dB").arg(m_settings.m_gainDB)); ui->interpolationFactor->setCurrentIndex(m_settings.m_log2Interp); applyInterpolation(); - restoreState(m_rollupState); + getRollupContents()->restoreState(m_rollupState); + updateAbsoluteCenterFrequency(); blockApplySettings(false); } @@ -325,23 +342,16 @@ void FileSourceGUI::displayRateAndShift() m_channelMarker.setBandwidth(channelSampleRate); } -void FileSourceGUI::displayStreamIndex() -{ - if (m_deviceUISet->m_deviceMIMOEngine) { - setStreamIndicator(tr("%1").arg(m_settings.m_streamIndex)); - } else { - setStreamIndicator("S"); // single channel indicator - } -} - -void FileSourceGUI::leaveEvent(QEvent*) +void FileSourceGUI::leaveEvent(QEvent* event) { m_channelMarker.setHighlighted(false); + ChannelGUI::leaveEvent(event); } -void FileSourceGUI::enterEvent(QEvent*) +void FileSourceGUI::enterEvent(QEvent* event) { m_channelMarker.setHighlighted(true); + ChannelGUI::enterEvent(event); } void FileSourceGUI::handleSourceMessages() @@ -362,7 +372,7 @@ void FileSourceGUI::onWidgetRolled(QWidget* widget, bool rollDown) (void) widget; (void) rollDown; - saveState(m_rollupState); + getRollupContents()->saveState(m_rollupState); applySettings(); } @@ -376,6 +386,13 @@ void FileSourceGUI::onMenuDialogCalled(const QPoint &p) dialog.setReverseAPIPort(m_settings.m_reverseAPIPort); dialog.setReverseAPIDeviceIndex(m_settings.m_reverseAPIDeviceIndex); dialog.setReverseAPIChannelIndex(m_settings.m_reverseAPIChannelIndex); + dialog.setDefaultTitle(m_displayedName); + + if (m_deviceUISet->m_deviceMIMOEngine) + { + dialog.setNumberOfStreams(m_fileSource->getNumberOfDeviceStreams()); + dialog.setStreamIndex(m_settings.m_streamIndex); + } dialog.move(p); dialog.exec(); @@ -391,20 +408,14 @@ void FileSourceGUI::onMenuDialogCalled(const QPoint &p) setWindowTitle(m_settings.m_title); setTitleColor(m_settings.m_rgbColor); - applySettings(); - } - else if ((m_contextMenuType == ContextMenuStreamSettings) && (m_deviceUISet->m_deviceMIMOEngine)) - { - DeviceStreamSelectionDialog dialog(this); - dialog.setNumberOfStreams(m_fileSource->getNumberOfDeviceStreams()); - dialog.setStreamIndex(m_settings.m_streamIndex); - dialog.move(p); - dialog.exec(); + if (m_deviceUISet->m_deviceMIMOEngine) + { + m_settings.m_streamIndex = dialog.getSelectedStreamIndex(); + m_channelMarker.clearStreamIndexes(); + m_channelMarker.addStreamIndex(m_settings.m_streamIndex); + updateIndexLabel(); + } - m_settings.m_streamIndex = dialog.getSelectedStreamIndex(); - m_channelMarker.clearStreamIndexes(); - m_channelMarker.addStreamIndex(m_settings.m_streamIndex); - displayStreamIndex(); applySettings(); } @@ -493,6 +504,7 @@ void FileSourceGUI::applyPosition() m_shiftFrequencyFactor = HBFilterChainConverter::convertToString(m_settings.m_log2Interp, m_settings.m_filterChainHash, s); ui->filterChainText->setText(s); + updateAbsoluteCenterFrequency(); displayRateAndShift(); applySettings(); } @@ -525,3 +537,20 @@ void FileSourceGUI::tick() void FileSourceGUI::channelMarkerChangedByCursor() { } + +void FileSourceGUI::makeUIConnections() +{ + QObject::connect(ui->interpolationFactor, QOverload::of(&QComboBox::currentIndexChanged), this, &FileSourceGUI::on_interpolationFactor_currentIndexChanged); + QObject::connect(ui->position, &QSlider::valueChanged, this, &FileSourceGUI::on_position_valueChanged); + QObject::connect(ui->gain, &QSlider::valueChanged, this, &FileSourceGUI::on_gain_valueChanged); + QObject::connect(ui->showFileDialog, &QPushButton::clicked, this, &FileSourceGUI::on_showFileDialog_clicked); + QObject::connect(ui->playLoop, &ButtonSwitch::toggled, this, &FileSourceGUI::on_playLoop_toggled); + QObject::connect(ui->play, &ButtonSwitch::toggled, this, &FileSourceGUI::on_play_toggled); + QObject::connect(ui->navTime, &QSlider::valueChanged, this, &FileSourceGUI::on_navTime_valueChanged); +} + +void FileSourceGUI::updateAbsoluteCenterFrequency() +{ + int shift = m_shiftFrequencyFactor * m_sampleRate; + setStatusFrequency(m_deviceCenterFrequency + shift); +} diff --git a/plugins/channeltx/filesource/filesourcegui.h b/plugins/channeltx/filesource/filesourcegui.h index 2e03655ca..640000b8c 100644 --- a/plugins/channeltx/filesource/filesourcegui.h +++ b/plugins/channeltx/filesource/filesourcegui.h @@ -45,10 +45,24 @@ public: QByteArray serialize() const; bool deserialize(const QByteArray& data); virtual MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; } + virtual void setWorkspaceIndex(int index) { m_settings.m_workspaceIndex = index; }; + virtual int getWorkspaceIndex() const { return m_settings.m_workspaceIndex; }; + virtual void setGeometryBytes(const QByteArray& blob) { m_settings.m_geometryBytes = blob; }; + virtual QByteArray getGeometryBytes() const { return m_settings.m_geometryBytes; }; + virtual QString getTitle() const { return m_settings.m_title; }; + virtual QColor getTitleColor() const { return m_settings.m_rgbColor; }; + virtual void zetHidden(bool hidden) { m_settings.m_hidden = hidden; } + virtual bool getHidden() const { return m_settings.m_hidden; } + virtual ChannelMarker& getChannelMarker() { return m_channelMarker; } + virtual int getStreamIndex() const { return m_settings.m_streamIndex; } + virtual void setStreamIndex(int streamIndex) { m_settings.m_streamIndex = streamIndex; } public slots: void channelMarkerChangedByCursor(); +protected: + void resizeEvent(QResizeEvent* size); + private: Ui::FileSourceGUI* ui; PluginAPI* m_pluginAPI; @@ -56,6 +70,7 @@ private: ChannelMarker m_channelMarker; RollupState m_rollupState; FileSourceSettings m_settings; + qint64 m_deviceCenterFrequency; int m_sampleRate; double m_shiftFrequencyFactor; //!< Channel frequency shift factor int m_fileSampleRate; @@ -83,8 +98,9 @@ private: void updateWithStreamTime(); void displaySettings(); void displayRateAndShift(); - void displayStreamIndex(); bool handleMessage(const Message& message); + void makeUIConnections(); + void updateAbsoluteCenterFrequency(); void leaveEvent(QEvent*); void enterEvent(QEvent*); diff --git a/plugins/channeltx/filesource/filesourcegui.ui b/plugins/channeltx/filesource/filesourcegui.ui index eaaeee84a..43a157b87 100644 --- a/plugins/channeltx/filesource/filesourcegui.ui +++ b/plugins/channeltx/filesource/filesourcegui.ui @@ -1,7 +1,7 @@ FileSourceGUI - + 0 @@ -11,7 +11,7 @@ - + 0 0 @@ -22,6 +22,12 @@ 140 + + + 560 + 16777215 + + Liberation Sans @@ -416,6 +422,7 @@ + Liberation Sans 9 @@ -447,6 +454,7 @@ + Liberation Sans 9 @@ -472,6 +480,7 @@ + Liberation Sans 9 @@ -696,22 +705,22 @@ - RollupWidget + RollupContents QWidget -
gui/rollupwidget.h
+
gui/rollupcontents.h
1
- - ButtonSwitch - QToolButton -
gui/buttonswitch.h
-
LevelMeterSignalDB QWidget
gui/levelmeter.h
1
+ + ButtonSwitch + QToolButton +
gui/buttonswitch.h
+
diff --git a/plugins/channeltx/filesource/filesourcesettings.cpp b/plugins/channeltx/filesource/filesourcesettings.cpp index 019e4bd1e..0a181dd36 100644 --- a/plugins/channeltx/filesource/filesourcesettings.cpp +++ b/plugins/channeltx/filesource/filesourcesettings.cpp @@ -45,6 +45,8 @@ void FileSourceSettings::resetToDefaults() m_reverseAPIPort = 8888; m_reverseAPIDeviceIndex = 0; m_reverseAPIChannelIndex = 0; + m_workspaceIndex = 0; + m_hidden = false; } QByteArray FileSourceSettings::serialize() const @@ -72,6 +74,10 @@ QByteArray FileSourceSettings::serialize() const s.writeBlob(15, m_channelMarker->serialize()); } + s.writeS32(16, m_workspaceIndex); + s.writeBlob(17, m_geometryBytes); + s.writeBool(18, m_hidden); + return s.final(); } @@ -129,6 +135,10 @@ bool FileSourceSettings::deserialize(const QByteArray& data) m_channelMarker->deserialize(bytetmp); } + d.readS32(16, &m_workspaceIndex, 0); + d.readBlob(17, &m_geometryBytes); + d.readBool(18, &m_hidden, false); + return true; } else diff --git a/plugins/channeltx/filesource/filesourcesettings.h b/plugins/channeltx/filesource/filesourcesettings.h index 8225ce4c9..34c5cf882 100644 --- a/plugins/channeltx/filesource/filesourcesettings.h +++ b/plugins/channeltx/filesource/filesourcesettings.h @@ -38,6 +38,9 @@ struct FileSourceSettings uint16_t m_reverseAPIPort; uint16_t m_reverseAPIDeviceIndex; uint16_t m_reverseAPIChannelIndex; + int m_workspaceIndex; + QByteArray m_geometryBytes; + bool m_hidden; Serializable *m_channelMarker; Serializable *m_rollupState; diff --git a/plugins/channeltx/filesource/readme.md b/plugins/channeltx/filesource/readme.md index be7ee073d..1173322ec 100644 --- a/plugins/channeltx/filesource/readme.md +++ b/plugins/channeltx/filesource/readme.md @@ -50,6 +50,8 @@ The I/Q samples are copied to the baseband to be transmitted by the sink output

Interface

+The top and bottom bars of the channel window are described [here](../../../sdrgui/channel/readme.md) + ![File source channel plugin GUI](../../../doc/img/FileSource_plugin.png)

1: Interpolation factor

diff --git a/plugins/channeltx/localsource/localsource.cpp b/plugins/channeltx/localsource/localsource.cpp index 99898a739..84b5bcaec 100644 --- a/plugins/channeltx/localsource/localsource.cpp +++ b/plugins/channeltx/localsource/localsource.cpp @@ -23,6 +23,7 @@ #include #include "SWGChannelSettings.h" +#include "SWGWorkspaceInfo.h" #include "util/simpleserializer.h" #include "dsp/dspcommands.h" @@ -38,7 +39,6 @@ #include "localsourcebaseband.h" MESSAGE_CLASS_DEFINITION(LocalSource::MsgConfigureLocalSource, Message) -MESSAGE_CLASS_DEFINITION(LocalSource::MsgBasebandSampleRateNotification, Message) const char* const LocalSource::m_channelIdURI = "sdrangel.channel.localsource"; const char* const LocalSource::m_channelId = "LocalSource"; @@ -85,6 +85,18 @@ LocalSource::~LocalSource() delete m_thread; } +void LocalSource::setDeviceAPI(DeviceAPI *deviceAPI) +{ + if (deviceAPI != m_deviceAPI) + { + m_deviceAPI->removeChannelSourceAPI(this); + m_deviceAPI->removeChannelSource(this); + m_deviceAPI = deviceAPI; + m_deviceAPI->addChannelSource(this); + m_deviceAPI->addChannelSinkAPI(this); + } +} + void LocalSource::start() { qDebug("LocalSource::start"); @@ -122,10 +134,8 @@ bool LocalSource::handleMessage(const Message& cmd) DSPSignalNotification *msg = new DSPSignalNotification(cfg.getSampleRate(), cfg.getCenterFrequency()); m_basebandSource->getInputMessageQueue()->push(msg); - if (m_guiMessageQueue) - { - MsgBasebandSampleRateNotification *msg = MsgBasebandSampleRateNotification::create(cfg.getSampleRate()); - m_guiMessageQueue->push(msg); + if (m_guiMessageQueue) { + m_guiMessageQueue->push(new DSPSignalNotification(cfg)); } return true; @@ -356,6 +366,15 @@ int LocalSource::webapiSettingsGet( return 200; } +int LocalSource::webapiWorkspaceGet( + SWGSDRangel::SWGWorkspaceInfo& response, + QString& errorMessage) +{ + (void) errorMessage; + response.setIndex(m_settings.m_workspaceIndex); + return 200; +} + int LocalSource::webapiSettingsPutPatch( bool force, const QStringList& channelSettingsKeys, diff --git a/plugins/channeltx/localsource/localsource.h b/plugins/channeltx/localsource/localsource.h index 76639d3ea..9ee878cc6 100644 --- a/plugins/channeltx/localsource/localsource.h +++ b/plugins/channeltx/localsource/localsource.h @@ -60,29 +60,11 @@ public: { } }; - class MsgBasebandSampleRateNotification : public Message { - MESSAGE_CLASS_DECLARATION - - public: - static MsgBasebandSampleRateNotification* create(int sampleRate) { - return new MsgBasebandSampleRateNotification(sampleRate); - } - - int getBasebandSampleRate() const { return m_sampleRate; } - - private: - - MsgBasebandSampleRateNotification(int sampleRate) : - Message(), - m_sampleRate(sampleRate) - { } - - int m_sampleRate; - }; - LocalSource(DeviceAPI *deviceAPI); virtual ~LocalSource(); virtual void destroy() { delete this; } + virtual void setDeviceAPI(DeviceAPI *deviceAPI); + virtual DeviceAPI *getDeviceAPI() { return m_deviceAPI; } virtual void start(); virtual void stop(); @@ -113,6 +95,10 @@ public: SWGSDRangel::SWGChannelSettings& response, QString& errorMessage); + virtual int webapiWorkspaceGet( + SWGSDRangel::SWGWorkspaceInfo& response, + QString& errorMessage); + virtual int webapiSettingsPutPatch( bool force, const QStringList& channelSettingsKeys, diff --git a/plugins/channeltx/localsource/localsourcegui.cpp b/plugins/channeltx/localsource/localsourcegui.cpp index f6a7a7fd1..4c028620c 100644 --- a/plugins/channeltx/localsource/localsourcegui.cpp +++ b/plugins/channeltx/localsource/localsourcegui.cpp @@ -16,11 +16,13 @@ /////////////////////////////////////////////////////////////////////////////////// #include +#include #include "device/deviceuiset.h" #include "gui/basicchannelsettingsdialog.h" #include "gui/devicestreamselectiondialog.h" #include "dsp/hbfilterchainconverter.h" +#include "dsp/dspcommands.h" #include "mainwindow.h" #include "localsourcegui.h" @@ -62,12 +64,22 @@ bool LocalSourceGUI::deserialize(const QByteArray& data) } } +void LocalSourceGUI::resizeEvent(QResizeEvent* size) +{ + int maxWidth = getRollupContents()->maximumWidth(); + int minHeight = getRollupContents()->minimumHeight() + getAdditionalHeight(); + resize(width() < maxWidth ? width() : maxWidth, minHeight); + size->accept(); +} + bool LocalSourceGUI::handleMessage(const Message& message) { - if (LocalSource::MsgBasebandSampleRateNotification::match(message)) + if (DSPSignalNotification::match(message)) { - LocalSource::MsgBasebandSampleRateNotification& notif = (LocalSource::MsgBasebandSampleRateNotification&) message; - m_basebandSampleRate = notif.getBasebandSampleRate(); + DSPSignalNotification& notif = (DSPSignalNotification&) message; + m_deviceCenterFrequency = notif.getCenterFrequency(); + m_basebandSampleRate = notif.getSampleRate(); + updateAbsoluteCenterFrequency(); displayRateAndShift(); return true; } @@ -93,12 +105,16 @@ LocalSourceGUI::LocalSourceGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, B m_pluginAPI(pluginAPI), m_deviceUISet(deviceUISet), m_basebandSampleRate(0), + m_deviceCenterFrequency(0), m_tickCount(0) { - ui->setupUi(this); - m_helpURL = "plugins/channeltx/localsource/readme.md"; setAttribute(Qt::WA_DeleteOnClose, true); - connect(this, SIGNAL(widgetRolled(QWidget*,bool)), this, SLOT(onWidgetRolled(QWidget*,bool))); + m_helpURL = "plugins/channeltx/localsource/readme.md"; + RollupContents *rollupContents = getRollupContents(); + ui->setupUi(rollupContents); + setSizePolicy(rollupContents->sizePolicy()); + rollupContents->arrangeRollups(); + connect(rollupContents, SIGNAL(widgetRolled(QWidget*,bool)), this, SLOT(onWidgetRolled(QWidget*,bool))); connect(this, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(onMenuDialogCalled(const QPoint &))); m_localSource = (LocalSource*) channeltx; @@ -116,12 +132,12 @@ LocalSourceGUI::LocalSourceGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, B m_settings.setRollupState(&m_rollupState); m_deviceUISet->addChannelMarker(&m_channelMarker); - m_deviceUISet->addRollupWidget(this); connect(getInputMessageQueue(), SIGNAL(messageEnqueued()), this, SLOT(handleSourceMessages())); updateLocalDevices(); displaySettings(); + makeUIConnections(); applySettings(true); } @@ -158,13 +174,15 @@ void LocalSourceGUI::displaySettings() setTitleColor(m_settings.m_rgbColor); setWindowTitle(m_channelMarker.getTitle()); - displayStreamIndex(); + setTitle(m_channelMarker.getTitle()); + updateIndexLabel(); blockApplySettings(true); ui->interpolationFactor->setCurrentIndex(m_settings.m_log2Interp); ui->localDevicePlay->setChecked(m_settings.m_play); applyInterpolation(); - restoreState(m_rollupState); + getRollupContents()->restoreState(m_rollupState); + updateAbsoluteCenterFrequency(); blockApplySettings(false); } @@ -179,15 +197,6 @@ void LocalSourceGUI::displayRateAndShift() m_channelMarker.setBandwidth(channelSampleRate); } -void LocalSourceGUI::displayStreamIndex() -{ - if (m_deviceUISet->m_deviceMIMOEngine) { - setStreamIndicator(tr("%1").arg(m_settings.m_streamIndex)); - } else { - setStreamIndicator("S"); // single channel indicator - } -} - void LocalSourceGUI::updateLocalDevices() { std::vector localDevicesIndexes; @@ -200,14 +209,16 @@ void LocalSourceGUI::updateLocalDevices() } } -void LocalSourceGUI::leaveEvent(QEvent*) +void LocalSourceGUI::leaveEvent(QEvent* event) { m_channelMarker.setHighlighted(false); + ChannelGUI::leaveEvent(event); } -void LocalSourceGUI::enterEvent(QEvent*) +void LocalSourceGUI::enterEvent(QEvent* event) { m_channelMarker.setHighlighted(true); + ChannelGUI::enterEvent(event); } void LocalSourceGUI::handleSourceMessages() @@ -228,7 +239,7 @@ void LocalSourceGUI::onWidgetRolled(QWidget* widget, bool rollDown) (void) widget; (void) rollDown; - saveState(m_rollupState); + getRollupContents()->saveState(m_rollupState); applySettings(); } @@ -242,6 +253,13 @@ void LocalSourceGUI::onMenuDialogCalled(const QPoint &p) dialog.setReverseAPIPort(m_settings.m_reverseAPIPort); dialog.setReverseAPIDeviceIndex(m_settings.m_reverseAPIDeviceIndex); dialog.setReverseAPIChannelIndex(m_settings.m_reverseAPIChannelIndex); + dialog.setDefaultTitle(m_displayedName); + + if (m_deviceUISet->m_deviceMIMOEngine) + { + dialog.setNumberOfStreams(m_localSource->getNumberOfDeviceStreams()); + dialog.setStreamIndex(m_settings.m_streamIndex); + } dialog.move(p); dialog.exec(); @@ -255,22 +273,17 @@ void LocalSourceGUI::onMenuDialogCalled(const QPoint &p) m_settings.m_reverseAPIChannelIndex = dialog.getReverseAPIChannelIndex(); setWindowTitle(m_settings.m_title); + setTitle(m_channelMarker.getTitle()); setTitleColor(m_settings.m_rgbColor); - applySettings(); - } - else if ((m_contextMenuType == ContextMenuStreamSettings) && (m_deviceUISet->m_deviceMIMOEngine)) - { - DeviceStreamSelectionDialog dialog(this); - dialog.setNumberOfStreams(m_localSource->getNumberOfDeviceStreams()); - dialog.setStreamIndex(m_settings.m_streamIndex); - dialog.move(p); - dialog.exec(); + if (m_deviceUISet->m_deviceMIMOEngine) + { + m_settings.m_streamIndex = dialog.getSelectedStreamIndex(); + m_channelMarker.clearStreamIndexes(); + m_channelMarker.addStreamIndex(m_settings.m_streamIndex); + updateIndexLabel(); + } - m_settings.m_streamIndex = dialog.getSelectedStreamIndex(); - m_channelMarker.clearStreamIndexes(); - m_channelMarker.addStreamIndex(m_settings.m_streamIndex); - displayStreamIndex(); applySettings(); } @@ -328,6 +341,7 @@ void LocalSourceGUI::applyPosition() m_shiftFrequencyFactor = HBFilterChainConverter::convertToString(m_settings.m_log2Interp, m_settings.m_filterChainHash, s); ui->filterChainText->setText(s); + updateAbsoluteCenterFrequency(); displayRateAndShift(); applySettings(); } @@ -338,3 +352,18 @@ void LocalSourceGUI::tick() m_tickCount = 0; } } + +void LocalSourceGUI::makeUIConnections() +{ + QObject::connect(ui->interpolationFactor, QOverload::of(&QComboBox::currentIndexChanged), this, &LocalSourceGUI::on_interpolationFactor_currentIndexChanged); + QObject::connect(ui->position, &QSlider::valueChanged, this, &LocalSourceGUI::on_position_valueChanged); + QObject::connect(ui->localDevice, QOverload::of(&QComboBox::currentIndexChanged), this, &LocalSourceGUI::on_localDevice_currentIndexChanged); + QObject::connect(ui->localDevicesRefresh, &QPushButton::clicked, this, &LocalSourceGUI::on_localDevicesRefresh_clicked); + QObject::connect(ui->localDevicePlay, &ButtonSwitch::toggled, this, &LocalSourceGUI::on_localDevicePlay_toggled); +} + +void LocalSourceGUI::updateAbsoluteCenterFrequency() +{ + int shift = m_shiftFrequencyFactor * m_basebandSampleRate; + setStatusFrequency(m_deviceCenterFrequency + shift); +} diff --git a/plugins/channeltx/localsource/localsourcegui.h b/plugins/channeltx/localsource/localsourcegui.h index c106998ac..890874924 100644 --- a/plugins/channeltx/localsource/localsourcegui.h +++ b/plugins/channeltx/localsource/localsourcegui.h @@ -48,6 +48,20 @@ public: QByteArray serialize() const; bool deserialize(const QByteArray& data); virtual MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; } + virtual void setWorkspaceIndex(int index) { m_settings.m_workspaceIndex = index; }; + virtual int getWorkspaceIndex() const { return m_settings.m_workspaceIndex; }; + virtual void setGeometryBytes(const QByteArray& blob) { m_settings.m_geometryBytes = blob; }; + virtual QByteArray getGeometryBytes() const { return m_settings.m_geometryBytes; }; + virtual QString getTitle() const { return m_settings.m_title; }; + virtual QColor getTitleColor() const { return m_settings.m_rgbColor; }; + virtual void zetHidden(bool hidden) { m_settings.m_hidden = hidden; } + virtual bool getHidden() const { return m_settings.m_hidden; } + virtual ChannelMarker& getChannelMarker() { return m_channelMarker; } + virtual int getStreamIndex() const { return m_settings.m_streamIndex; } + virtual void setStreamIndex(int streamIndex) { m_settings.m_streamIndex = streamIndex; } + +protected: + void resizeEvent(QResizeEvent* size); private: Ui::LocalSourceGUI* ui; @@ -73,9 +87,10 @@ private: void applySettings(bool force = false); void displaySettings(); void displayRateAndShift(); - void displayStreamIndex(); void updateLocalDevices(); bool handleMessage(const Message& message); + void makeUIConnections(); + void updateAbsoluteCenterFrequency(); void leaveEvent(QEvent*); void enterEvent(QEvent*); diff --git a/plugins/channeltx/localsource/localsourcegui.ui b/plugins/channeltx/localsource/localsourcegui.ui index b62c51e3b..e54ccc920 100644 --- a/plugins/channeltx/localsource/localsourcegui.ui +++ b/plugins/channeltx/localsource/localsourcegui.ui @@ -1,7 +1,7 @@ LocalSourceGUI - + 0 @@ -11,7 +11,7 @@ - + 0 0 @@ -24,7 +24,7 @@ - 320 + 560 16777215 @@ -330,9 +330,9 @@ - RollupWidget + RollupContents QWidget -
gui/rollupwidget.h
+
gui/rollupcontents.h
1
diff --git a/plugins/channeltx/localsource/localsourcesettings.cpp b/plugins/channeltx/localsource/localsourcesettings.cpp index a5d7dea51..88754eb73 100644 --- a/plugins/channeltx/localsource/localsourcesettings.cpp +++ b/plugins/channeltx/localsource/localsourcesettings.cpp @@ -44,6 +44,8 @@ void LocalSourceSettings::resetToDefaults() m_reverseAPIPort = 8888; m_reverseAPIDeviceIndex = 0; m_reverseAPIChannelIndex = 0; + m_workspaceIndex = 0; + m_hidden = false; } QByteArray LocalSourceSettings::serialize() const @@ -69,6 +71,10 @@ QByteArray LocalSourceSettings::serialize() const s.writeBlob(16, m_channelMarker->serialize()); } + s.writeS32(17, m_workspaceIndex); + s.writeBlob(18, m_geometryBytes); + s.writeBool(19, m_hidden); + return s.final(); } @@ -122,6 +128,10 @@ bool LocalSourceSettings::deserialize(const QByteArray& data) m_channelMarker->deserialize(bytetmp); } + d.readS32(17, &m_workspaceIndex, 0); + d.readBlob(18, &m_geometryBytes); + d.readBool(19, &m_hidden, false); + return true; } else diff --git a/plugins/channeltx/localsource/localsourcesettings.h b/plugins/channeltx/localsource/localsourcesettings.h index 81740e0bd..f68b7e47f 100644 --- a/plugins/channeltx/localsource/localsourcesettings.h +++ b/plugins/channeltx/localsource/localsourcesettings.h @@ -37,6 +37,9 @@ struct LocalSourceSettings uint16_t m_reverseAPIPort; uint16_t m_reverseAPIDeviceIndex; uint16_t m_reverseAPIChannelIndex; + int m_workspaceIndex; + QByteArray m_geometryBytes; + bool m_hidden; Serializable *m_channelMarker; Serializable *m_rollupState; diff --git a/plugins/channeltx/localsource/readme.md b/plugins/channeltx/localsource/readme.md index 1259484da..83447c219 100644 --- a/plugins/channeltx/localsource/readme.md +++ b/plugins/channeltx/localsource/readme.md @@ -10,6 +10,8 @@ Note that because it uses only the channelizer half band filter chain to achieve

Interface

+The top and bottom bars of the channel window are described [here](../../../sdrgui/channel/readme.md) + ![Local source channel plugin GUI](../../../doc/img/LocalSource.png)

1: Interpolation factor

diff --git a/plugins/channeltx/mod802.15.4/ieee_802_15_4_mod.cpp b/plugins/channeltx/mod802.15.4/ieee_802_15_4_mod.cpp index 8138c9078..5bd158a84 100644 --- a/plugins/channeltx/mod802.15.4/ieee_802_15_4_mod.cpp +++ b/plugins/channeltx/mod802.15.4/ieee_802_15_4_mod.cpp @@ -27,11 +27,11 @@ #include #include "SWGChannelSettings.h" +#include "SWGWorkspaceInfo.h" #include "SWGChannelReport.h" #include "SWGChannelActions.h" #include "SWGIEEE_802_15_4_ModReport.h" #include "SWGIEEE_802_15_4_ModActions.h" -#include "SWGIEEE_802_15_4_ModActions_tx.h" #include #include @@ -97,6 +97,18 @@ IEEE_802_15_4_Mod::~IEEE_802_15_4_Mod() delete m_thread; } +void IEEE_802_15_4_Mod::setDeviceAPI(DeviceAPI *deviceAPI) +{ + if (deviceAPI != m_deviceAPI) + { + m_deviceAPI->removeChannelSourceAPI(this); + m_deviceAPI->removeChannelSource(this); + m_deviceAPI = deviceAPI; + m_deviceAPI->addChannelSource(this); + m_deviceAPI->addChannelSinkAPI(this); + } +} + void IEEE_802_15_4_Mod::start() { qDebug("IEEE_802_15_4_Mod::start"); @@ -145,10 +157,8 @@ bool IEEE_802_15_4_Mod::handleMessage(const Message& cmd) m_basebandSource->getInputMessageQueue()->push(rep); // Forward to GUI - if (getMessageQueueToGUI()) - { - DSPSignalNotification *notifToGUI = new DSPSignalNotification(notif); - getMessageQueueToGUI()->push(notifToGUI); + if (getMessageQueueToGUI()) { + getMessageQueueToGUI()->push(new DSPSignalNotification(notif)); } return true; @@ -428,6 +438,15 @@ int IEEE_802_15_4_Mod::webapiSettingsGet( return 200; } +int IEEE_802_15_4_Mod::webapiWorkspaceGet( + SWGSDRangel::SWGWorkspaceInfo& response, + QString& errorMessage) +{ + (void) errorMessage; + response.setIndex(m_settings.m_workspaceIndex); + return 200; +} + int IEEE_802_15_4_Mod::webapiSettingsPutPatch( bool force, const QStringList& channelSettingsKeys, diff --git a/plugins/channeltx/mod802.15.4/ieee_802_15_4_mod.h b/plugins/channeltx/mod802.15.4/ieee_802_15_4_mod.h index 8068e7f67..0c168aadd 100644 --- a/plugins/channeltx/mod802.15.4/ieee_802_15_4_mod.h +++ b/plugins/channeltx/mod802.15.4/ieee_802_15_4_mod.h @@ -91,6 +91,8 @@ public: IEEE_802_15_4_Mod(DeviceAPI *deviceAPI); ~IEEE_802_15_4_Mod(); virtual void destroy() { delete this; } + virtual void setDeviceAPI(DeviceAPI *deviceAPI); + virtual DeviceAPI *getDeviceAPI() { return m_deviceAPI; } virtual void start(); virtual void stop(); @@ -121,6 +123,10 @@ public: SWGSDRangel::SWGChannelSettings& response, QString& errorMessage); + virtual int webapiWorkspaceGet( + SWGSDRangel::SWGWorkspaceInfo& response, + QString& errorMessage); + virtual int webapiSettingsPutPatch( bool force, const QStringList& channelSettingsKeys, diff --git a/plugins/channeltx/mod802.15.4/ieee_802_15_4_modgui.cpp b/plugins/channeltx/mod802.15.4/ieee_802_15_4_modgui.cpp index 773a8fcf1..ae3dddd83 100644 --- a/plugins/channeltx/mod802.15.4/ieee_802_15_4_modgui.cpp +++ b/plugins/channeltx/mod802.15.4/ieee_802_15_4_modgui.cpp @@ -104,7 +104,11 @@ bool IEEE_802_15_4_ModGUI::handleMessage(const Message& message) if (DSPSignalNotification::match(message)) { DSPSignalNotification& notif = (DSPSignalNotification&) message; + m_deviceCenterFrequency = notif.getCenterFrequency(); m_basebandSampleRate = notif.getSampleRate(); + ui->deltaFrequency->setValueRange(false, 7, -m_basebandSampleRate/2, m_basebandSampleRate/2); + ui->deltaFrequencyLabel->setToolTip(tr("Range %1 %L2 Hz").arg(QChar(0xB1)).arg(m_basebandSampleRate/2)); + updateAbsoluteCenterFrequency(); m_scopeVis->setLiveRate(m_basebandSampleRate); checkSampleRate(); return true; @@ -172,6 +176,7 @@ void IEEE_802_15_4_ModGUI::on_deltaFrequency_changed(qint64 value) { m_channelMarker.setCenterFrequency(value); m_settings.m_inputFrequencyOffset = m_channelMarker.getCenterFrequency(); + updateAbsoluteCenterFrequency(); applySettings(); } @@ -310,18 +315,23 @@ void IEEE_802_15_4_ModGUI::on_udpPort_editingFinished() applySettings(); } -void IEEE_802_15_4_ModGUI::on_udpBytesFormat_clicked(bool checked) -{ - m_settings.m_udpBytesFormat = checked; - applySettings(); -} - void IEEE_802_15_4_ModGUI::onWidgetRolled(QWidget* widget, bool rollDown) { (void) widget; (void) rollDown; - saveState(m_rollupState); + RollupContents *rollupContents = getRollupContents(); + + if (rollupContents->hasExpandableWidgets()) { + setSizePolicy(sizePolicy().horizontalPolicy(), QSizePolicy::Expanding); + } else { + setSizePolicy(sizePolicy().horizontalPolicy(), QSizePolicy::Fixed); + } + + int h = rollupContents->height() + getAdditionalHeight(); + resize(width(), h); + + rollupContents->saveState(m_rollupState); applySettings(); } @@ -335,10 +345,17 @@ void IEEE_802_15_4_ModGUI::onMenuDialogCalled(const QPoint &p) dialog.setReverseAPIPort(m_settings.m_reverseAPIPort); dialog.setReverseAPIDeviceIndex(m_settings.m_reverseAPIDeviceIndex); dialog.setReverseAPIChannelIndex(m_settings.m_reverseAPIChannelIndex); + dialog.setDefaultTitle(m_displayedName); + + if (m_deviceUISet->m_deviceMIMOEngine) + { + dialog.setNumberOfStreams(m_IEEE_802_15_4_Mod->getNumberOfDeviceStreams()); + dialog.setStreamIndex(m_settings.m_streamIndex); + } + dialog.move(p); dialog.exec(); - m_settings.m_inputFrequencyOffset = m_channelMarker.getCenterFrequency(); m_settings.m_rgbColor = m_channelMarker.getColor().rgb(); m_settings.m_title = m_channelMarker.getTitle(); m_settings.m_useReverseAPI = dialog.useReverseAPI(); @@ -348,22 +365,17 @@ void IEEE_802_15_4_ModGUI::onMenuDialogCalled(const QPoint &p) m_settings.m_reverseAPIChannelIndex = dialog.getReverseAPIChannelIndex(); setWindowTitle(m_settings.m_title); + setTitle(m_channelMarker.getTitle()); setTitleColor(m_settings.m_rgbColor); - applySettings(); - } - else if ((m_contextMenuType == ContextMenuStreamSettings) && (m_deviceUISet->m_deviceMIMOEngine)) - { - DeviceStreamSelectionDialog dialog(this); - dialog.setNumberOfStreams(m_IEEE_802_15_4_Mod->getNumberOfDeviceStreams()); - dialog.setStreamIndex(m_settings.m_streamIndex); - dialog.move(p); - dialog.exec(); + if (m_deviceUISet->m_deviceMIMOEngine) + { + m_settings.m_streamIndex = dialog.getSelectedStreamIndex(); + m_channelMarker.clearStreamIndexes(); + m_channelMarker.addStreamIndex(m_settings.m_streamIndex); + updateIndexLabel(); + } - m_settings.m_streamIndex = dialog.getSelectedStreamIndex(); - m_channelMarker.clearStreamIndexes(); - m_channelMarker.addStreamIndex(m_settings.m_streamIndex); - displayStreamIndex(); applySettings(); } @@ -376,14 +388,17 @@ IEEE_802_15_4_ModGUI::IEEE_802_15_4_ModGUI(PluginAPI* pluginAPI, DeviceUISet *de m_pluginAPI(pluginAPI), m_deviceUISet(deviceUISet), m_channelMarker(this), + m_deviceCenterFrequency(0), m_doApplySettings(true), m_basebandSampleRate(12000000) { - ui->setupUi(this); - m_helpURL = "plugins/channeltx/mod802.15.4/readme.md"; setAttribute(Qt::WA_DeleteOnClose, true); - - connect(this, SIGNAL(widgetRolled(QWidget*,bool)), this, SLOT(onWidgetRolled(QWidget*,bool))); + m_helpURL = "plugins/channeltx/mod802.15.4/readme.md"; + RollupContents *rollupContents = getRollupContents(); + ui->setupUi(rollupContents); + setSizePolicy(rollupContents->sizePolicy()); + rollupContents->arrangeRollups(); + connect(rollupContents, SIGNAL(widgetRolled(QWidget*,bool)), this, SLOT(onWidgetRolled(QWidget*,bool))); connect(this, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(onMenuDialogCalled(const QPoint &))); m_IEEE_802_15_4_Mod = (IEEE_802_15_4_Mod*) channelTx; @@ -453,7 +468,6 @@ IEEE_802_15_4_ModGUI::IEEE_802_15_4_ModGUI(PluginAPI* pluginAPI, DeviceUISet *de m_channelMarker.setVisible(true); // activate signal on the last setting only m_deviceUISet->addChannelMarker(&m_channelMarker); - m_deviceUISet->addRollupWidget(this); connect(&m_channelMarker, SIGNAL(changedByCursor()), this, SLOT(channelMarkerChangedByCursor())); @@ -466,6 +480,7 @@ IEEE_802_15_4_ModGUI::IEEE_802_15_4_ModGUI(PluginAPI* pluginAPI, DeviceUISet *de ui->spectrumGUI->setBuddies(m_spectrumVis, ui->glSpectrum); displaySettings(); + makeUIConnections(); applySettings(); } @@ -507,7 +522,8 @@ void IEEE_802_15_4_ModGUI::displaySettings() setTitleColor(m_settings.m_rgbColor); setWindowTitle(m_channelMarker.getTitle()); - displayStreamIndex(); + setTitle(m_channelMarker.getTitle()); + updateIndexLabel(); blockApplySettings(true); @@ -567,7 +583,8 @@ void IEEE_802_15_4_ModGUI::displaySettings() ui->udpAddress->setText(m_settings.m_udpAddress); ui->udpPort->setText(QString::number(m_settings.m_udpPort)); - restoreState(m_rollupState); + getRollupContents()->restoreState(m_rollupState); + updateAbsoluteCenterFrequency(); blockApplySettings(false); } @@ -600,23 +617,16 @@ QString IEEE_802_15_4_ModGUI::getDisplayValueWithMultiplier(int value) } } -void IEEE_802_15_4_ModGUI::displayStreamIndex() -{ - if (m_deviceUISet->m_deviceMIMOEngine) { - setStreamIndicator(tr("%1").arg(m_settings.m_streamIndex)); - } else { - setStreamIndicator("S"); // single channel indicator - } -} - -void IEEE_802_15_4_ModGUI::leaveEvent(QEvent*) +void IEEE_802_15_4_ModGUI::leaveEvent(QEvent* event) { m_channelMarker.setHighlighted(false); + ChannelGUI::leaveEvent(event); } -void IEEE_802_15_4_ModGUI::enterEvent(QEvent*) +void IEEE_802_15_4_ModGUI::enterEvent(QEvent* event) { m_channelMarker.setHighlighted(true); + ChannelGUI::enterEvent(event); } void IEEE_802_15_4_ModGUI::tick() @@ -625,3 +635,24 @@ void IEEE_802_15_4_ModGUI::tick() m_channelPowerDbAvg(powDb); ui->channelPower->setText(tr("%1 dB").arg(m_channelPowerDbAvg.asDouble(), 0, 'f', 1)); } + +void IEEE_802_15_4_ModGUI::makeUIConnections() +{ + QObject::connect(ui->deltaFrequency, &ValueDialZ::changed, this, &IEEE_802_15_4_ModGUI::on_deltaFrequency_changed); + QObject::connect(ui->phy, QOverload::of(&QComboBox::currentIndexChanged), this, &IEEE_802_15_4_ModGUI::on_phy_currentIndexChanged); + QObject::connect(ui->rfBW, &QSlider::valueChanged, this, &IEEE_802_15_4_ModGUI::on_rfBW_valueChanged); + QObject::connect(ui->gain, &QDial::valueChanged, this, &IEEE_802_15_4_ModGUI::on_gain_valueChanged); + QObject::connect(ui->channelMute, &QToolButton::toggled, this, &IEEE_802_15_4_ModGUI::on_channelMute_toggled); + QObject::connect(ui->txButton, &QToolButton::clicked, this, &IEEE_802_15_4_ModGUI::on_txButton_clicked); + QObject::connect(ui->frame, &QLineEdit::editingFinished, this, &IEEE_802_15_4_ModGUI::on_frame_editingFinished); + QObject::connect(ui->frame, &QLineEdit::returnPressed, this, &IEEE_802_15_4_ModGUI::on_frame_returnPressed); + QObject::connect(ui->repeat, &ButtonSwitch::toggled, this, &IEEE_802_15_4_ModGUI::on_repeat_toggled); + QObject::connect(ui->udpEnabled, &QCheckBox::clicked, this, &IEEE_802_15_4_ModGUI::on_udpEnabled_clicked); + QObject::connect(ui->udpAddress, &QLineEdit::editingFinished, this, &IEEE_802_15_4_ModGUI::on_udpAddress_editingFinished); + QObject::connect(ui->udpPort, &QLineEdit::editingFinished, this, &IEEE_802_15_4_ModGUI::on_udpPort_editingFinished); +} + +void IEEE_802_15_4_ModGUI::updateAbsoluteCenterFrequency() +{ + setStatusFrequency(m_deviceCenterFrequency + m_settings.m_inputFrequencyOffset); +} diff --git a/plugins/channeltx/mod802.15.4/ieee_802_15_4_modgui.h b/plugins/channeltx/mod802.15.4/ieee_802_15_4_modgui.h index 041928bc4..48ccf3d8c 100644 --- a/plugins/channeltx/mod802.15.4/ieee_802_15_4_modgui.h +++ b/plugins/channeltx/mod802.15.4/ieee_802_15_4_modgui.h @@ -33,7 +33,6 @@ class DeviceUISet; class BasebandSampleSource; class SpectrumVis; class ScopeVis; -class ScopeVisXY; namespace Ui { class IEEE_802_15_4_ModGUI; @@ -55,7 +54,17 @@ public: QByteArray serialize() const; bool deserialize(const QByteArray& data); virtual MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; } - virtual bool handleMessage(const Message& message); + virtual void setWorkspaceIndex(int index) { m_settings.m_workspaceIndex = index; }; + virtual int getWorkspaceIndex() const { return m_settings.m_workspaceIndex; }; + virtual void setGeometryBytes(const QByteArray& blob) { m_settings.m_geometryBytes = blob; }; + virtual QByteArray getGeometryBytes() const { return m_settings.m_geometryBytes; }; + virtual QString getTitle() const { return m_settings.m_title; }; + virtual QColor getTitleColor() const { return m_settings.m_rgbColor; }; + virtual void zetHidden(bool hidden) { m_settings.m_hidden = hidden; } + virtual bool getHidden() const { return m_settings.m_hidden; } + virtual ChannelMarker& getChannelMarker() { return m_channelMarker; } + virtual int getStreamIndex() const { return m_settings.m_streamIndex; } + virtual void setStreamIndex(int streamIndex) { m_settings.m_streamIndex = streamIndex; } public slots: void channelMarkerChangedByCursor(); @@ -67,6 +76,7 @@ private: ChannelMarker m_channelMarker; RollupState m_rollupState; IEEE_802_15_4_ModSettings m_settings; + qint64 m_deviceCenterFrequency; bool m_doApplySettings; SpectrumVis* m_spectrumVis; ScopeVis* m_scopeVis; @@ -85,10 +95,12 @@ private: void blockApplySettings(bool block); void applySettings(bool force = false); void displaySettings(); - void displayStreamIndex(); void displayRFBandwidth(int bandwidth); void displayChipRate(const IEEE_802_15_4_ModSettings& settings); QString getDisplayValueWithMultiplier(int value); + bool handleMessage(const Message& message); + void makeUIConnections(); + void updateAbsoluteCenterFrequency(); void leaveEvent(QEvent*); void enterEvent(QEvent*); @@ -110,7 +122,6 @@ private slots: void on_udpEnabled_clicked(bool checked); void on_udpAddress_editingFinished(); void on_udpPort_editingFinished(); - void on_udpBytesFormat_clicked(bool checked); void onWidgetRolled(QWidget* widget, bool rollDown); void onMenuDialogCalled(const QPoint& p); diff --git a/plugins/channeltx/mod802.15.4/ieee_802_15_4_modgui.ui b/plugins/channeltx/mod802.15.4/ieee_802_15_4_modgui.ui index 2cb001a38..e53cb30e5 100644 --- a/plugins/channeltx/mod802.15.4/ieee_802_15_4_modgui.ui +++ b/plugins/channeltx/mod802.15.4/ieee_802_15_4_modgui.ui @@ -1,24 +1,24 @@ IEEE_802_15_4_ModGUI - + 0 0 - 605 + 622 937 - + 0 0 - 0 + 600 0 @@ -40,15 +40,15 @@ - 2 - 2 + 0 + 0 600 151 - 600 + 598 0 @@ -586,14 +586,14 @@ - + 0 0 - 600 + 598 0 @@ -634,9 +634,15 @@ 284 + + + 0 + 0 + + - 600 + 598 0 @@ -661,6 +667,12 @@ + + + 0 + 0 + + 200 @@ -689,9 +701,15 @@ 284 + + + 0 + 0 + + - 600 + 598 0 @@ -716,6 +734,12 @@ + + + 0 + 0 + + 200 @@ -738,15 +762,21 @@ - RollupWidget + RollupContents QWidget -
gui/rollupwidget.h
+
gui/rollupcontents.h
1
- ValueDialZ + GLSpectrum QWidget -
gui/valuedialz.h
+
gui/glspectrum.h
+ 1 +
+ + GLSpectrumGUI + QWidget +
gui/glspectrumgui.h
1
@@ -761,23 +791,17 @@
gui/glscopegui.h
1
+ + ValueDialZ + QWidget +
gui/valuedialz.h
+ 1 +
ButtonSwitch QToolButton
gui/buttonswitch.h
- - GLSpectrum - QWidget -
gui/glspectrum.h
- 1 -
- - GLSpectrumGUI - QWidget -
gui/glspectrumgui.h
- 1 -
LevelMeterVU QWidget diff --git a/plugins/channeltx/mod802.15.4/ieee_802_15_4_modsettings.cpp b/plugins/channeltx/mod802.15.4/ieee_802_15_4_modsettings.cpp index 3540274ab..935f897a7 100644 --- a/plugins/channeltx/mod802.15.4/ieee_802_15_4_modsettings.cpp +++ b/plugins/channeltx/mod802.15.4/ieee_802_15_4_modsettings.cpp @@ -75,6 +75,8 @@ void IEEE_802_15_4_ModSettings::resetToDefaults() m_udpBytesFormat = false; m_udpAddress = "127.0.0.1"; m_udpPort = 9998; + m_workspaceIndex = 0; + m_hidden = false; } bool IEEE_802_15_4_ModSettings::setPHY(QString phy) @@ -202,6 +204,10 @@ QByteArray IEEE_802_15_4_ModSettings::serialize() const s.writeBlob(38, m_rollupState->serialize()); } + s.writeS32(39, m_workspaceIndex); + s.writeBlob(40, m_geometryBytes); + s.writeBool(41, m_hidden); + return s.final(); } @@ -288,6 +294,10 @@ bool IEEE_802_15_4_ModSettings::deserialize(const QByteArray& data) m_rollupState->deserialize(bytetmp); } + d.readS32(39, &m_workspaceIndex, 0); + d.readBlob(40, &m_geometryBytes); + d.readBool(41, &m_hidden, false); + return true; } else diff --git a/plugins/channeltx/mod802.15.4/ieee_802_15_4_modsettings.h b/plugins/channeltx/mod802.15.4/ieee_802_15_4_modsettings.h index 367570869..160c2d6e5 100644 --- a/plugins/channeltx/mod802.15.4/ieee_802_15_4_modsettings.h +++ b/plugins/channeltx/mod802.15.4/ieee_802_15_4_modsettings.h @@ -78,6 +78,9 @@ struct IEEE_802_15_4_ModSettings uint16_t m_udpPort; Serializable *m_rollupState; static const int m_udpBufferSize = 100000; + int m_workspaceIndex; + QByteArray m_geometryBytes; + bool m_hidden; IEEE_802_15_4_ModSettings(); void resetToDefaults(); diff --git a/plugins/channeltx/mod802.15.4/readme.md b/plugins/channeltx/mod802.15.4/readme.md index d7deb8aa0..a518a39a2 100644 --- a/plugins/channeltx/mod802.15.4/readme.md +++ b/plugins/channeltx/mod802.15.4/readme.md @@ -6,6 +6,8 @@ This plugin can be used to transmit IEEE 802.15.4 frames. The 802.15.4 PHY & RF

Interface

+The top and bottom bars of the channel window are described [here](../../../sdrgui/channel/readme.md) + ![802.15.4 Modulator plugin GUI](../../../doc/img/IEEE_802_15_4_Mod_plugin.png)

1: Frequency shift from center frequency of transmission

diff --git a/plugins/channeltx/modais/aismod.cpp b/plugins/channeltx/modais/aismod.cpp index 22f71d38f..46dafffc2 100644 --- a/plugins/channeltx/modais/aismod.cpp +++ b/plugins/channeltx/modais/aismod.cpp @@ -27,6 +27,7 @@ #include #include "SWGChannelSettings.h" +#include "SWGWorkspaceInfo.h" #include "SWGChannelReport.h" #include "SWGChannelActions.h" @@ -99,6 +100,18 @@ AISMod::~AISMod() delete m_thread; } +void AISMod::setDeviceAPI(DeviceAPI *deviceAPI) +{ + if (deviceAPI != m_deviceAPI) + { + m_deviceAPI->removeChannelSourceAPI(this); + m_deviceAPI->removeChannelSource(this); + m_deviceAPI = deviceAPI; + m_deviceAPI->addChannelSource(this); + m_deviceAPI->addChannelSinkAPI(this); + } +} + void AISMod::start() { qDebug("AISMod::start"); @@ -164,6 +177,10 @@ bool AISMod::handleMessage(const Message& cmd) DSPSignalNotification* rep = new DSPSignalNotification(notif); // make a copy qDebug() << "AISMod::handleMessage: DSPSignalNotification"; m_basebandSource->getInputMessageQueue()->push(rep); + // Forward to GUI if any + if (getMessageQueueToGUI()) { + getMessageQueueToGUI()->push(new DSPSignalNotification(notif)); + } return true; } else if (MainCore::MsgChannelDemodQuery::match(cmd)) @@ -527,6 +544,15 @@ int AISMod::webapiSettingsGet( return 200; } +int AISMod::webapiWorkspaceGet( + SWGSDRangel::SWGWorkspaceInfo& response, + QString& errorMessage) +{ + (void) errorMessage; + response.setIndex(m_settings.m_workspaceIndex); + return 200; +} + int AISMod::webapiSettingsPutPatch( bool force, const QStringList& channelSettingsKeys, diff --git a/plugins/channeltx/modais/aismod.h b/plugins/channeltx/modais/aismod.h index 1f610be16..7275fffb8 100644 --- a/plugins/channeltx/modais/aismod.h +++ b/plugins/channeltx/modais/aismod.h @@ -152,6 +152,8 @@ public: AISMod(DeviceAPI *deviceAPI); virtual ~AISMod(); virtual void destroy() { delete this; } + virtual void setDeviceAPI(DeviceAPI *deviceAPI); + virtual DeviceAPI *getDeviceAPI() { return m_deviceAPI; } virtual void start(); virtual void stop(); @@ -182,6 +184,10 @@ public: SWGSDRangel::SWGChannelSettings& response, QString& errorMessage); + virtual int webapiWorkspaceGet( + SWGSDRangel::SWGWorkspaceInfo& response, + QString& errorMessage); + virtual int webapiSettingsPutPatch( bool force, const QStringList& channelSettingsKeys, diff --git a/plugins/channeltx/modais/aismodgui.cpp b/plugins/channeltx/modais/aismodgui.cpp index bc616e74e..6514ee8ba 100644 --- a/plugins/channeltx/modais/aismodgui.cpp +++ b/plugins/channeltx/modais/aismodgui.cpp @@ -25,6 +25,7 @@ #include "dsp/spectrumvis.h" #include "dsp/scopevis.h" #include "dsp/glscopesettings.h" +#include "dsp/dspcommands.h" #include "device/deviceuiset.h" #include "plugin/pluginapi.h" #include "util/simpleserializer.h" @@ -96,6 +97,16 @@ bool AISModGUI::handleMessage(const Message& message) ui->message->setText(m_settings.m_data); return true; } + else if (DSPSignalNotification::match(message)) + { + const DSPSignalNotification& notif = (const DSPSignalNotification&) message; + m_deviceCenterFrequency = notif.getCenterFrequency(); + m_basebandSampleRate = notif.getSampleRate(); + ui->deltaFrequency->setValueRange(false, 7, -m_basebandSampleRate/2, m_basebandSampleRate/2); + ui->deltaFrequencyLabel->setToolTip(tr("Range %1 %L2 Hz").arg(QChar(0xB1)).arg(m_basebandSampleRate/2)); + updateAbsoluteCenterFrequency(); + return true; + } else { return false; @@ -127,6 +138,7 @@ void AISModGUI::on_deltaFrequency_changed(qint64 value) { m_channelMarker.setCenterFrequency(value); m_settings.m_inputFrequencyOffset = m_channelMarker.getCenterFrequency(); + updateAbsoluteCenterFrequency(); applySettings(); } @@ -331,7 +343,18 @@ void AISModGUI::onWidgetRolled(QWidget* widget, bool rollDown) (void) widget; (void) rollDown; - saveState(m_rollupState); + RollupContents *rollupContents = getRollupContents(); + + if (rollupContents->hasExpandableWidgets()) { + setSizePolicy(sizePolicy().horizontalPolicy(), QSizePolicy::Expanding); + } else { + setSizePolicy(sizePolicy().horizontalPolicy(), QSizePolicy::Fixed); + } + + int h = rollupContents->height() + getAdditionalHeight(); + resize(width(), h); + + rollupContents->saveState(m_rollupState); applySettings(); } @@ -345,10 +368,17 @@ void AISModGUI::onMenuDialogCalled(const QPoint &p) dialog.setReverseAPIPort(m_settings.m_reverseAPIPort); dialog.setReverseAPIDeviceIndex(m_settings.m_reverseAPIDeviceIndex); dialog.setReverseAPIChannelIndex(m_settings.m_reverseAPIChannelIndex); + dialog.setDefaultTitle(m_displayedName); + + if (m_deviceUISet->m_deviceMIMOEngine) + { + dialog.setNumberOfStreams(m_aisMod->getNumberOfDeviceStreams()); + dialog.setStreamIndex(m_settings.m_streamIndex); + } + dialog.move(p); dialog.exec(); - m_settings.m_inputFrequencyOffset = m_channelMarker.getCenterFrequency(); m_settings.m_rgbColor = m_channelMarker.getColor().rgb(); m_settings.m_title = m_channelMarker.getTitle(); m_settings.m_useReverseAPI = dialog.useReverseAPI(); @@ -358,22 +388,17 @@ void AISModGUI::onMenuDialogCalled(const QPoint &p) m_settings.m_reverseAPIChannelIndex = dialog.getReverseAPIChannelIndex(); setWindowTitle(m_settings.m_title); + setTitle(m_channelMarker.getTitle()); setTitleColor(m_settings.m_rgbColor); - applySettings(); - } - else if ((m_contextMenuType == ContextMenuStreamSettings) && (m_deviceUISet->m_deviceMIMOEngine)) - { - DeviceStreamSelectionDialog dialog(this); - dialog.setNumberOfStreams(m_aisMod->getNumberOfDeviceStreams()); - dialog.setStreamIndex(m_settings.m_streamIndex); - dialog.move(p); - dialog.exec(); + if (m_deviceUISet->m_deviceMIMOEngine) + { + m_settings.m_streamIndex = dialog.getSelectedStreamIndex(); + m_channelMarker.clearStreamIndexes(); + m_channelMarker.addStreamIndex(m_settings.m_streamIndex); + updateIndexLabel(); + } - m_settings.m_streamIndex = dialog.getSelectedStreamIndex(); - m_channelMarker.clearStreamIndexes(); - m_channelMarker.addStreamIndex(m_settings.m_streamIndex); - displayStreamIndex(); applySettings(); } @@ -386,13 +411,17 @@ AISModGUI::AISModGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, BasebandSam m_pluginAPI(pluginAPI), m_deviceUISet(deviceUISet), m_channelMarker(this), + m_deviceCenterFrequency(0), + m_basebandSampleRate(1), m_doApplySettings(true) { - ui->setupUi(this); - m_helpURL = "plugins/channeltx/modais/readme.md"; setAttribute(Qt::WA_DeleteOnClose, true); - - connect(this, SIGNAL(widgetRolled(QWidget*,bool)), this, SLOT(onWidgetRolled(QWidget*,bool))); + m_helpURL = "plugins/channeltx/modais/readme.md"; + RollupContents *rollupContents = getRollupContents(); + ui->setupUi(rollupContents); + setSizePolicy(rollupContents->sizePolicy()); + rollupContents->arrangeRollups(); + connect(rollupContents, SIGNAL(widgetRolled(QWidget*,bool)), this, SLOT(onWidgetRolled(QWidget*,bool))); connect(this, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(onMenuDialogCalled(const QPoint &))); m_aisMod = (AISMod*) channelTx; @@ -462,7 +491,6 @@ AISModGUI::AISModGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, BasebandSam m_channelMarker.setVisible(true); // activate signal on the last setting only m_deviceUISet->addChannelMarker(&m_channelMarker); - m_deviceUISet->addRollupWidget(this); connect(&m_channelMarker, SIGNAL(changedByCursor()), this, SLOT(channelMarkerChangedByCursor())); @@ -478,6 +506,7 @@ AISModGUI::AISModGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, BasebandSam ui->spectrumContainer->setVisible(false); displaySettings(); + makeUIConnections(); applySettings(); } @@ -518,7 +547,8 @@ void AISModGUI::displaySettings() setTitleColor(m_settings.m_rgbColor); setWindowTitle(m_channelMarker.getTitle()); - displayStreamIndex(); + setTitle(m_channelMarker.getTitle()); + updateIndexLabel(); blockApplySettings(true); @@ -552,27 +582,21 @@ void AISModGUI::displaySettings() ui->heading->setValue(m_settings.m_heading); ui->message->setText(m_settings.m_data); - restoreState(m_rollupState); + getRollupContents()->restoreState(m_rollupState); + updateAbsoluteCenterFrequency(); blockApplySettings(false); } -void AISModGUI::displayStreamIndex() -{ - if (m_deviceUISet->m_deviceMIMOEngine) { - setStreamIndicator(tr("%1").arg(m_settings.m_streamIndex)); - } else { - setStreamIndicator("S"); // single channel indicator - } -} - -void AISModGUI::leaveEvent(QEvent*) +void AISModGUI::leaveEvent(QEvent* event) { m_channelMarker.setHighlighted(false); + ChannelGUI::leaveEvent(event); } -void AISModGUI::enterEvent(QEvent*) +void AISModGUI::enterEvent(QEvent* event) { m_channelMarker.setHighlighted(true); + ChannelGUI::enterEvent(event); } void AISModGUI::tick() @@ -581,3 +605,36 @@ void AISModGUI::tick() m_channelPowerDbAvg(powDb); ui->channelPower->setText(tr("%1 dB").arg(m_channelPowerDbAvg.asDouble(), 0, 'f', 1)); } + +void AISModGUI::makeUIConnections() +{ + QObject::connect(ui->deltaFrequency, &ValueDialZ::changed, this, &AISModGUI::on_deltaFrequency_changed); + QObject::connect(ui->mode, QOverload::of(&QComboBox::currentIndexChanged), this, &AISModGUI::on_mode_currentIndexChanged); + QObject::connect(ui->rfBW, &QSlider::valueChanged, this, &AISModGUI::on_rfBW_valueChanged); + QObject::connect(ui->fmDev, &QSlider::valueChanged, this, &AISModGUI::on_fmDev_valueChanged); + QObject::connect(ui->bt, &QSlider::valueChanged, this, &AISModGUI::on_bt_valueChanged); + QObject::connect(ui->gain, &QDial::valueChanged, this, &AISModGUI::on_gain_valueChanged); + QObject::connect(ui->channelMute, &QToolButton::toggled, this, &AISModGUI::on_channelMute_toggled); + QObject::connect(ui->txButton, &QPushButton::clicked, this, &AISModGUI::on_txButton_clicked); + QObject::connect(ui->encode, &QToolButton::clicked, this, &AISModGUI::on_encode_clicked); + QObject::connect(ui->msgId, QOverload::of(&QComboBox::currentIndexChanged), this, &AISModGUI::on_msgId_currentIndexChanged); + QObject::connect(ui->mmsi, &QLineEdit::editingFinished, this, &AISModGUI::on_mmsi_editingFinished); + QObject::connect(ui->status, QOverload::of(&QComboBox::currentIndexChanged), this, &AISModGUI::on_status_currentIndexChanged); + QObject::connect(ui->latitude, QOverload::of(&QDoubleSpinBox::valueChanged), this, &AISModGUI::on_latitude_valueChanged); + QObject::connect(ui->longitude, QOverload::of(&QDoubleSpinBox::valueChanged), this, &AISModGUI::on_longitude_valueChanged); + QObject::connect(ui->insertPosition, &QToolButton::clicked, this, &AISModGUI::on_insertPosition_clicked); + QObject::connect(ui->course, QOverload::of(&QDoubleSpinBox::valueChanged), this, &AISModGUI::on_course_valueChanged); + QObject::connect(ui->speed, QOverload::of(&QDoubleSpinBox::valueChanged), this, &AISModGUI::on_speed_valueChanged); + QObject::connect(ui->heading, QOverload::of(&QSpinBox::valueChanged), this, &AISModGUI::on_heading_valueChanged); + QObject::connect(ui->message, &QLineEdit::editingFinished, this, &AISModGUI::on_message_editingFinished); + QObject::connect(ui->message, &QLineEdit::returnPressed, this, &AISModGUI::on_message_returnPressed); + QObject::connect(ui->repeat, &ButtonSwitch::toggled, this, &AISModGUI::on_repeat_toggled); + QObject::connect(ui->udpEnabled, &QCheckBox::clicked, this, &AISModGUI::on_udpEnabled_clicked); + QObject::connect(ui->udpAddress, &QLineEdit::editingFinished, this, &AISModGUI::on_udpAddress_editingFinished); + QObject::connect(ui->udpPort, &QLineEdit::editingFinished, this, &AISModGUI::on_udpPort_editingFinished); +} + +void AISModGUI::updateAbsoluteCenterFrequency() +{ + setStatusFrequency(m_deviceCenterFrequency + m_settings.m_inputFrequencyOffset); +} diff --git a/plugins/channeltx/modais/aismodgui.h b/plugins/channeltx/modais/aismodgui.h index 86081b287..7deb50c85 100644 --- a/plugins/channeltx/modais/aismodgui.h +++ b/plugins/channeltx/modais/aismodgui.h @@ -49,6 +49,17 @@ public: QByteArray serialize() const; bool deserialize(const QByteArray& data); virtual MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; } + virtual void setWorkspaceIndex(int index) { m_settings.m_workspaceIndex = index; }; + virtual int getWorkspaceIndex() const { return m_settings.m_workspaceIndex; }; + virtual void setGeometryBytes(const QByteArray& blob) { m_settings.m_geometryBytes = blob; }; + virtual QByteArray getGeometryBytes() const { return m_settings.m_geometryBytes; }; + virtual QString getTitle() const { return m_settings.m_title; }; + virtual QColor getTitleColor() const { return m_settings.m_rgbColor; }; + virtual void zetHidden(bool hidden) { m_settings.m_hidden = hidden; } + virtual bool getHidden() const { return m_settings.m_hidden; } + virtual ChannelMarker& getChannelMarker() { return m_channelMarker; } + virtual int getStreamIndex() const { return m_settings.m_streamIndex; } + virtual void setStreamIndex(int streamIndex) { m_settings.m_streamIndex = streamIndex; } public slots: void channelMarkerChangedByCursor(); @@ -60,6 +71,8 @@ private: ChannelMarker m_channelMarker; RollupState m_rollupState; AISModSettings m_settings; + qint64 m_deviceCenterFrequency; + int m_basebandSampleRate; bool m_doApplySettings; SpectrumVis* m_spectrumVis; ScopeVis* m_scopeVis; @@ -76,8 +89,9 @@ private: void blockApplySettings(bool block); void applySettings(bool force = false); void displaySettings(); - void displayStreamIndex(); bool handleMessage(const Message& message); + void makeUIConnections(); + void updateAbsoluteCenterFrequency(); void leaveEvent(QEvent*); void enterEvent(QEvent*); diff --git a/plugins/channeltx/modais/aismodgui.ui b/plugins/channeltx/modais/aismodgui.ui index 16b260bf4..cf270f5b8 100644 --- a/plugins/channeltx/modais/aismodgui.ui +++ b/plugins/channeltx/modais/aismodgui.ui @@ -1,7 +1,7 @@ AISModGUI - + 0 @@ -11,7 +11,7 @@ - + 0 0 @@ -1010,15 +1010,21 @@ 0 290 431 - 141 + 200 - + 0 0 + + + 0 + 200 + + Transmitted Messages @@ -1056,6 +1062,12 @@ 331 + + + 0 + 0 + + Baseband Spectrum @@ -1077,6 +1089,12 @@ + + + 0 + 0 + + 200 @@ -1105,6 +1123,12 @@ 311 + + + 0 + 0 + + IQ Waveforms @@ -1126,6 +1150,12 @@ + + + 0 + 0 + + 200 @@ -1148,15 +1178,21 @@ - RollupWidget + RollupContents QWidget -
gui/rollupwidget.h
+
gui/rollupcontents.h
1
- ValueDialZ + GLSpectrum QWidget -
gui/valuedialz.h
+
gui/glspectrum.h
+ 1 +
+ + GLSpectrumGUI + QWidget +
gui/glspectrumgui.h
1
@@ -1171,23 +1207,17 @@
gui/glscopegui.h
1
+ + ValueDialZ + QWidget +
gui/valuedialz.h
+ 1 +
ButtonSwitch QToolButton
gui/buttonswitch.h
- - GLSpectrum - QWidget -
gui/glspectrum.h
- 1 -
- - GLSpectrumGUI - QWidget -
gui/glspectrumgui.h
- 1 -
LevelMeterVU QWidget diff --git a/plugins/channeltx/modais/aismodsettings.cpp b/plugins/channeltx/modais/aismodsettings.cpp index 91d71ca44..f14445f1d 100644 --- a/plugins/channeltx/modais/aismodsettings.cpp +++ b/plugins/channeltx/modais/aismodsettings.cpp @@ -69,6 +69,8 @@ void AISModSettings::resetToDefaults() m_udpEnabled = false; m_udpAddress = "127.0.0.1"; m_udpPort = 9998; + m_workspaceIndex = 0; + m_hidden = false; } bool AISModSettings::setMode(QString mode) @@ -180,6 +182,10 @@ QByteArray AISModSettings::serialize() const s.writeBlob(40, m_rollupState->serialize()); } + s.writeS32(41, m_workspaceIndex); + s.writeBlob(42, m_geometryBytes); + s.writeBool(43, m_hidden); + return s.final(); } @@ -267,6 +273,10 @@ bool AISModSettings::deserialize(const QByteArray& data) m_rollupState->deserialize(bytetmp); } + d.readS32(41, &m_workspaceIndex, 0); + d.readBlob(42, &m_geometryBytes); + d.readBool(43, &m_hidden, false); + return true; } else diff --git a/plugins/channeltx/modais/aismodsettings.h b/plugins/channeltx/modais/aismodsettings.h index 2be80462e..127d9f3f3 100644 --- a/plugins/channeltx/modais/aismodsettings.h +++ b/plugins/channeltx/modais/aismodsettings.h @@ -87,6 +87,9 @@ struct AISModSettings QString m_udpAddress; uint16_t m_udpPort; Serializable *m_rollupState; + int m_workspaceIndex; + QByteArray m_geometryBytes; + bool m_hidden; // Sample rate is multiple of 9600 baud rate (use even multiple so Gausian filter has odd number of taps) // Is there any benefit to having this higher? diff --git a/plugins/channeltx/modais/readme.md b/plugins/channeltx/modais/readme.md index 106aa33af..2453ebb0d 100644 --- a/plugins/channeltx/modais/readme.md +++ b/plugins/channeltx/modais/readme.md @@ -8,6 +8,8 @@ You need an AIS license to transmit on the AIS VHF frequencies (161.975MHz and 1

Interface

+The top and bottom bars of the channel window are described [here](../../../sdrgui/channel/readme.md) + ![AIS Modulator plugin GUI](../../../doc/img/AISMod_plugin.png)

1: Frequency shift from center frequency of transmission

diff --git a/plugins/channeltx/modam/ammod.cpp b/plugins/channeltx/modam/ammod.cpp index d1f80abfd..287176ebb 100644 --- a/plugins/channeltx/modam/ammod.cpp +++ b/plugins/channeltx/modam/ammod.cpp @@ -27,6 +27,7 @@ #include #include "SWGChannelSettings.h" +#include "SWGWorkspaceInfo.h" #include "SWGChannelReport.h" #include "SWGAMModReport.h" @@ -97,6 +98,18 @@ AMMod::~AMMod() delete m_thread; } +void AMMod::setDeviceAPI(DeviceAPI *deviceAPI) +{ + if (deviceAPI != m_deviceAPI) + { + m_deviceAPI->removeChannelSourceAPI(this); + m_deviceAPI->removeChannelSource(this); + m_deviceAPI = deviceAPI; + m_deviceAPI->addChannelSource(this); + m_deviceAPI->addChannelSinkAPI(this); + } +} + uint32_t AMMod::getNumberOfDeviceStreams() const { return m_deviceAPI->getNbSinkStreams(); @@ -196,6 +209,10 @@ bool AMMod::handleMessage(const Message& cmd) DSPSignalNotification* rep = new DSPSignalNotification(notif); // make a copy qDebug() << "AMMod::handleMessage: DSPSignalNotification"; m_basebandSource->getInputMessageQueue()->push(rep); + // Forward to GUI if any + if (getMessageQueueToGUI()) { + getMessageQueueToGUI()->push(new DSPSignalNotification(notif)); + } return true; } @@ -400,6 +417,15 @@ int AMMod::webapiSettingsGet( return 200; } +int AMMod::webapiWorkspaceGet( + SWGSDRangel::SWGWorkspaceInfo& response, + QString& errorMessage) +{ + (void) errorMessage; + response.setIndex(m_settings.m_workspaceIndex); + return 200; +} + int AMMod::webapiSettingsPutPatch( bool force, const QStringList& channelSettingsKeys, diff --git a/plugins/channeltx/modam/ammod.h b/plugins/channeltx/modam/ammod.h index 46001df0b..1d2839eae 100644 --- a/plugins/channeltx/modam/ammod.h +++ b/plugins/channeltx/modam/ammod.h @@ -174,6 +174,8 @@ public: AMMod(DeviceAPI *deviceAPI); virtual ~AMMod(); virtual void destroy() { delete this; } + virtual void setDeviceAPI(DeviceAPI *deviceAPI); + virtual DeviceAPI *getDeviceAPI() { return m_deviceAPI; } virtual void start(); virtual void stop(); @@ -204,6 +206,10 @@ public: SWGSDRangel::SWGChannelSettings& response, QString& errorMessage); + virtual int webapiWorkspaceGet( + SWGSDRangel::SWGWorkspaceInfo& response, + QString& errorMessage); + virtual int webapiSettingsPutPatch( bool force, const QStringList& channelSettingsKeys, diff --git a/plugins/channeltx/modam/ammodgui.cpp b/plugins/channeltx/modam/ammodgui.cpp index 7f0bc8c8f..b2a1889b8 100644 --- a/plugins/channeltx/modam/ammodgui.cpp +++ b/plugins/channeltx/modam/ammodgui.cpp @@ -20,6 +20,7 @@ #include #include #include +#include #include "device/deviceuiset.h" @@ -28,6 +29,7 @@ #include "util/db.h" #include "dsp/dspengine.h" #include "dsp/cwkeyer.h" +#include "dsp/dspcommands.h" #include "gui/crightclickenabler.h" #include "gui/audioselectdialog.h" #include "gui/basicchannelsettingsdialog.h" @@ -72,6 +74,14 @@ bool AMModGUI::deserialize(const QByteArray& data) } } +void AMModGUI::resizeEvent(QResizeEvent* size) +{ + int maxWidth = getRollupContents()->maximumWidth(); + int minHeight = getRollupContents()->minimumHeight() + getAdditionalHeight(); + resize(width() < maxWidth ? width() : maxWidth, minHeight); + size->accept(); +} + bool AMModGUI::handleMessage(const Message& message) { if (AMMod::MsgReportFileSourceStreamData::match(message)) @@ -105,6 +115,16 @@ bool AMModGUI::handleMessage(const Message& message) ui->cwKeyerGUI->displaySettings(); return true; } + else if (DSPSignalNotification::match(message)) + { + const DSPSignalNotification& notif = (const DSPSignalNotification&) message; + m_deviceCenterFrequency = notif.getCenterFrequency(); + m_basebandSampleRate = notif.getSampleRate(); + ui->deltaFrequency->setValueRange(false, 7, -m_basebandSampleRate/2, m_basebandSampleRate/2); + ui->deltaFrequencyLabel->setToolTip(tr("Range %1 %L2 Hz").arg(QChar(0xB1)).arg(m_basebandSampleRate/2)); + updateAbsoluteCenterFrequency(); + return true; + } else { return false; @@ -135,6 +155,7 @@ void AMModGUI::on_deltaFrequency_changed(qint64 value) { m_channelMarker.setCenterFrequency(value); m_settings.m_inputFrequencyOffset = value; + updateAbsoluteCenterFrequency(); applySettings(); } @@ -271,7 +292,7 @@ void AMModGUI::onWidgetRolled(QWidget* widget, bool rollDown) (void) widget; (void) rollDown; - saveState(m_rollupState); + getRollupContents()->saveState(m_rollupState); applySettings(); } @@ -285,10 +306,17 @@ void AMModGUI::onMenuDialogCalled(const QPoint &p) dialog.setReverseAPIPort(m_settings.m_reverseAPIPort); dialog.setReverseAPIDeviceIndex(m_settings.m_reverseAPIDeviceIndex); dialog.setReverseAPIChannelIndex(m_settings.m_reverseAPIChannelIndex); + dialog.setDefaultTitle(m_displayedName); + + if (m_deviceUISet->m_deviceMIMOEngine) + { + dialog.setNumberOfStreams(m_amMod->getNumberOfDeviceStreams()); + dialog.setStreamIndex(m_settings.m_streamIndex); + } + dialog.move(p); dialog.exec(); - m_settings.m_inputFrequencyOffset = m_channelMarker.getCenterFrequency(); m_settings.m_rgbColor = m_channelMarker.getColor().rgb(); m_settings.m_title = m_channelMarker.getTitle(); m_settings.m_useReverseAPI = dialog.useReverseAPI(); @@ -298,22 +326,17 @@ void AMModGUI::onMenuDialogCalled(const QPoint &p) m_settings.m_reverseAPIChannelIndex = dialog.getReverseAPIChannelIndex(); setWindowTitle(m_settings.m_title); + setTitle(m_channelMarker.getTitle()); setTitleColor(m_settings.m_rgbColor); - applySettings(); - } - else if ((m_contextMenuType == ContextMenuStreamSettings) && (m_deviceUISet->m_deviceMIMOEngine)) - { - DeviceStreamSelectionDialog dialog(this); - dialog.setNumberOfStreams(m_amMod->getNumberOfDeviceStreams()); - dialog.setStreamIndex(m_settings.m_streamIndex); - dialog.move(p); - dialog.exec(); + if (m_deviceUISet->m_deviceMIMOEngine) + { + m_settings.m_streamIndex = dialog.getSelectedStreamIndex(); + m_channelMarker.clearStreamIndexes(); + m_channelMarker.addStreamIndex(m_settings.m_streamIndex); + updateIndexLabel(); + } - m_settings.m_streamIndex = dialog.getSelectedStreamIndex(); - m_channelMarker.clearStreamIndexes(); - m_channelMarker.addStreamIndex(m_settings.m_streamIndex); - displayStreamIndex(); applySettings(); } @@ -326,6 +349,8 @@ AMModGUI::AMModGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, BasebandSampl m_pluginAPI(pluginAPI), m_deviceUISet(deviceUISet), m_channelMarker(this), + m_deviceCenterFrequency(0), + m_basebandSampleRate(1), m_doApplySettings(true), m_recordLength(0), m_recordSampleRate(48000), @@ -335,10 +360,13 @@ AMModGUI::AMModGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, BasebandSampl m_tickCount(0), m_enableNavTime(false) { - ui->setupUi(this); - m_helpURL = "plugins/channeltx/modam/readme.md"; setAttribute(Qt::WA_DeleteOnClose, true); - connect(this, SIGNAL(widgetRolled(QWidget*,bool)), this, SLOT(onWidgetRolled(QWidget*,bool))); + m_helpURL = "plugins/channeltx/modam/readme.md"; + RollupContents *rollupContents = getRollupContents(); + ui->setupUi(rollupContents); + setSizePolicy(rollupContents->sizePolicy()); + rollupContents->arrangeRollups(); + connect(rollupContents, SIGNAL(widgetRolled(QWidget*,bool)), this, SLOT(onWidgetRolled(QWidget*,bool))); connect(this, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(onMenuDialogCalled(const QPoint &))); m_amMod = (AMMod*) channelTx; @@ -370,7 +398,6 @@ AMModGUI::AMModGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, BasebandSampl m_settings.setCWKeyerGUI(ui->cwKeyerGUI); m_deviceUISet->addChannelMarker(&m_channelMarker); - m_deviceUISet->addRollupWidget(this); connect(&m_channelMarker, SIGNAL(changedByCursor()), this, SLOT(channelMarkerChangedByCursor())); @@ -386,6 +413,7 @@ AMModGUI::AMModGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, BasebandSampl m_amMod->setLevelMeter(ui->volumeMeter); displaySettings(); + makeUIConnections(); applySettings(true); } @@ -420,6 +448,7 @@ void AMModGUI::displaySettings() setTitleColor(m_settings.m_rgbColor); setWindowTitle(m_channelMarker.getTitle()); + setTitle(m_channelMarker.getTitle()); blockApplySettings(true); @@ -455,29 +484,23 @@ void AMModGUI::displaySettings() ui->feedbackVolume->setValue(roundf(m_settings.m_feedbackVolumeFactor * 100.0)); ui->feedbackVolumeText->setText(QString("%1").arg(m_settings.m_feedbackVolumeFactor, 0, 'f', 2)); - displayStreamIndex(); + updateIndexLabel(); - restoreState(m_rollupState); + getRollupContents()->restoreState(m_rollupState); + updateAbsoluteCenterFrequency(); blockApplySettings(false); } -void AMModGUI::displayStreamIndex() -{ - if (m_deviceUISet->m_deviceMIMOEngine) { - setStreamIndicator(tr("%1").arg(m_settings.m_streamIndex)); - } else { - setStreamIndicator("S"); // single channel indicator - } -} - -void AMModGUI::leaveEvent(QEvent*) +void AMModGUI::leaveEvent(QEvent* event) { m_channelMarker.setHighlighted(false); + ChannelGUI::leaveEvent(event); } -void AMModGUI::enterEvent(QEvent*) +void AMModGUI::enterEvent(QEvent* event) { m_channelMarker.setHighlighted(true); + ChannelGUI::enterEvent(event); } void AMModGUI::audioSelect() @@ -578,3 +601,27 @@ void AMModGUI::updateWithStreamTime() ui->navTimeSlider->setValue((int) (posRatio * 100.0)); } } + +void AMModGUI::makeUIConnections() +{ + QObject::connect(ui->deltaFrequency, &ValueDialZ::changed, this, &AMModGUI::on_deltaFrequency_changed); + QObject::connect(ui->rfBW, &QSlider::valueChanged, this, &AMModGUI::on_rfBW_valueChanged); + QObject::connect(ui->modPercent, &QSlider::valueChanged, this, &AMModGUI::on_modPercent_valueChanged); + QObject::connect(ui->volume, &QDial::valueChanged, this, &AMModGUI::on_volume_valueChanged); + QObject::connect(ui->channelMute, &QToolButton::toggled, this, &AMModGUI::on_channelMute_toggled); + QObject::connect(ui->tone, &ButtonSwitch::toggled, this, &AMModGUI::on_tone_toggled); + QObject::connect(ui->toneFrequency, &QDial::valueChanged, this, &AMModGUI::on_toneFrequency_valueChanged); + QObject::connect(ui->mic, &ButtonSwitch::toggled, this, &AMModGUI::on_mic_toggled); + QObject::connect(ui->play, &ButtonSwitch::toggled, this, &AMModGUI::on_play_toggled); + QObject::connect(ui->morseKeyer, &ButtonSwitch::toggled, this, &AMModGUI::on_morseKeyer_toggled); + QObject::connect(ui->playLoop, &ButtonSwitch::toggled, this, &AMModGUI::on_playLoop_toggled); + QObject::connect(ui->navTimeSlider, &QSlider::valueChanged, this, &AMModGUI::on_navTimeSlider_valueChanged); + QObject::connect(ui->showFileDialog, &QPushButton::clicked, this, &AMModGUI::on_showFileDialog_clicked); + QObject::connect(ui->feedbackEnable, &QToolButton::toggled, this, &AMModGUI::on_feedbackEnable_toggled); + QObject::connect(ui->feedbackVolume, &QDial::valueChanged, this, &AMModGUI::on_feedbackVolume_valueChanged); +} + +void AMModGUI::updateAbsoluteCenterFrequency() +{ + setStatusFrequency(m_deviceCenterFrequency + m_settings.m_inputFrequencyOffset); +} diff --git a/plugins/channeltx/modam/ammodgui.h b/plugins/channeltx/modam/ammodgui.h index ba7ff7d77..76239be4e 100644 --- a/plugins/channeltx/modam/ammodgui.h +++ b/plugins/channeltx/modam/ammodgui.h @@ -48,10 +48,24 @@ public: QByteArray serialize() const; bool deserialize(const QByteArray& data); virtual MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; } + virtual void setWorkspaceIndex(int index) { m_settings.m_workspaceIndex = index; }; + virtual int getWorkspaceIndex() const { return m_settings.m_workspaceIndex; }; + virtual void setGeometryBytes(const QByteArray& blob) { m_settings.m_geometryBytes = blob; }; + virtual QByteArray getGeometryBytes() const { return m_settings.m_geometryBytes; }; + virtual QString getTitle() const { return m_settings.m_title; }; + virtual QColor getTitleColor() const { return m_settings.m_rgbColor; }; + virtual void zetHidden(bool hidden) { m_settings.m_hidden = hidden; } + virtual bool getHidden() const { return m_settings.m_hidden; } + virtual ChannelMarker& getChannelMarker() { return m_channelMarker; } + virtual int getStreamIndex() const { return m_settings.m_streamIndex; } + virtual void setStreamIndex(int streamIndex) { m_settings.m_streamIndex = streamIndex; } public slots: void channelMarkerChangedByCursor(); +protected: + void resizeEvent(QResizeEvent* size); + private: Ui::AMModGUI* ui; PluginAPI* m_pluginAPI; @@ -59,6 +73,8 @@ private: ChannelMarker m_channelMarker; RollupState m_rollupState; AMModSettings m_settings; + qint64 m_deviceCenterFrequency; + int m_basebandSampleRate; bool m_doApplySettings; AMMod* m_amMod; @@ -80,10 +96,11 @@ private: void blockApplySettings(bool block); void applySettings(bool force = false); void displaySettings(); - void displayStreamIndex(); void updateWithStreamData(); void updateWithStreamTime(); bool handleMessage(const Message& message); + void makeUIConnections(); + void updateAbsoluteCenterFrequency(); void leaveEvent(QEvent*); void enterEvent(QEvent*); diff --git a/plugins/channeltx/modam/ammodgui.ui b/plugins/channeltx/modam/ammodgui.ui index fd0974534..e34f48ebd 100644 --- a/plugins/channeltx/modam/ammodgui.ui +++ b/plugins/channeltx/modam/ammodgui.ui @@ -1,27 +1,33 @@ AMModGUI - + 0 0 - 342 - 363 + 360 + 347 - + 0 0 - 0 + 360 0 + + + 560 + 16777215 + + Liberation Sans @@ -37,15 +43,21 @@ - 10 - 10 - 320 + 0 + 0 + 358 341 + + + 0 + 0 + + - 280 + 358 0 @@ -725,26 +737,9 @@ - RollupWidget + RollupContents QWidget -
gui/rollupwidget.h
- 1 -
- - LevelMeterVU - QWidget -
gui/levelmeter.h
- 1 -
- - ButtonSwitch - QToolButton -
gui/buttonswitch.h
-
- - CWKeyerGUI - QWidget -
gui/cwkeyergui.h
+
gui/rollupcontents.h
1
@@ -753,6 +748,23 @@
gui/valuedialz.h
1
+ + ButtonSwitch + QToolButton +
gui/buttonswitch.h
+
+ + LevelMeterVU + QWidget +
gui/levelmeter.h
+ 1 +
+ + CWKeyerGUI + QWidget +
gui/cwkeyergui.h
+ 1 +
diff --git a/plugins/channeltx/modam/ammodsettings.cpp b/plugins/channeltx/modam/ammodsettings.cpp index 909dc75d6..aa87ed811 100644 --- a/plugins/channeltx/modam/ammodsettings.cpp +++ b/plugins/channeltx/modam/ammodsettings.cpp @@ -52,6 +52,8 @@ void AMModSettings::resetToDefaults() m_reverseAPIPort = 8888; m_reverseAPIDeviceIndex = 0; m_reverseAPIChannelIndex = 0; + m_workspaceIndex = 0; + m_hidden = false; } QByteArray AMModSettings::serialize() const @@ -92,6 +94,10 @@ QByteArray AMModSettings::serialize() const s.writeBlob(21, m_rollupState->serialize()); } + s.writeS32(22, m_workspaceIndex); + s.writeBlob(23, m_geometryBytes); + s.writeBool(24, m_hidden); + return s.final(); } @@ -166,6 +172,10 @@ bool AMModSettings::deserialize(const QByteArray& data) m_rollupState->deserialize(bytetmp); } + d.readS32(22, &m_workspaceIndex, 0); + d.readBlob(23, &m_geometryBytes); + d.readBool(24, &m_hidden, false); + return true; } else diff --git a/plugins/channeltx/modam/ammodsettings.h b/plugins/channeltx/modam/ammodsettings.h index 2bc8bfe47..78c2839e2 100644 --- a/plugins/channeltx/modam/ammodsettings.h +++ b/plugins/channeltx/modam/ammodsettings.h @@ -55,6 +55,9 @@ struct AMModSettings uint16_t m_reverseAPIPort; uint16_t m_reverseAPIDeviceIndex; uint16_t m_reverseAPIChannelIndex; + int m_workspaceIndex; + QByteArray m_geometryBytes; + bool m_hidden; Serializable *m_channelMarker; Serializable *m_cwKeyerGUI; diff --git a/plugins/channeltx/modam/readme.md b/plugins/channeltx/modam/readme.md index 10d5e8b01..025cb858a 100644 --- a/plugins/channeltx/modam/readme.md +++ b/plugins/channeltx/modam/readme.md @@ -6,6 +6,8 @@ This plugin can be used to generate a narrowband amplitude modulated signal. "Na

Interface

+The top and bottom bars of the channel window are described [here](../../../sdrgui/channel/readme.md) + ![AM Modulator plugin GUI](../../../doc/img/AMMod_plugin.png)

1: Frequency shift from center frequency of transmission

diff --git a/plugins/channeltx/modatv/atvmod.cpp b/plugins/channeltx/modatv/atvmod.cpp index 5377e20a6..705b55120 100644 --- a/plugins/channeltx/modatv/atvmod.cpp +++ b/plugins/channeltx/modatv/atvmod.cpp @@ -27,6 +27,7 @@ #include #include "SWGChannelSettings.h" +#include "SWGWorkspaceInfo.h" #include "SWGChannelReport.h" #include "SWGATVModReport.h" @@ -94,6 +95,18 @@ ATVMod::~ATVMod() delete m_thread; } +void ATVMod::setDeviceAPI(DeviceAPI *deviceAPI) +{ + if (deviceAPI != m_deviceAPI) + { + m_deviceAPI->removeChannelSourceAPI(this); + m_deviceAPI->removeChannelSource(this); + m_deviceAPI = deviceAPI; + m_deviceAPI->addChannelSource(this); + m_deviceAPI->addChannelSinkAPI(this); + } +} + uint32_t ATVMod::getNumberOfDeviceStreams() const { return m_deviceAPI->getNbSinkStreams(); @@ -161,6 +174,10 @@ bool ATVMod::handleMessage(const Message& cmd) DSPSignalNotification* rep = new DSPSignalNotification(notif); // make a copy qDebug() << "ATVMod::handleMessage: DSPSignalNotification"; m_basebandSource->getInputMessageQueue()->push(rep); + // Forward to GUI if any + if (getMessageQueueToGUI()) { + getMessageQueueToGUI()->push(new DSPSignalNotification(notif)); + } return true; } @@ -390,6 +407,15 @@ int ATVMod::webapiSettingsGet( return 200; } +int ATVMod::webapiWorkspaceGet( + SWGSDRangel::SWGWorkspaceInfo& response, + QString& errorMessage) +{ + (void) errorMessage; + response.setIndex(m_settings.m_workspaceIndex); + return 200; +} + int ATVMod::webapiSettingsPutPatch( bool force, const QStringList& channelSettingsKeys, diff --git a/plugins/channeltx/modatv/atvmod.h b/plugins/channeltx/modatv/atvmod.h index 4c2cc4daf..4577c0586 100644 --- a/plugins/channeltx/modatv/atvmod.h +++ b/plugins/channeltx/modatv/atvmod.h @@ -246,6 +246,8 @@ public: ATVMod(DeviceAPI *deviceAPI); virtual ~ATVMod(); virtual void destroy() { delete this; } + virtual void setDeviceAPI(DeviceAPI *deviceAPI); + virtual DeviceAPI *getDeviceAPI() { return m_deviceAPI; } virtual void start(); virtual void stop(); @@ -276,6 +278,10 @@ public: SWGSDRangel::SWGChannelSettings& response, QString& errorMessage); + virtual int webapiWorkspaceGet( + SWGSDRangel::SWGWorkspaceInfo& response, + QString& errorMessage); + virtual int webapiSettingsPutPatch( bool force, const QStringList& channelSettingsKeys, diff --git a/plugins/channeltx/modatv/atvmodgui.cpp b/plugins/channeltx/modatv/atvmodgui.cpp index 49caab00a..3be698ead 100644 --- a/plugins/channeltx/modatv/atvmodgui.cpp +++ b/plugins/channeltx/modatv/atvmodgui.cpp @@ -21,6 +21,7 @@ #include #include #include +#include #include @@ -28,6 +29,7 @@ #include "plugin/pluginapi.h" #include "util/simpleserializer.h" #include "dsp/dspengine.h" +#include "dsp/dspcommands.h" #include "util/db.h" #include "gui/basicchannelsettingsdialog.h" #include "gui/devicestreamselectiondialog.h" @@ -54,6 +56,8 @@ ATVModGUI::ATVModGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, BasebandSam m_pluginAPI(pluginAPI), m_deviceUISet(deviceUISet), m_channelMarker(this), + m_deviceCenterFrequency(0), + m_basebandSampleRate(1), m_doApplySettings(true), m_videoLength(0), m_videoFrameRate(48000), @@ -63,10 +67,13 @@ ATVModGUI::ATVModGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, BasebandSam m_camBusyFPSMessageBox(0), m_rfSliderDivisor(100000) { - ui->setupUi(this); - m_helpURL = "plugins/channeltx/modatv/readme.md"; setAttribute(Qt::WA_DeleteOnClose, true); - connect(this, SIGNAL(widgetRolled(QWidget*,bool)), this, SLOT(onWidgetRolled(QWidget*,bool))); + m_helpURL = "plugins/channeltx/modatv/readme.md"; + RollupContents *rollupContents = getRollupContents(); + ui->setupUi(rollupContents); + setSizePolicy(rollupContents->sizePolicy()); + rollupContents->arrangeRollups(); + connect(rollupContents, SIGNAL(widgetRolled(QWidget*,bool)), this, SLOT(onWidgetRolled(QWidget*,bool))); connect(this, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(onMenuDialogCalled(const QPoint &))); m_atvMod = (ATVMod*) channelTx; @@ -92,7 +99,6 @@ ATVModGUI::ATVModGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, BasebandSam m_settings.setRollupState(&m_rollupState); m_deviceUISet->addChannelMarker(&m_channelMarker); - m_deviceUISet->addRollupWidget(this); connect(&m_channelMarker, SIGNAL(changedByCursor()), this, SLOT(channelMarkerChangedByCursor())); @@ -112,6 +118,7 @@ ATVModGUI::ATVModGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, BasebandSam ui->fmExcursionLabel->setText(delta); displaySettings(); + makeUIConnections(); applySettings(true); } @@ -147,6 +154,14 @@ bool ATVModGUI::deserialize(const QByteArray& data) } } +void ATVModGUI::resizeEvent(QResizeEvent* size) +{ + int maxWidth = getRollupContents()->maximumWidth(); + int minHeight = getRollupContents()->minimumHeight() + getAdditionalHeight(); + resize(width() < maxWidth ? width() : maxWidth, minHeight); + size->accept(); +} + bool ATVModGUI::handleMessage(const Message& message) { if (ATVModReport::MsgReportVideoFileSourceStreamData::match(message)) @@ -226,6 +241,16 @@ bool ATVModGUI::handleMessage(const Message& message) ui->videoFileText->setText(cfg.getFileName()); return true; } + else if (DSPSignalNotification::match(message)) + { + const DSPSignalNotification& notif = (const DSPSignalNotification&) message; + m_deviceCenterFrequency = notif.getCenterFrequency(); + m_basebandSampleRate = notif.getSampleRate(); + ui->deltaFrequency->setValueRange(false, 8, -m_basebandSampleRate/2, m_basebandSampleRate/2); + ui->deltaFrequencyLabel->setToolTip(tr("Range %1 %L2 Hz").arg(QChar(0xB1)).arg(m_basebandSampleRate/2)); + updateAbsoluteCenterFrequency(); + return true; + } else { return false; @@ -433,6 +458,7 @@ void ATVModGUI::on_deltaFrequency_changed(qint64 value) { m_channelMarker.setCenterFrequency(value); m_settings.m_inputFrequencyOffset = value; + updateAbsoluteCenterFrequency(); applySettings(); } @@ -671,7 +697,7 @@ void ATVModGUI::onWidgetRolled(QWidget* widget, bool rollDown) (void) widget; (void) rollDown; - saveState(m_rollupState); + getRollupContents()->saveState(m_rollupState); applySettings(); } @@ -685,11 +711,17 @@ void ATVModGUI::onMenuDialogCalled(const QPoint &p) dialog.setReverseAPIPort(m_settings.m_reverseAPIPort); dialog.setReverseAPIDeviceIndex(m_settings.m_reverseAPIDeviceIndex); dialog.setReverseAPIChannelIndex(m_settings.m_reverseAPIChannelIndex); + dialog.setDefaultTitle(m_displayedName); + + if (m_deviceUISet->m_deviceMIMOEngine) + { + dialog.setNumberOfStreams(m_atvMod->getNumberOfDeviceStreams()); + dialog.setStreamIndex(m_settings.m_streamIndex); + } dialog.move(p); dialog.exec(); - m_settings.m_inputFrequencyOffset = m_channelMarker.getCenterFrequency(); m_settings.m_rgbColor = m_channelMarker.getColor().rgb(); m_settings.m_title = m_channelMarker.getTitle(); m_settings.m_useReverseAPI = dialog.useReverseAPI(); @@ -699,22 +731,17 @@ void ATVModGUI::onMenuDialogCalled(const QPoint &p) m_settings.m_reverseAPIChannelIndex = dialog.getReverseAPIChannelIndex(); setWindowTitle(m_settings.m_title); + setTitle(m_channelMarker.getTitle()); setTitleColor(m_settings.m_rgbColor); - applySettings(); - } - else if ((m_contextMenuType == ContextMenuStreamSettings) && (m_deviceUISet->m_deviceMIMOEngine)) - { - DeviceStreamSelectionDialog dialog(this); - dialog.setNumberOfStreams(m_atvMod->getNumberOfDeviceStreams()); - dialog.setStreamIndex(m_settings.m_streamIndex); - dialog.move(p); - dialog.exec(); + if (m_deviceUISet->m_deviceMIMOEngine) + { + m_settings.m_streamIndex = dialog.getSelectedStreamIndex(); + m_channelMarker.clearStreamIndexes(); + m_channelMarker.addStreamIndex(m_settings.m_streamIndex); + updateIndexLabel(); + } - m_settings.m_streamIndex = dialog.getSelectedStreamIndex(); - m_channelMarker.clearStreamIndexes(); - m_channelMarker.addStreamIndex(m_settings.m_streamIndex); - displayStreamIndex(); applySettings(); } @@ -750,7 +777,8 @@ void ATVModGUI::displaySettings() setTitleColor(m_settings.m_rgbColor); setWindowTitle(m_channelMarker.getTitle()); - displayStreamIndex(); + setTitle(m_channelMarker.getTitle()); + updateIndexLabel(); blockApplySettings(true); @@ -796,27 +824,21 @@ void ATVModGUI::displaySettings() ui->playVideo->setChecked(m_settings.m_videoPlay); ui->playLoop->setChecked(m_settings.m_videoPlayLoop); - restoreState(m_rollupState); + getRollupContents()->restoreState(m_rollupState); + updateAbsoluteCenterFrequency(); blockApplySettings(false); } -void ATVModGUI::displayStreamIndex() -{ - if (m_deviceUISet->m_deviceMIMOEngine) { - setStreamIndicator(tr("%1").arg(m_settings.m_streamIndex)); - } else { - setStreamIndicator("S"); // single channel indicator - } -} - -void ATVModGUI::leaveEvent(QEvent*) +void ATVModGUI::leaveEvent(QEvent* event) { m_channelMarker.setHighlighted(false); + ChannelGUI::leaveEvent(event); } -void ATVModGUI::enterEvent(QEvent*) +void ATVModGUI::enterEvent(QEvent* event) { m_channelMarker.setHighlighted(true); + ChannelGUI::enterEvent(event); } void ATVModGUI::tick() @@ -867,3 +889,36 @@ void ATVModGUI::updateWithStreamTime() } } +void ATVModGUI::makeUIConnections() +{ + QObject::connect(ui->deltaFrequency, &ValueDialZ::changed, this, &ATVModGUI::on_deltaFrequency_changed); + QObject::connect(ui->channelMute, &QToolButton::toggled, this, &ATVModGUI::on_channelMute_toggled); + QObject::connect(ui->forceDecimator, &ButtonSwitch::toggled, this, &ATVModGUI::on_forceDecimator_toggled); + QObject::connect(ui->modulation, QOverload::of(&QComboBox::currentIndexChanged), this, &ATVModGUI::on_modulation_currentIndexChanged); + QObject::connect(ui->rfScaling, &QDial::valueChanged, this, &ATVModGUI::on_rfScaling_valueChanged); + QObject::connect(ui->fmExcursion, &QDial::valueChanged, this, &ATVModGUI::on_fmExcursion_valueChanged); + QObject::connect(ui->rfBW, &QSlider::valueChanged, this, &ATVModGUI::on_rfBW_valueChanged); + QObject::connect(ui->rfOppBW, &QSlider::valueChanged, this, &ATVModGUI::on_rfOppBW_valueChanged); + QObject::connect(ui->nbLines, QOverload::of(&QComboBox::currentIndexChanged), this, &ATVModGUI::on_nbLines_currentIndexChanged); + QObject::connect(ui->fps, QOverload::of(&QComboBox::currentIndexChanged), this, &ATVModGUI::on_fps_currentIndexChanged); + QObject::connect(ui->standard, QOverload::of(&QComboBox::currentIndexChanged), this, &ATVModGUI::on_standard_currentIndexChanged); + QObject::connect(ui->invertVideo, &QCheckBox::clicked, this, &ATVModGUI::on_invertVideo_clicked); + QObject::connect(ui->uniformLevel, &QDial::valueChanged, this, &ATVModGUI::on_uniformLevel_valueChanged); + QObject::connect(ui->inputSelect, QOverload::of(&QComboBox::currentIndexChanged), this, &ATVModGUI::on_inputSelect_currentIndexChanged); + QObject::connect(ui->imageFileDialog, &QPushButton::clicked, this, &ATVModGUI::on_imageFileDialog_clicked); + QObject::connect(ui->videoFileDialog, &QPushButton::clicked, this, &ATVModGUI::on_videoFileDialog_clicked); + QObject::connect(ui->playVideo, &ButtonSwitch::toggled, this, &ATVModGUI::on_playVideo_toggled); + QObject::connect(ui->playLoop, &ButtonSwitch::toggled, this, &ATVModGUI::on_playLoop_toggled); + QObject::connect(ui->navTimeSlider, &QSlider::valueChanged, this, &ATVModGUI::on_navTimeSlider_valueChanged); + QObject::connect(ui->playCamera, &ButtonSwitch::toggled, this, &ATVModGUI::on_playCamera_toggled); + QObject::connect(ui->camSelect, QOverload::of(&QComboBox::currentIndexChanged), this, &ATVModGUI::on_camSelect_currentIndexChanged); + QObject::connect(ui->cameraManualFPSEnable, &ButtonSwitch::toggled, this, &ATVModGUI::on_cameraManualFPSEnable_toggled); + QObject::connect(ui->cameraManualFPS, &QDial::valueChanged, this, &ATVModGUI::on_cameraManualFPS_valueChanged); + QObject::connect(ui->overlayTextShow, &ButtonSwitch::toggled, this, &ATVModGUI::on_overlayTextShow_toggled); + QObject::connect(ui->overlayText, &QLineEdit::textEdited, this, &ATVModGUI::on_overlayText_textEdited); +} + +void ATVModGUI::updateAbsoluteCenterFrequency() +{ + setStatusFrequency(m_deviceCenterFrequency + m_settings.m_inputFrequencyOffset); +} diff --git a/plugins/channeltx/modatv/atvmodgui.h b/plugins/channeltx/modatv/atvmodgui.h index cf22f35d6..d8235ebb0 100644 --- a/plugins/channeltx/modatv/atvmodgui.h +++ b/plugins/channeltx/modatv/atvmodgui.h @@ -47,10 +47,24 @@ public: QByteArray serialize() const; bool deserialize(const QByteArray& data); virtual MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; } + virtual void setWorkspaceIndex(int index) { m_settings.m_workspaceIndex = index; }; + virtual int getWorkspaceIndex() const { return m_settings.m_workspaceIndex; }; + virtual void setGeometryBytes(const QByteArray& blob) { m_settings.m_geometryBytes = blob; }; + virtual QByteArray getGeometryBytes() const { return m_settings.m_geometryBytes; }; + virtual QString getTitle() const { return m_settings.m_title; }; + virtual QColor getTitleColor() const { return m_settings.m_rgbColor; }; + virtual void zetHidden(bool hidden) { m_settings.m_hidden = hidden; } + virtual bool getHidden() const { return m_settings.m_hidden; } + virtual ChannelMarker& getChannelMarker() { return m_channelMarker; } + virtual int getStreamIndex() const { return m_settings.m_streamIndex; } + virtual void setStreamIndex(int streamIndex) { m_settings.m_streamIndex = streamIndex; } public slots: void channelMarkerChangedByCursor(); +protected: + void resizeEvent(QResizeEvent* size); + private: Ui::ATVModGUI* ui; PluginAPI* m_pluginAPI; @@ -58,6 +72,8 @@ private: ChannelMarker m_channelMarker; RollupState m_rollupState; ATVModSettings m_settings; + qint64 m_deviceCenterFrequency; + int m_basebandSampleRate; bool m_doApplySettings; ATVMod* m_atvMod; @@ -80,7 +96,6 @@ private: void blockApplySettings(bool block); void applySettings(bool force = false); void displaySettings(); - void displayStreamIndex(); void updateWithStreamData(); void updateWithStreamTime(); void setRFFiltersSlidersRange(int sampleRate); @@ -90,6 +105,8 @@ private: int getNbLinesIndex(int nbLines); int getFPSIndex(int fps); bool handleMessage(const Message& message); + void makeUIConnections(); + void updateAbsoluteCenterFrequency(); void leaveEvent(QEvent*); void enterEvent(QEvent*); diff --git a/plugins/channeltx/modatv/atvmodgui.ui b/plugins/channeltx/modatv/atvmodgui.ui index 86af812c5..d175a0f95 100644 --- a/plugins/channeltx/modatv/atvmodgui.ui +++ b/plugins/channeltx/modatv/atvmodgui.ui @@ -1,7 +1,7 @@ ATVModGUI - + 0 @@ -11,7 +11,7 @@ - + 0 0 @@ -22,6 +22,12 @@ 0 + + + 760 + 16777215 + + Liberation Sans @@ -1304,15 +1310,15 @@ - RollupWidget + RollupContents QWidget -
gui/rollupwidget.h
+
gui/rollupcontents.h
1
- LevelMeterVU + ValueDialZ QWidget -
gui/levelmeter.h
+
gui/valuedialz.h
1
@@ -1321,9 +1327,9 @@
gui/buttonswitch.h
- ValueDialZ + LevelMeterVU QWidget -
gui/valuedialz.h
+
gui/levelmeter.h
1
diff --git a/plugins/channeltx/modatv/atvmodsettings.cpp b/plugins/channeltx/modatv/atvmodsettings.cpp index 060f4237e..c3176cfa6 100644 --- a/plugins/channeltx/modatv/atvmodsettings.cpp +++ b/plugins/channeltx/modatv/atvmodsettings.cpp @@ -58,6 +58,8 @@ void ATVModSettings::resetToDefaults() m_reverseAPIPort = 8888; m_reverseAPIDeviceIndex = 0; m_reverseAPIChannelIndex = 0; + m_workspaceIndex = 0; + m_hidden = false; } QByteArray ATVModSettings::serialize() const @@ -97,6 +99,10 @@ QByteArray ATVModSettings::serialize() const s.writeBlob(25, m_rollupState->serialize()); } + s.writeS32(26, m_workspaceIndex); + s.writeBlob(27, m_geometryBytes); + s.writeBool(28, m_hidden); + return s.final(); } @@ -169,6 +175,10 @@ bool ATVModSettings::deserialize(const QByteArray& data) m_rollupState->deserialize(bytetmp); } + d.readS32(26, &m_workspaceIndex, 0); + d.readBlob(27, &m_geometryBytes); + d.readBool(28, &m_hidden, false); + return true; } else diff --git a/plugins/channeltx/modatv/atvmodsettings.h b/plugins/channeltx/modatv/atvmodsettings.h index 8c4d66bf5..59984d633 100644 --- a/plugins/channeltx/modatv/atvmodsettings.h +++ b/plugins/channeltx/modatv/atvmodsettings.h @@ -89,6 +89,9 @@ struct ATVModSettings uint16_t m_reverseAPIPort; uint16_t m_reverseAPIDeviceIndex; uint16_t m_reverseAPIChannelIndex; + int m_workspaceIndex; + QByteArray m_geometryBytes; + bool m_hidden; Serializable *m_channelMarker; Serializable *m_rollupState; diff --git a/plugins/channeltx/modatv/readme.md b/plugins/channeltx/modatv/readme.md index 653248cad..50592d913 100644 --- a/plugins/channeltx/modatv/readme.md +++ b/plugins/channeltx/modatv/readme.md @@ -10,6 +10,8 @@ In practice 4 MS/s with about 300 points per line is the lowest sample rate that

Interface

+The top and bottom bars of the channel window are described [here](../../../sdrgui/channel/readme.md) + ![ATV Modulator plugin GUI](../../../doc/img/ATVMod_plugin.png)

1: Frequency shift from center frequency of transmission

diff --git a/plugins/channeltx/modchirpchat/chirpchatmod.cpp b/plugins/channeltx/modchirpchat/chirpchatmod.cpp index dc849b71b..37f7fd8ec 100644 --- a/plugins/channeltx/modchirpchat/chirpchatmod.cpp +++ b/plugins/channeltx/modchirpchat/chirpchatmod.cpp @@ -26,6 +26,7 @@ #include #include "SWGChannelSettings.h" +#include "SWGWorkspaceInfo.h" #include "SWGChannelReport.h" #include "SWGChirpChatModReport.h" @@ -93,6 +94,18 @@ ChirpChatMod::~ChirpChatMod() delete m_thread; } +void ChirpChatMod::setDeviceAPI(DeviceAPI *deviceAPI) +{ + if (deviceAPI != m_deviceAPI) + { + m_deviceAPI->removeChannelSourceAPI(this); + m_deviceAPI->removeChannelSource(this); + m_deviceAPI = deviceAPI; + m_deviceAPI->addChannelSource(this); + m_deviceAPI->addChannelSinkAPI(this); + } +} + void ChirpChatMod::start() { qDebug("ChirpChatMod::start"); @@ -132,10 +145,8 @@ bool ChirpChatMod::handleMessage(const Message& cmd) m_basebandSource->getInputMessageQueue()->push(rep); // Forward to the GUI - if (getMessageQueueToGUI()) - { - DSPSignalNotification* repToGUI = new DSPSignalNotification(notif); // make a copy - getMessageQueueToGUI()->push(repToGUI); + if (getMessageQueueToGUI()) { + getMessageQueueToGUI()->push(new DSPSignalNotification(notif)); } return true; @@ -448,6 +459,15 @@ int ChirpChatMod::webapiSettingsGet( return 200; } +int ChirpChatMod::webapiWorkspaceGet( + SWGSDRangel::SWGWorkspaceInfo& response, + QString& errorMessage) +{ + (void) errorMessage; + response.setIndex(m_settings.m_workspaceIndex); + return 200; +} + int ChirpChatMod::webapiSettingsPutPatch( bool force, const QStringList& channelSettingsKeys, diff --git a/plugins/channeltx/modchirpchat/chirpchatmod.h b/plugins/channeltx/modchirpchat/chirpchatmod.h index 09c0c0b22..18214d66e 100644 --- a/plugins/channeltx/modchirpchat/chirpchatmod.h +++ b/plugins/channeltx/modchirpchat/chirpchatmod.h @@ -89,6 +89,8 @@ public: ChirpChatMod(DeviceAPI *deviceAPI); virtual ~ChirpChatMod(); virtual void destroy() { delete this; } + virtual void setDeviceAPI(DeviceAPI *deviceAPI); + virtual DeviceAPI *getDeviceAPI() { return m_deviceAPI; } virtual void start(); virtual void stop(); @@ -119,6 +121,10 @@ public: SWGSDRangel::SWGChannelSettings& response, QString& errorMessage); + virtual int webapiWorkspaceGet( + SWGSDRangel::SWGWorkspaceInfo& response, + QString& errorMessage); + virtual int webapiSettingsPutPatch( bool force, const QStringList& channelSettingsKeys, diff --git a/plugins/channeltx/modchirpchat/chirpchatmodgui.cpp b/plugins/channeltx/modchirpchat/chirpchatmodgui.cpp index d7987b6d7..30c055a3c 100644 --- a/plugins/channeltx/modchirpchat/chirpchatmodgui.cpp +++ b/plugins/channeltx/modchirpchat/chirpchatmodgui.cpp @@ -20,6 +20,7 @@ #include #include #include +#include #include "device/deviceuiset.h" #include "plugin/pluginapi.h" @@ -74,6 +75,14 @@ bool ChirpChatModGUI::deserialize(const QByteArray& data) } } +void ChirpChatModGUI::resizeEvent(QResizeEvent* size) +{ + int maxWidth = getRollupContents()->maximumWidth(); + int minHeight = getRollupContents()->minimumHeight() + getAdditionalHeight(); + resize(width() < maxWidth ? width() : maxWidth, minHeight); + size->accept(); +} + bool ChirpChatModGUI::handleMessage(const Message& message) { if (ChirpChatMod::MsgConfigureChirpChatMod::match(message)) @@ -102,6 +111,7 @@ bool ChirpChatModGUI::handleMessage(const Message& message) else if (DSPSignalNotification::match(message)) { DSPSignalNotification& notif = (DSPSignalNotification&) message; + m_deviceCenterFrequency = notif.getCenterFrequency(); int basebandSampleRate = notif.getSampleRate(); qDebug() << "ChirpChatModGUI::handleMessage: DSPSignalNotification: m_basebandSampleRate: " << basebandSampleRate; @@ -111,6 +121,10 @@ bool ChirpChatModGUI::handleMessage(const Message& message) setBandwidths(); } + ui->deltaFrequency->setValueRange(false, 7, -m_basebandSampleRate/2, m_basebandSampleRate/2); + ui->deltaFrequencyLabel->setToolTip(tr("Range %1 %L2 Hz").arg(QChar(0xB1)).arg(m_basebandSampleRate/2)); + updateAbsoluteCenterFrequency(); + return true; } else @@ -143,6 +157,7 @@ void ChirpChatModGUI::on_deltaFrequency_changed(qint64 value) { m_channelMarker.setCenterFrequency(value); m_settings.m_inputFrequencyOffset = m_channelMarker.getCenterFrequency(); + updateAbsoluteCenterFrequency(); applySettings(); } @@ -357,7 +372,7 @@ void ChirpChatModGUI::onWidgetRolled(QWidget* widget, bool rollDown) (void) widget; (void) rollDown; - saveState(m_rollupState); + getRollupContents()->saveState(m_rollupState); applySettings(); } @@ -371,10 +386,17 @@ void ChirpChatModGUI::onMenuDialogCalled(const QPoint &p) dialog.setReverseAPIPort(m_settings.m_reverseAPIPort); dialog.setReverseAPIDeviceIndex(m_settings.m_reverseAPIDeviceIndex); dialog.setReverseAPIChannelIndex(m_settings.m_reverseAPIChannelIndex); + dialog.setDefaultTitle(m_displayedName); + + if (m_deviceUISet->m_deviceMIMOEngine) + { + dialog.setNumberOfStreams(m_chirpChatMod->getNumberOfDeviceStreams()); + dialog.setStreamIndex(m_settings.m_streamIndex); + } + dialog.move(p); dialog.exec(); - m_settings.m_inputFrequencyOffset = m_channelMarker.getCenterFrequency(); m_settings.m_rgbColor = m_channelMarker.getColor().rgb(); m_settings.m_title = m_channelMarker.getTitle(); m_settings.m_useReverseAPI = dialog.useReverseAPI(); @@ -384,22 +406,17 @@ void ChirpChatModGUI::onMenuDialogCalled(const QPoint &p) m_settings.m_reverseAPIChannelIndex = dialog.getReverseAPIChannelIndex(); setWindowTitle(m_settings.m_title); + setTitle(m_channelMarker.getTitle()); setTitleColor(m_settings.m_rgbColor); - applySettings(); - } - else if ((m_contextMenuType == ContextMenuStreamSettings) && (m_deviceUISet->m_deviceMIMOEngine)) - { - DeviceStreamSelectionDialog dialog(this); - dialog.setNumberOfStreams(m_chirpChatMod->getNumberOfDeviceStreams()); - dialog.setStreamIndex(m_settings.m_streamIndex); - dialog.move(p); - dialog.exec(); + if (m_deviceUISet->m_deviceMIMOEngine) + { + m_settings.m_streamIndex = dialog.getSelectedStreamIndex(); + m_channelMarker.clearStreamIndexes(); + m_channelMarker.addStreamIndex(m_settings.m_streamIndex); + updateIndexLabel(); + } - m_settings.m_streamIndex = dialog.getSelectedStreamIndex(); - m_channelMarker.clearStreamIndexes(); - m_channelMarker.addStreamIndex(m_settings.m_streamIndex); - displayStreamIndex(); applySettings(); } @@ -412,15 +429,18 @@ ChirpChatModGUI::ChirpChatModGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, m_pluginAPI(pluginAPI), m_deviceUISet(deviceUISet), m_channelMarker(this), + m_deviceCenterFrequency(0), m_basebandSampleRate(125000), m_doApplySettings(true), m_tickCount(0) { - ui->setupUi(this); - m_helpURL = "plugins/channeltx/modchirpchat/readme.md"; setAttribute(Qt::WA_DeleteOnClose, true); - - connect(this, SIGNAL(widgetRolled(QWidget*,bool)), this, SLOT(onWidgetRolled(QWidget*,bool))); + m_helpURL = "plugins/channeltx/modchirpchat/readme.md"; + RollupContents *rollupContents = getRollupContents(); + ui->setupUi(rollupContents); + setSizePolicy(rollupContents->sizePolicy()); + rollupContents->arrangeRollups(); + connect(rollupContents, SIGNAL(widgetRolled(QWidget*,bool)), this, SLOT(onWidgetRolled(QWidget*,bool))); connect(this, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(onMenuDialogCalled(const QPoint &))); m_chirpChatMod = (ChirpChatMod*) channelTx; @@ -442,7 +462,6 @@ ChirpChatModGUI::ChirpChatModGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, m_channelMarker.setVisible(true); // activate signal on the last setting only m_deviceUISet->addChannelMarker(&m_channelMarker); - m_deviceUISet->addRollupWidget(this); connect(&m_channelMarker, SIGNAL(changedByCursor()), this, SLOT(channelMarkerChangedByCursor())); @@ -453,6 +472,7 @@ ChirpChatModGUI::ChirpChatModGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, setBandwidths(); displaySettings(); + makeUIConnections(); applySettings(); } @@ -488,7 +508,8 @@ void ChirpChatModGUI::displaySettings() setTitleColor(m_settings.m_rgbColor); setWindowTitle(m_channelMarker.getTitle()); - displayStreamIndex(); + setTitle(m_channelMarker.getTitle()); + updateIndexLabel(); displayCurrentPayloadMessage(); displayBinaryMessage(); @@ -525,19 +546,11 @@ void ChirpChatModGUI::displaySettings() ui->udpEnabled->setChecked(m_settings.m_udpEnabled); ui->udpAddress->setText(m_settings.m_udpAddress); ui->udpPort->setText(QString::number(m_settings.m_udpPort)); - restoreState(m_rollupState); + getRollupContents()->restoreState(m_rollupState); + updateAbsoluteCenterFrequency(); blockApplySettings(false); } -void ChirpChatModGUI::displayStreamIndex() -{ - if (m_deviceUISet->m_deviceMIMOEngine) { - setStreamIndicator(tr("%1").arg(m_settings.m_streamIndex)); - } else { - setStreamIndicator("S"); // single channel indicator - } -} - void ChirpChatModGUI::displayCurrentPayloadMessage() { ui->messageText->blockSignals(true); @@ -589,14 +602,16 @@ void ChirpChatModGUI::setBandwidths() } } -void ChirpChatModGUI::leaveEvent(QEvent*) +void ChirpChatModGUI::leaveEvent(QEvent* event) { m_channelMarker.setHighlighted(false); + ChannelGUI::leaveEvent(event); } -void ChirpChatModGUI::enterEvent(QEvent*) +void ChirpChatModGUI::enterEvent(QEvent* event) { m_channelMarker.setHighlighted(true); + ChannelGUI::enterEvent(event); } void ChirpChatModGUI::tick() @@ -619,3 +634,38 @@ void ChirpChatModGUI::tick() } } } + +void ChirpChatModGUI::makeUIConnections() +{ + QObject::connect(ui->deltaFrequency, &ValueDialZ::changed, this, &ChirpChatModGUI::on_deltaFrequency_changed); + QObject::connect(ui->bw, &QSlider::valueChanged, this, &ChirpChatModGUI::on_bw_valueChanged); + QObject::connect(ui->spread, &QSlider::valueChanged, this, &ChirpChatModGUI::on_spread_valueChanged); + QObject::connect(ui->deBits, &QSlider::valueChanged, this, &ChirpChatModGUI::on_deBits_valueChanged); + QObject::connect(ui->preambleChirps, &QSlider::valueChanged, this, &ChirpChatModGUI::on_preambleChirps_valueChanged); + QObject::connect(ui->idleTime, &QSlider::valueChanged, this, &ChirpChatModGUI::on_idleTime_valueChanged); + QObject::connect(ui->syncWord, &QLineEdit::editingFinished, this, &ChirpChatModGUI::on_syncWord_editingFinished); + QObject::connect(ui->channelMute, &QToolButton::toggled, this, &ChirpChatModGUI::on_channelMute_toggled); + QObject::connect(ui->scheme, QOverload::of(&QComboBox::currentIndexChanged), this, &ChirpChatModGUI::on_scheme_currentIndexChanged); + QObject::connect(ui->fecParity, &QDial::valueChanged, this, &ChirpChatModGUI::on_fecParity_valueChanged); + QObject::connect(ui->crc, &QCheckBox::stateChanged, this, &ChirpChatModGUI::on_crc_stateChanged); + QObject::connect(ui->header, &QCheckBox::stateChanged, this, &ChirpChatModGUI::on_header_stateChanged); + QObject::connect(ui->myCall, &QLineEdit::editingFinished, this, &ChirpChatModGUI::on_myCall_editingFinished); + QObject::connect(ui->urCall, &QLineEdit::editingFinished, this, &ChirpChatModGUI::on_urCall_editingFinished); + QObject::connect(ui->myLocator, &QLineEdit::editingFinished, this, &ChirpChatModGUI::on_myLocator_editingFinished); + QObject::connect(ui->report, &QLineEdit::editingFinished, this, &ChirpChatModGUI::on_report_editingFinished); + QObject::connect(ui->msgType, QOverload::of(&QComboBox::currentIndexChanged), this, &ChirpChatModGUI::on_msgType_currentIndexChanged); + QObject::connect(ui->resetMessages, &QPushButton::clicked, this, &ChirpChatModGUI::on_resetMessages_clicked); + QObject::connect(ui->playMessage, &QPushButton::clicked, this, &ChirpChatModGUI::on_playMessage_clicked); + QObject::connect(ui->repeatMessage, &QDial::valueChanged, this, &ChirpChatModGUI::on_repeatMessage_valueChanged); + QObject::connect(ui->generateMessages, &QPushButton::clicked, this, &ChirpChatModGUI::on_generateMessages_clicked); + QObject::connect(ui->messageText, &CustomTextEdit::editingFinished, this, &ChirpChatModGUI::on_messageText_editingFinished); + QObject::connect(ui->hexText, &QLineEdit::editingFinished, this, &ChirpChatModGUI::on_hexText_editingFinished); + QObject::connect(ui->udpEnabled, &QCheckBox::clicked, this, &ChirpChatModGUI::on_udpEnabled_clicked); + QObject::connect(ui->udpAddress, &QLineEdit::editingFinished, this, &ChirpChatModGUI::on_udpAddress_editingFinished); + QObject::connect(ui->udpPort, &QLineEdit::editingFinished, this, &ChirpChatModGUI::on_udpPort_editingFinished); +} + +void ChirpChatModGUI::updateAbsoluteCenterFrequency() +{ + setStatusFrequency(m_deviceCenterFrequency + m_settings.m_inputFrequencyOffset); +} diff --git a/plugins/channeltx/modchirpchat/chirpchatmodgui.h b/plugins/channeltx/modchirpchat/chirpchatmodgui.h index 38d776cf5..219a7f933 100644 --- a/plugins/channeltx/modchirpchat/chirpchatmodgui.h +++ b/plugins/channeltx/modchirpchat/chirpchatmodgui.h @@ -46,10 +46,24 @@ public: QByteArray serialize() const; bool deserialize(const QByteArray& data); virtual MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; } + virtual void setWorkspaceIndex(int index) { m_settings.m_workspaceIndex = index; }; + virtual int getWorkspaceIndex() const { return m_settings.m_workspaceIndex; }; + virtual void setGeometryBytes(const QByteArray& blob) { m_settings.m_geometryBytes = blob; }; + virtual QByteArray getGeometryBytes() const { return m_settings.m_geometryBytes; }; + virtual QString getTitle() const { return m_settings.m_title; }; + virtual QColor getTitleColor() const { return m_settings.m_rgbColor; }; + virtual void zetHidden(bool hidden) { m_settings.m_hidden = hidden; } + virtual bool getHidden() const { return m_settings.m_hidden; } + virtual ChannelMarker& getChannelMarker() { return m_channelMarker; } + virtual int getStreamIndex() const { return m_settings.m_streamIndex; } + virtual void setStreamIndex(int streamIndex) { m_settings.m_streamIndex = streamIndex; } public slots: void channelMarkerChangedByCursor(); +protected: + void resizeEvent(QResizeEvent* size); + private: Ui::ChirpChatModGUI* ui; PluginAPI* m_pluginAPI; @@ -57,6 +71,7 @@ private: ChannelMarker m_channelMarker; RollupState m_rollupState; ChirpChatModSettings m_settings; + qint64 m_deviceCenterFrequency; int m_basebandSampleRate; bool m_doApplySettings; @@ -72,11 +87,12 @@ private: void blockApplySettings(bool block); void applySettings(bool force = false); void displaySettings(); - void displayStreamIndex(); void displayCurrentPayloadMessage(); void displayBinaryMessage(); void setBandwidths(); bool handleMessage(const Message& message); + void makeUIConnections(); + void updateAbsoluteCenterFrequency(); void leaveEvent(QEvent*); void enterEvent(QEvent*); diff --git a/plugins/channeltx/modchirpchat/chirpchatmodgui.ui b/plugins/channeltx/modchirpchat/chirpchatmodgui.ui index 96eee61b2..feb0f9db1 100644 --- a/plugins/channeltx/modchirpchat/chirpchatmodgui.ui +++ b/plugins/channeltx/modchirpchat/chirpchatmodgui.ui @@ -1,7 +1,7 @@ ChirpChatModGUI - + 0 @@ -10,12 +10,24 @@ 573 + + + 0 + 0 + + 392 180 + + + 560 + 16777215 + + Liberation Sans @@ -26,9 +38,6 @@ ChirpChat Modulator - - RF/mod/coder settings - 0 @@ -37,6 +46,9 @@ 131 + + RF/mod/coder settings + 2 @@ -498,9 +510,6 @@ - - Payload - 0 @@ -509,6 +518,9 @@ 401 + + Payload + 2 @@ -1180,27 +1192,14 @@
- - - - Qt::Vertical - - - - 20 - 40 - - - -
- RollupWidget + RollupContents QWidget -
gui/rollupwidget.h
+
gui/rollupcontents.h
1
diff --git a/plugins/channeltx/modchirpchat/chirpchatmodsettings.cpp b/plugins/channeltx/modchirpchat/chirpchatmodsettings.cpp index ad5669490..e2a37cd75 100644 --- a/plugins/channeltx/modchirpchat/chirpchatmodsettings.cpp +++ b/plugins/channeltx/modchirpchat/chirpchatmodsettings.cpp @@ -93,6 +93,9 @@ void ChirpChatModSettings::resetToDefaults() m_reverseAPIPort = 8888; m_reverseAPIDeviceIndex = 0; m_reverseAPIChannelIndex = 0; + m_workspaceIndex = 0; + m_hidden = false; + setDefaultTemplates(); } @@ -201,6 +204,10 @@ QByteArray ChirpChatModSettings::serialize() const s.writeBlob(59, m_rollupState->serialize()); } + s.writeS32(60, m_workspaceIndex); + s.writeBlob(61, m_geometryBytes); + s.writeBool(62, m_hidden); + return s.final(); } @@ -305,6 +312,10 @@ bool ChirpChatModSettings::deserialize(const QByteArray& data) m_rollupState->deserialize(bytetmp); } + d.readS32(60, &m_workspaceIndex, 0); + d.readBlob(61, &m_geometryBytes); + d.readBool(62, &m_hidden, false); + return true; } else diff --git a/plugins/channeltx/modchirpchat/chirpchatmodsettings.h b/plugins/channeltx/modchirpchat/chirpchatmodsettings.h index aee95ce76..15e46323e 100644 --- a/plugins/channeltx/modchirpchat/chirpchatmodsettings.h +++ b/plugins/channeltx/modchirpchat/chirpchatmodsettings.h @@ -88,6 +88,9 @@ struct ChirpChatModSettings uint16_t m_reverseAPIPort; uint16_t m_reverseAPIDeviceIndex; uint16_t m_reverseAPIChannelIndex; + int m_workspaceIndex; + QByteArray m_geometryBytes; + bool m_hidden; Serializable *m_channelMarker; Serializable *m_rollupState; diff --git a/plugins/channeltx/modchirpchat/readme.md b/plugins/channeltx/modchirpchat/readme.md index 46dcfefd4..31c8e6698 100644 --- a/plugins/channeltx/modchirpchat/readme.md +++ b/plugins/channeltx/modchirpchat/readme.md @@ -19,6 +19,8 @@ Note: this plugin is officially supported since version 6.

Interface

+The top and bottom bars of the channel window are described [here](../../../sdrgui/channel/readme.md) + ![ChitpChat Modulator plugin GUI](../../../doc/img/ChirpChatMod_plugin.png)

1: Frequency shift from center frequency of reception

diff --git a/plugins/channeltx/moddatv/datvmod.cpp b/plugins/channeltx/moddatv/datvmod.cpp index 2cbe26e06..196ecd85c 100644 --- a/plugins/channeltx/moddatv/datvmod.cpp +++ b/plugins/channeltx/moddatv/datvmod.cpp @@ -31,6 +31,7 @@ #include #include "SWGChannelSettings.h" +#include "SWGWorkspaceInfo.h" #include "SWGChannelReport.h" //#include "SWGDATVModReport.h" @@ -97,6 +98,18 @@ DATVMod::~DATVMod() delete m_thread; } +void DATVMod::setDeviceAPI(DeviceAPI *deviceAPI) +{ + if (deviceAPI != m_deviceAPI) + { + m_deviceAPI->removeChannelSourceAPI(this); + m_deviceAPI->removeChannelSource(this); + m_deviceAPI = deviceAPI; + m_deviceAPI->addChannelSource(this); + m_deviceAPI->addChannelSinkAPI(this); + } +} + uint32_t DATVMod::getNumberOfDeviceStreams() const { return m_deviceAPI->getNbSinkStreams(); @@ -164,6 +177,10 @@ bool DATVMod::handleMessage(const Message& cmd) DSPSignalNotification* rep = new DSPSignalNotification(notif); qDebug() << "DATVMod::handleMessage: DSPSignalNotification"; m_basebandSource->getInputMessageQueue()->push(rep); + // Forward to GUI if any + if (getMessageQueueToGUI()) { + getMessageQueueToGUI()->push(new DSPSignalNotification(notif)); + } return true; } @@ -356,6 +373,15 @@ int DATVMod::webapiSettingsGet( return 200; } +int DATVMod::webapiWorkspaceGet( + SWGSDRangel::SWGWorkspaceInfo& response, + QString& errorMessage) +{ + (void) errorMessage; + response.setIndex(m_settings.m_workspaceIndex); + return 200; +} + int DATVMod::webapiSettingsPutPatch( bool force, const QStringList& channelSettingsKeys, diff --git a/plugins/channeltx/moddatv/datvmod.h b/plugins/channeltx/moddatv/datvmod.h index 0cd939f2e..98781f861 100644 --- a/plugins/channeltx/moddatv/datvmod.h +++ b/plugins/channeltx/moddatv/datvmod.h @@ -202,6 +202,8 @@ public: DATVMod(DeviceAPI *deviceAPI); virtual ~DATVMod(); virtual void destroy() { delete this; } + virtual void setDeviceAPI(DeviceAPI *deviceAPI); + virtual DeviceAPI *getDeviceAPI() { return m_deviceAPI; } virtual void start(); virtual void stop(); @@ -232,6 +234,10 @@ public: SWGSDRangel::SWGChannelSettings& response, QString& errorMessage); + virtual int webapiWorkspaceGet( + SWGSDRangel::SWGWorkspaceInfo& response, + QString& errorMessage); + virtual int webapiSettingsPutPatch( bool force, const QStringList& channelSettingsKeys, diff --git a/plugins/channeltx/moddatv/datvmodgui.cpp b/plugins/channeltx/moddatv/datvmodgui.cpp index 52cdb9753..50ed21d8b 100644 --- a/plugins/channeltx/moddatv/datvmodgui.cpp +++ b/plugins/channeltx/moddatv/datvmodgui.cpp @@ -22,6 +22,7 @@ #include #include #include +#include #include @@ -29,6 +30,7 @@ #include "plugin/pluginapi.h" #include "util/simpleserializer.h" #include "dsp/dspengine.h" +#include "dsp/dspcommands.h" #include "util/db.h" #include "gui/basicchannelsettingsdialog.h" #include "gui/devicestreamselectiondialog.h" @@ -55,6 +57,8 @@ DATVModGUI::DATVModGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, BasebandS m_pluginAPI(pluginAPI), m_deviceUISet(deviceUISet), m_channelMarker(this), + m_deviceCenterFrequency(0), + m_basebandSampleRate(1), m_doApplySettings(true), m_tickMsgOutstanding(false), m_streamLength(0), @@ -63,10 +67,13 @@ DATVModGUI::DATVModGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, BasebandS m_tickCount(0), m_enableNavTime(false) { - ui->setupUi(this); - m_helpURL = "plugins/channeltx/moddatv/readme.md"; setAttribute(Qt::WA_DeleteOnClose, true); - connect(this, SIGNAL(widgetRolled(QWidget*,bool)), this, SLOT(onWidgetRolled(QWidget*,bool))); + m_helpURL = "plugins/channeltx/moddatv/readme.md"; + RollupContents *rollupContents = getRollupContents(); + ui->setupUi(rollupContents); + setSizePolicy(rollupContents->sizePolicy()); + rollupContents->arrangeRollups(); + connect(rollupContents, SIGNAL(widgetRolled(QWidget*,bool)), this, SLOT(onWidgetRolled(QWidget*,bool))); connect(this, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(onMenuDialogCalled(const QPoint &))); m_datvMod = (DATVMod*) channelTx; @@ -92,7 +99,6 @@ DATVModGUI::DATVModGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, BasebandS m_settings.setRollupState(&m_rollupState); m_deviceUISet->addChannelMarker(&m_channelMarker); - m_deviceUISet->addRollupWidget(this); connect(&m_channelMarker, SIGNAL(changedByCursor()), this, SLOT(channelMarkerChangedByCursor())); @@ -107,6 +113,7 @@ DATVModGUI::DATVModGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, BasebandS #endif displaySettings(); + makeUIConnections(); applySettings(true); if (!m_settings.m_tsFileName.isEmpty()) configureTsFileName(); @@ -146,6 +153,14 @@ bool DATVModGUI::deserialize(const QByteArray& data) } } +void DATVModGUI::resizeEvent(QResizeEvent* size) +{ + int maxWidth = getRollupContents()->maximumWidth(); + int minHeight = getRollupContents()->minimumHeight() + getAdditionalHeight(); + resize(width() < maxWidth ? width() : maxWidth, minHeight); + size->accept(); +} + bool DATVModGUI::handleMessage(const Message& message) { if (DATVModReport::MsgReportTsFileSourceStreamData::match(message)) @@ -206,6 +221,17 @@ bool DATVModGUI::handleMessage(const Message& message) ui->tsFileText->setText(m_settings.m_tsFileName); return true; } + else if (DSPSignalNotification::match(message)) + { + const DSPSignalNotification& notif = (const DSPSignalNotification&) message; + m_deviceCenterFrequency = notif.getCenterFrequency(); + m_basebandSampleRate = notif.getSampleRate(); + ui->deltaFrequency->setValueRange(false, 8, -m_basebandSampleRate/2, m_basebandSampleRate/2); + ui->deltaFrequencyLabel->setToolTip(tr("Range %1 %L2 Hz").arg(QChar(0xB1)).arg(m_basebandSampleRate/2)); + updateAbsoluteCenterFrequency(); + return true; + + } else { return false; @@ -236,6 +262,7 @@ void DATVModGUI::on_deltaFrequency_changed(qint64 value) { m_channelMarker.setCenterFrequency(value); m_settings.m_inputFrequencyOffset = value; + updateAbsoluteCenterFrequency(); applySettings(); } @@ -473,7 +500,7 @@ void DATVModGUI::onWidgetRolled(QWidget* widget, bool rollDown) (void) widget; (void) rollDown; - saveState(m_rollupState); + getRollupContents()->saveState(m_rollupState); applySettings(); } @@ -487,11 +514,17 @@ void DATVModGUI::onMenuDialogCalled(const QPoint &p) dialog.setReverseAPIPort(m_settings.m_reverseAPIPort); dialog.setReverseAPIDeviceIndex(m_settings.m_reverseAPIDeviceIndex); dialog.setReverseAPIChannelIndex(m_settings.m_reverseAPIChannelIndex); + dialog.setDefaultTitle(m_displayedName); + + if (m_deviceUISet->m_deviceMIMOEngine) + { + dialog.setNumberOfStreams(m_datvMod->getNumberOfDeviceStreams()); + dialog.setStreamIndex(m_settings.m_streamIndex); + } dialog.move(p); dialog.exec(); - m_settings.m_inputFrequencyOffset = m_channelMarker.getCenterFrequency(); m_settings.m_rgbColor = m_channelMarker.getColor().rgb(); m_settings.m_title = m_channelMarker.getTitle(); m_settings.m_useReverseAPI = dialog.useReverseAPI(); @@ -501,22 +534,17 @@ void DATVModGUI::onMenuDialogCalled(const QPoint &p) m_settings.m_reverseAPIChannelIndex = dialog.getReverseAPIChannelIndex(); setWindowTitle(m_settings.m_title); + setTitle(m_channelMarker.getTitle()); setTitleColor(m_settings.m_rgbColor); - applySettings(); - } - else if ((m_contextMenuType == ContextMenuStreamSettings) && (m_deviceUISet->m_deviceMIMOEngine)) - { - DeviceStreamSelectionDialog dialog(this); - dialog.setNumberOfStreams(m_datvMod->getNumberOfDeviceStreams()); - dialog.setStreamIndex(m_settings.m_streamIndex); - dialog.move(p); - dialog.exec(); + if (m_deviceUISet->m_deviceMIMOEngine) + { + m_settings.m_streamIndex = dialog.getSelectedStreamIndex(); + m_channelMarker.clearStreamIndexes(); + m_channelMarker.addStreamIndex(m_settings.m_streamIndex); + updateIndexLabel(); + } - m_settings.m_streamIndex = dialog.getSelectedStreamIndex(); - m_channelMarker.clearStreamIndexes(); - m_channelMarker.addStreamIndex(m_settings.m_streamIndex); - displayStreamIndex(); applySettings(); } @@ -552,7 +580,8 @@ void DATVModGUI::displaySettings() setTitleColor(m_settings.m_rgbColor); setWindowTitle(m_channelMarker.getTitle()); - displayStreamIndex(); + setTitle(m_channelMarker.getTitle()); + updateIndexLabel(); blockApplySettings(true); @@ -581,27 +610,21 @@ void DATVModGUI::displaySettings() ui->udpAddress->setText(m_settings.m_udpAddress); ui->udpPort->setValue(m_settings.m_udpPort); - restoreState(m_rollupState); + getRollupContents()->restoreState(m_rollupState); + updateAbsoluteCenterFrequency(); blockApplySettings(false); } -void DATVModGUI::displayStreamIndex() -{ - if (m_deviceUISet->m_deviceMIMOEngine) { - setStreamIndicator(tr("%1").arg(m_settings.m_streamIndex)); - } else { - setStreamIndicator("S"); // single channel indicator - } -} - -void DATVModGUI::leaveEvent(QEvent*) +void DATVModGUI::leaveEvent(QEvent* event) { m_channelMarker.setHighlighted(false); + ChannelGUI::leaveEvent(event); } -void DATVModGUI::enterEvent(QEvent*) +void DATVModGUI::enterEvent(QEvent* event) { m_channelMarker.setHighlighted(true); + ChannelGUI::enterEvent(event); } void DATVModGUI::tick() @@ -662,3 +685,26 @@ void DATVModGUI::updateWithStreamTime() } } +void DATVModGUI::makeUIConnections() +{ + QObject::connect(ui->deltaFrequency, &ValueDialZ::changed, this, &DATVModGUI::on_deltaFrequency_changed); + QObject::connect(ui->channelMute, &QToolButton::toggled, this, &DATVModGUI::on_channelMute_toggled); + QObject::connect(ui->dvbStandard, QOverload::of(&QComboBox::currentIndexChanged), this, &DATVModGUI::on_dvbStandard_currentIndexChanged); + QObject::connect(ui->symbolRate, QOverload::of(&QSpinBox::valueChanged), this, &DATVModGUI::on_symbolRate_valueChanged); + QObject::connect(ui->rfBW, &QSlider::valueChanged, this, &DATVModGUI::on_rfBW_valueChanged); + QObject::connect(ui->fec, QOverload::of(&QComboBox::currentIndexChanged), this, &DATVModGUI::on_fec_currentIndexChanged); + QObject::connect(ui->modulation, QOverload::of(&QComboBox::currentIndexChanged), this, &DATVModGUI::on_modulation_currentIndexChanged); + QObject::connect(ui->rollOff, QOverload::of(&QComboBox::currentIndexChanged), this, &DATVModGUI::on_rollOff_currentIndexChanged); + QObject::connect(ui->inputSelect, QOverload::of(&QComboBox::currentIndexChanged), this, &DATVModGUI::on_inputSelect_currentIndexChanged); + QObject::connect(ui->tsFileDialog, &QPushButton::clicked, this, &DATVModGUI::on_tsFileDialog_clicked); + QObject::connect(ui->playFile, &ButtonSwitch::toggled, this, &DATVModGUI::on_playFile_toggled); + QObject::connect(ui->playLoop, &ButtonSwitch::toggled, this, &DATVModGUI::on_playLoop_toggled); + QObject::connect(ui->navTimeSlider, &QSlider::valueChanged, this, &DATVModGUI::on_navTimeSlider_valueChanged); + QObject::connect(ui->udpAddress, &QLineEdit::editingFinished, this, &DATVModGUI::on_udpAddress_editingFinished); + QObject::connect(ui->udpPort, QOverload::of(&QSpinBox::valueChanged), this, &DATVModGUI::on_udpPort_valueChanged); +} + +void DATVModGUI::updateAbsoluteCenterFrequency() +{ + setStatusFrequency(m_deviceCenterFrequency + m_settings.m_inputFrequencyOffset); +} diff --git a/plugins/channeltx/moddatv/datvmodgui.h b/plugins/channeltx/moddatv/datvmodgui.h index 5ddc6f102..40096319c 100644 --- a/plugins/channeltx/moddatv/datvmodgui.h +++ b/plugins/channeltx/moddatv/datvmodgui.h @@ -48,10 +48,24 @@ public: QByteArray serialize() const; bool deserialize(const QByteArray& data); virtual MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; } + virtual void setWorkspaceIndex(int index) { m_settings.m_workspaceIndex = index; }; + virtual int getWorkspaceIndex() const { return m_settings.m_workspaceIndex; }; + virtual void setGeometryBytes(const QByteArray& blob) { m_settings.m_geometryBytes = blob; }; + virtual QByteArray getGeometryBytes() const { return m_settings.m_geometryBytes; }; + virtual QString getTitle() const { return m_settings.m_title; }; + virtual QColor getTitleColor() const { return m_settings.m_rgbColor; }; + virtual void zetHidden(bool hidden) { m_settings.m_hidden = hidden; } + virtual bool getHidden() const { return m_settings.m_hidden; } + virtual ChannelMarker& getChannelMarker() { return m_channelMarker; } + virtual int getStreamIndex() const { return m_settings.m_streamIndex; } + virtual void setStreamIndex(int streamIndex) { m_settings.m_streamIndex = streamIndex; } public slots: void channelMarkerChangedByCursor(); +protected: + void resizeEvent(QResizeEvent* size); + private: Ui::DATVModGUI* ui; PluginAPI* m_pluginAPI; @@ -59,6 +73,8 @@ private: ChannelMarker m_channelMarker; RollupState m_rollupState; DATVModSettings m_settings; + qint64 m_deviceCenterFrequency; + int m_basebandSampleRate; bool m_doApplySettings; bool m_tickMsgOutstanding; @@ -81,11 +97,13 @@ private: void blockApplySettings(bool block); void applySettings(bool force = false); void displaySettings(); - void displayStreamIndex(); void updateWithStreamData(); void updateWithStreamTime(); void setChannelMarkerBandwidth(); bool handleMessage(const Message& message); + void makeUIConnections(); + void updateAbsoluteCenterFrequency(); + void updateFEC(); void leaveEvent(QEvent*); diff --git a/plugins/channeltx/moddatv/datvmodgui.ui b/plugins/channeltx/moddatv/datvmodgui.ui index f2d92648c..fca177925 100644 --- a/plugins/channeltx/moddatv/datvmodgui.ui +++ b/plugins/channeltx/moddatv/datvmodgui.ui @@ -1,7 +1,7 @@ DATVModGUI - + 0 @@ -11,7 +11,7 @@ - + 0 0 @@ -22,6 +22,12 @@ 0 + + + 700 + 16777215 + + Liberation Sans @@ -794,22 +800,22 @@ - RollupWidget + RollupContents QWidget -
gui/rollupwidget.h
+
gui/rollupcontents.h
1
- - ButtonSwitch - QToolButton -
gui/buttonswitch.h
-
ValueDialZ QWidget
gui/valuedialz.h
1
+ + ButtonSwitch + QToolButton +
gui/buttonswitch.h
+
diff --git a/plugins/channeltx/moddatv/datvmodsettings.cpp b/plugins/channeltx/moddatv/datvmodsettings.cpp index ee5fda37c..ab175acd9 100644 --- a/plugins/channeltx/moddatv/datvmodsettings.cpp +++ b/plugins/channeltx/moddatv/datvmodsettings.cpp @@ -57,6 +57,8 @@ void DATVModSettings::resetToDefaults() m_reverseAPIPort = 8888; m_reverseAPIDeviceIndex = 0; m_reverseAPIChannelIndex = 0; + m_workspaceIndex = 0; + m_hidden = false; } QByteArray DATVModSettings::serialize() const @@ -93,6 +95,10 @@ QByteArray DATVModSettings::serialize() const s.writeBlob(29, m_rollupState->serialize()); } + s.writeS32(30, m_workspaceIndex); + s.writeBlob(31, m_geometryBytes); + s.writeBool(32, m_hidden); + return s.final(); } @@ -163,6 +169,10 @@ bool DATVModSettings::deserialize(const QByteArray& data) m_rollupState->deserialize(bytetmp); } + d.readS32(30, &m_workspaceIndex, 0); + d.readBlob(31, &m_geometryBytes); + d.readBool(32, &m_hidden, false); + return true; } else diff --git a/plugins/channeltx/moddatv/datvmodsettings.h b/plugins/channeltx/moddatv/datvmodsettings.h index 9fe609747..757d4c78b 100644 --- a/plugins/channeltx/moddatv/datvmodsettings.h +++ b/plugins/channeltx/moddatv/datvmodsettings.h @@ -97,6 +97,9 @@ struct DATVModSettings uint16_t m_reverseAPIDeviceIndex; uint16_t m_reverseAPIChannelIndex; Serializable *m_rollupState; + int m_workspaceIndex; + QByteArray m_geometryBytes; + bool m_hidden; DATVModSettings(); void resetToDefaults(); diff --git a/plugins/channeltx/moddatv/readme.md b/plugins/channeltx/moddatv/readme.md index 94b598861..1241dcebb 100644 --- a/plugins/channeltx/moddatv/readme.md +++ b/plugins/channeltx/moddatv/readme.md @@ -15,6 +15,8 @@ DVB-S2 includes: scrambling, BCH encoder, LDPC encoder, bit interleaver and QPSK

Interface

+The top and bottom bars of the channel window are described [here](../../../sdrgui/channel/readme.md) + ![DATV Modulator plugin GUI](../../../doc/img/DATVMod_plugin.png)

1: Frequency shift from center frequency of transmission

diff --git a/plugins/channeltx/modfreedv/freedvmod.cpp b/plugins/channeltx/modfreedv/freedvmod.cpp index dd3d4a004..8ffa17f3b 100644 --- a/plugins/channeltx/modfreedv/freedvmod.cpp +++ b/plugins/channeltx/modfreedv/freedvmod.cpp @@ -28,6 +28,7 @@ #include #include "SWGChannelSettings.h" +#include "SWGWorkspaceInfo.h" #include "SWGChannelReport.h" #include "SWGFreeDVModReport.h" @@ -97,6 +98,18 @@ FreeDVMod::~FreeDVMod() delete m_thread; } +void FreeDVMod::setDeviceAPI(DeviceAPI *deviceAPI) +{ + if (deviceAPI != m_deviceAPI) + { + m_deviceAPI->removeChannelSourceAPI(this); + m_deviceAPI->removeChannelSource(this); + m_deviceAPI = deviceAPI; + m_deviceAPI->addChannelSource(this); + m_deviceAPI->addChannelSinkAPI(this); + } +} + void FreeDVMod::start() { qDebug("FreeDVMod::start"); @@ -196,6 +209,10 @@ bool FreeDVMod::handleMessage(const Message& cmd) DSPSignalNotification* rep = new DSPSignalNotification(notif); // make a copy qDebug() << "FreeDVMod::handleMessage: DSPSignalNotification"; m_basebandSource->getInputMessageQueue()->push(rep); + // Forward to GUI if any + if (getMessageQueueToGUI()) { + getMessageQueueToGUI()->push(new DSPSignalNotification(notif)); + } return true; } @@ -375,6 +392,15 @@ int FreeDVMod::webapiSettingsGet( return 200; } +int FreeDVMod::webapiWorkspaceGet( + SWGSDRangel::SWGWorkspaceInfo& response, + QString& errorMessage) +{ + (void) errorMessage; + response.setIndex(m_settings.m_workspaceIndex); + return 200; +} + int FreeDVMod::webapiSettingsPutPatch( bool force, const QStringList& channelSettingsKeys, diff --git a/plugins/channeltx/modfreedv/freedvmod.h b/plugins/channeltx/modfreedv/freedvmod.h index 49f2cc6d8..0ed5c8feb 100644 --- a/plugins/channeltx/modfreedv/freedvmod.h +++ b/plugins/channeltx/modfreedv/freedvmod.h @@ -178,6 +178,8 @@ public: FreeDVMod(DeviceAPI *deviceAPI); virtual ~FreeDVMod(); virtual void destroy() { delete this; } + virtual void setDeviceAPI(DeviceAPI *deviceAPI); + virtual DeviceAPI *getDeviceAPI() { return m_deviceAPI; } virtual void start(); virtual void stop(); @@ -208,6 +210,10 @@ public: SWGSDRangel::SWGChannelSettings& response, QString& errorMessage); + virtual int webapiWorkspaceGet( + SWGSDRangel::SWGWorkspaceInfo& response, + QString& errorMessage); + virtual int webapiSettingsPutPatch( bool force, const QStringList& channelSettingsKeys, diff --git a/plugins/channeltx/modfreedv/freedvmodgui.cpp b/plugins/channeltx/modfreedv/freedvmodgui.cpp index e0de4cd92..19ac57d3e 100644 --- a/plugins/channeltx/modfreedv/freedvmodgui.cpp +++ b/plugins/channeltx/modfreedv/freedvmodgui.cpp @@ -99,6 +99,16 @@ bool FreeDVModGUI::handleMessage(const Message& message) applyBandwidths(5 - ui->spanLog2->value()); // will update spectrum details with new sample rate return true; } + else if (DSPSignalNotification::match(message)) + { + const DSPSignalNotification& notif = (const DSPSignalNotification&) message; + m_deviceCenterFrequency = notif.getCenterFrequency(); + m_basebandSampleRate = notif.getSampleRate(); + ui->deltaFrequency->setValueRange(false, 7, -m_basebandSampleRate/2, m_basebandSampleRate/2); + ui->deltaFrequencyLabel->setToolTip(tr("Range %1 %L2 Hz").arg(QChar(0xB1)).arg(m_basebandSampleRate/2)); + updateAbsoluteCenterFrequency(); + return true; + } else if (FreeDVMod::MsgConfigureFreeDVMod::match(message)) { const FreeDVMod::MsgConfigureFreeDVMod& cfg = (FreeDVMod::MsgConfigureFreeDVMod&) message; @@ -154,6 +164,7 @@ void FreeDVModGUI::on_deltaFrequency_changed(qint64 value) { m_channelMarker.setCenterFrequency(value); m_settings.m_inputFrequencyOffset = m_channelMarker.getCenterFrequency(); + updateAbsoluteCenterFrequency(); applySettings(); } @@ -284,7 +295,18 @@ void FreeDVModGUI::onWidgetRolled(QWidget* widget, bool rollDown) (void) widget; (void) rollDown; - saveState(m_rollupState); + RollupContents *rollupContents = getRollupContents(); + + if (rollupContents->hasExpandableWidgets()) { + setSizePolicy(sizePolicy().horizontalPolicy(), QSizePolicy::Expanding); + } else { + setSizePolicy(sizePolicy().horizontalPolicy(), QSizePolicy::Fixed); + } + + int h = rollupContents->height() + getAdditionalHeight(); + resize(width(), h); + + rollupContents->saveState(m_rollupState); applySettings(); } @@ -298,11 +320,17 @@ void FreeDVModGUI::onMenuDialogCalled(const QPoint &p) dialog.setReverseAPIPort(m_settings.m_reverseAPIPort); dialog.setReverseAPIDeviceIndex(m_settings.m_reverseAPIDeviceIndex); dialog.setReverseAPIChannelIndex(m_settings.m_reverseAPIChannelIndex); + dialog.setDefaultTitle(m_displayedName); + + if (m_deviceUISet->m_deviceMIMOEngine) + { + dialog.setNumberOfStreams(m_freeDVMod->getNumberOfDeviceStreams()); + dialog.setStreamIndex(m_settings.m_streamIndex); + } dialog.move(p); dialog.exec(); - m_settings.m_inputFrequencyOffset = m_channelMarker.getCenterFrequency(); m_settings.m_rgbColor = m_channelMarker.getColor().rgb(); m_settings.m_title = m_channelMarker.getTitle(); m_settings.m_useReverseAPI = dialog.useReverseAPI(); @@ -312,22 +340,17 @@ void FreeDVModGUI::onMenuDialogCalled(const QPoint &p) m_settings.m_reverseAPIChannelIndex = dialog.getReverseAPIChannelIndex(); setWindowTitle(m_settings.m_title); + setTitle(m_channelMarker.getTitle()); setTitleColor(m_settings.m_rgbColor); - applySettings(); - } - else if ((m_contextMenuType == ContextMenuStreamSettings) && (m_deviceUISet->m_deviceMIMOEngine)) - { - DeviceStreamSelectionDialog dialog(this); - dialog.setNumberOfStreams(m_freeDVMod->getNumberOfDeviceStreams()); - dialog.setStreamIndex(m_settings.m_streamIndex); - dialog.move(p); - dialog.exec(); + if (m_deviceUISet->m_deviceMIMOEngine) + { + m_settings.m_streamIndex = dialog.getSelectedStreamIndex(); + m_channelMarker.clearStreamIndexes(); + m_channelMarker.addStreamIndex(m_settings.m_streamIndex); + updateIndexLabel(); + } - m_settings.m_streamIndex = dialog.getSelectedStreamIndex(); - m_channelMarker.clearStreamIndexes(); - m_channelMarker.addStreamIndex(m_settings.m_streamIndex); - displayStreamIndex(); applySettings(); } @@ -340,6 +363,8 @@ FreeDVModGUI::FreeDVModGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, Baseb m_pluginAPI(pluginAPI), m_deviceUISet(deviceUISet), m_channelMarker(this), + m_deviceCenterFrequency(0), + m_basebandSampleRate(1), m_doApplySettings(true), m_spectrumRate(6000), m_recordLength(0), @@ -349,10 +374,13 @@ FreeDVModGUI::FreeDVModGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, Baseb m_tickCount(0), m_enableNavTime(false) { - ui->setupUi(this); - m_helpURL = "plugins/channeltx/modfreedv/readme.md"; setAttribute(Qt::WA_DeleteOnClose, true); - connect(this, SIGNAL(widgetRolled(QWidget*,bool)), this, SLOT(onWidgetRolled(QWidget*,bool))); + m_helpURL = "plugins/channeltx/modfreedv/readme.md"; + RollupContents *rollupContents = getRollupContents(); + ui->setupUi(rollupContents); + setSizePolicy(rollupContents->sizePolicy()); + rollupContents->arrangeRollups(); + connect(rollupContents, SIGNAL(widgetRolled(QWidget*,bool)), this, SLOT(onWidgetRolled(QWidget*,bool))); connect(this, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(onMenuDialogCalled(const QPoint &))); m_freeDVMod = (FreeDVMod*) channelTx; @@ -381,7 +409,6 @@ FreeDVModGUI::FreeDVModGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, Baseb m_channelMarker.setVisible(true); m_deviceUISet->addChannelMarker(&m_channelMarker); - m_deviceUISet->addRollupWidget(this); connect(&m_channelMarker, SIGNAL(changedByCursor()), this, SLOT(channelMarkerChangedByCursor())); @@ -397,6 +424,7 @@ FreeDVModGUI::FreeDVModGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, Baseb m_freeDVMod->setLevelMeter(ui->volumeMeter); displaySettings(); + makeUIConnections(); applyBandwidths(5 - ui->spanLog2->value(), true); // does applySettings(true) } @@ -460,7 +488,8 @@ void FreeDVModGUI::displaySettings() setTitleColor(m_settings.m_rgbColor); setWindowTitle(m_channelMarker.getTitle()); - displayStreamIndex(); + setTitle(m_channelMarker.getTitle()); + updateIndexLabel(); blockApplySettings(true); @@ -501,27 +530,21 @@ void FreeDVModGUI::displaySettings() ui->play->setChecked(m_settings.m_modAFInput == FreeDVModSettings::FreeDVModInputAF::FreeDVModInputFile); ui->morseKeyer->setChecked(m_settings.m_modAFInput == FreeDVModSettings::FreeDVModInputAF::FreeDVModInputCWTone); - restoreState(m_rollupState); + getRollupContents()->restoreState(m_rollupState); + updateAbsoluteCenterFrequency(); blockApplySettings(false); } -void FreeDVModGUI::displayStreamIndex() -{ - if (m_deviceUISet->m_deviceMIMOEngine) { - setStreamIndicator(tr("%1").arg(m_settings.m_streamIndex)); - } else { - setStreamIndicator("S"); // single channel indicator - } -} - -void FreeDVModGUI::leaveEvent(QEvent*) +void FreeDVModGUI::leaveEvent(QEvent* event) { m_channelMarker.setHighlighted(false); + ChannelGUI::leaveEvent(event); } -void FreeDVModGUI::enterEvent(QEvent*) +void FreeDVModGUI::enterEvent(QEvent* event) { m_channelMarker.setHighlighted(true); + ChannelGUI::enterEvent(event); } void FreeDVModGUI::audioSelect() @@ -596,3 +619,25 @@ void FreeDVModGUI::updateWithStreamTime() ui->navTimeSlider->setValue((int) (posRatio * 100.0)); } } + +void FreeDVModGUI::makeUIConnections() +{ + QObject::connect(ui->deltaFrequency, &ValueDialZ::changed, this, &FreeDVModGUI::on_deltaFrequency_changed); + QObject::connect(ui->gaugeInput, &QCheckBox::toggled, this, &FreeDVModGUI::on_gaugeInput_toggled); + QObject::connect(ui->volume, &QDial::valueChanged, this, &FreeDVModGUI::on_volume_valueChanged); + QObject::connect(ui->audioMute, &QToolButton::toggled, this, &FreeDVModGUI::on_audioMute_toggled); + QObject::connect(ui->freeDVMode, QOverload::of(&QComboBox::currentIndexChanged), this, &FreeDVModGUI::on_freeDVMode_currentIndexChanged); + QObject::connect(ui->tone, &ButtonSwitch::toggled, this, &FreeDVModGUI::on_tone_toggled); + QObject::connect(ui->toneFrequency, &QDial::valueChanged, this, &FreeDVModGUI::on_toneFrequency_valueChanged); + QObject::connect(ui->mic, &ButtonSwitch::toggled, this, &FreeDVModGUI::on_mic_toggled); + QObject::connect(ui->play, &ButtonSwitch::toggled, this, &FreeDVModGUI::on_play_toggled); + QObject::connect(ui->playLoop, &ButtonSwitch::toggled, this, &FreeDVModGUI::on_playLoop_toggled); + QObject::connect(ui->morseKeyer, &ButtonSwitch::toggled, this, &FreeDVModGUI::on_morseKeyer_toggled); + QObject::connect(ui->navTimeSlider, &QSlider::valueChanged, this, &FreeDVModGUI::on_navTimeSlider_valueChanged); + QObject::connect(ui->showFileDialog, &QPushButton::clicked, this, &FreeDVModGUI::on_showFileDialog_clicked); +} + +void FreeDVModGUI::updateAbsoluteCenterFrequency() +{ + setStatusFrequency(m_deviceCenterFrequency + m_settings.m_inputFrequencyOffset); +} diff --git a/plugins/channeltx/modfreedv/freedvmodgui.h b/plugins/channeltx/modfreedv/freedvmodgui.h index 09fbe3dc9..6bd48fc5d 100644 --- a/plugins/channeltx/modfreedv/freedvmodgui.h +++ b/plugins/channeltx/modfreedv/freedvmodgui.h @@ -49,6 +49,17 @@ public: QByteArray serialize() const; bool deserialize(const QByteArray& data); virtual MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; } + virtual void setWorkspaceIndex(int index) { m_settings.m_workspaceIndex = index; }; + virtual int getWorkspaceIndex() const { return m_settings.m_workspaceIndex; }; + virtual void setGeometryBytes(const QByteArray& blob) { m_settings.m_geometryBytes = blob; }; + virtual QByteArray getGeometryBytes() const { return m_settings.m_geometryBytes; }; + virtual QString getTitle() const { return m_settings.m_title; }; + virtual QColor getTitleColor() const { return m_settings.m_rgbColor; }; + virtual void zetHidden(bool hidden) { m_settings.m_hidden = hidden; } + virtual bool getHidden() const { return m_settings.m_hidden; } + virtual ChannelMarker& getChannelMarker() { return m_channelMarker; } + virtual int getStreamIndex() const { return m_settings.m_streamIndex; } + virtual void setStreamIndex(int streamIndex) { m_settings.m_streamIndex = streamIndex; } public slots: void channelMarkerChangedByCursor(); @@ -60,6 +71,8 @@ private: ChannelMarker m_channelMarker; RollupState m_rollupState; FreeDVModSettings m_settings; + qint64 m_deviceCenterFrequency; + int m_basebandSampleRate; bool m_doApplySettings; int m_spectrumRate; @@ -84,11 +97,12 @@ private: void applyBandwidths(int spanLog2, bool force = false); void displayBandwidths(int spanLog2); void displaySettings(); - void displayStreamIndex(); void updateWithStreamData(); void updateWithStreamTime(); void channelMarkerUpdate(); bool handleMessage(const Message& message); + void makeUIConnections(); + void updateAbsoluteCenterFrequency(); void leaveEvent(QEvent*); void enterEvent(QEvent*); diff --git a/plugins/channeltx/modfreedv/freedvmodgui.ui b/plugins/channeltx/modfreedv/freedvmodgui.ui index bd4dc6062..0f3a15610 100644 --- a/plugins/channeltx/modfreedv/freedvmodgui.ui +++ b/plugins/channeltx/modfreedv/freedvmodgui.ui @@ -1,7 +1,7 @@ FreeDVModGUI - + 0 @@ -11,7 +11,7 @@ - + 0 0 @@ -675,6 +675,12 @@ 284 + + + 0 + 0 + + Channel Spectrum @@ -696,6 +702,12 @@ + + + 0 + 0 + + 200 @@ -718,9 +730,9 @@ - RollupWidget + RollupContents QWidget -
gui/rollupwidget.h
+
gui/rollupcontents.h
1
@@ -736,9 +748,9 @@ 1 - LevelMeterVU + ValueDialZ QWidget -
gui/levelmeter.h
+
gui/valuedialz.h
1
@@ -747,15 +759,15 @@
gui/buttonswitch.h
- CWKeyerGUI + LevelMeterVU QWidget -
gui/cwkeyergui.h
+
gui/levelmeter.h
1
- ValueDialZ + CWKeyerGUI QWidget -
gui/valuedialz.h
+
gui/cwkeyergui.h
1
diff --git a/plugins/channeltx/modfreedv/freedvmodsettings.cpp b/plugins/channeltx/modfreedv/freedvmodsettings.cpp index 051a52309..f2b1ea565 100644 --- a/plugins/channeltx/modfreedv/freedvmodsettings.cpp +++ b/plugins/channeltx/modfreedv/freedvmodsettings.cpp @@ -51,6 +51,8 @@ void FreeDVModSettings::resetToDefaults() m_reverseAPIPort = 8888; m_reverseAPIDeviceIndex = 0; m_reverseAPIChannelIndex = 0; + m_workspaceIndex = 0; + m_hidden = false; } QByteArray FreeDVModSettings::serialize() const @@ -94,6 +96,10 @@ QByteArray FreeDVModSettings::serialize() const s.writeBlob(28, m_rollupState->serialize()); } + s.writeS32(29, m_workspaceIndex); + s.writeBlob(30, m_geometryBytes); + s.writeBool(31, m_hidden); + return s.final(); } @@ -181,6 +187,10 @@ bool FreeDVModSettings::deserialize(const QByteArray& data) m_rollupState->deserialize(bytetmp); } + d.readS32(29, &m_workspaceIndex, 0); + d.readBlob(30, &m_geometryBytes); + d.readBool(31, &m_hidden, false); + return true; } else diff --git a/plugins/channeltx/modfreedv/freedvmodsettings.h b/plugins/channeltx/modfreedv/freedvmodsettings.h index a58635433..4f7bcf96d 100644 --- a/plugins/channeltx/modfreedv/freedvmodsettings.h +++ b/plugins/channeltx/modfreedv/freedvmodsettings.h @@ -66,6 +66,9 @@ struct FreeDVModSettings uint16_t m_reverseAPIPort; uint16_t m_reverseAPIDeviceIndex; uint16_t m_reverseAPIChannelIndex; + int m_workspaceIndex; + QByteArray m_geometryBytes; + bool m_hidden; Serializable *m_channelMarker; Serializable *m_spectrumGUI; diff --git a/plugins/channeltx/modfreedv/readme.md b/plugins/channeltx/modfreedv/readme.md index f4ea2cb5d..b79c11b56 100644 --- a/plugins/channeltx/modfreedv/readme.md +++ b/plugins/channeltx/modfreedv/readme.md @@ -8,6 +8,8 @@ This plugin can be used to generate a signal following the [FreeDV digital voice

Interface

+The top and bottom bars of the channel window are described [here](../../../sdrgui/channel/readme.md) + ![FreeDV Modulator plugin GUI](../../../doc/img/FreeDVMod_plugin.png)

1: Frequency shift from center frequency of transmission

@@ -177,4 +179,4 @@ The transmitted signal is further decimated by a power of two before being appli

17: Channel spectrum display

-This is the channel spectrum display. Controls at the bottom of the panel are the same as with the central spectrum display. +This is the channel spectrum display. Details on the spectrum view and controls can be found [here](../../../sdrgui/gui/spectrum.md) diff --git a/plugins/channeltx/modnfm/nfmmod.cpp b/plugins/channeltx/modnfm/nfmmod.cpp index 70ddfbe57..62c7b5d18 100644 --- a/plugins/channeltx/modnfm/nfmmod.cpp +++ b/plugins/channeltx/modnfm/nfmmod.cpp @@ -24,6 +24,7 @@ #include #include "SWGChannelSettings.h" +#include "SWGWorkspaceInfo.h" #include "SWGCWKeyerSettings.h" #include "SWGChannelReport.h" #include "SWGNFMModReport.h" @@ -98,6 +99,18 @@ NFMMod::~NFMMod() delete m_thread; } +void NFMMod::setDeviceAPI(DeviceAPI *deviceAPI) +{ + if (deviceAPI != m_deviceAPI) + { + m_deviceAPI->removeChannelSourceAPI(this); + m_deviceAPI->removeChannelSource(this); + m_deviceAPI = deviceAPI; + m_deviceAPI->addChannelSource(this); + m_deviceAPI->addChannelSinkAPI(this); + } +} + void NFMMod::start() { qDebug("NFMMod::start"); @@ -228,6 +241,10 @@ bool NFMMod::handleMessage(const Message& cmd) DSPSignalNotification* rep = new DSPSignalNotification(notif); // make a copy qDebug() << "NFMMod::handleMessage: DSPSignalNotification"; m_basebandSource->getInputMessageQueue()->push(rep); + // Forward to GUI if any + if (getMessageQueueToGUI()) { + getMessageQueueToGUI()->push(new DSPSignalNotification(notif)); + } return true; } @@ -447,6 +464,15 @@ int NFMMod::webapiSettingsGet( return 200; } +int NFMMod::webapiWorkspaceGet( + SWGSDRangel::SWGWorkspaceInfo& response, + QString& errorMessage) +{ + (void) errorMessage; + response.setIndex(m_settings.m_workspaceIndex); + return 200; +} + int NFMMod::webapiSettingsPutPatch( bool force, const QStringList& channelSettingsKeys, diff --git a/plugins/channeltx/modnfm/nfmmod.h b/plugins/channeltx/modnfm/nfmmod.h index 121b1a9a1..43f610168 100644 --- a/plugins/channeltx/modnfm/nfmmod.h +++ b/plugins/channeltx/modnfm/nfmmod.h @@ -174,6 +174,8 @@ public: NFMMod(DeviceAPI *deviceAPI); virtual ~NFMMod(); virtual void destroy() { delete this; } + virtual void setDeviceAPI(DeviceAPI *deviceAPI); + virtual DeviceAPI *getDeviceAPI() { return m_deviceAPI; } virtual void start(); virtual void stop(); @@ -204,6 +206,10 @@ public: SWGSDRangel::SWGChannelSettings& response, QString& errorMessage); + virtual int webapiWorkspaceGet( + SWGSDRangel::SWGWorkspaceInfo& response, + QString& errorMessage); + virtual int webapiSettingsPutPatch( bool force, const QStringList& channelSettingsKeys, diff --git a/plugins/channeltx/modnfm/nfmmodgui.cpp b/plugins/channeltx/modnfm/nfmmodgui.cpp index 267f0882a..cf1937b4b 100644 --- a/plugins/channeltx/modnfm/nfmmodgui.cpp +++ b/plugins/channeltx/modnfm/nfmmodgui.cpp @@ -21,6 +21,7 @@ #include #include #include +#include #include "device/deviceuiset.h" #include "plugin/pluginapi.h" @@ -28,6 +29,7 @@ #include "util/db.h" #include "dsp/dspengine.h" #include "dsp/cwkeyer.h" +#include "dsp/dspcommands.h" #include "gui/crightclickenabler.h" #include "gui/audioselectdialog.h" #include "gui/basicchannelsettingsdialog.h" @@ -73,6 +75,14 @@ bool NFMModGUI::deserialize(const QByteArray& data) } } +void NFMModGUI::resizeEvent(QResizeEvent* size) +{ + int maxWidth = getRollupContents()->maximumWidth(); + int minHeight = getRollupContents()->minimumHeight() + getAdditionalHeight(); + resize(width() < maxWidth ? width() : maxWidth, minHeight); + size->accept(); +} + bool NFMModGUI::handleMessage(const Message& message) { if (NFMMod::MsgReportFileSourceStreamData::match(message)) @@ -106,6 +116,16 @@ bool NFMModGUI::handleMessage(const Message& message) ui->cwKeyerGUI->displaySettings(); return true; } + else if (DSPSignalNotification::match(message)) + { + const DSPSignalNotification& notif = (const DSPSignalNotification&) message; + m_deviceCenterFrequency = notif.getCenterFrequency(); + m_basebandSampleRate = notif.getSampleRate(); + ui->deltaFrequency->setValueRange(false, 7, -m_basebandSampleRate/2, m_basebandSampleRate/2); + ui->deltaFrequencyLabel->setToolTip(tr("Range %1 %L2 Hz").arg(QChar(0xB1)).arg(m_basebandSampleRate/2)); + updateAbsoluteCenterFrequency(); + return true; + } else { return false; @@ -136,6 +156,7 @@ void NFMModGUI::on_deltaFrequency_changed(qint64 value) { m_channelMarker.setCenterFrequency(value); m_settings.m_inputFrequencyOffset = m_channelMarker.getCenterFrequency(); + updateAbsoluteCenterFrequency(); applySettings(); } @@ -343,7 +364,7 @@ void NFMModGUI::onWidgetRolled(QWidget* widget, bool rollDown) (void) widget; (void) rollDown; - saveState(m_rollupState); + getRollupContents()->saveState(m_rollupState); applySettings(); } @@ -357,10 +378,17 @@ void NFMModGUI::onMenuDialogCalled(const QPoint &p) dialog.setReverseAPIPort(m_settings.m_reverseAPIPort); dialog.setReverseAPIDeviceIndex(m_settings.m_reverseAPIDeviceIndex); dialog.setReverseAPIChannelIndex(m_settings.m_reverseAPIChannelIndex); + dialog.setDefaultTitle(m_displayedName); + + if (m_deviceUISet->m_deviceMIMOEngine) + { + dialog.setNumberOfStreams(m_nfmMod->getNumberOfDeviceStreams()); + dialog.setStreamIndex(m_settings.m_streamIndex); + } + dialog.move(p); dialog.exec(); - m_settings.m_inputFrequencyOffset = m_channelMarker.getCenterFrequency(); m_settings.m_rgbColor = m_channelMarker.getColor().rgb(); m_settings.m_title = m_channelMarker.getTitle(); m_settings.m_useReverseAPI = dialog.useReverseAPI(); @@ -370,22 +398,17 @@ void NFMModGUI::onMenuDialogCalled(const QPoint &p) m_settings.m_reverseAPIChannelIndex = dialog.getReverseAPIChannelIndex(); setWindowTitle(m_settings.m_title); + setTitle(m_channelMarker.getTitle()); setTitleColor(m_settings.m_rgbColor); - applySettings(); - } - else if ((m_contextMenuType == ContextMenuStreamSettings) && (m_deviceUISet->m_deviceMIMOEngine)) - { - DeviceStreamSelectionDialog dialog(this); - dialog.setNumberOfStreams(m_nfmMod->getNumberOfDeviceStreams()); - dialog.setStreamIndex(m_settings.m_streamIndex); - dialog.move(p); - dialog.exec(); + if (m_deviceUISet->m_deviceMIMOEngine) + { + m_settings.m_streamIndex = dialog.getSelectedStreamIndex(); + m_channelMarker.clearStreamIndexes(); + m_channelMarker.addStreamIndex(m_settings.m_streamIndex); + updateIndexLabel(); + } - m_settings.m_streamIndex = dialog.getSelectedStreamIndex(); - m_channelMarker.clearStreamIndexes(); - m_channelMarker.addStreamIndex(m_settings.m_streamIndex); - displayStreamIndex(); applySettings(); } @@ -398,6 +421,8 @@ NFMModGUI::NFMModGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, BasebandSam m_pluginAPI(pluginAPI), m_deviceUISet(deviceUISet), m_channelMarker(this), + m_deviceCenterFrequency(0), + m_basebandSampleRate(1), m_doApplySettings(true), m_recordLength(0), m_recordSampleRate(48000), @@ -408,9 +433,13 @@ NFMModGUI::NFMModGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, BasebandSam m_enableNavTime(false), m_dcsCodeValidator(QRegExp("[0-7]{1,3}")) { - ui->setupUi(this); - m_helpURL = "plugins/channeltx/modnfm/readme.md"; setAttribute(Qt::WA_DeleteOnClose, true); + m_helpURL = "plugins/channeltx/modnfm/readme.md"; + RollupContents *rollupContents = getRollupContents(); + ui->setupUi(rollupContents); + setSizePolicy(rollupContents->sizePolicy()); + rollupContents->arrangeRollups(); + connect(rollupContents, SIGNAL(widgetRolled(QWidget*,bool)), this, SLOT(onWidgetRolled(QWidget*,bool))); ui->channelSpacing->blockSignals(true); ui->channelSpacing->clear(); @@ -422,7 +451,6 @@ NFMModGUI::NFMModGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, BasebandSam ui->channelSpacing->setCurrentIndex(NFMModSettings::getChannelSpacingIndex(25000)); ui->channelSpacing->blockSignals(false); - connect(this, SIGNAL(widgetRolled(QWidget*,bool)), this, SLOT(onWidgetRolled(QWidget*,bool))); connect(this, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(onMenuDialogCalled(const QPoint &))); m_nfmMod = (NFMMod*) channelTx; @@ -450,7 +478,6 @@ NFMModGUI::NFMModGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, BasebandSam m_channelMarker.setVisible(true); // activate signal on the last setting only m_deviceUISet->addChannelMarker(&m_channelMarker); - m_deviceUISet->addRollupWidget(this); connect(&m_channelMarker, SIGNAL(changedByCursor()), this, SLOT(channelMarkerChangedByCursor())); @@ -474,6 +501,7 @@ NFMModGUI::NFMModGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, BasebandSam m_settings.setRollupState(&m_rollupState); displaySettings(); + makeUIConnections(); applySettings(); } @@ -506,7 +534,8 @@ void NFMModGUI::displaySettings() setTitleColor(m_settings.m_rgbColor); setWindowTitle(m_channelMarker.getTitle()); - displayStreamIndex(); + setTitle(m_channelMarker.getTitle()); + updateIndexLabel(); blockApplySettings(true); @@ -556,27 +585,21 @@ void NFMModGUI::displaySettings() ui->feedbackVolume->setValue(roundf(m_settings.m_feedbackVolumeFactor * 100.0)); ui->feedbackVolumeText->setText(QString("%1").arg(m_settings.m_feedbackVolumeFactor, 0, 'f', 2)); - restoreState(m_rollupState); + getRollupContents()->restoreState(m_rollupState); + updateAbsoluteCenterFrequency(); blockApplySettings(false); } -void NFMModGUI::displayStreamIndex() -{ - if (m_deviceUISet->m_deviceMIMOEngine) { - setStreamIndicator(tr("%1").arg(m_settings.m_streamIndex)); - } else { - setStreamIndicator("S"); // single channel indicator - } -} - -void NFMModGUI::leaveEvent(QEvent*) +void NFMModGUI::leaveEvent(QEvent* event) { m_channelMarker.setHighlighted(false); + ChannelGUI::leaveEvent(event); } -void NFMModGUI::enterEvent(QEvent*) +void NFMModGUI::enterEvent(QEvent* event) { m_channelMarker.setHighlighted(true); + ChannelGUI::enterEvent(event); } void NFMModGUI::audioSelect() @@ -677,3 +700,34 @@ void NFMModGUI::updateWithStreamTime() ui->navTimeSlider->setValue((int) (posRatio * 100.0)); } } + +void NFMModGUI::makeUIConnections() +{ + QObject::connect(ui->deltaFrequency, &ValueDialZ::changed, this, &NFMModGUI::on_deltaFrequency_changed); + QObject::connect(ui->channelSpacingApply, &QPushButton::clicked, this, &NFMModGUI::on_channelSpacingApply_clicked); + QObject::connect(ui->rfBW, &QSlider::valueChanged, this, &NFMModGUI::on_rfBW_valueChanged); + QObject::connect(ui->afBW, &QSlider::valueChanged, this, &NFMModGUI::on_afBW_valueChanged); + QObject::connect(ui->fmDev, &QSlider::valueChanged, this, &NFMModGUI::on_fmDev_valueChanged); + QObject::connect(ui->toneFrequency, &QDial::valueChanged, this, &NFMModGUI::on_toneFrequency_valueChanged); + QObject::connect(ui->volume, &QDial::valueChanged, this, &NFMModGUI::on_volume_valueChanged); + QObject::connect(ui->channelMute, &QToolButton::toggled, this, &NFMModGUI::on_channelMute_toggled); + QObject::connect(ui->tone, &ButtonSwitch::toggled, this, &NFMModGUI::on_tone_toggled); + QObject::connect(ui->morseKeyer, &ButtonSwitch::toggled, this, &NFMModGUI::on_morseKeyer_toggled); + QObject::connect(ui->mic, &ButtonSwitch::toggled, this, &NFMModGUI::on_mic_toggled); + QObject::connect(ui->play, &ButtonSwitch::toggled, this, &NFMModGUI::on_play_toggled); + QObject::connect(ui->playLoop, &ButtonSwitch::toggled, this, &NFMModGUI::on_playLoop_toggled); + QObject::connect(ui->navTimeSlider, &QSlider::valueChanged, this, &NFMModGUI::on_navTimeSlider_valueChanged); + QObject::connect(ui->showFileDialog, &QPushButton::clicked, this, &NFMModGUI::on_showFileDialog_clicked); + QObject::connect(ui->ctcss, QOverload::of(&QComboBox::currentIndexChanged), this, &NFMModGUI::on_ctcss_currentIndexChanged); + QObject::connect(ui->ctcssOn, &QCheckBox::toggled, this, &NFMModGUI::on_ctcssOn_toggled); + QObject::connect(ui->dcsOn, &QCheckBox::toggled, this, &NFMModGUI::on_dcsOn_toggled); + QObject::connect(ui->dcsCode, &QLineEdit::editingFinished, this, &NFMModGUI::on_dcsCode_editingFinished); + QObject::connect(ui->dcsPositive, &QCheckBox::toggled, this, &NFMModGUI::on_dcsPositive_toggled); + QObject::connect(ui->feedbackEnable, &QToolButton::toggled, this, &NFMModGUI::on_feedbackEnable_toggled); + QObject::connect(ui->feedbackVolume, &QDial::valueChanged, this, &NFMModGUI::on_feedbackVolume_valueChanged); +} + +void NFMModGUI::updateAbsoluteCenterFrequency() +{ + setStatusFrequency(m_deviceCenterFrequency + m_settings.m_inputFrequencyOffset); +} diff --git a/plugins/channeltx/modnfm/nfmmodgui.h b/plugins/channeltx/modnfm/nfmmodgui.h index d0c3f1a26..3d20b38e4 100644 --- a/plugins/channeltx/modnfm/nfmmodgui.h +++ b/plugins/channeltx/modnfm/nfmmodgui.h @@ -48,10 +48,24 @@ public: QByteArray serialize() const; bool deserialize(const QByteArray& data); virtual MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; } + virtual void setWorkspaceIndex(int index) { m_settings.m_workspaceIndex = index; }; + virtual int getWorkspaceIndex() const { return m_settings.m_workspaceIndex; }; + virtual void setGeometryBytes(const QByteArray& blob) { m_settings.m_geometryBytes = blob; }; + virtual QByteArray getGeometryBytes() const { return m_settings.m_geometryBytes; }; + virtual QString getTitle() const { return m_settings.m_title; }; + virtual QColor getTitleColor() const { return m_settings.m_rgbColor; }; + virtual void zetHidden(bool hidden) { m_settings.m_hidden = hidden; } + virtual bool getHidden() const { return m_settings.m_hidden; } + virtual ChannelMarker& getChannelMarker() { return m_channelMarker; } + virtual int getStreamIndex() const { return m_settings.m_streamIndex; } + virtual void setStreamIndex(int streamIndex) { m_settings.m_streamIndex = streamIndex; } public slots: void channelMarkerChangedByCursor(); +protected: + void resizeEvent(QResizeEvent* size); + private: Ui::NFMModGUI* ui; PluginAPI* m_pluginAPI; @@ -59,6 +73,8 @@ private: ChannelMarker m_channelMarker; RollupState m_rollupState; NFMModSettings m_settings; + qint64 m_deviceCenterFrequency; + int m_basebandSampleRate; bool m_doApplySettings; NFMMod* m_nfmMod; @@ -82,10 +98,11 @@ private: void blockApplySettings(bool block); void applySettings(bool force = false); void displaySettings(); - void displayStreamIndex(); void updateWithStreamData(); void updateWithStreamTime(); bool handleMessage(const Message& message); + void makeUIConnections(); + void updateAbsoluteCenterFrequency(); void leaveEvent(QEvent*); void enterEvent(QEvent*); diff --git a/plugins/channeltx/modnfm/nfmmodgui.ui b/plugins/channeltx/modnfm/nfmmodgui.ui index 732e4b8f7..086c4d5da 100644 --- a/plugins/channeltx/modnfm/nfmmodgui.ui +++ b/plugins/channeltx/modnfm/nfmmodgui.ui @@ -1,27 +1,33 @@ NFMModGUI - + 0 0 - 363 - 300 + 360 + 278 - + 0 0 - 0 + 360 0 + + + 560 + 16777215 + + Liberation Sans @@ -37,15 +43,15 @@ - 2 - 2 - 341 + 0 + 0 + 358 271 - 280 + 358 0 @@ -928,22 +934,22 @@ - RollupWidget + RollupContents QWidget -
gui/rollupwidget.h
+
gui/rollupcontents.h
1
- - ButtonSwitch - QToolButton -
gui/buttonswitch.h
-
ValueDialZ QWidget
gui/valuedialz.h
1
+ + ButtonSwitch + QToolButton +
gui/buttonswitch.h
+
LevelMeterVU QWidget diff --git a/plugins/channeltx/modnfm/nfmmodsettings.cpp b/plugins/channeltx/modnfm/nfmmodsettings.cpp index a60ddc885..956466aaa 100644 --- a/plugins/channeltx/modnfm/nfmmodsettings.cpp +++ b/plugins/channeltx/modnfm/nfmmodsettings.cpp @@ -79,6 +79,8 @@ void NFMModSettings::resetToDefaults() m_reverseAPIPort = 8888; m_reverseAPIDeviceIndex = 0; m_reverseAPIChannelIndex = 0; + m_workspaceIndex = 0; + m_hidden = false; } QByteArray NFMModSettings::serialize() const @@ -125,6 +127,10 @@ QByteArray NFMModSettings::serialize() const s.writeBlob(27, m_rollupState->serialize()); } + s.writeS32(28, m_workspaceIndex); + s.writeBlob(29, m_geometryBytes); + s.writeBool(30, m_hidden); + return s.final(); } @@ -208,6 +214,10 @@ bool NFMModSettings::deserialize(const QByteArray& data) m_rollupState->deserialize(bytetmp); } + d.readS32(28, &m_workspaceIndex, 0); + d.readBlob(29, &m_geometryBytes); + d.readBool(30, &m_hidden, false); + return true; } else diff --git a/plugins/channeltx/modnfm/nfmmodsettings.h b/plugins/channeltx/modnfm/nfmmodsettings.h index 82c60ece5..9ce5fbf68 100644 --- a/plugins/channeltx/modnfm/nfmmodsettings.h +++ b/plugins/channeltx/modnfm/nfmmodsettings.h @@ -67,6 +67,9 @@ struct NFMModSettings uint16_t m_reverseAPIPort; uint16_t m_reverseAPIDeviceIndex; uint16_t m_reverseAPIChannelIndex; + int m_workspaceIndex; + QByteArray m_geometryBytes; + bool m_hidden; Serializable *m_channelMarker; Serializable *m_cwKeyerGUI; diff --git a/plugins/channeltx/modnfm/readme.md b/plugins/channeltx/modnfm/readme.md index 3a317f1b5..83c599859 100644 --- a/plugins/channeltx/modnfm/readme.md +++ b/plugins/channeltx/modnfm/readme.md @@ -6,6 +6,8 @@ This plugin can be used to generate a narrowband frequency modulated signal. "Na

Interface

+The top and bottom bars of the channel window are described [here](../../../sdrgui/channel/readme.md) + ![NFM Modulator plugin GUI](../../../doc/img/NFMMod_plugin.png)

1: Frequency shift from center frequency of transmission

diff --git a/plugins/channeltx/modpacket/packetmod.cpp b/plugins/channeltx/modpacket/packetmod.cpp index 73c1e2dc3..b9f3ca8b5 100644 --- a/plugins/channeltx/modpacket/packetmod.cpp +++ b/plugins/channeltx/modpacket/packetmod.cpp @@ -27,11 +27,11 @@ #include #include "SWGChannelSettings.h" +#include "SWGWorkspaceInfo.h" #include "SWGChannelReport.h" #include "SWGChannelActions.h" #include "SWGPacketModReport.h" #include "SWGPacketModActions.h" -#include "SWGPacketModActions_tx.h" #include #include @@ -103,6 +103,18 @@ PacketMod::~PacketMod() delete m_thread; } +void PacketMod::setDeviceAPI(DeviceAPI *deviceAPI) +{ + if (deviceAPI != m_deviceAPI) + { + m_deviceAPI->removeChannelSourceAPI(this); + m_deviceAPI->removeChannelSource(this); + m_deviceAPI = deviceAPI; + m_deviceAPI->addChannelSource(this); + m_deviceAPI->addChannelSinkAPI(this); + } +} + void PacketMod::start() { qDebug("PacketMod::start"); @@ -147,6 +159,10 @@ bool PacketMod::handleMessage(const Message& cmd) DSPSignalNotification* rep = new DSPSignalNotification(notif); // make a copy qDebug() << "PacketMod::handleMessage: DSPSignalNotification"; m_basebandSource->getInputMessageQueue()->push(rep); + // Forward to GUI if any + if (getMessageQueueToGUI()) { + getMessageQueueToGUI()->push(new DSPSignalNotification(notif)); + } return true; } @@ -477,6 +493,15 @@ int PacketMod::webapiSettingsGet( return 200; } +int PacketMod::webapiWorkspaceGet( + SWGSDRangel::SWGWorkspaceInfo& response, + QString& errorMessage) +{ + (void) errorMessage; + response.setIndex(m_settings.m_workspaceIndex); + return 200; +} + int PacketMod::webapiSettingsPutPatch( bool force, const QStringList& channelSettingsKeys, diff --git a/plugins/channeltx/modpacket/packetmod.h b/plugins/channeltx/modpacket/packetmod.h index 7a9bd95d6..afd992f2b 100644 --- a/plugins/channeltx/modpacket/packetmod.h +++ b/plugins/channeltx/modpacket/packetmod.h @@ -142,6 +142,8 @@ public: PacketMod(DeviceAPI *deviceAPI); virtual ~PacketMod(); virtual void destroy() { delete this; } + virtual void setDeviceAPI(DeviceAPI *deviceAPI); + virtual DeviceAPI *getDeviceAPI() { return m_deviceAPI; } virtual void start(); virtual void stop(); @@ -172,6 +174,10 @@ public: SWGSDRangel::SWGChannelSettings& response, QString& errorMessage); + virtual int webapiWorkspaceGet( + SWGSDRangel::SWGWorkspaceInfo& response, + QString& errorMessage); + virtual int webapiSettingsPutPatch( bool force, const QStringList& channelSettingsKeys, diff --git a/plugins/channeltx/modpacket/packetmodgui.cpp b/plugins/channeltx/modpacket/packetmodgui.cpp index 368782df5..74d0b793b 100644 --- a/plugins/channeltx/modpacket/packetmodgui.cpp +++ b/plugins/channeltx/modpacket/packetmodgui.cpp @@ -23,11 +23,12 @@ #include #include "dsp/spectrumvis.h" +#include "dsp/dspengine.h" +#include "dsp/dspcommands.h" #include "device/deviceuiset.h" #include "plugin/pluginapi.h" #include "util/simpleserializer.h" #include "util/db.h" -#include "dsp/dspengine.h" #include "gui/glspectrum.h" #include "gui/crightclickenabler.h" #include "gui/basicchannelsettingsdialog.h" @@ -95,6 +96,16 @@ bool PacketModGUI::handleMessage(const Message& message) ui->transmittedText->appendPlainText(str); return true; } + else if (DSPSignalNotification::match(message)) + { + const DSPSignalNotification& notif = (const DSPSignalNotification&) message; + m_deviceCenterFrequency = notif.getCenterFrequency(); + m_basebandSampleRate = notif.getSampleRate(); + ui->deltaFrequency->setValueRange(false, 7, -m_basebandSampleRate/2, m_basebandSampleRate/2); + ui->deltaFrequencyLabel->setToolTip(tr("Range %1 %L2 Hz").arg(QChar(0xB1)).arg(m_basebandSampleRate/2)); + updateAbsoluteCenterFrequency(); + return true; + } else { return false; @@ -125,6 +136,7 @@ void PacketModGUI::on_deltaFrequency_changed(qint64 value) { m_channelMarker.setCenterFrequency(value); m_settings.m_inputFrequencyOffset = m_channelMarker.getCenterFrequency(); + updateAbsoluteCenterFrequency(); applySettings(); } @@ -368,7 +380,18 @@ void PacketModGUI::onWidgetRolled(QWidget* widget, bool rollDown) (void) widget; (void) rollDown; - saveState(m_rollupState); + RollupContents *rollupContents = getRollupContents(); + + if (rollupContents->hasExpandableWidgets()) { + setSizePolicy(sizePolicy().horizontalPolicy(), QSizePolicy::Expanding); + } else { + setSizePolicy(sizePolicy().horizontalPolicy(), QSizePolicy::Fixed); + } + + int h = rollupContents->height() + getAdditionalHeight(); + resize(width(), h); + + rollupContents->saveState(m_rollupState); applySettings(); } @@ -382,10 +405,17 @@ void PacketModGUI::onMenuDialogCalled(const QPoint &p) dialog.setReverseAPIPort(m_settings.m_reverseAPIPort); dialog.setReverseAPIDeviceIndex(m_settings.m_reverseAPIDeviceIndex); dialog.setReverseAPIChannelIndex(m_settings.m_reverseAPIChannelIndex); + dialog.setDefaultTitle(m_displayedName); + + if (m_deviceUISet->m_deviceMIMOEngine) + { + dialog.setNumberOfStreams(m_packetMod->getNumberOfDeviceStreams()); + dialog.setStreamIndex(m_settings.m_streamIndex); + } + dialog.move(p); dialog.exec(); - m_settings.m_inputFrequencyOffset = m_channelMarker.getCenterFrequency(); m_settings.m_rgbColor = m_channelMarker.getColor().rgb(); m_settings.m_title = m_channelMarker.getTitle(); m_settings.m_useReverseAPI = dialog.useReverseAPI(); @@ -395,22 +425,17 @@ void PacketModGUI::onMenuDialogCalled(const QPoint &p) m_settings.m_reverseAPIChannelIndex = dialog.getReverseAPIChannelIndex(); setWindowTitle(m_settings.m_title); + setTitle(m_channelMarker.getTitle()); setTitleColor(m_settings.m_rgbColor); - applySettings(); - } - else if ((m_contextMenuType == ContextMenuStreamSettings) && (m_deviceUISet->m_deviceMIMOEngine)) - { - DeviceStreamSelectionDialog dialog(this); - dialog.setNumberOfStreams(m_packetMod->getNumberOfDeviceStreams()); - dialog.setStreamIndex(m_settings.m_streamIndex); - dialog.move(p); - dialog.exec(); + if (m_deviceUISet->m_deviceMIMOEngine) + { + m_settings.m_streamIndex = dialog.getSelectedStreamIndex(); + m_channelMarker.clearStreamIndexes(); + m_channelMarker.addStreamIndex(m_settings.m_streamIndex); + updateIndexLabel(); + } - m_settings.m_streamIndex = dialog.getSelectedStreamIndex(); - m_channelMarker.clearStreamIndexes(); - m_channelMarker.addStreamIndex(m_settings.m_streamIndex); - displayStreamIndex(); applySettings(); } @@ -423,13 +448,17 @@ PacketModGUI::PacketModGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, Baseb m_pluginAPI(pluginAPI), m_deviceUISet(deviceUISet), m_channelMarker(this), + m_deviceCenterFrequency(0), + m_basebandSampleRate(1), m_doApplySettings(true) { - ui->setupUi(this); - m_helpURL = "plugins/channeltx/modpacket/readme.md"; setAttribute(Qt::WA_DeleteOnClose, true); - - connect(this, SIGNAL(widgetRolled(QWidget*,bool)), this, SLOT(onWidgetRolled(QWidget*,bool))); + m_helpURL = "plugins/channeltx/modpacket/readme.md"; + RollupContents *rollupContents = getRollupContents(); + ui->setupUi(rollupContents); + setSizePolicy(rollupContents->sizePolicy()); + rollupContents->arrangeRollups(); + connect(rollupContents, SIGNAL(widgetRolled(QWidget*,bool)), this, SLOT(onWidgetRolled(QWidget*,bool))); connect(this, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(onMenuDialogCalled(const QPoint &))); m_packetMod = (PacketMod*) channelTx; @@ -476,7 +505,6 @@ PacketModGUI::PacketModGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, Baseb m_channelMarker.setVisible(true); // activate signal on the last setting only m_deviceUISet->addChannelMarker(&m_channelMarker); - m_deviceUISet->addRollupWidget(this); connect(&m_channelMarker, SIGNAL(changedByCursor()), this, SLOT(channelMarkerChangedByCursor())); @@ -491,6 +519,7 @@ PacketModGUI::PacketModGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, Baseb ui->spectrumContainer->setVisible(false); displaySettings(); + makeUIConnections(); applySettings(); } @@ -533,7 +562,8 @@ void PacketModGUI::displaySettings() setTitleColor(m_settings.m_rgbColor); setWindowTitle(m_channelMarker.getTitle()); - displayStreamIndex(); + setTitle(m_channelMarker.getTitle()); + updateIndexLabel(); blockApplySettings(true); @@ -572,27 +602,21 @@ void PacketModGUI::displaySettings() ui->via->lineEdit()->setText(m_settings.m_via); ui->packet->setText(m_settings.m_data); - restoreState(m_rollupState); + getRollupContents()->restoreState(m_rollupState); + updateAbsoluteCenterFrequency(); blockApplySettings(false); } -void PacketModGUI::displayStreamIndex() -{ - if (m_deviceUISet->m_deviceMIMOEngine) { - setStreamIndicator(tr("%1").arg(m_settings.m_streamIndex)); - } else { - setStreamIndicator("S"); // single channel indicator - } -} - -void PacketModGUI::leaveEvent(QEvent*) +void PacketModGUI::leaveEvent(QEvent* event) { m_channelMarker.setHighlighted(false); + ChannelGUI::leaveEvent(event); } -void PacketModGUI::enterEvent(QEvent*) +void PacketModGUI::enterEvent(QEvent* event) { m_channelMarker.setHighlighted(true); + ChannelGUI::enterEvent(event); } void PacketModGUI::tick() @@ -601,3 +625,31 @@ void PacketModGUI::tick() m_channelPowerDbAvg(powDb); ui->channelPower->setText(tr("%1 dB").arg(m_channelPowerDbAvg.asDouble(), 0, 'f', 1)); } + +void PacketModGUI::makeUIConnections() +{ + QObject::connect(ui->deltaFrequency, &ValueDialZ::changed, this, &PacketModGUI::on_deltaFrequency_changed); + QObject::connect(ui->mode, QOverload::of(&QComboBox::currentIndexChanged), this, &PacketModGUI::on_mode_currentIndexChanged); + QObject::connect(ui->rfBW, &QSlider::valueChanged, this, &PacketModGUI::on_rfBW_valueChanged); + QObject::connect(ui->fmDev, &QSlider::valueChanged, this, &PacketModGUI::on_fmDev_valueChanged); + QObject::connect(ui->gain, &QDial::valueChanged, this, &PacketModGUI::on_gain_valueChanged); + QObject::connect(ui->channelMute, &QToolButton::toggled, this, &PacketModGUI::on_channelMute_toggled); + QObject::connect(ui->txButton, &QToolButton::clicked, this, &PacketModGUI::on_txButton_clicked); + QObject::connect(ui->callsign, &QLineEdit::editingFinished, this, &PacketModGUI::on_callsign_editingFinished); + QObject::connect(ui->to, &QComboBox::currentTextChanged, this, &PacketModGUI::on_to_currentTextChanged); + QObject::connect(ui->via, &QComboBox::currentTextChanged, this, &PacketModGUI::on_via_currentTextChanged); + QObject::connect(ui->packet, &QLineEdit::editingFinished, this, &PacketModGUI::on_packet_editingFinished); + QObject::connect(ui->insertPosition, &QToolButton::clicked, this, &PacketModGUI::on_insertPosition_clicked); + QObject::connect(ui->packet, &QLineEdit::returnPressed, this, &PacketModGUI::on_packet_returnPressed); + QObject::connect(ui->repeat, &ButtonSwitch::toggled, this, &PacketModGUI::on_repeat_toggled); + QObject::connect(ui->preEmphasis, &ButtonSwitch::toggled, this, &PacketModGUI::on_preEmphasis_toggled); + QObject::connect(ui->bpf, &ButtonSwitch::toggled, this, &PacketModGUI::on_bpf_toggled); + QObject::connect(ui->udpEnabled, &QCheckBox::clicked, this, &PacketModGUI::on_udpEnabled_clicked); + QObject::connect(ui->udpAddress, &QLineEdit::editingFinished, this, &PacketModGUI::on_udpAddress_editingFinished); + QObject::connect(ui->udpPort, &QLineEdit::editingFinished, this, &PacketModGUI::on_udpPort_editingFinished); +} + +void PacketModGUI::updateAbsoluteCenterFrequency() +{ + setStatusFrequency(m_deviceCenterFrequency + m_settings.m_inputFrequencyOffset); +} diff --git a/plugins/channeltx/modpacket/packetmodgui.h b/plugins/channeltx/modpacket/packetmodgui.h index 336039d8d..1ff5837f7 100644 --- a/plugins/channeltx/modpacket/packetmodgui.h +++ b/plugins/channeltx/modpacket/packetmodgui.h @@ -48,6 +48,17 @@ public: QByteArray serialize() const; bool deserialize(const QByteArray& data); virtual MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; } + virtual void setWorkspaceIndex(int index) { m_settings.m_workspaceIndex = index; }; + virtual int getWorkspaceIndex() const { return m_settings.m_workspaceIndex; }; + virtual void setGeometryBytes(const QByteArray& blob) { m_settings.m_geometryBytes = blob; }; + virtual QByteArray getGeometryBytes() const { return m_settings.m_geometryBytes; }; + virtual QString getTitle() const { return m_settings.m_title; }; + virtual QColor getTitleColor() const { return m_settings.m_rgbColor; }; + virtual void zetHidden(bool hidden) { m_settings.m_hidden = hidden; } + virtual bool getHidden() const { return m_settings.m_hidden; } + virtual ChannelMarker& getChannelMarker() { return m_channelMarker; } + virtual int getStreamIndex() const { return m_settings.m_streamIndex; } + virtual void setStreamIndex(int streamIndex) { m_settings.m_streamIndex = streamIndex; } public slots: void channelMarkerChangedByCursor(); @@ -59,6 +70,8 @@ private: ChannelMarker m_channelMarker; RollupState m_rollupState; PacketModSettings m_settings; + qint64 m_deviceCenterFrequency; + int m_basebandSampleRate; bool m_doApplySettings; SpectrumVis* m_spectrumVis; @@ -74,8 +87,9 @@ private: void blockApplySettings(bool block); void applySettings(bool force = false); void displaySettings(); - void displayStreamIndex(); bool handleMessage(const Message& message); + void makeUIConnections(); + void updateAbsoluteCenterFrequency(); void leaveEvent(QEvent*); void enterEvent(QEvent*); diff --git a/plugins/channeltx/modpacket/packetmodgui.ui b/plugins/channeltx/modpacket/packetmodgui.ui index 34fea6897..8df7d2d31 100644 --- a/plugins/channeltx/modpacket/packetmodgui.ui +++ b/plugins/channeltx/modpacket/packetmodgui.ui @@ -1,7 +1,7 @@ PacketModGUI - + 0 @@ -11,7 +11,7 @@ - + 0 0 @@ -828,6 +828,12 @@ APRS examples: 284 + + + 0 + 0 + + Baseband Spectrum @@ -849,6 +855,12 @@ APRS examples:
+ + + 0 + 0 + + 200 @@ -871,22 +883,11 @@ APRS examples: - RollupWidget + RollupContents QWidget -
gui/rollupwidget.h
+
gui/rollupcontents.h
1
- - ValueDialZ - QWidget -
gui/valuedialz.h
- 1 -
- - ButtonSwitch - QToolButton -
gui/buttonswitch.h
-
GLSpectrum QWidget @@ -899,6 +900,17 @@ APRS examples:
gui/glspectrumgui.h
1
+ + ValueDialZ + QWidget +
gui/valuedialz.h
+ 1 +
+ + ButtonSwitch + QToolButton +
gui/buttonswitch.h
+
LevelMeterVU QWidget diff --git a/plugins/channeltx/modpacket/packetmodsettings.cpp b/plugins/channeltx/modpacket/packetmodsettings.cpp index 3c4bc8d8b..5939717f2 100644 --- a/plugins/channeltx/modpacket/packetmodsettings.cpp +++ b/plugins/channeltx/modpacket/packetmodsettings.cpp @@ -85,6 +85,8 @@ void PacketModSettings::resetToDefaults() m_udpEnabled = false; m_udpAddress = "127.0.0.1"; m_udpPort = 9998; + m_workspaceIndex = 0; + m_hidden = false; } bool PacketModSettings::setMode(QString mode) @@ -231,6 +233,10 @@ QByteArray PacketModSettings::serialize() const s.writeBlob(54, m_rollupState->serialize()); } + s.writeS32(55, m_workspaceIndex); + s.writeBlob(56, m_geometryBytes); + s.writeBool(57, m_hidden); + return s.final(); } @@ -332,6 +338,10 @@ bool PacketModSettings::deserialize(const QByteArray& data) m_rollupState->deserialize(bytetmp); } + d.readS32(55, &m_workspaceIndex, 0); + d.readBlob(56, &m_geometryBytes); + d.readBool(57, &m_hidden, false); + return true; } else diff --git a/plugins/channeltx/modpacket/packetmodsettings.h b/plugins/channeltx/modpacket/packetmodsettings.h index 805ae22f7..25d79ad52 100644 --- a/plugins/channeltx/modpacket/packetmodsettings.h +++ b/plugins/channeltx/modpacket/packetmodsettings.h @@ -83,6 +83,9 @@ struct PacketModSettings QString m_udpAddress; uint16_t m_udpPort; Serializable *m_rollupState; + int m_workspaceIndex; + QByteArray m_geometryBytes; + bool m_hidden; PacketModSettings(); void resetToDefaults(); diff --git a/plugins/channeltx/modpacket/readme.md b/plugins/channeltx/modpacket/readme.md index f30f0570b..2ae2496fa 100644 --- a/plugins/channeltx/modpacket/readme.md +++ b/plugins/channeltx/modpacket/readme.md @@ -6,6 +6,8 @@ This plugin can be used to modulate packet radio (APRS/AX.25) data packets.

Interface

+The top and bottom bars of the channel window are described [here](../../../sdrgui/channel/readme.md) + ![Packet Modulator plugin GUI](../../../doc/img/PacketMod_plugin.png)

1: Frequency shift from center frequency of transmission

diff --git a/plugins/channeltx/modssb/readme.md b/plugins/channeltx/modssb/readme.md index 11a7c70ca..1489c7642 100644 --- a/plugins/channeltx/modssb/readme.md +++ b/plugins/channeltx/modssb/readme.md @@ -6,6 +6,8 @@ This plugin can be used to generate a single sideband or double sidebands modula

Interface

+The top and bottom bars of the channel window are described [here](../../../sdrgui/channel/readme.md) + ![SSB Modulator plugin GUI](../../../doc/img/SSBModulator_plugin.png) ☞ In order to toggle USB or LSB mode in SSB mode you have to set the "BW" in channel filter cutoff control (8) to a positive (USB) or negative (LSB) value. The above screenshot shows a USB setup. See the (7) to (9) paragraphs below for details. @@ -247,4 +249,4 @@ This slider can be used to randomly set the current position in the file when fi

22: Channel spectrum display

-This is the channel spectrum display. Controls at the bottom of the panel are the same as with the central spectrum display. +This is the channel spectrum display. Details on the spectrum view and controls can be found [here](../../../sdrgui/gui/spectrum.md) diff --git a/plugins/channeltx/modssb/ssbmod.cpp b/plugins/channeltx/modssb/ssbmod.cpp index b833c0562..f9e997c92 100644 --- a/plugins/channeltx/modssb/ssbmod.cpp +++ b/plugins/channeltx/modssb/ssbmod.cpp @@ -28,6 +28,7 @@ #include #include "SWGChannelSettings.h" +#include "SWGWorkspaceInfo.h" #include "SWGChannelReport.h" #include "SWGSSBModReport.h" @@ -99,6 +100,18 @@ SSBMod::~SSBMod() delete m_thread; } +void SSBMod::setDeviceAPI(DeviceAPI *deviceAPI) +{ + if (deviceAPI != m_deviceAPI) + { + m_deviceAPI->removeChannelSourceAPI(this); + m_deviceAPI->removeChannelSource(this); + m_deviceAPI = deviceAPI; + m_deviceAPI->addChannelSource(this); + m_deviceAPI->addChannelSinkAPI(this); + } +} + void SSBMod::start() { qDebug("SSBMod::start"); @@ -193,6 +206,10 @@ bool SSBMod::handleMessage(const Message& cmd) DSPSignalNotification* rep = new DSPSignalNotification(notif); // make a copy qDebug() << "SSBMod::handleMessage: DSPSignalNotification"; m_basebandSource->getInputMessageQueue()->push(rep); + // Forward to GUI if any + if (getMessageQueueToGUI()) { + getMessageQueueToGUI()->push(new DSPSignalNotification(notif)); + } return true; } @@ -424,6 +441,15 @@ int SSBMod::webapiSettingsGet( return 200; } +int SSBMod::webapiWorkspaceGet( + SWGSDRangel::SWGWorkspaceInfo& response, + QString& errorMessage) +{ + (void) errorMessage; + response.setIndex(m_settings.m_workspaceIndex); + return 200; +} + int SSBMod::webapiSettingsPutPatch( bool force, const QStringList& channelSettingsKeys, diff --git a/plugins/channeltx/modssb/ssbmod.h b/plugins/channeltx/modssb/ssbmod.h index 77afa532f..d09f97ed2 100644 --- a/plugins/channeltx/modssb/ssbmod.h +++ b/plugins/channeltx/modssb/ssbmod.h @@ -176,6 +176,8 @@ public: SSBMod(DeviceAPI *deviceAPI); virtual ~SSBMod(); virtual void destroy() { delete this; } + virtual void setDeviceAPI(DeviceAPI *deviceAPI); + virtual DeviceAPI *getDeviceAPI() { return m_deviceAPI; } virtual void start(); virtual void stop(); @@ -206,6 +208,10 @@ public: SWGSDRangel::SWGChannelSettings& response, QString& errorMessage); + virtual int webapiWorkspaceGet( + SWGSDRangel::SWGWorkspaceInfo& response, + QString& errorMessage); + virtual int webapiSettingsPutPatch( bool force, const QStringList& channelSettingsKeys, diff --git a/plugins/channeltx/modssb/ssbmodgui.cpp b/plugins/channeltx/modssb/ssbmodgui.cpp index 4c183a16f..7a3749b09 100644 --- a/plugins/channeltx/modssb/ssbmodgui.cpp +++ b/plugins/channeltx/modssb/ssbmodgui.cpp @@ -99,6 +99,16 @@ bool SSBModGUI::handleMessage(const Message& message) applyBandwidths(5 - ui->spanLog2->value()); // will update spectrum details with new sample rate return true; } + else if (DSPSignalNotification::match(message)) + { + const DSPSignalNotification& notif = (const DSPSignalNotification&) message; + m_deviceCenterFrequency = notif.getCenterFrequency(); + m_basebandSampleRate = notif.getSampleRate(); + ui->deltaFrequency->setValueRange(false, 7, -m_basebandSampleRate/2, m_basebandSampleRate/2); + ui->deltaFrequencyLabel->setToolTip(tr("Range %1 %L2 Hz").arg(QChar(0xB1)).arg(m_basebandSampleRate/2)); + updateAbsoluteCenterFrequency(); + return true; + } else if (SSBMod::MsgConfigureSSBMod::match(message)) { SSBModSettings mod_settings; // different USB/LSB convention between modulator and GUI @@ -160,6 +170,7 @@ void SSBModGUI::on_deltaFrequency_changed(qint64 value) { m_channelMarker.setCenterFrequency(value); m_settings.m_inputFrequencyOffset = m_channelMarker.getCenterFrequency(); + updateAbsoluteCenterFrequency(); applySettings(); } @@ -348,7 +359,18 @@ void SSBModGUI::onWidgetRolled(QWidget* widget, bool rollDown) (void) widget; (void) rollDown; - saveState(m_rollupState); + RollupContents *rollupContents = getRollupContents(); + + if (rollupContents->hasExpandableWidgets()) { + setSizePolicy(sizePolicy().horizontalPolicy(), QSizePolicy::Expanding); + } else { + setSizePolicy(sizePolicy().horizontalPolicy(), QSizePolicy::Fixed); + } + + int h = rollupContents->height() + getAdditionalHeight(); + resize(width(), h); + + rollupContents->saveState(m_rollupState); applySettings(); } @@ -362,11 +384,17 @@ void SSBModGUI::onMenuDialogCalled(const QPoint &p) dialog.setReverseAPIPort(m_settings.m_reverseAPIPort); dialog.setReverseAPIDeviceIndex(m_settings.m_reverseAPIDeviceIndex); dialog.setReverseAPIChannelIndex(m_settings.m_reverseAPIChannelIndex); + dialog.setDefaultTitle(m_displayedName); + + if (m_deviceUISet->m_deviceMIMOEngine) + { + dialog.setNumberOfStreams(m_ssbMod->getNumberOfDeviceStreams()); + dialog.setStreamIndex(m_settings.m_streamIndex); + } dialog.move(p); dialog.exec(); - m_settings.m_inputFrequencyOffset = m_channelMarker.getCenterFrequency(); m_settings.m_rgbColor = m_channelMarker.getColor().rgb(); m_settings.m_title = m_channelMarker.getTitle(); m_settings.m_useReverseAPI = dialog.useReverseAPI(); @@ -376,22 +404,17 @@ void SSBModGUI::onMenuDialogCalled(const QPoint &p) m_settings.m_reverseAPIChannelIndex = dialog.getReverseAPIChannelIndex(); setWindowTitle(m_settings.m_title); + setTitle(m_channelMarker.getTitle()); setTitleColor(m_settings.m_rgbColor); - applySettings(); - } - else if ((m_contextMenuType == ContextMenuStreamSettings) && (m_deviceUISet->m_deviceMIMOEngine)) - { - DeviceStreamSelectionDialog dialog(this); - dialog.setNumberOfStreams(m_ssbMod->getNumberOfDeviceStreams()); - dialog.setStreamIndex(m_settings.m_streamIndex); - dialog.move(p); - dialog.exec(); + if (m_deviceUISet->m_deviceMIMOEngine) + { + m_settings.m_streamIndex = dialog.getSelectedStreamIndex(); + m_channelMarker.clearStreamIndexes(); + m_channelMarker.addStreamIndex(m_settings.m_streamIndex); + updateIndexLabel(); + } - m_settings.m_streamIndex = dialog.getSelectedStreamIndex(); - m_channelMarker.clearStreamIndexes(); - m_channelMarker.addStreamIndex(m_settings.m_streamIndex); - displayStreamIndex(); applySettings(); } @@ -404,6 +427,8 @@ SSBModGUI::SSBModGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, BasebandSam m_pluginAPI(pluginAPI), m_deviceUISet(deviceUISet), m_channelMarker(this), + m_deviceCenterFrequency(0), + m_basebandSampleRate(1), m_doApplySettings(true), m_spectrumRate(6000), m_recordLength(0), @@ -414,10 +439,13 @@ SSBModGUI::SSBModGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, BasebandSam m_tickCount(0), m_enableNavTime(false) { - ui->setupUi(this); - m_helpURL = "plugins/channeltx/modssb/readme.md"; setAttribute(Qt::WA_DeleteOnClose, true); - connect(this, SIGNAL(widgetRolled(QWidget*,bool)), this, SLOT(onWidgetRolled(QWidget*,bool))); + m_helpURL = "plugins/channeltx/modssb/readme.md"; + RollupContents *rollupContents = getRollupContents(); + ui->setupUi(rollupContents); + setSizePolicy(rollupContents->sizePolicy()); + rollupContents->arrangeRollups(); + connect(rollupContents, SIGNAL(widgetRolled(QWidget*,bool)), this, SLOT(onWidgetRolled(QWidget*,bool))); connect(this, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(onMenuDialogCalled(const QPoint &))); m_ssbMod = (SSBMod*) channelTx; @@ -458,7 +486,6 @@ SSBModGUI::SSBModGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, BasebandSam setTitleColor(m_channelMarker.getColor()); m_deviceUISet->addChannelMarker(&m_channelMarker); - m_deviceUISet->addRollupWidget(this); connect(&m_channelMarker, SIGNAL(changedByCursor()), this, SLOT(channelMarkerChangedByCursor())); @@ -479,6 +506,7 @@ SSBModGUI::SSBModGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, BasebandSam m_iconDSBLSB.addPixmap(QPixmap("://lsb.png"), QIcon::Normal, QIcon::Off); displaySettings(); + makeUIConnections(); applyBandwidths(5 - ui->spanLog2->value(), true); // does applySettings(true) } @@ -648,7 +676,8 @@ void SSBModGUI::displaySettings() setTitleColor(m_settings.m_rgbColor); setWindowTitle(m_channelMarker.getTitle()); - displayStreamIndex(); + setTitle(m_channelMarker.getTitle()); + updateIndexLabel(); blockApplySettings(true); @@ -715,27 +744,21 @@ void SSBModGUI::displaySettings() ui->feedbackVolume->setValue(roundf(m_settings.m_feedbackVolumeFactor * 100.0)); ui->feedbackVolumeText->setText(QString("%1").arg(m_settings.m_feedbackVolumeFactor, 0, 'f', 2)); - restoreState(m_rollupState); + getRollupContents()->restoreState(m_rollupState); + updateAbsoluteCenterFrequency(); blockApplySettings(false); } -void SSBModGUI::displayStreamIndex() -{ - if (m_deviceUISet->m_deviceMIMOEngine) { - setStreamIndicator(tr("%1").arg(m_settings.m_streamIndex)); - } else { - setStreamIndicator("S"); // single channel indicator - } -} - -void SSBModGUI::leaveEvent(QEvent*) +void SSBModGUI::leaveEvent(QEvent* event) { m_channelMarker.setHighlighted(false); + ChannelGUI::leaveEvent(event); } -void SSBModGUI::enterEvent(QEvent*) +void SSBModGUI::enterEvent(QEvent* event) { m_channelMarker.setHighlighted(true); + ChannelGUI::enterEvent(event); } void SSBModGUI::audioSelect() @@ -836,3 +859,34 @@ void SSBModGUI::updateWithStreamTime() ui->navTimeSlider->setValue((int) (posRatio * 100.0)); } } + +void SSBModGUI::makeUIConnections() +{ + QObject::connect(ui->deltaFrequency, &ValueDialZ::changed, this, &SSBModGUI::on_deltaFrequency_changed); + QObject::connect(ui->flipSidebands, &QPushButton::clicked, this, &SSBModGUI::on_flipSidebands_clicked); + QObject::connect(ui->dsb, &QToolButton::toggled, this, &SSBModGUI::on_dsb_toggled); + QObject::connect(ui->audioBinaural, &QToolButton::toggled, this, &SSBModGUI::on_audioBinaural_toggled); + QObject::connect(ui->audioFlipChannels, &QToolButton::toggled, this, &SSBModGUI::on_audioFlipChannels_toggled); + QObject::connect(ui->BW, &TickedSlider::valueChanged, this, &SSBModGUI::on_BW_valueChanged); + QObject::connect(ui->lowCut, &TickedSlider::valueChanged, this, &SSBModGUI::on_lowCut_valueChanged); + QObject::connect(ui->volume, &QDial::valueChanged, this, &SSBModGUI::on_volume_valueChanged); + QObject::connect(ui->audioMute, &QToolButton::toggled, this, &SSBModGUI::on_audioMute_toggled); + QObject::connect(ui->tone, &ButtonSwitch::toggled, this, &SSBModGUI::on_tone_toggled); + QObject::connect(ui->toneFrequency, &QDial::valueChanged, this, &SSBModGUI::on_toneFrequency_valueChanged); + QObject::connect(ui->mic, &ButtonSwitch::toggled, this, &SSBModGUI::on_mic_toggled); + QObject::connect(ui->agc, &ButtonSwitch::toggled, this, &SSBModGUI::on_agc_toggled); + QObject::connect(ui->cmpPreGain, &QDial::valueChanged, this, &SSBModGUI::on_cmpPreGain_valueChanged); + QObject::connect(ui->cmpThreshold, &QDial::valueChanged, this, &SSBModGUI::on_cmpThreshold_valueChanged); + QObject::connect(ui->play, &ButtonSwitch::toggled, this, &SSBModGUI::on_play_toggled); + QObject::connect(ui->playLoop, &ButtonSwitch::toggled, this, &SSBModGUI::on_playLoop_toggled); + QObject::connect(ui->morseKeyer, &ButtonSwitch::toggled, this, &SSBModGUI::on_morseKeyer_toggled); + QObject::connect(ui->navTimeSlider, &QSlider::valueChanged, this, &SSBModGUI::on_navTimeSlider_valueChanged); + QObject::connect(ui->showFileDialog, &QPushButton::clicked, this, &SSBModGUI::on_showFileDialog_clicked); + QObject::connect(ui->feedbackEnable, &QToolButton::toggled, this, &SSBModGUI::on_feedbackEnable_toggled); + QObject::connect(ui->feedbackVolume, &QDial::valueChanged, this, &SSBModGUI::on_feedbackVolume_valueChanged); +} + +void SSBModGUI::updateAbsoluteCenterFrequency() +{ + setStatusFrequency(m_deviceCenterFrequency + m_settings.m_inputFrequencyOffset); +} diff --git a/plugins/channeltx/modssb/ssbmodgui.h b/plugins/channeltx/modssb/ssbmodgui.h index f5159ba7f..dd793e1bc 100644 --- a/plugins/channeltx/modssb/ssbmodgui.h +++ b/plugins/channeltx/modssb/ssbmodgui.h @@ -49,6 +49,17 @@ public: QByteArray serialize() const; bool deserialize(const QByteArray& data); virtual MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; } + virtual void setWorkspaceIndex(int index) { m_settings.m_workspaceIndex = index; }; + virtual int getWorkspaceIndex() const { return m_settings.m_workspaceIndex; }; + virtual void setGeometryBytes(const QByteArray& blob) { m_settings.m_geometryBytes = blob; }; + virtual QByteArray getGeometryBytes() const { return m_settings.m_geometryBytes; }; + virtual QString getTitle() const { return m_settings.m_title; }; + virtual QColor getTitleColor() const { return m_settings.m_rgbColor; }; + virtual void zetHidden(bool hidden) { m_settings.m_hidden = hidden; } + virtual bool getHidden() const { return m_settings.m_hidden; } + virtual ChannelMarker& getChannelMarker() { return m_channelMarker; } + virtual int getStreamIndex() const { return m_settings.m_streamIndex; } + virtual void setStreamIndex(int streamIndex) { m_settings.m_streamIndex = streamIndex; } public slots: void channelMarkerChangedByCursor(); @@ -60,6 +71,8 @@ private: ChannelMarker m_channelMarker; RollupState m_rollupState; SSBModSettings m_settings; + qint64 m_deviceCenterFrequency; + int m_basebandSampleRate; bool m_doApplySettings; int m_spectrumRate; @@ -87,11 +100,12 @@ private: void applySettings(bool force = false); void applyBandwidths(int spanLog2, bool force = false); void displaySettings(); - void displayStreamIndex(); void updateWithStreamData(); void updateWithStreamTime(); void channelMarkerUpdate(); bool handleMessage(const Message& message); + void makeUIConnections(); + void updateAbsoluteCenterFrequency(); void leaveEvent(QEvent*); void enterEvent(QEvent*); diff --git a/plugins/channeltx/modssb/ssbmodgui.ui b/plugins/channeltx/modssb/ssbmodgui.ui index 035a6dbf7..69d90c843 100644 --- a/plugins/channeltx/modssb/ssbmodgui.ui +++ b/plugins/channeltx/modssb/ssbmodgui.ui @@ -1,24 +1,24 @@ SSBModGUI - + 0 0 - 430 - 643 + 414 + 331 - + 0 0 - 430 + 414 0 @@ -36,13 +36,13 @@ 0 0 - 430 + 412 331 - 385 + 412 0 @@ -503,6 +503,7 @@ + Liberation Sans 8 @@ -524,6 +525,7 @@ + Liberation Sans 8 @@ -536,6 +538,7 @@ + Liberation Sans 8 @@ -557,6 +560,7 @@ + Liberation Sans 8 @@ -572,6 +576,7 @@ + Liberation Sans 8 @@ -593,6 +598,7 @@ + Liberation Sans 8 @@ -1202,6 +1208,12 @@ 284 + + + 0 + 0 + + Channel Spectrum @@ -1223,6 +1235,12 @@ + + + 0 + 0 + + 200 @@ -1245,9 +1263,9 @@ - RollupWidget + RollupContents QWidget -
gui/rollupwidget.h
+
gui/rollupcontents.h
1
@@ -1263,9 +1281,9 @@ 1 - LevelMeterVU + ValueDialZ QWidget -
gui/levelmeter.h
+
gui/valuedialz.h
1
@@ -1274,15 +1292,15 @@
gui/buttonswitch.h
- CWKeyerGUI + LevelMeterVU QWidget -
gui/cwkeyergui.h
+
gui/levelmeter.h
1
- ValueDialZ + CWKeyerGUI QWidget -
gui/valuedialz.h
+
gui/cwkeyergui.h
1
diff --git a/plugins/channeltx/modssb/ssbmodsettings.cpp b/plugins/channeltx/modssb/ssbmodsettings.cpp index 7ddfa67ba..3cc48adeb 100644 --- a/plugins/channeltx/modssb/ssbmodsettings.cpp +++ b/plugins/channeltx/modssb/ssbmodsettings.cpp @@ -75,6 +75,8 @@ void SSBModSettings::resetToDefaults() m_reverseAPIPort = 8888; m_reverseAPIDeviceIndex = 0; m_reverseAPIChannelIndex = 0; + m_workspaceIndex = 0; + m_hidden = false; } QByteArray SSBModSettings::serialize() const @@ -127,6 +129,10 @@ QByteArray SSBModSettings::serialize() const s.writeBlob(31, m_rollupState->serialize()); } + s.writeS32(32, m_workspaceIndex); + s.writeBlob(33, m_geometryBytes); + s.writeBool(34, m_hidden); + return s.final(); } @@ -219,6 +225,10 @@ bool SSBModSettings::deserialize(const QByteArray& data) m_rollupState->deserialize(bytetmp); } + d.readS32(32, &m_workspaceIndex, 0); + d.readBlob(33, &m_geometryBytes); + d.readBool(34, &m_hidden, false); + return true; } else diff --git a/plugins/channeltx/modssb/ssbmodsettings.h b/plugins/channeltx/modssb/ssbmodsettings.h index dbe67f68a..5327a8106 100644 --- a/plugins/channeltx/modssb/ssbmodsettings.h +++ b/plugins/channeltx/modssb/ssbmodsettings.h @@ -70,6 +70,9 @@ struct SSBModSettings uint16_t m_reverseAPIPort; uint16_t m_reverseAPIDeviceIndex; uint16_t m_reverseAPIChannelIndex; + int m_workspaceIndex; + QByteArray m_geometryBytes; + bool m_hidden; Serializable *m_channelMarker; Serializable *m_spectrumGUI; diff --git a/plugins/channeltx/modwfm/readme.md b/plugins/channeltx/modwfm/readme.md index ad3f4b0ad..df61d4f61 100644 --- a/plugins/channeltx/modwfm/readme.md +++ b/plugins/channeltx/modwfm/readme.md @@ -6,6 +6,8 @@ This plugin can be used to generate a wideband frequency modulated signal. "Wide

Interface

+The top and bottom bars of the channel window are described [here](../../../sdrgui/channel/readme.md) + ![WFM Modulator plugin GUI](../../../doc/img/WFMMod_plugin.png)

1: Frequency shift from center frequency of transmission

diff --git a/plugins/channeltx/modwfm/wfmmod.cpp b/plugins/channeltx/modwfm/wfmmod.cpp index 2aceef3e2..e95a01a3e 100644 --- a/plugins/channeltx/modwfm/wfmmod.cpp +++ b/plugins/channeltx/modwfm/wfmmod.cpp @@ -28,6 +28,7 @@ #include #include "SWGChannelSettings.h" +#include "SWGWorkspaceInfo.h" #include "SWGChannelReport.h" #include "SWGAMModReport.h" @@ -96,6 +97,18 @@ WFMMod::~WFMMod() delete m_thread; } +void WFMMod::setDeviceAPI(DeviceAPI *deviceAPI) +{ + if (deviceAPI != m_deviceAPI) + { + m_deviceAPI->removeChannelSourceAPI(this); + m_deviceAPI->removeChannelSource(this); + m_deviceAPI = deviceAPI; + m_deviceAPI->addChannelSource(this); + m_deviceAPI->addChannelSinkAPI(this); + } +} + void WFMMod::start() { qDebug("WFMMod::start"); @@ -189,6 +202,10 @@ bool WFMMod::handleMessage(const Message& cmd) DSPSignalNotification* rep = new DSPSignalNotification(notif); // make a copy qDebug() << "WFMMod::handleMessage: DSPSignalNotification"; m_basebandSource->getInputMessageQueue()->push(rep); + // Forward to GUI if any + if (getMessageQueueToGUI()) { + getMessageQueueToGUI()->push(new DSPSignalNotification(notif)); + } return true; } @@ -386,6 +403,15 @@ int WFMMod::webapiSettingsGet( return 200; } +int WFMMod::webapiWorkspaceGet( + SWGSDRangel::SWGWorkspaceInfo& response, + QString& errorMessage) +{ + (void) errorMessage; + response.setIndex(m_settings.m_workspaceIndex); + return 200; +} + int WFMMod::webapiSettingsPutPatch( bool force, const QStringList& channelSettingsKeys, diff --git a/plugins/channeltx/modwfm/wfmmod.h b/plugins/channeltx/modwfm/wfmmod.h index 0f05972bb..d209ef708 100644 --- a/plugins/channeltx/modwfm/wfmmod.h +++ b/plugins/channeltx/modwfm/wfmmod.h @@ -174,6 +174,8 @@ public: WFMMod(DeviceAPI *deviceAPI); virtual ~WFMMod(); virtual void destroy() { delete this; } + virtual void setDeviceAPI(DeviceAPI *deviceAPI); + virtual DeviceAPI *getDeviceAPI() { return m_deviceAPI; } virtual void start(); virtual void stop(); @@ -204,6 +206,10 @@ public: SWGSDRangel::SWGChannelSettings& response, QString& errorMessage); + virtual int webapiWorkspaceGet( + SWGSDRangel::SWGWorkspaceInfo& response, + QString& errorMessage); + virtual int webapiSettingsPutPatch( bool force, const QStringList& channelSettingsKeys, diff --git a/plugins/channeltx/modwfm/wfmmodgui.cpp b/plugins/channeltx/modwfm/wfmmodgui.cpp index 2039b56d6..4af2c0a31 100644 --- a/plugins/channeltx/modwfm/wfmmodgui.cpp +++ b/plugins/channeltx/modwfm/wfmmodgui.cpp @@ -21,6 +21,7 @@ #include #include #include +#include #include "device/deviceuiset.h" #include "plugin/pluginapi.h" @@ -28,6 +29,7 @@ #include "util/db.h" #include "dsp/dspengine.h" #include "dsp/cwkeyer.h" +#include "dsp/dspcommands.h" #include "gui/crightclickenabler.h" #include "gui/audioselectdialog.h" #include "gui/basicchannelsettingsdialog.h" @@ -72,6 +74,14 @@ bool WFMModGUI::deserialize(const QByteArray& data) } } +void WFMModGUI::resizeEvent(QResizeEvent* size) +{ + int maxWidth = getRollupContents()->maximumWidth(); + int minHeight = getRollupContents()->minimumHeight() + getAdditionalHeight(); + resize(width() < maxWidth ? width() : maxWidth, minHeight); + size->accept(); +} + bool WFMModGUI::handleMessage(const Message& message) { if (WFMMod::MsgReportFileSourceStreamData::match(message)) @@ -105,6 +115,16 @@ bool WFMModGUI::handleMessage(const Message& message) ui->cwKeyerGUI->displaySettings(); return true; } + else if (DSPSignalNotification::match(message)) + { + const DSPSignalNotification& notif = (const DSPSignalNotification&) message; + m_deviceCenterFrequency = notif.getCenterFrequency(); + m_basebandSampleRate = notif.getSampleRate(); + ui->deltaFrequency->setValueRange(false, 8, -m_basebandSampleRate/2, m_basebandSampleRate/2); + ui->deltaFrequencyLabel->setToolTip(tr("Range %1 %L2 Hz").arg(QChar(0xB1)).arg(m_basebandSampleRate/2)); + updateAbsoluteCenterFrequency(); + return true; + } else { return false; @@ -135,6 +155,7 @@ void WFMModGUI::on_deltaFrequency_changed(qint64 value) { m_channelMarker.setCenterFrequency(value); m_settings.m_inputFrequencyOffset = m_channelMarker.getCenterFrequency(); + updateAbsoluteCenterFrequency(); applySettings(); } @@ -277,7 +298,7 @@ void WFMModGUI::onWidgetRolled(QWidget* widget, bool rollDown) (void) widget; (void) rollDown; - saveState(m_rollupState); + getRollupContents()->saveState(m_rollupState); applySettings(); } @@ -291,11 +312,17 @@ void WFMModGUI::onMenuDialogCalled(const QPoint &p) dialog.setReverseAPIPort(m_settings.m_reverseAPIPort); dialog.setReverseAPIDeviceIndex(m_settings.m_reverseAPIDeviceIndex); dialog.setReverseAPIChannelIndex(m_settings.m_reverseAPIChannelIndex); + dialog.setDefaultTitle(m_displayedName); + + if (m_deviceUISet->m_deviceMIMOEngine) + { + dialog.setNumberOfStreams(m_wfmMod->getNumberOfDeviceStreams()); + dialog.setStreamIndex(m_settings.m_streamIndex); + } dialog.move(p); dialog.exec(); - m_settings.m_inputFrequencyOffset = m_channelMarker.getCenterFrequency(); m_settings.m_rgbColor = m_channelMarker.getColor().rgb(); m_settings.m_title = m_channelMarker.getTitle(); m_settings.m_useReverseAPI = dialog.useReverseAPI(); @@ -305,22 +332,17 @@ void WFMModGUI::onMenuDialogCalled(const QPoint &p) m_settings.m_reverseAPIChannelIndex = dialog.getReverseAPIChannelIndex(); setWindowTitle(m_settings.m_title); + setTitle(m_channelMarker.getTitle()); setTitleColor(m_settings.m_rgbColor); - applySettings(); - } - else if ((m_contextMenuType == ContextMenuStreamSettings) && (m_deviceUISet->m_deviceMIMOEngine)) - { - DeviceStreamSelectionDialog dialog(this); - dialog.setNumberOfStreams(m_wfmMod->getNumberOfDeviceStreams()); - dialog.setStreamIndex(m_settings.m_streamIndex); - dialog.move(p); - dialog.exec(); + if (m_deviceUISet->m_deviceMIMOEngine) + { + m_settings.m_streamIndex = dialog.getSelectedStreamIndex(); + m_channelMarker.clearStreamIndexes(); + m_channelMarker.addStreamIndex(m_settings.m_streamIndex); + updateIndexLabel(); + } - m_settings.m_streamIndex = dialog.getSelectedStreamIndex(); - m_channelMarker.clearStreamIndexes(); - m_channelMarker.addStreamIndex(m_settings.m_streamIndex); - displayStreamIndex(); applySettings(); } @@ -333,6 +355,8 @@ WFMModGUI::WFMModGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, BasebandSam m_pluginAPI(pluginAPI), m_deviceUISet(deviceUISet), m_channelMarker(this), + m_deviceCenterFrequency(0), + m_basebandSampleRate(1), m_doApplySettings(true), m_recordLength(0), m_recordSampleRate(48000), @@ -342,9 +366,13 @@ WFMModGUI::WFMModGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, BasebandSam m_tickCount(0), m_enableNavTime(false) { - ui->setupUi(this); - m_helpURL = "plugins/channeltx/modwfm/readme.md"; setAttribute(Qt::WA_DeleteOnClose, true); + m_helpURL = "plugins/channeltx/modwfm/readme.md"; + RollupContents *rollupContents = getRollupContents(); + ui->setupUi(rollupContents); + setSizePolicy(rollupContents->sizePolicy()); + rollupContents->arrangeRollups(); + connect(rollupContents, SIGNAL(widgetRolled(QWidget*,bool)), this, SLOT(onWidgetRolled(QWidget*,bool))); blockApplySettings(true); @@ -356,7 +384,6 @@ WFMModGUI::WFMModGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, BasebandSam blockApplySettings(false); - connect(this, SIGNAL(widgetRolled(QWidget*,bool)), this, SLOT(onWidgetRolled(QWidget*,bool))); connect(this, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(onMenuDialogCalled(const QPoint &))); m_wfmMod = (WFMMod*) channelTx; @@ -384,7 +411,6 @@ WFMModGUI::WFMModGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, BasebandSam m_channelMarker.setVisible(true); // activate signal on the last setting only m_deviceUISet->addChannelMarker(&m_channelMarker); - m_deviceUISet->addRollupWidget(this); connect(&m_channelMarker, SIGNAL(changedByCursor()), this, SLOT(channelMarkerChangedByCursor())); @@ -403,6 +429,7 @@ WFMModGUI::WFMModGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, BasebandSam m_wfmMod->setLevelMeter(ui->volumeMeter); displaySettings(); + makeUIConnections(); applySettings(true); } @@ -438,7 +465,8 @@ void WFMModGUI::displaySettings() setTitleColor(m_settings.m_rgbColor); setWindowTitle(m_channelMarker.getTitle()); - displayStreamIndex(); + setTitle(m_channelMarker.getTitle()); + updateIndexLabel(); blockApplySettings(true); @@ -475,27 +503,21 @@ void WFMModGUI::displaySettings() ui->feedbackVolume->setValue(roundf(m_settings.m_feedbackVolumeFactor * 100.0)); ui->feedbackVolumeText->setText(QString("%1").arg(m_settings.m_feedbackVolumeFactor, 0, 'f', 2)); - restoreState(m_rollupState); + getRollupContents()->restoreState(m_rollupState); + updateAbsoluteCenterFrequency(); blockApplySettings(false); } -void WFMModGUI::displayStreamIndex() -{ - if (m_deviceUISet->m_deviceMIMOEngine) { - setStreamIndicator(tr("%1").arg(m_settings.m_streamIndex)); - } else { - setStreamIndicator("S"); // single channel indicator - } -} - -void WFMModGUI::leaveEvent(QEvent*) +void WFMModGUI::leaveEvent(QEvent* event) { m_channelMarker.setHighlighted(false); + ChannelGUI::leaveEvent(event); } -void WFMModGUI::enterEvent(QEvent*) +void WFMModGUI::enterEvent(QEvent* event) { m_channelMarker.setHighlighted(true); + ChannelGUI::enterEvent(event); } void WFMModGUI::audioSelect() @@ -596,3 +618,28 @@ void WFMModGUI::updateWithStreamTime() ui->navTimeSlider->setValue((int) (posRatio * 100.0)); } } + +void WFMModGUI::makeUIConnections() +{ + QObject::connect(ui->deltaFrequency, &ValueDialZ::changed, this, &WFMModGUI::on_deltaFrequency_changed); + QObject::connect(ui->rfBW, QOverload::of(&QComboBox::currentIndexChanged), this, &WFMModGUI::on_rfBW_currentIndexChanged); + QObject::connect(ui->afBW, &QSlider::valueChanged, this, &WFMModGUI::on_afBW_valueChanged); + QObject::connect(ui->fmDev, &QSlider::valueChanged, this, &WFMModGUI::on_fmDev_valueChanged); + QObject::connect(ui->toneFrequency, &QDial::valueChanged, this, &WFMModGUI::on_toneFrequency_valueChanged); + QObject::connect(ui->volume, &QDial::valueChanged, this, &WFMModGUI::on_volume_valueChanged); + QObject::connect(ui->channelMute, &QToolButton::toggled, this, &WFMModGUI::on_channelMute_toggled); + QObject::connect(ui->tone, &ButtonSwitch::toggled, this, &WFMModGUI::on_tone_toggled); + QObject::connect(ui->morseKeyer, &ButtonSwitch::toggled, this, &WFMModGUI::on_morseKeyer_toggled); + QObject::connect(ui->mic, &ButtonSwitch::toggled, this, &WFMModGUI::on_mic_toggled); + QObject::connect(ui->play, &ButtonSwitch::toggled, this, &WFMModGUI::on_play_toggled); + QObject::connect(ui->playLoop, &ButtonSwitch::toggled, this, &WFMModGUI::on_playLoop_toggled); + QObject::connect(ui->navTimeSlider, &QSlider::valueChanged, this, &WFMModGUI::on_navTimeSlider_valueChanged); + QObject::connect(ui->showFileDialog, &QPushButton::clicked, this, &WFMModGUI::on_showFileDialog_clicked); + QObject::connect(ui->feedbackEnable, &QToolButton::toggled, this, &WFMModGUI::on_feedbackEnable_toggled); + QObject::connect(ui->feedbackVolume, &QDial::valueChanged, this, &WFMModGUI::on_feedbackVolume_valueChanged); +} + +void WFMModGUI::updateAbsoluteCenterFrequency() +{ + setStatusFrequency(m_deviceCenterFrequency + m_settings.m_inputFrequencyOffset); +} diff --git a/plugins/channeltx/modwfm/wfmmodgui.h b/plugins/channeltx/modwfm/wfmmodgui.h index f85465ab5..35d0c1ad1 100644 --- a/plugins/channeltx/modwfm/wfmmodgui.h +++ b/plugins/channeltx/modwfm/wfmmodgui.h @@ -46,10 +46,24 @@ public: QByteArray serialize() const; bool deserialize(const QByteArray& data); virtual MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; } + virtual void setWorkspaceIndex(int index) { m_settings.m_workspaceIndex = index; }; + virtual int getWorkspaceIndex() const { return m_settings.m_workspaceIndex; }; + virtual void setGeometryBytes(const QByteArray& blob) { m_settings.m_geometryBytes = blob; }; + virtual QByteArray getGeometryBytes() const { return m_settings.m_geometryBytes; }; + virtual QString getTitle() const { return m_settings.m_title; }; + virtual QColor getTitleColor() const { return m_settings.m_rgbColor; }; + virtual void zetHidden(bool hidden) { m_settings.m_hidden = hidden; } + virtual bool getHidden() const { return m_settings.m_hidden; } + virtual ChannelMarker& getChannelMarker() { return m_channelMarker; } + virtual int getStreamIndex() const { return m_settings.m_streamIndex; } + virtual void setStreamIndex(int streamIndex) { m_settings.m_streamIndex = streamIndex; } public slots: void channelMarkerChangedByCursor(); +protected: + void resizeEvent(QResizeEvent* size); + private: Ui::WFMModGUI* ui; PluginAPI* m_pluginAPI; @@ -57,6 +71,8 @@ private: ChannelMarker m_channelMarker; RollupState m_rollupState; WFMModSettings m_settings; + qint64 m_deviceCenterFrequency; + int m_basebandSampleRate; bool m_doApplySettings; WFMMod* m_wfmMod; @@ -78,10 +94,11 @@ private: void blockApplySettings(bool block); void applySettings(bool force = false); void displaySettings(); - void displayStreamIndex(); void updateWithStreamData(); void updateWithStreamTime(); bool handleMessage(const Message& message); + void makeUIConnections(); + void updateAbsoluteCenterFrequency(); void leaveEvent(QEvent*); void enterEvent(QEvent*); diff --git a/plugins/channeltx/modwfm/wfmmodgui.ui b/plugins/channeltx/modwfm/wfmmodgui.ui index 919a97c37..4a8d5bb2b 100644 --- a/plugins/channeltx/modwfm/wfmmodgui.ui +++ b/plugins/channeltx/modwfm/wfmmodgui.ui @@ -1,27 +1,33 @@ WFMModGUI - + 0 0 - 298 + 360 300 - + 0 0 - 0 + 360 0 + + + 560 + 16777215 + + Liberation Sans @@ -765,26 +771,9 @@ - RollupWidget + RollupContents QWidget -
gui/rollupwidget.h
- 1 -
- - LevelMeterVU - QWidget -
gui/levelmeter.h
- 1 -
- - ButtonSwitch - QToolButton -
gui/buttonswitch.h
-
- - CWKeyerGUI - QWidget -
gui/cwkeyergui.h
+
gui/rollupcontents.h
1
@@ -793,6 +782,23 @@
gui/valuedialz.h
1
+ + ButtonSwitch + QToolButton +
gui/buttonswitch.h
+
+ + LevelMeterVU + QWidget +
gui/levelmeter.h
+ 1 +
+ + CWKeyerGUI + QWidget +
gui/cwkeyergui.h
+ 1 +
diff --git a/plugins/channeltx/modwfm/wfmmodsettings.cpp b/plugins/channeltx/modwfm/wfmmodsettings.cpp index 3bebd733b..ccf7501ca 100644 --- a/plugins/channeltx/modwfm/wfmmodsettings.cpp +++ b/plugins/channeltx/modwfm/wfmmodsettings.cpp @@ -60,6 +60,8 @@ void WFMModSettings::resetToDefaults() m_reverseAPIPort = 8888; m_reverseAPIDeviceIndex = 0; m_reverseAPIChannelIndex = 0; + m_workspaceIndex = 0; + m_hidden = false; } QByteArray WFMModSettings::serialize() const @@ -101,6 +103,10 @@ QByteArray WFMModSettings::serialize() const s.writeBlob(22, m_rollupState->serialize()); } + s.writeS32(23, m_workspaceIndex); + s.writeBlob(24, m_geometryBytes); + s.writeBool(25, m_hidden); + return s.final(); } @@ -177,6 +183,10 @@ bool WFMModSettings::deserialize(const QByteArray& data) m_rollupState->deserialize(bytetmp); } + d.readS32(23, &m_workspaceIndex, 0); + d.readBlob(24, &m_geometryBytes); + d.readBool(25, &m_hidden, false); + return true; } else diff --git a/plugins/channeltx/modwfm/wfmmodsettings.h b/plugins/channeltx/modwfm/wfmmodsettings.h index 6d6dbb457..9d5edd10b 100644 --- a/plugins/channeltx/modwfm/wfmmodsettings.h +++ b/plugins/channeltx/modwfm/wfmmodsettings.h @@ -59,6 +59,9 @@ struct WFMModSettings uint16_t m_reverseAPIPort; uint16_t m_reverseAPIDeviceIndex; uint16_t m_reverseAPIChannelIndex; + int m_workspaceIndex; + QByteArray m_geometryBytes; + bool m_hidden; Serializable *m_channelMarker; Serializable *m_cwKeyerGUI; diff --git a/plugins/channeltx/remotesource/readme.md b/plugins/channeltx/remotesource/readme.md index 63b1a246d..ea86b51a8 100644 --- a/plugins/channeltx/remotesource/readme.md +++ b/plugins/channeltx/remotesource/readme.md @@ -10,6 +10,8 @@ The plugin will be built only if the [CM256cc library](https://github.com/f4exb/

Interface

+The top and bottom bars of the channel window are described [here](../../../sdrgui/channel/readme.md) + ![Remote source channel plugin GUI](../../../doc/img/RemoteSource.png)

1: Data local address

diff --git a/plugins/channeltx/remotesource/remotesource.cpp b/plugins/channeltx/remotesource/remotesource.cpp index 3512b7c35..35ef6f583 100644 --- a/plugins/channeltx/remotesource/remotesource.cpp +++ b/plugins/channeltx/remotesource/remotesource.cpp @@ -24,6 +24,7 @@ #include #include "SWGChannelSettings.h" +#include "SWGWorkspaceInfo.h" #include "SWGChannelReport.h" #include "SWGRemoteSourceReport.h" @@ -42,7 +43,6 @@ MESSAGE_CLASS_DEFINITION(RemoteSource::MsgConfigureRemoteSource, Message) MESSAGE_CLASS_DEFINITION(RemoteSource::MsgQueryStreamData, Message) MESSAGE_CLASS_DEFINITION(RemoteSource::MsgReportStreamData, Message) -MESSAGE_CLASS_DEFINITION(RemoteSource::MsgBasebandSampleRateNotification, Message) const char* const RemoteSource::m_channelIdURI = "sdrangel.channeltx.remotesource"; const char* const RemoteSource::m_channelId ="RemoteSource"; @@ -89,6 +89,18 @@ RemoteSource::~RemoteSource() delete m_thread; } +void RemoteSource::setDeviceAPI(DeviceAPI *deviceAPI) +{ + if (deviceAPI != m_deviceAPI) + { + m_deviceAPI->removeChannelSourceAPI(this); + m_deviceAPI->removeChannelSource(this); + m_deviceAPI = deviceAPI; + m_deviceAPI->addChannelSource(this); + m_deviceAPI->addChannelSinkAPI(this); + } +} + void RemoteSource::start() { qDebug("RemoteSource::start"); @@ -124,10 +136,8 @@ bool RemoteSource::handleMessage(const Message& cmd) calculateFrequencyOffset(m_settings.m_log2Interp, m_settings.m_filterChainHash); // This is when device sample rate changes m_centerFrequency = notif.getCenterFrequency(); - if (m_guiMessageQueue) - { - MsgBasebandSampleRateNotification *msg = MsgBasebandSampleRateNotification::create(notif.getSampleRate()); - m_guiMessageQueue->push(msg); + if (m_guiMessageQueue) { + m_guiMessageQueue->push(new DSPSignalNotification(notif)); } return true; @@ -291,6 +301,15 @@ int RemoteSource::webapiSettingsGet( return 200; } +int RemoteSource::webapiWorkspaceGet( + SWGSDRangel::SWGWorkspaceInfo& response, + QString& errorMessage) +{ + (void) errorMessage; + response.setIndex(m_settings.m_workspaceIndex); + return 200; +} + int RemoteSource::webapiSettingsPutPatch( bool force, const QStringList& channelSettingsKeys, diff --git a/plugins/channeltx/remotesource/remotesource.h b/plugins/channeltx/remotesource/remotesource.h index b86a7ca21..0ada09b3c 100644 --- a/plugins/channeltx/remotesource/remotesource.h +++ b/plugins/channeltx/remotesource/remotesource.h @@ -153,31 +153,11 @@ public: { } }; - - class MsgBasebandSampleRateNotification : public Message { - MESSAGE_CLASS_DECLARATION - - public: - static MsgBasebandSampleRateNotification* create(int sampleRate) { - return new MsgBasebandSampleRateNotification(sampleRate); - } - - int getBasebandSampleRate() const { return m_sampleRate; } - - private: - - MsgBasebandSampleRateNotification(int sampleRate) : - Message(), - m_sampleRate(sampleRate) - { } - - int m_sampleRate; - }; - RemoteSource(DeviceAPI *deviceAPI); virtual ~RemoteSource(); - virtual void destroy() { delete this; } + virtual void setDeviceAPI(DeviceAPI *deviceAPI); + virtual DeviceAPI *getDeviceAPI() { return m_deviceAPI; } virtual void start(); virtual void stop(); @@ -208,6 +188,10 @@ public: SWGSDRangel::SWGChannelSettings& response, QString& errorMessage); + virtual int webapiWorkspaceGet( + SWGSDRangel::SWGWorkspaceInfo& response, + QString& errorMessage); + virtual int webapiSettingsPutPatch( bool force, const QStringList& channelSettingsKeys, diff --git a/plugins/channeltx/remotesource/remotesourcegui.cpp b/plugins/channeltx/remotesource/remotesourcegui.cpp index 998d2110f..5ae264408 100644 --- a/plugins/channeltx/remotesource/remotesourcegui.cpp +++ b/plugins/channeltx/remotesource/remotesourcegui.cpp @@ -16,10 +16,12 @@ /////////////////////////////////////////////////////////////////////////////////// #include +#include #include "device/deviceapi.h" #include "device/deviceuiset.h" #include "dsp/hbfilterchainconverter.h" +#include "dsp/dspcommands.h" #include "gui/basicchannelsettingsdialog.h" #include "gui/devicestreamselectiondialog.h" #include "mainwindow.h" @@ -64,12 +66,22 @@ bool RemoteSourceGUI::deserialize(const QByteArray& data) } } +void RemoteSourceGUI::resizeEvent(QResizeEvent* size) +{ + int maxWidth = getRollupContents()->maximumWidth(); + int minHeight = getRollupContents()->minimumHeight() + getAdditionalHeight(); + resize(width() < maxWidth ? width() : maxWidth, minHeight); + size->accept(); +} + bool RemoteSourceGUI::handleMessage(const Message& message) { - if (RemoteSource::MsgBasebandSampleRateNotification::match(message)) + if (DSPSignalNotification::match(message)) { - RemoteSource::MsgBasebandSampleRateNotification& notif = (RemoteSource::MsgBasebandSampleRateNotification&) message; - m_basebandSampleRate = notif.getBasebandSampleRate(); + DSPSignalNotification& notif = (DSPSignalNotification&) message; + m_deviceCenterFrequency = notif.getCenterFrequency(); + m_basebandSampleRate = notif.getSampleRate(); + updateAbsoluteCenterFrequency(); displayRateAndShift(); return true; } @@ -156,6 +168,7 @@ RemoteSourceGUI::RemoteSourceGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, ui(new Ui::RemoteSourceGUI), m_pluginAPI(pluginAPI), m_deviceUISet(deviceUISet), + m_deviceCenterFrequency(0), m_remoteSampleRate(48000), m_basebandSampleRate(48000), m_shiftFrequencyFactor(0.0), @@ -168,11 +181,13 @@ RemoteSourceGUI::RemoteSourceGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, m_resetCounts(true), m_tickCount(0) { - (void) channelTx; - ui->setupUi(this); - m_helpURL = "plugins/channeltx/remotesource/readme.md"; setAttribute(Qt::WA_DeleteOnClose, true); - connect(this, SIGNAL(widgetRolled(QWidget*,bool)), this, SLOT(onWidgetRolled(QWidget*,bool))); + m_helpURL = "plugins/channeltx/remotesource/readme.md"; + RollupContents *rollupContents = getRollupContents(); + ui->setupUi(rollupContents); + setSizePolicy(rollupContents->sizePolicy()); + rollupContents->arrangeRollups(); + connect(rollupContents, SIGNAL(widgetRolled(QWidget*,bool)), this, SLOT(onWidgetRolled(QWidget*,bool))); connect(this, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(onMenuDialogCalled(const QPoint &))); m_remoteSrc = (RemoteSource*) channelTx; @@ -192,7 +207,6 @@ RemoteSourceGUI::RemoteSourceGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, m_settings.setRollupState(&m_rollupState); m_deviceUISet->addChannelMarker(&m_channelMarker); - m_deviceUISet->addRollupWidget(this); connect(&m_channelMarker, SIGNAL(changedByCursor()), this, SLOT(channelMarkerChangedByCursor())); connect(getInputMessageQueue(), SIGNAL(messageEnqueued()), this, SLOT(handleSourceMessages())); @@ -200,6 +214,7 @@ RemoteSourceGUI::RemoteSourceGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, m_time.start(); displaySettings(); + makeUIConnections(); displayPosition(); displayRateAndShift(); applySettings(true); @@ -237,12 +252,14 @@ void RemoteSourceGUI::displaySettings() setTitleColor(m_settings.m_rgbColor); setWindowTitle(m_channelMarker.getTitle()); - displayStreamIndex(); + setTitle(m_channelMarker.getTitle()); + updateIndexLabel(); blockApplySettings(true); ui->dataAddress->setText(m_settings.m_dataAddress); ui->dataPort->setText(tr("%1").arg(m_settings.m_dataPort)); - restoreState(m_rollupState); + getRollupContents()->restoreState(m_rollupState); + updateAbsoluteCenterFrequency(); blockApplySettings(false); } @@ -265,23 +282,16 @@ void RemoteSourceGUI::displayPosition() ui->filterChainText->setText(s); } -void RemoteSourceGUI::displayStreamIndex() -{ - if (m_deviceUISet->m_deviceMIMOEngine) { - setStreamIndicator(tr("%1").arg(m_settings.m_streamIndex)); - } else { - setStreamIndicator("S"); // single channel indicator - } -} - -void RemoteSourceGUI::leaveEvent(QEvent*) +void RemoteSourceGUI::leaveEvent(QEvent* event) { m_channelMarker.setHighlighted(false); + ChannelGUI::leaveEvent(event); } -void RemoteSourceGUI::enterEvent(QEvent*) +void RemoteSourceGUI::enterEvent(QEvent* event) { m_channelMarker.setHighlighted(true); + ChannelGUI::enterEvent(event); } void RemoteSourceGUI::handleSourceMessages() @@ -302,7 +312,7 @@ void RemoteSourceGUI::onWidgetRolled(QWidget* widget, bool rollDown) (void) widget; (void) rollDown; - saveState(m_rollupState); + getRollupContents()->saveState(m_rollupState); applySettings(); } @@ -316,6 +326,13 @@ void RemoteSourceGUI::onMenuDialogCalled(const QPoint &p) dialog.setReverseAPIPort(m_settings.m_reverseAPIPort); dialog.setReverseAPIDeviceIndex(m_settings.m_reverseAPIDeviceIndex); dialog.setReverseAPIChannelIndex(m_settings.m_reverseAPIChannelIndex); + dialog.setDefaultTitle(m_displayedName); + + if (m_deviceUISet->m_deviceMIMOEngine) + { + dialog.setNumberOfStreams(m_remoteSrc->getNumberOfDeviceStreams()); + dialog.setStreamIndex(m_settings.m_streamIndex); + } dialog.move(p); dialog.exec(); @@ -329,22 +346,17 @@ void RemoteSourceGUI::onMenuDialogCalled(const QPoint &p) m_settings.m_reverseAPIChannelIndex = dialog.getReverseAPIChannelIndex(); setWindowTitle(m_settings.m_title); + setTitle(m_channelMarker.getTitle()); setTitleColor(m_settings.m_rgbColor); - applySettings(); - } - else if ((m_contextMenuType == ContextMenuStreamSettings) && (m_deviceUISet->m_deviceMIMOEngine)) - { - DeviceStreamSelectionDialog dialog(this); - dialog.setNumberOfStreams(m_remoteSrc->getNumberOfDeviceStreams()); - dialog.setStreamIndex(m_settings.m_streamIndex); - dialog.move(p); - dialog.exec(); + if (m_deviceUISet->m_deviceMIMOEngine) + { + m_settings.m_streamIndex = dialog.getSelectedStreamIndex(); + m_channelMarker.clearStreamIndexes(); + m_channelMarker.addStreamIndex(m_settings.m_streamIndex); + updateIndexLabel(); + } - m_settings.m_streamIndex = dialog.getSelectedStreamIndex(); - m_channelMarker.clearStreamIndexes(); - m_channelMarker.addStreamIndex(m_settings.m_streamIndex); - displayStreamIndex(); applySettings(); } @@ -429,6 +441,7 @@ void RemoteSourceGUI::applyPosition() m_shiftFrequencyFactor = HBFilterChainConverter::convertToString(m_settings.m_log2Interp, m_settings.m_filterChainHash, s); ui->filterChainText->setText(s); + updateAbsoluteCenterFrequency(); displayRateAndShift(); applySettings(); } @@ -483,3 +496,20 @@ void RemoteSourceGUI::tick() void RemoteSourceGUI::channelMarkerChangedByCursor() { } + +void RemoteSourceGUI::makeUIConnections() +{ + QObject::connect(ui->interpolationFactor, QOverload::of(&QComboBox::currentIndexChanged), this, &RemoteSourceGUI::on_interpolationFactor_currentIndexChanged); + QObject::connect(ui->position, &QSlider::valueChanged, this, &RemoteSourceGUI::on_position_valueChanged); + QObject::connect(ui->dataAddress, &QLineEdit::returnPressed, this, &RemoteSourceGUI::on_dataAddress_returnPressed); + QObject::connect(ui->dataPort, &QLineEdit::returnPressed, this, &RemoteSourceGUI::on_dataPort_returnPressed); + QObject::connect(ui->dataApplyButton, &QPushButton::clicked, this, &RemoteSourceGUI::on_dataApplyButton_clicked); + QObject::connect(ui->eventCountsReset, &QPushButton::clicked, this, &RemoteSourceGUI::on_eventCountsReset_clicked); +} + +void RemoteSourceGUI::updateAbsoluteCenterFrequency() +{ + int shift = m_shiftFrequencyFactor * m_basebandSampleRate; + setStatusFrequency(m_deviceCenterFrequency + shift); +} + diff --git a/plugins/channeltx/remotesource/remotesourcegui.h b/plugins/channeltx/remotesource/remotesourcegui.h index daca3cd25..09c410ad3 100644 --- a/plugins/channeltx/remotesource/remotesourcegui.h +++ b/plugins/channeltx/remotesource/remotesourcegui.h @@ -47,10 +47,24 @@ public: QByteArray serialize() const; bool deserialize(const QByteArray& data); virtual MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; } + virtual void setWorkspaceIndex(int index) { m_settings.m_workspaceIndex = index; }; + virtual int getWorkspaceIndex() const { return m_settings.m_workspaceIndex; }; + virtual void setGeometryBytes(const QByteArray& blob) { m_settings.m_geometryBytes = blob; }; + virtual QByteArray getGeometryBytes() const { return m_settings.m_geometryBytes; }; + virtual QString getTitle() const { return m_settings.m_title; }; + virtual QColor getTitleColor() const { return m_settings.m_rgbColor; }; + virtual void zetHidden(bool hidden) { m_settings.m_hidden = hidden; } + virtual bool getHidden() const { return m_settings.m_hidden; } + virtual ChannelMarker& getChannelMarker() { return m_channelMarker; } + virtual int getStreamIndex() const { return m_settings.m_streamIndex; } + virtual void setStreamIndex(int streamIndex) { m_settings.m_streamIndex = streamIndex; } public slots: void channelMarkerChangedByCursor(); +protected: + void resizeEvent(QResizeEvent* size); + private: Ui::RemoteSourceGUI* ui; PluginAPI* m_pluginAPI; @@ -58,6 +72,7 @@ private: ChannelMarker m_channelMarker; RollupState m_rollupState; RemoteSourceSettings m_settings; + qint64 m_deviceCenterFrequency; int m_remoteSampleRate; int m_basebandSampleRate; bool m_doApplySettings; @@ -84,8 +99,9 @@ private: void displaySettings(); void displayRateAndShift(); void displayPosition(); - void displayStreamIndex(); bool handleMessage(const Message& message); + void makeUIConnections(); + void updateAbsoluteCenterFrequency(); void leaveEvent(QEvent*); void enterEvent(QEvent*); diff --git a/plugins/channeltx/remotesource/remotesourcegui.ui b/plugins/channeltx/remotesource/remotesourcegui.ui index 81d1463f1..a246d4290 100644 --- a/plugins/channeltx/remotesource/remotesourcegui.ui +++ b/plugins/channeltx/remotesource/remotesourcegui.ui @@ -1,7 +1,7 @@ RemoteSourceGUI - + 0 @@ -11,7 +11,7 @@ - + 0 0 @@ -24,7 +24,7 @@ - 320 + 560 16777215 @@ -40,8 +40,8 @@ - 10 - 10 + 0 + 0 301 191 @@ -571,27 +571,14 @@
- - - - Qt::Vertical - - - - 20 - 40 - - - -
- RollupWidget + RollupContents QWidget -
gui/rollupwidget.h
+
gui/rollupcontents.h
1
diff --git a/plugins/channeltx/remotesource/remotesourcesettings.cpp b/plugins/channeltx/remotesource/remotesourcesettings.cpp index d0fcbfe21..77124000b 100644 --- a/plugins/channeltx/remotesource/remotesourcesettings.cpp +++ b/plugins/channeltx/remotesource/remotesourcesettings.cpp @@ -44,6 +44,8 @@ void RemoteSourceSettings::resetToDefaults() m_reverseAPIPort = 8888; m_reverseAPIDeviceIndex = 0; m_reverseAPIChannelIndex = 0; + m_workspaceIndex = 0; + m_hidden = false; } QByteArray RemoteSourceSettings::serialize() const @@ -71,6 +73,10 @@ QByteArray RemoteSourceSettings::serialize() const s.writeBlob(14, m_channelMarker->serialize()); } + s.writeS32(15, m_workspaceIndex); + s.writeBlob(16, m_geometryBytes); + s.writeBool(17, m_hidden); + return s.final(); } @@ -132,6 +138,10 @@ bool RemoteSourceSettings::deserialize(const QByteArray& data) m_channelMarker->deserialize(bytetmp); } + d.readS32(15, &m_workspaceIndex, 0); + d.readBlob(16, &m_geometryBytes); + d.readBool(17, &m_hidden, false); + return true; } else diff --git a/plugins/channeltx/remotesource/remotesourcesettings.h b/plugins/channeltx/remotesource/remotesourcesettings.h index aff6a0426..a58039ad2 100644 --- a/plugins/channeltx/remotesource/remotesourcesettings.h +++ b/plugins/channeltx/remotesource/remotesourcesettings.h @@ -37,6 +37,9 @@ struct RemoteSourceSettings uint16_t m_reverseAPIPort; uint16_t m_reverseAPIDeviceIndex; uint16_t m_reverseAPIChannelIndex; + int m_workspaceIndex; + QByteArray m_geometryBytes; + bool m_hidden; Serializable *m_channelMarker; Serializable *m_rollupState; diff --git a/plugins/channeltx/udpsource/readme.md b/plugins/channeltx/udpsource/readme.md index 5dbcaedc3..9bb601d2c 100644 --- a/plugins/channeltx/udpsource/readme.md +++ b/plugins/channeltx/udpsource/readme.md @@ -10,6 +10,8 @@ This plugin is available for Linux and Mac O/S only.

Interface

+The top and bottom bars of the channel window are described [here](../../../sdrgui/channel/readme.md) + ![UDP Source plugin GUI](../../../doc/img/UDPsource_plugin.png)

1: Frequency shift from center frequency of reception

@@ -30,7 +32,7 @@ Use this button to switch off the RF on the channel. The background of the butto

5: UDP address and port

-Enter the network interface address and listening port. The display is in the format `address:data port` +Enter the network interface address and listening port. The display is in the format `address:data port`

6: Join multicast group

@@ -57,7 +59,7 @@ Combo box to specify the type of samples that are received and sent in the chann

10: Mono/Stereo input

This toggles switches between 1 channel (mono) and 2 channels (stereo) input samples format. - +

11: Output signal bandwidth

The signal is bandpass filtered to this bandwidth (zero frequency centered) before being sent out in the channel. In SSB modes only half of the filter is used (LSB: lower, USB: upper). Thus to send a signal with 3000 Hz bandwidth a bandwidth of 6000 Hz must be selected. In addition in SSB modes a 300 Hz highpass filter is applied. @@ -72,9 +74,9 @@ this is the AM percentage modulation when a +/- 1.0 amplitude modulating signal

14: Squelch

-The slider sets the squelch power threshold based on channel input power (2). At the right of the slider the value in dB is displayed. +The slider sets the squelch power threshold based on channel input power (2). At the right of the slider the value in dB is displayed. -The button sets the delay after which a signal constantly above the squelch threshold effectively opens the squelch. The same delay is used for squelch release. The delay in milliseconds is displayed at the right of the button. +The button sets the delay after which a signal constantly above the squelch threshold effectively opens the squelch. The same delay is used for squelch release. The delay in milliseconds is displayed at the right of the button.

15: Input and output Gains

@@ -94,7 +96,7 @@ This gauge shows the percentage of deviation from a R/W pointer distance of half There is an automatic correction to try to maintain the half buffer distance between read and write pointers. This adjust the sample rate and therefore some wiggling around the nominal sample rate can occur. This should be hardly noticeable for most modulations but can be problematic with very narrowband modulations like WSPR. -The buffer consists in 512 bytes frames so that a normalized UDP block can be placed in one frame. Half the number of frames is calculated as the sample rate divided by 375. This results in a fixed average delay 0f 341 ms for sample rates of 48 kS/s and above. +The buffer consists in 512 bytes frames so that a normalized UDP block can be placed in one frame. Half the number of frames is calculated as the sample rate divided by 375. This results in a fixed average delay 0f 341 ms for sample rates of 48 kS/s and above.

18: Reset input buffer R/W pointers

@@ -117,10 +119,10 @@ The changes in the following items only become effective when this button is pre - FM deviation (12) - AM percentage (13) -When any item of these items is changed the button is lit in green until it is pressed. +When any item of these items is changed the button is lit in green until it is pressed.

21: Spectrum display

-This is the spectrum display of the channel signal before filtering. Please refer to the Spectrum display description for details. +This is the spectrum display of the channel signal before filtering. Details on the spectrum view and controls can be found [here](../../../sdrgui/gui/spectrum.md) -This spectrum is centered on the center frequency of the channel (center frequency of reception + channel shift) and is that of a complex signal i.e. there are positive and negative frequencies. The width of the spectrum is proportional of the sample rate. That is for a sample rate of S samples per seconds the spectrum spans from -S/2 to +S/2 Hz. +This spectrum is centered on the center frequency of the channel (center frequency of reception + channel shift) and is that of a complex signal i.e. there are positive and negative frequencies. The width of the spectrum is proportional of the sample rate. That is for a sample rate of S samples per seconds the spectrum spans from -S/2 to +S/2 Hz. diff --git a/plugins/channeltx/udpsource/udpsource.cpp b/plugins/channeltx/udpsource/udpsource.cpp index f455801c4..9068c6526 100644 --- a/plugins/channeltx/udpsource/udpsource.cpp +++ b/plugins/channeltx/udpsource/udpsource.cpp @@ -22,6 +22,7 @@ #include #include "SWGChannelSettings.h" +#include "SWGWorkspaceInfo.h" #include "SWGChannelReport.h" #include "SWGUDPSourceReport.h" @@ -82,6 +83,18 @@ UDPSource::~UDPSource() delete m_thread; } +void UDPSource::setDeviceAPI(DeviceAPI *deviceAPI) +{ + if (deviceAPI != m_deviceAPI) + { + m_deviceAPI->removeChannelSourceAPI(this); + m_deviceAPI->removeChannelSource(this); + m_deviceAPI = deviceAPI; + m_deviceAPI->addChannelSource(this); + m_deviceAPI->addChannelSinkAPI(this); + } +} + void UDPSource::start() { qDebug("UDPSource::start"); @@ -145,6 +158,10 @@ bool UDPSource::handleMessage(const Message& cmd) DSPSignalNotification* rep = new DSPSignalNotification(notif); // make a copy qDebug() << "UDPSource::handleMessage: DSPSignalNotification"; m_basebandSource->getInputMessageQueue()->push(rep); + // Forward to GUI if any + if (getMessageQueueToGUI()) { + getMessageQueueToGUI()->push(new DSPSignalNotification(notif)); + } return true; } @@ -324,6 +341,15 @@ int UDPSource::webapiSettingsGet( return 200; } +int UDPSource::webapiWorkspaceGet( + SWGSDRangel::SWGWorkspaceInfo& response, + QString& errorMessage) +{ + (void) errorMessage; + response.setIndex(m_settings.m_workspaceIndex); + return 200; +} + int UDPSource::webapiSettingsPutPatch( bool force, const QStringList& channelSettingsKeys, diff --git a/plugins/channeltx/udpsource/udpsource.h b/plugins/channeltx/udpsource/udpsource.h index 4d9cb6297..6bab5cd1e 100644 --- a/plugins/channeltx/udpsource/udpsource.h +++ b/plugins/channeltx/udpsource/udpsource.h @@ -95,6 +95,8 @@ public: UDPSource(DeviceAPI *deviceAPI); virtual ~UDPSource(); virtual void destroy() { delete this; } + virtual void setDeviceAPI(DeviceAPI *deviceAPI); + virtual DeviceAPI *getDeviceAPI() { return m_deviceAPI; } virtual void start(); virtual void stop(); @@ -125,6 +127,10 @@ public: SWGSDRangel::SWGChannelSettings& response, QString& errorMessage); + virtual int webapiWorkspaceGet( + SWGSDRangel::SWGWorkspaceInfo& response, + QString& errorMessage); + virtual int webapiSettingsPutPatch( bool force, const QStringList& channelSettingsKeys, diff --git a/plugins/channeltx/udpsource/udpsourcegui.cpp b/plugins/channeltx/udpsource/udpsourcegui.cpp index 905a8cd4c..0dd9c2533 100644 --- a/plugins/channeltx/udpsource/udpsourcegui.cpp +++ b/plugins/channeltx/udpsource/udpsourcegui.cpp @@ -20,6 +20,7 @@ #include "device/deviceuiset.h" #include "dsp/spectrumvis.h" #include "dsp/dspengine.h" +#include "dsp/dspcommands.h" #include "util/simpleserializer.h" #include "util/db.h" #include "gui/basicchannelsettingsdialog.h" @@ -78,6 +79,16 @@ bool UDPSourceGUI::handleMessage(const Message& message) blockApplySettings(false); return true; } + else if (DSPSignalNotification::match(message)) + { + const DSPSignalNotification& notif = (const DSPSignalNotification&) message; + m_deviceCenterFrequency = notif.getCenterFrequency(); + m_basebandSampleRate = notif.getSampleRate(); + ui->deltaFrequency->setValueRange(false, 8, -m_basebandSampleRate/2, m_basebandSampleRate/2); + ui->deltaFrequencyLabel->setToolTip(tr("Range %1 %L2 Hz").arg(QChar(0xB1)).arg(m_basebandSampleRate/2)); + updateAbsoluteCenterFrequency(); + return true; + } else { return false; @@ -104,14 +115,19 @@ UDPSourceGUI::UDPSourceGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, Baseb m_deviceUISet(deviceUISet), m_tickCount(0), m_channelMarker(this), + m_deviceCenterFrequency(0), + m_basebandSampleRate(1), m_rfBandwidthChanged(false), m_doApplySettings(true) { - ui->setupUi(this); - m_helpURL = "plugins/channeltx/udpsource/readme.md"; - connect(this, SIGNAL(widgetRolled(QWidget*,bool)), this, SLOT(onWidgetRolled(QWidget*,bool))); - connect(this, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(onMenuDialogCalled(const QPoint &))); setAttribute(Qt::WA_DeleteOnClose, true); + m_helpURL = "plugins/channeltx/udpsource/readme.md"; + RollupContents *rollupContents = getRollupContents(); + ui->setupUi(rollupContents); + setSizePolicy(rollupContents->sizePolicy()); + rollupContents->arrangeRollups(); + connect(rollupContents, SIGNAL(widgetRolled(QWidget*,bool)), this, SLOT(onWidgetRolled(QWidget*,bool))); + connect(this, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(onMenuDialogCalled(const QPoint &))); m_udpSource = (UDPSource*) channelTx; m_spectrumVis = m_udpSource->getSpectrumVis(); @@ -140,7 +156,6 @@ UDPSourceGUI::UDPSourceGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, Baseb m_channelMarker.setVisible(true); // activate signal on the last setting only m_deviceUISet->addChannelMarker(&m_channelMarker); - m_deviceUISet->addRollupWidget(this); connect(&m_channelMarker, SIGNAL(changedByCursor()), this, SLOT(channelMarkerChangedByCursor())); @@ -154,6 +169,7 @@ UDPSourceGUI::UDPSourceGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, Baseb m_settings.setRollupState(&m_rollupState); displaySettings(); + makeUIConnections(); applySettings(true); } @@ -193,8 +209,9 @@ void UDPSourceGUI::displaySettings() m_channelMarker.setColor(m_settings.m_rgbColor); setTitleColor(m_settings.m_rgbColor); - this->setWindowTitle(m_channelMarker.getTitle()); - displayStreamIndex(); + setWindowTitle(m_channelMarker.getTitle()); + setTitle(m_channelMarker.getTitle()); + updateIndexLabel(); blockApplySettings(true); @@ -236,19 +253,11 @@ void UDPSourceGUI::displaySettings() ui->applyBtn->setEnabled(false); ui->applyBtn->setStyleSheet("QPushButton { background:rgb(79,79,79); }"); - restoreState(m_rollupState); + getRollupContents()->restoreState(m_rollupState); + updateAbsoluteCenterFrequency(); blockApplySettings(false); } -void UDPSourceGUI::displayStreamIndex() -{ - if (m_deviceUISet->m_deviceMIMOEngine) { - setStreamIndicator(tr("%1").arg(m_settings.m_streamIndex)); - } else { - setStreamIndicator("S"); // single channel indicator - } -} - void UDPSourceGUI::channelMarkerChangedByCursor() { ui->deltaFrequency->setValue(m_channelMarker.getCenterFrequency()); @@ -260,6 +269,7 @@ void UDPSourceGUI::on_deltaFrequency_changed(qint64 value) { m_settings.m_inputFrequencyOffset = value; m_channelMarker.setCenterFrequency(value); + updateAbsoluteCenterFrequency(); applySettings(); } @@ -472,7 +482,18 @@ void UDPSourceGUI::onWidgetRolled(QWidget* widget, bool rollDown) m_udpSource->setSpectrum(rollDown); } - saveState(m_rollupState); + RollupContents *rollupContents = getRollupContents(); + + if (rollupContents->hasExpandableWidgets()) { + setSizePolicy(sizePolicy().horizontalPolicy(), QSizePolicy::Expanding); + } else { + setSizePolicy(sizePolicy().horizontalPolicy(), QSizePolicy::Fixed); + } + + int h = rollupContents->height() + getAdditionalHeight(); + resize(width(), h); + + rollupContents->saveState(m_rollupState); applySettings(); } @@ -486,11 +507,17 @@ void UDPSourceGUI::onMenuDialogCalled(const QPoint &p) dialog.setReverseAPIPort(m_settings.m_reverseAPIPort); dialog.setReverseAPIDeviceIndex(m_settings.m_reverseAPIDeviceIndex); dialog.setReverseAPIChannelIndex(m_settings.m_reverseAPIChannelIndex); + dialog.setDefaultTitle(m_displayedName); + + if (m_deviceUISet->m_deviceMIMOEngine) + { + dialog.setNumberOfStreams(m_udpSource->getNumberOfDeviceStreams()); + dialog.setStreamIndex(m_settings.m_streamIndex); + } dialog.move(p); dialog.exec(); - m_settings.m_inputFrequencyOffset = m_channelMarker.getCenterFrequency(); m_settings.m_rgbColor = m_channelMarker.getColor().rgb(); m_settings.m_useReverseAPI = dialog.useReverseAPI(); m_settings.m_reverseAPIAddress = dialog.getReverseAPIAddress(); @@ -499,36 +526,33 @@ void UDPSourceGUI::onMenuDialogCalled(const QPoint &p) m_settings.m_reverseAPIChannelIndex = dialog.getReverseAPIChannelIndex(); setWindowTitle(m_channelMarker.getTitle()); + setTitle(m_channelMarker.getTitle()); setTitleColor(m_settings.m_rgbColor); - applySettings(); - } - else if ((m_contextMenuType == ContextMenuStreamSettings) && (m_deviceUISet->m_deviceMIMOEngine)) - { - DeviceStreamSelectionDialog dialog(this); - dialog.setNumberOfStreams(m_udpSource->getNumberOfDeviceStreams()); - dialog.setStreamIndex(m_settings.m_streamIndex); - dialog.move(p); - dialog.exec(); + if (m_deviceUISet->m_deviceMIMOEngine) + { + m_settings.m_streamIndex = dialog.getSelectedStreamIndex(); + m_channelMarker.clearStreamIndexes(); + m_channelMarker.addStreamIndex(m_settings.m_streamIndex); + updateIndexLabel(); + } - m_settings.m_streamIndex = dialog.getSelectedStreamIndex(); - m_channelMarker.clearStreamIndexes(); - m_channelMarker.addStreamIndex(m_settings.m_streamIndex); - displayStreamIndex(); applySettings(); } resetContextMenuType(); } -void UDPSourceGUI::leaveEvent(QEvent*) +void UDPSourceGUI::leaveEvent(QEvent* event) { m_channelMarker.setHighlighted(false); + ChannelGUI::leaveEvent(event); } -void UDPSourceGUI::enterEvent(QEvent*) +void UDPSourceGUI::enterEvent(QEvent* event) { m_channelMarker.setHighlighted(true); + ChannelGUI::enterEvent(event); } void UDPSourceGUI::tick() @@ -637,3 +661,30 @@ void UDPSourceGUI::setSampleFormat(int index) } } +void UDPSourceGUI::makeUIConnections() +{ + QObject::connect(ui->deltaFrequency, &ValueDialZ::changed, this, &UDPSourceGUI::on_deltaFrequency_changed); + QObject::connect(ui->sampleFormat, QOverload::of(&QComboBox::currentIndexChanged), this, &UDPSourceGUI::on_sampleFormat_currentIndexChanged); + QObject::connect(ui->localUDPAddress, &QLineEdit::editingFinished, this, &UDPSourceGUI::on_localUDPAddress_editingFinished); + QObject::connect(ui->localUDPPort, &QLineEdit::editingFinished, this, &UDPSourceGUI::on_localUDPPort_editingFinished); + QObject::connect(ui->multicastAddress, &QLineEdit::editingFinished, this, &UDPSourceGUI::on_multicastAddress_editingFinished); + QObject::connect(ui->multicastJoin, &ButtonSwitch::toggled, this, &UDPSourceGUI::on_multicastJoin_toggled); + QObject::connect(ui->sampleRate, &QLineEdit::textEdited, this, &UDPSourceGUI::on_sampleRate_textEdited); + QObject::connect(ui->rfBandwidth, &QLineEdit::textEdited, this, &UDPSourceGUI::on_rfBandwidth_textEdited); + QObject::connect(ui->fmDeviation, &QLineEdit::textEdited, this, &UDPSourceGUI::on_fmDeviation_textEdited); + QObject::connect(ui->amModPercent, &QLineEdit::textEdited, this, &UDPSourceGUI::on_amModPercent_textEdited); + QObject::connect(ui->applyBtn, &QPushButton::clicked, this, &UDPSourceGUI::on_applyBtn_clicked); + QObject::connect(ui->gainIn, &QDial::valueChanged, this, &UDPSourceGUI::on_gainIn_valueChanged); + QObject::connect(ui->gainOut, &QDial::valueChanged, this, &UDPSourceGUI::on_gainOut_valueChanged); + QObject::connect(ui->squelch, &QSlider::valueChanged, this, &UDPSourceGUI::on_squelch_valueChanged); + QObject::connect(ui->squelchGate, &QDial::valueChanged, this, &UDPSourceGUI::on_squelchGate_valueChanged); + QObject::connect(ui->channelMute, &QToolButton::toggled, this, &UDPSourceGUI::on_channelMute_toggled); + QObject::connect(ui->resetUDPReadIndex, &QPushButton::clicked, this, &UDPSourceGUI::on_resetUDPReadIndex_clicked); + QObject::connect(ui->autoRWBalance, &ButtonSwitch::toggled, this, &UDPSourceGUI::on_autoRWBalance_toggled); + QObject::connect(ui->stereoInput, &QToolButton::toggled, this, &UDPSourceGUI::on_stereoInput_toggled); +} + +void UDPSourceGUI::updateAbsoluteCenterFrequency() +{ + setStatusFrequency(m_deviceCenterFrequency + m_settings.m_inputFrequencyOffset); +} diff --git a/plugins/channeltx/udpsource/udpsourcegui.h b/plugins/channeltx/udpsource/udpsourcegui.h index d20614aa5..68afee72d 100644 --- a/plugins/channeltx/udpsource/udpsourcegui.h +++ b/plugins/channeltx/udpsource/udpsourcegui.h @@ -49,6 +49,17 @@ public: virtual QByteArray serialize() const; virtual bool deserialize(const QByteArray& data); virtual MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; } + virtual void setWorkspaceIndex(int index) { m_settings.m_workspaceIndex = index; }; + virtual int getWorkspaceIndex() const { return m_settings.m_workspaceIndex; }; + virtual void setGeometryBytes(const QByteArray& blob) { m_settings.m_geometryBytes = blob; }; + virtual QByteArray getGeometryBytes() const { return m_settings.m_geometryBytes; }; + virtual QString getTitle() const { return m_settings.m_title; }; + virtual QColor getTitleColor() const { return m_settings.m_rgbColor; }; + virtual void zetHidden(bool hidden) { m_settings.m_hidden = hidden; } + virtual bool getHidden() const { return m_settings.m_hidden; } + virtual ChannelMarker& getChannelMarker() { return m_channelMarker; } + virtual int getStreamIndex() const { return m_settings.m_streamIndex; } + virtual void setStreamIndex(int streamIndex) { m_settings.m_streamIndex = streamIndex; } public slots: void channelMarkerChangedByCursor(); @@ -67,6 +78,8 @@ private: // settings UDPSourceSettings m_settings; + qint64 m_deviceCenterFrequency; + int m_basebandSampleRate; bool m_rfBandwidthChanged; bool m_doApplySettings; MessageQueue m_inputMessageQueue; @@ -77,10 +90,11 @@ private: void blockApplySettings(bool block); void applySettings(bool force = false); void displaySettings(); - void displayStreamIndex(); void setSampleFormat(int index); void setSampleFormatIndex(const UDPSourceSettings::SampleFormat& sampleFormat); bool handleMessage(const Message& message); + void makeUIConnections(); + void updateAbsoluteCenterFrequency(); void leaveEvent(QEvent*); void enterEvent(QEvent*); diff --git a/plugins/channeltx/udpsource/udpsourcegui.ui b/plugins/channeltx/udpsource/udpsourcegui.ui index 95764c265..90cccc5ef 100644 --- a/plugins/channeltx/udpsource/udpsourcegui.ui +++ b/plugins/channeltx/udpsource/udpsourcegui.ui @@ -1,27 +1,27 @@ UDPSourceGUI - + 0 0 - 395 - 403 + 420 + 400 + + + 0 + 0 + + - 395 + 420 0 - - - 400 - 16777215 - - Liberation Sans @@ -39,13 +39,13 @@ 2 2 - 390 + 412 221 - 390 + 412 0 @@ -190,6 +190,15 @@ + + + + 26 + 26 + 26 + + + @@ -210,6 +219,15 @@ + + + + 26 + 26 + 26 + + + @@ -230,11 +248,21 @@ + + + + 26 + 26 + 26 + + + + Liberation Sans 8 @@ -1003,6 +1031,12 @@ 156 + + + 0 + 0 + + Channel Spectrum @@ -1024,6 +1058,12 @@ + + + 0 + 0 + + Liberation Mono @@ -1040,9 +1080,9 @@ - RollupWidget + RollupContents QWidget -
gui/rollupwidget.h
+
gui/rollupcontents.h
1
@@ -1063,17 +1103,17 @@
gui/valuedialz.h
1
+ + ButtonSwitch + QToolButton +
gui/buttonswitch.h
+
LevelMeterVU QWidget
gui/levelmeter.h
1
- - ButtonSwitch - QToolButton -
gui/buttonswitch.h
-
diff --git a/plugins/channeltx/udpsource/udpsourcesettings.cpp b/plugins/channeltx/udpsource/udpsourcesettings.cpp index 5254a3e0d..346cb996c 100644 --- a/plugins/channeltx/udpsource/udpsourcesettings.cpp +++ b/plugins/channeltx/udpsource/udpsourcesettings.cpp @@ -60,6 +60,8 @@ void UDPSourceSettings::resetToDefaults() m_reverseAPIPort = 8888; m_reverseAPIDeviceIndex = 0; m_reverseAPIChannelIndex = 0; + m_workspaceIndex = 0; + m_hidden = false; } QByteArray UDPSourceSettings::serialize() const @@ -102,6 +104,10 @@ QByteArray UDPSourceSettings::serialize() const s.writeBlob(27, m_rollupState->serialize()); } + s.writeS32(28, m_workspaceIndex); + s.writeBlob(29, m_geometryBytes); + s.writeBool(30, m_hidden); + return s.final(); } @@ -195,6 +201,10 @@ bool UDPSourceSettings::deserialize(const QByteArray& data) m_rollupState->deserialize(bytetmp); } + d.readS32(28, &m_workspaceIndex, 0); + d.readBlob(29, &m_geometryBytes); + d.readBool(30, &m_hidden, false); + return true; } else diff --git a/plugins/channeltx/udpsource/udpsourcesettings.h b/plugins/channeltx/udpsource/udpsourcesettings.h index e971db7ad..3aa3b5429 100644 --- a/plugins/channeltx/udpsource/udpsourcesettings.h +++ b/plugins/channeltx/udpsource/udpsourcesettings.h @@ -67,6 +67,9 @@ struct UDPSourceSettings uint16_t m_reverseAPIPort; uint16_t m_reverseAPIDeviceIndex; uint16_t m_reverseAPIChannelIndex; + int m_workspaceIndex; + QByteArray m_geometryBytes; + bool m_hidden; Serializable *m_channelMarker; Serializable *m_spectrumGUI; diff --git a/plugins/feature/afc/afcgui.cpp b/plugins/feature/afc/afcgui.cpp index cb2acc19f..6d8a1b0de 100644 --- a/plugins/feature/afc/afcgui.cpp +++ b/plugins/feature/afc/afcgui.cpp @@ -16,6 +16,7 @@ /////////////////////////////////////////////////////////////////////////////////// #include +#include #include "feature/featureuiset.h" #include "device/deviceset.h" @@ -54,6 +55,7 @@ bool AFCGUI::deserialize(const QByteArray& data) { if (m_settings.deserialize(data)) { + m_feature->setWorkspaceIndex(m_settings.m_workspaceIndex); displaySettings(); applySettings(true); return true; @@ -65,6 +67,14 @@ bool AFCGUI::deserialize(const QByteArray& data) } } +void AFCGUI::resizeEvent(QResizeEvent* size) +{ + int maxWidth = getRollupContents()->maximumWidth(); + int minHeight = getRollupContents()->minimumHeight() + getAdditionalHeight(); + resize(width() < maxWidth ? width() : maxWidth, minHeight); + size->accept(); +} + bool AFCGUI::handleMessage(const Message& message) { if (AFC::MsgConfigureAFC::match(message)) @@ -118,7 +128,7 @@ void AFCGUI::onWidgetRolled(QWidget* widget, bool rollDown) (void) widget; (void) rollDown; - saveState(m_rollupState); + getRollupContents()->saveState(m_rollupState); applySettings(); } @@ -130,9 +140,14 @@ AFCGUI::AFCGUI(PluginAPI* pluginAPI, FeatureUISet *featureUISet, Feature *featur m_doApplySettings(true), m_lastFeatureState(0) { - ui->setupUi(this); - m_helpURL = "plugins/feature/afc/readme.md"; + m_feature = feature; setAttribute(Qt::WA_DeleteOnClose, true); + m_helpURL = "plugins/feature/afc/readme.md"; + RollupContents *rollupContents = getRollupContents(); + ui->setupUi(rollupContents); + setSizePolicy(rollupContents->sizePolicy()); + rollupContents->arrangeRollups(); + connect(rollupContents, SIGNAL(widgetRolled(QWidget*,bool)), this, SLOT(onWidgetRolled(QWidget*,bool))); ui->targetFrequency->setColorMapper(ColorMapper(ColorMapper::GrayGold)); ui->targetFrequency->setValueRange(10, 0, 9999999999L); @@ -140,13 +155,9 @@ AFCGUI::AFCGUI(PluginAPI* pluginAPI, FeatureUISet *featureUISet, Feature *featur ui->toleranceFrequency->setColorMapper(ColorMapper(ColorMapper::GrayYellow)); ui->toleranceFrequency->setValueRange(5, 0, 99999L); - setChannelWidget(false); - connect(this, SIGNAL(widgetRolled(QWidget*,bool)), this, SLOT(onWidgetRolled(QWidget*,bool))); m_afc = reinterpret_cast(feature); m_afc->setMessageQueueToGUI(&m_inputMessageQueue); - m_featureUISet->addRollupWidget(this); - connect(this, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(onMenuDialogCalled(const QPoint &))); connect(getInputMessageQueue(), SIGNAL(messageEnqueued()), this, SLOT(handleInputMessages())); @@ -162,6 +173,7 @@ AFCGUI::AFCGUI(PluginAPI* pluginAPI, FeatureUISet *featureUISet, Feature *featur requestDeviceSetLists(); displaySettings(); applySettings(true); + makeUIConnections(); } AFCGUI::~AFCGUI() @@ -169,6 +181,12 @@ AFCGUI::~AFCGUI() delete ui; } +void AFCGUI::setWorkspaceIndex(int index) +{ + m_settings.m_workspaceIndex = index; + m_feature->setWorkspaceIndex(index); +} + void AFCGUI::blockApplySettings(bool block) { m_doApplySettings = !block; @@ -178,6 +196,7 @@ void AFCGUI::displaySettings() { setTitleColor(m_settings.m_rgbColor); setWindowTitle(m_settings.m_title); + setTitle(m_settings.m_title); blockApplySettings(true); ui->hasTargetFrequency->setChecked(m_settings.m_hasTargetFrequency); ui->transverterTarget->setChecked(m_settings.m_transverterTarget); @@ -185,7 +204,7 @@ void AFCGUI::displaySettings() ui->toleranceFrequency->setValue(m_settings.m_freqTolerance); ui->targetPeriod->setValue(m_settings.m_trackerAdjustPeriod); ui->targetPeriodText->setText(tr("%1").arg(m_settings.m_trackerAdjustPeriod)); - restoreState(m_rollupState); + getRollupContents()->restoreState(m_rollupState); blockApplySettings(false); } @@ -255,31 +274,22 @@ void AFCGUI::updateDeviceSetLists(const AFC::MsgDeviceSetListsReport& report) ui->trackedDevice->blockSignals(false); } -void AFCGUI::leaveEvent(QEvent*) -{ -} - -void AFCGUI::enterEvent(QEvent*) -{ -} - void AFCGUI::onMenuDialogCalled(const QPoint &p) { if (m_contextMenuType == ContextMenuChannelSettings) { BasicFeatureSettingsDialog dialog(this); dialog.setTitle(m_settings.m_title); - dialog.setColor(m_settings.m_rgbColor); dialog.setUseReverseAPI(m_settings.m_useReverseAPI); dialog.setReverseAPIAddress(m_settings.m_reverseAPIAddress); dialog.setReverseAPIPort(m_settings.m_reverseAPIPort); dialog.setReverseAPIFeatureSetIndex(m_settings.m_reverseAPIFeatureSetIndex); dialog.setReverseAPIFeatureIndex(m_settings.m_reverseAPIFeatureIndex); + dialog.setDefaultTitle(m_displayedName); dialog.move(p); dialog.exec(); - m_settings.m_rgbColor = dialog.getColor().rgb(); m_settings.m_title = dialog.getTitle(); m_settings.m_useReverseAPI = dialog.useReverseAPI(); m_settings.m_reverseAPIAddress = dialog.getReverseAPIAddress(); @@ -287,7 +297,7 @@ void AFCGUI::onMenuDialogCalled(const QPoint &p) m_settings.m_reverseAPIFeatureSetIndex = dialog.getReverseAPIFeatureSetIndex(); m_settings.m_reverseAPIFeatureIndex = dialog.getReverseAPIFeatureIndex(); - setWindowTitle(m_settings.m_title); + setTitle(m_settings.m_title); setTitleColor(m_settings.m_rgbColor); applySettings(); @@ -414,3 +424,18 @@ void AFCGUI::applySettings(bool force) m_afc->getInputMessageQueue()->push(message); } } + +void AFCGUI::makeUIConnections() +{ + QObject::connect(ui->startStop, &ButtonSwitch::toggled, this, &AFCGUI::on_startStop_toggled); + QObject::connect(ui->hasTargetFrequency, &ButtonSwitch::toggled, this, &AFCGUI::on_hasTargetFrequency_toggled); + QObject::connect(ui->targetFrequency, &ValueDial::changed, this, &AFCGUI::on_targetFrequency_changed); + QObject::connect(ui->transverterTarget, &ButtonSwitch::toggled, this, &AFCGUI::on_transverterTarget_toggled); + QObject::connect(ui->toleranceFrequency, &ValueDial::changed, this, &AFCGUI::on_toleranceFrequency_changed); + QObject::connect(ui->deviceTrack, &QPushButton::clicked, this, &AFCGUI::on_deviceTrack_clicked); + QObject::connect(ui->devicesRefresh, &QPushButton::clicked, this, &AFCGUI::on_devicesRefresh_clicked); + QObject::connect(ui->trackerDevice, QOverload::of(&QComboBox::currentIndexChanged), this, &AFCGUI::on_trackerDevice_currentIndexChanged); + QObject::connect(ui->trackedDevice, QOverload::of(&QComboBox::currentIndexChanged), this, &AFCGUI::on_trackedDevice_currentIndexChanged); + QObject::connect(ui->devicesApply, &QPushButton::clicked, this, &AFCGUI::on_devicesApply_clicked); + QObject::connect(ui->targetPeriod, &QDial::valueChanged, this, &AFCGUI::on_targetPeriod_valueChanged); +} diff --git a/plugins/feature/afc/afcgui.h b/plugins/feature/afc/afcgui.h index 9f76e4333..fa210aa41 100644 --- a/plugins/feature/afc/afcgui.h +++ b/plugins/feature/afc/afcgui.h @@ -43,6 +43,13 @@ public: QByteArray serialize() const; bool deserialize(const QByteArray& data); virtual MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; } + virtual void setWorkspaceIndex(int index); + virtual int getWorkspaceIndex() const { return m_settings.m_workspaceIndex; } + virtual void setGeometryBytes(const QByteArray& blob) { m_settings.m_geometryBytes = blob; } + virtual QByteArray getGeometryBytes() const { return m_settings.m_geometryBytes; } + +protected: + void resizeEvent(QResizeEvent* size); private: Ui::AFCGUI* ui; @@ -67,9 +74,7 @@ private: void requestDeviceSetLists(); void updateDeviceSetLists(const AFC::MsgDeviceSetListsReport& report); bool handleMessage(const Message& message); - - void leaveEvent(QEvent*); - void enterEvent(QEvent*); + void makeUIConnections(); private slots: void onMenuDialogCalled(const QPoint &p); diff --git a/plugins/feature/afc/afcgui.ui b/plugins/feature/afc/afcgui.ui index bb6c85553..b72795a21 100644 --- a/plugins/feature/afc/afcgui.ui +++ b/plugins/feature/afc/afcgui.ui @@ -1,24 +1,30 @@ AFCGUI - + 0 0 - 340 - 160 + 320 + 100 - + 0 0 - 340 + 320 + 100 + + + + + 560 100 @@ -37,7 +43,7 @@ 0 0 340 - 151 + 111 @@ -407,9 +413,9 @@ - RollupWidget + RollupContents QWidget -
gui/rollupwidget.h
+
gui/rollupcontents.h
1
diff --git a/plugins/feature/afc/afcsettings.cpp b/plugins/feature/afc/afcsettings.cpp index 7eec426c9..d8dc8eed5 100644 --- a/plugins/feature/afc/afcsettings.cpp +++ b/plugins/feature/afc/afcsettings.cpp @@ -44,6 +44,7 @@ void AFCSettings::resetToDefaults() m_reverseAPIPort = 8888; m_reverseAPIFeatureSetIndex = 0; m_reverseAPIFeatureIndex = 0; + m_workspaceIndex = 0; } QByteArray AFCSettings::serialize() const @@ -69,6 +70,9 @@ QByteArray AFCSettings::serialize() const s.writeBlob(15, m_rollupState->serialize()); } + s.writeS32(16, m_workspaceIndex); + s.writeBlob(17, m_geometryBytes); + return s.final(); } @@ -118,6 +122,9 @@ bool AFCSettings::deserialize(const QByteArray& data) m_rollupState->deserialize(bytetmp); } + d.readS32(16, &m_workspaceIndex, 0); + d.readBlob(17, &m_geometryBytes); + return true; } else diff --git a/plugins/feature/afc/afcsettings.h b/plugins/feature/afc/afcsettings.h index 115cdfebf..fb3d750a4 100644 --- a/plugins/feature/afc/afcsettings.h +++ b/plugins/feature/afc/afcsettings.h @@ -40,6 +40,8 @@ struct AFCSettings uint16_t m_reverseAPIFeatureSetIndex; uint16_t m_reverseAPIFeatureIndex; Serializable *m_rollupState; + int m_workspaceIndex; + QByteArray m_geometryBytes; AFCSettings(); void resetToDefaults(); diff --git a/plugins/feature/ais/aisgui.cpp b/plugins/feature/ais/aisgui.cpp index 9b284bbdd..eaa6749c6 100644 --- a/plugins/feature/ais/aisgui.cpp +++ b/plugins/feature/ais/aisgui.cpp @@ -112,6 +112,7 @@ bool AISGUI::deserialize(const QByteArray& data) { if (m_settings.deserialize(data)) { + m_feature->setWorkspaceIndex(m_settings.m_workspaceIndex); displaySettings(); applySettings(true); return true; @@ -166,7 +167,18 @@ void AISGUI::onWidgetRolled(QWidget* widget, bool rollDown) (void) widget; (void) rollDown; - saveState(m_rollupState); + RollupContents *rollupContents = getRollupContents(); + + if (rollupContents->hasExpandableWidgets()) { + setSizePolicy(sizePolicy().horizontalPolicy(), QSizePolicy::Expanding); + } else { + setSizePolicy(sizePolicy().horizontalPolicy(), QSizePolicy::Fixed); + } + + int h = rollupContents->height() + getAdditionalHeight(); + resize(width(), h); + + rollupContents->saveState(m_rollupState); applySettings(); } @@ -178,16 +190,18 @@ AISGUI::AISGUI(PluginAPI* pluginAPI, FeatureUISet *featureUISet, Feature *featur m_doApplySettings(true), m_lastFeatureState(0) { - ui->setupUi(this); - m_helpURL = "plugins/feature/ais/readme.md"; + m_feature = feature; setAttribute(Qt::WA_DeleteOnClose, true); - setChannelWidget(false); - connect(this, SIGNAL(widgetRolled(QWidget*,bool)), this, SLOT(onWidgetRolled(QWidget*,bool))); + m_helpURL = "plugins/feature/ais/readme.md"; + RollupContents *rollupContents = getRollupContents(); + ui->setupUi(rollupContents); + setSizePolicy(rollupContents->sizePolicy()); + rollupContents->arrangeRollups(); + connect(rollupContents, SIGNAL(widgetRolled(QWidget*,bool)), this, SLOT(onWidgetRolled(QWidget*,bool))); + m_ais = reinterpret_cast(feature); m_ais->setMessageQueueToGUI(&m_inputMessageQueue); - m_featureUISet->addRollupWidget(this); - connect(this, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(onMenuDialogCalled(const QPoint &))); connect(getInputMessageQueue(), SIGNAL(messageEnqueued()), this, SLOT(handleInputMessages())); @@ -229,6 +243,12 @@ AISGUI::~AISGUI() delete ui; } +void AISGUI::setWorkspaceIndex(int index) +{ + m_settings.m_workspaceIndex = index; + m_feature->setWorkspaceIndex(index); +} + void AISGUI::blockApplySettings(bool block) { m_doApplySettings = !block; @@ -238,6 +258,7 @@ void AISGUI::displaySettings() { setTitleColor(m_settings.m_rgbColor); setWindowTitle(m_settings.m_title); + setTitle(m_settings.m_title); blockApplySettings(true); // Order and size columns @@ -253,17 +274,9 @@ void AISGUI::displaySettings() header->moveSection(header->visualIndex(i), m_settings.m_vesselColumnIndexes[i]); } - restoreState(m_rollupState); + getRollupContents()->restoreState(m_rollupState); blockApplySettings(false); - arrangeRollups(); -} - -void AISGUI::leaveEvent(QEvent*) -{ -} - -void AISGUI::enterEvent(QEvent*) -{ + getRollupContents()->arrangeRollups(); } void AISGUI::onMenuDialogCalled(const QPoint &p) @@ -272,17 +285,16 @@ void AISGUI::onMenuDialogCalled(const QPoint &p) { BasicFeatureSettingsDialog dialog(this); dialog.setTitle(m_settings.m_title); - dialog.setColor(m_settings.m_rgbColor); dialog.setUseReverseAPI(m_settings.m_useReverseAPI); dialog.setReverseAPIAddress(m_settings.m_reverseAPIAddress); dialog.setReverseAPIPort(m_settings.m_reverseAPIPort); dialog.setReverseAPIFeatureSetIndex(m_settings.m_reverseAPIFeatureSetIndex); dialog.setReverseAPIFeatureIndex(m_settings.m_reverseAPIFeatureIndex); + dialog.setDefaultTitle(m_displayedName); dialog.move(p); dialog.exec(); - m_settings.m_rgbColor = dialog.getColor().rgb(); m_settings.m_title = dialog.getTitle(); m_settings.m_useReverseAPI = dialog.useReverseAPI(); m_settings.m_reverseAPIAddress = dialog.getReverseAPIAddress(); @@ -290,7 +302,7 @@ void AISGUI::onMenuDialogCalled(const QPoint &p) m_settings.m_reverseAPIFeatureSetIndex = dialog.getReverseAPIFeatureSetIndex(); m_settings.m_reverseAPIFeatureIndex = dialog.getReverseAPIFeatureIndex(); - setWindowTitle(m_settings.m_title); + setTitle(m_settings.m_title); setTitleColor(m_settings.m_rgbColor); applySettings(); diff --git a/plugins/feature/ais/aisgui.h b/plugins/feature/ais/aisgui.h index a1e43584a..4e30f7d15 100644 --- a/plugins/feature/ais/aisgui.h +++ b/plugins/feature/ais/aisgui.h @@ -57,6 +57,10 @@ public: QByteArray serialize() const; bool deserialize(const QByteArray& data); virtual MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; } + virtual void setWorkspaceIndex(int index); + virtual int getWorkspaceIndex() const { return m_settings.m_workspaceIndex; } + virtual void setGeometryBytes(const QByteArray& blob) { m_settings.m_geometryBytes = blob; } + virtual QByteArray getGeometryBytes() const { return m_settings.m_geometryBytes; } private: Ui::AISGUI* ui; @@ -88,9 +92,6 @@ private: void displaySettings(); bool handleMessage(const Message& message); - void leaveEvent(QEvent*); - void enterEvent(QEvent*); - void sendToMap(const QString &name, const QString &label, const QString &image, const QString &text, const QString &model, float modelOffset, float labelOffset, diff --git a/plugins/feature/ais/aisgui.ui b/plugins/feature/ais/aisgui.ui index 5c3b9fb9f..bfeaf9342 100644 --- a/plugins/feature/ais/aisgui.ui +++ b/plugins/feature/ais/aisgui.ui @@ -1,7 +1,7 @@ AISGUI - + 0 @@ -206,9 +206,9 @@ - RollupWidget + RollupContents QWidget -
gui/rollupwidget.h
+
gui/rollupcontents.h
1
diff --git a/plugins/feature/ais/aissettings.cpp b/plugins/feature/ais/aissettings.cpp index 7d902d105..552543bcb 100644 --- a/plugins/feature/ais/aissettings.cpp +++ b/plugins/feature/ais/aissettings.cpp @@ -47,6 +47,7 @@ void AISSettings::resetToDefaults() m_reverseAPIPort = 8888; m_reverseAPIFeatureSetIndex = 0; m_reverseAPIFeatureIndex = 0; + m_workspaceIndex = 0; for (int i = 0; i < AIS_VESSEL_COLUMNS; i++) { @@ -71,6 +72,9 @@ QByteArray AISSettings::serialize() const s.writeBlob(27, m_rollupState->serialize()); } + s.writeS32(28, m_workspaceIndex); + s.writeBlob(29, m_geometryBytes); + for (int i = 0; i < AIS_VESSEL_COLUMNS; i++) { s.writeS32(300 + i, m_vesselColumnIndexes[i]); } @@ -122,6 +126,9 @@ bool AISSettings::deserialize(const QByteArray& data) m_rollupState->deserialize(bytetmp); } + d.readS32(28, &m_workspaceIndex, 0); + d.readBlob(29, &m_geometryBytes); + for (int i = 0; i < AIS_VESSEL_COLUMNS; i++) { d.readS32(300 + i, &m_vesselColumnIndexes[i], i); } diff --git a/plugins/feature/ais/aissettings.h b/plugins/feature/ais/aissettings.h index d29fe3f84..2cf555800 100644 --- a/plugins/feature/ais/aissettings.h +++ b/plugins/feature/ais/aissettings.h @@ -39,6 +39,8 @@ struct AISSettings uint16_t m_reverseAPIFeatureSetIndex; uint16_t m_reverseAPIFeatureIndex; Serializable *m_rollupState; + int m_workspaceIndex; + QByteArray m_geometryBytes; int m_vesselColumnIndexes[AIS_VESSEL_COLUMNS]; int m_vesselColumnSizes[AIS_VESSEL_COLUMNS]; diff --git a/plugins/feature/antennatools/antennatoolsgui.cpp b/plugins/feature/antennatools/antennatoolsgui.cpp index f37f7fef8..1b2141062 100644 --- a/plugins/feature/antennatools/antennatoolsgui.cpp +++ b/plugins/feature/antennatools/antennatoolsgui.cpp @@ -18,6 +18,8 @@ #include +#include + #include "feature/featureuiset.h" #include "gui/basicfeaturesettingsdialog.h" #include "channel/channelwebapiutils.h" @@ -57,6 +59,7 @@ bool AntennaToolsGUI::deserialize(const QByteArray& data) { if (m_settings.deserialize(data)) { + m_feature->setWorkspaceIndex(m_settings.m_workspaceIndex); displaySettings(); applySettings(true); return true; @@ -68,6 +71,12 @@ bool AntennaToolsGUI::deserialize(const QByteArray& data) } } +void AntennaToolsGUI::resizeEvent(QResizeEvent* size) +{ + adjustSize(); + size->accept(); +} + bool AntennaToolsGUI::handleMessage(const Message& message) { if (AntennaTools::MsgConfigureAntennaTools::match(message)) @@ -102,7 +111,18 @@ void AntennaToolsGUI::onWidgetRolled(QWidget* widget, bool rollDown) (void) widget; (void) rollDown; - saveState(m_rollupState); + RollupContents *rollupContents = getRollupContents(); + + if (rollupContents->hasExpandableWidgets()) { + setSizePolicy(sizePolicy().horizontalPolicy(), QSizePolicy::Expanding); + } else { + setSizePolicy(sizePolicy().horizontalPolicy(), QSizePolicy::Fixed); + } + + int h = rollupContents->height() + getAdditionalHeight(); + resize(width(), h); + + rollupContents->saveState(m_rollupState); applySettings(); } @@ -114,17 +134,18 @@ AntennaToolsGUI::AntennaToolsGUI(PluginAPI* pluginAPI, FeatureUISet *featureUISe m_doApplySettings(true), m_deviceSets(0) { - ui->setupUi(this); - m_helpURL = "plugins/feature/antennatools/readme.md"; - + m_feature = feature; setAttribute(Qt::WA_DeleteOnClose, true); - setChannelWidget(false); - connect(this, SIGNAL(widgetRolled(QWidget*,bool)), this, SLOT(onWidgetRolled(QWidget*,bool))); + m_helpURL = "plugins/feature/antennatools/readme.md"; + RollupContents *rollupContents = getRollupContents(); + ui->setupUi(rollupContents); + setSizePolicy(rollupContents->sizePolicy()); + rollupContents->arrangeRollups(); + connect(rollupContents, SIGNAL(widgetRolled(QWidget*,bool)), this, SLOT(onWidgetRolled(QWidget*,bool))); + m_antennatools = reinterpret_cast(feature); m_antennatools->setMessageQueueToGUI(&m_inputMessageQueue); - m_featureUISet->addRollupWidget(this); - connect(this, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(onMenuDialogCalled(const QPoint &))); connect(getInputMessageQueue(), SIGNAL(messageEnqueued()), this, SLOT(handleInputMessages())); @@ -136,6 +157,7 @@ AntennaToolsGUI::AntennaToolsGUI(PluginAPI* pluginAPI, FeatureUISet *featureUISe displaySettings(); applySettings(true); + makeUIConnections(); } AntennaToolsGUI::~AntennaToolsGUI() @@ -143,6 +165,12 @@ AntennaToolsGUI::~AntennaToolsGUI() delete ui; } +void AntennaToolsGUI::setWorkspaceIndex(int index) +{ + m_settings.m_workspaceIndex = index; + m_feature->setWorkspaceIndex(index); +} + void AntennaToolsGUI::blockApplySettings(bool block) { m_doApplySettings = !block; @@ -152,6 +180,7 @@ void AntennaToolsGUI::displaySettings() { setTitleColor(m_settings.m_rgbColor); setWindowTitle(m_settings.m_title); + setTitle(m_settings.m_title); blockApplySettings(true); ui->dipoleFrequency->setValue(m_settings.m_dipoleFrequencyMHz); ui->dipoleFrequencySelect->setCurrentIndex(m_settings.m_dipoleFrequencySelect); @@ -170,15 +199,24 @@ void AntennaToolsGUI::displaySettings() calcDishBeamwidth(); calcDishGain(); calcDishEffectiveArea(); - restoreState(m_rollupState); + getRollupContents()->restoreState(m_rollupState); } -void AntennaToolsGUI::leaveEvent(QEvent*) -{ -} - -void AntennaToolsGUI::enterEvent(QEvent*) +void AntennaToolsGUI::makeUIConnections() { + QObject::connect(ui->dipoleFrequency, qOverload(&QDoubleSpinBox::valueChanged), this, &AntennaToolsGUI::on_dipoleFrequency_valueChanged); + QObject::connect(ui->dipoleFrequencySelect, qOverload(&QComboBox::currentIndexChanged), this, &AntennaToolsGUI::on_dipoleFrequencySelect_currentIndexChanged); + QObject::connect(ui->dipoleEndEffectFactor, qOverload(&QDoubleSpinBox::valueChanged), this, &AntennaToolsGUI::on_dipoleEndEffectFactor_valueChanged); + QObject::connect(ui->dipoleLengthUnits, qOverload(&QComboBox::currentIndexChanged), this, &AntennaToolsGUI::on_dipoleLengthUnits_currentIndexChanged); + QObject::connect(ui->dipoleLength, qOverload(&QDoubleSpinBox::valueChanged), this, &AntennaToolsGUI::on_dipoleLength_valueChanged); + QObject::connect(ui->dipoleElementLength, qOverload(&QDoubleSpinBox::valueChanged), this, &AntennaToolsGUI::on_dipoleElementLength_valueChanged); + QObject::connect(ui->dishFrequency, qOverload(&QDoubleSpinBox::valueChanged), this, &AntennaToolsGUI::on_dishFrequency_valueChanged); + QObject::connect(ui->dishFrequencySelect, qOverload(&QComboBox::currentIndexChanged), this, &AntennaToolsGUI::on_dishFrequencySelect_currentIndexChanged); + QObject::connect(ui->dishDiameter, qOverload(&QDoubleSpinBox::valueChanged), this, &AntennaToolsGUI::on_dishDiameter_valueChanged); + QObject::connect(ui->dishLengthUnits, qOverload(&QComboBox::currentIndexChanged), this, &AntennaToolsGUI::on_dishLengthUnits_currentIndexChanged); + QObject::connect(ui->dishDepth, qOverload(&QDoubleSpinBox::valueChanged), this, &AntennaToolsGUI::on_dishDepth_valueChanged); + QObject::connect(ui->dishEfficiency, qOverload(&QSpinBox::valueChanged), this, &AntennaToolsGUI::on_dishEfficiency_valueChanged); + QObject::connect(ui->dishSurfaceError, qOverload(&QDoubleSpinBox::valueChanged), this, &AntennaToolsGUI::on_dishSurfaceError_valueChanged); } void AntennaToolsGUI::onMenuDialogCalled(const QPoint &p) @@ -187,17 +225,16 @@ void AntennaToolsGUI::onMenuDialogCalled(const QPoint &p) { BasicFeatureSettingsDialog dialog(this); dialog.setTitle(m_settings.m_title); - dialog.setColor(m_settings.m_rgbColor); dialog.setUseReverseAPI(m_settings.m_useReverseAPI); dialog.setReverseAPIAddress(m_settings.m_reverseAPIAddress); dialog.setReverseAPIPort(m_settings.m_reverseAPIPort); dialog.setReverseAPIFeatureSetIndex(m_settings.m_reverseAPIFeatureSetIndex); dialog.setReverseAPIFeatureIndex(m_settings.m_reverseAPIFeatureIndex); + dialog.setDefaultTitle(m_displayedName); dialog.move(p); dialog.exec(); - m_settings.m_rgbColor = dialog.getColor().rgb(); m_settings.m_title = dialog.getTitle(); m_settings.m_useReverseAPI = dialog.useReverseAPI(); m_settings.m_reverseAPIAddress = dialog.getReverseAPIAddress(); @@ -205,7 +242,7 @@ void AntennaToolsGUI::onMenuDialogCalled(const QPoint &p) m_settings.m_reverseAPIFeatureSetIndex = dialog.getReverseAPIFeatureSetIndex(); m_settings.m_reverseAPIFeatureIndex = dialog.getReverseAPIFeatureIndex(); - setWindowTitle(m_settings.m_title); + setTitle(m_settings.m_title); setTitleColor(m_settings.m_rgbColor); applySettings(); diff --git a/plugins/feature/antennatools/antennatoolsgui.h b/plugins/feature/antennatools/antennatoolsgui.h index 5d4213ab4..431d95785 100644 --- a/plugins/feature/antennatools/antennatoolsgui.h +++ b/plugins/feature/antennatools/antennatoolsgui.h @@ -46,6 +46,13 @@ public: QByteArray serialize() const; bool deserialize(const QByteArray& data); virtual MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; } + virtual void setWorkspaceIndex(int index); + virtual int getWorkspaceIndex() const { return m_settings.m_workspaceIndex; } + virtual void setGeometryBytes(const QByteArray& blob) { m_settings.m_geometryBytes = blob; } + virtual QByteArray getGeometryBytes() const { return m_settings.m_geometryBytes; } + +protected: + void resizeEvent(QResizeEvent* size); private: Ui::AntennaToolsGUI* ui; @@ -67,9 +74,7 @@ private: void applySettings(bool force = false); void displaySettings(); bool handleMessage(const Message& message); - - void leaveEvent(QEvent*); - void enterEvent(QEvent*); + void makeUIConnections(); void calcDipoleLength(); double calcDipoleFrequency(double totalLength); diff --git a/plugins/feature/antennatools/antennatoolsgui.ui b/plugins/feature/antennatools/antennatoolsgui.ui index 7cdbb6a19..c7f0cc066 100644 --- a/plugins/feature/antennatools/antennatoolsgui.ui +++ b/plugins/feature/antennatools/antennatoolsgui.ui @@ -1,17 +1,17 @@ AntennaToolsGUI - + 0 0 - 394 - 523 + 360 + 584 - + 0 0 @@ -19,7 +19,13 @@ 360 - 0 + 584 + + + + + 560 + 584 @@ -37,10 +43,10 @@ - 16 - 19 + 0 + 0 371 - 481 + 581 @@ -53,7 +59,7 @@ Calculators - 1 + 0 @@ -64,7 +70,7 @@ - 94 + 90 0 @@ -260,7 +266,7 @@ - 94 + 90 0 @@ -503,9 +509,9 @@ - RollupWidget + RollupContents QWidget -
gui/rollupwidget.h
+
gui/rollupcontents.h
1
diff --git a/plugins/feature/antennatools/antennatoolssettings.cpp b/plugins/feature/antennatools/antennatoolssettings.cpp index 2dd559bbe..2dce3f633 100644 --- a/plugins/feature/antennatools/antennatoolssettings.cpp +++ b/plugins/feature/antennatools/antennatoolssettings.cpp @@ -49,6 +49,7 @@ void AntennaToolsSettings::resetToDefaults() m_reverseAPIPort = 8888; m_reverseAPIFeatureSetIndex = 0; m_reverseAPIFeatureIndex = 0; + m_workspaceIndex = 0; } QByteArray AntennaToolsSettings::serialize() const @@ -78,6 +79,9 @@ QByteArray AntennaToolsSettings::serialize() const s.writeBlob(19, m_rollupState->serialize()); } + s.writeS32(20, m_workspaceIndex); + s.writeBlob(21, m_geometryBytes); + return s.final(); } @@ -131,6 +135,9 @@ bool AntennaToolsSettings::deserialize(const QByteArray& data) m_rollupState->deserialize(bytetmp); } + d.readS32(20, &m_workspaceIndex, 0); + d.readBlob(21, &m_geometryBytes); + return true; } else diff --git a/plugins/feature/antennatools/antennatoolssettings.h b/plugins/feature/antennatools/antennatoolssettings.h index 704f17501..3302cdfd4 100644 --- a/plugins/feature/antennatools/antennatoolssettings.h +++ b/plugins/feature/antennatools/antennatoolssettings.h @@ -51,6 +51,8 @@ struct AntennaToolsSettings uint16_t m_reverseAPIFeatureSetIndex; uint16_t m_reverseAPIFeatureIndex; Serializable *m_rollupState; + int m_workspaceIndex; + QByteArray m_geometryBytes; AntennaToolsSettings(); void resetToDefaults(); diff --git a/plugins/feature/aprs/aprsgui.cpp b/plugins/feature/aprs/aprsgui.cpp index 1023bb53b..bd2dd5013 100644 --- a/plugins/feature/aprs/aprsgui.cpp +++ b/plugins/feature/aprs/aprsgui.cpp @@ -132,6 +132,7 @@ bool APRSGUI::deserialize(const QByteArray& data) { if (m_settings.deserialize(data)) { + m_feature->setWorkspaceIndex(m_settings.m_workspaceIndex); displaySettings(); applySettings(true); return true; @@ -418,7 +419,7 @@ void APRSGUI::onWidgetRolled(QWidget* widget, bool rollDown) (void) widget; (void) rollDown; - saveState(m_rollupState); + getRollupContents()->saveState(m_rollupState); applySettings(); } @@ -430,17 +431,18 @@ APRSGUI::APRSGUI(PluginAPI* pluginAPI, FeatureUISet *featureUISet, Feature *feat m_doApplySettings(true), m_lastFeatureState(0) { - ui->setupUi(this); - m_helpURL = "plugins/feature/aprs/readme.md"; - + m_feature = feature; setAttribute(Qt::WA_DeleteOnClose, true); - setChannelWidget(false); - connect(this, SIGNAL(widgetRolled(QWidget*,bool)), this, SLOT(onWidgetRolled(QWidget*,bool))); + m_helpURL = "plugins/feature/aprs/readme.md"; + RollupContents *rollupContents = getRollupContents(); + ui->setupUi(rollupContents); + setSizePolicy(rollupContents->sizePolicy()); + rollupContents->arrangeRollups(); + connect(rollupContents, SIGNAL(widgetRolled(QWidget*,bool)), this, SLOT(onWidgetRolled(QWidget*,bool))); + m_aprs = reinterpret_cast(feature); m_aprs->setMessageQueueToGUI(&m_inputMessageQueue); - m_featureUISet->addRollupWidget(this); - connect(this, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(onMenuDialogCalled(const QPoint &))); connect(getInputMessageQueue(), SIGNAL(messageEnqueued()), this, SLOT(handleInputMessages())); @@ -564,6 +566,7 @@ APRSGUI::APRSGUI(PluginAPI* pluginAPI, FeatureUISet *featureUISet, Feature *feat displaySettings(); applySettings(true); + makeUIConnections(); } APRSGUI::~APRSGUI() @@ -571,6 +574,12 @@ APRSGUI::~APRSGUI() delete ui; } +void APRSGUI::setWorkspaceIndex(int index) +{ + m_settings.m_workspaceIndex = index; + m_feature->setWorkspaceIndex(index); +} + void APRSGUI::blockApplySettings(bool block) { m_doApplySettings = !block; @@ -629,6 +638,7 @@ void APRSGUI::displaySettings() { setTitleColor(m_settings.m_rgbColor); setWindowTitle(m_settings.m_title); + setTitle(m_settings.m_title); blockApplySettings(true); ui->igate->setChecked(m_settings.m_igateEnabled); ui->stationFilter->setCurrentIndex((int)m_settings.m_stationFilter); @@ -643,7 +653,7 @@ void APRSGUI::displaySettings() displayTableSettings(ui->telemetryTable, telemetryTableMenu, m_settings.m_telemetryTableColumnSizes, m_settings.m_telemetryTableColumnIndexes, APRS_TELEMETRY_TABLE_COLUMNS); displayTableSettings(ui->motionTable, motionTableMenu, m_settings.m_motionTableColumnSizes, m_settings.m_motionTableColumnIndexes, APRS_MOTION_TABLE_COLUMNS); - restoreState(m_rollupState); + getRollupContents()->restoreState(m_rollupState); blockApplySettings(false); } @@ -660,21 +670,12 @@ void APRSGUI::updateChannelList() ui->sourcePipes->blockSignals(false); } -void APRSGUI::leaveEvent(QEvent*) -{ -} - -void APRSGUI::enterEvent(QEvent*) -{ -} - -void APRSGUI::resizeEvent(QResizeEvent* size) +void APRSGUI::resizeEvent(QResizeEvent*) { // Replot graphs to ensure Axis are visible plotWeather(); plotTelemetry(); plotMotion(); - FeatureGUI::resizeEvent(size); } void APRSGUI::onMenuDialogCalled(const QPoint &p) @@ -683,17 +684,16 @@ void APRSGUI::onMenuDialogCalled(const QPoint &p) { BasicFeatureSettingsDialog dialog(this); dialog.setTitle(m_settings.m_title); - dialog.setColor(m_settings.m_rgbColor); dialog.setUseReverseAPI(m_settings.m_useReverseAPI); dialog.setReverseAPIAddress(m_settings.m_reverseAPIAddress); dialog.setReverseAPIPort(m_settings.m_reverseAPIPort); dialog.setReverseAPIFeatureSetIndex(m_settings.m_reverseAPIFeatureSetIndex); dialog.setReverseAPIFeatureIndex(m_settings.m_reverseAPIFeatureIndex); + dialog.setDefaultTitle(m_displayedName); dialog.move(p); dialog.exec(); - m_settings.m_rgbColor = dialog.getColor().rgb(); m_settings.m_title = dialog.getTitle(); m_settings.m_useReverseAPI = dialog.useReverseAPI(); m_settings.m_reverseAPIAddress = dialog.getReverseAPIAddress(); @@ -701,7 +701,7 @@ void APRSGUI::onMenuDialogCalled(const QPoint &p) m_settings.m_reverseAPIFeatureSetIndex = dialog.getReverseAPIFeatureSetIndex(); m_settings.m_reverseAPIFeatureIndex = dialog.getReverseAPIFeatureIndex(); - setWindowTitle(m_settings.m_title); + setTitle(m_settings.m_title); setTitleColor(m_settings.m_rgbColor); applySettings(); @@ -2026,3 +2026,20 @@ void APRSGUI::on_viewOnMap_clicked() } } } + +void APRSGUI::makeUIConnections() +{ + QObject::connect(ui->stationFilter, qOverload(&QComboBox::currentIndexChanged), this, &APRSGUI::on_stationFilter_currentIndexChanged); + QObject::connect(ui->stationSelect, qOverload(&QComboBox::currentIndexChanged), this, &APRSGUI::on_stationSelect_currentIndexChanged); + QObject::connect(ui->filterAddressee, &QLineEdit::editingFinished, this, &APRSGUI::on_filterAddressee_editingFinished); + QObject::connect(ui->deleteMessages, &QPushButton::clicked, this, &APRSGUI::on_deleteMessages_clicked); + QObject::connect(ui->weatherTimeSelect, qOverload(&QComboBox::currentIndexChanged), this, &APRSGUI::on_weatherTimeSelect_currentIndexChanged); + QObject::connect(ui->weatherPlotSelect, qOverload(&QComboBox::currentIndexChanged), this, &APRSGUI::on_weatherPlotSelect_currentIndexChanged); + QObject::connect(ui->telemetryTimeSelect, qOverload(&QComboBox::currentIndexChanged), this, &APRSGUI::on_telemetryTimeSelect_currentIndexChanged); + QObject::connect(ui->telemetryPlotSelect, qOverload(&QComboBox::currentIndexChanged), this, &APRSGUI::on_telemetryPlotSelect_currentIndexChanged); + QObject::connect(ui->motionTimeSelect, qOverload(&QComboBox::currentIndexChanged), this, &APRSGUI::on_motionTimeSelect_currentIndexChanged); + QObject::connect(ui->motionPlotSelect, qOverload(&QComboBox::currentIndexChanged), this, &APRSGUI::on_motionPlotSelect_currentIndexChanged); + QObject::connect(ui->displaySettings, &QPushButton::clicked, this, &APRSGUI::on_displaySettings_clicked); + QObject::connect(ui->igate, &ButtonSwitch::toggled, this, &APRSGUI::on_igate_toggled); + QObject::connect(ui->viewOnMap, &QPushButton::clicked, this, &APRSGUI::on_viewOnMap_clicked); +} diff --git a/plugins/feature/aprs/aprsgui.h b/plugins/feature/aprs/aprsgui.h index 170c2282f..fdb730a91 100644 --- a/plugins/feature/aprs/aprsgui.h +++ b/plugins/feature/aprs/aprsgui.h @@ -105,6 +105,10 @@ public: QByteArray serialize() const; bool deserialize(const QByteArray& data); virtual MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; } + virtual void setWorkspaceIndex(int index); + virtual int getWorkspaceIndex() const { return m_settings.m_workspaceIndex; } + virtual void setGeometryBytes(const QByteArray& blob) { m_settings.m_geometryBytes = blob; } + virtual QByteArray getGeometryBytes() const { return m_settings.m_geometryBytes; } protected: void resizeEvent(QResizeEvent* size); @@ -155,9 +159,7 @@ private: void displaySettings(); void updateChannelList(); bool handleMessage(const Message& message); - - void leaveEvent(QEvent*); - void enterEvent(QEvent*); + void makeUIConnections(); void filterMessageRow(int row); void filterMessages(); diff --git a/plugins/feature/aprs/aprsgui.ui b/plugins/feature/aprs/aprsgui.ui index 68a8c1acf..92014f20f 100644 --- a/plugins/feature/aprs/aprsgui.ui +++ b/plugins/feature/aprs/aprsgui.ui @@ -1,13 +1,13 @@ APRSGUI - + 0 0 469 - 761 + 578 @@ -181,6 +181,12 @@ 0 + + + 0 + 0 + + Stations and Objects @@ -562,6 +568,12 @@ + + + 0 + 0 + + Weather @@ -834,6 +846,12 @@ + + + 0 + 0 + + Motion @@ -1001,6 +1019,12 @@ + + + 0 + 0 + + Telemetry @@ -1265,6 +1289,12 @@ + + + 0 + 0 + + Status @@ -1317,6 +1347,12 @@ + + + 0 + 0 + + Packets @@ -1368,6 +1404,12 @@ + + + 0 + 0 + + Messages @@ -1447,17 +1489,17 @@ - - RollupWidget - QWidget -
gui/rollupwidget.h
- 1 -
ButtonSwitch QToolButton
gui/buttonswitch.h
+ + RollupContents + QWidget +
gui/rollupcontents.h
+ 1 +
QChartView QGraphicsView diff --git a/plugins/feature/aprs/aprssettings.cpp b/plugins/feature/aprs/aprssettings.cpp index 5e843f04b..b9b2036af 100644 --- a/plugins/feature/aprs/aprssettings.cpp +++ b/plugins/feature/aprs/aprssettings.cpp @@ -77,6 +77,7 @@ void APRSSettings::resetToDefaults() m_reverseAPIPort = 8888; m_reverseAPIFeatureSetIndex = 0; m_reverseAPIFeatureIndex = 0; + m_workspaceIndex = 0; for (int i = 0; i < APRS_PACKETS_TABLE_COLUMNS; i++) { @@ -143,6 +144,9 @@ QByteArray APRSSettings::serialize() const s.writeBlob(20, m_rollupState->serialize()); } + s.writeS32(21, m_workspaceIndex); + s.writeBlob(22, m_geometryBytes); + for (int i = 0; i < APRS_PACKETS_TABLE_COLUMNS; i++) s.writeS32(100 + i, m_packetsTableColumnIndexes[i]); for (int i = 0; i < APRS_PACKETS_TABLE_COLUMNS; i++) @@ -222,6 +226,9 @@ bool APRSSettings::deserialize(const QByteArray& data) m_rollupState->deserialize(bytetmp); } + d.readS32(21, &m_workspaceIndex, 0); + d.readBlob(22, &m_geometryBytes); + for (int i = 0; i < APRS_PACKETS_TABLE_COLUMNS; i++) d.readS32(100 + i, &m_packetsTableColumnIndexes[i], i); for (int i = 0; i < APRS_PACKETS_TABLE_COLUMNS; i++) diff --git a/plugins/feature/aprs/aprssettings.h b/plugins/feature/aprs/aprssettings.h index 509bdd160..99c58894f 100644 --- a/plugins/feature/aprs/aprssettings.h +++ b/plugins/feature/aprs/aprssettings.h @@ -77,6 +77,8 @@ struct APRSSettings uint16_t m_reverseAPIFeatureSetIndex; uint16_t m_reverseAPIFeatureIndex; Serializable *m_rollupState; + int m_workspaceIndex; + QByteArray m_geometryBytes; int m_packetsTableColumnIndexes[APRS_PACKETS_TABLE_COLUMNS];//!< How the columns are ordered in the table int m_packetsTableColumnSizes[APRS_PACKETS_TABLE_COLUMNS]; //!< Size of the columns in the table diff --git a/plugins/feature/demodanalyzer/demodanalyzergui.cpp b/plugins/feature/demodanalyzer/demodanalyzergui.cpp index 7b064fc4a..fd6d39bcf 100644 --- a/plugins/feature/demodanalyzer/demodanalyzergui.cpp +++ b/plugins/feature/demodanalyzer/demodanalyzergui.cpp @@ -57,6 +57,7 @@ bool DemodAnalyzerGUI::deserialize(const QByteArray& data) { if (m_settings.deserialize(data)) { + m_feature->setWorkspaceIndex(m_settings.m_workspaceIndex); displaySettings(); applySettings(true); return true; @@ -125,7 +126,18 @@ void DemodAnalyzerGUI::onWidgetRolled(QWidget* widget, bool rollDown) (void) widget; (void) rollDown; - saveState(m_rollupState); + RollupContents *rollupContents = getRollupContents(); + + if (rollupContents->hasExpandableWidgets()) { + setSizePolicy(sizePolicy().horizontalPolicy(), QSizePolicy::Expanding); + } else { + setSizePolicy(sizePolicy().horizontalPolicy(), QSizePolicy::Fixed); + } + + int h = rollupContents->height() + getAdditionalHeight(); + resize(width(), h); + + rollupContents->saveState(m_rollupState); applySettings(); } @@ -139,11 +151,14 @@ DemodAnalyzerGUI::DemodAnalyzerGUI(PluginAPI* pluginAPI, FeatureUISet *featureUI m_lastFeatureState(0), m_selectedChannel(nullptr) { - ui->setupUi(this); - m_helpURL = "plugins/feature/demodanalyzer/readme.md"; + m_feature = feature; setAttribute(Qt::WA_DeleteOnClose, true); - setChannelWidget(false); - connect(this, SIGNAL(widgetRolled(QWidget*,bool)), this, SLOT(onWidgetRolled(QWidget*,bool))); + m_helpURL = "plugins/feature/demodanalyzer/readme.md"; + RollupContents *rollupContents = getRollupContents(); + ui->setupUi(rollupContents); + setSizePolicy(rollupContents->sizePolicy()); + rollupContents->arrangeRollups(); + connect(rollupContents, SIGNAL(widgetRolled(QWidget*,bool)), this, SLOT(onWidgetRolled(QWidget*,bool))); m_demodAnalyzer = reinterpret_cast(feature); m_demodAnalyzer->setMessageQueueToGUI(&m_inputMessageQueue); @@ -169,14 +184,13 @@ DemodAnalyzerGUI::DemodAnalyzerGUI(PluginAPI* pluginAPI, FeatureUISet *featureUI ui->glScope->connectTimer(MainCore::instance()->getMasterTimer()); connect(&MainCore::instance()->getMasterTimer(), SIGNAL(timeout()), this, SLOT(tick())); - m_featureUISet->addRollupWidget(this); - m_settings.setSpectrumGUI(ui->spectrumGUI); m_settings.setScopeGUI(ui->scopeGUI); m_settings.setRollupState(&m_rollupState); displaySettings(); applySettings(true); + makeUIConnections(); } DemodAnalyzerGUI::~DemodAnalyzerGUI() @@ -189,13 +203,20 @@ void DemodAnalyzerGUI::blockApplySettings(bool block) m_doApplySettings = !block; } +void DemodAnalyzerGUI::setWorkspaceIndex(int index) +{ + m_settings.m_workspaceIndex = index; + m_feature->setWorkspaceIndex(index); +} + void DemodAnalyzerGUI::displaySettings() { setTitleColor(m_settings.m_rgbColor); setWindowTitle(m_settings.m_title); + setTitle(m_settings.m_title); blockApplySettings(true); ui->log2Decim->setCurrentIndex(m_settings.m_log2Decim); - restoreState(m_rollupState); + getRollupContents()->restoreState(m_rollupState); blockApplySettings(false); } @@ -239,31 +260,22 @@ void DemodAnalyzerGUI::updateChannelList() } } -void DemodAnalyzerGUI::leaveEvent(QEvent*) -{ -} - -void DemodAnalyzerGUI::enterEvent(QEvent*) -{ -} - void DemodAnalyzerGUI::onMenuDialogCalled(const QPoint &p) { if (m_contextMenuType == ContextMenuChannelSettings) { BasicFeatureSettingsDialog dialog(this); dialog.setTitle(m_settings.m_title); - dialog.setColor(m_settings.m_rgbColor); dialog.setUseReverseAPI(m_settings.m_useReverseAPI); dialog.setReverseAPIAddress(m_settings.m_reverseAPIAddress); dialog.setReverseAPIPort(m_settings.m_reverseAPIPort); dialog.setReverseAPIFeatureSetIndex(m_settings.m_reverseAPIFeatureSetIndex); dialog.setReverseAPIFeatureIndex(m_settings.m_reverseAPIFeatureIndex); + dialog.setDefaultTitle(m_displayedName); dialog.move(p); dialog.exec(); - m_settings.m_rgbColor = dialog.getColor().rgb(); m_settings.m_title = dialog.getTitle(); m_settings.m_useReverseAPI = dialog.useReverseAPI(); m_settings.m_reverseAPIAddress = dialog.getReverseAPIAddress(); @@ -271,7 +283,7 @@ void DemodAnalyzerGUI::onMenuDialogCalled(const QPoint &p) m_settings.m_reverseAPIFeatureSetIndex = dialog.getReverseAPIFeatureSetIndex(); m_settings.m_reverseAPIFeatureIndex = dialog.getReverseAPIFeatureIndex(); - setWindowTitle(m_settings.m_title); + setTitle(m_settings.m_title); setTitleColor(m_settings.m_rgbColor); applySettings(); @@ -369,3 +381,12 @@ void DemodAnalyzerGUI::applySettings(bool force) m_demodAnalyzer->getInputMessageQueue()->push(message); } } + +void DemodAnalyzerGUI::makeUIConnections() +{ + QObject::connect(ui->startStop, &ButtonSwitch::toggled, this, &DemodAnalyzerGUI::on_startStop_toggled); + QObject::connect(ui->devicesRefresh, &QPushButton::clicked, this, &DemodAnalyzerGUI::on_devicesRefresh_clicked); + QObject::connect(ui->channels, qOverload(&QComboBox::currentIndexChanged), this, &DemodAnalyzerGUI::on_channels_currentIndexChanged); + QObject::connect(ui->channelApply, &QPushButton::clicked, this, &DemodAnalyzerGUI::on_channelApply_clicked); + QObject::connect(ui->log2Decim, qOverload(&QComboBox::currentIndexChanged), this, &DemodAnalyzerGUI::on_log2Decim_currentIndexChanged); +} diff --git a/plugins/feature/demodanalyzer/demodanalyzergui.h b/plugins/feature/demodanalyzer/demodanalyzergui.h index 69f0fab22..84483f668 100644 --- a/plugins/feature/demodanalyzer/demodanalyzergui.h +++ b/plugins/feature/demodanalyzer/demodanalyzergui.h @@ -49,6 +49,10 @@ public: QByteArray serialize() const; bool deserialize(const QByteArray& data); virtual MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; } + virtual void setWorkspaceIndex(int index); + virtual int getWorkspaceIndex() const { return m_settings.m_workspaceIndex; } + virtual void setGeometryBytes(const QByteArray& blob) { m_settings.m_geometryBytes = blob; } + virtual QByteArray getGeometryBytes() const { return m_settings.m_geometryBytes; } private: Ui::DemodAnalyzerGUI* ui; @@ -78,9 +82,7 @@ private: void displaySampleRate(int sampleRate); void updateChannelList(); bool handleMessage(const Message& message); - - void leaveEvent(QEvent*); - void enterEvent(QEvent*); + void makeUIConnections(); private slots: void onMenuDialogCalled(const QPoint &p); diff --git a/plugins/feature/demodanalyzer/demodanalyzergui.ui b/plugins/feature/demodanalyzer/demodanalyzergui.ui index 49a3fdcd0..a4ca773de 100644 --- a/plugins/feature/demodanalyzer/demodanalyzergui.ui +++ b/plugins/feature/demodanalyzer/demodanalyzergui.ui @@ -1,7 +1,7 @@ DemodAnalyzerGUI - + 0 @@ -36,10 +36,16 @@ 0 10 - 631 + 718 41 + + + 718 + 0 + + Settings @@ -262,7 +268,7 @@ - 716 + 718 0 @@ -287,6 +293,12 @@ + + + 0 + 0 + + 200 @@ -323,7 +335,7 @@ - 716 + 718 0 @@ -348,6 +360,12 @@ + + + 0 + 0 + + 200 @@ -370,9 +388,14 @@ - RollupWidget + ButtonSwitch + QToolButton +
gui/buttonswitch.h
+
+ + RollupContents QWidget -
gui/rollupwidget.h
+
gui/rollupcontents.h
1
@@ -387,11 +410,6 @@
gui/glspectrumgui.h
1
- - ButtonSwitch - QToolButton -
gui/buttonswitch.h
-
GLScope QWidget diff --git a/plugins/feature/demodanalyzer/demodanalyzersettings.cpp b/plugins/feature/demodanalyzer/demodanalyzersettings.cpp index 12419b2cc..d261e5417 100644 --- a/plugins/feature/demodanalyzer/demodanalyzersettings.cpp +++ b/plugins/feature/demodanalyzer/demodanalyzersettings.cpp @@ -76,6 +76,7 @@ void DemodAnalyzerSettings::resetToDefaults() m_reverseAPIPort = 8888; m_reverseAPIFeatureSetIndex = 0; m_reverseAPIFeatureIndex = 0; + m_workspaceIndex = 0; } QByteArray DemodAnalyzerSettings::serialize() const @@ -103,6 +104,9 @@ QByteArray DemodAnalyzerSettings::serialize() const s.writeBlob(12, m_rollupState->serialize()); } + s.writeS32(13, m_workspaceIndex); + s.writeBlob(14, m_geometryBytes); + return s.final(); } @@ -158,6 +162,9 @@ bool DemodAnalyzerSettings::deserialize(const QByteArray& data) m_rollupState->deserialize(bytetmp); } + d.readS32(13, &m_workspaceIndex, 0); + d.readBlob(14, &m_geometryBytes); + return true; } else diff --git a/plugins/feature/demodanalyzer/demodanalyzersettings.h b/plugins/feature/demodanalyzer/demodanalyzersettings.h index c4ba8516a..d3670d181 100644 --- a/plugins/feature/demodanalyzer/demodanalyzersettings.h +++ b/plugins/feature/demodanalyzer/demodanalyzersettings.h @@ -52,6 +52,8 @@ struct DemodAnalyzerSettings Serializable *m_spectrumGUI; Serializable *m_scopeGUI; Serializable *m_rollupState; + int m_workspaceIndex; + QByteArray m_geometryBytes; DemodAnalyzerSettings(); void resetToDefaults(); diff --git a/plugins/feature/demodanalyzer/readme.md b/plugins/feature/demodanalyzer/readme.md index 76ede3c98..5aac2bd84 100644 --- a/plugins/feature/demodanalyzer/readme.md +++ b/plugins/feature/demodanalyzer/readme.md @@ -75,7 +75,7 @@ Average total power in dB relative to a +/- 1.0 amplitude signal received in the

B. Spectrum view

-This is the same display as with the channel analyzer spectrum view. This is the spectrum of a real signal so it is symmetrical around zero frequency. See Channel Analyzer plugin documentation for details. +This is the same display as with the channel analyzer spectrum view. This is the spectrum of a real signal so it is symmetrical around zero frequency. Details on the spectrum view and controls can be found [here](../../../sdrgui/gui/spectrum.md)

C. Scope view

diff --git a/plugins/feature/gs232controller/gs232controllergui.cpp b/plugins/feature/gs232controller/gs232controllergui.cpp index 6d8110bc7..d9adff147 100644 --- a/plugins/feature/gs232controller/gs232controllergui.cpp +++ b/plugins/feature/gs232controller/gs232controllergui.cpp @@ -19,6 +19,7 @@ #include #include #include +#include #include "SWGTargetAzimuthElevation.h" @@ -59,6 +60,7 @@ bool GS232ControllerGUI::deserialize(const QByteArray& data) { if (m_settings.deserialize(data)) { + m_feature->setWorkspaceIndex(m_settings.m_workspaceIndex); displaySettings(); applySettings(true); return true; @@ -70,6 +72,14 @@ bool GS232ControllerGUI::deserialize(const QByteArray& data) } } +void GS232ControllerGUI::resizeEvent(QResizeEvent* size) +{ + int maxWidth = getRollupContents()->maximumWidth(); + int minHeight = getRollupContents()->minimumHeight() + getAdditionalHeight(); + resize(width() < maxWidth ? width() : maxWidth, minHeight); + size->accept(); +} + bool GS232ControllerGUI::handleMessage(const Message& message) { if (GS232Controller::MsgConfigureGS232Controller::match(message)) @@ -127,7 +137,7 @@ void GS232ControllerGUI::onWidgetRolled(QWidget* widget, bool rollDown) { (void) widget; (void) rollDown; - saveState(m_rollupState); + getRollupContents()->saveState(m_rollupState); applySettings(); } @@ -140,16 +150,18 @@ GS232ControllerGUI::GS232ControllerGUI(PluginAPI* pluginAPI, FeatureUISet *featu m_lastFeatureState(0), m_lastOnTarget(false) { - ui->setupUi(this); - m_helpURL = "plugins/feature/gs232controller/readme.md"; + m_feature = feature; setAttribute(Qt::WA_DeleteOnClose, true); - setChannelWidget(false); - connect(this, SIGNAL(widgetRolled(QWidget*,bool)), this, SLOT(onWidgetRolled(QWidget*,bool))); + m_helpURL = "plugins/feature/gs232controller/readme.md"; + RollupContents *rollupContents = getRollupContents(); + ui->setupUi(rollupContents); + setSizePolicy(rollupContents->sizePolicy()); + rollupContents->arrangeRollups(); + connect(rollupContents, SIGNAL(widgetRolled(QWidget*,bool)), this, SLOT(onWidgetRolled(QWidget*,bool))); + m_gs232Controller = reinterpret_cast(feature); m_gs232Controller->setMessageQueueToGUI(&m_inputMessageQueue); - m_featureUISet->addRollupWidget(this); - connect(this, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(onMenuDialogCalled(const QPoint &))); connect(getInputMessageQueue(), SIGNAL(messageEnqueued()), this, SLOT(handleInputMessages())); @@ -165,6 +177,7 @@ GS232ControllerGUI::GS232ControllerGUI(PluginAPI* pluginAPI, FeatureUISet *featu displaySettings(); applySettings(true); + makeUIConnections(); } GS232ControllerGUI::~GS232ControllerGUI() @@ -172,6 +185,12 @@ GS232ControllerGUI::~GS232ControllerGUI() delete ui; } +void GS232ControllerGUI::setWorkspaceIndex(int index) +{ + m_settings.m_workspaceIndex = index; + m_feature->setWorkspaceIndex(index); +} + void GS232ControllerGUI::blockApplySettings(bool block) { m_doApplySettings = !block; @@ -181,6 +200,7 @@ void GS232ControllerGUI::displaySettings() { setTitleColor(m_settings.m_rgbColor); setWindowTitle(m_settings.m_title); + setTitle(m_settings.m_title); blockApplySettings(true); ui->azimuth->setValue(m_settings.m_azimuth); ui->elevation->setValue(m_settings.m_elevation); @@ -202,7 +222,7 @@ void GS232ControllerGUI::displaySettings() ui->elevationMin->setValue(m_settings.m_elevationMin); ui->elevationMax->setValue(m_settings.m_elevationMax); ui->tolerance->setValue(m_settings.m_tolerance); - restoreState(m_rollupState); + getRollupContents()->restoreState(m_rollupState); updateConnectionWidgets(); blockApplySettings(false); } @@ -284,31 +304,22 @@ void GS232ControllerGUI::updatePipeList(const QListgetInputMessageQueue()->push(message); } } + +void GS232ControllerGUI::makeUIConnections() +{ + QObject::connect(ui->startStop, &ButtonSwitch::toggled, this, &GS232ControllerGUI::on_startStop_toggled); + QObject::connect(ui->protocol, qOverload(&QComboBox::currentIndexChanged), this, &GS232ControllerGUI::on_protocol_currentIndexChanged); + QObject::connect(ui->connection, qOverload(&QComboBox::currentIndexChanged), this, &GS232ControllerGUI::on_connection_currentIndexChanged); + QObject::connect(ui->serialPort, qOverload(&QComboBox::currentIndexChanged), this, &GS232ControllerGUI::on_serialPort_currentIndexChanged); + QObject::connect(ui->host, &QLineEdit::editingFinished, this, &GS232ControllerGUI::on_host_editingFinished); + QObject::connect(ui->port, qOverload(&QSpinBox::valueChanged), this, &GS232ControllerGUI::on_port_valueChanged); + QObject::connect(ui->baudRate, qOverload(&QComboBox::currentIndexChanged), this, &GS232ControllerGUI::on_baudRate_currentIndexChanged); + QObject::connect(ui->track, &QCheckBox::stateChanged, this, &GS232ControllerGUI::on_track_stateChanged); + QObject::connect(ui->azimuth, qOverload(&QDoubleSpinBox::valueChanged), this, &GS232ControllerGUI::on_azimuth_valueChanged); + QObject::connect(ui->elevation, qOverload(&QDoubleSpinBox::valueChanged), this, &GS232ControllerGUI::on_elevation_valueChanged); + QObject::connect(ui->sources, &QComboBox::currentTextChanged, this, &GS232ControllerGUI::on_sources_currentTextChanged); + QObject::connect(ui->azimuthOffset, qOverload(&QSpinBox::valueChanged), this, &GS232ControllerGUI::on_azimuthOffset_valueChanged); + QObject::connect(ui->elevationOffset, qOverload(&QSpinBox::valueChanged), this, &GS232ControllerGUI::on_elevationOffset_valueChanged); + QObject::connect(ui->azimuthMin, qOverload(&QSpinBox::valueChanged), this, &GS232ControllerGUI::on_azimuthMin_valueChanged); + QObject::connect(ui->azimuthMax, qOverload(&QSpinBox::valueChanged), this, &GS232ControllerGUI::on_azimuthMax_valueChanged); + QObject::connect(ui->elevationMin, qOverload(&QSpinBox::valueChanged), this, &GS232ControllerGUI::on_elevationMin_valueChanged); + QObject::connect(ui->elevationMax, qOverload(&QSpinBox::valueChanged), this, &GS232ControllerGUI::on_elevationMax_valueChanged); + QObject::connect(ui->tolerance, qOverload(&QDoubleSpinBox::valueChanged), this, &GS232ControllerGUI::on_tolerance_valueChanged); +} diff --git a/plugins/feature/gs232controller/gs232controllergui.h b/plugins/feature/gs232controller/gs232controllergui.h index 5ecdd8932..ce3dd8466 100644 --- a/plugins/feature/gs232controller/gs232controllergui.h +++ b/plugins/feature/gs232controller/gs232controllergui.h @@ -45,6 +45,13 @@ public: QByteArray serialize() const; bool deserialize(const QByteArray& data); virtual MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; } + virtual void setWorkspaceIndex(int index); + virtual int getWorkspaceIndex() const { return m_settings.m_workspaceIndex; } + virtual void setGeometryBytes(const QByteArray& blob) { m_settings.m_geometryBytes = blob; } + virtual QByteArray getGeometryBytes() const { return m_settings.m_geometryBytes; } + +protected: + void resizeEvent(QResizeEvent* size); private: Ui::GS232ControllerGUI* ui; @@ -71,9 +78,7 @@ private: void updatePipeList(const QList& sources); void updateSerialPortList(); bool handleMessage(const Message& message); - - void leaveEvent(QEvent*); - void enterEvent(QEvent*); + void makeUIConnections(); private slots: void onMenuDialogCalled(const QPoint &p); diff --git a/plugins/feature/gs232controller/gs232controllergui.ui b/plugins/feature/gs232controller/gs232controllergui.ui index 656be9249..b697bc9eb 100644 --- a/plugins/feature/gs232controller/gs232controllergui.ui +++ b/plugins/feature/gs232controller/gs232controllergui.ui @@ -1,7 +1,7 @@ GS232ControllerGUI - + 0 @@ -11,7 +11,7 @@ - + 0 0 @@ -24,7 +24,7 @@ - 360 + 560 16777215 @@ -542,9 +542,9 @@ - RollupWidget + RollupContents QWidget -
gui/rollupwidget.h
+
gui/rollupcontents.h
1
diff --git a/plugins/feature/gs232controller/gs232controllersettings.cpp b/plugins/feature/gs232controller/gs232controllersettings.cpp index 0e9f3d756..fd9a34278 100644 --- a/plugins/feature/gs232controller/gs232controllersettings.cpp +++ b/plugins/feature/gs232controller/gs232controllersettings.cpp @@ -69,6 +69,7 @@ void GS232ControllerSettings::resetToDefaults() m_connection = SERIAL; m_host = "127.0.0.1"; m_port = 4533; + m_workspaceIndex = 0; } QByteArray GS232ControllerSettings::serialize() const @@ -104,6 +105,9 @@ QByteArray GS232ControllerSettings::serialize() const s.writeBlob(26, m_rollupState->serialize()); } + s.writeS32(27, m_workspaceIndex); + s.writeBlob(28, m_geometryBytes); + return s.final(); } @@ -163,6 +167,9 @@ bool GS232ControllerSettings::deserialize(const QByteArray& data) m_rollupState->deserialize(bytetmp); } + d.readS32(27, &m_workspaceIndex, 0); + d.readBlob(28, &m_geometryBytes); + return true; } else diff --git a/plugins/feature/gs232controller/gs232controllersettings.h b/plugins/feature/gs232controller/gs232controllersettings.h index f922022f8..3db11f2ce 100644 --- a/plugins/feature/gs232controller/gs232controllersettings.h +++ b/plugins/feature/gs232controller/gs232controllersettings.h @@ -68,6 +68,8 @@ struct GS232ControllerSettings uint16_t m_reverseAPIPort; uint16_t m_reverseAPIFeatureSetIndex; uint16_t m_reverseAPIFeatureIndex; + int m_workspaceIndex; + QByteArray m_geometryBytes; GS232ControllerSettings(); void resetToDefaults(); diff --git a/plugins/feature/jogdialcontroller/jogdialcontrollergui.cpp b/plugins/feature/jogdialcontroller/jogdialcontrollergui.cpp index 12afa2009..ece4480c9 100644 --- a/plugins/feature/jogdialcontroller/jogdialcontrollergui.cpp +++ b/plugins/feature/jogdialcontroller/jogdialcontrollergui.cpp @@ -17,6 +17,7 @@ #include #include +#include #include "feature/featureuiset.h" #include "gui/basicfeaturesettingsdialog.h" @@ -55,6 +56,7 @@ bool JogdialControllerGUI::deserialize(const QByteArray& data) { if (m_settings.deserialize(data)) { + m_feature->setWorkspaceIndex(m_settings.m_workspaceIndex); displaySettings(); applySettings(true); return true; @@ -66,6 +68,14 @@ bool JogdialControllerGUI::deserialize(const QByteArray& data) } } +void JogdialControllerGUI::resizeEvent(QResizeEvent* size) +{ + int maxWidth = getRollupContents()->maximumWidth(); + int minHeight = getRollupContents()->minimumHeight() + getAdditionalHeight(); + resize(width() < maxWidth ? width() : maxWidth, minHeight); + size->accept(); +} + bool JogdialControllerGUI::handleMessage(const Message& message) { if (JogdialController::MsgConfigureJogdialController::match(message)) @@ -132,7 +142,7 @@ void JogdialControllerGUI::onWidgetRolled(QWidget* widget, bool rollDown) (void) widget; (void) rollDown; - saveState(m_rollupState); + getRollupContents()->saveState(m_rollupState); applySettings(); } @@ -145,17 +155,18 @@ JogdialControllerGUI::JogdialControllerGUI(PluginAPI* pluginAPI, FeatureUISet *f m_lastFeatureState(0), m_selectedChannel(nullptr) { - ui->setupUi(this); - m_helpURL = "plugins/feature/jogdialcontroller/readme.md"; + m_feature = feature; setAttribute(Qt::WA_DeleteOnClose, true); - setChannelWidget(false); - connect(this, SIGNAL(widgetRolled(QWidget*,bool)), this, SLOT(onWidgetRolled(QWidget*,bool))); + m_helpURL = "plugins/feature/jogdialcontroller/readme.md"; + RollupContents *rollupContents = getRollupContents(); + ui->setupUi(rollupContents); + setSizePolicy(rollupContents->sizePolicy()); + rollupContents->arrangeRollups(); + connect(rollupContents, SIGNAL(widgetRolled(QWidget*,bool)), this, SLOT(onWidgetRolled(QWidget*,bool))); m_jogdialController = reinterpret_cast(feature); m_jogdialController->setMessageQueueToGUI(&m_inputMessageQueue); - m_featureUISet->addRollupWidget(this); - connect(this, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(onMenuDialogCalled(const QPoint &))); connect(getInputMessageQueue(), SIGNAL(messageEnqueued()), this, SLOT(handleInputMessages())); @@ -169,6 +180,7 @@ JogdialControllerGUI::JogdialControllerGUI(PluginAPI* pluginAPI, FeatureUISet *f displaySettings(); applySettings(true); + makeUIConnections(); } JogdialControllerGUI::~JogdialControllerGUI() @@ -176,6 +188,12 @@ JogdialControllerGUI::~JogdialControllerGUI() delete ui; } +void JogdialControllerGUI::setWorkspaceIndex(int index) +{ + m_settings.m_workspaceIndex = index; + m_feature->setWorkspaceIndex(index); +} + void JogdialControllerGUI::blockApplySettings(bool block) { m_doApplySettings = !block; @@ -185,8 +203,9 @@ void JogdialControllerGUI::displaySettings() { setTitleColor(m_settings.m_rgbColor); setWindowTitle(m_settings.m_title); + setTitle(m_settings.m_title); blockApplySettings(true); - restoreState(m_rollupState); + getRollupContents()->restoreState(m_rollupState); blockApplySettings(false); } @@ -229,31 +248,22 @@ void JogdialControllerGUI::updateChannelList() } } -void JogdialControllerGUI::leaveEvent(QEvent*) -{ -} - -void JogdialControllerGUI::enterEvent(QEvent*) -{ -} - void JogdialControllerGUI::onMenuDialogCalled(const QPoint &p) { if (m_contextMenuType == ContextMenuChannelSettings) { BasicFeatureSettingsDialog dialog(this); dialog.setTitle(m_settings.m_title); - dialog.setColor(m_settings.m_rgbColor); dialog.setUseReverseAPI(m_settings.m_useReverseAPI); dialog.setReverseAPIAddress(m_settings.m_reverseAPIAddress); dialog.setReverseAPIPort(m_settings.m_reverseAPIPort); dialog.setReverseAPIFeatureSetIndex(m_settings.m_reverseAPIFeatureSetIndex); dialog.setReverseAPIFeatureIndex(m_settings.m_reverseAPIFeatureIndex); + dialog.setDefaultTitle(m_displayedName); dialog.move(p); dialog.exec(); - m_settings.m_rgbColor = dialog.getColor().rgb(); m_settings.m_title = dialog.getTitle(); m_settings.m_useReverseAPI = dialog.useReverseAPI(); m_settings.m_reverseAPIAddress = dialog.getReverseAPIAddress(); @@ -261,7 +271,7 @@ void JogdialControllerGUI::onMenuDialogCalled(const QPoint &p) m_settings.m_reverseAPIFeatureSetIndex = dialog.getReverseAPIFeatureSetIndex(); m_settings.m_reverseAPIFeatureIndex = dialog.getReverseAPIFeatureIndex(); - setWindowTitle(m_settings.m_title); + setTitle(m_settings.m_title); setTitleColor(m_settings.m_rgbColor); applySettings(); @@ -362,3 +372,10 @@ void JogdialControllerGUI::focusOutEvent(QFocusEvent*) ui->focusIndicator->setStyleSheet("QLabel { background-color: gray; border-radius: 8px; }"); // gray ui->focusIndicator->setToolTip("Idle"); } + +void JogdialControllerGUI::makeUIConnections() +{ + QObject::connect(ui->startStop, &ButtonSwitch::toggled, this, &JogdialControllerGUI::on_startStop_toggled); + QObject::connect(ui->devicesRefresh, &QPushButton::clicked, this, &JogdialControllerGUI::on_devicesRefresh_clicked); + QObject::connect(ui->channels, qOverload(&QComboBox::currentIndexChanged), this, &JogdialControllerGUI::on_channels_currentIndexChanged); +} diff --git a/plugins/feature/jogdialcontroller/jogdialcontrollergui.h b/plugins/feature/jogdialcontroller/jogdialcontrollergui.h index a6b680ceb..8569190f0 100644 --- a/plugins/feature/jogdialcontroller/jogdialcontrollergui.h +++ b/plugins/feature/jogdialcontroller/jogdialcontrollergui.h @@ -47,10 +47,15 @@ public: QByteArray serialize() const; bool deserialize(const QByteArray& data); virtual MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; } + virtual void setWorkspaceIndex(int index); + virtual int getWorkspaceIndex() const { return m_settings.m_workspaceIndex; } + virtual void setGeometryBytes(const QByteArray& blob) { m_settings.m_geometryBytes = blob; } + virtual QByteArray getGeometryBytes() const { return m_settings.m_geometryBytes; } protected: void focusInEvent(QFocusEvent* e); void focusOutEvent(QFocusEvent *e); + void resizeEvent(QResizeEvent* size); private: Ui::JogdialControllerGUI* ui; @@ -76,9 +81,7 @@ private: void displaySettings(); void updateChannelList(); bool handleMessage(const Message& message); - - void leaveEvent(QEvent*); - void enterEvent(QEvent*); + void makeUIConnections(); private slots: void onMenuDialogCalled(const QPoint &p); diff --git a/plugins/feature/jogdialcontroller/jogdialcontrollergui.ui b/plugins/feature/jogdialcontroller/jogdialcontrollergui.ui index 5b9a8e687..01211f584 100644 --- a/plugins/feature/jogdialcontroller/jogdialcontrollergui.ui +++ b/plugins/feature/jogdialcontroller/jogdialcontrollergui.ui @@ -1,25 +1,31 @@ JogdialControllerGUI - + 0 0 - 365 - 105 + 370 + 60 - + 0 0 - 340 - 100 + 360 + 60 + + + + + 370 + 16777215 @@ -37,9 +43,15 @@ 0 0 360 - 81 + 51 + + + 0 + 0 + + 360 @@ -172,38 +184,21 @@
- - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - -
- - RollupWidget - QWidget -
gui/rollupwidget.h
- 1 -
ButtonSwitch QToolButton
gui/buttonswitch.h
+ + RollupContents + QWidget +
gui/rollupcontents.h
+ 1 +
diff --git a/plugins/feature/jogdialcontroller/jogdialcontrollersettings.cpp b/plugins/feature/jogdialcontroller/jogdialcontrollersettings.cpp index 8893cbe5e..01900a482 100644 --- a/plugins/feature/jogdialcontroller/jogdialcontrollersettings.cpp +++ b/plugins/feature/jogdialcontroller/jogdialcontrollersettings.cpp @@ -71,6 +71,7 @@ void JogdialControllerSettings::resetToDefaults() m_reverseAPIPort = 8888; m_reverseAPIFeatureSetIndex = 0; m_reverseAPIFeatureIndex = 0; + m_workspaceIndex = 0; } QByteArray JogdialControllerSettings::serialize() const @@ -89,6 +90,9 @@ QByteArray JogdialControllerSettings::serialize() const s.writeBlob(12, m_rollupState->serialize()); } + s.writeS32(13, m_workspaceIndex); + s.writeBlob(14, m_geometryBytes); + return s.final(); } @@ -131,6 +135,9 @@ bool JogdialControllerSettings::deserialize(const QByteArray& data) m_rollupState->deserialize(bytetmp); } + d.readS32(13, &m_workspaceIndex, 0); + d.readBlob(14, &m_geometryBytes); + return true; } else diff --git a/plugins/feature/jogdialcontroller/jogdialcontrollersettings.h b/plugins/feature/jogdialcontroller/jogdialcontrollersettings.h index 5d1b82773..fecb052a4 100644 --- a/plugins/feature/jogdialcontroller/jogdialcontrollersettings.h +++ b/plugins/feature/jogdialcontroller/jogdialcontrollersettings.h @@ -52,6 +52,8 @@ struct JogdialControllerSettings uint16_t m_reverseAPIFeatureSetIndex; uint16_t m_reverseAPIFeatureIndex; Serializable *m_rollupState; + int m_workspaceIndex; + QByteArray m_geometryBytes; JogdialControllerSettings(); void resetToDefaults(); diff --git a/plugins/feature/map/map.cpp b/plugins/feature/map/map.cpp index 259ca4dfd..b7f2a66c1 100644 --- a/plugins/feature/map/map.cpp +++ b/plugins/feature/map/map.cpp @@ -110,7 +110,7 @@ bool Map::handleMessage(const Message& cmd) } else if (MainCore::MsgMapItem::match(cmd)) { - qDebug() << "Map::handleMessage: MsgMapItem"; + // qDebug() << "Map::handleMessage: MsgMapItem"; MainCore::MsgMapItem& msgMapItem = (MainCore::MsgMapItem&) cmd; MainCore::MsgMapItem *copy = new MainCore::MsgMapItem(msgMapItem); getMessageQueueToGUI()->push(copy); diff --git a/plugins/feature/map/mapgui.cpp b/plugins/feature/map/mapgui.cpp index c344eb856..56ad80f9e 100644 --- a/plugins/feature/map/mapgui.cpp +++ b/plugins/feature/map/mapgui.cpp @@ -72,6 +72,7 @@ bool MapGUI::deserialize(const QByteArray& data) { if (m_settings.deserialize(data)) { + m_feature->setWorkspaceIndex(m_settings.m_workspaceIndex); displaySettings(); applySettings(true); return true; @@ -162,7 +163,18 @@ void MapGUI::onWidgetRolled(QWidget* widget, bool rollDown) (void) widget; (void) rollDown; - saveState(m_rollupState); + RollupContents *rollupContents = getRollupContents(); + + if (rollupContents->hasExpandableWidgets()) { + setSizePolicy(sizePolicy().horizontalPolicy(), QSizePolicy::Expanding); + } else { + setSizePolicy(sizePolicy().horizontalPolicy(), QSizePolicy::Fixed); + } + + int h = rollupContents->height() + getAdditionalHeight(); + resize(width(), h); + + rollupContents->saveState(m_rollupState); applySettings(); } @@ -179,8 +191,14 @@ MapGUI::MapGUI(PluginAPI* pluginAPI, FeatureUISet *featureUISet, Feature *featur m_radioTimeDialog(this), m_cesium(nullptr) { - ui->setupUi(this); + m_feature = feature; + setAttribute(Qt::WA_DeleteOnClose, true); m_helpURL = "plugins/feature/map/readme.md"; + RollupContents *rollupContents = getRollupContents(); + ui->setupUi(rollupContents); + setSizePolicy(rollupContents->sizePolicy()); + rollupContents->arrangeRollups(); + connect(rollupContents, SIGNAL(widgetRolled(QWidget*,bool)), this, SLOT(onWidgetRolled(QWidget*,bool))); m_osmPort = 0; m_templateServer = new OSMTemplateServer(thunderforestAPIKey(), maptilerAPIKey(), m_osmPort); @@ -200,13 +218,9 @@ MapGUI::MapGUI(PluginAPI* pluginAPI, FeatureUISet *featureUISet, Feature *featur m_settings.m_modelURL = QString("http://127.0.0.1:%1/3d/").arg(m_webPort); m_webServer->addPathSubstitution("3d", m_settings.m_modelDir); - setAttribute(Qt::WA_DeleteOnClose, true); - setChannelWidget(false); - connect(this, SIGNAL(widgetRolled(QWidget*,bool)), this, SLOT(onWidgetRolled(QWidget*,bool))); m_map = reinterpret_cast(feature); m_map->setMessageQueueToGUI(&m_inputMessageQueue); - m_featureUISet->addRollupWidget(this); m_settings.setRollupState(&m_rollupState); connect(this, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(onMenuDialogCalled(const QPoint &))); @@ -268,6 +282,8 @@ MapGUI::MapGUI(PluginAPI* pluginAPI, FeatureUISet *featureUISet, Feature *featur connect(&m_redrawMapTimer, &QTimer::timeout, this, &MapGUI::redrawMap); m_redrawMapTimer.setSingleShot(true); ui->map->installEventFilter(this); + + makeUIConnections(); } MapGUI::~MapGUI() @@ -289,6 +305,12 @@ MapGUI::~MapGUI() delete ui; } +void MapGUI::setWorkspaceIndex(int index) +{ + m_settings.m_workspaceIndex = index; + m_feature->setWorkspaceIndex(index); +} + // Update a map item or image void MapGUI::update(const QObject *source, SWGSDRangel::SWGMapItem *swgMapItem, const QString &group) { @@ -847,6 +869,7 @@ void MapGUI::displaySettings() { setTitleColor(m_settings.m_rgbColor); setWindowTitle(m_settings.m_title); + setTitle(m_settings.m_title); blockApplySettings(true); ui->displayNames->setChecked(m_settings.m_displayNames); ui->displaySelectedGroundTracks->setChecked(m_settings.m_displaySelectedGroundTracks); @@ -857,35 +880,26 @@ void MapGUI::displaySettings() m_mapModel.updateItemSettings(m_settings.m_itemSettings); applyMap2DSettings(true); applyMap3DSettings(true); - restoreState(m_rollupState); + getRollupContents()->restoreState(m_rollupState); blockApplySettings(false); } -void MapGUI::leaveEvent(QEvent*) -{ -} - -void MapGUI::enterEvent(QEvent*) -{ -} - void MapGUI::onMenuDialogCalled(const QPoint &p) { if (m_contextMenuType == ContextMenuChannelSettings) { BasicFeatureSettingsDialog dialog(this); dialog.setTitle(m_settings.m_title); - dialog.setColor(m_settings.m_rgbColor); dialog.setUseReverseAPI(m_settings.m_useReverseAPI); dialog.setReverseAPIAddress(m_settings.m_reverseAPIAddress); dialog.setReverseAPIPort(m_settings.m_reverseAPIPort); dialog.setReverseAPIFeatureSetIndex(m_settings.m_reverseAPIFeatureSetIndex); dialog.setReverseAPIFeatureIndex(m_settings.m_reverseAPIFeatureIndex); + dialog.setDefaultTitle(m_displayedName); dialog.move(p); dialog.exec(); - m_settings.m_rgbColor = dialog.getColor().rgb(); m_settings.m_title = dialog.getTitle(); m_settings.m_useReverseAPI = dialog.useReverseAPI(); m_settings.m_reverseAPIAddress = dialog.getReverseAPIAddress(); @@ -893,7 +907,7 @@ void MapGUI::onMenuDialogCalled(const QPoint &p) m_settings.m_reverseAPIFeatureSetIndex = dialog.getReverseAPIFeatureSetIndex(); m_settings.m_reverseAPIFeatureIndex = dialog.getReverseAPIFeatureIndex(); - setWindowTitle(m_settings.m_title); + setTitle(m_settings.m_title); setTitleColor(m_settings.m_rgbColor); applySettings(); @@ -1214,3 +1228,18 @@ void MapGUI::preferenceChanged(int elementType) update(m_map, &m_antennaMapItem, "Station"); } } + +void MapGUI::makeUIConnections() +{ + QObject::connect(ui->displayNames, &ButtonSwitch::clicked, this, &MapGUI::on_displayNames_clicked); + QObject::connect(ui->displayAllGroundTracks, &ButtonSwitch::clicked, this, &MapGUI::on_displayAllGroundTracks_clicked); + QObject::connect(ui->displaySelectedGroundTracks, &ButtonSwitch::clicked, this, &MapGUI::on_displaySelectedGroundTracks_clicked); + QObject::connect(ui->find, &QLineEdit::returnPressed, this, &MapGUI::on_find_returnPressed); + QObject::connect(ui->maidenhead, &QToolButton::clicked, this, &MapGUI::on_maidenhead_clicked); + QObject::connect(ui->deleteAll, &QToolButton::clicked, this, &MapGUI::on_deleteAll_clicked); + QObject::connect(ui->displaySettings, &QToolButton::clicked, this, &MapGUI::on_displaySettings_clicked); + QObject::connect(ui->mapTypes, qOverload(&QComboBox::currentIndexChanged), this, &MapGUI::on_mapTypes_currentIndexChanged); + QObject::connect(ui->beacons, &QToolButton::clicked, this, &MapGUI::on_beacons_clicked); + QObject::connect(ui->ibpBeacons, &QToolButton::clicked, this, &MapGUI::on_ibpBeacons_clicked); + QObject::connect(ui->radiotime, &QToolButton::clicked, this, &MapGUI::on_radiotime_clicked); +} diff --git a/plugins/feature/map/mapgui.h b/plugins/feature/map/mapgui.h index 96cbf2c2b..4a2d29a2c 100644 --- a/plugins/feature/map/mapgui.h +++ b/plugins/feature/map/mapgui.h @@ -72,6 +72,10 @@ public: QByteArray serialize() const; bool deserialize(const QByteArray& data); virtual MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; } + virtual void setWorkspaceIndex(int index); + virtual int getWorkspaceIndex() const { return m_settings.m_workspaceIndex; } + virtual void setGeometryBytes(const QByteArray& blob) { m_settings.m_geometryBytes = blob; } + virtual QByteArray getGeometryBytes() const { return m_settings.m_geometryBytes; } AzEl *getAzEl() { return &m_azEl; } Map *getMap() { return m_map; } QQuickItem *getMapItem(); @@ -132,9 +136,7 @@ private: QString maptilerAPIKey() const; QString cesiumIonAPIKey() const; void redrawMap(); - - void leaveEvent(QEvent*); - void enterEvent(QEvent*); + void makeUIConnections(); static QString getDataDir(); static const QList m_radioTimeTransmitters; diff --git a/plugins/feature/map/mapgui.ui b/plugins/feature/map/mapgui.ui index c0596d44a..70834ba70 100644 --- a/plugins/feature/map/mapgui.ui +++ b/plugins/feature/map/mapgui.ui @@ -1,7 +1,7 @@ MapGUI - + 0 @@ -339,7 +339,7 @@ - + 0 @@ -365,9 +365,9 @@
QtQuickWidgets/QQuickWidget
- RollupWidget + QWebEngineView QWidget -
gui/rollupwidget.h
+
QtWebEngineWidgets/QWebEngineView
1
@@ -376,9 +376,9 @@
gui/buttonswitch.h
- QWebEngineView + RollupContents QWidget -
QWebEngineView
+
gui/rollupcontents.h
1
diff --git a/plugins/feature/map/mapsettings.cpp b/plugins/feature/map/mapsettings.cpp index 732e58502..8df0b3501 100644 --- a/plugins/feature/map/mapsettings.cpp +++ b/plugins/feature/map/mapsettings.cpp @@ -106,6 +106,7 @@ void MapSettings::resetToDefaults() m_eciCamera = false; m_modelDir = HttpDownloadManager::downloadDir() + "/3d"; m_antiAliasing = "None"; + m_workspaceIndex = 0; } QByteArray MapSettings::serialize() const @@ -144,6 +145,8 @@ QByteArray MapSettings::serialize() const s.writeBool(30, m_eciCamera); s.writeString(31, m_cesiumIonAPIKey); s.writeString(32, m_antiAliasing); + s.writeS32(33, m_workspaceIndex); + s.writeBlob(34, m_geometryBytes); return s.final(); } @@ -210,6 +213,8 @@ bool MapSettings::deserialize(const QByteArray& data) d.readBool(30, &m_eciCamera, false); d.readString(31, &m_cesiumIonAPIKey, ""); d.readString(32, &m_antiAliasing, "None"); + d.readS32(33, &m_workspaceIndex, 0); + d.readBlob(34, &m_geometryBytes); return true; } diff --git a/plugins/feature/map/mapsettings.h b/plugins/feature/map/mapsettings.h index e190f770a..7ce04b65f 100644 --- a/plugins/feature/map/mapsettings.h +++ b/plugins/feature/map/mapsettings.h @@ -90,6 +90,8 @@ struct MapSettings Serializable *m_rollupState; bool m_map2DEnabled; QString m_mapType; // "Street Map", "Satellite Map", etc.. as selected in combobox + int m_workspaceIndex; + QByteArray m_geometryBytes; // 3D Map settings bool m_map3DEnabled; diff --git a/plugins/feature/pertester/pertestergui.cpp b/plugins/feature/pertester/pertestergui.cpp index cc3083931..3f24c5ca0 100644 --- a/plugins/feature/pertester/pertestergui.cpp +++ b/plugins/feature/pertester/pertestergui.cpp @@ -19,6 +19,7 @@ #include #include #include +#include #include "feature/featureuiset.h" #include "gui/basicfeaturesettingsdialog.h" @@ -57,6 +58,7 @@ bool PERTesterGUI::deserialize(const QByteArray& data) { if (m_settings.deserialize(data)) { + m_feature->setWorkspaceIndex(m_settings.m_workspaceIndex); displaySettings(); applySettings(true); return true; @@ -68,6 +70,14 @@ bool PERTesterGUI::deserialize(const QByteArray& data) } } +void PERTesterGUI::resizeEvent(QResizeEvent* size) +{ + int maxWidth = getRollupContents()->maximumWidth(); + int minHeight = getRollupContents()->minimumHeight() + getAdditionalHeight(); + resize(width() < maxWidth ? width() : maxWidth, minHeight); + size->accept(); +} + bool PERTesterGUI::handleMessage(const Message& message) { if (PERTester::MsgConfigurePERTester::match(message)) @@ -114,7 +124,7 @@ void PERTesterGUI::onWidgetRolled(QWidget* widget, bool rollDown) (void) widget; (void) rollDown; - saveState(m_rollupState); + getRollupContents()->saveState(m_rollupState); applySettings(); } @@ -126,15 +136,18 @@ PERTesterGUI::PERTesterGUI(PluginAPI* pluginAPI, FeatureUISet *featureUISet, Fea m_doApplySettings(true), m_lastFeatureState(0) { - ui->setupUi(this); - m_helpURL = "plugins/feature/pertester/readme.md"; + m_feature = feature; setAttribute(Qt::WA_DeleteOnClose, true); - setChannelWidget(false); - connect(this, SIGNAL(widgetRolled(QWidget*,bool)), this, SLOT(onWidgetRolled(QWidget*,bool))); + m_helpURL = "plugins/feature/pertester/readme.md"; + RollupContents *rollupContents = getRollupContents(); + ui->setupUi(rollupContents); + setSizePolicy(rollupContents->sizePolicy()); + rollupContents->arrangeRollups(); + connect(rollupContents, SIGNAL(widgetRolled(QWidget*,bool)), this, SLOT(onWidgetRolled(QWidget*,bool))); + m_perTester = reinterpret_cast(feature); m_perTester->setMessageQueueToGUI(&m_inputMessageQueue); - m_featureUISet->addRollupWidget(this); m_settings.setRollupState(&m_rollupState); connect(this, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(onMenuDialogCalled(const QPoint &))); @@ -145,6 +158,7 @@ PERTesterGUI::PERTesterGUI(PluginAPI* pluginAPI, FeatureUISet *featureUISet, Fea displaySettings(); applySettings(true); + makeUIConnections(); } PERTesterGUI::~PERTesterGUI() @@ -152,6 +166,12 @@ PERTesterGUI::~PERTesterGUI() delete ui; } +void PERTesterGUI::setWorkspaceIndex(int index) +{ + m_settings.m_workspaceIndex = index; + m_feature->setWorkspaceIndex(index); +} + void PERTesterGUI::blockApplySettings(bool block) { m_doApplySettings = !block; @@ -161,6 +181,7 @@ void PERTesterGUI::displaySettings() { setTitleColor(m_settings.m_rgbColor); setWindowTitle(m_settings.m_title); + setTitle(m_settings.m_title); blockApplySettings(true); ui->packetCount->setValue(m_settings.m_packetCount); ui->start->setCurrentIndex((int)m_settings.m_start); @@ -175,17 +196,9 @@ void PERTesterGUI::displaySettings() ui->txUDPPort->setText(QString::number(m_settings.m_txUDPPort)); ui->rxUDPAddress->setText(m_settings.m_rxUDPAddress); ui->rxUDPPort->setText(QString::number(m_settings.m_rxUDPPort)); - restoreState(m_rollupState); + getRollupContents()->restoreState(m_rollupState); blockApplySettings(false); - arrangeRollups(); -} - -void PERTesterGUI::leaveEvent(QEvent*) -{ -} - -void PERTesterGUI::enterEvent(QEvent*) -{ + getRollupContents()->arrangeRollups(); } void PERTesterGUI::onMenuDialogCalled(const QPoint &p) @@ -194,17 +207,16 @@ void PERTesterGUI::onMenuDialogCalled(const QPoint &p) { BasicFeatureSettingsDialog dialog(this); dialog.setTitle(m_settings.m_title); - dialog.setColor(m_settings.m_rgbColor); dialog.setUseReverseAPI(m_settings.m_useReverseAPI); dialog.setReverseAPIAddress(m_settings.m_reverseAPIAddress); dialog.setReverseAPIPort(m_settings.m_reverseAPIPort); dialog.setReverseAPIFeatureSetIndex(m_settings.m_reverseAPIFeatureSetIndex); dialog.setReverseAPIFeatureIndex(m_settings.m_reverseAPIFeatureIndex); + dialog.setDefaultTitle(m_displayedName); dialog.move(p); dialog.exec(); - m_settings.m_rgbColor = dialog.getColor().rgb(); m_settings.m_title = dialog.getTitle(); m_settings.m_useReverseAPI = dialog.useReverseAPI(); m_settings.m_reverseAPIAddress = dialog.getReverseAPIAddress(); @@ -212,7 +224,7 @@ void PERTesterGUI::onMenuDialogCalled(const QPoint &p) m_settings.m_reverseAPIFeatureSetIndex = dialog.getReverseAPIFeatureSetIndex(); m_settings.m_reverseAPIFeatureIndex = dialog.getReverseAPIFeatureIndex(); - setWindowTitle(m_settings.m_title); + setTitle(m_settings.m_title); setTitleColor(m_settings.m_rgbColor); applySettings(); @@ -251,7 +263,7 @@ void PERTesterGUI::on_start_currentIndexChanged(int index) ui->satellites->setVisible(m_settings.m_start != PERTesterSettings::START_IMMEDIATELY); ui->satellitesLabel->setVisible(m_settings.m_start != PERTesterSettings::START_IMMEDIATELY); applySettings(); - arrangeRollups(); + getRollupContents()->arrangeRollups(); } void PERTesterGUI::on_satellites_editingFinished() @@ -353,3 +365,20 @@ void PERTesterGUI::applySettings(bool force) m_perTester->getInputMessageQueue()->push(message); } } + +void PERTesterGUI::makeUIConnections() +{ + QObject::connect(ui->startStop, &ButtonSwitch::toggled, this, &PERTesterGUI::on_startStop_toggled); + QObject::connect(ui->resetStats, &QToolButton::clicked, this, &PERTesterGUI::on_resetStats_clicked); + QObject::connect(ui->packetCount, qOverload(&QSpinBox::valueChanged), this, &PERTesterGUI::on_packetCount_valueChanged); + QObject::connect(ui->start, qOverload(&QComboBox::currentIndexChanged), this, &PERTesterGUI::on_start_currentIndexChanged); + QObject::connect(ui->satellites, &QLineEdit::editingFinished, this, &PERTesterGUI::on_satellites_editingFinished); + QObject::connect(ui->interval, qOverload(&QDoubleSpinBox::valueChanged), this, &PERTesterGUI::on_interval_valueChanged); + QObject::connect(ui->packet, &QPlainTextEdit::textChanged, this, &PERTesterGUI::on_packet_textChanged); + QObject::connect(ui->leading, qOverload(&QSpinBox::valueChanged), this, &PERTesterGUI::on_leading_valueChanged); + QObject::connect(ui->trailing, qOverload(&QSpinBox::valueChanged), this, &PERTesterGUI::on_trailing_valueChanged); + QObject::connect(ui->txUDPAddress, &QLineEdit::editingFinished, this, &PERTesterGUI::on_txUDPAddress_editingFinished); + QObject::connect(ui->txUDPPort, &QLineEdit::editingFinished, this, &PERTesterGUI::on_txUDPPort_editingFinished); + QObject::connect(ui->rxUDPAddress, &QLineEdit::editingFinished, this, &PERTesterGUI::on_rxUDPAddress_editingFinished); + QObject::connect(ui->rxUDPPort, &QLineEdit::editingFinished, this, &PERTesterGUI::on_rxUDPPort_editingFinished); +} diff --git a/plugins/feature/pertester/pertestergui.h b/plugins/feature/pertester/pertestergui.h index 26f26e585..af3a67bb0 100644 --- a/plugins/feature/pertester/pertestergui.h +++ b/plugins/feature/pertester/pertestergui.h @@ -45,6 +45,13 @@ public: QByteArray serialize() const; bool deserialize(const QByteArray& data); virtual MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; } + virtual void setWorkspaceIndex(int index); + virtual int getWorkspaceIndex() const { return m_settings.m_workspaceIndex; } + virtual void setGeometryBytes(const QByteArray& blob) { m_settings.m_geometryBytes = blob; } + virtual QByteArray getGeometryBytes() const { return m_settings.m_geometryBytes; } + +protected: + void resizeEvent(QResizeEvent* size); private: Ui::PERTesterGUI* ui; @@ -66,9 +73,7 @@ private: void applySettings(bool force = false); void displaySettings(); bool handleMessage(const Message& message); - - void leaveEvent(QEvent*); - void enterEvent(QEvent*); + void makeUIConnections(); private slots: void onMenuDialogCalled(const QPoint &p); diff --git a/plugins/feature/pertester/pertestergui.ui b/plugins/feature/pertester/pertestergui.ui index ff1e2d391..f2917bf2b 100644 --- a/plugins/feature/pertester/pertestergui.ui +++ b/plugins/feature/pertester/pertestergui.ui @@ -1,30 +1,30 @@ PERTesterGUI - + 0 0 - 350 - 430 + 360 + 477 - + 0 0 - 320 - 100 + 360 + 0 - 350 + 600 16777215 @@ -35,17 +35,23 @@
- GS-232 Rotator Controller + Packet Error Rate Tester - 10 - 10 - 331 - 291 + 2 + 2 + 351 + 341 + + + 0 + 0 + + Settings @@ -157,6 +163,12 @@
+ + + 0 + 0 + + Packets @@ -456,10 +468,10 @@ Substitutions: - 10 - 310 - 331 - 91 + 2 + 352 + 351 + 117 @@ -554,17 +566,17 @@ Substitutions: - - RollupWidget - QWidget -
gui/rollupwidget.h
- 1 -
ButtonSwitch QToolButton
gui/buttonswitch.h
+ + RollupContents + QWidget +
gui/rollupcontents.h
+ 1 +
startStop diff --git a/plugins/feature/pertester/pertestersettings.cpp b/plugins/feature/pertester/pertestersettings.cpp index 7499902d4..0121b1d8d 100644 --- a/plugins/feature/pertester/pertestersettings.cpp +++ b/plugins/feature/pertester/pertestersettings.cpp @@ -50,6 +50,7 @@ void PERTesterSettings::resetToDefaults() m_reverseAPIPort = 8888; m_reverseAPIFeatureSetIndex = 0; m_reverseAPIFeatureIndex = 0; + m_workspaceIndex = 0; } QByteArray PERTesterSettings::serialize() const @@ -78,6 +79,8 @@ QByteArray PERTesterSettings::serialize() const s.writeBlob(27, m_rollupState->serialize()); } + s.writeS32(28, m_workspaceIndex); + return s.final(); } @@ -146,6 +149,9 @@ bool PERTesterSettings::deserialize(const QByteArray& data) m_rollupState->deserialize(bytetmp); } + d.readS32(28, &m_workspaceIndex, 0); + d.readBlob(29, &m_geometryBytes); + return true; } else diff --git a/plugins/feature/pertester/pertestersettings.h b/plugins/feature/pertester/pertestersettings.h index ea2cfcc83..119aebbcd 100644 --- a/plugins/feature/pertester/pertestersettings.h +++ b/plugins/feature/pertester/pertestersettings.h @@ -48,6 +48,8 @@ struct PERTesterSettings uint16_t m_reverseAPIFeatureSetIndex; uint16_t m_reverseAPIFeatureIndex; Serializable *m_rollupState; + int m_workspaceIndex; + QByteArray m_geometryBytes; PERTesterSettings(); void resetToDefaults(); diff --git a/plugins/feature/radiosonde/radiosondegui.cpp b/plugins/feature/radiosonde/radiosondegui.cpp index 871d02a27..c4b1af7a6 100644 --- a/plugins/feature/radiosonde/radiosondegui.cpp +++ b/plugins/feature/radiosonde/radiosondegui.cpp @@ -63,6 +63,7 @@ bool RadiosondeGUI::deserialize(const QByteArray& data) { if (m_settings.deserialize(data)) { + m_feature->setWorkspaceIndex(m_settings.m_workspaceIndex); displaySettings(); applySettings(true); return true; @@ -117,7 +118,18 @@ void RadiosondeGUI::onWidgetRolled(QWidget* widget, bool rollDown) (void) widget; (void) rollDown; - saveState(m_rollupState); + RollupContents *rollupContents = getRollupContents(); + + if (rollupContents->hasExpandableWidgets()) { + setSizePolicy(sizePolicy().horizontalPolicy(), QSizePolicy::Expanding); + } else { + setSizePolicy(sizePolicy().horizontalPolicy(), QSizePolicy::Fixed); + } + + int h = rollupContents->height() + getAdditionalHeight(); + resize(width(), h); + + rollupContents->saveState(m_rollupState); applySettings(); } @@ -129,16 +141,18 @@ RadiosondeGUI::RadiosondeGUI(PluginAPI* pluginAPI, FeatureUISet *featureUISet, F m_doApplySettings(true), m_lastFeatureState(0) { - ui->setupUi(this); - m_helpURL = "plugins/feature/radiosonde/readme.md"; + m_feature = feature; setAttribute(Qt::WA_DeleteOnClose, true); - setChannelWidget(false); - connect(this, SIGNAL(widgetRolled(QWidget*,bool)), this, SLOT(onWidgetRolled(QWidget*,bool))); + m_helpURL = "plugins/feature/radiosonde/readme.md"; + RollupContents *rollupContents = getRollupContents(); + ui->setupUi(rollupContents); + setSizePolicy(rollupContents->sizePolicy()); + rollupContents->arrangeRollups(); + connect(rollupContents, SIGNAL(widgetRolled(QWidget*,bool)), this, SLOT(onWidgetRolled(QWidget*,bool))); + m_radiosonde = reinterpret_cast(feature); m_radiosonde->setMessageQueueToGUI(&m_inputMessageQueue); - m_featureUISet->addRollupWidget(this); - connect(this, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(onMenuDialogCalled(const QPoint &))); connect(getInputMessageQueue(), SIGNAL(messageEnqueued()), this, SLOT(handleInputMessages())); @@ -180,6 +194,7 @@ RadiosondeGUI::RadiosondeGUI(PluginAPI* pluginAPI, FeatureUISet *featureUISet, F displaySettings(); applySettings(true); + makeUIConnections(); plotChart(); } @@ -190,6 +205,12 @@ RadiosondeGUI::~RadiosondeGUI() delete ui; } +void RadiosondeGUI::setWorkspaceIndex(int index) +{ + m_settings.m_workspaceIndex = index; + m_feature->setWorkspaceIndex(index); +} + void RadiosondeGUI::blockApplySettings(bool block) { m_doApplySettings = !block; @@ -199,6 +220,7 @@ void RadiosondeGUI::displaySettings() { setTitleColor(m_settings.m_rgbColor); setWindowTitle(m_settings.m_title); + setTitle(m_settings.m_title); blockApplySettings(true); // Order and size columns @@ -217,17 +239,9 @@ void RadiosondeGUI::displaySettings() ui->y1->setCurrentIndex((int)m_settings.m_y1); ui->y2->setCurrentIndex((int)m_settings.m_y2); - restoreState(m_rollupState); + getRollupContents()->restoreState(m_rollupState); blockApplySettings(false); - arrangeRollups(); -} - -void RadiosondeGUI::leaveEvent(QEvent*) -{ -} - -void RadiosondeGUI::enterEvent(QEvent*) -{ + getRollupContents()->arrangeRollups(); } void RadiosondeGUI::onMenuDialogCalled(const QPoint &p) @@ -236,17 +250,16 @@ void RadiosondeGUI::onMenuDialogCalled(const QPoint &p) { BasicFeatureSettingsDialog dialog(this); dialog.setTitle(m_settings.m_title); - dialog.setColor(m_settings.m_rgbColor); dialog.setUseReverseAPI(m_settings.m_useReverseAPI); dialog.setReverseAPIAddress(m_settings.m_reverseAPIAddress); dialog.setReverseAPIPort(m_settings.m_reverseAPIPort); dialog.setReverseAPIFeatureSetIndex(m_settings.m_reverseAPIFeatureSetIndex); dialog.setReverseAPIFeatureIndex(m_settings.m_reverseAPIFeatureIndex); + dialog.setDefaultTitle(m_displayedName); dialog.move(p); dialog.exec(); - m_settings.m_rgbColor = dialog.getColor().rgb(); m_settings.m_title = dialog.getTitle(); m_settings.m_useReverseAPI = dialog.useReverseAPI(); m_settings.m_reverseAPIAddress = dialog.getReverseAPIAddress(); @@ -254,7 +267,7 @@ void RadiosondeGUI::onMenuDialogCalled(const QPoint &p) m_settings.m_reverseAPIFeatureSetIndex = dialog.getReverseAPIFeatureSetIndex(); m_settings.m_reverseAPIFeatureIndex = dialog.getReverseAPIFeatureIndex(); - setWindowTitle(m_settings.m_title); + setTitle(m_settings.m_title); setTitleColor(m_settings.m_rgbColor); applySettings(); @@ -853,3 +866,12 @@ void RadiosondeGUI::on_deleteAll_clicked() m_radiosondes.remove(serial); } } + +void RadiosondeGUI::makeUIConnections() +{ + QObject::connect(ui->radiosondes, &QTableWidget::itemSelectionChanged, this, &RadiosondeGUI::on_radiosondes_itemSelectionChanged); + QObject::connect(ui->radiosondes, &QTableWidget::cellDoubleClicked, this, &RadiosondeGUI::on_radiosondes_cellDoubleClicked); + QObject::connect(ui->y1, qOverload(&QComboBox::currentIndexChanged), this, &RadiosondeGUI::on_y1_currentIndexChanged); + QObject::connect(ui->y2, qOverload(&QComboBox::currentIndexChanged), this, &RadiosondeGUI::on_y2_currentIndexChanged); + QObject::connect(ui->deleteAll, &QPushButton::clicked, this, &RadiosondeGUI::on_deleteAll_clicked); +} diff --git a/plugins/feature/radiosonde/radiosondegui.h b/plugins/feature/radiosonde/radiosondegui.h index 3a9b2883f..355a9b76d 100644 --- a/plugins/feature/radiosonde/radiosondegui.h +++ b/plugins/feature/radiosonde/radiosondegui.h @@ -74,6 +74,10 @@ public: QByteArray serialize() const; bool deserialize(const QByteArray& data); virtual MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; } + virtual void setWorkspaceIndex(int index); + virtual int getWorkspaceIndex() const { return m_settings.m_workspaceIndex; } + virtual void setGeometryBytes(const QByteArray& blob) { m_settings.m_geometryBytes = blob; } + virtual QByteArray getGeometryBytes() const { return m_settings.m_geometryBytes; } private: Ui::RadiosondeGUI* ui; @@ -98,9 +102,7 @@ private: void applySettings(bool force = false); void displaySettings(); bool handleMessage(const Message& message); - - void leaveEvent(QEvent*); - void enterEvent(QEvent*); + void makeUIConnections(); void sendToMap(const QString &name, const QString &label, const QString &image, const QString &text, diff --git a/plugins/feature/radiosonde/radiosondegui.ui b/plugins/feature/radiosonde/radiosondegui.ui index 14a31362f..4dccbfa46 100644 --- a/plugins/feature/radiosonde/radiosondegui.ui +++ b/plugins/feature/radiosonde/radiosondegui.ui @@ -1,7 +1,7 @@ RadiosondeGUI - + 0 @@ -22,12 +22,6 @@ 100 - - - 16777215 - 16777215 - - 9 @@ -426,9 +420,9 @@ - RollupWidget + RollupContents QWidget -
gui/rollupwidget.h
+
gui/rollupcontents.h
1
diff --git a/plugins/feature/radiosonde/radiosondesettings.cpp b/plugins/feature/radiosonde/radiosondesettings.cpp index 565d44877..2e2f016b6 100644 --- a/plugins/feature/radiosonde/radiosondesettings.cpp +++ b/plugins/feature/radiosonde/radiosondesettings.cpp @@ -76,6 +76,8 @@ QByteArray RadiosondeSettings::serialize() const s.writeS32(10, (int)m_y1); s.writeS32(11, (int)m_y2); + s.writeS32(12, m_workspaceIndex); + s.writeBlob(13, m_geometryBytes); for (int i = 0; i < RADIOSONDES_COLUMNS; i++) { s.writeS32(300 + i, m_radiosondesColumnIndexes[i]); @@ -130,6 +132,8 @@ bool RadiosondeSettings::deserialize(const QByteArray& data) d.readS32(10, (int *)&m_y1, (int)ALTITUDE); d.readS32(11, (int *)&m_y2, (int)TEMPERATURE); + d.readS32(12, &m_workspaceIndex, 0); + d.readBlob(13, &m_geometryBytes); for (int i = 0; i < RADIOSONDES_COLUMNS; i++) { d.readS32(300 + i, &m_radiosondesColumnIndexes[i], i); diff --git a/plugins/feature/radiosonde/radiosondesettings.h b/plugins/feature/radiosonde/radiosondesettings.h index 4c199c731..878b39bfc 100644 --- a/plugins/feature/radiosonde/radiosondesettings.h +++ b/plugins/feature/radiosonde/radiosondesettings.h @@ -39,6 +39,8 @@ struct RadiosondeSettings uint16_t m_reverseAPIFeatureSetIndex; uint16_t m_reverseAPIFeatureIndex; Serializable *m_rollupState; + int m_workspaceIndex; + QByteArray m_geometryBytes; enum ChartData { NONE, diff --git a/plugins/feature/rigctlserver/rigctlservergui.cpp b/plugins/feature/rigctlserver/rigctlservergui.cpp index da18a7698..017093c89 100644 --- a/plugins/feature/rigctlserver/rigctlservergui.cpp +++ b/plugins/feature/rigctlserver/rigctlservergui.cpp @@ -17,6 +17,7 @@ /////////////////////////////////////////////////////////////////////////////////// #include +#include #include "feature/featureuiset.h" #include "gui/basicfeaturesettingsdialog.h" @@ -47,7 +48,6 @@ void RigCtlServerGUI::resetToDefaults() QByteArray RigCtlServerGUI::serialize() const { - qDebug("RigCtlServerGUI::serialize: %d", m_settings.m_channelIndex); return m_settings.serialize(); } @@ -55,7 +55,7 @@ bool RigCtlServerGUI::deserialize(const QByteArray& data) { if (m_settings.deserialize(data)) { - qDebug("RigCtlServerGUI::deserialize: %d", m_settings.m_channelIndex); + m_feature->setWorkspaceIndex(m_settings.m_workspaceIndex); updateDeviceSetList(); displaySettings(); applySettings(true); @@ -68,6 +68,14 @@ bool RigCtlServerGUI::deserialize(const QByteArray& data) } } +void RigCtlServerGUI::resizeEvent(QResizeEvent* size) +{ + int maxWidth = getRollupContents()->maximumWidth(); + int minHeight = getRollupContents()->minimumHeight() + getAdditionalHeight(); + resize(width() < maxWidth ? width() : maxWidth, minHeight); + size->accept(); +} + bool RigCtlServerGUI::handleMessage(const Message& message) { if (RigCtlServer::MsgConfigureRigCtlServer::match(message)) @@ -114,7 +122,7 @@ void RigCtlServerGUI::onWidgetRolled(QWidget* widget, bool rollDown) (void) widget; (void) rollDown; - saveState(m_rollupState); + getRollupContents()->saveState(m_rollupState); applySettings(); } @@ -126,15 +134,18 @@ RigCtlServerGUI::RigCtlServerGUI(PluginAPI* pluginAPI, FeatureUISet *featureUISe m_doApplySettings(true), m_lastFeatureState(0) { - ui->setupUi(this); - m_helpURL = "plugins/feature/rigctlserver/readme.md"; + m_feature = feature; setAttribute(Qt::WA_DeleteOnClose, true); - setChannelWidget(false); - connect(this, SIGNAL(widgetRolled(QWidget*,bool)), this, SLOT(onWidgetRolled(QWidget*,bool))); + m_helpURL = "plugins/feature/rigctlserver/readme.md"; + RollupContents *rollupContents = getRollupContents(); + ui->setupUi(rollupContents); + setSizePolicy(rollupContents->sizePolicy()); + rollupContents->arrangeRollups(); + connect(rollupContents, SIGNAL(widgetRolled(QWidget*,bool)), this, SLOT(onWidgetRolled(QWidget*,bool))); + m_rigCtlServer = reinterpret_cast(feature); m_rigCtlServer->setMessageQueueToGUI(&m_inputMessageQueue); - m_featureUISet->addRollupWidget(this); m_settings.setRollupState(&m_rollupState); connect(this, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(onMenuDialogCalled(const QPoint &))); @@ -146,6 +157,7 @@ RigCtlServerGUI::RigCtlServerGUI(PluginAPI* pluginAPI, FeatureUISet *featureUISe updateDeviceSetList(); displaySettings(); applySettings(true); + makeUIConnections(); } RigCtlServerGUI::~RigCtlServerGUI() @@ -153,6 +165,12 @@ RigCtlServerGUI::~RigCtlServerGUI() delete ui; } +void RigCtlServerGUI::setWorkspaceIndex(int index) +{ + m_settings.m_workspaceIndex = index; + m_feature->setWorkspaceIndex(index); +} + void RigCtlServerGUI::blockApplySettings(bool block) { m_doApplySettings = !block; @@ -162,10 +180,11 @@ void RigCtlServerGUI::displaySettings() { setTitleColor(m_settings.m_rgbColor); setWindowTitle(m_settings.m_title); + setTitle(m_settings.m_title); blockApplySettings(true); ui->rigCtrlPort->setValue(m_settings.m_rigCtlPort); ui->maxFrequencyOffset->setValue(m_settings.m_maxFrequencyOffset); - restoreState(m_rollupState); + getRollupContents()->restoreState(m_rollupState); blockApplySettings(false); } @@ -267,31 +286,22 @@ bool RigCtlServerGUI::updateChannelList() return false; } -void RigCtlServerGUI::leaveEvent(QEvent*) -{ -} - -void RigCtlServerGUI::enterEvent(QEvent*) -{ -} - void RigCtlServerGUI::onMenuDialogCalled(const QPoint &p) { if (m_contextMenuType == ContextMenuChannelSettings) { BasicFeatureSettingsDialog dialog(this); dialog.setTitle(m_settings.m_title); - dialog.setColor(m_settings.m_rgbColor); dialog.setUseReverseAPI(m_settings.m_useReverseAPI); dialog.setReverseAPIAddress(m_settings.m_reverseAPIAddress); dialog.setReverseAPIPort(m_settings.m_reverseAPIPort); dialog.setReverseAPIFeatureSetIndex(m_settings.m_reverseAPIFeatureSetIndex); dialog.setReverseAPIFeatureIndex(m_settings.m_reverseAPIFeatureIndex); + dialog.setDefaultTitle(m_displayedName); dialog.move(p); dialog.exec(); - m_settings.m_rgbColor = dialog.getColor().rgb(); m_settings.m_title = dialog.getTitle(); m_settings.m_useReverseAPI = dialog.useReverseAPI(); m_settings.m_reverseAPIAddress = dialog.getReverseAPIAddress(); @@ -299,7 +309,7 @@ void RigCtlServerGUI::onMenuDialogCalled(const QPoint &p) m_settings.m_reverseAPIFeatureSetIndex = dialog.getReverseAPIFeatureSetIndex(); m_settings.m_reverseAPIFeatureIndex = dialog.getReverseAPIFeatureIndex(); - setWindowTitle(m_settings.m_title); + setTitle(m_settings.m_title); setTitleColor(m_settings.m_rgbColor); applySettings(); @@ -398,3 +408,14 @@ void RigCtlServerGUI::applySettings(bool force) m_rigCtlServer->getInputMessageQueue()->push(message); } } + +void RigCtlServerGUI::makeUIConnections() +{ + QObject::connect(ui->startStop, &ButtonSwitch::toggled, this, &RigCtlServerGUI::on_startStop_toggled); + QObject::connect(ui->enable, &QCheckBox::toggled, this, &RigCtlServerGUI::on_enable_toggled); + QObject::connect(ui->devicesRefresh, &QPushButton::clicked, this, &RigCtlServerGUI::on_devicesRefresh_clicked); + QObject::connect(ui->device, qOverload(&QComboBox::currentIndexChanged), this, &RigCtlServerGUI::on_device_currentIndexChanged); + QObject::connect(ui->channel, qOverload(&QComboBox::currentIndexChanged), this, &RigCtlServerGUI::on_channel_currentIndexChanged); + QObject::connect(ui->rigCtrlPort, qOverload(&QSpinBox::valueChanged), this, &RigCtlServerGUI::on_rigCtrlPort_valueChanged); + QObject::connect(ui->maxFrequencyOffset, qOverload(&QSpinBox::valueChanged), this, &RigCtlServerGUI::on_maxFrequencyOffset_valueChanged); +} diff --git a/plugins/feature/rigctlserver/rigctlservergui.h b/plugins/feature/rigctlserver/rigctlservergui.h index 1529ae2bf..e56c0e941 100644 --- a/plugins/feature/rigctlserver/rigctlservergui.h +++ b/plugins/feature/rigctlserver/rigctlservergui.h @@ -45,6 +45,13 @@ public: QByteArray serialize() const; bool deserialize(const QByteArray& data); virtual MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; } + virtual void setWorkspaceIndex(int index); + virtual int getWorkspaceIndex() const { return m_settings.m_workspaceIndex; } + virtual void setGeometryBytes(const QByteArray& blob) { m_settings.m_geometryBytes = blob; } + virtual QByteArray getGeometryBytes() const { return m_settings.m_geometryBytes; } + +protected: + void resizeEvent(QResizeEvent* size); private: Ui::RigCtlServerGUI* ui; @@ -68,9 +75,7 @@ private: void updateDeviceSetList(); bool updateChannelList(); //!< true if channel index has changed bool handleMessage(const Message& message); - - void leaveEvent(QEvent*); - void enterEvent(QEvent*); + void makeUIConnections(); private slots: void onMenuDialogCalled(const QPoint &p); diff --git a/plugins/feature/rigctlserver/rigctlservergui.ui b/plugins/feature/rigctlserver/rigctlservergui.ui index 3e3873dbd..cef98d408 100644 --- a/plugins/feature/rigctlserver/rigctlservergui.ui +++ b/plugins/feature/rigctlserver/rigctlservergui.ui @@ -1,31 +1,31 @@ RigCtlServerGUI - + 0 0 - 320 - 189 + 330 + 173 - + 0 0 - 320 - 100 + 330 + 173 - 320 - 16777215 + 560 + 173 @@ -40,9 +40,9 @@ - 10 - 10 - 301 + 2 + 2 + 328 171 @@ -263,17 +263,17 @@ Default is 10000. - - RollupWidget - QWidget -
gui/rollupwidget.h
- 1 -
ButtonSwitch QToolButton
gui/buttonswitch.h
+ + RollupContents + QWidget +
gui/rollupcontents.h
+ 1 +
diff --git a/plugins/feature/rigctlserver/rigctlserversettings.cpp b/plugins/feature/rigctlserver/rigctlserversettings.cpp index a875dc5d1..ad00529cb 100644 --- a/plugins/feature/rigctlserver/rigctlserversettings.cpp +++ b/plugins/feature/rigctlserver/rigctlserversettings.cpp @@ -44,6 +44,7 @@ void RigCtlServerSettings::resetToDefaults() m_reverseAPIPort = 8888; m_reverseAPIFeatureSetIndex = 0; m_reverseAPIFeatureIndex = 0; + m_workspaceIndex = 0; } QByteArray RigCtlServerSettings::serialize() const @@ -66,6 +67,9 @@ QByteArray RigCtlServerSettings::serialize() const s.writeBlob(12, m_rollupState->serialize()); } + s.writeS32(13, m_workspaceIndex); + s.writeBlob(14, m_geometryBytes); + return s.final(); } @@ -119,6 +123,9 @@ bool RigCtlServerSettings::deserialize(const QByteArray& data) m_rollupState->deserialize(bytetmp); } + d.readS32(13, &m_workspaceIndex, 0); + d.readBlob(14, &m_geometryBytes); + return true; } else diff --git a/plugins/feature/rigctlserver/rigctlserversettings.h b/plugins/feature/rigctlserver/rigctlserversettings.h index 70bdabf65..b76562b38 100644 --- a/plugins/feature/rigctlserver/rigctlserversettings.h +++ b/plugins/feature/rigctlserver/rigctlserversettings.h @@ -60,6 +60,8 @@ struct RigCtlServerSettings uint16_t m_reverseAPIFeatureSetIndex; uint16_t m_reverseAPIFeatureIndex; Serializable *m_rollupState; + int m_workspaceIndex; + QByteArray m_geometryBytes; RigCtlServerSettings(); void resetToDefaults(); diff --git a/plugins/feature/satellitetracker/satellitetrackergui.cpp b/plugins/feature/satellitetracker/satellitetrackergui.cpp index d3f983817..701490b4f 100644 --- a/plugins/feature/satellitetracker/satellitetrackergui.cpp +++ b/plugins/feature/satellitetracker/satellitetrackergui.cpp @@ -73,6 +73,7 @@ bool SatelliteTrackerGUI::deserialize(const QByteArray& data) { if (m_settings.deserialize(data)) { + m_feature->setWorkspaceIndex(m_settings.m_workspaceIndex); updateSelectedSats(); displaySettings(); qDebug() << " deserialize " << m_settings.m_satellites; @@ -230,7 +231,18 @@ void SatelliteTrackerGUI::onWidgetRolled(QWidget* widget, bool rollDown) (void) widget; (void) rollDown; - saveState(m_rollupState); + RollupContents *rollupContents = getRollupContents(); + + if (rollupContents->hasExpandableWidgets()) { + setSizePolicy(sizePolicy().horizontalPolicy(), QSizePolicy::Expanding); + } else { + setSizePolicy(sizePolicy().horizontalPolicy(), QSizePolicy::Fixed); + } + + int h = rollupContents->height() + getAdditionalHeight(); + resize(width(), h); + + rollupContents->saveState(m_rollupState); applySettings(); } @@ -248,15 +260,18 @@ SatelliteTrackerGUI::SatelliteTrackerGUI(PluginAPI* pluginAPI, FeatureUISet *fea m_polarChart(nullptr), m_geostationarySatVisible(false) { - ui->setupUi(this); - m_helpURL = "plugins/feature/satellitetracker/readme.md"; + m_feature = feature; setAttribute(Qt::WA_DeleteOnClose, true); - setChannelWidget(false); - connect(this, SIGNAL(widgetRolled(QWidget*,bool)), this, SLOT(onWidgetRolled(QWidget*,bool))); + m_helpURL = "plugins/feature/satellitetracker/readme.md"; + RollupContents *rollupContents = getRollupContents(); + ui->setupUi(rollupContents); + setSizePolicy(rollupContents->sizePolicy()); + rollupContents->arrangeRollups(); + connect(rollupContents, SIGNAL(widgetRolled(QWidget*,bool)), this, SLOT(onWidgetRolled(QWidget*,bool))); + m_satelliteTracker = reinterpret_cast(feature); m_satelliteTracker->setMessageQueueToGUI(&m_inputMessageQueue); - m_featureUISet->addRollupWidget(this); m_settings.setRollupState(&m_rollupState); connect(this, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(onMenuDialogCalled(const QPoint &))); @@ -303,6 +318,7 @@ SatelliteTrackerGUI::SatelliteTrackerGUI(PluginAPI* pluginAPI, FeatureUISet *fea displaySettings(); applySettings(true); + makeUIConnections(); // Get initial list of satellites on_updateSatData_clicked(); @@ -313,6 +329,12 @@ SatelliteTrackerGUI::~SatelliteTrackerGUI() delete ui; } +void SatelliteTrackerGUI::setWorkspaceIndex(int index) +{ + m_settings.m_workspaceIndex = index; + m_feature->setWorkspaceIndex(index); +} + void SatelliteTrackerGUI::blockApplySettings(bool block) { m_doApplySettings = !block; @@ -322,6 +344,7 @@ void SatelliteTrackerGUI::displaySettings() { setTitleColor(m_settings.m_rgbColor); setWindowTitle(m_settings.m_title); + setTitle(m_settings.m_title); blockApplySettings(true); ui->latitude->setValue(m_settings.m_latitude); ui->longitude->setValue(m_settings.m_longitude); @@ -337,36 +360,27 @@ void SatelliteTrackerGUI::displaySettings() ui->dateTime->setDateTime(QDateTime::fromString(m_settings.m_dateTime, Qt::ISODateWithMs)); ui->autoTarget->setChecked(m_settings.m_autoTarget); ui->darkTheme->setChecked(m_settings.m_chartsDarkTheme); - restoreState(m_rollupState); + getRollupContents()->restoreState(m_rollupState); plotChart(); blockApplySettings(false); } -void SatelliteTrackerGUI::leaveEvent(QEvent*) -{ -} - -void SatelliteTrackerGUI::enterEvent(QEvent*) -{ -} - void SatelliteTrackerGUI::onMenuDialogCalled(const QPoint &p) { if (m_contextMenuType == ContextMenuChannelSettings) { BasicFeatureSettingsDialog dialog(this); dialog.setTitle(m_settings.m_title); - dialog.setColor(m_settings.m_rgbColor); dialog.setUseReverseAPI(m_settings.m_useReverseAPI); dialog.setReverseAPIAddress(m_settings.m_reverseAPIAddress); dialog.setReverseAPIPort(m_settings.m_reverseAPIPort); dialog.setReverseAPIFeatureSetIndex(m_settings.m_reverseAPIFeatureSetIndex); dialog.setReverseAPIFeatureIndex(m_settings.m_reverseAPIFeatureIndex); + dialog.setDefaultTitle(m_displayedName); dialog.move(p); dialog.exec(); - m_settings.m_rgbColor = dialog.getColor().rgb(); m_settings.m_title = dialog.getTitle(); m_settings.m_useReverseAPI = dialog.useReverseAPI(); m_settings.m_reverseAPIAddress = dialog.getReverseAPIAddress(); @@ -374,7 +388,7 @@ void SatelliteTrackerGUI::onMenuDialogCalled(const QPoint &p) m_settings.m_reverseAPIFeatureSetIndex = dialog.getReverseAPIFeatureSetIndex(); m_settings.m_reverseAPIFeatureIndex = dialog.getReverseAPIFeatureIndex(); - setWindowTitle(m_settings.m_title); + setTitle(m_settings.m_title); setTitleColor(m_settings.m_rgbColor); applySettings(); @@ -1313,3 +1327,26 @@ void SatelliteTrackerGUI::on_deviceFeatureSelect_currentIndexChanged(int index) } applySettings(); } + +void SatelliteTrackerGUI::makeUIConnections() +{ + QObject::connect(ui->startStop, &ButtonSwitch::toggled, this, &SatelliteTrackerGUI::on_startStop_toggled); + QObject::connect(ui->useMyPosition, &QToolButton::clicked, this, &SatelliteTrackerGUI::on_useMyPosition_clicked); + QObject::connect(ui->latitude, qOverload(&QDoubleSpinBox::valueChanged), this, &SatelliteTrackerGUI::on_latitude_valueChanged); + QObject::connect(ui->longitude, qOverload(&QDoubleSpinBox::valueChanged), this, &SatelliteTrackerGUI::on_longitude_valueChanged); + QObject::connect(ui->target, &QComboBox::currentTextChanged, this, &SatelliteTrackerGUI::on_target_currentTextChanged); + QObject::connect(ui->displaySettings, &QToolButton::clicked, this, &SatelliteTrackerGUI::on_displaySettings_clicked); + QObject::connect(ui->radioControl, &QToolButton::clicked, this, &SatelliteTrackerGUI::on_radioControl_clicked); + QObject::connect(ui->dateTimeSelect, qOverload(&QComboBox::currentIndexChanged), this, &SatelliteTrackerGUI::on_dateTimeSelect_currentIndexChanged); + QObject::connect(ui->dateTime, &WrappingDateTimeEdit::dateTimeChanged, this, &SatelliteTrackerGUI::on_dateTime_dateTimeChanged); + QObject::connect(ui->viewOnMap, &QToolButton::clicked, this, &SatelliteTrackerGUI::on_viewOnMap_clicked); + QObject::connect(ui->updateSatData, &QToolButton::clicked, this, &SatelliteTrackerGUI::on_updateSatData_clicked); + QObject::connect(ui->selectSats, &QToolButton::clicked, this, &SatelliteTrackerGUI::on_selectSats_clicked); + QObject::connect(ui->autoTarget, &ButtonSwitch::clicked, this, &SatelliteTrackerGUI::on_autoTarget_clicked); + QObject::connect(ui->chartSelect, qOverload(&QComboBox::currentIndexChanged), this, &SatelliteTrackerGUI::on_chartSelect_currentIndexChanged); + QObject::connect(ui->nextPass, &QToolButton::clicked, this, &SatelliteTrackerGUI::on_nextPass_clicked); + QObject::connect(ui->prevPass, &QToolButton::clicked, this, &SatelliteTrackerGUI::on_prevPass_clicked); + QObject::connect(ui->darkTheme, &QToolButton::clicked, this, &SatelliteTrackerGUI::on_darkTheme_clicked); + QObject::connect(ui->satTable, &QTableWidget::cellDoubleClicked, this, &SatelliteTrackerGUI::on_satTable_cellDoubleClicked); + QObject::connect(ui->deviceFeatureSelect, qOverload(&QComboBox::currentIndexChanged), this, &SatelliteTrackerGUI::on_deviceFeatureSelect_currentIndexChanged); +} diff --git a/plugins/feature/satellitetracker/satellitetrackergui.h b/plugins/feature/satellitetracker/satellitetrackergui.h index f9c9939e9..f5a058789 100644 --- a/plugins/feature/satellitetracker/satellitetrackergui.h +++ b/plugins/feature/satellitetracker/satellitetrackergui.h @@ -52,6 +52,10 @@ public: QByteArray serialize() const; bool deserialize(const QByteArray& data); virtual MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; } + virtual void setWorkspaceIndex(int index); + virtual int getWorkspaceIndex() const { return m_settings.m_workspaceIndex; } + virtual void setGeometryBytes(const QByteArray& blob) { m_settings.m_geometryBytes = blob; } + virtual QByteArray getGeometryBytes() const { return m_settings.m_geometryBytes; } private: Ui::SatelliteTrackerGUI* ui; @@ -130,9 +134,7 @@ private: void updateDeviceFeatureCombo(const QStringList &items, const QString &selected); void updateFileInputList(); void updateMapList(); - - void leaveEvent(QEvent*); - void enterEvent(QEvent*); + void makeUIConnections(); private slots: void onMenuDialogCalled(const QPoint &p); diff --git a/plugins/feature/satellitetracker/satellitetrackergui.ui b/plugins/feature/satellitetracker/satellitetrackergui.ui index f15e45f34..53abf8df6 100644 --- a/plugins/feature/satellitetracker/satellitetrackergui.ui +++ b/plugins/feature/satellitetracker/satellitetrackergui.ui @@ -1,7 +1,7 @@ SatelliteTrackerGUI - + 0 @@ -399,7 +399,7 @@ - + 0 0 @@ -716,17 +716,17 @@ - - RollupWidget - QWidget -
gui/rollupwidget.h
- 1 -
ButtonSwitch QToolButton
gui/buttonswitch.h
+ + RollupContents + QWidget +
gui/rollupcontents.h
+ 1 +
QChartView QGraphicsView diff --git a/plugins/feature/satellitetracker/satellitetrackersettings.cpp b/plugins/feature/satellitetracker/satellitetrackersettings.cpp index 1d7eaa9ad..9afab8bd5 100644 --- a/plugins/feature/satellitetracker/satellitetrackersettings.cpp +++ b/plugins/feature/satellitetracker/satellitetrackersettings.cpp @@ -78,6 +78,8 @@ void SatelliteTrackerSettings::resetToDefaults() m_dateTimeSelect = NOW; m_mapFeature = ""; m_fileInputDevice = ""; + m_workspaceIndex = 0; + for (int i = 0; i < SAT_COL_COLUMNS; i++) { m_columnIndexes[i] = i; @@ -134,6 +136,8 @@ QByteArray SatelliteTrackerSettings::serialize() const s.writeS32(42, (int)m_dateTimeSelect); s.writeString(43, m_mapFeature); s.writeString(44, m_fileInputDevice); + s.writeS32(45, m_workspaceIndex); + s.writeBlob(46, m_geometryBytes); for (int i = 0; i < SAT_COL_COLUMNS; i++) { s.writeS32(100 + i, m_columnIndexes[i]); @@ -225,6 +229,8 @@ bool SatelliteTrackerSettings::deserialize(const QByteArray& data) d.readS32(42, (int *)&m_dateTimeSelect, (int)NOW); d.readString(43, &m_mapFeature, ""); d.readString(44, &m_fileInputDevice, ""); + d.readS32(45, &m_workspaceIndex, 0); + d.readBlob(46, &m_geometryBytes); for (int i = 0; i < SAT_COL_COLUMNS; i++) { d.readS32(100 + i, &m_columnIndexes[i], i); diff --git a/plugins/feature/satellitetracker/satellitetrackersettings.h b/plugins/feature/satellitetracker/satellitetrackersettings.h index 238d1f5c7..34495e41b 100644 --- a/plugins/feature/satellitetracker/satellitetrackersettings.h +++ b/plugins/feature/satellitetracker/satellitetrackersettings.h @@ -94,6 +94,8 @@ struct SatelliteTrackerSettings uint16_t m_reverseAPIFeatureSetIndex; uint16_t m_reverseAPIFeatureIndex; Serializable *m_rollupState; + int m_workspaceIndex; + QByteArray m_geometryBytes; SatelliteTrackerSettings(); void resetToDefaults(); diff --git a/plugins/feature/simpleptt/simplepttgui.cpp b/plugins/feature/simpleptt/simplepttgui.cpp index 695a5800d..c7bc256b0 100644 --- a/plugins/feature/simpleptt/simplepttgui.cpp +++ b/plugins/feature/simpleptt/simplepttgui.cpp @@ -16,6 +16,7 @@ /////////////////////////////////////////////////////////////////////////////////// #include +#include #include "feature/featureuiset.h" #include "gui/basicfeaturesettingsdialog.h" @@ -58,6 +59,7 @@ bool SimplePTTGUI::deserialize(const QByteArray& data) { if (m_settings.deserialize(data)) { + m_feature->setWorkspaceIndex(m_settings.m_workspaceIndex); displaySettings(); applySettings(true); return true; @@ -69,6 +71,14 @@ bool SimplePTTGUI::deserialize(const QByteArray& data) } } +void SimplePTTGUI::resizeEvent(QResizeEvent* size) +{ + int maxWidth = getRollupContents()->maximumWidth(); + int minHeight = getRollupContents()->minimumHeight() + getAdditionalHeight(); + resize(width() < maxWidth ? width() : maxWidth, minHeight); + size->accept(); +} + bool SimplePTTGUI::handleMessage(const Message& message) { if (SimplePTT::MsgConfigureSimplePTT::match(message)) @@ -138,7 +148,7 @@ void SimplePTTGUI::onWidgetRolled(QWidget* widget, bool rollDown) (void) widget; (void) rollDown; - saveState(m_rollupState); + getRollupContents()->saveState(m_rollupState); applySettings(); } @@ -150,15 +160,18 @@ SimplePTTGUI::SimplePTTGUI(PluginAPI* pluginAPI, FeatureUISet *featureUISet, Fea m_doApplySettings(true), m_lastFeatureState(0) { - ui->setupUi(this); - m_helpURL = "plugins/feature/simpleptt/readme.md"; + m_feature = feature; setAttribute(Qt::WA_DeleteOnClose, true); - setChannelWidget(false); - connect(this, SIGNAL(widgetRolled(QWidget*,bool)), this, SLOT(onWidgetRolled(QWidget*,bool))); + m_helpURL = "plugins/feature/simpleptt/readme.md"; + RollupContents *rollupContents = getRollupContents(); + ui->setupUi(rollupContents); + setSizePolicy(rollupContents->sizePolicy()); + rollupContents->arrangeRollups(); + connect(rollupContents, SIGNAL(widgetRolled(QWidget*,bool)), this, SLOT(onWidgetRolled(QWidget*,bool))); + m_simplePTT = reinterpret_cast(feature); m_simplePTT->setMessageQueueToGUI(&m_inputMessageQueue); - m_featureUISet->addRollupWidget(this); m_settings.setRollupState(&m_rollupState); connect(this, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(onMenuDialogCalled(const QPoint &))); @@ -180,6 +193,7 @@ SimplePTTGUI::SimplePTTGUI(PluginAPI* pluginAPI, FeatureUISet *featureUISet, Fea updateDeviceSetLists(); displaySettings(); applySettings(true); + makeUIConnections(); } SimplePTTGUI::~SimplePTTGUI() @@ -187,6 +201,12 @@ SimplePTTGUI::~SimplePTTGUI() delete ui; } +void SimplePTTGUI::setWorkspaceIndex(int index) +{ + m_settings.m_workspaceIndex = index; + m_feature->setWorkspaceIndex(index); +} + void SimplePTTGUI::blockApplySettings(bool block) { m_doApplySettings = !block; @@ -196,10 +216,11 @@ void SimplePTTGUI::displaySettings() { setTitleColor(m_settings.m_rgbColor); setWindowTitle(m_settings.m_title); + setTitle(m_settings.m_title); blockApplySettings(true); ui->rxtxDelay->setValue(m_settings.m_rx2TxDelayMs); ui->txrxDelay->setValue(m_settings.m_tx2RxDelayMs); - restoreState(m_rollupState); + getRollupContents()->restoreState(m_rollupState); ui->vox->setChecked(m_settings.m_vox); ui->voxEnable->setChecked(m_settings.m_voxEnable); ui->voxLevel->setValue(m_settings.m_voxLevel); @@ -287,31 +308,22 @@ void SimplePTTGUI::updateDeviceSetLists() ui->txDevice->blockSignals(false); } -void SimplePTTGUI::leaveEvent(QEvent*) -{ -} - -void SimplePTTGUI::enterEvent(QEvent*) -{ -} - void SimplePTTGUI::onMenuDialogCalled(const QPoint &p) { if (m_contextMenuType == ContextMenuChannelSettings) { BasicFeatureSettingsDialog dialog(this); dialog.setTitle(m_settings.m_title); - dialog.setColor(m_settings.m_rgbColor); dialog.setUseReverseAPI(m_settings.m_useReverseAPI); dialog.setReverseAPIAddress(m_settings.m_reverseAPIAddress); dialog.setReverseAPIPort(m_settings.m_reverseAPIPort); dialog.setReverseAPIFeatureSetIndex(m_settings.m_reverseAPIFeatureSetIndex); dialog.setReverseAPIFeatureIndex(m_settings.m_reverseAPIFeatureIndex); + dialog.setDefaultTitle(m_displayedName); dialog.move(p); dialog.exec(); - m_settings.m_rgbColor = dialog.getColor().rgb(); m_settings.m_title = dialog.getTitle(); m_settings.m_useReverseAPI = dialog.useReverseAPI(); m_settings.m_reverseAPIAddress = dialog.getReverseAPIAddress(); @@ -319,7 +331,7 @@ void SimplePTTGUI::onMenuDialogCalled(const QPoint &p) m_settings.m_reverseAPIFeatureSetIndex = dialog.getReverseAPIFeatureSetIndex(); m_settings.m_reverseAPIFeatureIndex = dialog.getReverseAPIFeatureIndex(); - setWindowTitle(m_settings.m_title); + setTitle(m_settings.m_title); setTitleColor(m_settings.m_rgbColor); applySettings(); @@ -479,3 +491,18 @@ void SimplePTTGUI::audioSelect() applySettings(); } } + +void SimplePTTGUI::makeUIConnections() +{ + QObject::connect(ui->startStop, &ButtonSwitch::toggled, this, &SimplePTTGUI::on_startStop_toggled); + QObject::connect(ui->devicesRefresh, &QPushButton::clicked, this, &SimplePTTGUI::on_devicesRefresh_clicked); + QObject::connect(ui->rxDevice, qOverload(&QComboBox::currentIndexChanged), this, &SimplePTTGUI::on_rxDevice_currentIndexChanged); + QObject::connect(ui->txDevice, qOverload(&QComboBox::currentIndexChanged), this, &SimplePTTGUI::on_txDevice_currentIndexChanged); + QObject::connect(ui->rxtxDelay, qOverload(&QSpinBox::valueChanged), this, &SimplePTTGUI::on_rxtxDelay_valueChanged); + QObject::connect(ui->txrxDelay, qOverload(&QSpinBox::valueChanged), this, &SimplePTTGUI::on_txrxDelay_valueChanged); + QObject::connect(ui->ptt, &ButtonSwitch::toggled, this, &SimplePTTGUI::on_ptt_toggled); + QObject::connect(ui->vox, &ButtonSwitch::toggled, this, &SimplePTTGUI::on_vox_toggled); + QObject::connect(ui->voxEnable, &QCheckBox::clicked, this, &SimplePTTGUI::on_voxEnable_clicked); + QObject::connect(ui->voxLevel, &QDial::valueChanged, this, &SimplePTTGUI::on_voxLevel_valueChanged); + QObject::connect(ui->voxHold, qOverload(&QSpinBox::valueChanged), this, &SimplePTTGUI::on_voxHold_valueChanged); +} diff --git a/plugins/feature/simpleptt/simplepttgui.h b/plugins/feature/simpleptt/simplepttgui.h index b2b73fb7e..55a744bf1 100644 --- a/plugins/feature/simpleptt/simplepttgui.h +++ b/plugins/feature/simpleptt/simplepttgui.h @@ -44,6 +44,13 @@ public: QByteArray serialize() const; bool deserialize(const QByteArray& data); virtual MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; } + virtual void setWorkspaceIndex(int index); + virtual int getWorkspaceIndex() const { return m_settings.m_workspaceIndex; } + virtual void setGeometryBytes(const QByteArray& blob) { m_settings.m_geometryBytes = blob; } + virtual QByteArray getGeometryBytes() const { return m_settings.m_geometryBytes; } + +protected: + void resizeEvent(QResizeEvent* size); private: Ui::SimplePTTGUI* ui; @@ -69,9 +76,7 @@ private: void displaySettings(); void updateDeviceSetLists(); bool handleMessage(const Message& message); - - void leaveEvent(QEvent*); - void enterEvent(QEvent*); + void makeUIConnections(); private slots: void onMenuDialogCalled(const QPoint &p); diff --git a/plugins/feature/simpleptt/simplepttgui.ui b/plugins/feature/simpleptt/simplepttgui.ui index 619aaf38a..0f1e865f7 100644 --- a/plugins/feature/simpleptt/simplepttgui.ui +++ b/plugins/feature/simpleptt/simplepttgui.ui @@ -1,17 +1,17 @@ SimplePTTGUI - + 0 0 320 - 181 + 155 - + 0 0 @@ -19,13 +19,13 @@ 320 - 100 + 155 - 320 - 16777215 + 560 + 155 @@ -40,9 +40,9 @@ - 10 - 10 - 301 + 2 + 2 + 300 151 @@ -448,17 +448,17 @@ - - RollupWidget - QWidget -
gui/rollupwidget.h
- 1 -
ButtonSwitch QToolButton
gui/buttonswitch.h
+ + RollupContents + QWidget +
gui/rollupcontents.h
+ 1 +
diff --git a/plugins/feature/simpleptt/simplepttsettings.cpp b/plugins/feature/simpleptt/simplepttsettings.cpp index 1029d312f..efbafdbd8 100644 --- a/plugins/feature/simpleptt/simplepttsettings.cpp +++ b/plugins/feature/simpleptt/simplepttsettings.cpp @@ -47,6 +47,7 @@ void SimplePTTSettings::resetToDefaults() m_reverseAPIPort = 8888; m_reverseAPIFeatureSetIndex = 0; m_reverseAPIFeatureIndex = 0; + m_workspaceIndex = 0; } QByteArray SimplePTTSettings::serialize() const @@ -74,6 +75,8 @@ QByteArray SimplePTTSettings::serialize() const s.writeBool(15, m_vox); s.writeBool(16, m_voxEnable); s.writeS32(17, m_voxHold); + s.writeS32(18, m_workspaceIndex); + s.writeBlob(19, m_geometryBytes); return s.final(); } @@ -125,7 +128,9 @@ bool SimplePTTSettings::deserialize(const QByteArray& data) d.readS32(14, &m_voxLevel, -20); d.readBool(15, &m_vox, false); d.readBool(16, &m_voxEnable, false); - d.readS32(16, &m_voxHold, 500); + d.readS32(17, &m_voxHold, 500); + d.readS32(18, &m_workspaceIndex, 0); + d.readBlob(19, &m_geometryBytes); return true; } diff --git a/plugins/feature/simpleptt/simplepttsettings.h b/plugins/feature/simpleptt/simplepttsettings.h index 00a12a77c..39c9a2fdb 100644 --- a/plugins/feature/simpleptt/simplepttsettings.h +++ b/plugins/feature/simpleptt/simplepttsettings.h @@ -42,6 +42,8 @@ struct SimplePTTSettings uint16_t m_reverseAPIFeatureSetIndex; uint16_t m_reverseAPIFeatureIndex; Serializable *m_rollupState; + int m_workspaceIndex; + QByteArray m_geometryBytes; SimplePTTSettings(); void resetToDefaults(); diff --git a/plugins/feature/startracker/startrackergui.cpp b/plugins/feature/startracker/startrackergui.cpp index 4fde5482c..b7ee738b4 100644 --- a/plugins/feature/startracker/startrackergui.cpp +++ b/plugins/feature/startracker/startrackergui.cpp @@ -79,6 +79,7 @@ bool StarTrackerGUI::deserialize(const QByteArray& data) { if (m_settings.deserialize(data)) { + m_feature->setWorkspaceIndex(m_settings.m_workspaceIndex); displaySettings(); applySettings(true); return true; @@ -224,7 +225,18 @@ void StarTrackerGUI::onWidgetRolled(QWidget* widget, bool rollDown) (void) widget; (void) rollDown; - saveState(m_rollupState); + RollupContents *rollupContents = getRollupContents(); + + if (rollupContents->hasExpandableWidgets()) { + setSizePolicy(sizePolicy().horizontalPolicy(), QSizePolicy::Expanding); + } else { + setSizePolicy(sizePolicy().horizontalPolicy(), QSizePolicy::Fixed); + } + + int h = rollupContents->height() + getAdditionalHeight(); + resize(width(), h); + + rollupContents->saveState(m_rollupState); applySettings(); } @@ -254,15 +266,18 @@ StarTrackerGUI::StarTrackerGUI(PluginAPI* pluginAPI, FeatureUISet *featureUISet, m_moonRA(0.0), m_moonDec(0.0) { - ui->setupUi(this); - m_helpURL = "plugins/feature/startracker/readme.md"; + m_feature = feature; setAttribute(Qt::WA_DeleteOnClose, true); - setChannelWidget(false); - connect(this, SIGNAL(widgetRolled(QWidget*,bool)), this, SLOT(onWidgetRolled(QWidget*,bool))); + m_helpURL = "plugins/feature/startracker/readme.md"; + RollupContents *rollupContents = getRollupContents(); + ui->setupUi(rollupContents); + setSizePolicy(rollupContents->sizePolicy()); + rollupContents->arrangeRollups(); + connect(rollupContents, SIGNAL(widgetRolled(QWidget*,bool)), this, SLOT(onWidgetRolled(QWidget*,bool))); + m_starTracker = reinterpret_cast(feature); m_starTracker->setMessageQueueToGUI(&m_inputMessageQueue); - m_featureUISet->addRollupWidget(this); m_settings.setRollupState(&m_rollupState); connect(this, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(onMenuDialogCalled(const QPoint &))); @@ -325,6 +340,7 @@ StarTrackerGUI::StarTrackerGUI(PluginAPI* pluginAPI, FeatureUISet *featureUISet, ui->dateTime->setDateTime(QDateTime::currentDateTime()); displaySettings(); applySettings(true); + makeUIConnections(); // Populate subchart menu on_chartSelect_currentIndexChanged(0); @@ -383,6 +399,12 @@ StarTrackerGUI::~StarTrackerGUI() delete ui; } +void StarTrackerGUI::setWorkspaceIndex(int index) +{ + m_settings.m_workspaceIndex = index; + m_feature->setWorkspaceIndex(index); +} + void StarTrackerGUI::blockApplySettings(bool block) { m_doApplySettings = !block; @@ -392,6 +414,7 @@ void StarTrackerGUI::displaySettings() { setTitleColor(m_settings.m_rgbColor); setWindowTitle(m_settings.m_title); + setTitle(m_settings.m_title); blockApplySettings(true); ui->darkTheme->setChecked(m_settings.m_chartsDarkTheme); if (m_solarFluxChart) { @@ -445,36 +468,27 @@ void StarTrackerGUI::displaySettings() ui->frequency->setValue(m_settings.m_frequency/1000000.0); ui->beamwidth->setValue(m_settings.m_beamwidth); updateForTarget(); - restoreState(m_rollupState); + getRollupContents()->restoreState(m_rollupState); plotChart(); blockApplySettings(false); } -void StarTrackerGUI::leaveEvent(QEvent*) -{ -} - -void StarTrackerGUI::enterEvent(QEvent*) -{ -} - void StarTrackerGUI::onMenuDialogCalled(const QPoint &p) { if (m_contextMenuType == ContextMenuChannelSettings) { BasicFeatureSettingsDialog dialog(this); dialog.setTitle(m_settings.m_title); - dialog.setColor(m_settings.m_rgbColor); dialog.setUseReverseAPI(m_settings.m_useReverseAPI); dialog.setReverseAPIAddress(m_settings.m_reverseAPIAddress); dialog.setReverseAPIPort(m_settings.m_reverseAPIPort); dialog.setReverseAPIFeatureSetIndex(m_settings.m_reverseAPIFeatureSetIndex); dialog.setReverseAPIFeatureIndex(m_settings.m_reverseAPIFeatureIndex); + dialog.setDefaultTitle(m_displayedName); dialog.move(p); dialog.exec(); - m_settings.m_rgbColor = dialog.getColor().rgb(); m_settings.m_title = dialog.getTitle(); m_settings.m_useReverseAPI = dialog.useReverseAPI(); m_settings.m_reverseAPIAddress = dialog.getReverseAPIAddress(); @@ -482,7 +496,7 @@ void StarTrackerGUI::onMenuDialogCalled(const QPoint &p) m_settings.m_reverseAPIFeatureSetIndex = dialog.getReverseAPIFeatureSetIndex(); m_settings.m_reverseAPIFeatureIndex = dialog.getReverseAPIFeatureIndex(); - setWindowTitle(m_settings.m_title); + setTitle(m_settings.m_title); setTitleColor(m_settings.m_rgbColor); applySettings(); @@ -2036,3 +2050,38 @@ void StarTrackerGUI::downloadFinished(const QString& filename, bool success) if (success) readSolarFlux(); } + +void StarTrackerGUI::makeUIConnections() +{ + QObject::connect(ui->startStop, &ButtonSwitch::toggled, this, &StarTrackerGUI::on_startStop_toggled); + QObject::connect(ui->link, &ButtonSwitch::clicked, this, &StarTrackerGUI::on_link_clicked); + QObject::connect(ui->useMyPosition, &QToolButton::clicked, this, &StarTrackerGUI::on_useMyPosition_clicked); + QObject::connect(ui->latitude, qOverload(&QDoubleSpinBox::valueChanged), this, &StarTrackerGUI::on_latitude_valueChanged); + QObject::connect(ui->longitude, qOverload(&QDoubleSpinBox::valueChanged), this, &StarTrackerGUI::on_longitude_valueChanged); + QObject::connect(ui->rightAscension, &QLineEdit::editingFinished, this, &StarTrackerGUI::on_rightAscension_editingFinished); + QObject::connect(ui->declination, &QLineEdit::editingFinished, this, &StarTrackerGUI::on_declination_editingFinished); + QObject::connect(ui->azimuth, &DMSSpinBox::valueChanged, this, &StarTrackerGUI::on_azimuth_valueChanged); + QObject::connect(ui->elevation, &DMSSpinBox::valueChanged, this, &StarTrackerGUI::on_elevation_valueChanged); + QObject::connect(ui->azimuthOffset, qOverload(&QDoubleSpinBox::valueChanged), this, &StarTrackerGUI::on_azimuthOffset_valueChanged); + QObject::connect(ui->elevationOffset, qOverload(&QDoubleSpinBox::valueChanged), this, &StarTrackerGUI::on_elevationOffset_valueChanged); + QObject::connect(ui->galacticLatitude, &DMSSpinBox::valueChanged, this, &StarTrackerGUI::on_galacticLatitude_valueChanged); + QObject::connect(ui->galacticLongitude, &DMSSpinBox::valueChanged, this, &StarTrackerGUI::on_galacticLongitude_valueChanged); + QObject::connect(ui->frequency, qOverload(&QSpinBox::valueChanged), this, &StarTrackerGUI::on_frequency_valueChanged); + QObject::connect(ui->beamwidth, qOverload(&QDoubleSpinBox::valueChanged), this, &StarTrackerGUI::on_beamwidth_valueChanged); + QObject::connect(ui->target, &QComboBox::currentTextChanged, this, &StarTrackerGUI::on_target_currentTextChanged); + QObject::connect(ui->displaySettings, &QToolButton::clicked, this, &StarTrackerGUI::on_displaySettings_clicked); + QObject::connect(ui->dateTimeSelect, &QComboBox::currentTextChanged, this, &StarTrackerGUI::on_dateTimeSelect_currentTextChanged); + QObject::connect(ui->dateTime, &WrappingDateTimeEdit::dateTimeChanged, this, &StarTrackerGUI::on_dateTime_dateTimeChanged); + QObject::connect(ui->viewOnMap, &QToolButton::clicked, this, &StarTrackerGUI::on_viewOnMap_clicked); + QObject::connect(ui->chartSelect, qOverload(&QComboBox::currentIndexChanged), this, &StarTrackerGUI::on_chartSelect_currentIndexChanged); + QObject::connect(ui->chartSubSelect, qOverload(&QComboBox::currentIndexChanged), this, &StarTrackerGUI::on_chartSubSelect_currentIndexChanged); + QObject::connect(ui->downloadSolarFlux, &QToolButton::clicked, this, &StarTrackerGUI::on_downloadSolarFlux_clicked); + QObject::connect(ui->darkTheme, &QToolButton::clicked, this, &StarTrackerGUI::on_darkTheme_clicked); + QObject::connect(ui->zoomIn, &QToolButton::clicked, this, &StarTrackerGUI::on_zoomIn_clicked); + QObject::connect(ui->zoomOut, &QToolButton::clicked, this, &StarTrackerGUI::on_zoomOut_clicked); + QObject::connect(ui->addAnimationFrame, &QToolButton::clicked, this, &StarTrackerGUI::on_addAnimationFrame_clicked); + QObject::connect(ui->clearAnimation, &QToolButton::clicked, this, &StarTrackerGUI::on_clearAnimation_clicked); + QObject::connect(ui->saveAnimation, &QToolButton::clicked, this, &StarTrackerGUI::on_saveAnimation_clicked); + QObject::connect(ui->drawSun, &QToolButton::clicked, this, &StarTrackerGUI::on_drawSun_clicked); + QObject::connect(ui->drawMoon, &QToolButton::clicked, this, &StarTrackerGUI::on_drawMoon_clicked); +} diff --git a/plugins/feature/startracker/startrackergui.h b/plugins/feature/startracker/startrackergui.h index b3e6b89d3..c0acf6015 100644 --- a/plugins/feature/startracker/startrackergui.h +++ b/plugins/feature/startracker/startrackergui.h @@ -66,6 +66,10 @@ public: QByteArray serialize() const; bool deserialize(const QByteArray& data); virtual MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; } + virtual void setWorkspaceIndex(int index); + virtual int getWorkspaceIndex() const { return m_settings.m_workspaceIndex; } + virtual void setGeometryBytes(const QByteArray& blob) { m_settings.m_geometryBytes = blob; } + virtual QByteArray getGeometryBytes() const { return m_settings.m_geometryBytes; } private: Ui::StarTrackerGUI* ui; @@ -153,9 +157,7 @@ private: void raDecChanged(); void updateChartSubSelect(); void updateSolarFlux(bool all); - - void leaveEvent(QEvent*); - void enterEvent(QEvent*); + void makeUIConnections(); private slots: void onMenuDialogCalled(const QPoint &p); diff --git a/plugins/feature/startracker/startrackergui.ui b/plugins/feature/startracker/startrackergui.ui index 11866fb24..3f42355e6 100644 --- a/plugins/feature/startracker/startrackergui.ui +++ b/plugins/feature/startracker/startrackergui.ui @@ -1,7 +1,7 @@ StarTrackerGUI - + 0 @@ -846,17 +846,17 @@ This can be specified as a decimal (E.g. 34.23) or in degrees, minutes and secon - - RollupWidget - QWidget -
gui/rollupwidget.h
- 1 -
ButtonSwitch QToolButton
gui/buttonswitch.h
+ + RollupContents + QWidget +
gui/rollupcontents.h
+ 1 +
QChartView QGraphicsView diff --git a/plugins/feature/startracker/startrackersettings.cpp b/plugins/feature/startracker/startrackersettings.cpp index f15aad679..b83e3d802 100644 --- a/plugins/feature/startracker/startrackersettings.cpp +++ b/plugins/feature/startracker/startrackersettings.cpp @@ -82,6 +82,7 @@ void StarTrackerSettings::resetToDefaults() m_weatherUpdatePeriod = 60; m_drawSunOnSkyTempChart = true; m_drawMoonOnSkyTempChart = true; + m_workspaceIndex = 0; } QByteArray StarTrackerSettings::serialize() const @@ -136,6 +137,9 @@ QByteArray StarTrackerSettings::serialize() const s.writeBlob(44, m_rollupState->serialize()); } + s.writeS32(45, m_workspaceIndex); + s.writeBlob(46, m_geometryBytes); + return s.final(); } @@ -221,6 +225,9 @@ bool StarTrackerSettings::deserialize(const QByteArray& data) m_rollupState->deserialize(bytetmp); } + d.readS32(45, &m_workspaceIndex, 0); + d.readBlob(46, &m_geometryBytes); + return true; } else diff --git a/plugins/feature/startracker/startrackersettings.h b/plugins/feature/startracker/startrackersettings.h index 9232eea9c..eec6f2627 100644 --- a/plugins/feature/startracker/startrackersettings.h +++ b/plugins/feature/startracker/startrackersettings.h @@ -72,6 +72,8 @@ struct StarTrackerSettings bool m_drawSunOnSkyTempChart; bool m_drawMoonOnSkyTempChart; Serializable *m_rollupState; + int m_workspaceIndex; + QByteArray m_geometryBytes; StarTrackerSettings(); void resetToDefaults(); diff --git a/plugins/feature/vorlocalizer/CMakeLists.txt b/plugins/feature/vorlocalizer/CMakeLists.txt index ddf07bb7a..aaf5267bd 100644 --- a/plugins/feature/vorlocalizer/CMakeLists.txt +++ b/plugins/feature/vorlocalizer/CMakeLists.txt @@ -34,7 +34,6 @@ if(NOT SERVER_MODE) set(vor_HEADERS ${vor_HEADERS} vorlocalizergui.h - navaid.h ) set(TARGET_NAME vorlocalizer) diff --git a/plugins/feature/vorlocalizer/navaid.h b/plugins/feature/vorlocalizer/navaid.h deleted file mode 100644 index 1ac7419f6..000000000 --- a/plugins/feature/vorlocalizer/navaid.h +++ /dev/null @@ -1,368 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////////// -// Copyright (C) 2020 Jon Beniston, M7RCE // -// // -// This program is free software; you can redistribute it and/or modify // -// it under the terms of the GNU General Public License as published by // -// the Free Software Foundation as version 3 of the License, or // -// (at your option) any later version. // -// // -// This program is distributed in the hope that it will be useful, // -// but WITHOUT ANY WARRANTY; without even the implied warranty of // -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // -// GNU General Public License V3 for more details. // -// // -// You should have received a copy of the GNU General Public License // -// along with this program. If not, see . // -/////////////////////////////////////////////////////////////////////////////////// - -#ifndef INCLUDE_NAVAID_H -#define INCLUDE_NAVAID_H - -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include "util/units.h" -#include "util/csv.h" - -#define OURAIRPORTS_NAVAIDS_URL "https://ourairports.com/data/navaids.csv" -#define OPENAIP_NAVAIDS_URL "https://www.openaip.net/customer_export_akfshb9237tgwiuvb4tgiwbf/%1_nav.aip" - -struct NavAid { - - int m_id; - QString m_ident; // 2 or 3 character ident - QString m_type; // VOR, VOR-DME or VORTAC - QString m_name; - float m_latitude; - float m_longitude; - float m_elevation; - int m_frequencykHz; - QString m_channel; - int m_range; // Nautical miles - float m_magneticDeclination; - bool m_alignedTrueNorth; // Is the VOR aligned to true North, rather than magnetic (may be the case at high latitudes) - - static QString trimQuotes(const QString s) - { - if (s.startsWith('\"') && s.endsWith('\"')) - return s.mid(1, s.size() - 2); - else - return s; - } - - int getRangeMetres() - { - return Units::nauticalMilesToIntegerMetres((float)m_range); - } - - // OpenAIP XML file - static void readNavAidsXML(QHash *navAidInfo, const QString &filename) - { - QFile file(filename); - if (file.open(QIODevice::ReadOnly | QIODevice::Text)) - { - QXmlStreamReader xmlReader(&file); - - while(!xmlReader.atEnd() && !xmlReader.hasError()) - { - if (xmlReader.readNextStartElement()) - { - if (xmlReader.name() == "NAVAID") - { - QStringRef typeRef = xmlReader.attributes().value("TYPE"); - if ((typeRef == QLatin1String("VOR")) - || (typeRef== QLatin1String("VOR-DME")) - || (typeRef == QLatin1String("VORTAC"))) - { - QString type = typeRef.toString(); - int identifier = 0; - QString name; - QString id; - float lat = 0.0f; - float lon = 0.0f; - float elevation = 0.0f; - int frequency = 0; - QString channel; - int range = 25; - float declination = 0.0f; - bool alignedTrueNorth = false; - while(xmlReader.readNextStartElement()) - { - if (xmlReader.name() == QLatin1String("IDENTIFIER")) - identifier = xmlReader.readElementText().toInt(); - else if (xmlReader.name() == QLatin1String("NAME")) - name = xmlReader.readElementText(); - else if (xmlReader.name() == QLatin1String("ID")) - id = xmlReader.readElementText(); - else if (xmlReader.name() == QLatin1String("GEOLOCATION")) - { - while(xmlReader.readNextStartElement()) - { - if (xmlReader.name() == QLatin1String("LAT")) - lat = xmlReader.readElementText().toFloat(); - else if (xmlReader.name() == QLatin1String("LON")) - lon = xmlReader.readElementText().toFloat(); - else if (xmlReader.name() == QLatin1String("ELEV")) - elevation = xmlReader.readElementText().toFloat(); - else - xmlReader.skipCurrentElement(); - } - } - else if (xmlReader.name() == QLatin1String("RADIO")) - { - while(xmlReader.readNextStartElement()) - { - if (xmlReader.name() == QLatin1String("FREQUENCY")) - frequency = (int)(xmlReader.readElementText().toFloat() * 1000); - else if (xmlReader.name() == QLatin1String("CHANNEL")) - channel = xmlReader.readElementText(); - else - xmlReader.skipCurrentElement(); - } - } - else if (xmlReader.name() == QLatin1String("PARAMS")) - { - while(xmlReader.readNextStartElement()) - { - if (xmlReader.name() == QLatin1String("RANGE")) - range = xmlReader.readElementText().toInt(); - else if (xmlReader.name() == QLatin1String("DECLINATION")) - declination = xmlReader.readElementText().toFloat(); - else if (xmlReader.name() == QLatin1String("ALIGNEDTOTRUENORTH")) - alignedTrueNorth = xmlReader.readElementText() == "TRUE"; - else - xmlReader.skipCurrentElement(); - } - } - else - xmlReader.skipCurrentElement(); - } - NavAid *vor = new NavAid(); - vor->m_id = identifier; - vor->m_ident = id; - // Check idents conform to our filtering rules - if (vor->m_ident.size() < 2) - qDebug() << "Warning: VOR Ident less than 2 characters: " << vor->m_ident; - else if (vor->m_ident.size() > 3) - qDebug() << "Warning: VOR Ident greater than 3 characters: " << vor->m_ident; - vor->m_type = type; - vor->m_name = name; - vor->m_frequencykHz = frequency; - vor->m_channel = channel; - vor->m_latitude = lat; - vor->m_longitude = lon; - vor->m_elevation = elevation; - vor->m_range = range; - vor->m_magneticDeclination = declination; - vor->m_alignedTrueNorth = alignedTrueNorth; - navAidInfo->insert(identifier, vor); - } - } - } - } - - file.close(); - } - else - qDebug() << "NavAid::readNavAidsXML: Could not open " << filename << " for reading."; - } - - // Read OurAirport's NavAids CSV file - // See comments for readOSNDB - static QHash *readNavAidsDB(const QString &filename) - { - int cnt = 0; - QHash *navAidInfo = nullptr; - - // Column numbers used for the data as of 2020/10/28 - int idCol = 0; - int identCol = 2; - int typeCol = 4; - int nameCol = 3; - int frequencyCol = 5; - int latitudeCol = 6; - int longitudeCol = 7; - int elevationCol = 8; - int powerCol = 18; - - qDebug() << "NavAid::readNavAidsDB: " << filename; - - FILE *file; - QByteArray utfFilename = filename.toUtf8(); - QLocale cLocale(QLocale::C); - if ((file = fopen(utfFilename.constData(), "r")) != NULL) - { - char row[2048]; - - if (fgets(row, sizeof(row), file)) - { - navAidInfo = new QHash(); - navAidInfo->reserve(15000); - - // Read header - int idx = 0; - char *p = strtok(row, ","); - while (p != NULL) - { - if (!strcmp(p, "id")) - idCol = idx; - else if (!strcmp(p, "ident")) - identCol = idx; - else if (!strcmp(p, "type")) - typeCol = idx; - else if (!strcmp(p, "name")) - nameCol = idx; - else if (!strcmp(p, "frequency_khz")) - frequencyCol = idx; - else if (!strcmp(p, "latitude_deg")) - latitudeCol = idx; - else if (!strcmp(p, "longitude_deg")) - longitudeCol = idx; - else if (!strcmp(p, "elevation_ft")) - elevationCol = idx; - else if (!strcmp(p, "power")) - powerCol = idx; - p = strtok(NULL, ","); - idx++; - } - // Read data - while (fgets(row, sizeof(row), file)) - { - int id = 0; - char *idString = NULL; - char *ident = NULL; - size_t identLen = 0; - char *type = NULL; - size_t typeLen = 0; - char *name = NULL; - size_t nameLen = 0; - char *frequencyString = NULL; - int frequency; - float latitude = 0.0f; - char *latitudeString = NULL; - size_t latitudeLen = 0; - float longitude = 0.0f; - char *longitudeString = NULL; - size_t longitudeLen = 0; - float elevation = 0.0f; - char *elevationString = NULL; - size_t elevationLen = 0; - char *power = NULL; - size_t powerLen = 0; - - char *q = row; - idx = 0; - while ((p = csvNext(&q)) != nullptr) - { - // Read strings, stripping quotes - if (idx == idCol) - { - idString = p; - idString[strlen(idString)] = '\0'; - id = strtol(idString, NULL, 10); - } - else if ((idx == identCol) && (p[0] == '\"')) - { - ident = p+1; - identLen = strlen(ident)-1; - ident[identLen] = '\0'; - } - else if ((idx == typeCol) && (p[0] == '\"')) - { - type = p+1; - typeLen = strlen(type)-1; - type[typeLen] = '\0'; - } - else if ((idx == nameCol) && (p[0] == '\"')) - { - name = p+1; - nameLen = strlen(name)-1; - name[nameLen] = '\0'; - } - if (idx == frequencyCol) - { - frequencyString = p; - frequencyString[strlen(frequencyString)] = '\0'; - frequency = strtol(frequencyString, NULL, 10); - } - else if (idx == latitudeCol) - { - latitudeString = p; - latitudeLen = strlen(latitudeString)-1; - latitudeString[latitudeLen] = '\0'; - latitude = cLocale.toFloat(latitudeString); - } - else if (idx == longitudeCol) - { - longitudeString = p; - longitudeLen = strlen(longitudeString)-1; - longitudeString[longitudeLen] = '\0'; - longitude = cLocale.toFloat(longitudeString); - } - else if (idx == elevationCol) - { - elevationString = p; - elevationLen = strlen(elevationString)-1; - elevationString[elevationLen] = '\0'; - elevation = cLocale.toFloat(elevationString); - } - else if ((idx == powerCol) && (p[0] == '\"')) - { - power = p+1; - powerLen = strlen(power)-1; - power[powerLen] = '\0'; - } - idx++; - } - - // For now, we only want VORs - if (type && !strncmp(type, "VOR", 3)) - { - NavAid *vor = new NavAid(); - vor->m_id = id; - vor->m_ident = QString(ident); - // Check idents conform to our filtering rules - if (vor->m_ident.size() < 2) - qDebug() << "Warning: VOR Ident less than 2 characters: " << vor->m_ident; - else if (vor->m_ident.size() > 3) - qDebug() << "Warning: VOR Ident greater than 3 characters: " << vor->m_ident; - vor->m_type = QString(type); - vor->m_name = QString(name); - vor->m_frequencykHz = frequency; - vor->m_latitude = latitude; - vor->m_longitude = longitude; - vor->m_elevation = elevation; - if (power && !strcmp(power, "HIGH")) - vor->m_range = 100; - else if (power && !strcmp(power, "MEDIUM")) - vor->m_range = 40; - else - vor->m_range = 25; - vor->m_magneticDeclination = 0.0f; - vor->m_alignedTrueNorth = false; - navAidInfo->insert(id, vor); - cnt++; - } - } - } - fclose(file); - } - else - qDebug() << "NavAid::readNavAidsDB: Failed to open " << filename; - - qDebug() << "NavAid::readNavAidsDB: Read " << cnt << " VORs"; - - return navAidInfo; - } - -}; - -#endif // INCLUDE_NAVAID_H diff --git a/plugins/feature/vorlocalizer/readme.md b/plugins/feature/vorlocalizer/readme.md index 057424524..2f4050fb9 100644 --- a/plugins/feature/vorlocalizer/readme.md +++ b/plugins/feature/vorlocalizer/readme.md @@ -2,7 +2,7 @@

Introduction

-This plugin can control and receive information from single channel VOR demodulators (see [VOR single channel demodulator](../../channelrx/demodvorsc/readme.md) for details) and collate information from multiple VOR demodulators in order to show your position on a map. +This plugin can control and receive information from VOR demodulators (see [VOR demodulator](../../channelrx/demodvor/readme.md) for details) and collate information from multiple VOR demodulators in order to show your position on a map.

Interface

@@ -19,7 +19,7 @@ There are 3 sections in this interface:

1: Start/Stop plugin

-This button starts or stops the plugin +This button starts or stops the plugin.

2: Download VOR Database

@@ -35,7 +35,7 @@ Available VOR demodulator channels are allocated to service the selected VORs on

5: Round robin turn time progress

-Shows the round robin turn time progress +Shows the round robin turn time progress.

6: Force averaging over round robin turn time

@@ -55,10 +55,6 @@ Channels may be used in round robin turns if their number is not enough to cover When there is more than one turn for a device valid radial directions are averaged and the resulting average is used during the round robin loop. Averaging also takes place for reference and variable signal levels. -

9: Refresh VOR demodulators list and allocation

- -Use this button to (re)scan the available VOR demodulators in the SDRangel instance and (re)run the round robin allocation. -

B: VOR Table

The VOR table displays information about selected VORs. To select or deselect a VOR, double click it on the map. The information displayed includes: @@ -67,7 +63,6 @@ The VOR table displays information about selected VORs. To select or deselect a * Name - The name of the VOR. For example: 'LONDON'. * Freq (MHz) - The center frequency the VOR transmits on in MHz. The frequency is highlighted in green when the VOR is serviced by a demodulator. -* Nav Id - This is the VOR unique identifier from the VOR database. * Ident - A 2 or 3 character identifier for the VOR. For example: 'LON'. * Morse - The Morse code identifier for the VOR. For example: '.-.. --- -.' * RX Ident - This contains the demodulated ident. If it matches the expected ident, it will be displayed in green, if not, it will be displayed in red. If an ident is received that is not 2 or 3 characters, it will not be displayed, but the last received ident will be displayed in yellow. diff --git a/plugins/feature/vorlocalizer/vorlocalizer.cpp b/plugins/feature/vorlocalizer/vorlocalizer.cpp index f618cc580..30d8d5d58 100644 --- a/plugins/feature/vorlocalizer/vorlocalizer.cpp +++ b/plugins/feature/vorlocalizer/vorlocalizer.cpp @@ -152,10 +152,10 @@ bool VORLocalizer::handleMessage(const Message& cmd) SWGSDRangel::SWGChannelReport* swgChannelReport = report.getSWGReport(); QString *channelType = swgChannelReport->getChannelType(); - if (*channelType == "VORDemodSC") + if (*channelType == "VORDemod") { - SWGSDRangel::SWGVORDemodSCReport *swgVORDemodSCReport = swgChannelReport->getVorDemodScReport(); - int navId = swgVORDemodSCReport->getNavId(); + SWGSDRangel::SWGVORDemodReport *swgVORDemodReport = swgChannelReport->getVorDemodReport(); + int navId = swgVORDemodReport->getNavId(); if (navId < 0) { // disregard message for unallocated channels return true; @@ -165,45 +165,45 @@ bool VORLocalizer::handleMessage(const Message& cmd) m_vorSinglePlans[navId] : false; - // qDebug() << "VORLocalizer::handleMessage: MainCore::MsgChannelReport(VORDemodSC): " + // qDebug() << "VORLocalizer::handleMessage: MainCore::MsgChannelReport(VORDemod): " // << "navId:" << navId // << "singlePlanProvided" << m_vorSinglePlans.contains(navId) // << "singlePlan:" << singlePlan; if (m_vorChannelReports.contains(navId)) { - m_vorChannelReports[navId].m_radial = swgVORDemodSCReport->getRadial(); - m_vorChannelReports[navId].m_refMag = swgVORDemodSCReport->getRefMag(); - m_vorChannelReports[navId].m_varMag = swgVORDemodSCReport->getVarMag(); - m_vorChannelReports[navId].m_validRadial = swgVORDemodSCReport->getValidRadial() != 0; - m_vorChannelReports[navId].m_validRefMag = swgVORDemodSCReport->getValidRefMag() != 0; - m_vorChannelReports[navId].m_validVarMag = swgVORDemodSCReport->getValidVarMag() != 0; - m_vorChannelReports[navId].m_morseIdent = *swgVORDemodSCReport->getMorseIdent(); + m_vorChannelReports[navId].m_radial = swgVORDemodReport->getRadial(); + m_vorChannelReports[navId].m_refMag = swgVORDemodReport->getRefMag(); + m_vorChannelReports[navId].m_varMag = swgVORDemodReport->getVarMag(); + m_vorChannelReports[navId].m_validRadial = swgVORDemodReport->getValidRadial() != 0; + m_vorChannelReports[navId].m_validRefMag = swgVORDemodReport->getValidRefMag() != 0; + m_vorChannelReports[navId].m_validVarMag = swgVORDemodReport->getValidVarMag() != 0; + m_vorChannelReports[navId].m_morseIdent = *swgVORDemodReport->getMorseIdent(); } else { m_vorChannelReports[navId] = VORChannelReport{ - swgVORDemodSCReport->getRadial(), - swgVORDemodSCReport->getRefMag(), - swgVORDemodSCReport->getVarMag(), + swgVORDemodReport->getRadial(), + swgVORDemodReport->getRefMag(), + swgVORDemodReport->getVarMag(), AverageUtil(), AverageUtil(), AverageUtil(), - swgVORDemodSCReport->getValidRadial() != 0, - swgVORDemodSCReport->getValidRefMag() != 0, - swgVORDemodSCReport->getValidVarMag() != 0, - *swgVORDemodSCReport->getMorseIdent() + swgVORDemodReport->getValidRadial() != 0, + swgVORDemodReport->getValidRefMag() != 0, + swgVORDemodReport->getValidVarMag() != 0, + *swgVORDemodReport->getMorseIdent() }; } if (m_vorChannelReports[navId].m_validRadial) { - m_vorChannelReports[navId].m_radialAvg(swgVORDemodSCReport->getRadial()); + m_vorChannelReports[navId].m_radialAvg(swgVORDemodReport->getRadial()); } if (m_vorChannelReports[navId].m_validRefMag) { - m_vorChannelReports[navId].m_refMagAvg(swgVORDemodSCReport->getRefMag()); + m_vorChannelReports[navId].m_refMagAvg(swgVORDemodReport->getRefMag()); } if (m_vorChannelReports[navId].m_validVarMag) { - m_vorChannelReports[navId].m_varMagAvg(swgVORDemodSCReport->getVarMag()); + m_vorChannelReports[navId].m_varMagAvg(swgVORDemodReport->getVarMag()); } if (getMessageQueueToGUI()) @@ -373,7 +373,7 @@ void VORLocalizer::updateChannels() { ChannelAPI *channel = deviceSet->getChannelAt(chi); - if (channel->getURI() == "sdrangel.channel.vordemodsc") + if (channel->getURI() == "sdrangel.channel.vordemod") { if (!m_availableChannels.contains(channel)) { @@ -667,7 +667,7 @@ void VORLocalizer::handleChannelAdded(int deviceSetIndex, ChannelAPI *channel) DeviceSet *deviceSet = MainCore::instance()->getDeviceSets()[deviceSetIndex]; DSPDeviceSourceEngine *deviceSourceEngine = deviceSet->m_deviceSourceEngine; - if (deviceSourceEngine && (channel->getURI() == "sdrangel.channel.vordemodsc")) + if (deviceSourceEngine && (channel->getURI() == "sdrangel.channel.vordemod")) { DeviceSampleSource *deviceSource = deviceSourceEngine->getSource(); quint64 deviceCenterFrequency = deviceSource->getCenterFrequency(); diff --git a/plugins/feature/vorlocalizer/vorlocalizergui.cpp b/plugins/feature/vorlocalizer/vorlocalizergui.cpp index ae89e4612..7f8811f4a 100644 --- a/plugins/feature/vorlocalizer/vorlocalizergui.cpp +++ b/plugins/feature/vorlocalizer/vorlocalizergui.cpp @@ -47,258 +47,6 @@ #include "vorlocalizersettings.h" #include "vorlocalizergui.h" -static const char *countryCodes[] = { - "ad", - "ae", - "af", - "ag", - "ai", - "al", - "am", - "an", - "ao", - "aq", - "ar", - "as", - "at", - "au", - "aw", - "ax", - "az", - "ba", - "bb", - "bd", - "be", - "bf", - "bg", - "bh", - "bi", - "bj", - "bl", - "bm", - "bn", - "bo", - "bq", - "br", - "bs", - "bt", - "bv", - "bw", - "by", - "bz", - "ca", - "cc", - "cd", - "cf", - "cg", - "ch", - "ci", - "ck", - "cl", - "cm", - "cn", - "co", - "cr", - "cu", - "cv", - "cw", - "cx", - "cy", - "cz", - "de", - "dj", - "dk", - "dm", - "do", - "dz", - "ec", - "ee", - "eg", - "eh", - "er", - "es", - "et", - "fi", - "fj", - "fk", - "fm", - "fo", - "fr", - "ga", - "gb", - "ge", - "gf", - "gg", - "gh", - "gi", - "gl", - "gm", - "gn", - "gp", - "gq", - "gr", - "gs", - "gt", - "gu", - "gw", - "gy", - "hk", - "hm", - "hn", - "hr", - "hu", - "id", - "ie", - "il", - "im", - "in", - "io", - "iq", - "ir", - "is", - "it", - "je", - "jm", - "jo", - "jp", - "ke", - "kg", - "kh", - "ki", - "km", - "kn", - "kp", - "kr", - "kw", - "ky", - "kz", - "la", - "lb", - "lc", - "li", - "lk", - "lr", - "ls", - "lt", - "lu", - "lv", - "ly", - "ma", - "mc", - "md", - "me", - "mf", - "mg", - "mh", - "mk", - "ml", - "mm", - "mn", - "mo", - "mp", - "mq", - "mr", - "ms", - "mt", - "mu", - "mv", - "mw", - "mx", - "my", - "mz", - "na", - "nc", - "ne", - "nf", - "ng", - "ni", - "nl", - "no", - "np", - "nr", - "nu", - "nz", - "om", - "pa", - "pe", - "pf", - "pg", - "ph", - "pk", - "pl", - "pm", - "pn", - "pr", - "ps", - "pt", - "pw", - "py", - "qa", - "re", - "ro", - "rs", - "ru", - "rw", - "sa", - "sb", - "sc", - "sd", - "se", - "sg", - "sh", - "si", - "sj", - "sk", - "sl", - "sm", - "sn", - "so", - "sr", - "ss", - "st", - "sv", - "sx", - "sy", - "sz", - "tc", - "td", - "tf", - "tg", - "th", - "tj", - "tk", - "tl", - "tm", - "tn", - "to", - "tr", - "tt", - "tv", - "tw", - "tz", - "ua", - "ug", - "um", - "us", - "uy", - "uz", - "va", - "vc", - "ve", - "vg", - "vi", - "vn", - "vu", - "wf", - "ws", - "ye", - "yt", - "za", - "zm", - "zw", - nullptr -}; - // Lats and longs in decimal degrees. Distance in metres. Bearing in degrees. // https://www.movable-type.co.uk/scripts/latlong.html static void calcRadialEndPoint(float startLatitude, float startLongitude, float distance, float bearing, float &endLatitude, float &endLongitude) @@ -389,7 +137,6 @@ VORGUI::VORGUI(NavAid *navAid, VORLocalizerGUI *gui) : // These are deleted by QTableWidget m_nameItem = new QTableWidgetItem(); m_frequencyItem = new QTableWidgetItem(); - m_navIdItem = new QTableWidgetItem(); m_radialItem = new QTableWidgetItem(); m_identItem = new QTableWidgetItem(); m_morseItem = new QTableWidgetItem(); @@ -610,7 +357,6 @@ void VORLocalizerGUI::resizeTable() ui->vorData->setRowCount(row + 1); ui->vorData->setItem(row, VORLocalizerSettings::VOR_COL_NAME, new QTableWidgetItem("White Sulphur Springs")); ui->vorData->setItem(row, VORLocalizerSettings::VOR_COL_FREQUENCY, new QTableWidgetItem("Freq (MHz) ")); - ui->vorData->setItem(row, VORLocalizerSettings::VOR_COL_NAVID, new QTableWidgetItem("99999999")); ui->vorData->setItem(row, VORLocalizerSettings::VOR_COL_IDENT, new QTableWidgetItem("Ident ")); ui->vorData->setItem(row, VORLocalizerSettings::VOR_COL_MORSE, new QTableWidgetItem(Morse::toSpacedUnicode(morse))); ui->vorData->setItem(row, VORLocalizerSettings::VOR_COL_RADIAL, new QTableWidgetItem("Radial (o) ")); @@ -684,7 +430,6 @@ void VORLocalizerGUI::selectVOR(VORGUI *vorGUI, bool selected) ui->vorData->setRowCount(row + 1); ui->vorData->setItem(row, VORLocalizerSettings::VOR_COL_NAME, vorGUI->m_nameItem); ui->vorData->setItem(row, VORLocalizerSettings::VOR_COL_FREQUENCY, vorGUI->m_frequencyItem); - ui->vorData->setItem(row, VORLocalizerSettings::VOR_COL_NAVID, vorGUI->m_navIdItem); ui->vorData->setItem(row, VORLocalizerSettings::VOR_COL_IDENT, vorGUI->m_identItem); ui->vorData->setItem(row, VORLocalizerSettings::VOR_COL_MORSE, vorGUI->m_morseItem); ui->vorData->setItem(row, VORLocalizerSettings::VOR_COL_RADIAL, vorGUI->m_radialItem); @@ -702,7 +447,7 @@ void VORLocalizerGUI::selectVOR(VORGUI *vorGUI, bool selected) // Add to settings to create corresponding demodulator m_settings.m_subChannelSettings.insert(navId, VORLocalizerSubChannelSettings{ navId, - vorGUI->m_navAid->m_frequencykHz * 1000, + (int)(vorGUI->m_navAid->m_frequencykHz * 1000), false }); @@ -725,23 +470,21 @@ void VORLocalizerGUI::selectVOR(VORGUI *vorGUI, bool selected) void VORLocalizerGUI::updateVORs() { m_vorModel.removeAllVORs(); - QHash::iterator i = m_vors->begin(); AzEl azEl = m_azEl; - while (i != m_vors->end()) + for (auto vor : m_vors) { - NavAid *vor = i.value(); + if (vor->m_type.contains("VOR")) // Exclude DMEs + { + // Calculate distance to VOR from My Position + azEl.setTarget(vor->m_latitude, vor->m_longitude, Units::feetToMetres(vor->m_elevation)); + azEl.calculate(); - // Calculate distance to VOR from My Position - azEl.setTarget(vor->m_latitude, vor->m_longitude, Units::feetToMetres(vor->m_elevation)); - azEl.calculate(); - - // Only display VOR if in range - if (azEl.getDistance() <= 200000) { - m_vorModel.addVOR(vor); + // Only display VOR if in range + if (azEl.getDistance() <= 200000) { + m_vorModel.addVOR(vor); + } } - - ++i; } } @@ -772,6 +515,7 @@ bool VORLocalizerGUI::deserialize(const QByteArray& data) { if (m_settings.deserialize(data)) { + m_feature->setWorkspaceIndex(m_settings.m_workspaceIndex); displaySettings(); applySettings(true); return true; @@ -807,41 +551,46 @@ bool VORLocalizerGUI::handleMessage(const Message& message) int subChannelId = report.getSubChannelId(); VORGUI *vorGUI = m_selectedVORs.value(subChannelId); + if (vorGUI) + { + // Display radial and signal magnitudes in table - // Display radial and signal magnitudes in table + Real varMagDB = std::round(20.0*std::log10(report.getVarMag())); + Real refMagDB = std::round(20.0*std::log10(report.getRefMag())); - Real varMagDB = std::round(20.0*std::log10(report.getVarMag())); - Real refMagDB = std::round(20.0*std::log10(report.getRefMag())); + bool validRadial = report.getValidRadial(); + vorGUI->m_radialItem->setData(Qt::DisplayRole, std::round(report.getRadial())); - bool validRadial = report.getValidRadial(); - vorGUI->m_radialItem->setData(Qt::DisplayRole, std::round(report.getRadial())); - vorGUI->m_navIdItem->setData(Qt::DisplayRole, subChannelId); + if (validRadial) { + vorGUI->m_radialItem->setForeground(QBrush(Qt::white)); + } else { + vorGUI->m_radialItem->setForeground(QBrush(Qt::red)); + } - if (validRadial) { - vorGUI->m_radialItem->setForeground(QBrush(Qt::white)); - } else { - vorGUI->m_radialItem->setForeground(QBrush(Qt::red)); + vorGUI->m_refMagItem->setData(Qt::DisplayRole, refMagDB); + + if (report.getValidRefMag()) { + vorGUI->m_refMagItem->setForeground(QBrush(Qt::white)); + } else { + vorGUI->m_refMagItem->setForeground(QBrush(Qt::red)); + } + + vorGUI->m_varMagItem->setData(Qt::DisplayRole, varMagDB); + + if (report.getValidVarMag()) { + vorGUI->m_varMagItem->setForeground(QBrush(Qt::white)); + } else { + vorGUI->m_varMagItem->setForeground(QBrush(Qt::red)); + } + + // Update radial on map + m_vorModel.setRadial(subChannelId, validRadial, report.getRadial()); } - - vorGUI->m_refMagItem->setData(Qt::DisplayRole, refMagDB); - - if (report.getValidRefMag()) { - vorGUI->m_refMagItem->setForeground(QBrush(Qt::white)); - } else { - vorGUI->m_refMagItem->setForeground(QBrush(Qt::red)); + else + { + qDebug() << "VORLocalizerGUI::handleMessage: Got MsgReportRadial for non-existant subChannelId " << subChannelId; } - vorGUI->m_varMagItem->setData(Qt::DisplayRole, varMagDB); - - if (report.getValidVarMag()) { - vorGUI->m_varMagItem->setForeground(QBrush(Qt::white)); - } else { - vorGUI->m_varMagItem->setForeground(QBrush(Qt::red)); - } - - // Update radial on map - m_vorModel.setRadial(subChannelId, validRadial, report.getRadial()); - return true; } else if (VORLocalizerReport::MsgReportIdent::match(message)) @@ -850,38 +599,45 @@ bool VORLocalizerGUI::handleMessage(const Message& message) int subChannelId = report.getSubChannelId(); VORGUI *vorGUI = m_selectedVORs.value(subChannelId); - - QString ident = report.getIdent(); - // Convert Morse to a string - QString identString = Morse::toString(ident); - // Idents should only be two or three characters, so filter anything else - // other than TEST which indicates a VOR is under maintainance (may also be TST) - if (((identString.size() >= 2) && (identString.size() <= 3)) || (identString == "TEST")) + if (vorGUI) { - vorGUI->m_rxIdentItem->setText(identString); - vorGUI->m_rxMorseItem->setText(Morse::toSpacedUnicode(ident)); - if (vorGUI->m_navAid->m_ident == identString) + QString ident = report.getIdent(); + // Convert Morse to a string + QString identString = Morse::toString(ident); + // Idents should only be two or three characters, so filter anything else + // other than TEST which indicates a VOR is under maintainance (may also be TST) + if (((identString.size() >= 2) && (identString.size() <= 3)) || (identString == "TEST")) { - // Set colour to green if matching expected ident - vorGUI->m_rxIdentItem->setForeground(QBrush(Qt::green)); - vorGUI->m_rxMorseItem->setForeground(QBrush(Qt::green)); + vorGUI->m_rxIdentItem->setText(identString); + vorGUI->m_rxMorseItem->setText(Morse::toSpacedUnicode(ident)); + + if (vorGUI->m_navAid->m_ident == identString) + { + // Set colour to green if matching expected ident + vorGUI->m_rxIdentItem->setForeground(QBrush(Qt::green)); + vorGUI->m_rxMorseItem->setForeground(QBrush(Qt::green)); + } + else + { + // Set colour to green if not matching expected ident + vorGUI->m_rxIdentItem->setForeground(QBrush(Qt::red)); + vorGUI->m_rxMorseItem->setForeground(QBrush(Qt::red)); + } } else { - // Set colour to green if not matching expected ident - vorGUI->m_rxIdentItem->setForeground(QBrush(Qt::red)); - vorGUI->m_rxMorseItem->setForeground(QBrush(Qt::red)); + // Set yellow to indicate we've filtered something (unless red) + if (vorGUI->m_rxIdentItem->foreground().color() != Qt::red) + { + vorGUI->m_rxIdentItem->setForeground(QBrush(Qt::yellow)); + vorGUI->m_rxMorseItem->setForeground(QBrush(Qt::yellow)); + } } } else { - // Set yellow to indicate we've filtered something (unless red) - if (vorGUI->m_rxIdentItem->foreground().color() != Qt::red) - { - vorGUI->m_rxIdentItem->setForeground(QBrush(Qt::yellow)); - vorGUI->m_rxMorseItem->setForeground(QBrush(Qt::yellow)); - } + qDebug() << "VORLocalizerGUI::handleMessage: Got MsgReportIdent for non-existant subChannelId " << subChannelId; } return true; @@ -938,168 +694,17 @@ void VORLocalizerGUI::handleInputMessages() } } -qint64 VORLocalizerGUI::fileAgeInDays(QString filename) -{ - QFile file(filename); - - if (file.exists()) - { - QDateTime modified = file.fileTime(QFileDevice::FileModificationTime); - - if (modified.isValid()) { - return modified.daysTo(QDateTime::currentDateTime()); - } else { - return -1; - } - } - - return -1; -} - -bool VORLocalizerGUI::confirmDownload(QString filename) -{ - qint64 age = fileAgeInDays(filename); - - if ((age == -1) || (age > 100)) - { - return true; - } - else - { - QMessageBox::StandardButton reply; - - if (age == 0) { - reply = QMessageBox::question(this, "Confirm download", "This file was last downloaded today. Are you sure you wish to redownload it?", QMessageBox::Yes|QMessageBox::No); - } else if (age == 1) { - reply = QMessageBox::question(this, "Confirm download", "This file was last downloaded yesterday. Are you sure you wish to redownload it?", QMessageBox::Yes|QMessageBox::No); - } else { - reply = QMessageBox::question(this, "Confirm download", QString("This file was last downloaded %1 days ago. Are you sure you wish to redownload this file?").arg(age), QMessageBox::Yes|QMessageBox::No); - } - - return reply == QMessageBox::Yes; - } -} - -QString VORLocalizerGUI::getDataDir() -{ - // Get directory to store app data in - QStringList locations = QStandardPaths::standardLocations(QStandardPaths::AppDataLocation); - // First dir is writable - return locations[0]; -} - -QString VORLocalizerGUI::getOpenAIPVORDBFilename(int i) -{ - if (countryCodes[i] != nullptr) { - return getDataDir() + "/" + countryCodes[i] + "_nav.aip"; - } else { - return ""; - } -} - -QString VORLocalizerGUI::getOpenAIPVORDBURL(int i) -{ - if (countryCodes[i] != nullptr) { - return QString(OPENAIP_NAVAIDS_URL).arg(countryCodes[i]); - } else { - return ""; - } -} - -QString VORLocalizerGUI::getVORDBFilename() -{ - return getDataDir() + "/vorDatabase.csv"; -} - -void VORLocalizerGUI::updateDownloadProgress(qint64 bytesRead, qint64 totalBytes) -{ - if (m_progressDialog) - { - m_progressDialog->setMaximum(totalBytes); - m_progressDialog->setValue(bytesRead); - } -} - -void VORLocalizerGUI::downloadFinished(const QString& filename, bool success) -{ - bool closeDialog = true; - if (success) - { - if (filename == getVORDBFilename()) - { - m_vors = NavAid::readNavAidsDB(filename); - - if (m_vors != nullptr) { - updateVORs(); - } - } - else if (filename == getOpenAIPVORDBFilename(m_countryIndex)) - { - m_countryIndex++; - - if (countryCodes[m_countryIndex] != nullptr) - { - QString vorDBFile = getOpenAIPVORDBFilename(m_countryIndex); - QString urlString = getOpenAIPVORDBURL(m_countryIndex); - QUrl dbURL(urlString); - m_progressDialog->setLabelText(QString("Downloading %1.").arg(urlString)); - m_progressDialog->setValue(m_countryIndex); - m_dlm.download(dbURL, vorDBFile); - closeDialog = false; - } - else - { - readNavAids(); - - if (m_vors) { - updateVORs(); - } - } - } - else - { - qDebug() << "VORLocalizerGUI::downloadFinished: Unexpected filename: " << filename; - } - } - else - { - qDebug() << "VORLocalizerGUI::downloadFinished: Failed: " << filename; - QMessageBox::warning(this, "Download failed", QString("Failed to download %1").arg(filename)); - } - if (closeDialog && m_progressDialog) - { - m_progressDialog->close(); - delete m_progressDialog; - m_progressDialog = nullptr; - } -} - void VORLocalizerGUI::on_startStop_toggled(bool checked) { if (m_doApplySettings) { VORLocalizer::MsgStartStop *message = VORLocalizer::MsgStartStop::create(checked); m_vorLocalizer->getInputMessageQueue()->push(message); - } -} -void VORLocalizerGUI::on_getOurAirportsVORDB_clicked() -{ - // Don't try to download while already in progress - if (m_progressDialog == nullptr) - { - QString vorDBFile = getVORDBFilename(); - - if (confirmDownload(vorDBFile)) + if (checked) { - // Download OurAirports navaid database to disk - QUrl dbURL(QString(OURAIRPORTS_NAVAIDS_URL)); - m_progressDialog = new QProgressDialog(this); - m_progressDialog->setCancelButton(nullptr); - m_progressDialog->setMinimumDuration(500); - m_progressDialog->setLabelText(QString("Downloading %1.").arg(OURAIRPORTS_NAVAIDS_URL)); - QNetworkReply *reply = m_dlm.download(dbURL, vorDBFile); - connect(reply, SIGNAL(downloadProgress(qint64,qint64)), this, SLOT(updateDownloadProgress(qint64,qint64))); + // Refresh channels in case device b/w has changed + channelsRefresh(); } } } @@ -1109,33 +714,51 @@ void VORLocalizerGUI::on_getOpenAIPVORDB_clicked() // Don't try to download while already in progress if (!m_progressDialog) { - m_countryIndex = 0; - QString vorDBFile = getOpenAIPVORDBFilename(m_countryIndex); + m_progressDialog = new QProgressDialog(this); + m_progressDialog->setMaximum(OpenAIP::m_countryCodes.size()); + m_progressDialog->setCancelButton(nullptr); - if (confirmDownload(vorDBFile)) - { - // Download OpenAIP XML to disk - QString urlString = getOpenAIPVORDBURL(m_countryIndex); - QUrl dbURL(urlString); - m_progressDialog = new QProgressDialog(this); - m_progressDialog->setCancelButton(nullptr); - m_progressDialog->setMinimumDuration(500); - m_progressDialog->setMaximum(sizeof(countryCodes)/sizeof(countryCodes[0])); - m_progressDialog->setValue(0); - m_progressDialog->setLabelText(QString("Downloading %1.").arg(urlString)); - m_dlm.download(dbURL, vorDBFile); - } + m_openAIP.downloadNavAids(); } } void VORLocalizerGUI::readNavAids() { - m_vors = new QHash(); + m_vors = OpenAIP::readNavAids(); + updateVORs(); +} - for (int countryIndex = 0; countryCodes[countryIndex] != nullptr; countryIndex++) +void VORLocalizerGUI::downloadingURL(const QString& url) +{ + if (m_progressDialog) { - QString vorDBFile = getOpenAIPVORDBFilename(countryIndex); - NavAid::readNavAidsXML(m_vors, vorDBFile); + m_progressDialog->setLabelText(QString("Downloading %1.").arg(url)); + m_progressDialog->setValue(m_progressDialog->value() + 1); + } +} + +void VORLocalizerGUI::downloadError(const QString& error) +{ + QMessageBox::critical(this, "VOR Localizer", error); + if (m_progressDialog) + { + m_progressDialog->close(); + delete m_progressDialog; + m_progressDialog = nullptr; + } +} + +void VORLocalizerGUI::downloadNavAidsFinished() +{ + if (m_progressDialog) { + m_progressDialog->setLabelText("Reading NAVAIDs."); + } + readNavAids(); + if (m_progressDialog) + { + m_progressDialog->close(); + delete m_progressDialog; + m_progressDialog = nullptr; } } @@ -1160,7 +783,7 @@ void VORLocalizerGUI::on_centerShift_valueChanged(int value) applySettings(); } -void VORLocalizerGUI::on_channelsRefresh_clicked() +void VORLocalizerGUI::channelsRefresh() { if (m_doApplySettings) { @@ -1174,7 +797,18 @@ void VORLocalizerGUI::onWidgetRolled(QWidget* widget, bool rollDown) (void) widget; (void) rollDown; - saveState(m_rollupState); + RollupContents *rollupContents = getRollupContents(); + + if (rollupContents->hasExpandableWidgets()) { + setSizePolicy(sizePolicy().horizontalPolicy(), QSizePolicy::Expanding); + } else { + setSizePolicy(sizePolicy().horizontalPolicy(), QSizePolicy::Fixed); + } + + int h = rollupContents->height() + getAdditionalHeight(); + resize(width(), h); + + rollupContents->saveState(m_rollupState); applySettings(); } @@ -1184,17 +818,16 @@ void VORLocalizerGUI::onMenuDialogCalled(const QPoint &p) { BasicFeatureSettingsDialog dialog(this); dialog.setTitle(m_settings.m_title); - dialog.setColor(m_settings.m_rgbColor); dialog.setUseReverseAPI(m_settings.m_useReverseAPI); dialog.setReverseAPIAddress(m_settings.m_reverseAPIAddress); dialog.setReverseAPIPort(m_settings.m_reverseAPIPort); dialog.setReverseAPIFeatureSetIndex(m_settings.m_reverseAPIFeatureSetIndex); dialog.setReverseAPIFeatureIndex(m_settings.m_reverseAPIFeatureIndex); + dialog.setDefaultTitle(m_displayedName); dialog.move(p); dialog.exec(); - m_settings.m_rgbColor = dialog.getColor().rgb(); m_settings.m_title = dialog.getTitle(); m_settings.m_useReverseAPI = dialog.useReverseAPI(); m_settings.m_reverseAPIAddress = dialog.getReverseAPIAddress(); @@ -1202,7 +835,7 @@ void VORLocalizerGUI::onMenuDialogCalled(const QPoint &p) m_settings.m_reverseAPIFeatureSetIndex = dialog.getReverseAPIFeatureSetIndex(); m_settings.m_reverseAPIFeatureIndex = dialog.getReverseAPIFeatureIndex(); - setWindowTitle(m_settings.m_title); + setTitle(m_settings.m_title); setTitleColor(m_settings.m_rgbColor); applySettings(); @@ -1221,12 +854,17 @@ VORLocalizerGUI::VORLocalizerGUI(PluginAPI* pluginAPI, FeatureUISet *featureUISe m_tickCount(0), m_progressDialog(nullptr), m_vorModel(this), - m_vors(nullptr), m_lastFeatureState(0), m_rrSecondsCount(0) { - ui->setupUi(this); + m_feature = feature; + setAttribute(Qt::WA_DeleteOnClose, true); m_helpURL = "plugins/feature/vorlocalizer/readme.md"; + RollupContents *rollupContents = getRollupContents(); + ui->setupUi(rollupContents); + setSizePolicy(rollupContents->sizePolicy()); + rollupContents->arrangeRollups(); + connect(rollupContents, SIGNAL(widgetRolled(QWidget*,bool)), this, SLOT(onWidgetRolled(QWidget*,bool))); ui->map->rootContext()->setContextProperty("vorModel", &m_vorModel); ui->map->setSource(QUrl(QStringLiteral("qrc:/demodvor/map/map.qml"))); @@ -1234,17 +872,16 @@ VORLocalizerGUI::VORLocalizerGUI(PluginAPI* pluginAPI, FeatureUISet *featureUISe m_muteIcon.addPixmap(QPixmap("://sound_off.png"), QIcon::Normal, QIcon::On); m_muteIcon.addPixmap(QPixmap("://sound_on.png"), QIcon::Normal, QIcon::Off); - 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(&m_dlm, &HttpDownloadManager::downloadComplete, this, &VORLocalizerGUI::downloadFinished); + connect(&m_openAIP, &OpenAIP::downloadingURL, this, &VORLocalizerGUI::downloadingURL); + connect(&m_openAIP, &OpenAIP::downloadError, this, &VORLocalizerGUI::downloadError); + connect(&m_openAIP, &OpenAIP::downloadNavAidsFinished, this, &VORLocalizerGUI::downloadNavAidsFinished); m_vorLocalizer = reinterpret_cast(feature); m_vorLocalizer->setMessageQueueToGUI(getInputMessageQueue()); connect(&MainCore::instance()->getMasterTimer(), SIGNAL(timeout()), this, SLOT(tick())); // 50 ms - m_featureUISet->addRollupWidget(this); m_settings.setRollupState(&m_rollupState); connect(getInputMessageQueue(), SIGNAL(messageEnqueued()), this, SLOT(handleInputMessages())); @@ -1281,22 +918,7 @@ VORLocalizerGUI::VORLocalizerGUI(PluginAPI* pluginAPI, FeatureUISet *featureUISe } // Read in VOR information if it exists - bool useOurAirports = false; - - if (useOurAirports) - { - m_vors = NavAid::readNavAidsDB(getVORDBFilename()); - ui->getOpenAIPVORDB->setVisible(false); - } - else - { - readNavAids(); - ui->getOurAirportsVORDB->setVisible(false); - } - - if (m_vors) { - updateVORs(); - } + readNavAids(); // Resize the table using dummy data resizeTable(); @@ -1326,13 +948,39 @@ VORLocalizerGUI::VORLocalizerGUI(PluginAPI* pluginAPI, FeatureUISet *featureUISe ui->rrTurnTimeProgress->setValue(0); ui->rrTurnTimeProgress->setToolTip(tr("Round robin turn time %1s").arg(0)); + // Get updated when position changes + connect(&MainCore::instance()->getSettings(), &MainSettings::preferenceChanged, this, &VORLocalizerGUI::preferenceChanged); + displaySettings(); applySettings(true); + + connect(&m_redrawMapTimer, &QTimer::timeout, this, &VORLocalizerGUI::redrawMap); + m_redrawMapTimer.setSingleShot(true); + ui->map->installEventFilter(this); + + makeUIConnections(); + + // Update channel list when added/removed + connect(MainCore::instance(), &MainCore::channelAdded, this, &VORLocalizerGUI::channelsRefresh); + connect(MainCore::instance(), &MainCore::channelRemoved, this, &VORLocalizerGUI::channelsRefresh); + // Also replan when device changed (as bandwidth may change or may becomed fixed center freq) + connect(MainCore::instance(), &MainCore::deviceChanged, this, &VORLocalizerGUI::channelsRefresh); + // List already opened channels + channelsRefresh(); } VORLocalizerGUI::~VORLocalizerGUI() { + disconnect(&m_redrawMapTimer, &QTimer::timeout, this, &VORLocalizerGUI::redrawMap); + m_redrawMapTimer.stop(); delete ui; + qDeleteAll(m_vors); +} + +void VORLocalizerGUI::setWorkspaceIndex(int index) +{ + m_settings.m_workspaceIndex = index; + m_feature->setWorkspaceIndex(index); } void VORLocalizerGUI::blockApplySettings(bool block) @@ -1353,6 +1001,7 @@ void VORLocalizerGUI::displaySettings() { setTitleColor(m_settings.m_rgbColor); setWindowTitle(m_settings.m_title); + setTitle(m_settings.m_title); blockApplySettings(true); @@ -1378,18 +1027,10 @@ void VORLocalizerGUI::displaySettings() ui->centerShift->setValue(m_settings.m_centerShift/1000); ui->forceRRAveraging->setChecked(m_settings.m_forceRRAveraging); - restoreState(m_rollupState); + getRollupContents()->restoreState(m_rollupState); blockApplySettings(false); } -void VORLocalizerGUI::leaveEvent(QEvent*) -{ -} - -void VORLocalizerGUI::enterEvent(QEvent*) -{ -} - void VORLocalizerGUI::updateStatus() { int state = m_vorLocalizer->getState(); @@ -1449,3 +1090,108 @@ void VORLocalizerGUI::tick() m_tickCount = 0; } } + +void VORLocalizerGUI::preferenceChanged(int elementType) +{ + Preferences::ElementType pref = (Preferences::ElementType)elementType; + if ((pref == Preferences::Latitude) || (pref == Preferences::Longitude) || (pref == Preferences::Altitude)) + { + Real stationLatitude = MainCore::instance()->getSettings().getLatitude(); + Real stationLongitude = MainCore::instance()->getSettings().getLongitude(); + Real stationAltitude = MainCore::instance()->getSettings().getAltitude(); + + if ( (stationLatitude != m_azEl.getLocationSpherical().m_latitude) + || (stationLongitude != m_azEl.getLocationSpherical().m_longitude) + || (stationAltitude != m_azEl.getLocationSpherical().m_altitude)) + { + m_azEl.setLocation(stationLatitude, stationLongitude, stationAltitude); + + // Update distances and what is visible + updateVORs(); + + // Update icon position on Map + QQuickItem *item = ui->map->rootObject(); + QObject *map = item->findChild("map"); + if (map != nullptr) + { + QObject *stationObject = map->findChild("station"); + if(stationObject != NULL) + { + QGeoCoordinate coords = stationObject->property("coordinate").value(); + coords.setLatitude(stationLatitude); + coords.setLongitude(stationLongitude); + coords.setAltitude(stationAltitude); + stationObject->setProperty("coordinate", QVariant::fromValue(coords)); + } + } + } + } + if (pref == Preferences::StationName) + { + // Update icon label on Map + QQuickItem *item = ui->map->rootObject(); + QObject *map = item->findChild("map"); + if (map != nullptr) + { + QObject *stationObject = map->findChild("station"); + if(stationObject != NULL) { + stationObject->setProperty("stationName", QVariant::fromValue(MainCore::instance()->getSettings().getStationName())); + } + } + } +} + +void VORLocalizerGUI::redrawMap() +{ + // An awful workaround for https://bugreports.qt.io/browse/QTBUG-100333 + // Also used in ADS-B demod + QQuickItem *item = ui->map->rootObject(); + if (item) + { + QObject *object = item->findChild("map"); + if (object) + { + double zoom = object->property("zoomLevel").value(); + object->setProperty("zoomLevel", QVariant::fromValue(zoom+1)); + object->setProperty("zoomLevel", QVariant::fromValue(zoom)); + } + } +} + +void VORLocalizerGUI::showEvent(QShowEvent *event) +{ + if (!event->spontaneous()) + { + // Workaround for https://bugreports.qt.io/browse/QTBUG-100333 + // MapQuickItems can be in wrong position when window is first displayed + m_redrawMapTimer.start(500); + } +} + +bool VORLocalizerGUI::eventFilter(QObject *obj, QEvent *event) +{ + if (obj == ui->map) + { + if (event->type() == QEvent::Resize) + { + // Workaround for https://bugreports.qt.io/browse/QTBUG-100333 + // MapQuickItems can be in wrong position after vertical resize + QResizeEvent *resizeEvent = static_cast(event); + QSize oldSize = resizeEvent->oldSize(); + QSize size = resizeEvent->size(); + if (oldSize.height() != size.height()) { + redrawMap(); + } + } + } + return false; +} + +void VORLocalizerGUI::makeUIConnections() +{ + QObject::connect(ui->startStop, &ButtonSwitch::toggled, this, &VORLocalizerGUI::on_startStop_toggled); + QObject::connect(ui->getOpenAIPVORDB, &QPushButton::clicked, this, &VORLocalizerGUI::on_getOpenAIPVORDB_clicked); + QObject::connect(ui->magDecAdjust, &ButtonSwitch::toggled, this, &VORLocalizerGUI::on_magDecAdjust_toggled); + QObject::connect(ui->rrTime, &QDial::valueChanged, this, &VORLocalizerGUI::on_rrTime_valueChanged); + QObject::connect(ui->centerShift, &QDial::valueChanged, this, &VORLocalizerGUI::on_centerShift_valueChanged); +} diff --git a/plugins/feature/vorlocalizer/vorlocalizergui.h b/plugins/feature/vorlocalizer/vorlocalizergui.h index 6a0092879..d0785a077 100644 --- a/plugins/feature/vorlocalizer/vorlocalizergui.h +++ b/plugins/feature/vorlocalizer/vorlocalizergui.h @@ -37,10 +37,10 @@ #include "util/messagequeue.h" #include "util/httpdownloadmanager.h" #include "util/azel.h" +#include "util/openaip.h" #include "settings/rollupstate.h" #include "vorlocalizersettings.h" -#include "navaid.h" class PluginAPI; class FeatureUISet; @@ -64,7 +64,6 @@ public: QTableWidgetItem *m_nameItem; QTableWidgetItem *m_frequencyItem; - QTableWidgetItem *m_navIdItem; QTableWidgetItem *m_identItem; QTableWidgetItem *m_morseItem; QTableWidgetItem *m_radialItem; @@ -214,6 +213,10 @@ public: bool deserialize(const QByteArray& data); virtual MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; } void selectVOR(VORGUI *vorGUI, bool selected); + virtual void setWorkspaceIndex(int index); + virtual int getWorkspaceIndex() const { return m_settings.m_workspaceIndex; } + virtual void setGeometryBytes(const QByteArray& blob) { m_settings.m_geometryBytes = blob; } + virtual QByteArray getGeometryBytes() const { return m_settings.m_geometryBytes; } private: friend class VORGUI; @@ -235,15 +238,17 @@ private: QMenu *menu; // Column select context menu HttpDownloadManager m_dlm; QProgressDialog *m_progressDialog; + OpenAIP m_openAIP; int m_countryIndex; VORModel m_vorModel; - QHash *m_vors; + QList m_vors; QHash m_selectedVORs; AzEl m_azEl; // Position of station QIcon m_muteIcon; QTimer m_statusTimer; int m_lastFeatureState; int m_rrSecondsCount; + QTimer m_redrawMapTimer; explicit VORLocalizerGUI(PluginAPI* pluginAPI, FeatureUISet *featureUISet, Feature *feature, QWidget* parent = nullptr); virtual ~VORLocalizerGUI(); @@ -252,9 +257,8 @@ private: void applySettings(bool force = false); void displaySettings(); bool handleMessage(const Message& message); - - void leaveEvent(QEvent*); - void enterEvent(QEvent*); + void redrawMap(); + void makeUIConnections(); void resizeTable(); QAction *createCheckableItem(QString& text, int idx, bool checked); @@ -262,35 +266,31 @@ private: void calculateFreqOffset(VORGUI *vorGUI); void calculateFreqOffsets(); void updateVORs(); - QString getOpenAIPVORDBURL(int i); - QString getOpenAIPVORDBFilename(int i); - QString getVORDBFilename(); void readNavAids(); - // Move to util - QString getDataDir(); - qint64 fileAgeInDays(QString filename); - bool confirmDownload(QString filename); void updateChannelList(); private slots: void on_startStop_toggled(bool checked); - void on_getOurAirportsVORDB_clicked(); void on_getOpenAIPVORDB_clicked(); void on_magDecAdjust_toggled(bool checked); void on_rrTime_valueChanged(int value); void on_centerShift_valueChanged(int value); - void on_channelsRefresh_clicked(); + void channelsRefresh(); void vorData_sectionMoved(int logicalIndex, int oldVisualIndex, int newVisualIndex); void vorData_sectionResized(int logicalIndex, int oldSize, int newSize); void columnSelectMenu(QPoint pos); void columnSelectMenuChecked(bool checked = false); void onWidgetRolled(QWidget* widget, bool rollDown); void onMenuDialogCalled(const QPoint& p); - void updateDownloadProgress(qint64 bytesRead, qint64 totalBytes); - void downloadFinished(const QString& filename, bool success); void handleInputMessages(); void updateStatus(); void tick(); + void downloadingURL(const QString& url); + void downloadError(const QString& error); + void downloadNavAidsFinished(); + void preferenceChanged(int elementType); + virtual void showEvent(QShowEvent *event); + virtual bool eventFilter(QObject *obj, QEvent *event); }; #endif // INCLUDE_VORLOCALIZERGUI_H diff --git a/plugins/feature/vorlocalizer/vorlocalizergui.ui b/plugins/feature/vorlocalizer/vorlocalizergui.ui index 256d519fd..1653842f4 100644 --- a/plugins/feature/vorlocalizer/vorlocalizergui.ui +++ b/plugins/feature/vorlocalizer/vorlocalizergui.ui @@ -1,13 +1,13 @@ VORLocalizerGUI - + 0 0 - 462 - 893 + 470 + 850 @@ -40,7 +40,7 @@ 0 0 461 - 61 + 31 @@ -85,23 +85,6 @@
- - - - true - - - Download OurAirports VOR database - - - - - - - :/demodvor/icons/vor.png:/demodvor/icons/vor.png - - - @@ -136,6 +119,13 @@ + + + + Qt::Vertical + + + @@ -180,7 +170,7 @@ - Sound volume (%) + Round robin turn time (s) 20s @@ -200,6 +190,7 @@ + Ubuntu 8 @@ -222,10 +213,17 @@ QToolTip{background-color: white; color: black;} + + + + Qt::Vertical + + + - Sh + Δcf @@ -274,22 +272,12 @@ QToolTip{background-color: white; color: black;}
- + - Qt::Horizontal + Qt::Vertical - - - 40 - 20 - - - +
- -
- - @@ -305,27 +293,7 @@ QToolTip{background-color: white; color: black;} - - - - 24 - 16777215 - - - - Refresh VOR channels available - - - - - - - :/recycle.png:/recycle.png - - - - - + Qt::Horizontal @@ -344,141 +312,10 @@ QToolTip{background-color: white; color: black;} - 0 - 110 - 461 - 140 - - - - - 0 - 0 - - - - VORs - - - - 2 - - - 3 - - - 3 - - - 3 - - - 3 - - - - - QAbstractItemView::NoEditTriggers - - - - Name - - - Name of the VOR - - - - - Freq (MHz) - - - Frequency of the VOR in MHz - - - - - Nav Id - - - Offset of the VOR's frequency from the current center frequency. Red indicates out of range. - - - - - Ident - - - Ident for the VOR - - - - - Morse - - - Morse code ident for the VOR - - - - - RX Ident - - - Received ident - - - - - RX Morse - - - Received Morse code ident - - - - - Radial (°) - - - Calculated radial from the VOR - - - - - Ref (dB) - - - Magnitude of received reference signal in dB - - - - - Var (dB) - - - Magnitude of received variable signal in dB - - - - - Mute - - - Mute/unmute audio from selected VORs - - - - - - - - - - 0 - 260 - 461 - 581 + 10 + 50 + 441 + 710 @@ -487,50 +324,155 @@ QToolTip{background-color: white; color: black;} 0 - - Map + + + 0 + 145 + - - - 2 - + + VORs + + - 3 + 0 - 3 + 0 - 3 + 0 - 3 + 0 - + 0 0 - - - 100 - 500 - - - - VOR map - - - QQuickWidget::SizeRootObjectToView - - - - - + + Qt::Vertical + + + + 0 + 1 + + + + QAbstractItemView::NoEditTriggers + + + + Name + + + Name of the VOR + + + + + Freq (MHz) + + + Frequency of the VOR in MHz + + + + + Ident + + + Ident for the VOR + + + + + Morse + + + Morse code ident for the VOR + + + + + RX Ident + + + Received ident + + + + + RX Morse + + + Received Morse code ident + + + + + Radial (°) + + + Calculated radial from the VOR + + + + + Ref (dB) + + + Magnitude of received reference signal in dB + + + + + Var (dB) + + + Magnitude of received variable signal in dB + + + + + Mute + + + Mute/unmute audio from selected VORs + + + + + + + 0 + 4 + + + + + 100 + 500 + + + + VOR map + + + QQuickWidget::SizeRootObjectToView + + + + + + + @@ -542,22 +484,20 @@ QToolTip{background-color: white; color: black;} QWidget
QtQuickWidgets/QQuickWidget
- - RollupWidget - QWidget -
gui/rollupwidget.h
- 1 -
ButtonSwitch QToolButton
gui/buttonswitch.h
+ + RollupContents + QWidget +
gui/rollupcontents.h
+ 1 +
- getOurAirportsVORDB vorData - map diff --git a/plugins/feature/vorlocalizer/vorlocalizersettings.cpp b/plugins/feature/vorlocalizer/vorlocalizersettings.cpp index 760a450d4..a6e4da6c7 100644 --- a/plugins/feature/vorlocalizer/vorlocalizersettings.cpp +++ b/plugins/feature/vorlocalizer/vorlocalizersettings.cpp @@ -41,7 +41,7 @@ void VORLocalizerSettings::resetToDefaults() m_reverseAPIPort = 8888; m_reverseAPIFeatureSetIndex = 0; m_reverseAPIFeatureIndex = 0; - + m_workspaceIndex = 0; for (int i = 0; i < VORDEMOD_COLUMNS; i++) { @@ -69,6 +69,9 @@ QByteArray VORLocalizerSettings::serialize() const s.writeBlob(19, m_rollupState->serialize()); } + s.writeS32(20, m_workspaceIndex); + s.writeBlob(21, m_geometryBytes); + for (int i = 0; i < VORDEMOD_COLUMNS; i++) { s.writeS32(100 + i, m_columnIndexes[i]); } @@ -123,6 +126,9 @@ bool VORLocalizerSettings::deserialize(const QByteArray& data) m_rollupState->deserialize(bytetmp); } + d.readS32(20, &m_workspaceIndex, 0); + d.readBlob(21, &m_geometryBytes); + for (int i = 0; i < VORDEMOD_COLUMNS; i++) { d.readS32(100 + i, &m_columnIndexes[i], i); } diff --git a/plugins/feature/vorlocalizer/vorlocalizersettings.h b/plugins/feature/vorlocalizer/vorlocalizersettings.h index 410c96331..0c50e3beb 100644 --- a/plugins/feature/vorlocalizer/vorlocalizersettings.h +++ b/plugins/feature/vorlocalizer/vorlocalizersettings.h @@ -74,20 +74,20 @@ struct VORLocalizerSettings uint16_t m_reverseAPIFeatureSetIndex; uint16_t m_reverseAPIFeatureIndex; Serializable *m_rollupState; + int m_workspaceIndex; + QByteArray m_geometryBytes; - - static const int VORDEMOD_COLUMNS = 11; + static const int VORDEMOD_COLUMNS = 10; static const int VOR_COL_NAME = 0; static const int VOR_COL_FREQUENCY = 1; - static const int VOR_COL_NAVID = 2; - static const int VOR_COL_IDENT = 3; - static const int VOR_COL_MORSE = 4; - static const int VOR_COL_RX_IDENT = 5; - static const int VOR_COL_RX_MORSE = 6; - static const int VOR_COL_RADIAL = 7; - static const int VOR_COL_REF_MAG = 8; - static const int VOR_COL_VAR_MAG = 9; - static const int VOR_COL_MUTE = 10; + static const int VOR_COL_IDENT = 2; + static const int VOR_COL_MORSE = 3; + static const int VOR_COL_RX_IDENT = 4; + static const int VOR_COL_RX_MORSE = 5; + static const int VOR_COL_RADIAL = 6; + static const int VOR_COL_REF_MAG = 7; + static const int VOR_COL_VAR_MAG = 8; + static const int VOR_COL_MUTE = 9; int m_columnIndexes[VORDEMOD_COLUMNS];//!< How the columns are ordered in the table int m_columnSizes[VORDEMOD_COLUMNS]; //!< Size of the coumns in the table diff --git a/plugins/feature/vorlocalizer/vorlocalizerworker.cpp b/plugins/feature/vorlocalizer/vorlocalizerworker.cpp index ebe1cd3e4..2c2affb67 100644 --- a/plugins/feature/vorlocalizer/vorlocalizerworker.cpp +++ b/plugins/feature/vorlocalizer/vorlocalizerworker.cpp @@ -24,7 +24,11 @@ #include "SWGErrorResponse.h" #include "device/deviceset.h" +#include "device/deviceapi.h" +#include "dsp/devicesamplesource.h" +#include "dsp/devicesamplesink.h" #include "channel/channelapi.h" +#include "channel/channelwebapiutils.h" #include "webapi/webapiadapterinterface.h" #include "webapi/webapiutils.h" #include "maincore.h" @@ -78,6 +82,7 @@ void VorLocalizerWorker::started() m_rrTimer.start(m_settings.m_rrTime * 1000); disconnect(thread(), SIGNAL(started()), this, SLOT(started())); } + void VorLocalizerWorker::stopWork() { QMutexLocker mutexLocker(&m_mutex); @@ -205,6 +210,53 @@ void VorLocalizerWorker::updateHardware() m_mutex.unlock(); } +quint64 VorLocalizerWorker::getDeviceCenterFrequency(int deviceIndex) +{ + std::vector deviceSets = MainCore::instance()->getDeviceSets(); + if (deviceIndex < (int) deviceSets.size()) + { + DeviceSet *deviceSet = deviceSets[deviceIndex]; + if (deviceSet->m_deviceSourceEngine) + { + DeviceSampleSource *source = deviceSet->m_deviceAPI->getSampleSource(); + return source->getCenterFrequency(); + } + else if (deviceSet->m_deviceSinkEngine) + { + DeviceSampleSink *sink = deviceSet->m_deviceAPI->getSampleSink(); + return sink->getCenterFrequency(); + } + } + return 0; +} + +int VorLocalizerWorker::getDeviceSampleRate(int deviceIndex) +{ + std::vector deviceSets = MainCore::instance()->getDeviceSets(); + if (deviceIndex < (int) deviceSets.size()) + { + DeviceSet *deviceSet = deviceSets[deviceIndex]; + if (deviceSet->m_deviceSourceEngine) + { + DeviceSampleSource *source = deviceSet->m_deviceAPI->getSampleSource(); + return source->getSampleRate(); + } + else if (deviceSet->m_deviceSinkEngine) + { + DeviceSampleSink *sink = deviceSet->m_deviceAPI->getSampleSink(); + return sink->getSampleRate(); + } + } + return 0; +} + +// Does this device have a center frequency setting (FileInput doesn't) +bool VorLocalizerWorker::hasCenterFrequencySetting(int deviceIndex) +{ + double deviceFrequency; + return !ChannelWebAPIUtils::getCenterFrequency(deviceIndex, deviceFrequency); +} + void VorLocalizerWorker::removeVORChannel(int navId) { qDebug("VorLocalizerWorker::removeVORChannel: %d", navId); @@ -294,7 +346,12 @@ void VorLocalizerWorker::updateChannels() RRTurnPlan turnPlan(deviceChannel); int fMin = vorList.front().m_frequency; int fMax = vorList.back().m_frequency; - int devFreq = (fMin + fMax) / 2; + int devFreq; + if (turnPlan.m_fixedCenterFrequency) { + devFreq = getDeviceCenterFrequency(turnPlan.m_device.m_deviceIndex); + } else { + devFreq = (fMin + fMax) / 2; + } turnPlan.m_device.m_frequency = devFreq; int iCh = 0; @@ -321,7 +378,6 @@ void VorLocalizerWorker::updateChannels() ++it; } } - iCh++; } @@ -359,7 +415,12 @@ void VorLocalizerWorker::updateChannels() RRTurnPlan turnPlan(deviceChannel); int fMin = vorList.front().m_frequency; int fMax = vorList.back().m_frequency; - int devFreq = (fMin + fMax) / 2; + int devFreq; + if (turnPlan.m_fixedCenterFrequency) { + devFreq = getDeviceCenterFrequency(turnPlan.m_device.m_deviceIndex); + } else { + devFreq = (fMin + fMax) / 2; + } turnPlan.m_device.m_frequency = devFreq; int iCh = 0; @@ -395,11 +456,8 @@ void VorLocalizerWorker::updateChannels() for (auto rrChannel : rrPlan.m_channels) { - qDebug() << "VorLocalizerWorker::updateChannels: RR channel: " - << "channel:" << rrChannel.m_channelAPI - << "index:" << rrChannel.m_channelIndex - << "shift:" << rrChannel.m_frequencyShift - << "navId:" << rrChannel.m_navId; + qDebug("VorLocalizerWorker::updateChannels: RR channel: %p index: %d shift: %d navId: %d", + rrChannel.m_channelAPI, rrChannel.m_channelIndex, rrChannel.m_frequencyShift, rrChannel.m_navId); } } } @@ -409,69 +467,6 @@ void VorLocalizerWorker::updateChannels() rrNextTurn(); } -void VorLocalizerWorker::allocateChannel(ChannelAPI *channel, int vorFrequency, int vorNavId, int channelShift) -{ - VORLocalizerSettings::AvailableChannel& availableChannel = m_availableChannels->operator[](channel); - qDebug() << "VorLocalizerWorker::allocateChannel:" - << " vorNavId:" << vorNavId - << " vorFrequency:" << vorFrequency - << " channelShift:" << channelShift - << " deviceIndex:" << availableChannel.m_deviceSetIndex - << " channelIndex:" << availableChannel.m_channelIndex; - double deviceFrequency = vorFrequency - channelShift; - setDeviceFrequency(availableChannel.m_deviceSetIndex, deviceFrequency); - setChannelShift(availableChannel.m_deviceSetIndex, availableChannel.m_channelIndex, channelShift, vorNavId); - availableChannel.m_navId = vorNavId; -} - -void VorLocalizerWorker::setDeviceFrequency(int deviceIndex, double targetFrequency) -{ - SWGSDRangel::SWGDeviceSettings deviceSettingsResponse; - SWGSDRangel::SWGErrorResponse errorResponse; - int httpRC; - - // Get current device center frequency - httpRC = m_webAPIAdapterInterface->devicesetDeviceSettingsGet( - deviceIndex, - deviceSettingsResponse, - errorResponse - ); - - if (httpRC/100 != 2) - { - qWarning("VorLocalizerWorker::setDeviceFrequency: get device frequency error %d: %s", - httpRC, qPrintable(*errorResponse.getMessage())); - } - - QJsonObject *jsonObj = deviceSettingsResponse.asJsonObject(); - - // Update centerFrequency - WebAPIUtils::setSubObjectDouble(*jsonObj, "centerFrequency", targetFrequency); - QStringList deviceSettingsKeys; - deviceSettingsKeys.append("centerFrequency"); - deviceSettingsResponse.init(); - deviceSettingsResponse.fromJsonObject(*jsonObj); - SWGSDRangel::SWGErrorResponse errorResponse2; - - httpRC = m_webAPIAdapterInterface->devicesetDeviceSettingsPutPatch( - deviceIndex, - false, // PATCH - deviceSettingsKeys, - deviceSettingsResponse, - errorResponse2 - ); - - if (httpRC/100 == 2) - { - qDebug("VorLocalizerWorker::setDeviceFrequency: set device frequency %f OK", targetFrequency); - } - else - { - qWarning("VorLocalizerWorker::setDeviceFrequency: set device frequency error %d: %s", - httpRC, qPrintable(*errorResponse2.getMessage())); - } -} - void VorLocalizerWorker::setChannelShift(int deviceIndex, int channelIndex, double targetOffset, int vorNavId) { SWGSDRangel::SWGChannelSettings channelSettingsResponse; @@ -677,14 +672,16 @@ void VorLocalizerWorker::getChannelsByDevice( for (; itr != availableChannels->end(); ++itr) { devicesChannelsMap[itr->m_deviceSetIndex].m_device.m_deviceIndex = itr->m_deviceSetIndex; - devicesChannelsMap[itr->m_deviceSetIndex].m_bandwidth = itr->m_basebandSampleRate; + devicesChannelsMap[itr->m_deviceSetIndex].m_bandwidth = getDeviceSampleRate(itr->m_deviceSetIndex); // Get b/w of device, not channel, as the latter may be decimated devicesChannelsMap[itr->m_deviceSetIndex].m_channels.push_back(RRChannel{itr->m_channelAPI, itr->m_channelIndex, 0, -1}); } - QMap::const_iterator itm = devicesChannelsMap.begin(); + QMap::iterator itm = devicesChannelsMap.begin(); devicesChannels.clear(); - for (; itm != devicesChannelsMap.end(); ++itm) { + for (; itm != devicesChannelsMap.end(); ++itm) + { + itm->m_fixedCenterFrequency = hasCenterFrequencySetting(itm->m_device.m_deviceIndex); devicesChannels.push_back(*itm); } @@ -703,23 +700,32 @@ void VorLocalizerWorker::rrNextTurn() unsigned int turnCount = m_rrTurnCounters[iDevPlan]; int deviceIndex = rrPlan[turnCount].m_device.m_deviceIndex; int deviceFrequency = rrPlan[turnCount].m_device.m_frequency - m_settings.m_centerShift; + qDebug() << "VorLocalizerWorker::rrNextTurn: " << "turn:" << turnCount << "device:" << deviceIndex << "frequency:" << deviceFrequency - m_settings.m_centerShift; - setDeviceFrequency(deviceIndex, deviceFrequency); + + if (!rrPlan[turnCount].m_fixedCenterFrequency) { + ChannelWebAPIUtils::setCenterFrequency(deviceIndex, deviceFrequency); + } for (auto channel : rrPlan[turnCount].m_channels) { + int shift = channel.m_frequencyShift; + if (!rrPlan[turnCount].m_fixedCenterFrequency) { + shift += m_settings.m_centerShift; + } + qDebug() << "VorLocalizerWorker::rrNextTurn: " << "device:" << deviceIndex << "channel:" << channel.m_channelIndex - << "shift:" << channel.m_frequencyShift + m_settings.m_centerShift + << "shift:" << shift << "navId:" << channel.m_navId; setChannelShift( deviceIndex, channel.m_channelIndex, - channel.m_frequencyShift + m_settings.m_centerShift, + shift, channel.m_navId ); m_channelAllocations[channel.m_navId] = ChannelAllocation{ diff --git a/plugins/feature/vorlocalizer/vorlocalizerworker.h b/plugins/feature/vorlocalizer/vorlocalizerworker.h index c6d3c724a..daf693c44 100644 --- a/plugins/feature/vorlocalizer/vorlocalizerworker.h +++ b/plugins/feature/vorlocalizer/vorlocalizerworker.h @@ -121,6 +121,7 @@ private: RRDevice m_device; int m_bandwidth; std::vector m_channels; + bool m_fixedCenterFrequency; // Devices such as FileInput that can't have center freq changed RRTurnPlan() = default; RRTurnPlan(const RRTurnPlan&) = default; @@ -157,10 +158,11 @@ private: void removeVORChannel(int navId); void addVORChannel(const VORLocalizerSubChannelSettings& subChannelSettings); void updateChannels(); //!< (re)allocate channels to service VORs - void allocateChannel(ChannelAPI *channel, int vorFrequency, int vorNavId, int channelShift); - void setDeviceFrequency(int deviceIndex, double targetFrequency); void setChannelShift(int deviceIndex, int channelIndex, double targetOffset, int vorNavId); void setAudioMute(int vorNavId, bool audioMute); + static quint64 getDeviceCenterFrequency(int deviceIndex); + static int getDeviceSampleRate(int deviceIndex); + static bool hasCenterFrequencySetting(int deviceIndex); static void generateIndexCombinations(int length, int subLength, std::vector>& indexCombinations); static void getVORRanges(const QList& vors, int subLength, std::vector& vorRanges); static void filterVORRanges(std::vector& vorRanges, int thresholdBW); diff --git a/plugins/samplemimo/bladerf2mimo/bladerf2mimogui.cpp b/plugins/samplemimo/bladerf2mimo/bladerf2mimogui.cpp index ecbc3ab34..4b174c8ce 100644 --- a/plugins/samplemimo/bladerf2mimo/bladerf2mimogui.cpp +++ b/plugins/samplemimo/bladerf2mimo/bladerf2mimogui.cpp @@ -23,13 +23,13 @@ #include #include #include +#include #include "plugin/pluginapi.h" #include "device/deviceapi.h" #include "device/deviceuiset.h" #include "gui/colormapper.h" #include "gui/glspectrum.h" -#include "gui/crightclickenabler.h" #include "gui/basicdevicesettingsdialog.h" #include "dsp/dspengine.h" #include "dsp/dspdevicemimoengine.h" @@ -46,7 +46,6 @@ BladeRF2MIMOGui::BladeRF2MIMOGui(DeviceUISet *deviceUISet, QWidget* parent) : DeviceGUI(parent), ui(new Ui::BladeRF2MIMOGui), - m_deviceUISet(deviceUISet), m_settings(), m_rxElseTx(true), m_streamIndex(0), @@ -66,7 +65,12 @@ BladeRF2MIMOGui::BladeRF2MIMOGui(DeviceUISet *deviceUISet, QWidget* parent) : m_sampleRateMode(true) { qDebug("BladeRF2MIMOGui::BladeRF2MIMOGui"); - ui->setupUi(this); + m_deviceUISet = deviceUISet; + setAttribute(Qt::WA_DeleteOnClose, true); + ui->setupUi(getContents()); + setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); + getContents()->setStyleSheet("#BladeRF2MIMOGui { background-color: rgb(64, 64, 64); }"); + m_helpURL = "plugins/samplemimo/bladerf2mimo/readme.md"; m_sampleMIMO = (BladeRF2MIMO*) m_deviceUISet->m_deviceAPI->getSampleMIMO(); m_sampleMIMO->getRxFrequencyRange(m_fMinRx, m_fMaxRx, m_fStepRx, m_fScaleRx); @@ -96,10 +100,10 @@ BladeRF2MIMOGui::BladeRF2MIMOGui(DeviceUISet *deviceUISet, QWidget* parent) : connect(&m_inputMessageQueue, SIGNAL(messageEnqueued()), this, SLOT(handleInputMessages()), Qt::QueuedConnection); m_sampleMIMO->setMessageQueueToGUI(&m_inputMessageQueue); - CRightClickEnabler *startStopRightClickEnabler = new CRightClickEnabler(ui->startStopRx); - connect(startStopRightClickEnabler, SIGNAL(rightClick(const QPoint &)), this, SLOT(openDeviceSettingsDialog(const QPoint &))); + connect(this, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(openDeviceSettingsDialog(const QPoint &))); sendSettings(); + makeUIConnections(); } BladeRF2MIMOGui::~BladeRF2MIMOGui() @@ -140,6 +144,12 @@ bool BladeRF2MIMOGui::deserialize(const QByteArray& data) } } +void BladeRF2MIMOGui::resizeEvent(QResizeEvent* size) +{ + adjustSize(); + size->accept(); +} + void BladeRF2MIMOGui::displaySettings() { updateFrequencyLimits(); @@ -789,21 +799,26 @@ void BladeRF2MIMOGui::updateStatus() void BladeRF2MIMOGui::openDeviceSettingsDialog(const QPoint& p) { - BasicDeviceSettingsDialog dialog(this); - dialog.setUseReverseAPI(m_settings.m_useReverseAPI); - dialog.setReverseAPIAddress(m_settings.m_reverseAPIAddress); - dialog.setReverseAPIPort(m_settings.m_reverseAPIPort); - dialog.setReverseAPIDeviceIndex(m_settings.m_reverseAPIDeviceIndex); + if (m_contextMenuType == ContextMenuDeviceSettings) + { + BasicDeviceSettingsDialog dialog(this); + dialog.setUseReverseAPI(m_settings.m_useReverseAPI); + dialog.setReverseAPIAddress(m_settings.m_reverseAPIAddress); + dialog.setReverseAPIPort(m_settings.m_reverseAPIPort); + dialog.setReverseAPIDeviceIndex(m_settings.m_reverseAPIDeviceIndex); - dialog.move(p); - dialog.exec(); + dialog.move(p); + dialog.exec(); - m_settings.m_useReverseAPI = dialog.useReverseAPI(); - m_settings.m_reverseAPIAddress = dialog.getReverseAPIAddress(); - m_settings.m_reverseAPIPort = dialog.getReverseAPIPort(); - m_settings.m_reverseAPIDeviceIndex = dialog.getReverseAPIDeviceIndex(); + m_settings.m_useReverseAPI = dialog.useReverseAPI(); + m_settings.m_reverseAPIAddress = dialog.getReverseAPIAddress(); + m_settings.m_reverseAPIPort = dialog.getReverseAPIPort(); + m_settings.m_reverseAPIDeviceIndex = dialog.getReverseAPIDeviceIndex(); - sendSettings(); + sendSettings(); + } + + resetContextMenuType(); } float BladeRF2MIMOGui::getGainDB(int gainValue, int gainMin, int gainMax, int gainStep, float gainScale) @@ -821,3 +836,27 @@ int BladeRF2MIMOGui::getGainValue(float gainDB, int gainMin, int gainMax, int ga gainDB, gainMin, gainMax, gainStep, gainScale, gain); return gain; } + +void BladeRF2MIMOGui::makeUIConnections() +{ + QObject::connect(ui->streamSide, QOverload::of(&QComboBox::currentIndexChanged), this, &BladeRF2MIMOGui::on_streamSide_currentIndexChanged); + QObject::connect(ui->streamIndex, QOverload::of(&QComboBox::currentIndexChanged), this, &BladeRF2MIMOGui::on_streamIndex_currentIndexChanged); + QObject::connect(ui->spectrumSide, QOverload::of(&QComboBox::currentIndexChanged), this, &BladeRF2MIMOGui::on_spectrumSide_currentIndexChanged); + QObject::connect(ui->spectrumIndex, QOverload::of(&QComboBox::currentIndexChanged), this, &BladeRF2MIMOGui::on_spectrumIndex_currentIndexChanged); + QObject::connect(ui->startStopRx, &ButtonSwitch::toggled, this, &BladeRF2MIMOGui::on_startStopRx_toggled); + QObject::connect(ui->startStopTx, &ButtonSwitch::toggled, this, &BladeRF2MIMOGui::on_startStopTx_toggled); + QObject::connect(ui->centerFrequency, &ValueDial::changed, this, &BladeRF2MIMOGui::on_centerFrequency_changed); + QObject::connect(ui->LOppm, &QSlider::valueChanged, this, &BladeRF2MIMOGui::on_LOppm_valueChanged); + QObject::connect(ui->dcOffset, &ButtonSwitch::toggled, this, &BladeRF2MIMOGui::on_dcOffset_toggled); + QObject::connect(ui->iqImbalance, &ButtonSwitch::toggled, this, &BladeRF2MIMOGui::on_iqImbalance_toggled); + QObject::connect(ui->bandwidth, &ValueDial::changed, this, &BladeRF2MIMOGui::on_bandwidth_changed); + QObject::connect(ui->sampleRate, &ValueDial::changed, this, &BladeRF2MIMOGui::on_sampleRate_changed); + QObject::connect(ui->fcPos, QOverload::of(&QComboBox::currentIndexChanged), this, &BladeRF2MIMOGui::on_fcPos_currentIndexChanged); + QObject::connect(ui->decim, QOverload::of(&QComboBox::currentIndexChanged), this, &BladeRF2MIMOGui::on_decim_currentIndexChanged); + QObject::connect(ui->gainLock, &QToolButton::toggled, this, &BladeRF2MIMOGui::on_gainLock_toggled); + QObject::connect(ui->gainMode, QOverload::of(&QComboBox::currentIndexChanged), this, &BladeRF2MIMOGui::on_gainMode_currentIndexChanged); + QObject::connect(ui->gain, &QSlider::valueChanged, this, &BladeRF2MIMOGui::on_gain_valueChanged); + QObject::connect(ui->biasTee, &ButtonSwitch::toggled, this, &BladeRF2MIMOGui::on_biasTee_toggled); + QObject::connect(ui->transverter, &TransverterButton::clicked, this, &BladeRF2MIMOGui::on_transverter_clicked); + +} diff --git a/plugins/samplemimo/bladerf2mimo/bladerf2mimogui.h b/plugins/samplemimo/bladerf2mimo/bladerf2mimogui.h index 23101e88d..ad0b150be 100644 --- a/plugins/samplemimo/bladerf2mimo/bladerf2mimogui.h +++ b/plugins/samplemimo/bladerf2mimo/bladerf2mimogui.h @@ -45,10 +45,12 @@ public: bool deserialize(const QByteArray& data); virtual MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; } +protected: + void resizeEvent(QResizeEvent* size); + private: Ui::BladeRF2MIMOGui* ui; - DeviceUISet* m_deviceUISet; BladeRF2MIMOSettings m_settings; bool m_rxElseTx; //!< Which side is being dealt with int m_streamIndex; //!< Current stream index being dealt with @@ -97,6 +99,7 @@ private: int getGainValue(float gainDB, int gainMin, int gainMax, int gainStep, float gainScale); float setGainFromValue(int value); bool handleMessage(const Message& message); + void makeUIConnections(); private slots: void handleInputMessages(); diff --git a/plugins/samplemimo/bladerf2mimo/bladerf2mimogui.ui b/plugins/samplemimo/bladerf2mimo/bladerf2mimogui.ui index 8b862d61e..8cab40fc7 100644 --- a/plugins/samplemimo/bladerf2mimo/bladerf2mimogui.ui +++ b/plugins/samplemimo/bladerf2mimo/bladerf2mimogui.ui @@ -6,19 +6,25 @@ 0 0 - 366 - 228 + 370 + 208 - + 0 0 - 350 + 370 + 208 + + + + + 390 220 @@ -313,7 +319,7 @@ Liberation Mono - 20 + 16 @@ -761,30 +767,6 @@
- - - - Qt::Horizontal - - - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - -
diff --git a/plugins/samplemimo/bladerf2mimo/readme.md b/plugins/samplemimo/bladerf2mimo/readme.md index 5425a54bb..f8dc2c303 100644 --- a/plugins/samplemimo/bladerf2mimo/readme.md +++ b/plugins/samplemimo/bladerf2mimo/readme.md @@ -19,6 +19,8 @@ The BladeRF Host library is also provided by many Linux distributions (check its

Interface

+The top and bottom bars of the device window are described [here](../../../sdrgui/device/readme.md) + ![BladeRF2 MIMO plugin GUI](../../../doc/img/BladeRF2MIMO_plugin.png)

1. Rx/Tx settings selection

diff --git a/plugins/samplemimo/limesdrmimo/limesdrmimogui.cpp b/plugins/samplemimo/limesdrmimo/limesdrmimogui.cpp index 6a0b4c649..a41cd7d5f 100644 --- a/plugins/samplemimo/limesdrmimo/limesdrmimogui.cpp +++ b/plugins/samplemimo/limesdrmimo/limesdrmimogui.cpp @@ -22,13 +22,13 @@ #include #include #include +#include #include "plugin/pluginapi.h" #include "device/deviceapi.h" #include "device/deviceuiset.h" #include "gui/colormapper.h" #include "gui/glspectrum.h" -#include "gui/crightclickenabler.h" #include "gui/basicdevicesettingsdialog.h" #include "dsp/dspengine.h" #include "dsp/dspdevicemimoengine.h" @@ -46,7 +46,6 @@ LimeSDRMIMOGUI::LimeSDRMIMOGUI(DeviceUISet *deviceUISet, QWidget* parent) : DeviceGUI(parent), ui(new Ui::LimeSDRMIMOGUI), - m_deviceUISet(deviceUISet), m_settings(), m_rxElseTx(true), m_streamIndex(0), @@ -68,7 +67,12 @@ LimeSDRMIMOGUI::LimeSDRMIMOGUI(DeviceUISet *deviceUISet, QWidget* parent) : m_sampleRateMode(true) { qDebug("LimeSDRMIMOGUI::LimeSDRMIMOGUI"); - ui->setupUi(this); + m_deviceUISet = deviceUISet; + setAttribute(Qt::WA_DeleteOnClose, true); + ui->setupUi(getContents()); + setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); + getContents()->setStyleSheet("#LimeSDRMIMOGUI { background-color: rgb(64, 64, 64); }"); + m_helpURL = "plugins/samplemimo/limesdrmimo/readme.md"; m_limeSDRMIMO = (LimeSDRMIMO*) m_deviceUISet->m_deviceAPI->getSampleMIMO(); m_limeSDRMIMO->getRxFrequencyRange(m_fMinRx, m_fMaxRx, m_fStepRx); @@ -96,10 +100,10 @@ LimeSDRMIMOGUI::LimeSDRMIMOGUI(DeviceUISet *deviceUISet, QWidget* parent) : connect(&m_inputMessageQueue, SIGNAL(messageEnqueued()), this, SLOT(handleInputMessages()), Qt::QueuedConnection); m_limeSDRMIMO->setMessageQueueToGUI(&m_inputMessageQueue); - CRightClickEnabler *startStopRightClickEnabler = new CRightClickEnabler(ui->startStopRx); - connect(startStopRightClickEnabler, SIGNAL(rightClick(const QPoint &)), this, SLOT(openDeviceSettingsDialog(const QPoint &))); + connect(this, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(openDeviceSettingsDialog(const QPoint &))); sendSettings(); + makeUIConnections(); } LimeSDRMIMOGUI::~LimeSDRMIMOGUI() @@ -140,6 +144,12 @@ bool LimeSDRMIMOGUI::deserialize(const QByteArray& data) } } +void LimeSDRMIMOGUI::resizeEvent(QResizeEvent* size) +{ + adjustSize(); + size->accept(); +} + void LimeSDRMIMOGUI::handleInputMessages() { Message* message; @@ -1121,19 +1131,54 @@ void LimeSDRMIMOGUI::on_antenna_currentIndexChanged(int index) void LimeSDRMIMOGUI::openDeviceSettingsDialog(const QPoint& p) { - BasicDeviceSettingsDialog dialog(this); - dialog.setUseReverseAPI(m_settings.m_useReverseAPI); - dialog.setReverseAPIAddress(m_settings.m_reverseAPIAddress); - dialog.setReverseAPIPort(m_settings.m_reverseAPIPort); - dialog.setReverseAPIDeviceIndex(m_settings.m_reverseAPIDeviceIndex); + if (m_contextMenuType == ContextMenuDeviceSettings) + { + BasicDeviceSettingsDialog dialog(this); + dialog.setUseReverseAPI(m_settings.m_useReverseAPI); + dialog.setReverseAPIAddress(m_settings.m_reverseAPIAddress); + dialog.setReverseAPIPort(m_settings.m_reverseAPIPort); + dialog.setReverseAPIDeviceIndex(m_settings.m_reverseAPIDeviceIndex); - dialog.move(p); - dialog.exec(); + dialog.move(p); + dialog.exec(); - m_settings.m_useReverseAPI = dialog.useReverseAPI(); - m_settings.m_reverseAPIAddress = dialog.getReverseAPIAddress(); - m_settings.m_reverseAPIPort = dialog.getReverseAPIPort(); - m_settings.m_reverseAPIDeviceIndex = dialog.getReverseAPIDeviceIndex(); + m_settings.m_useReverseAPI = dialog.useReverseAPI(); + m_settings.m_reverseAPIAddress = dialog.getReverseAPIAddress(); + m_settings.m_reverseAPIPort = dialog.getReverseAPIPort(); + m_settings.m_reverseAPIDeviceIndex = dialog.getReverseAPIDeviceIndex(); - sendSettings(); + sendSettings(); + } + + resetContextMenuType(); +} + +void LimeSDRMIMOGUI::makeUIConnections() +{ + QObject::connect(ui->streamSide, QOverload::of(&QComboBox::currentIndexChanged), this, &LimeSDRMIMOGUI::on_streamSide_currentIndexChanged); + QObject::connect(ui->streamIndex, QOverload::of(&QComboBox::currentIndexChanged), this, &LimeSDRMIMOGUI::on_streamIndex_currentIndexChanged); + QObject::connect(ui->spectrumSide, QOverload::of(&QComboBox::currentIndexChanged), this, &LimeSDRMIMOGUI::on_spectrumSide_currentIndexChanged); + QObject::connect(ui->spectrumIndex, QOverload::of(&QComboBox::currentIndexChanged), this, &LimeSDRMIMOGUI::on_spectrumIndex_currentIndexChanged); + QObject::connect(ui->startStopRx, &ButtonSwitch::toggled, this, &LimeSDRMIMOGUI::on_startStopRx_toggled); + QObject::connect(ui->startStopTx, &ButtonSwitch::toggled, this, &LimeSDRMIMOGUI::on_startStopTx_toggled); + QObject::connect(ui->centerFrequency, &ValueDial::changed, this, &LimeSDRMIMOGUI::on_centerFrequency_changed); + QObject::connect(ui->ncoEnable, &ButtonSwitch::toggled, this, &LimeSDRMIMOGUI::on_ncoEnable_toggled); + QObject::connect(ui->ncoFrequency, &ValueDialZ::changed, this, &LimeSDRMIMOGUI::on_ncoFrequency_changed); + QObject::connect(ui->dcOffset, &ButtonSwitch::toggled, this, &LimeSDRMIMOGUI::on_dcOffset_toggled); + QObject::connect(ui->iqImbalance, &ButtonSwitch::toggled, this, &LimeSDRMIMOGUI::on_iqImbalance_toggled); + QObject::connect(ui->extClock, &ExternalClockButton::clicked, this, &LimeSDRMIMOGUI::on_extClock_clicked); + QObject::connect(ui->hwDecim, QOverload::of(&QComboBox::currentIndexChanged), this, &LimeSDRMIMOGUI::on_hwDecim_currentIndexChanged); + QObject::connect(ui->swDecim, QOverload::of(&QComboBox::currentIndexChanged), this, &LimeSDRMIMOGUI::on_swDecim_currentIndexChanged); + QObject::connect(ui->sampleRateMode, &QToolButton::toggled, this, &LimeSDRMIMOGUI::on_sampleRateMode_toggled); + QObject::connect(ui->sampleRate, &ValueDial::changed, this, &LimeSDRMIMOGUI::on_sampleRate_changed); + QObject::connect(ui->lpf, &ValueDial::changed, this, &LimeSDRMIMOGUI::on_lpf_changed); + QObject::connect(ui->lpFIREnable, &ButtonSwitch::toggled, this, &LimeSDRMIMOGUI::on_lpFIREnable_toggled); + QObject::connect(ui->lpFIR, &ValueDial::changed, this, &LimeSDRMIMOGUI::on_lpFIR_changed); + QObject::connect(ui->transverter, &TransverterButton::clicked, this, &LimeSDRMIMOGUI::on_transverter_clicked); + QObject::connect(ui->gainMode, QOverload::of(&QComboBox::currentIndexChanged), this, &LimeSDRMIMOGUI::on_gainMode_currentIndexChanged); + QObject::connect(ui->gain, &QDial::valueChanged, this, &LimeSDRMIMOGUI::on_gain_valueChanged); + QObject::connect(ui->lnaGain, &QDial::valueChanged, this, &LimeSDRMIMOGUI::on_lnaGain_valueChanged); + QObject::connect(ui->tiaGain, QOverload::of(&QComboBox::currentIndexChanged), this, &LimeSDRMIMOGUI::on_tiaGain_currentIndexChanged); + QObject::connect(ui->pgaGain, &QDial::valueChanged, this, &LimeSDRMIMOGUI::on_pgaGain_valueChanged); + QObject::connect(ui->antenna, QOverload::of(&QComboBox::currentIndexChanged), this, &LimeSDRMIMOGUI::on_antenna_currentIndexChanged); } diff --git a/plugins/samplemimo/limesdrmimo/limesdrmimogui.h b/plugins/samplemimo/limesdrmimo/limesdrmimogui.h index e42720cdd..3b50812d0 100644 --- a/plugins/samplemimo/limesdrmimo/limesdrmimogui.h +++ b/plugins/samplemimo/limesdrmimo/limesdrmimogui.h @@ -45,10 +45,12 @@ public: bool deserialize(const QByteArray& data); virtual MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; } +protected: + void resizeEvent(QResizeEvent* size); + private: Ui::LimeSDRMIMOGUI* ui; - DeviceUISet* m_deviceUISet; LimeSDRMIMOSettings m_settings; bool m_rxElseTx; //!< Which side is being dealt with int m_streamIndex; //!< Current stream index being dealt with @@ -96,6 +98,7 @@ private: void updateSampleRateAndFrequency(); void sendSettings(); bool handleMessage(const Message& message); + void makeUIConnections(); private slots: void handleInputMessages(); diff --git a/plugins/samplemimo/limesdrmimo/limesdrmimogui.ui b/plugins/samplemimo/limesdrmimo/limesdrmimogui.ui index 818a5d5cd..a474b5909 100644 --- a/plugins/samplemimo/limesdrmimo/limesdrmimogui.ui +++ b/plugins/samplemimo/limesdrmimo/limesdrmimogui.ui @@ -6,8 +6,8 @@ 0 0 - 360 - 290 + 370 + 244 @@ -18,8 +18,14 @@ - 360 - 290 + 370 + 244 + + + + + 390 + 286 @@ -336,7 +342,7 @@ Liberation Mono - 20 + 16 50 false @@ -1246,6 +1252,7 @@ + Ubuntu 8 @@ -1319,30 +1326,6 @@ QToolTip{background-color: white; color: black;} - - - - Qt::Horizontal - - - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - -
@@ -1357,11 +1340,6 @@ QToolTip{background-color: white; color: black;} QToolButton
gui/buttonswitch.h
- - ExternalClockButton - QToolButton -
gui/externalclockbutton.h
-
ValueDialZ QWidget @@ -1373,6 +1351,11 @@ QToolTip{background-color: white; color: black;} QPushButton
gui/transverterbutton.h
+ + ExternalClockButton + QToolButton +
gui/externalclockbutton.h
+
diff --git a/plugins/samplemimo/limesdrmimo/limesdrmimosettings.cpp b/plugins/samplemimo/limesdrmimo/limesdrmimosettings.cpp index 7deaecb71..22b1a28c2 100644 --- a/plugins/samplemimo/limesdrmimo/limesdrmimosettings.cpp +++ b/plugins/samplemimo/limesdrmimo/limesdrmimosettings.cpp @@ -255,4 +255,4 @@ bool LimeSDRMIMOSettings::deserialize(const QByteArray& data) resetToDefaults(); return false; } -} \ No newline at end of file +} diff --git a/plugins/samplemimo/limesdrmimo/limesdrmimosettings.h b/plugins/samplemimo/limesdrmimo/limesdrmimosettings.h index 6bb8617a5..75049a5bd 100644 --- a/plugins/samplemimo/limesdrmimo/limesdrmimosettings.h +++ b/plugins/samplemimo/limesdrmimo/limesdrmimosettings.h @@ -125,4 +125,4 @@ struct LimeSDRMIMOSettings bool deserialize(const QByteArray& data); }; -#endif // PLUGINS_SAMPLEMIMO_LIMESDRMIMO_LIMESDRMIMOSETTINGS_H_ \ No newline at end of file +#endif // PLUGINS_SAMPLEMIMO_LIMESDRMIMO_LIMESDRMIMOSETTINGS_H_ diff --git a/plugins/samplemimo/limesdrmimo/readme.md b/plugins/samplemimo/limesdrmimo/readme.md index dee0039c4..6e70b2046 100644 --- a/plugins/samplemimo/limesdrmimo/readme.md +++ b/plugins/samplemimo/limesdrmimo/readme.md @@ -10,6 +10,8 @@ This MIMO plugin sends and receives its samples to/from a [LimeSDR device](https

Interface

+The top and bottom bars of the device window are described [here](../../../sdrgui/device/readme.md) + ![LimeSDR MIMO plugin GUI](../../../doc/img/LimeSDRMIMO_plugin.png)

1. Rx/Tx settings selection

diff --git a/plugins/samplemimo/metismiso/metismisogui.cpp b/plugins/samplemimo/metismiso/metismisogui.cpp index 3e720162c..b3836f1d7 100644 --- a/plugins/samplemimo/metismiso/metismisogui.cpp +++ b/plugins/samplemimo/metismiso/metismisogui.cpp @@ -22,13 +22,13 @@ #include #include #include +#include #include "plugin/pluginapi.h" #include "device/deviceapi.h" #include "device/deviceuiset.h" #include "gui/colormapper.h" #include "gui/glspectrum.h" -#include "gui/crightclickenabler.h" #include "gui/basicdevicesettingsdialog.h" #include "dsp/dspengine.h" #include "dsp/dspdevicemimoengine.h" @@ -43,7 +43,6 @@ MetisMISOGui::MetisMISOGui(DeviceUISet *deviceUISet, QWidget* parent) : DeviceGUI(parent), ui(new Ui::MetisMISOGui), - m_deviceUISet(deviceUISet), m_settings(), m_doApplySettings(true), m_forceSettings(true), @@ -52,11 +51,16 @@ MetisMISOGui::MetisMISOGui(DeviceUISet *deviceUISet, QWidget* parent) : m_lastEngineState(DeviceAPI::StNotStarted) { qDebug("MetisMISOGui::MetisMISOGui"); + m_deviceUISet = deviceUISet; + setAttribute(Qt::WA_DeleteOnClose, true); m_sampleMIMO = m_deviceUISet->m_deviceAPI->getSampleMIMO(); m_rxSampleRate = 48000; m_txSampleRate = 48000; - ui->setupUi(this); + ui->setupUi(getContents()); + setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); + getContents()->setStyleSheet("#MetisMISOGui { background-color: rgb(64, 64, 64); }"); + m_helpURL = "plugins/samplemimo/metismiso/readme.md"; ui->centerFrequency->setColorMapper(ColorMapper(ColorMapper::GrayGold)); ui->centerFrequency->setValueRange(7, 0, m_absMaxFreq); @@ -69,8 +73,9 @@ MetisMISOGui::MetisMISOGui(DeviceUISet *deviceUISet, QWidget* parent) : connect(&m_inputMessageQueue, SIGNAL(messageEnqueued()), this, SLOT(handleInputMessages()), Qt::QueuedConnection); m_sampleMIMO->setMessageQueueToGUI(&m_inputMessageQueue); - CRightClickEnabler *startStopRightClickEnabler = new CRightClickEnabler(ui->startStop); - connect(startStopRightClickEnabler, SIGNAL(rightClick(const QPoint &)), this, SLOT(openDeviceSettingsDialog(const QPoint &))); + connect(this, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(openDeviceSettingsDialog(const QPoint &))); + + makeUIConnections(); } MetisMISOGui::~MetisMISOGui() @@ -102,6 +107,12 @@ void MetisMISOGui::setCenterFrequency(qint64 centerFrequency) sendSettings(); } +void MetisMISOGui::resizeEvent(QResizeEvent* size) +{ + adjustSize(); + size->accept(); +} + QByteArray MetisMISOGui::serialize() const { return m_settings.serialize(); @@ -558,19 +569,47 @@ void MetisMISOGui::updateSubsamplingIndex() void MetisMISOGui::openDeviceSettingsDialog(const QPoint& p) { - BasicDeviceSettingsDialog dialog(this); - dialog.setUseReverseAPI(m_settings.m_useReverseAPI); - dialog.setReverseAPIAddress(m_settings.m_reverseAPIAddress); - dialog.setReverseAPIPort(m_settings.m_reverseAPIPort); - dialog.setReverseAPIDeviceIndex(m_settings.m_reverseAPIDeviceIndex); + if (m_contextMenuType == ContextMenuDeviceSettings) + { + BasicDeviceSettingsDialog dialog(this); + dialog.setUseReverseAPI(m_settings.m_useReverseAPI); + dialog.setReverseAPIAddress(m_settings.m_reverseAPIAddress); + dialog.setReverseAPIPort(m_settings.m_reverseAPIPort); + dialog.setReverseAPIDeviceIndex(m_settings.m_reverseAPIDeviceIndex); - dialog.move(p); - dialog.exec(); + dialog.move(p); + dialog.exec(); - m_settings.m_useReverseAPI = dialog.useReverseAPI(); - m_settings.m_reverseAPIAddress = dialog.getReverseAPIAddress(); - m_settings.m_reverseAPIPort = dialog.getReverseAPIPort(); - m_settings.m_reverseAPIDeviceIndex = dialog.getReverseAPIDeviceIndex(); + m_settings.m_useReverseAPI = dialog.useReverseAPI(); + m_settings.m_reverseAPIAddress = dialog.getReverseAPIAddress(); + m_settings.m_reverseAPIPort = dialog.getReverseAPIPort(); + m_settings.m_reverseAPIDeviceIndex = dialog.getReverseAPIDeviceIndex(); - sendSettings(); + sendSettings(); + } + + resetContextMenuType(); +} + +void MetisMISOGui::makeUIConnections() +{ + QObject::connect(ui->streamIndex, QOverload::of(&QComboBox::currentIndexChanged), this, &MetisMISOGui::on_streamIndex_currentIndexChanged); + QObject::connect(ui->spectrumSource, QOverload::of(&QComboBox::currentIndexChanged), this, &MetisMISOGui::on_spectrumSource_currentIndexChanged); + QObject::connect(ui->streamLock, &QToolButton::toggled, this, &MetisMISOGui::on_streamLock_toggled); + QObject::connect(ui->LOppm, &QSlider::valueChanged, this, &MetisMISOGui::on_LOppm_valueChanged); + QObject::connect(ui->startStop, &ButtonSwitch::toggled, this, &MetisMISOGui::on_startStop_toggled); + QObject::connect(ui->centerFrequency, &ValueDial::changed, this, &MetisMISOGui::on_centerFrequency_changed); + QObject::connect(ui->samplerateIndex, QOverload::of(&QComboBox::currentIndexChanged), this, &MetisMISOGui::on_samplerateIndex_currentIndexChanged); + QObject::connect(ui->log2Decim, QOverload::of(&QComboBox::currentIndexChanged), this, &MetisMISOGui::on_log2Decim_currentIndexChanged); + QObject::connect(ui->subsamplingIndex, QOverload::of(&QComboBox::currentIndexChanged), this, &MetisMISOGui::on_subsamplingIndex_currentIndexChanged); + QObject::connect(ui->dcBlock, &ButtonSwitch::toggled, this, &MetisMISOGui::on_dcBlock_toggled); + QObject::connect(ui->iqCorrection, &ButtonSwitch::toggled, this, &MetisMISOGui::on_iqCorrection_toggled); + QObject::connect(ui->transverter, &TransverterButton::clicked, this, &MetisMISOGui::on_transverter_clicked); + QObject::connect(ui->preamp, &ButtonSwitch::toggled, this, &MetisMISOGui::on_preamp_toggled); + QObject::connect(ui->random, &ButtonSwitch::toggled, this, &MetisMISOGui::on_random_toggled); + QObject::connect(ui->dither, &ButtonSwitch::toggled, this, &MetisMISOGui::on_dither_toggled); + QObject::connect(ui->duplex, &ButtonSwitch::toggled, this, &MetisMISOGui::on_duplex_toggled); + QObject::connect(ui->nbRxIndex, QOverload::of(&QComboBox::currentIndexChanged), this, &MetisMISOGui::on_nbRxIndex_currentIndexChanged); + QObject::connect(ui->txEnable, &ButtonSwitch::toggled, this, &MetisMISOGui::on_txEnable_toggled); + QObject::connect(ui->txDrive, &QDial::valueChanged, this, &MetisMISOGui::on_txDrive_valueChanged); } diff --git a/plugins/samplemimo/metismiso/metismisogui.h b/plugins/samplemimo/metismiso/metismisogui.h index 48cad3f44..f22c53ebf 100644 --- a/plugins/samplemimo/metismiso/metismisogui.h +++ b/plugins/samplemimo/metismiso/metismisogui.h @@ -46,10 +46,12 @@ public: bool deserialize(const QByteArray& data); virtual MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; } +protected: + void resizeEvent(QResizeEvent* size); + private: Ui::MetisMISOGui* ui; - DeviceUISet* m_deviceUISet; MetisMISOSettings m_settings; int m_rxSampleRate; int m_txSampleRate; @@ -74,6 +76,7 @@ private: void sendSettings(); void setCenterFrequency(qint64 centerFrequency); bool handleMessage(const Message& message); + void makeUIConnections(); private slots: void handleInputMessages(); diff --git a/plugins/samplemimo/metismiso/metismisogui.ui b/plugins/samplemimo/metismiso/metismisogui.ui index df0c87514..bcb622bba 100644 --- a/plugins/samplemimo/metismiso/metismisogui.ui +++ b/plugins/samplemimo/metismiso/metismisogui.ui @@ -6,12 +6,12 @@ 0 0 - 483 - 228 + 360 + 200 - + 0 0 @@ -22,6 +22,12 @@ 200 + + + 397 + 234 + + Liberation Sans @@ -306,7 +312,7 @@ Liberation Mono - 20 + 16 50 false false @@ -807,33 +813,20 @@ - - - - Qt::Vertical - - - - 20 - 40 - - - -
- - ButtonSwitch - QToolButton -
gui/buttonswitch.h
-
ValueDial QWidget
gui/valuedial.h
1
+ + ButtonSwitch + QToolButton +
gui/buttonswitch.h
+
TransverterButton QPushButton diff --git a/plugins/samplemimo/metismiso/readme.md b/plugins/samplemimo/metismiso/readme.md index 02dced384..c8ca6f173 100644 --- a/plugins/samplemimo/metismiso/readme.md +++ b/plugins/samplemimo/metismiso/readme.md @@ -17,6 +17,8 @@ The plugin is present in the core of the software and thus is always present in

Interface

+The top and bottom bars of the device window are described [here](../../../sdrgui/device/readme.md) + ![Metis MISO plugin GUI](../../../doc/img/MetisMISO_plugin.png)

1: Active stream selection

diff --git a/plugins/samplemimo/plutosdrmimo/plutosdrmimogui.cpp b/plugins/samplemimo/plutosdrmimo/plutosdrmimogui.cpp index 95f750f94..c47ee554c 100644 --- a/plugins/samplemimo/plutosdrmimo/plutosdrmimogui.cpp +++ b/plugins/samplemimo/plutosdrmimo/plutosdrmimogui.cpp @@ -21,13 +21,13 @@ #include #include #include +#include #include "plugin/pluginapi.h" #include "device/deviceapi.h" #include "device/deviceuiset.h" #include "gui/colormapper.h" #include "gui/glspectrum.h" -#include "gui/crightclickenabler.h" #include "gui/basicdevicesettingsdialog.h" #include "dsp/dspengine.h" #include "dsp/dspdevicemimoengine.h" @@ -47,7 +47,6 @@ PlutoSDRMIMOGUI::PlutoSDRMIMOGUI(DeviceUISet *deviceUISet, QWidget* parent) : DeviceGUI(parent), ui(new Ui::PlutoSDRMIMOGUI), - m_deviceUISet(deviceUISet), m_settings(), m_rxElseTx(true), m_streamIndex(0), @@ -68,7 +67,12 @@ PlutoSDRMIMOGUI::PlutoSDRMIMOGUI(DeviceUISet *deviceUISet, QWidget* parent) : m_sampleRateMode(true) { qDebug("PlutoSDRMIMOGui::PlutoSDRMIMOGui"); - ui->setupUi(this); + m_deviceUISet = deviceUISet; + setAttribute(Qt::WA_DeleteOnClose, true); + ui->setupUi(getContents()); + setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); + getContents()->setStyleSheet("#PlutoSDRMIMOGUI { background-color: rgb(64, 64, 64); }"); + m_helpURL = "plugins/samplemimo/plutosdrmimo/readme.md"; m_sampleMIMO = (PlutoSDRMIMO*) m_deviceUISet->m_deviceAPI->getSampleMIMO(); ui->centerFrequency->setColorMapper(ColorMapper(ColorMapper::GrayGold)); @@ -89,8 +93,7 @@ PlutoSDRMIMOGUI::PlutoSDRMIMOGUI(DeviceUISet *deviceUISet, QWidget* parent) : ui->swDecimLabel->setText(QString::fromUtf8("S\u2193")); ui->lpFIRDecimationLabel->setText(QString::fromUtf8("\u2193")); - CRightClickEnabler *startStopRightClickEnabler = new CRightClickEnabler(ui->startStopRx); - connect(startStopRightClickEnabler, SIGNAL(rightClick(const QPoint &)), this, SLOT(openDeviceSettingsDialog(const QPoint &))); + connect(this, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(openDeviceSettingsDialog(const QPoint &))); blockApplySettings(true); displaySettings(); @@ -102,6 +105,8 @@ PlutoSDRMIMOGUI::PlutoSDRMIMOGUI(DeviceUISet *deviceUISet, QWidget* parent) : connect(&m_inputMessageQueue, SIGNAL(messageEnqueued()), this, SLOT(handleInputMessages()), Qt::QueuedConnection); m_sampleMIMO->setMessageQueueToGUI(&m_inputMessageQueue); + + makeUIConnections(); } PlutoSDRMIMOGUI::~PlutoSDRMIMOGUI() @@ -142,6 +147,12 @@ bool PlutoSDRMIMOGUI::deserialize(const QByteArray& data) } } +void PlutoSDRMIMOGUI::resizeEvent(QResizeEvent* size) +{ + adjustSize(); + size->accept(); +} + void PlutoSDRMIMOGUI::displaySettings() { if (m_rxElseTx) @@ -875,19 +886,56 @@ void PlutoSDRMIMOGUI::on_sampleRateMode_toggled(bool checked) void PlutoSDRMIMOGUI::openDeviceSettingsDialog(const QPoint& p) { - BasicDeviceSettingsDialog dialog(this); - dialog.setUseReverseAPI(m_settings.m_useReverseAPI); - dialog.setReverseAPIAddress(m_settings.m_reverseAPIAddress); - dialog.setReverseAPIPort(m_settings.m_reverseAPIPort); - dialog.setReverseAPIDeviceIndex(m_settings.m_reverseAPIDeviceIndex); + if (m_contextMenuType == ContextMenuDeviceSettings) + { + BasicDeviceSettingsDialog dialog(this); + dialog.setUseReverseAPI(m_settings.m_useReverseAPI); + dialog.setReverseAPIAddress(m_settings.m_reverseAPIAddress); + dialog.setReverseAPIPort(m_settings.m_reverseAPIPort); + dialog.setReverseAPIDeviceIndex(m_settings.m_reverseAPIDeviceIndex); - dialog.move(p); - dialog.exec(); + dialog.move(p); + dialog.exec(); - m_settings.m_useReverseAPI = dialog.useReverseAPI(); - m_settings.m_reverseAPIAddress = dialog.getReverseAPIAddress(); - m_settings.m_reverseAPIPort = dialog.getReverseAPIPort(); - m_settings.m_reverseAPIDeviceIndex = dialog.getReverseAPIDeviceIndex(); + m_settings.m_useReverseAPI = dialog.useReverseAPI(); + m_settings.m_reverseAPIAddress = dialog.getReverseAPIAddress(); + m_settings.m_reverseAPIPort = dialog.getReverseAPIPort(); + m_settings.m_reverseAPIDeviceIndex = dialog.getReverseAPIDeviceIndex(); - sendSettings(); + sendSettings(); + } + + resetContextMenuType(); +} + +void PlutoSDRMIMOGUI::makeUIConnections() +{ + QObject::connect(ui->streamSide, QOverload::of(&QComboBox::currentIndexChanged), this, &PlutoSDRMIMOGUI::on_streamSide_currentIndexChanged); + QObject::connect(ui->streamIndex, QOverload::of(&QComboBox::currentIndexChanged), this, &PlutoSDRMIMOGUI::on_streamIndex_currentIndexChanged); + QObject::connect(ui->spectrumSide, QOverload::of(&QComboBox::currentIndexChanged), this, &PlutoSDRMIMOGUI::on_spectrumSide_currentIndexChanged); + QObject::connect(ui->spectrumIndex, QOverload::of(&QComboBox::currentIndexChanged), this, &PlutoSDRMIMOGUI::on_spectrumIndex_currentIndexChanged); + QObject::connect(ui->startStopRx, &ButtonSwitch::toggled, this, &PlutoSDRMIMOGUI::on_startStopRx_toggled); + QObject::connect(ui->startStopTx, &ButtonSwitch::toggled, this, &PlutoSDRMIMOGUI::on_startStopTx_toggled); + QObject::connect(ui->centerFrequency, &ValueDial::changed, this, &PlutoSDRMIMOGUI::on_centerFrequency_changed); + QObject::connect(ui->loPPM, &QSlider::valueChanged, this, &PlutoSDRMIMOGUI::on_loPPM_valueChanged); + QObject::connect(ui->dcOffset, &ButtonSwitch::toggled, this, &PlutoSDRMIMOGUI::on_dcOffset_toggled); + QObject::connect(ui->iqImbalance, &ButtonSwitch::toggled, this, &PlutoSDRMIMOGUI::on_iqImbalance_toggled); + QObject::connect(ui->sampleRate, &ValueDial::changed, this, &PlutoSDRMIMOGUI::on_sampleRate_changed); + QObject::connect(ui->sampleRateMode, &QToolButton::toggled, this, &PlutoSDRMIMOGUI::on_sampleRateMode_toggled); + QObject::connect(ui->fcPos, QOverload::of(&QComboBox::currentIndexChanged),this, &PlutoSDRMIMOGUI::on_fcPos_currentIndexChanged); + QObject::connect(ui->swDecim, QOverload::of(&QComboBox::currentIndexChanged), this, &PlutoSDRMIMOGUI::on_swDecim_currentIndexChanged); + QObject::connect(ui->gainLock, &QToolButton::toggled, this, &PlutoSDRMIMOGUI::on_gainLock_toggled); + QObject::connect(ui->gainMode, QOverload::of(&QComboBox::currentIndexChanged), this, &PlutoSDRMIMOGUI::on_gainMode_currentIndexChanged); + QObject::connect(ui->gain, &QDial::valueChanged, this, &PlutoSDRMIMOGUI::on_gain_valueChanged); + QObject::connect(ui->att, &QDial::valueChanged, this, &PlutoSDRMIMOGUI::on_att_valueChanged); + QObject::connect(ui->transverter, &TransverterButton::clicked, this, &PlutoSDRMIMOGUI::on_transverter_clicked); + QObject::connect(ui->rfDCOffset, &ButtonSwitch::toggled, this, &PlutoSDRMIMOGUI::on_rfDCOffset_toggled); + QObject::connect(ui->bbDCOffset, &ButtonSwitch::toggled, this, &PlutoSDRMIMOGUI::on_bbDCOffset_toggled); + QObject::connect(ui->hwIQImbalance, &ButtonSwitch::toggled, this, &PlutoSDRMIMOGUI::on_hwIQImbalance_toggled); + QObject::connect(ui->lpf, &ValueDial::changed, this, &PlutoSDRMIMOGUI::on_lpf_changed); + QObject::connect(ui->lpFIREnable, &ButtonSwitch::toggled, this, &PlutoSDRMIMOGUI::on_lpFIREnable_toggled); + QObject::connect(ui->lpFIR, &ValueDial::changed, this, &PlutoSDRMIMOGUI::on_lpFIR_changed); + QObject::connect(ui->lpFIRDecimation, QOverload::of(&QComboBox::currentIndexChanged), this, &PlutoSDRMIMOGUI::on_lpFIRDecimation_currentIndexChanged); + QObject::connect(ui->lpFIRGain, QOverload::of(&QComboBox::currentIndexChanged), this, &PlutoSDRMIMOGUI::on_lpFIRGain_currentIndexChanged); + QObject::connect(ui->antenna, QOverload::of(&QComboBox::currentIndexChanged), this, &PlutoSDRMIMOGUI::on_antenna_currentIndexChanged); } diff --git a/plugins/samplemimo/plutosdrmimo/plutosdrmimogui.h b/plugins/samplemimo/plutosdrmimo/plutosdrmimogui.h index 0f58ffd8d..e7993c1bb 100644 --- a/plugins/samplemimo/plutosdrmimo/plutosdrmimogui.h +++ b/plugins/samplemimo/plutosdrmimo/plutosdrmimogui.h @@ -45,10 +45,12 @@ public: bool deserialize(const QByteArray& data); virtual MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; } +protected: + void resizeEvent(QResizeEvent* size); + private: Ui::PlutoSDRMIMOGUI* ui; - DeviceUISet* m_deviceUISet; PlutoSDRMIMOSettings m_settings; bool m_rxElseTx; //!< Which side is being dealt with int m_streamIndex; //!< Current stream index being dealt with @@ -81,6 +83,7 @@ private: void setSampleRateLimits(); void updateFrequencyLimits(); bool handleMessage(const Message& message); + void makeUIConnections(); private slots: void handleInputMessages(); diff --git a/plugins/samplemimo/plutosdrmimo/plutosdrmimogui.ui b/plugins/samplemimo/plutosdrmimo/plutosdrmimogui.ui index 5434ff697..d5eaaeb65 100644 --- a/plugins/samplemimo/plutosdrmimo/plutosdrmimogui.ui +++ b/plugins/samplemimo/plutosdrmimo/plutosdrmimogui.ui @@ -6,20 +6,26 @@ 0 0 - 344 - 320 + 370 + 278 - + 0 0 - 344 - 320 + 370 + 278 + + + + + 390 + 319 @@ -313,7 +319,7 @@ Liberation Mono - 20 + 16 @@ -1257,23 +1263,6 @@ - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - -
diff --git a/plugins/samplemimo/plutosdrmimo/readme.md b/plugins/samplemimo/plutosdrmimo/readme.md index e571f1151..e30bfd53d 100644 --- a/plugins/samplemimo/plutosdrmimo/readme.md +++ b/plugins/samplemimo/plutosdrmimo/readme.md @@ -36,6 +36,8 @@ Then add the following defines on `cmake` command line when compiling SDRangel:

Interface

+The top and bottom bars of the device window are described [here](../../../sdrgui/device/readme.md) + ![PlutoSDR MIMO plugin GUI](../../../doc/img/PlutoSDRMIMO_plugin.png)

1. Rx/Tx settings selection

diff --git a/plugins/samplemimo/testmi/readme.md b/plugins/samplemimo/testmi/readme.md index 1f66d548e..639506a4a 100644 --- a/plugins/samplemimo/testmi/readme.md +++ b/plugins/samplemimo/testmi/readme.md @@ -10,6 +10,8 @@ The plugin is present in the core of the software and thus is always present in

Interface

+The top and bottom bars of the device window are described [here](../../../sdrgui/device/readme.md) + ![Test source input plugin GUI](../../../doc/img/TestSourceInput_plugin.png)

1: Common stream parameters

diff --git a/plugins/samplemimo/testmi/testmigui.cpp b/plugins/samplemimo/testmi/testmigui.cpp index e39e93c76..cc0d6a4cf 100644 --- a/plugins/samplemimo/testmi/testmigui.cpp +++ b/plugins/samplemimo/testmi/testmigui.cpp @@ -22,13 +22,13 @@ #include #include #include +#include #include "plugin/pluginapi.h" #include "device/deviceapi.h" #include "device/deviceuiset.h" #include "gui/colormapper.h" #include "gui/glspectrum.h" -#include "gui/crightclickenabler.h" #include "gui/basicdevicesettingsdialog.h" #include "dsp/dspengine.h" #include "dsp/dspdevicemimoengine.h" @@ -43,8 +43,9 @@ TestMIGui::TestMIGui(DeviceUISet *deviceUISet, QWidget* parent) : DeviceGUI(parent), ui(new Ui::TestMIGui), - m_deviceUISet(deviceUISet), m_settings(), + m_streamIndex(0), + m_spectrumStreamIndex(0), m_doApplySettings(true), m_forceSettings(true), m_sampleMIMO(nullptr), @@ -52,6 +53,13 @@ TestMIGui::TestMIGui(DeviceUISet *deviceUISet, QWidget* parent) : m_lastEngineState(DeviceAPI::StNotStarted) { qDebug("TestMIGui::TestMIGui"); + m_deviceUISet = deviceUISet; + setAttribute(Qt::WA_DeleteOnClose, true); + m_helpURL = "plugins/samplemimo/testmi/readme.md"; + ui->setupUi(getContents()); + setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); + getContents()->setStyleSheet("#TestMIGui { background-color: rgb(64, 64, 64); }"); + m_sampleMIMO = m_deviceUISet->m_deviceAPI->getSampleMIMO(); m_streamIndex = 0; m_deviceCenterFrequencies.push_back(m_settings.m_streams[0].m_centerFrequency); @@ -59,7 +67,6 @@ TestMIGui::TestMIGui(DeviceUISet *deviceUISet, QWidget* parent) : m_deviceSampleRates.push_back(m_settings.m_streams[0].m_sampleRate / (1<setupUi(this); ui->spectrumSource->addItem("0"); ui->spectrumSource->addItem("1"); ui->centerFrequency->setColorMapper(ColorMapper(ColorMapper::GrayGold)); @@ -79,8 +86,9 @@ TestMIGui::TestMIGui(DeviceUISet *deviceUISet, QWidget* parent) : connect(&m_inputMessageQueue, SIGNAL(messageEnqueued()), this, SLOT(handleInputMessages()), Qt::QueuedConnection); m_sampleMIMO->setMessageQueueToGUI(&m_inputMessageQueue); - CRightClickEnabler *startStopRightClickEnabler = new CRightClickEnabler(ui->startStop); - connect(startStopRightClickEnabler, SIGNAL(rightClick(const QPoint &)), this, SLOT(openDeviceSettingsDialog(const QPoint &))); + connect(this, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(openDeviceSettingsDialog(const QPoint &))); + + makeUIConnections(); } TestMIGui::~TestMIGui() @@ -118,6 +126,12 @@ bool TestMIGui::deserialize(const QByteArray& data) } } +void TestMIGui::resizeEvent(QResizeEvent* size) +{ + adjustSize(); + size->accept(); +} + void TestMIGui::on_startStop_toggled(bool checked) { if (m_doApplySettings) @@ -543,19 +557,49 @@ void TestMIGui::updateSampleRateAndFrequency() void TestMIGui::openDeviceSettingsDialog(const QPoint& p) { - BasicDeviceSettingsDialog dialog(this); - dialog.setUseReverseAPI(m_settings.m_useReverseAPI); - dialog.setReverseAPIAddress(m_settings.m_reverseAPIAddress); - dialog.setReverseAPIPort(m_settings.m_reverseAPIPort); - dialog.setReverseAPIDeviceIndex(m_settings.m_reverseAPIDeviceIndex); + if (m_contextMenuType == ContextMenuDeviceSettings) + { + BasicDeviceSettingsDialog dialog(this); + dialog.setUseReverseAPI(m_settings.m_useReverseAPI); + dialog.setReverseAPIAddress(m_settings.m_reverseAPIAddress); + dialog.setReverseAPIPort(m_settings.m_reverseAPIPort); + dialog.setReverseAPIDeviceIndex(m_settings.m_reverseAPIDeviceIndex); - dialog.move(p); - dialog.exec(); + dialog.move(p); + dialog.exec(); - m_settings.m_useReverseAPI = dialog.useReverseAPI(); - m_settings.m_reverseAPIAddress = dialog.getReverseAPIAddress(); - m_settings.m_reverseAPIPort = dialog.getReverseAPIPort(); - m_settings.m_reverseAPIDeviceIndex = dialog.getReverseAPIDeviceIndex(); + m_settings.m_useReverseAPI = dialog.useReverseAPI(); + m_settings.m_reverseAPIAddress = dialog.getReverseAPIAddress(); + m_settings.m_reverseAPIPort = dialog.getReverseAPIPort(); + m_settings.m_reverseAPIDeviceIndex = dialog.getReverseAPIDeviceIndex(); - sendSettings(); + sendSettings(); + } + + resetContextMenuType(); +} + +void TestMIGui::makeUIConnections() +{ + QObject::connect(ui->startStop, &ButtonSwitch::toggled, this, &TestMIGui::on_startStop_toggled); + QObject::connect(ui->streamIndex, QOverload::of(&QComboBox::currentIndexChanged), this, &TestMIGui::on_streamIndex_currentIndexChanged); + QObject::connect(ui->spectrumSource, QOverload::of(&QComboBox::currentIndexChanged), this, &TestMIGui::on_spectrumSource_currentIndexChanged); + QObject::connect(ui->streamLock, &QToolButton::toggled, this, &TestMIGui::on_streamLock_toggled); + QObject::connect(ui->centerFrequency, &ValueDial::changed, this, &TestMIGui::on_centerFrequency_changed); + QObject::connect(ui->autoCorr, QOverload::of(&QComboBox::currentIndexChanged), this, &TestMIGui::on_autoCorr_currentIndexChanged); + QObject::connect(ui->frequencyShift, &ValueDialZ::changed, this, &TestMIGui::on_frequencyShift_changed); + QObject::connect(ui->decimation, QOverload::of(&QComboBox::currentIndexChanged), this, &TestMIGui::on_decimation_currentIndexChanged); + QObject::connect(ui->fcPos, QOverload::of(&QComboBox::currentIndexChanged), this, &TestMIGui::on_fcPos_currentIndexChanged); + QObject::connect(ui->sampleRate, &ValueDial::changed, this, &TestMIGui::on_sampleRate_changed); + QObject::connect(ui->sampleSize, QOverload::of(&QComboBox::currentIndexChanged), this, &TestMIGui::on_sampleSize_currentIndexChanged); + QObject::connect(ui->amplitudeCoarse, &QSlider::valueChanged, this, &TestMIGui::on_amplitudeCoarse_valueChanged); + QObject::connect(ui->amplitudeFine, &QSlider::valueChanged, this, &TestMIGui::on_amplitudeFine_valueChanged); + QObject::connect(ui->modulation, QOverload::of(&QComboBox::currentIndexChanged), this, &TestMIGui::on_modulation_currentIndexChanged); + QObject::connect(ui->modulationFrequency, &QDial::valueChanged, this, &TestMIGui::on_modulationFrequency_valueChanged); + QObject::connect(ui->amModulation, &QDial::valueChanged, this, &TestMIGui::on_amModulation_valueChanged); + QObject::connect(ui->fmDeviation, &QDial::valueChanged, this, &TestMIGui::on_fmDeviation_valueChanged); + QObject::connect(ui->dcBias, &QSlider::valueChanged, this, &TestMIGui::on_dcBias_valueChanged); + QObject::connect(ui->iBias, &QSlider::valueChanged, this, &TestMIGui::on_iBias_valueChanged); + QObject::connect(ui->qBias, &QSlider::valueChanged, this, &TestMIGui::on_qBias_valueChanged); + QObject::connect(ui->phaseImbalance, &QSlider::valueChanged, this, &TestMIGui::on_phaseImbalance_valueChanged); } diff --git a/plugins/samplemimo/testmi/testmigui.h b/plugins/samplemimo/testmi/testmigui.h index a3b9ecd6f..41a949014 100644 --- a/plugins/samplemimo/testmi/testmigui.h +++ b/plugins/samplemimo/testmi/testmigui.h @@ -46,10 +46,12 @@ public: bool deserialize(const QByteArray& data); virtual MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; } +protected: + void resizeEvent(QResizeEvent* size); + private: Ui::TestMIGui* ui; - DeviceUISet* m_deviceUISet; TestMISettings m_settings; int m_streamIndex; //!< Current stream index being dealt with int m_spectrumStreamIndex; //!< Index of the stream displayed on main spectrum @@ -73,6 +75,7 @@ private: void updateAmpFineLimit(); void updateFrequencyShiftLimit(); bool handleMessage(const Message& message); + void makeUIConnections(); private slots: void handleInputMessages(); diff --git a/plugins/samplemimo/testmi/testmigui.ui b/plugins/samplemimo/testmi/testmigui.ui index 45b8e95a5..9ede84f55 100644 --- a/plugins/samplemimo/testmi/testmigui.ui +++ b/plugins/samplemimo/testmi/testmigui.ui @@ -6,20 +6,26 @@ 0 0 - 360 - 300 + 370 + 297 - + 0 0 - 360 - 300 + 370 + 297 + + + + + 390 + 368 @@ -223,7 +229,10 @@ Liberation Mono - 20 + 16 + 50 + false + false @@ -488,6 +497,9 @@ Liberation Mono 12 + 50 + false + false @@ -644,6 +656,9 @@ Liberation Mono 12 + 50 + false + false @@ -764,13 +779,6 @@ - - - - Qt::Horizontal - - - @@ -1052,9 +1060,6 @@ - - -
diff --git a/plugins/samplemimo/testmi/testmisettings.h b/plugins/samplemimo/testmi/testmisettings.h index 62c328b97..63c11889b 100644 --- a/plugins/samplemimo/testmi/testmisettings.h +++ b/plugins/samplemimo/testmi/testmisettings.h @@ -65,7 +65,8 @@ struct TestMIStreamSettings { void resetToDefaults(); }; -struct TestMISettings { +struct TestMISettings +{ bool m_useReverseAPI; QString m_reverseAPIAddress; uint16_t m_reverseAPIPort; diff --git a/plugins/samplemimo/testmosync/readme.md b/plugins/samplemimo/testmosync/readme.md index 8c053be4d..2343a8199 100644 --- a/plugins/samplemimo/testmosync/readme.md +++ b/plugins/samplemimo/testmosync/readme.md @@ -10,6 +10,8 @@ The plugin is always built.

Interface

+The top and bottom bars of the device window are described [here](../../../sdrgui/device/readme.md) + ![Test MO sync plugin GUI](../../../doc/img/TestMOSync_plugin.png)

1: Start/Stop

@@ -44,4 +46,4 @@ Use the wheels to adjust the sample rate. Left click on a digit sets the cursor

7: Spectrum display

-This is the final output stream spectrum display after interpolation (5). This would be sent to the hardware device. Controls on the bottom of the panel are identical to the ones of the main spectrum display. +This is the final output stream spectrum display after interpolation (5). This would be sent to the hardware device. Details on the spectrum view and controls can be found [here](../../../sdrgui/gui/spectrum.md) diff --git a/plugins/samplemimo/testmosync/testmosyncgui.cpp b/plugins/samplemimo/testmosync/testmosyncgui.cpp index cbcd64670..1b53e70fe 100644 --- a/plugins/samplemimo/testmosync/testmosyncgui.cpp +++ b/plugins/samplemimo/testmosync/testmosyncgui.cpp @@ -24,6 +24,7 @@ #include "plugin/pluginapi.h" #include "gui/colormapper.h" #include "gui/glspectrum.h" +#include "gui/basicdevicesettingsdialog.h" #include "dsp/dspengine.h" #include "dsp/dspcommands.h" #include "dsp/spectrumvis.h" @@ -38,7 +39,6 @@ TestMOSyncGui::TestMOSyncGui(DeviceUISet *deviceUISet, QWidget* parent) : DeviceGUI(parent), ui(new Ui::TestMOSyncGui), - m_deviceUISet(deviceUISet), m_doApplySettings(true), m_forceSettings(true), m_settings(), @@ -49,7 +49,14 @@ TestMOSyncGui::TestMOSyncGui(DeviceUISet *deviceUISet, QWidget* parent) : m_tickCount(0), m_lastEngineState(DeviceAPI::StNotStarted) { - ui->setupUi(this); + m_deviceUISet = deviceUISet; + setAttribute(Qt::WA_DeleteOnClose, true); + m_helpURL = "plugins/samplemimo/testmosync/readme.md"; + QWidget *contents = getContents(); + ui->setupUi(contents); + setSizePolicy(contents->sizePolicy()); + + getContents()->setStyleSheet("#TestMOSyncGui { background-color: rgb(64, 64, 64); }"); m_sampleMIMO = (TestMOSync*) m_deviceUISet->m_deviceAPI->getSampleMIMO(); ui->centerFrequency->setColorMapper(ColorMapper(ColorMapper::GrayGold)); @@ -70,6 +77,7 @@ TestMOSyncGui::TestMOSyncGui(DeviceUISet *deviceUISet, QWidget* parent) : m_statusTimer.start(500); displaySettings(); + makeUIConnections(); m_sampleMIMO->setMessageQueueToGUI(&m_inputMessageQueue); connect(&m_inputMessageQueue, SIGNAL(messageEnqueued()), this, SLOT(handleInputMessages()), Qt::QueuedConnection); @@ -77,6 +85,8 @@ TestMOSyncGui::TestMOSyncGui(DeviceUISet *deviceUISet, QWidget* parent) : m_deviceUISet->m_spectrum->setDisplayedStream(false, 0); m_deviceUISet->m_deviceAPI->setSpectrumSinkInput(false, 0); m_deviceUISet->setSpectrumScalingFactor(SDR_TX_SCALEF); + + connect(this, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(openDeviceSettingsDialog(const QPoint &))); } TestMOSyncGui::~TestMOSyncGui() @@ -282,3 +292,36 @@ void TestMOSyncGui::on_spectrumIndex_currentIndexChanged(int index) void TestMOSyncGui::tick() { } + +void TestMOSyncGui::openDeviceSettingsDialog(const QPoint& p) +{ + if (m_contextMenuType == ContextMenuDeviceSettings) + { + BasicDeviceSettingsDialog dialog(this); + dialog.setUseReverseAPI(m_settings.m_useReverseAPI); + dialog.setReverseAPIAddress(m_settings.m_reverseAPIAddress); + dialog.setReverseAPIPort(m_settings.m_reverseAPIPort); + dialog.setReverseAPIDeviceIndex(m_settings.m_reverseAPIDeviceIndex); + + dialog.move(p); + dialog.exec(); + + m_settings.m_useReverseAPI = dialog.useReverseAPI(); + m_settings.m_reverseAPIAddress = dialog.getReverseAPIAddress(); + m_settings.m_reverseAPIPort = dialog.getReverseAPIPort(); + m_settings.m_reverseAPIDeviceIndex = dialog.getReverseAPIDeviceIndex(); + + sendSettings(); + } + + resetContextMenuType(); +} + +void TestMOSyncGui::makeUIConnections() +{ + QObject::connect(ui->centerFrequency, &ValueDial::changed, this, &TestMOSyncGui::on_centerFrequency_changed); + QObject::connect(ui->sampleRate, &ValueDial::changed, this, &TestMOSyncGui::on_sampleRate_changed); + QObject::connect(ui->startStop, &ButtonSwitch::toggled, this, &TestMOSyncGui::on_startStop_toggled); + QObject::connect(ui->interp, QOverload::of(&QComboBox::currentIndexChanged), this, &TestMOSyncGui::on_interp_currentIndexChanged); + QObject::connect(ui->spectrumIndex, QOverload::of(&QComboBox::currentIndexChanged), this, &TestMOSyncGui::on_spectrumIndex_currentIndexChanged); +} diff --git a/plugins/samplemimo/testmosync/testmosyncgui.h b/plugins/samplemimo/testmosync/testmosyncgui.h index e6b066d0b..7815d10ba 100644 --- a/plugins/samplemimo/testmosync/testmosyncgui.h +++ b/plugins/samplemimo/testmosync/testmosyncgui.h @@ -51,7 +51,6 @@ public: private: Ui::TestMOSyncGui* ui; - DeviceUISet* m_deviceUISet; bool m_doApplySettings; bool m_forceSettings; TestMOSyncSettings m_settings; @@ -72,6 +71,7 @@ private: void sendSettings(); void updateSampleRateAndFrequency(); bool handleMessage(const Message& message); + void makeUIConnections(); private slots: void handleInputMessages(); @@ -80,6 +80,7 @@ private slots: void on_startStop_toggled(bool checked); void on_interp_currentIndexChanged(int index); void on_spectrumIndex_currentIndexChanged(int index); + void openDeviceSettingsDialog(const QPoint& p); void updateHardware(); void updateStatus(); void tick(); diff --git a/plugins/samplemimo/testmosync/testmosyncgui.ui b/plugins/samplemimo/testmosync/testmosyncgui.ui index 104df588a..ce43ea830 100644 --- a/plugins/samplemimo/testmosync/testmosyncgui.ui +++ b/plugins/samplemimo/testmosync/testmosyncgui.ui @@ -6,20 +6,20 @@ 0 0 - 350 - 400 + 360 + 420 - + 0 0 - 350 - 400 + 360 + 420 @@ -131,7 +131,7 @@ Liberation Mono - 20 + 16 @@ -147,6 +147,12 @@ + + + 0 + 47 + + kHz @@ -263,6 +269,12 @@ + + + 0 + 29 + + SR @@ -323,59 +335,56 @@ - - - - - - 200 - 200 - - - - - Liberation Mono - 8 - - - - - - - - - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - + + + + 0 + 0 + + + + + + + + 0 + 0 + + + + + 200 + 200 + + + + + Liberation Mono + 8 + + + + + + + + + + + ButtonSwitch + QToolButton +
gui/buttonswitch.h
+
ValueDial QWidget
gui/valuedial.h
1
- - ButtonSwitch - QToolButton -
gui/buttonswitch.h
-
GLSpectrum QWidget diff --git a/plugins/samplemimo/testmosync/testmosyncsettings.cpp b/plugins/samplemimo/testmosync/testmosyncsettings.cpp index 596f90432..020551f31 100644 --- a/plugins/samplemimo/testmosync/testmosyncsettings.cpp +++ b/plugins/samplemimo/testmosync/testmosyncsettings.cpp @@ -31,6 +31,10 @@ void TestMOSyncSettings::resetToDefaults() m_sampleRate = 48000; m_log2Interp = 0; m_fcPosTx = FC_POS_CENTER; + m_useReverseAPI = false; + m_reverseAPIAddress = "127.0.0.1"; + m_reverseAPIPort = 8888; + m_reverseAPIDeviceIndex = 0; } QByteArray TestMOSyncSettings::serialize() const @@ -40,6 +44,10 @@ QByteArray TestMOSyncSettings::serialize() const s.writeU64(1, m_sampleRate); s.writeU32(2, m_log2Interp); s.writeS32(3, (int) m_fcPosTx); + s.writeBool(6, m_useReverseAPI); + s.writeString(7, m_reverseAPIAddress); + s.writeU32(8, m_reverseAPIPort); + s.writeU32(9, m_reverseAPIDeviceIndex); return s.final(); } @@ -57,11 +65,24 @@ bool TestMOSyncSettings::deserialize(const QByteArray& data) if (d.getVersion() == 1) { int intval; + uint32_t utmp; d.readU64(1, &m_sampleRate, 48000); d.readU32(2, &m_log2Interp, 0); - d.readS32(38, &intval, 2); + d.readS32(3, &intval, 2); m_fcPosTx = (fcPos_t) intval; + d.readBool(1, &m_useReverseAPI, false); + d.readString(2, &m_reverseAPIAddress, "127.0.0.1"); + d.readU32(3, &utmp, 0); + + if ((utmp > 1023) && (utmp < 65535)) { + m_reverseAPIPort = utmp; + } else { + m_reverseAPIPort = 8888; + } + + d.readU32(4, &utmp, 0); + m_reverseAPIDeviceIndex = utmp > 99 ? 99 : utmp; return true; } diff --git a/plugins/samplemimo/testmosync/testmosyncsettings.h b/plugins/samplemimo/testmosync/testmosyncsettings.h index dc40e9c5a..31cbe3774 100644 --- a/plugins/samplemimo/testmosync/testmosyncsettings.h +++ b/plugins/samplemimo/testmosync/testmosyncsettings.h @@ -18,8 +18,6 @@ #ifndef PLUGINS_SAMPLEMIMO_TESTMOSYNC_TESTMOSYNCSETTINGS_H_ #define PLUGINS_SAMPLEMIMO_TESTMOSYNC_TESTMOSYNCSETTINGS_H_ -#include - struct TestMOSyncSettings { typedef enum { FC_POS_INFRA = 0, @@ -31,6 +29,10 @@ struct TestMOSyncSettings { quint64 m_sampleRate; quint32 m_log2Interp; fcPos_t m_fcPosTx; + bool m_useReverseAPI; + QString m_reverseAPIAddress; + uint16_t m_reverseAPIPort; + uint16_t m_reverseAPIDeviceIndex; static const unsigned int m_msThrottle; diff --git a/plugins/samplemimo/xtrxmimo/readme.md b/plugins/samplemimo/xtrxmimo/readme.md index 9041318c8..9037dac77 100644 --- a/plugins/samplemimo/xtrxmimo/readme.md +++ b/plugins/samplemimo/xtrxmimo/readme.md @@ -40,6 +40,8 @@ For a group the syntax is the same but the group name is prefixed with `@` like:

Interface

+The top and bottom bars of the device window are described [here](../../../sdrgui/device/readme.md) + ![XTRX MIMO plugin GUI](../../../doc/img/XTRXMIMO_plugin.png)

1. Rx/Tx settings selection

diff --git a/plugins/samplemimo/xtrxmimo/xtrxmimogui.cpp b/plugins/samplemimo/xtrxmimo/xtrxmimogui.cpp index cace01d2f..1f66fa5d0 100644 --- a/plugins/samplemimo/xtrxmimo/xtrxmimogui.cpp +++ b/plugins/samplemimo/xtrxmimo/xtrxmimogui.cpp @@ -20,13 +20,13 @@ #include #include #include +#include #include "plugin/pluginapi.h" #include "device/deviceapi.h" #include "device/deviceuiset.h" #include "gui/colormapper.h" #include "gui/glspectrum.h" -#include "gui/crightclickenabler.h" #include "gui/basicdevicesettingsdialog.h" #include "dsp/dspengine.h" #include "dsp/dspdevicemimoengine.h" @@ -44,7 +44,6 @@ XTRXMIMOGUI::XTRXMIMOGUI(DeviceUISet *deviceUISet, QWidget* parent) : DeviceGUI(parent), ui(new Ui::XTRXMIMOGUI), - m_deviceUISet(deviceUISet), m_settings(), m_rxElseTx(true), m_streamIndex(0), @@ -65,7 +64,12 @@ XTRXMIMOGUI::XTRXMIMOGUI(DeviceUISet *deviceUISet, QWidget* parent) : m_sampleRateMode(true) { qDebug("XTRXMIMOGUI::XTRXMIMOGUI"); - ui->setupUi(this); + m_deviceUISet = deviceUISet; + setAttribute(Qt::WA_DeleteOnClose, true); + ui->setupUi(getContents()); + setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); + getContents()->setStyleSheet("#XTRXMIMOGUI { background-color: rgb(64, 64, 64); }"); + m_helpURL = "plugins/samplemimo/xtrxmimo/readme.md"; m_xtrxMIMO = (XTRXMIMO*) m_deviceUISet->m_deviceAPI->getSampleMIMO(); float minF, maxF, stepF; @@ -93,10 +97,10 @@ XTRXMIMOGUI::XTRXMIMOGUI(DeviceUISet *deviceUISet, QWidget* parent) : connect(&m_inputMessageQueue, SIGNAL(messageEnqueued()), this, SLOT(handleInputMessages()), Qt::QueuedConnection); m_xtrxMIMO->setMessageQueueToGUI(&m_inputMessageQueue); - CRightClickEnabler *startStopRightClickEnabler = new CRightClickEnabler(ui->startStopRx); - connect(startStopRightClickEnabler, SIGNAL(rightClick(const QPoint &)), this, SLOT(openDeviceSettingsDialog(const QPoint &))); + connect(this, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(openDeviceSettingsDialog(const QPoint &))); sendSettings(); + makeUIConnections(); } XTRXMIMOGUI::~XTRXMIMOGUI() @@ -137,6 +141,12 @@ bool XTRXMIMOGUI::deserialize(const QByteArray& data) } } +void XTRXMIMOGUI::resizeEvent(QResizeEvent* size) +{ + adjustSize(); + size->accept(); +} + void XTRXMIMOGUI::handleInputMessages() { Message* message; @@ -997,19 +1007,52 @@ void XTRXMIMOGUI::on_antenna_currentIndexChanged(int index) void XTRXMIMOGUI::openDeviceSettingsDialog(const QPoint& p) { - BasicDeviceSettingsDialog dialog(this); - dialog.setUseReverseAPI(m_settings.m_useReverseAPI); - dialog.setReverseAPIAddress(m_settings.m_reverseAPIAddress); - dialog.setReverseAPIPort(m_settings.m_reverseAPIPort); - dialog.setReverseAPIDeviceIndex(m_settings.m_reverseAPIDeviceIndex); + if (m_contextMenuType == ContextMenuDeviceSettings) + { + BasicDeviceSettingsDialog dialog(this); + dialog.setUseReverseAPI(m_settings.m_useReverseAPI); + dialog.setReverseAPIAddress(m_settings.m_reverseAPIAddress); + dialog.setReverseAPIPort(m_settings.m_reverseAPIPort); + dialog.setReverseAPIDeviceIndex(m_settings.m_reverseAPIDeviceIndex); - dialog.move(p); - dialog.exec(); + dialog.move(p); + dialog.exec(); - m_settings.m_useReverseAPI = dialog.useReverseAPI(); - m_settings.m_reverseAPIAddress = dialog.getReverseAPIAddress(); - m_settings.m_reverseAPIPort = dialog.getReverseAPIPort(); - m_settings.m_reverseAPIDeviceIndex = dialog.getReverseAPIDeviceIndex(); + m_settings.m_useReverseAPI = dialog.useReverseAPI(); + m_settings.m_reverseAPIAddress = dialog.getReverseAPIAddress(); + m_settings.m_reverseAPIPort = dialog.getReverseAPIPort(); + m_settings.m_reverseAPIDeviceIndex = dialog.getReverseAPIDeviceIndex(); - sendSettings(); + sendSettings(); + } + + resetContextMenuType(); +} + +void XTRXMIMOGUI::makeUIConnections() +{ + QObject::connect(ui->streamSide, QOverload::of(&QComboBox::currentIndexChanged), this, &XTRXMIMOGUI::on_streamSide_currentIndexChanged); + QObject::connect(ui->streamIndex, QOverload::of(&QComboBox::currentIndexChanged), this, &XTRXMIMOGUI::on_streamIndex_currentIndexChanged); + QObject::connect(ui->spectrumSide, QOverload::of(&QComboBox::currentIndexChanged), this, &XTRXMIMOGUI::on_spectrumSide_currentIndexChanged); + QObject::connect(ui->spectrumIndex, QOverload::of(&QComboBox::currentIndexChanged), this, &XTRXMIMOGUI::on_spectrumIndex_currentIndexChanged); + QObject::connect(ui->startStopRx, &ButtonSwitch::toggled, this, &XTRXMIMOGUI::on_startStopRx_toggled); + QObject::connect(ui->startStopTx, &ButtonSwitch::toggled, this, &XTRXMIMOGUI::on_startStopTx_toggled); + QObject::connect(ui->centerFrequency, &ValueDial::changed, this, &XTRXMIMOGUI::on_centerFrequency_changed); + QObject::connect(ui->ncoEnable, &ButtonSwitch::toggled, this, &XTRXMIMOGUI::on_ncoEnable_toggled); + QObject::connect(ui->ncoFrequency, &ValueDialZ::changed, this, &XTRXMIMOGUI::on_ncoFrequency_changed); + QObject::connect(ui->dcOffset, &ButtonSwitch::toggled, this, &XTRXMIMOGUI::on_dcOffset_toggled); + QObject::connect(ui->iqImbalance, &ButtonSwitch::toggled, this, &XTRXMIMOGUI::on_iqImbalance_toggled); + QObject::connect(ui->extClock, &ExternalClockButton::clicked, this, &XTRXMIMOGUI::on_extClock_clicked); + QObject::connect(ui->hwDecim, QOverload::of(&QComboBox::currentIndexChanged), this, &XTRXMIMOGUI::on_hwDecim_currentIndexChanged); + QObject::connect(ui->swDecim, QOverload::of(&QComboBox::currentIndexChanged), this, &XTRXMIMOGUI::on_swDecim_currentIndexChanged); + QObject::connect(ui->sampleRateMode, &QToolButton::toggled, this, &XTRXMIMOGUI::on_sampleRateMode_toggled); + QObject::connect(ui->sampleRate, &ValueDial::changed, this, &XTRXMIMOGUI::on_sampleRate_changed); + QObject::connect(ui->lpf, &ValueDial::changed, this, &XTRXMIMOGUI::on_lpf_changed); + QObject::connect(ui->pwrmode, QOverload::of(&QComboBox::currentIndexChanged), this, &XTRXMIMOGUI::on_pwrmode_currentIndexChanged); + QObject::connect(ui->gainMode, QOverload::of(&QComboBox::currentIndexChanged), this, &XTRXMIMOGUI::on_gainMode_currentIndexChanged); + QObject::connect(ui->gain, &QDial::valueChanged, this, &XTRXMIMOGUI::on_gain_valueChanged); + QObject::connect(ui->lnaGain, &QDial::valueChanged, this, &XTRXMIMOGUI::on_lnaGain_valueChanged); + QObject::connect(ui->tiaGain, QOverload::of(&QComboBox::currentIndexChanged), this, &XTRXMIMOGUI::on_tiaGain_currentIndexChanged); + QObject::connect(ui->pgaGain, &QDial::valueChanged, this, &XTRXMIMOGUI::on_pgaGain_valueChanged); + QObject::connect(ui->antenna, QOverload::of(&QComboBox::currentIndexChanged), this, &XTRXMIMOGUI::on_antenna_currentIndexChanged); } diff --git a/plugins/samplemimo/xtrxmimo/xtrxmimogui.h b/plugins/samplemimo/xtrxmimo/xtrxmimogui.h index 4699300fb..913195065 100644 --- a/plugins/samplemimo/xtrxmimo/xtrxmimogui.h +++ b/plugins/samplemimo/xtrxmimo/xtrxmimogui.h @@ -45,10 +45,12 @@ public: bool deserialize(const QByteArray& data); virtual MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; } +protected: + void resizeEvent(QResizeEvent* size); + private: Ui::XTRXMIMOGUI* ui; - DeviceUISet* m_deviceUISet; XTRXMIMOSettings m_settings; bool m_rxElseTx; //!< Which side is being dealt with int m_streamIndex; //!< Current stream index being dealt with @@ -85,6 +87,7 @@ private: void updateADCRate(); void updateDACRate(); bool handleMessage(const Message& message); + void makeUIConnections(); private slots: void handleInputMessages(); diff --git a/plugins/samplemimo/xtrxmimo/xtrxmimogui.ui b/plugins/samplemimo/xtrxmimo/xtrxmimogui.ui index c59b43367..d5319eb42 100644 --- a/plugins/samplemimo/xtrxmimo/xtrxmimogui.ui +++ b/plugins/samplemimo/xtrxmimo/xtrxmimogui.ui @@ -7,19 +7,25 @@ 0 0 370 - 290 + 242
- + 0 0 - 360 - 290 + 370 + 242 + + + + + 390 + 284 @@ -336,7 +342,7 @@ Liberation Mono - 20 + 16 50 false @@ -1185,6 +1191,7 @@ + Liberation Sans 8 @@ -1274,30 +1281,6 @@ QToolTip{background-color: white; color: black;} - - - - Qt::Horizontal - - - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - @@ -1312,17 +1295,17 @@ QToolTip{background-color: white; color: black;} QToolButton
gui/buttonswitch.h
- - ExternalClockButton - QToolButton -
gui/externalclockbutton.h
-
ValueDialZ QWidget
gui/valuedialz.h
1
+ + ExternalClockButton + QToolButton +
gui/externalclockbutton.h
+
diff --git a/plugins/samplesink/audiooutput/audiooutputgui.cpp b/plugins/samplesink/audiooutput/audiooutputgui.cpp index be4df2bb1..f20cfaf19 100644 --- a/plugins/samplesink/audiooutput/audiooutputgui.cpp +++ b/plugins/samplesink/audiooutput/audiooutputgui.cpp @@ -17,11 +17,11 @@ #include #include +#include #include "ui_audiooutputgui.h" #include "gui/colormapper.h" #include "gui/glspectrum.h" -#include "gui/crightclickenabler.h" #include "gui/basicdevicesettingsdialog.h" #include "gui/audioselectdialog.h" #include "dsp/dspengine.h" @@ -34,20 +34,22 @@ AudioOutputGui::AudioOutputGui(DeviceUISet *deviceUISet, QWidget* parent) : DeviceGUI(parent), ui(new Ui::AudioOutputGui), - m_deviceUISet(deviceUISet), m_doApplySettings(true), m_forceSettings(true), m_settings(), m_centerFrequency(0) { + m_deviceUISet = deviceUISet; + setAttribute(Qt::WA_DeleteOnClose, true); m_audioOutput = (AudioOutput*) m_deviceUISet->m_deviceAPI->getSampleSink(); - ui->setupUi(this); + ui->setupUi(getContents()); + setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); + getContents()->setStyleSheet("#AudioOutputGui { background-color: rgb(64, 64, 64); }"); + m_helpURL = "plugins/samplesink/audiooutput/readme.md"; connect(&m_updateTimer, SIGNAL(timeout()), this, SLOT(updateHardware())); - - CRightClickEnabler *startStopRightClickEnabler = new CRightClickEnabler(ui->startStop); - connect(startStopRightClickEnabler, SIGNAL(rightClick(const QPoint &)), this, SLOT(openDeviceSettingsDialog(const QPoint &))); + connect(this, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(openDeviceSettingsDialog(const QPoint &))); m_sampleRate = m_audioOutput->getSampleRate(); m_centerFrequency = m_audioOutput->getCenterFrequency(); @@ -57,6 +59,8 @@ AudioOutputGui::AudioOutputGui(DeviceUISet *deviceUISet, QWidget* parent) : connect(&m_inputMessageQueue, SIGNAL(messageEnqueued()), this, SLOT(handleInputMessages()), Qt::QueuedConnection); m_audioOutput->setMessageQueueToGUI(&m_inputMessageQueue); + + makeUIConnections(); } AudioOutputGui::~AudioOutputGui() @@ -97,6 +101,12 @@ bool AudioOutputGui::deserialize(const QByteArray& data) } } +void AudioOutputGui::resizeEvent(QResizeEvent* size) +{ + adjustSize(); + size->accept(); +} + bool AudioOutputGui::handleMessage(const Message& message) { if (AudioOutput::MsgConfigureAudioOutput::match(message)) @@ -221,19 +231,32 @@ void AudioOutputGui::updateHardware() void AudioOutputGui::openDeviceSettingsDialog(const QPoint& p) { - BasicDeviceSettingsDialog dialog(this); - dialog.setUseReverseAPI(m_settings.m_useReverseAPI); - dialog.setReverseAPIAddress(m_settings.m_reverseAPIAddress); - dialog.setReverseAPIPort(m_settings.m_reverseAPIPort); - dialog.setReverseAPIDeviceIndex(m_settings.m_reverseAPIDeviceIndex); + if (m_contextMenuType == ContextMenuDeviceSettings) + { + BasicDeviceSettingsDialog dialog(this); + dialog.setUseReverseAPI(m_settings.m_useReverseAPI); + dialog.setReverseAPIAddress(m_settings.m_reverseAPIAddress); + dialog.setReverseAPIPort(m_settings.m_reverseAPIPort); + dialog.setReverseAPIDeviceIndex(m_settings.m_reverseAPIDeviceIndex); - dialog.move(p); - dialog.exec(); + dialog.move(p); + dialog.exec(); - m_settings.m_useReverseAPI = dialog.useReverseAPI(); - m_settings.m_reverseAPIAddress = dialog.getReverseAPIAddress(); - m_settings.m_reverseAPIPort = dialog.getReverseAPIPort(); - m_settings.m_reverseAPIDeviceIndex = dialog.getReverseAPIDeviceIndex(); + m_settings.m_useReverseAPI = dialog.useReverseAPI(); + m_settings.m_reverseAPIAddress = dialog.getReverseAPIAddress(); + m_settings.m_reverseAPIPort = dialog.getReverseAPIPort(); + m_settings.m_reverseAPIDeviceIndex = dialog.getReverseAPIDeviceIndex(); - sendSettings(); + sendSettings(); + } + + resetContextMenuType(); +} + +void AudioOutputGui::makeUIConnections() +{ + QObject::connect(ui->deviceSelect, &QPushButton::clicked, this, &AudioOutputGui::on_deviceSelect_clicked); + QObject::connect(ui->volume, &QDial::valueChanged, this, &AudioOutputGui::on_volume_valueChanged); + QObject::connect(ui->channels, QOverload::of(&QComboBox::currentIndexChanged), this, &AudioOutputGui::on_channels_currentIndexChanged); + QObject::connect(ui->startStop, &ButtonSwitch::toggled, this, &AudioOutputGui::on_startStop_toggled); } diff --git a/plugins/samplesink/audiooutput/audiooutputgui.h b/plugins/samplesink/audiooutput/audiooutputgui.h index 84e3e92a9..ae38f6dbb 100644 --- a/plugins/samplesink/audiooutput/audiooutputgui.h +++ b/plugins/samplesink/audiooutput/audiooutputgui.h @@ -46,10 +46,12 @@ public: bool deserialize(const QByteArray& data); virtual MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; } +protected: + void resizeEvent(QResizeEvent* size); + private: Ui::AudioOutputGui* ui; - DeviceUISet* m_deviceUISet; AudioOutput* m_audioOutput; bool m_doApplySettings; bool m_forceSettings; @@ -65,6 +67,7 @@ private: void sendSettings(); void updateSampleRateAndFrequency(); bool handleMessage(const Message& message); + void makeUIConnections(); private slots: void handleInputMessages(); diff --git a/plugins/samplesink/audiooutput/audiooutputgui.ui b/plugins/samplesink/audiooutput/audiooutputgui.ui index 291a3b123..db815efd5 100644 --- a/plugins/samplesink/audiooutput/audiooutputgui.ui +++ b/plugins/samplesink/audiooutput/audiooutputgui.ui @@ -6,20 +6,26 @@ 0 0 - 320 - 200 + 360 + 124
- + 0 0 - 320 - 200 + 360 + 124 + + + + + 380 + 143 @@ -161,13 +167,6 @@ - - - - Qt::Horizontal - - - @@ -257,23 +256,6 @@ - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - diff --git a/plugins/samplesink/audiooutput/readme.md b/plugins/samplesink/audiooutput/readme.md index 7275c48a9..dacf5d877 100644 --- a/plugins/samplesink/audiooutput/readme.md +++ b/plugins/samplesink/audiooutput/readme.md @@ -6,6 +6,8 @@ This output plugin sends its samples to an audio device.

Interface

+The top and bottom bars of the device window are described [here](../../../sdrgui/device/readme.md) + ![Audio output plugin GUI](../../../doc/img/AudioOutput_plugin.png)

1: Start/Stop

diff --git a/plugins/samplesink/bladerf1output/bladerf1outputgui.cpp b/plugins/samplesink/bladerf1output/bladerf1outputgui.cpp index 56c2168a8..efd1bcfb7 100644 --- a/plugins/samplesink/bladerf1output/bladerf1outputgui.cpp +++ b/plugins/samplesink/bladerf1output/bladerf1outputgui.cpp @@ -17,13 +17,13 @@ #include #include +#include #include #include "ui_bladerf1outputgui.h" #include "gui/colormapper.h" #include "gui/glspectrum.h" -#include "gui/crightclickenabler.h" #include "gui/basicdevicesettingsdialog.h" #include "dsp/dspengine.h" #include "dsp/dspcommands.h" @@ -34,7 +34,6 @@ Bladerf1OutputGui::Bladerf1OutputGui(DeviceUISet *deviceUISet, QWidget* parent) : DeviceGUI(parent), ui(new Ui::Bladerf1OutputGui), - m_deviceUISet(deviceUISet), m_doApplySettings(true), m_forceSettings(true), m_settings(), @@ -43,10 +42,14 @@ Bladerf1OutputGui::Bladerf1OutputGui(DeviceUISet *deviceUISet, QWidget* parent) m_sampleRate(0), m_lastEngineState(DeviceAPI::StNotStarted) { + m_deviceUISet = deviceUISet; + setAttribute(Qt::WA_DeleteOnClose, true); m_deviceSampleSink = (Bladerf1Output*) m_deviceUISet->m_deviceAPI->getSampleSink(); - ui->setupUi(this); - ui->centerFrequency->setColorMapper(ColorMapper(ColorMapper::GrayGold)); + ui->setupUi(getContents()); + setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); + getContents()->setStyleSheet("#Bladerf1OutputGui { background-color: rgb(64, 64, 64); }"); + m_helpURL = "/plugins/samplesink/bladerf1output/readme.md"; ui->centerFrequency->setColorMapper(ColorMapper(ColorMapper::GrayGold)); ui->centerFrequency->setValueRange(7, BLADERF_FREQUENCY_MIN_XB200/1000, BLADERF_FREQUENCY_MAX/1000); ui->sampleRate->setColorMapper(ColorMapper(ColorMapper::GrayGreenYellow)); @@ -63,10 +66,10 @@ Bladerf1OutputGui::Bladerf1OutputGui(DeviceUISet *deviceUISet, QWidget* parent) connect(&m_statusTimer, SIGNAL(timeout()), this, SLOT(updateStatus())); m_statusTimer.start(500); - CRightClickEnabler *startStopRightClickEnabler = new CRightClickEnabler(ui->startStop); - connect(startStopRightClickEnabler, SIGNAL(rightClick(const QPoint &)), this, SLOT(openDeviceSettingsDialog(const QPoint &))); + connect(this, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(openDeviceSettingsDialog(const QPoint &))); displaySettings(); + makeUIConnections(); connect(&m_inputMessageQueue, SIGNAL(messageEnqueued()), this, SLOT(handleInputMessages()), Qt::QueuedConnection); } @@ -106,6 +109,12 @@ bool Bladerf1OutputGui::deserialize(const QByteArray& data) } } +void Bladerf1OutputGui::resizeEvent(QResizeEvent* size) +{ + adjustSize(); + size->accept(); +} + bool Bladerf1OutputGui::handleMessage(const Message& message) { if (Bladerf1Output::MsgConfigureBladerf1::match(message)) @@ -444,19 +453,34 @@ unsigned int Bladerf1OutputGui::getXb200Index(bool xb_200, bladerf_xb200_path xb void Bladerf1OutputGui::openDeviceSettingsDialog(const QPoint& p) { - BasicDeviceSettingsDialog dialog(this); - dialog.setUseReverseAPI(m_settings.m_useReverseAPI); - dialog.setReverseAPIAddress(m_settings.m_reverseAPIAddress); - dialog.setReverseAPIPort(m_settings.m_reverseAPIPort); - dialog.setReverseAPIDeviceIndex(m_settings.m_reverseAPIDeviceIndex); + if (m_contextMenuType == ContextMenuDeviceSettings) + { + BasicDeviceSettingsDialog dialog(this); + dialog.setUseReverseAPI(m_settings.m_useReverseAPI); + dialog.setReverseAPIAddress(m_settings.m_reverseAPIAddress); + dialog.setReverseAPIPort(m_settings.m_reverseAPIPort); + dialog.setReverseAPIDeviceIndex(m_settings.m_reverseAPIDeviceIndex); - dialog.move(p); - dialog.exec(); + dialog.move(p); + dialog.exec(); - m_settings.m_useReverseAPI = dialog.useReverseAPI(); - m_settings.m_reverseAPIAddress = dialog.getReverseAPIAddress(); - m_settings.m_reverseAPIPort = dialog.getReverseAPIPort(); - m_settings.m_reverseAPIDeviceIndex = dialog.getReverseAPIDeviceIndex(); + m_settings.m_useReverseAPI = dialog.useReverseAPI(); + m_settings.m_reverseAPIAddress = dialog.getReverseAPIAddress(); + m_settings.m_reverseAPIPort = dialog.getReverseAPIPort(); + m_settings.m_reverseAPIDeviceIndex = dialog.getReverseAPIDeviceIndex(); - sendSettings(); + sendSettings(); + } + + resetContextMenuType(); +} + +void Bladerf1OutputGui::makeUIConnections() +{ + QObject::connect(ui->centerFrequency, &ValueDial::changed, this, &Bladerf1OutputGui::on_centerFrequency_changed); + QObject::connect(ui->sampleRate, &ValueDial::changed, this, &Bladerf1OutputGui::on_sampleRate_changed); + QObject::connect(ui->bandwidth, QOverload::of(&QComboBox::currentIndexChanged), this, &Bladerf1OutputGui::on_bandwidth_currentIndexChanged); + QObject::connect(ui->interp, QOverload::of(&QComboBox::currentIndexChanged), this, &Bladerf1OutputGui::on_interp_currentIndexChanged); + QObject::connect(ui->startStop, &ButtonSwitch::toggled, this, &Bladerf1OutputGui::on_startStop_toggled); + QObject::connect(ui->sampleRateMode, &QToolButton::toggled, this, &Bladerf1OutputGui::on_sampleRateMode_toggled); } diff --git a/plugins/samplesink/bladerf1output/bladerf1outputgui.h b/plugins/samplesink/bladerf1output/bladerf1outputgui.h index 36d8312aa..b7689f3f3 100644 --- a/plugins/samplesink/bladerf1output/bladerf1outputgui.h +++ b/plugins/samplesink/bladerf1output/bladerf1outputgui.h @@ -46,10 +46,12 @@ public: bool deserialize(const QByteArray& data); virtual MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; } +protected: + void resizeEvent(QResizeEvent* size); + private: Ui::Bladerf1OutputGui* ui; - DeviceUISet* m_deviceUISet; bool m_doApplySettings; bool m_forceSettings; BladeRF1OutputSettings m_settings; @@ -69,6 +71,7 @@ private: unsigned int getXb200Index(bool xb_200, bladerf_xb200_path xb200Path, bladerf_xb200_filter xb200Filter); void updateSampleRateAndFrequency(); bool handleMessage(const Message& message); + void makeUIConnections(); private slots: void handleInputMessages(); diff --git a/plugins/samplesink/bladerf1output/bladerf1outputgui.ui b/plugins/samplesink/bladerf1output/bladerf1outputgui.ui index d8260c1d4..b63d61509 100644 --- a/plugins/samplesink/bladerf1output/bladerf1outputgui.ui +++ b/plugins/samplesink/bladerf1output/bladerf1outputgui.ui @@ -6,8 +6,8 @@ 0 0 - 310 - 250 + 360 + 159
@@ -18,8 +18,14 @@ - 310 - 250 + 360 + 159 + + + + + 380 + 214 @@ -128,7 +134,7 @@ Liberation Mono - 20 + 16 @@ -548,30 +554,6 @@ - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - - - Qt::Horizontal - - - diff --git a/plugins/samplesink/bladerf1output/readme.md b/plugins/samplesink/bladerf1output/readme.md index 9617d8ca5..8de72b15f 100644 --- a/plugins/samplesink/bladerf1output/readme.md +++ b/plugins/samplesink/bladerf1output/readme.md @@ -37,6 +37,8 @@ The BladeRF Host library is also provided by many Linux distributions (check its

Interface

+The top and bottom bars of the device window are described [here](../../../sdrgui/device/readme.md) + ![BladeRF1 output plugin GUI](../../../doc/img/BladeRF1Output_plugin.png)

1: Start/Stop

diff --git a/plugins/samplesink/bladerf2output/bladerf2outputgui.cpp b/plugins/samplesink/bladerf2output/bladerf2outputgui.cpp index eac2bb5c7..8b2fc5bfd 100644 --- a/plugins/samplesink/bladerf2output/bladerf2outputgui.cpp +++ b/plugins/samplesink/bladerf2output/bladerf2outputgui.cpp @@ -17,13 +17,13 @@ #include #include +#include #include #include "ui_bladerf2outputgui.h" #include "gui/colormapper.h" #include "gui/glspectrum.h" -#include "gui/crightclickenabler.h" #include "gui/basicdevicesettingsdialog.h" #include "dsp/dspengine.h" #include "dsp/dspcommands.h" @@ -35,7 +35,6 @@ BladeRF2OutputGui::BladeRF2OutputGui(DeviceUISet *deviceUISet, QWidget* parent) : DeviceGUI(parent), ui(new Ui::BladeRF2OutputGui), - m_deviceUISet(deviceUISet), m_doApplySettings(true), m_forceSettings(true), m_settings(), @@ -43,12 +42,17 @@ BladeRF2OutputGui::BladeRF2OutputGui(DeviceUISet *deviceUISet, QWidget* parent) m_sampleRate(0), m_lastEngineState(DeviceAPI::StNotStarted) { + m_deviceUISet = deviceUISet; + setAttribute(Qt::WA_DeleteOnClose, true); m_sampleSink = (BladeRF2Output*) m_deviceUISet->m_deviceAPI->getSampleSink(); int max, min, step; float scale; uint64_t f_min, f_max; - ui->setupUi(this); + ui->setupUi(getContents()); + setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); + getContents()->setStyleSheet("#BladeRF2OutputGui { background-color: rgb(64, 64, 64); }"); + m_helpURL = "plugins/samplesink/bladerf2output/readme.md"; ui->centerFrequency->setColorMapper(ColorMapper(ColorMapper::GrayGold)); m_sampleSink->getFrequencyRange(f_min, f_max, step, scale); qDebug("BladeRF2OutputGui::BladeRF2OutputGui: getFrequencyRange: [%lu,%lu] step: %d", f_min, f_max, step); @@ -76,10 +80,10 @@ BladeRF2OutputGui::BladeRF2OutputGui(DeviceUISet *deviceUISet, QWidget* parent) connect(&m_statusTimer, SIGNAL(timeout()), this, SLOT(updateStatus())); m_statusTimer.start(500); - CRightClickEnabler *startStopRightClickEnabler = new CRightClickEnabler(ui->startStop); - connect(startStopRightClickEnabler, SIGNAL(rightClick(const QPoint &)), this, SLOT(openDeviceSettingsDialog(const QPoint &))); + connect(this, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(openDeviceSettingsDialog(const QPoint &))); displaySettings(); + makeUIConnections(); connect(&m_inputMessageQueue, SIGNAL(messageEnqueued()), this, SLOT(handleInputMessages()), Qt::QueuedConnection); m_sampleSink->setMessageQueueToGUI(&m_inputMessageQueue); @@ -120,6 +124,12 @@ bool BladeRF2OutputGui::deserialize(const QByteArray& data) } } +void BladeRF2OutputGui::resizeEvent(QResizeEvent* size) +{ + adjustSize(); + size->accept(); +} + void BladeRF2OutputGui::updateFrequencyLimits() { // values in kHz @@ -421,21 +431,26 @@ void BladeRF2OutputGui::updateStatus() void BladeRF2OutputGui::openDeviceSettingsDialog(const QPoint& p) { - BasicDeviceSettingsDialog dialog(this); - dialog.setUseReverseAPI(m_settings.m_useReverseAPI); - dialog.setReverseAPIAddress(m_settings.m_reverseAPIAddress); - dialog.setReverseAPIPort(m_settings.m_reverseAPIPort); - dialog.setReverseAPIDeviceIndex(m_settings.m_reverseAPIDeviceIndex); + if (m_contextMenuType == ContextMenuDeviceSettings) + { + BasicDeviceSettingsDialog dialog(this); + dialog.setUseReverseAPI(m_settings.m_useReverseAPI); + dialog.setReverseAPIAddress(m_settings.m_reverseAPIAddress); + dialog.setReverseAPIPort(m_settings.m_reverseAPIPort); + dialog.setReverseAPIDeviceIndex(m_settings.m_reverseAPIDeviceIndex); - dialog.move(p); - dialog.exec(); + dialog.move(p); + dialog.exec(); - m_settings.m_useReverseAPI = dialog.useReverseAPI(); - m_settings.m_reverseAPIAddress = dialog.getReverseAPIAddress(); - m_settings.m_reverseAPIPort = dialog.getReverseAPIPort(); - m_settings.m_reverseAPIDeviceIndex = dialog.getReverseAPIDeviceIndex(); + m_settings.m_useReverseAPI = dialog.useReverseAPI(); + m_settings.m_reverseAPIAddress = dialog.getReverseAPIAddress(); + m_settings.m_reverseAPIPort = dialog.getReverseAPIPort(); + m_settings.m_reverseAPIDeviceIndex = dialog.getReverseAPIDeviceIndex(); - sendSettings(); + sendSettings(); + } + + resetContextMenuType(); } float BladeRF2OutputGui::getGainDB(int gainValue) @@ -453,3 +468,17 @@ int BladeRF2OutputGui::getGainValue(float gainDB) // gainDB, m_gainMin, m_gainMax, m_gainStep, gain); return gain; } + +void BladeRF2OutputGui::makeUIConnections() +{ + QObject::connect(ui->centerFrequency, &ValueDial::changed, this, &BladeRF2OutputGui::on_centerFrequency_changed); + QObject::connect(ui->LOppm, &QSlider::valueChanged, this, &BladeRF2OutputGui::on_LOppm_valueChanged); + QObject::connect(ui->biasTee, &ButtonSwitch::toggled, this, &BladeRF2OutputGui::on_biasTee_toggled); + QObject::connect(ui->sampleRate, &ValueDial::changed, this, &BladeRF2OutputGui::on_sampleRate_changed); + QObject::connect(ui->bandwidth, &ValueDial::changed, this, &BladeRF2OutputGui::on_bandwidth_changed); + QObject::connect(ui->interp, QOverload::of(&QComboBox::currentIndexChanged), this, &BladeRF2OutputGui::on_interp_currentIndexChanged); + QObject::connect(ui->gain, &QSlider::valueChanged, this, &BladeRF2OutputGui::on_gain_valueChanged); + QObject::connect(ui->startStop, &ButtonSwitch::toggled, this, &BladeRF2OutputGui::on_startStop_toggled); + QObject::connect(ui->transverter, &TransverterButton::clicked, this, &BladeRF2OutputGui::on_transverter_clicked); + QObject::connect(ui->sampleRateMode, &QToolButton::toggled, this, &BladeRF2OutputGui::on_sampleRateMode_toggled); +} diff --git a/plugins/samplesink/bladerf2output/bladerf2outputgui.h b/plugins/samplesink/bladerf2output/bladerf2outputgui.h index 19e382f34..345754dc3 100644 --- a/plugins/samplesink/bladerf2output/bladerf2outputgui.h +++ b/plugins/samplesink/bladerf2output/bladerf2outputgui.h @@ -47,10 +47,12 @@ public: virtual MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; } virtual bool handleMessage(const Message& message); +protected: + void resizeEvent(QResizeEvent* size); + private: Ui::BladeRF2OutputGui* ui; - DeviceUISet* m_deviceUISet; bool m_doApplySettings; bool m_forceSettings; BladeRF2OutputSettings m_settings; @@ -76,6 +78,7 @@ private: void setCenterFrequencySetting(uint64_t kHzValue); float getGainDB(int gainValue); int getGainValue(float gainDB); + void makeUIConnections(); private slots: void handleInputMessages(); diff --git a/plugins/samplesink/bladerf2output/bladerf2outputgui.ui b/plugins/samplesink/bladerf2output/bladerf2outputgui.ui index a589a1d9c..c53e8cbd2 100644 --- a/plugins/samplesink/bladerf2output/bladerf2outputgui.ui +++ b/plugins/samplesink/bladerf2output/bladerf2outputgui.ui @@ -6,20 +6,26 @@ 0 0 - 350 - 200 + 360 + 165
- + 0 0 - 350 - 200 + 360 + 165 + + + + + 380 + 202 @@ -128,7 +134,7 @@ Liberation Mono - 20 + 16 @@ -487,30 +493,6 @@ - - - - Qt::Horizontal - - - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - diff --git a/plugins/samplesink/bladerf2output/readme.md b/plugins/samplesink/bladerf2output/readme.md index 661dfa507..5288003dd 100644 --- a/plugins/samplesink/bladerf2output/readme.md +++ b/plugins/samplesink/bladerf2output/readme.md @@ -14,6 +14,8 @@ The BladeRF Host library is also provided by many Linux distributions (check its

Interface

+The top and bottom bars of the device window are described [here](../../../sdrgui/device/readme.md) + ![BladeRF2 output plugin GUI](../../../doc/img/BladeRF2Output_plugin.png)

1: Start/Stop

diff --git a/plugins/samplesink/fileoutput/fileoutputgui.cpp b/plugins/samplesink/fileoutput/fileoutputgui.cpp index 3a06d16e0..48a93316f 100644 --- a/plugins/samplesink/fileoutput/fileoutputgui.cpp +++ b/plugins/samplesink/fileoutput/fileoutputgui.cpp @@ -22,11 +22,13 @@ #include #include #include +#include #include "ui_fileoutputgui.h" #include "plugin/pluginapi.h" #include "gui/colormapper.h" #include "gui/glspectrum.h" +#include "gui/basicdevicesettingsdialog.h" #include "dsp/dspengine.h" #include "dsp/dspcommands.h" @@ -39,7 +41,6 @@ FileOutputGui::FileOutputGui(DeviceUISet *deviceUISet, QWidget* parent) : DeviceGUI(parent), ui(new Ui::FileOutputGui), - m_deviceUISet(deviceUISet), m_doApplySettings(true), m_forceSettings(true), m_settings(), @@ -51,7 +52,13 @@ FileOutputGui::FileOutputGui(DeviceUISet *deviceUISet, QWidget* parent) : m_tickCount(0), m_lastEngineState(DeviceAPI::StNotStarted) { - ui->setupUi(this); + m_deviceUISet = deviceUISet; + setAttribute(Qt::WA_DeleteOnClose, true); + ui->setupUi(getContents()); + setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); + getContents()->setStyleSheet("#FileOutputGui { background-color: rgb(64, 64, 64); }"); + m_helpURL = "plugins/samplesink/fileoutput/readme.md"; + ui->centerFrequency->setColorMapper(ColorMapper(ColorMapper::GrayGold)); ui->centerFrequency->setColorMapper(ColorMapper(ColorMapper::GrayGold)); ui->centerFrequency->setValueRange(7, 0, pow(10,7)); @@ -67,9 +74,11 @@ FileOutputGui::FileOutputGui(DeviceUISet *deviceUISet, QWidget* parent) : m_statusTimer.start(500); displaySettings(); + makeUIConnections(); m_deviceSampleSink = (FileOutput*) m_deviceUISet->m_deviceAPI->getSampleSink(); connect(&m_inputMessageQueue, SIGNAL(messageEnqueued()), this, SLOT(handleInputMessages()), Qt::QueuedConnection); + connect(this, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(openDeviceSettingsDialog(const QPoint &))); } FileOutputGui::~FileOutputGui() @@ -107,6 +116,12 @@ bool FileOutputGui::deserialize(const QByteArray& data) } } +void FileOutputGui::resizeEvent(QResizeEvent* size) +{ + adjustSize(); + size->accept(); +} + bool FileOutputGui::handleMessage(const Message& message) { if (FileOutput::MsgConfigureFileOutput::match(message)) @@ -316,3 +331,36 @@ void FileOutputGui::tick() m_deviceSampleSink->getInputMessageQueue()->push(message); } } + +void FileOutputGui::openDeviceSettingsDialog(const QPoint& p) +{ + if (m_contextMenuType == ContextMenuDeviceSettings) + { + BasicDeviceSettingsDialog dialog(this); + dialog.setUseReverseAPI(m_settings.m_useReverseAPI); + dialog.setReverseAPIAddress(m_settings.m_reverseAPIAddress); + dialog.setReverseAPIPort(m_settings.m_reverseAPIPort); + dialog.setReverseAPIDeviceIndex(m_settings.m_reverseAPIDeviceIndex); + + dialog.move(p); + dialog.exec(); + + m_settings.m_useReverseAPI = dialog.useReverseAPI(); + m_settings.m_reverseAPIAddress = dialog.getReverseAPIAddress(); + m_settings.m_reverseAPIPort = dialog.getReverseAPIPort(); + m_settings.m_reverseAPIDeviceIndex = dialog.getReverseAPIDeviceIndex(); + + sendSettings(); + } + + resetContextMenuType(); +} + +void FileOutputGui::makeUIConnections() +{ + QObject::connect(ui->centerFrequency, &ValueDial::changed, this, &FileOutputGui::on_centerFrequency_changed); + QObject::connect(ui->sampleRate, &ValueDial::changed, this, &FileOutputGui::on_sampleRate_changed); + QObject::connect(ui->startStop, &ButtonSwitch::toggled, this, &FileOutputGui::on_startStop_toggled); + QObject::connect(ui->showFileDialog, &QPushButton::clicked, this, &FileOutputGui::on_showFileDialog_clicked); + QObject::connect(ui->interp, QOverload::of(&QComboBox::currentIndexChanged), this, &FileOutputGui::on_interp_currentIndexChanged); +} diff --git a/plugins/samplesink/fileoutput/fileoutputgui.h b/plugins/samplesink/fileoutput/fileoutputgui.h index 0b8061bbb..f7ca4da87 100644 --- a/plugins/samplesink/fileoutput/fileoutputgui.h +++ b/plugins/samplesink/fileoutput/fileoutputgui.h @@ -48,10 +48,12 @@ public: bool deserialize(const QByteArray& data); virtual MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; } +protected: + void resizeEvent(QResizeEvent* size); + private: Ui::FileOutputGui* ui; - DeviceUISet* m_deviceUISet; bool m_doApplySettings; bool m_forceSettings; FileOutputSettings m_settings; @@ -76,6 +78,7 @@ private: void updateWithStreamTime(); void updateSampleRateAndFrequency(); bool handleMessage(const Message& message); + void makeUIConnections(); private slots: void handleInputMessages(); @@ -84,6 +87,7 @@ private slots: void on_startStop_toggled(bool checked); void on_showFileDialog_clicked(bool checked); void on_interp_currentIndexChanged(int index); + void openDeviceSettingsDialog(const QPoint& p); void updateHardware(); void updateStatus(); void tick(); diff --git a/plugins/samplesink/fileoutput/fileoutputgui.ui b/plugins/samplesink/fileoutput/fileoutputgui.ui index 6deafee04..c36dbb4e6 100644 --- a/plugins/samplesink/fileoutput/fileoutputgui.ui +++ b/plugins/samplesink/fileoutput/fileoutputgui.ui @@ -6,20 +6,26 @@ 0 0 - 350 - 190 + 360 + 126
- + 0 0 - 350 - 190 + 360 + 126 + + + + + 380 + 144 @@ -131,7 +137,7 @@ Liberation Mono - 20 + 16 @@ -364,23 +370,6 @@ - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - diff --git a/plugins/samplesink/fileoutput/fileoutputsettings.h b/plugins/samplesink/fileoutput/fileoutputsettings.h index 3b6b666c4..91b0df057 100644 --- a/plugins/samplesink/fileoutput/fileoutputsettings.h +++ b/plugins/samplesink/fileoutput/fileoutputsettings.h @@ -18,8 +18,6 @@ #ifndef PLUGINS_SAMPLESINK_FILEOUTPUT_FILEOUTPUTSETTINGS_H_ #define PLUGINS_SAMPLESINK_FILEOUTPUT_FILEOUTPUTSETTINGS_H_ -#include - struct FileOutputSettings { quint64 m_centerFrequency; quint64 m_sampleRate; diff --git a/plugins/samplesink/fileoutput/readme.md b/plugins/samplesink/fileoutput/readme.md index a54dcdf63..6ba050a36 100644 --- a/plugins/samplesink/fileoutput/readme.md +++ b/plugins/samplesink/fileoutput/readme.md @@ -18,6 +18,8 @@ The plugin is always built.

Interface

+The top and bottom bars of the device window are described [here](../../../sdrgui/device/readme.md) + ![File output plugin GUI](../../../doc/img/FileOutput_plugin.png)

1: Start/Stop

diff --git a/plugins/samplesink/hackrfoutput/hackrfoutputgui.cpp b/plugins/samplesink/hackrfoutput/hackrfoutputgui.cpp index a7453bea3..b4be2bdb8 100644 --- a/plugins/samplesink/hackrfoutput/hackrfoutputgui.cpp +++ b/plugins/samplesink/hackrfoutput/hackrfoutputgui.cpp @@ -17,12 +17,12 @@ #include #include +#include #include #include "gui/colormapper.h" #include "gui/glspectrum.h" -#include "gui/crightclickenabler.h" #include "gui/basicdevicesettingsdialog.h" #include "dsp/dspengine.h" #include "dsp/dspcommands.h" @@ -37,7 +37,6 @@ HackRFOutputGui::HackRFOutputGui(DeviceUISet *deviceUISet, QWidget* parent) : DeviceGUI(parent), ui(new Ui::HackRFOutputGui), - m_deviceUISet(deviceUISet), m_forceSettings(true), m_settings(), m_sampleRateMode(true), @@ -45,9 +44,14 @@ HackRFOutputGui::HackRFOutputGui(DeviceUISet *deviceUISet, QWidget* parent) : m_lastEngineState(DeviceAPI::StNotStarted), m_doApplySettings(true) { + m_deviceUISet = deviceUISet; + setAttribute(Qt::WA_DeleteOnClose, true); m_deviceSampleSink = (HackRFOutput*) m_deviceUISet->m_deviceAPI->getSampleSink(); - ui->setupUi(this); + ui->setupUi(getContents()); + setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); + getContents()->setStyleSheet("#HackRFOutputGui { background-color: rgb(64, 64, 64); }"); + m_helpURL = "plugins/samplesink/hackrfoutput/readme.md"; ui->centerFrequency->setColorMapper(ColorMapper(ColorMapper::GrayGold)); ui->centerFrequency->setValueRange(7, 0U, 7250000U); @@ -58,12 +62,12 @@ HackRFOutputGui::HackRFOutputGui(DeviceUISet *deviceUISet, QWidget* parent) : connect(&m_statusTimer, SIGNAL(timeout()), this, SLOT(updateStatus())); m_statusTimer.start(500); - CRightClickEnabler *startStopRightClickEnabler = new CRightClickEnabler(ui->startStop); - connect(startStopRightClickEnabler, SIGNAL(rightClick(const QPoint &)), this, SLOT(openDeviceSettingsDialog(const QPoint &))); + connect(this, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(openDeviceSettingsDialog(const QPoint &))); displaySettings(); displayBandwidths(); sendSettings(); + makeUIConnections(); connect(&m_inputMessageQueue, SIGNAL(messageEnqueued()), this, SLOT(handleInputMessages()), Qt::QueuedConnection); } @@ -106,6 +110,12 @@ bool HackRFOutputGui::deserialize(const QByteArray& data) } } +void HackRFOutputGui::resizeEvent(QResizeEvent* size) +{ + adjustSize(); + size->accept(); +} + void HackRFOutputGui::blockApplySettings(bool block) { m_doApplySettings = !block; @@ -438,19 +448,40 @@ void HackRFOutputGui::updateStatus() void HackRFOutputGui::openDeviceSettingsDialog(const QPoint& p) { - BasicDeviceSettingsDialog dialog(this); - dialog.setUseReverseAPI(m_settings.m_useReverseAPI); - dialog.setReverseAPIAddress(m_settings.m_reverseAPIAddress); - dialog.setReverseAPIPort(m_settings.m_reverseAPIPort); - dialog.setReverseAPIDeviceIndex(m_settings.m_reverseAPIDeviceIndex); + if (m_contextMenuType == ContextMenuDeviceSettings) + { + BasicDeviceSettingsDialog dialog(this); + dialog.setUseReverseAPI(m_settings.m_useReverseAPI); + dialog.setReverseAPIAddress(m_settings.m_reverseAPIAddress); + dialog.setReverseAPIPort(m_settings.m_reverseAPIPort); + dialog.setReverseAPIDeviceIndex(m_settings.m_reverseAPIDeviceIndex); - dialog.move(p); - dialog.exec(); + dialog.move(p); + dialog.exec(); - m_settings.m_useReverseAPI = dialog.useReverseAPI(); - m_settings.m_reverseAPIAddress = dialog.getReverseAPIAddress(); - m_settings.m_reverseAPIPort = dialog.getReverseAPIPort(); - m_settings.m_reverseAPIDeviceIndex = dialog.getReverseAPIDeviceIndex(); + m_settings.m_useReverseAPI = dialog.useReverseAPI(); + m_settings.m_reverseAPIAddress = dialog.getReverseAPIAddress(); + m_settings.m_reverseAPIPort = dialog.getReverseAPIPort(); + m_settings.m_reverseAPIDeviceIndex = dialog.getReverseAPIDeviceIndex(); - sendSettings(); + sendSettings(); + } + + resetContextMenuType(); +} + +void HackRFOutputGui::makeUIConnections() +{ + QObject::connect(ui->centerFrequency, &ValueDial::changed, this, &HackRFOutputGui::on_centerFrequency_changed); + QObject::connect(ui->sampleRate, &ValueDial::changed, this, &HackRFOutputGui::on_sampleRate_changed); + QObject::connect(ui->LOppm, &QSlider::valueChanged, this, &HackRFOutputGui::on_LOppm_valueChanged); + QObject::connect(ui->biasT, &QCheckBox::stateChanged, this, &HackRFOutputGui::on_biasT_stateChanged); + QObject::connect(ui->interp, QOverload::of(&QComboBox::currentIndexChanged), this, &HackRFOutputGui::on_interp_currentIndexChanged); + QObject::connect(ui->fcPos, QOverload::of(&QComboBox::currentIndexChanged), this, &HackRFOutputGui::on_fcPos_currentIndexChanged); + QObject::connect(ui->lnaExt, &QCheckBox::stateChanged, this, &HackRFOutputGui::on_lnaExt_stateChanged); + QObject::connect(ui->bbFilter, QOverload::of(&QComboBox::currentIndexChanged), this, &HackRFOutputGui::on_bbFilter_currentIndexChanged); + QObject::connect(ui->txvga, &QSlider::valueChanged, this, &HackRFOutputGui::on_txvga_valueChanged); + QObject::connect(ui->startStop, &ButtonSwitch::toggled, this, &HackRFOutputGui::on_startStop_toggled); + QObject::connect(ui->sampleRateMode, &QToolButton::toggled, this, &HackRFOutputGui::on_sampleRateMode_toggled); + QObject::connect(ui->transverter, &TransverterButton::clicked, this, &HackRFOutputGui::on_transverter_clicked); } diff --git a/plugins/samplesink/hackrfoutput/hackrfoutputgui.h b/plugins/samplesink/hackrfoutput/hackrfoutputgui.h index 0774a134a..0541ff791 100644 --- a/plugins/samplesink/hackrfoutput/hackrfoutputgui.h +++ b/plugins/samplesink/hackrfoutput/hackrfoutputgui.h @@ -56,10 +56,12 @@ public: bool deserialize(const QByteArray& data); virtual MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; } +protected: + void resizeEvent(QResizeEvent* size); + private: Ui::HackRFOutputGui* ui; - DeviceUISet* m_deviceUISet; bool m_forceSettings; HackRFOutputSettings m_settings; bool m_sampleRateMode; //!< true: device, false: base band sample rate update mode @@ -81,6 +83,7 @@ private: void updateFrequencyLimits(); void blockApplySettings(bool block); bool handleMessage(const Message& message); + void makeUIConnections(); private slots: void handleInputMessages(); diff --git a/plugins/samplesink/hackrfoutput/hackrfoutputgui.ui b/plugins/samplesink/hackrfoutput/hackrfoutputgui.ui index 8b9e1e455..72924fe1d 100644 --- a/plugins/samplesink/hackrfoutput/hackrfoutputgui.ui +++ b/plugins/samplesink/hackrfoutput/hackrfoutputgui.ui @@ -6,20 +6,26 @@ 0 0 - 320 - 200 + 360 + 174
- + 0 0 - 320 - 200 + 360 + 174 + + + + + 380 + 207 @@ -33,7 +39,7 @@ - 3 + 2 2 @@ -131,7 +137,7 @@ Liberation Mono - 20 + 16 @@ -537,23 +543,6 @@ - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - diff --git a/plugins/samplesink/hackrfoutput/readme.md b/plugins/samplesink/hackrfoutput/readme.md index 512e18488..898e7b3e0 100644 --- a/plugins/samplesink/hackrfoutput/readme.md +++ b/plugins/samplesink/hackrfoutput/readme.md @@ -6,6 +6,8 @@ This output sample sink plugin sends its samples to a [HackRF device](https://gr

Interface

+The top and bottom bars of the device window are described [here](../../../sdrgui/device/readme.md) + ![HackRF output plugin GUI](../../../doc/img/HackRFOutput_plugin.png)

1: Start/Stop

@@ -111,4 +113,4 @@ When a device set for the same physical device is present the device center freq When the center frequency position Fc (control 9) is set to center (Cen) in both Tx and Rx the actual frequency of reception and transmission are the same. -In other cases for both frequencies to match you have to set the same sample rate and Fc position (either Inf or Sup) in the Tx and Rx. \ No newline at end of file +In other cases for both frequencies to match you have to set the same sample rate and Fc position (either Inf or Sup) in the Tx and Rx. diff --git a/plugins/samplesink/limesdroutput/limesdroutputgui.cpp b/plugins/samplesink/limesdroutput/limesdroutputgui.cpp index 7bca77a1b..77135e5ae 100644 --- a/plugins/samplesink/limesdroutput/limesdroutputgui.cpp +++ b/plugins/samplesink/limesdroutput/limesdroutputgui.cpp @@ -17,11 +17,11 @@ #include #include +#include #include "ui_limesdroutputgui.h" #include "gui/colormapper.h" #include "gui/glspectrum.h" -#include "gui/crightclickenabler.h" #include "gui/basicdevicesettingsdialog.h" #include "dsp/dspengine.h" #include "dsp/dspcommands.h" @@ -32,7 +32,6 @@ LimeSDROutputGUI::LimeSDROutputGUI(DeviceUISet *deviceUISet, QWidget* parent) : DeviceGUI(parent), ui(new Ui::LimeSDROutputGUI), - m_deviceUISet(deviceUISet), m_settings(), m_sampleRateMode(true), m_sampleRate(0), @@ -42,9 +41,14 @@ LimeSDROutputGUI::LimeSDROutputGUI(DeviceUISet *deviceUISet, QWidget* parent) : m_statusCounter(0), m_deviceStatusCounter(0) { + m_deviceUISet = deviceUISet; + setAttribute(Qt::WA_DeleteOnClose, true); m_limeSDROutput = (LimeSDROutput*) m_deviceUISet->m_deviceAPI->getSampleSink(); - ui->setupUi(this); + ui->setupUi(getContents()); + setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); + getContents()->setStyleSheet("#LimeSDROutputGUI { background-color: rgb(64, 64, 64); }"); + m_helpURL = "plugins/samplesink/limesdroutput/readme.md"; float minF, maxF; @@ -89,11 +93,10 @@ LimeSDROutputGUI::LimeSDROutputGUI(DeviceUISet *deviceUISet, QWidget* parent) : sprintf(recFileNameCStr, "test_%d.sdriq", m_deviceUISet->m_deviceAPI->getDeviceUID()); connect(&m_inputMessageQueue, SIGNAL(messageEnqueued()), this, SLOT(handleInputMessages()), Qt::QueuedConnection); - - CRightClickEnabler *startStopRightClickEnabler = new CRightClickEnabler(ui->startStop); - connect(startStopRightClickEnabler, SIGNAL(rightClick(const QPoint &)), this, SLOT(openDeviceSettingsDialog(const QPoint &))); + connect(this, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(openDeviceSettingsDialog(const QPoint &))); sendSettings(); + makeUIConnections(); } LimeSDROutputGUI::~LimeSDROutputGUI() @@ -134,6 +137,12 @@ bool LimeSDROutputGUI::deserialize(const QByteArray& data) } } +void LimeSDROutputGUI::resizeEvent(QResizeEvent* size) +{ + adjustSize(); + size->accept(); +} + void LimeSDROutputGUI::updateFrequencyLimits() { // values in kHz @@ -614,19 +623,43 @@ void LimeSDROutputGUI::on_sampleRateMode_toggled(bool checked) void LimeSDROutputGUI::openDeviceSettingsDialog(const QPoint& p) { - BasicDeviceSettingsDialog dialog(this); - dialog.setUseReverseAPI(m_settings.m_useReverseAPI); - dialog.setReverseAPIAddress(m_settings.m_reverseAPIAddress); - dialog.setReverseAPIPort(m_settings.m_reverseAPIPort); - dialog.setReverseAPIDeviceIndex(m_settings.m_reverseAPIDeviceIndex); + if (m_contextMenuType == ContextMenuDeviceSettings) + { + BasicDeviceSettingsDialog dialog(this); + dialog.setUseReverseAPI(m_settings.m_useReverseAPI); + dialog.setReverseAPIAddress(m_settings.m_reverseAPIAddress); + dialog.setReverseAPIPort(m_settings.m_reverseAPIPort); + dialog.setReverseAPIDeviceIndex(m_settings.m_reverseAPIDeviceIndex); - dialog.move(p); - dialog.exec(); + dialog.move(p); + dialog.exec(); - m_settings.m_useReverseAPI = dialog.useReverseAPI(); - m_settings.m_reverseAPIAddress = dialog.getReverseAPIAddress(); - m_settings.m_reverseAPIPort = dialog.getReverseAPIPort(); - m_settings.m_reverseAPIDeviceIndex = dialog.getReverseAPIDeviceIndex(); + m_settings.m_useReverseAPI = dialog.useReverseAPI(); + m_settings.m_reverseAPIAddress = dialog.getReverseAPIAddress(); + m_settings.m_reverseAPIPort = dialog.getReverseAPIPort(); + m_settings.m_reverseAPIDeviceIndex = dialog.getReverseAPIDeviceIndex(); - sendSettings(); + sendSettings(); + } + + resetContextMenuType(); +} + +void LimeSDROutputGUI::makeUIConnections() +{ + QObject::connect(ui->startStop, &ButtonSwitch::toggled, this, &LimeSDROutputGUI::on_startStop_toggled); + QObject::connect(ui->centerFrequency, &ValueDial::changed, this, &LimeSDROutputGUI::on_centerFrequency_changed); + QObject::connect(ui->ncoFrequency, &ValueDialZ::changed, this, &LimeSDROutputGUI::on_ncoFrequency_changed); + QObject::connect(ui->ncoEnable, &ButtonSwitch::toggled, this, &LimeSDROutputGUI::on_ncoEnable_toggled); + QObject::connect(ui->sampleRate, &ValueDial::changed, this, &LimeSDROutputGUI::on_sampleRate_changed); + QObject::connect(ui->hwInterp, QOverload::of(&QComboBox::currentIndexChanged), this, &LimeSDROutputGUI::on_hwInterp_currentIndexChanged); + QObject::connect(ui->swInterp, QOverload::of(&QComboBox::currentIndexChanged), this, &LimeSDROutputGUI::on_swInterp_currentIndexChanged); + QObject::connect(ui->lpf, &ValueDial::changed, this, &LimeSDROutputGUI::on_lpf_changed); + QObject::connect(ui->lpFIREnable, &ButtonSwitch::toggled, this, &LimeSDROutputGUI::on_lpFIREnable_toggled); + QObject::connect(ui->lpFIR, &ValueDial::changed, this, &LimeSDROutputGUI::on_lpFIR_changed); + QObject::connect(ui->gain, &QSlider::valueChanged, this, &LimeSDROutputGUI::on_gain_valueChanged); + QObject::connect(ui->antenna, QOverload::of(&QComboBox::currentIndexChanged), this, &LimeSDROutputGUI::on_antenna_currentIndexChanged); + QObject::connect(ui->extClock, &ExternalClockButton::clicked, this, &LimeSDROutputGUI::on_extClock_clicked); + QObject::connect(ui->transverter, &TransverterButton::clicked, this, &LimeSDROutputGUI::on_transverter_clicked); + QObject::connect(ui->sampleRateMode, &QToolButton::toggled, this, &LimeSDROutputGUI::on_sampleRateMode_toggled); } diff --git a/plugins/samplesink/limesdroutput/limesdroutputgui.h b/plugins/samplesink/limesdroutput/limesdroutputgui.h index 5093b7e80..71831b414 100644 --- a/plugins/samplesink/limesdroutput/limesdroutputgui.h +++ b/plugins/samplesink/limesdroutput/limesdroutputgui.h @@ -46,10 +46,12 @@ public: bool deserialize(const QByteArray& data); virtual MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; } +protected: + void resizeEvent(QResizeEvent* size); + private: Ui::LimeSDROutputGUI* ui; - DeviceUISet* m_deviceUISet; LimeSDROutput* m_limeSDROutput; //!< Same object as above but gives easy access to LimeSDROutput methods and attributes that are used intensively LimeSDROutputSettings m_settings; bool m_sampleRateMode; //!< true: device, false: base band sample rate update mode @@ -75,6 +77,7 @@ private: void updateFrequencyLimits(); void blockApplySettings(bool block); bool handleMessage(const Message& message); + void makeUIConnections(); private slots: void handleInputMessages(); diff --git a/plugins/samplesink/limesdroutput/limesdroutputgui.ui b/plugins/samplesink/limesdroutput/limesdroutputgui.ui index 7fe2c2758..91ff5d9cc 100644 --- a/plugins/samplesink/limesdroutput/limesdroutputgui.ui +++ b/plugins/samplesink/limesdroutput/limesdroutputgui.ui @@ -7,11 +7,11 @@ 0 0 360 - 290 + 209
- + 0 0 @@ -19,7 +19,13 @@ 360 - 290 + 209 + + + + + 380 + 264 @@ -128,7 +134,7 @@ Liberation Mono - 20 + 16 @@ -854,6 +860,7 @@ + Ubuntu 8 @@ -924,30 +931,6 @@ QToolTip{background-color: white; color: black;} - - - - Qt::Horizontal - - - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - @@ -962,11 +945,6 @@ QToolTip{background-color: white; color: black;} QToolButton
gui/buttonswitch.h
- - ExternalClockButton - QToolButton -
gui/externalclockbutton.h
-
ValueDialZ QWidget @@ -978,6 +956,11 @@ QToolTip{background-color: white; color: black;} QPushButton
gui/transverterbutton.h
+ + ExternalClockButton + QToolButton +
gui/externalclockbutton.h
+
diff --git a/plugins/samplesink/limesdroutput/readme.md b/plugins/samplesink/limesdroutput/readme.md index eecccd764..71dbc87e7 100644 --- a/plugins/samplesink/limesdroutput/readme.md +++ b/plugins/samplesink/limesdroutput/readme.md @@ -32,6 +32,8 @@ Then add the following defines on `cmake` command line:

Interface

+The top and bottom bars of the device window are described [here](../../../sdrgui/device/readme.md) + ![LimeSDR output plugin GUI](../../../doc/img/LimeSDROutput_plugin.png)

1: Start/Stop

diff --git a/plugins/samplesink/localoutput/localoutputgui.cpp b/plugins/samplesink/localoutput/localoutputgui.cpp index 70619e7c4..054c2a1fc 100644 --- a/plugins/samplesink/localoutput/localoutputgui.cpp +++ b/plugins/samplesink/localoutput/localoutputgui.cpp @@ -28,11 +28,11 @@ #include #include #include +#include #include "ui_localoutputgui.h" #include "gui/colormapper.h" #include "gui/glspectrum.h" -#include "gui/crightclickenabler.h" #include "gui/basicdevicesettingsdialog.h" #include "dsp/dspengine.h" #include "dsp/dspcommands.h" @@ -46,7 +46,6 @@ LocalOutputGui::LocalOutputGui(DeviceUISet *deviceUISet, QWidget* parent) : DeviceGUI(parent), ui(new Ui::LocalOutputGui), - m_deviceUISet(deviceUISet), m_settings(), m_sampleSink(0), m_acquisition(false), @@ -58,13 +57,17 @@ LocalOutputGui::LocalOutputGui(DeviceUISet *deviceUISet, QWidget* parent) : m_doApplySettings(true), m_forceSettings(true) { + m_deviceUISet = deviceUISet; + setAttribute(Qt::WA_DeleteOnClose, true); m_paletteGreenText.setColor(QPalette::WindowText, Qt::green); m_paletteWhiteText.setColor(QPalette::WindowText, Qt::white); - ui->setupUi(this); + ui->setupUi(getContents()); + setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); + getContents()->setStyleSheet("#LocalOutputGui { background-color: rgb(64, 64, 64); }"); + m_helpURL = "plugins/samplesink/localoutput/readme.md"; - CRightClickEnabler *startStopRightClickEnabler = new CRightClickEnabler(ui->startStop); - connect(startStopRightClickEnabler, SIGNAL(rightClick(const QPoint &)), this, SLOT(openDeviceSettingsDialog(const QPoint &))); + connect(this, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(openDeviceSettingsDialog(const QPoint &))); displaySettings(); @@ -79,6 +82,7 @@ LocalOutputGui::LocalOutputGui(DeviceUISet *deviceUISet, QWidget* parent) : m_forceSettings = true; sendSettings(); + makeUIConnections(); } LocalOutputGui::~LocalOutputGui() @@ -127,6 +131,12 @@ bool LocalOutputGui::deserialize(const QByteArray& data) } } +void LocalOutputGui::resizeEvent(QResizeEvent* size) +{ + adjustSize(); + size->accept(); +} + bool LocalOutputGui::handleMessage(const Message& message) { if (LocalOutput::MsgConfigureLocalOutput::match(message)) @@ -277,19 +287,29 @@ void LocalOutputGui::updateStatus() void LocalOutputGui::openDeviceSettingsDialog(const QPoint& p) { - BasicDeviceSettingsDialog dialog(this); - dialog.setUseReverseAPI(m_settings.m_useReverseAPI); - dialog.setReverseAPIAddress(m_settings.m_reverseAPIAddress); - dialog.setReverseAPIPort(m_settings.m_reverseAPIPort); - dialog.setReverseAPIDeviceIndex(m_settings.m_reverseAPIDeviceIndex); + if (m_contextMenuType == ContextMenuDeviceSettings) + { + BasicDeviceSettingsDialog dialog(this); + dialog.setUseReverseAPI(m_settings.m_useReverseAPI); + dialog.setReverseAPIAddress(m_settings.m_reverseAPIAddress); + dialog.setReverseAPIPort(m_settings.m_reverseAPIPort); + dialog.setReverseAPIDeviceIndex(m_settings.m_reverseAPIDeviceIndex); - dialog.move(p); - dialog.exec(); + dialog.move(p); + dialog.exec(); - m_settings.m_useReverseAPI = dialog.useReverseAPI(); - m_settings.m_reverseAPIAddress = dialog.getReverseAPIAddress(); - m_settings.m_reverseAPIPort = dialog.getReverseAPIPort(); - m_settings.m_reverseAPIDeviceIndex = dialog.getReverseAPIDeviceIndex(); + m_settings.m_useReverseAPI = dialog.useReverseAPI(); + m_settings.m_reverseAPIAddress = dialog.getReverseAPIAddress(); + m_settings.m_reverseAPIPort = dialog.getReverseAPIPort(); + m_settings.m_reverseAPIDeviceIndex = dialog.getReverseAPIDeviceIndex(); - sendSettings(); + sendSettings(); + } + + resetContextMenuType(); +} + +void LocalOutputGui::makeUIConnections() +{ + QObject::connect(ui->startStop, &ButtonSwitch::toggled, this, &LocalOutputGui::on_startStop_toggled); } diff --git a/plugins/samplesink/localoutput/localoutputgui.h b/plugins/samplesink/localoutput/localoutputgui.h index f9d27e8f4..9c2e46252 100644 --- a/plugins/samplesink/localoutput/localoutputgui.h +++ b/plugins/samplesink/localoutput/localoutputgui.h @@ -47,10 +47,12 @@ public: bool deserialize(const QByteArray& data); virtual MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; } +protected: + void resizeEvent(QResizeEvent* size); + private: Ui::LocalOutputGui* ui; - DeviceUISet* m_deviceUISet; LocalOutputSettings m_settings; //!< current settings LocalOutput* m_sampleSink; bool m_acquisition; @@ -75,6 +77,7 @@ private: void sendSettings(); void updateSampleRateAndFrequency(); bool handleMessage(const Message& message); + void makeUIConnections(); private slots: void handleInputMessages(); diff --git a/plugins/samplesink/localoutput/localoutputgui.ui b/plugins/samplesink/localoutput/localoutputgui.ui index 66467b17d..4d03c6d63 100644 --- a/plugins/samplesink/localoutput/localoutputgui.ui +++ b/plugins/samplesink/localoutput/localoutputgui.ui @@ -7,13 +7,25 @@ 0 0 360 - 80 + 47
+ + + 0 + 0 + + 360 - 80 + 47 + + + + + 380 + 68 @@ -152,30 +164,6 @@ - - - - Qt::Horizontal - - - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - diff --git a/plugins/samplesink/localoutput/localoutputsettings.cpp b/plugins/samplesink/localoutput/localoutputsettings.cpp index 226bfd807..1b4bfe3cf 100644 --- a/plugins/samplesink/localoutput/localoutputsettings.cpp +++ b/plugins/samplesink/localoutput/localoutputsettings.cpp @@ -67,6 +67,7 @@ bool LocalOutputSettings::deserialize(const QByteArray& data) d.readU32(6, &uintval, 0); m_reverseAPIDeviceIndex = uintval > 99 ? 99 : uintval; + return true; } else diff --git a/plugins/samplesink/localoutput/readme.md b/plugins/samplesink/localoutput/readme.md index fedd3fcfd..796ec7f2a 100644 --- a/plugins/samplesink/localoutput/readme.md +++ b/plugins/samplesink/localoutput/readme.md @@ -6,6 +6,8 @@ This output sample sink plugin sends its samples to a Local Source channel in an

Interface

+The top and bottom bars of the device window are described [here](../../../sdrgui/device/readme.md) + ![SDR Local output plugin GUI](../../../doc/img/LocalOutput_plugin.png)

1: Start/Stop

diff --git a/plugins/samplesink/plutosdroutput/plutosdroutputgui.cpp b/plugins/samplesink/plutosdroutput/plutosdroutputgui.cpp index be0b3e59d..29a4d85b9 100644 --- a/plugins/samplesink/plutosdroutput/plutosdroutputgui.cpp +++ b/plugins/samplesink/plutosdroutput/plutosdroutputgui.cpp @@ -18,11 +18,11 @@ #include #include #include +#include #include "dsp/dspengine.h" #include "dsp/dspcommands.h" #include "gui/glspectrum.h" -#include "gui/crightclickenabler.h" #include "gui/basicdevicesettingsdialog.h" #include "device/deviceapi.h" #include "device/deviceuiset.h" @@ -34,7 +34,6 @@ PlutoSDROutputGUI::PlutoSDROutputGUI(DeviceUISet *deviceUISet, QWidget* parent) : DeviceGUI(parent), ui(new Ui::PlutoSDROutputGUI), - m_deviceUISet(deviceUISet), m_settings(), m_sampleRateMode(true), m_forceSettings(true), @@ -45,9 +44,14 @@ PlutoSDROutputGUI::PlutoSDROutputGUI(DeviceUISet *deviceUISet, QWidget* parent) m_doApplySettings(true), m_statusCounter(0) { + m_deviceUISet = deviceUISet; + setAttribute(Qt::WA_DeleteOnClose, true); m_sampleSink = (PlutoSDROutput*) m_deviceUISet->m_deviceAPI->getSampleSink(); - ui->setupUi(this); + ui->setupUi(getContents()); + setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); + getContents()->setStyleSheet("#PlutoSDROutputGUI { background-color: rgb(64, 64, 64); }"); + m_helpURL = "plugins/samplesink/plutosdroutput/readme.md"; ui->centerFrequency->setColorMapper(ColorMapper(ColorMapper::GrayGold)); updateFrequencyLimits(); @@ -66,11 +70,11 @@ PlutoSDROutputGUI::PlutoSDROutputGUI(DeviceUISet *deviceUISet, QWidget* parent) ui->swInterpLabel->setText(QString::fromUtf8("S\u2191")); ui->lpFIRInterpolationLabel->setText(QString::fromUtf8("\u2191")); - CRightClickEnabler *startStopRightClickEnabler = new CRightClickEnabler(ui->startStop); - connect(startStopRightClickEnabler, SIGNAL(rightClick(const QPoint &)), this, SLOT(openDeviceSettingsDialog(const QPoint &))); + connect(this, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(openDeviceSettingsDialog(const QPoint &))); blockApplySettings(true); displaySettings(); + makeUIConnections(); blockApplySettings(false); connect(&m_updateTimer, SIGNAL(timeout()), this, SLOT(updateHardware())); @@ -117,6 +121,12 @@ bool PlutoSDROutputGUI::deserialize(const QByteArray& data) } } +void PlutoSDROutputGUI::resizeEvent(QResizeEvent* size) +{ + adjustSize(); + size->accept(); +} + bool PlutoSDROutputGUI::handleMessage(const Message& message) { (void) message; @@ -477,19 +487,42 @@ void PlutoSDROutputGUI::updateSampleRateAndFrequency() void PlutoSDROutputGUI::openDeviceSettingsDialog(const QPoint& p) { - BasicDeviceSettingsDialog dialog(this); - dialog.setUseReverseAPI(m_settings.m_useReverseAPI); - dialog.setReverseAPIAddress(m_settings.m_reverseAPIAddress); - dialog.setReverseAPIPort(m_settings.m_reverseAPIPort); - dialog.setReverseAPIDeviceIndex(m_settings.m_reverseAPIDeviceIndex); + if (m_contextMenuType == ContextMenuDeviceSettings) + { + BasicDeviceSettingsDialog dialog(this); + dialog.setUseReverseAPI(m_settings.m_useReverseAPI); + dialog.setReverseAPIAddress(m_settings.m_reverseAPIAddress); + dialog.setReverseAPIPort(m_settings.m_reverseAPIPort); + dialog.setReverseAPIDeviceIndex(m_settings.m_reverseAPIDeviceIndex); - dialog.move(p); - dialog.exec(); + dialog.move(p); + dialog.exec(); - m_settings.m_useReverseAPI = dialog.useReverseAPI(); - m_settings.m_reverseAPIAddress = dialog.getReverseAPIAddress(); - m_settings.m_reverseAPIPort = dialog.getReverseAPIPort(); - m_settings.m_reverseAPIDeviceIndex = dialog.getReverseAPIDeviceIndex(); + m_settings.m_useReverseAPI = dialog.useReverseAPI(); + m_settings.m_reverseAPIAddress = dialog.getReverseAPIAddress(); + m_settings.m_reverseAPIPort = dialog.getReverseAPIPort(); + m_settings.m_reverseAPIDeviceIndex = dialog.getReverseAPIDeviceIndex(); - sendSettings(); + sendSettings(); + } + + resetContextMenuType(); +} + +void PlutoSDROutputGUI::makeUIConnections() +{ + QObject::connect(ui->startStop, &ButtonSwitch::toggled, this, &PlutoSDROutputGUI::on_startStop_toggled); + QObject::connect(ui->centerFrequency, &ValueDial::changed, this, &PlutoSDROutputGUI::on_centerFrequency_changed); + QObject::connect(ui->loPPM, &QSlider::valueChanged, this, &PlutoSDROutputGUI::on_loPPM_valueChanged); + QObject::connect(ui->swInterp, QOverload::of(&QComboBox::currentIndexChanged), this, &PlutoSDROutputGUI::on_swInterp_currentIndexChanged); + QObject::connect(ui->sampleRate, &ValueDial::changed, this, &PlutoSDROutputGUI::on_sampleRate_changed); + QObject::connect(ui->lpf, &ValueDial::changed, this, &PlutoSDROutputGUI::on_lpf_changed); + QObject::connect(ui->lpFIREnable, &ButtonSwitch::toggled, this, &PlutoSDROutputGUI::on_lpFIREnable_toggled); + QObject::connect(ui->lpFIR, &ValueDial::changed, this, &PlutoSDROutputGUI::on_lpFIR_changed); + QObject::connect(ui->lpFIRInterpolation, QOverload::of(&QComboBox::currentIndexChanged), this, &PlutoSDROutputGUI::on_lpFIRInterpolation_currentIndexChanged); + QObject::connect(ui->lpFIRGain, QOverload::of(&QComboBox::currentIndexChanged), this, &PlutoSDROutputGUI::on_lpFIRGain_currentIndexChanged); + QObject::connect(ui->att, &QDial::valueChanged, this, &PlutoSDROutputGUI::on_att_valueChanged); + QObject::connect(ui->antenna, QOverload::of(&QComboBox::currentIndexChanged), this, &PlutoSDROutputGUI::on_antenna_currentIndexChanged); + QObject::connect(ui->transverter, &TransverterButton::clicked, this, &PlutoSDROutputGUI::on_transverter_clicked); + QObject::connect(ui->sampleRateMode, &QToolButton::toggled, this, &PlutoSDROutputGUI::on_sampleRateMode_toggled); } diff --git a/plugins/samplesink/plutosdroutput/plutosdroutputgui.h b/plugins/samplesink/plutosdroutput/plutosdroutputgui.h index 61db78122..0032780a9 100644 --- a/plugins/samplesink/plutosdroutput/plutosdroutputgui.h +++ b/plugins/samplesink/plutosdroutput/plutosdroutputgui.h @@ -48,9 +48,11 @@ public: virtual bool deserialize(const QByteArray& data); virtual MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; } +protected: + void resizeEvent(QResizeEvent* size); + private: Ui::PlutoSDROutputGUI* ui; - DeviceUISet* m_deviceUISet; PlutoSDROutputSettings m_settings; bool m_sampleRateMode; //!< true: device, false: base band sample rate update mode bool m_forceSettings; @@ -73,6 +75,7 @@ private: void setSampleRateLimits(); void updateFrequencyLimits(); bool handleMessage(const Message& message); + void makeUIConnections(); private slots: void on_startStop_toggled(bool checked); diff --git a/plugins/samplesink/plutosdroutput/plutosdroutputgui.ui b/plugins/samplesink/plutosdroutput/plutosdroutputgui.ui index 8dc5b657d..374ebddb2 100644 --- a/plugins/samplesink/plutosdroutput/plutosdroutputgui.ui +++ b/plugins/samplesink/plutosdroutput/plutosdroutputgui.ui @@ -6,20 +6,26 @@ 0 0 - 350 - 260 + 360 + 197
- + 0 0 - 350 - 260 + 360 + 197 + + + + + 380 + 250 @@ -128,7 +134,7 @@ Liberation Mono - 20 + 16 50 false @@ -766,23 +772,6 @@ - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - diff --git a/plugins/samplesink/plutosdroutput/readme.md b/plugins/samplesink/plutosdroutput/readme.md index fd2a6c223..6907cb500 100644 --- a/plugins/samplesink/plutosdroutput/readme.md +++ b/plugins/samplesink/plutosdroutput/readme.md @@ -27,6 +27,8 @@ Then add the following defines on `cmake` command line when compiling SDRangel:

Interface

+The top and bottom bars of the device window are described [here](../../../sdrgui/device/readme.md) + ![PlutoSDR output plugin GUI](../../../doc/img/PlutoSDROutput_plugin.png)

1: Common stream parameters

diff --git a/plugins/samplesink/remoteoutput/readme.md b/plugins/samplesink/remoteoutput/readme.md index 6f2d154c0..046b61d07 100644 --- a/plugins/samplesink/remoteoutput/readme.md +++ b/plugins/samplesink/remoteoutput/readme.md @@ -16,6 +16,8 @@ The plugin will be built only if the [CM256cc library](https://github.com/f4exb/

Interface

+The top and bottom bars of the device window are described [here](../../../sdrgui/device/readme.md) + ![SDR Remote output plugin GUI](../../../doc/img/RemoteOutput_plugin.png)

1: Start/Stop

diff --git a/plugins/samplesink/remoteoutput/remoteoutputgui.cpp b/plugins/samplesink/remoteoutput/remoteoutputgui.cpp index 393dead1e..8d494378e 100644 --- a/plugins/samplesink/remoteoutput/remoteoutputgui.cpp +++ b/plugins/samplesink/remoteoutput/remoteoutputgui.cpp @@ -20,6 +20,7 @@ #include #include #include +#include #include #include @@ -28,7 +29,6 @@ #include "plugin/pluginapi.h" #include "gui/colormapper.h" #include "gui/glspectrum.h" -#include "gui/crightclickenabler.h" #include "gui/basicdevicesettingsdialog.h" #include "dsp/dspengine.h" #include "dsp/dspcommands.h" @@ -44,7 +44,6 @@ RemoteOutputSinkGui::RemoteOutputSinkGui(DeviceUISet *deviceUISet, QWidget* parent) : DeviceGUI(parent), ui(new Ui::RemoteOutputGui), - m_deviceUISet(deviceUISet), m_settings(), m_remoteOutput(0), m_deviceCenterFrequency(0), @@ -56,6 +55,8 @@ RemoteOutputSinkGui::RemoteOutputSinkGui(DeviceUISet *deviceUISet, QWidget* pare m_forceSettings(true), m_remoteAPIConnected(false) { + m_deviceUISet = deviceUISet; + setAttribute(Qt::WA_DeleteOnClose, true); m_countUnrecoverable = 0; m_countRecovered = 0; m_lastCountUnrecoverable = 0; @@ -66,7 +67,10 @@ RemoteOutputSinkGui::RemoteOutputSinkGui(DeviceUISet *deviceUISet, QWidget* pare m_paletteRedText.setColor(QPalette::WindowText, Qt::red); m_paletteWhiteText.setColor(QPalette::WindowText, Qt::white); - ui->setupUi(this); + ui->setupUi(getContents()); + setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); + getContents()->setStyleSheet("#RemoteOutputGui { background-color: rgb(64, 64, 64); }"); + m_helpURL = "plugins/samplesink/remoteoutput/readme.md"; connect(&(m_deviceUISet->m_deviceAPI->getMasterTimer()), SIGNAL(timeout()), this, SLOT(tick())); connect(&m_updateTimer, SIGNAL(timeout()), this, SLOT(updateHardware())); @@ -83,11 +87,11 @@ RemoteOutputSinkGui::RemoteOutputSinkGui(DeviceUISet *deviceUISet, QWidget* pare displayEventCounts(); displayEventTimer(); - CRightClickEnabler *startStopRightClickEnabler = new CRightClickEnabler(ui->startStop); - connect(startStopRightClickEnabler, SIGNAL(rightClick(const QPoint &)), this, SLOT(openDeviceSettingsDialog(const QPoint &))); + connect(this, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(openDeviceSettingsDialog(const QPoint &))); displaySettings(); sendSettings(); + makeUIConnections(); } RemoteOutputSinkGui::~RemoteOutputSinkGui() @@ -138,6 +142,12 @@ bool RemoteOutputSinkGui::deserialize(const QByteArray& data) } } +void RemoteOutputSinkGui::resizeEvent(QResizeEvent* size) +{ + adjustSize(); + size->accept(); +} + bool RemoteOutputSinkGui::handleMessage(const Message& message) { if (RemoteOutput::MsgConfigureRemoteOutput::match(message)) @@ -524,19 +534,40 @@ void RemoteOutputSinkGui::displayRemoteFixedData(const RemoteOutput::MsgReportRe void RemoteOutputSinkGui::openDeviceSettingsDialog(const QPoint& p) { - BasicDeviceSettingsDialog dialog(this); - dialog.setUseReverseAPI(m_settings.m_useReverseAPI); - dialog.setReverseAPIAddress(m_settings.m_reverseAPIAddress); - dialog.setReverseAPIPort(m_settings.m_reverseAPIPort); - dialog.setReverseAPIDeviceIndex(m_settings.m_reverseAPIDeviceIndex); + if (m_contextMenuType == ContextMenuDeviceSettings) + { + BasicDeviceSettingsDialog dialog(this); + dialog.setUseReverseAPI(m_settings.m_useReverseAPI); + dialog.setReverseAPIAddress(m_settings.m_reverseAPIAddress); + dialog.setReverseAPIPort(m_settings.m_reverseAPIPort); + dialog.setReverseAPIDeviceIndex(m_settings.m_reverseAPIDeviceIndex); - dialog.move(p); - dialog.exec(); + dialog.move(p); + dialog.exec(); - m_settings.m_useReverseAPI = dialog.useReverseAPI(); - m_settings.m_reverseAPIAddress = dialog.getReverseAPIAddress(); - m_settings.m_reverseAPIPort = dialog.getReverseAPIPort(); - m_settings.m_reverseAPIDeviceIndex = dialog.getReverseAPIDeviceIndex(); + m_settings.m_useReverseAPI = dialog.useReverseAPI(); + m_settings.m_reverseAPIAddress = dialog.getReverseAPIAddress(); + m_settings.m_reverseAPIPort = dialog.getReverseAPIPort(); + m_settings.m_reverseAPIDeviceIndex = dialog.getReverseAPIDeviceIndex(); - sendSettings(); + sendSettings(); + } + + resetContextMenuType(); +} + +void RemoteOutputSinkGui::makeUIConnections() +{ + QObject::connect(ui->nbFECBlocks, &QDial::valueChanged, this, &RemoteOutputSinkGui::on_nbFECBlocks_valueChanged); + QObject::connect(ui->deviceIndex, &QLineEdit::returnPressed, this, &RemoteOutputSinkGui::on_deviceIndex_returnPressed); + QObject::connect(ui->channelIndex, &QLineEdit::returnPressed, this, &RemoteOutputSinkGui::on_channelIndex_returnPressed); + QObject::connect(ui->nbTxBytes, QOverload::of(&QComboBox::currentIndexChanged), this, &RemoteOutputSinkGui::on_nbTxBytes_currentIndexChanged); + QObject::connect(ui->apiAddress, &QLineEdit::returnPressed, this, &RemoteOutputSinkGui::on_apiAddress_returnPressed); + QObject::connect(ui->apiPort, &QLineEdit::returnPressed, this, &RemoteOutputSinkGui::on_apiPort_returnPressed); + QObject::connect(ui->dataAddress, &QLineEdit::returnPressed, this, &RemoteOutputSinkGui::on_dataAddress_returnPressed); + QObject::connect(ui->dataPort, &QLineEdit::returnPressed, this, &RemoteOutputSinkGui::on_dataPort_returnPressed); + QObject::connect(ui->apiApplyButton, &QPushButton::clicked, this, &RemoteOutputSinkGui::on_apiApplyButton_clicked); + QObject::connect(ui->dataApplyButton, &QPushButton::clicked, this, &RemoteOutputSinkGui::on_dataApplyButton_clicked); + QObject::connect(ui->startStop, &ButtonSwitch::toggled, this, &RemoteOutputSinkGui::on_startStop_toggled); + QObject::connect(ui->eventCountsReset, &QPushButton::clicked, this, &RemoteOutputSinkGui::on_eventCountsReset_clicked); } diff --git a/plugins/samplesink/remoteoutput/remoteoutputgui.h b/plugins/samplesink/remoteoutput/remoteoutputgui.h index 7b1964440..77aab4905 100644 --- a/plugins/samplesink/remoteoutput/remoteoutputgui.h +++ b/plugins/samplesink/remoteoutput/remoteoutputgui.h @@ -78,10 +78,12 @@ public: bool deserialize(const QByteArray& data); virtual MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; } +protected: + void resizeEvent(QResizeEvent* size); + private: Ui::RemoteOutputGui* ui; - DeviceUISet* m_deviceUISet; RemoteOutputSettings m_settings; //!< current settings RemoteOutputSettings m_controlSettings; //!< settings last sent to device via control port QTimer m_updateTimer; @@ -123,6 +125,7 @@ private: void displayEventStatus(int recoverableCount, int unrecoverableCount); void displayEventTimer(); bool handleMessage(const Message& message); + void makeUIConnections(); private slots: void handleInputMessages(); diff --git a/plugins/samplesink/remoteoutput/remoteoutputgui.ui b/plugins/samplesink/remoteoutput/remoteoutputgui.ui index 84a293ac8..c356eb699 100644 --- a/plugins/samplesink/remoteoutput/remoteoutputgui.ui +++ b/plugins/samplesink/remoteoutput/remoteoutputgui.ui @@ -9,20 +9,26 @@ 0 0 - 360 - 270 + 380 + 231
- + 0 0 - 360 - 270 + 380 + 231 + + + + + 400 + 284 @@ -719,23 +725,6 @@ - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - diff --git a/plugins/samplesink/soapysdroutput/readme.md b/plugins/samplesink/soapysdroutput/readme.md index 1956a740a..69e49d74a 100644 --- a/plugins/samplesink/soapysdroutput/readme.md +++ b/plugins/samplesink/soapysdroutput/readme.md @@ -65,6 +65,8 @@ When installed the Red Pitaya SoapySDR plugin lists a Red Pitaya device even if

Interface

+The top and bottom bars of the device window are described [here](../../../sdrgui/device/readme.md) + ![SoapySDR input plugin GUI](../../../doc/img/SoapySDROutput_plugin1.png) The top part described by number tags is common for all devices. The bottom part under the "A" tag depends on the SoapySDR device implementation. The corresponding widgets are stacked vertically inside a scrollable area as there may be many controls depending on how the device interface is implemented in SoapySDR. Move the slider on the right to see all parameters available. diff --git a/plugins/samplesink/soapysdroutput/soapysdroutputgui.cpp b/plugins/samplesink/soapysdroutput/soapysdroutputgui.cpp index 677de3e3f..ae98737d9 100644 --- a/plugins/samplesink/soapysdroutput/soapysdroutputgui.cpp +++ b/plugins/samplesink/soapysdroutput/soapysdroutputgui.cpp @@ -17,6 +17,7 @@ #include #include +#include #include "dsp/dspengine.h" #include "dsp/dspcommands.h" @@ -25,7 +26,6 @@ #include "util/simpleserializer.h" #include "ui_soapysdroutputgui.h" #include "gui/glspectrum.h" -#include "gui/crightclickenabler.h" #include "gui/basicdevicesettingsdialog.h" #include "soapygui/discreterangegui.h" #include "soapygui/intervalrangegui.h" @@ -41,7 +41,6 @@ SoapySDROutputGui::SoapySDROutputGui(DeviceUISet *deviceUISet, QWidget* parent) : DeviceGUI(parent), ui(new Ui::SoapySDROutputGui), - m_deviceUISet(deviceUISet), m_forceSettings(true), m_doApplySettings(true), m_sampleSink(0), @@ -57,8 +56,13 @@ SoapySDROutputGui::SoapySDROutputGui(DeviceUISet *deviceUISet, QWidget* parent) m_autoDCCorrection(0), m_autoIQCorrection(0) { + m_deviceUISet = deviceUISet; + setAttribute(Qt::WA_DeleteOnClose, true); m_sampleSink = (SoapySDROutput*) m_deviceUISet->m_deviceAPI->getSampleSink(); - ui->setupUi(this); + ui->setupUi(getContents()); + setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Expanding); + getContents()->setStyleSheet("#SoapySDROutputGui { background-color: rgb(64, 64, 64); }"); + m_helpURL = "plugins/samplesink/soapysdroutput/readme.md"; ui->centerFrequency->setColorMapper(ColorMapper(ColorMapper::GrayGold)); uint64_t f_min, f_max; @@ -90,8 +94,7 @@ SoapySDROutputGui::SoapySDROutputGui(DeviceUISet *deviceUISet, QWidget* parent) connect(&m_statusTimer, SIGNAL(timeout()), this, SLOT(updateStatus())); m_statusTimer.start(500); - CRightClickEnabler *startStopRightClickEnabler = new CRightClickEnabler(ui->startStop); - connect(startStopRightClickEnabler, SIGNAL(rightClick(const QPoint &)), this, SLOT(openDeviceSettingsDialog(const QPoint &))); + connect(this, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(openDeviceSettingsDialog(const QPoint &))); displaySettings(); @@ -99,6 +102,7 @@ SoapySDROutputGui::SoapySDROutputGui(DeviceUISet *deviceUISet, QWidget* parent) m_sampleSink->setMessageQueueToGUI(&m_inputMessageQueue); sendSettings(); + makeUIConnections(); } SoapySDROutputGui::~SoapySDROutputGui() @@ -440,6 +444,11 @@ bool SoapySDROutputGui::deserialize(const QByteArray& data) } } +void SoapySDROutputGui::resizeEvent(QResizeEvent* size) +{ + resize(360, height()); + size->accept(); +} bool SoapySDROutputGui::handleMessage(const Message& message) { @@ -867,19 +876,33 @@ void SoapySDROutputGui::updateStatus() void SoapySDROutputGui::openDeviceSettingsDialog(const QPoint& p) { - BasicDeviceSettingsDialog dialog(this); - dialog.setUseReverseAPI(m_settings.m_useReverseAPI); - dialog.setReverseAPIAddress(m_settings.m_reverseAPIAddress); - dialog.setReverseAPIPort(m_settings.m_reverseAPIPort); - dialog.setReverseAPIDeviceIndex(m_settings.m_reverseAPIDeviceIndex); + if (m_contextMenuType == ContextMenuDeviceSettings) + { + BasicDeviceSettingsDialog dialog(this); + dialog.setUseReverseAPI(m_settings.m_useReverseAPI); + dialog.setReverseAPIAddress(m_settings.m_reverseAPIAddress); + dialog.setReverseAPIPort(m_settings.m_reverseAPIPort); + dialog.setReverseAPIDeviceIndex(m_settings.m_reverseAPIDeviceIndex); - dialog.move(p); - dialog.exec(); + dialog.move(p); + dialog.exec(); - m_settings.m_useReverseAPI = dialog.useReverseAPI(); - m_settings.m_reverseAPIAddress = dialog.getReverseAPIAddress(); - m_settings.m_reverseAPIPort = dialog.getReverseAPIPort(); - m_settings.m_reverseAPIDeviceIndex = dialog.getReverseAPIDeviceIndex(); + m_settings.m_useReverseAPI = dialog.useReverseAPI(); + m_settings.m_reverseAPIAddress = dialog.getReverseAPIAddress(); + m_settings.m_reverseAPIPort = dialog.getReverseAPIPort(); + m_settings.m_reverseAPIDeviceIndex = dialog.getReverseAPIDeviceIndex(); - sendSettings(); + sendSettings(); + } + + resetContextMenuType(); +} + +void SoapySDROutputGui::makeUIConnections() +{ + QObject::connect(ui->centerFrequency, &ValueDial::changed, this, &SoapySDROutputGui::on_centerFrequency_changed); + QObject::connect(ui->LOppm, &QSlider::valueChanged, this, &SoapySDROutputGui::on_LOppm_valueChanged); + QObject::connect(ui->interp, QOverload::of(&QComboBox::currentIndexChanged), this, &SoapySDROutputGui::on_interp_currentIndexChanged); + QObject::connect(ui->transverter, &TransverterButton::clicked, this, &SoapySDROutputGui::on_transverter_clicked); + QObject::connect(ui->startStop, &ButtonSwitch::toggled, this, &SoapySDROutputGui::on_startStop_toggled); } diff --git a/plugins/samplesink/soapysdroutput/soapysdroutputgui.h b/plugins/samplesink/soapysdroutput/soapysdroutputgui.h index a16e2b779..258df8362 100644 --- a/plugins/samplesink/soapysdroutput/soapysdroutputgui.h +++ b/plugins/samplesink/soapysdroutput/soapysdroutputgui.h @@ -54,6 +54,9 @@ public: virtual bool deserialize(const QByteArray& data); virtual MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; } +protected: + void resizeEvent(QResizeEvent* size); + private: void createRangesControl( ItemSettingGUI **settingGUI, @@ -70,7 +73,6 @@ private: Ui::SoapySDROutputGui* ui; - DeviceUISet* m_deviceUISet; bool m_forceSettings; bool m_doApplySettings; SoapySDROutputSettings m_settings; @@ -107,6 +109,7 @@ private: void updateSampleRateAndFrequency(); void updateFrequencyLimits(); void setCenterFrequencySetting(uint64_t kHzValue); + void makeUIConnections(); private slots: void handleInputMessages(); diff --git a/plugins/samplesink/soapysdroutput/soapysdroutputgui.ui b/plugins/samplesink/soapysdroutput/soapysdroutputgui.ui index 985bb5c90..6ea2b933b 100644 --- a/plugins/samplesink/soapysdroutput/soapysdroutputgui.ui +++ b/plugins/samplesink/soapysdroutput/soapysdroutputgui.ui @@ -6,14 +6,20 @@ 0 0 - 324 - 176 + 360 + 236
+ + + 0 + 0 + + - 320 - 132 + 360 + 236 @@ -116,7 +122,7 @@ Liberation Mono - 20 + 16 @@ -301,6 +307,18 @@ + + + 0 + 0 + + + + + 356 + 0 + + true @@ -309,8 +327,8 @@ 0 0 - 318 - 49 + 352 + 83 @@ -336,17 +354,17 @@ + + ButtonSwitch + QToolButton +
gui/buttonswitch.h
+
ValueDial QWidget
gui/valuedial.h
1
- - ButtonSwitch - QToolButton -
gui/buttonswitch.h
-
TransverterButton QPushButton diff --git a/plugins/samplesink/testsink/readme.md b/plugins/samplesink/testsink/readme.md index cf3ceff0b..63158a909 100644 --- a/plugins/samplesink/testsink/readme.md +++ b/plugins/samplesink/testsink/readme.md @@ -10,6 +10,8 @@ The plugin is always built.

Interface

+The top and bottom bars of the device window are described [here](../../../sdrgui/device/readme.md) + ![Test sink plugin GUI](../../../doc/img/TestSink.png)

1: Start/Stop

@@ -40,4 +42,4 @@ Use the wheels to adjust the sample rate. Left click on a digit sets the cursor

6: Spectrum display

-This is the final output stream spectrum display after interpolation (4). This would be sent to the hardware device. Controls on the bottom of the panel are identical to the ones of the main spectrum display. \ No newline at end of file +This is the final output stream spectrum display after interpolation (4). This would be sent to the hardware device. Details on the spectrum view and controls can be found [here](../../../sdrgui/gui/spectrum.md) diff --git a/plugins/samplesink/testsink/testsinkgui.cpp b/plugins/samplesink/testsink/testsinkgui.cpp index 5afe0f4ab..04b5ffa6f 100644 --- a/plugins/samplesink/testsink/testsinkgui.cpp +++ b/plugins/samplesink/testsink/testsinkgui.cpp @@ -25,6 +25,7 @@ #include "plugin/pluginapi.h" #include "gui/colormapper.h" #include "gui/glspectrum.h" +#include "gui/basicdevicesettingsdialog.h" #include "dsp/spectrumvis.h" #include "dsp/dspengine.h" #include "dsp/dspcommands.h" @@ -38,7 +39,6 @@ TestSinkGui::TestSinkGui(DeviceUISet *deviceUISet, QWidget* parent) : DeviceGUI(parent), ui(new Ui::TestSinkGui), - m_deviceUISet(deviceUISet), m_doApplySettings(true), m_forceSettings(true), m_settings(), @@ -48,7 +48,14 @@ TestSinkGui::TestSinkGui(DeviceUISet *deviceUISet, QWidget* parent) : m_tickCount(0), m_lastEngineState(DeviceAPI::StNotStarted) { - ui->setupUi(this); + m_deviceUISet = deviceUISet; + setAttribute(Qt::WA_DeleteOnClose, true); + m_helpURL = "plugins/samplesink/testsink/readme.md"; + QWidget *contents = getContents(); + ui->setupUi(contents); + setSizePolicy(contents->sizePolicy()); + setMinimumSize(m_MinimumWidth, m_MinimumHeight); + getContents()->setStyleSheet("#TestSinkGui { background-color: rgb(64, 64, 64); }"); m_sampleSink = (TestSinkOutput*) m_deviceUISet->m_deviceAPI->getSampleSink(); ui->centerFrequency->setColorMapper(ColorMapper(ColorMapper::GrayGold)); @@ -69,8 +76,10 @@ TestSinkGui::TestSinkGui(DeviceUISet *deviceUISet, QWidget* parent) : m_statusTimer.start(500); displaySettings(); + makeUIConnections(); connect(&m_inputMessageQueue, SIGNAL(messageEnqueued()), this, SLOT(handleInputMessages()), Qt::QueuedConnection); + connect(this, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(openDeviceSettingsDialog(const QPoint &))); } TestSinkGui::~TestSinkGui() @@ -257,3 +266,35 @@ void TestSinkGui::on_startStop_toggled(bool checked) void TestSinkGui::tick() { } + +void TestSinkGui::openDeviceSettingsDialog(const QPoint& p) +{ + if (m_contextMenuType == ContextMenuDeviceSettings) + { + BasicDeviceSettingsDialog dialog(this); + dialog.setUseReverseAPI(m_settings.m_useReverseAPI); + dialog.setReverseAPIAddress(m_settings.m_reverseAPIAddress); + dialog.setReverseAPIPort(m_settings.m_reverseAPIPort); + dialog.setReverseAPIDeviceIndex(m_settings.m_reverseAPIDeviceIndex); + + dialog.move(p); + dialog.exec(); + + m_settings.m_useReverseAPI = dialog.useReverseAPI(); + m_settings.m_reverseAPIAddress = dialog.getReverseAPIAddress(); + m_settings.m_reverseAPIPort = dialog.getReverseAPIPort(); + m_settings.m_reverseAPIDeviceIndex = dialog.getReverseAPIDeviceIndex(); + + sendSettings(); + } + + resetContextMenuType(); +} + +void TestSinkGui::makeUIConnections() +{ + QObject::connect(ui->centerFrequency, &ValueDial::changed, this, &TestSinkGui::on_centerFrequency_changed); + QObject::connect(ui->sampleRate, &ValueDial::changed, this, &TestSinkGui::on_sampleRate_changed); + QObject::connect(ui->startStop, &ButtonSwitch::toggled, this, &TestSinkGui::on_startStop_toggled); + QObject::connect(ui->interp, QOverload::of(&QComboBox::currentIndexChanged), this, &TestSinkGui::on_interp_currentIndexChanged); +} diff --git a/plugins/samplesink/testsink/testsinkgui.h b/plugins/samplesink/testsink/testsinkgui.h index 257c57cbd..8d8b5f1da 100644 --- a/plugins/samplesink/testsink/testsinkgui.h +++ b/plugins/samplesink/testsink/testsinkgui.h @@ -52,7 +52,6 @@ public: private: Ui::TestSinkGui* ui; - DeviceUISet* m_deviceUISet; bool m_doApplySettings; bool m_forceSettings; TestSinkSettings m_settings; @@ -67,12 +66,15 @@ private: int m_lastEngineState; MessageQueue m_inputMessageQueue; SpectrumVis* m_spectrumVis; + static const int m_MinimumWidth = 360; + static const int m_MinimumHeight = 200 + 20 + 10 + 4*22 + 5; void blockApplySettings(bool block) { m_doApplySettings = !block; } void displaySettings(); void sendSettings(); void updateSampleRateAndFrequency(); bool handleMessage(const Message& message); + void makeUIConnections(); private slots: void handleInputMessages(); @@ -80,6 +82,7 @@ private slots: void on_sampleRate_changed(quint64 value); void on_startStop_toggled(bool checked); void on_interp_currentIndexChanged(int index); + void openDeviceSettingsDialog(const QPoint& p); void updateHardware(); void updateStatus(); void tick(); diff --git a/plugins/samplesink/testsink/testsinkgui.ui b/plugins/samplesink/testsink/testsinkgui.ui index 1d491e993..7858fc1c5 100644 --- a/plugins/samplesink/testsink/testsinkgui.ui +++ b/plugins/samplesink/testsink/testsinkgui.ui @@ -6,20 +6,20 @@ 0 0 - 350 - 400 + 364 + 420
- + 0 0 - 350 - 400 + 364 + 420 @@ -131,7 +131,7 @@ Liberation Mono - 20 + 16 @@ -290,59 +290,69 @@ - - - - - - 200 - 200 - - - - - Liberation Mono - 8 - - - - - - - - - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - + + + + 0 + 0 + + + + + + + + 0 + 0 + + + + + 354 + 200 + + + + + Liberation Mono + 8 + + + + + + + + + 0 + 0 + + + + + 354 + 30 + + + + + + + + ButtonSwitch + QToolButton +
gui/buttonswitch.h
+
ValueDial QWidget
gui/valuedial.h
1
- - ButtonSwitch - QToolButton -
gui/buttonswitch.h
-
GLSpectrum QWidget diff --git a/plugins/samplesink/testsink/testsinksettings.cpp b/plugins/samplesink/testsink/testsinksettings.cpp index 89ad8b87c..3b8fe09b5 100644 --- a/plugins/samplesink/testsink/testsinksettings.cpp +++ b/plugins/samplesink/testsink/testsinksettings.cpp @@ -30,6 +30,10 @@ void TestSinkSettings::resetToDefaults() m_sampleRate = 48000; m_log2Interp = 0; m_spectrumGUI = nullptr; + m_useReverseAPI = false; + m_reverseAPIAddress = "127.0.0.1"; + m_reverseAPIPort = 8888; + m_reverseAPIDeviceIndex = 0; } QByteArray TestSinkSettings::serialize() const @@ -44,6 +48,10 @@ QByteArray TestSinkSettings::serialize() const s.writeBlob(4, m_spectrumGUI->serialize()); } + s.writeBool(7, m_useReverseAPI); + s.writeString(8, m_reverseAPIAddress); + s.writeU32(9, m_reverseAPIPort); + s.writeU32(10, m_reverseAPIDeviceIndex); return s.final(); } @@ -60,6 +68,7 @@ bool TestSinkSettings::deserialize(const QByteArray& data) if (d.getVersion() == 1) { QByteArray bytetmp; + uint32_t uintval; d.readU64(1, &m_sampleRate, 435000*1000); d.readU64(2, &m_sampleRate, 48000); @@ -71,6 +80,19 @@ bool TestSinkSettings::deserialize(const QByteArray& data) m_spectrumGUI->deserialize(bytetmp); } + d.readBool(7, &m_useReverseAPI, false); + d.readString(8, &m_reverseAPIAddress, "127.0.0.1"); + d.readU32(9, &uintval, 0); + + if ((uintval > 1023) && (uintval < 65535)) { + m_reverseAPIPort = uintval; + } else { + m_reverseAPIPort = 8888; + } + + d.readU32(10, &uintval, 0); + m_reverseAPIDeviceIndex = uintval > 99 ? 99 : uintval; + return true; } else diff --git a/plugins/samplesink/testsink/testsinksettings.h b/plugins/samplesink/testsink/testsinksettings.h index 355537569..27a7d0589 100644 --- a/plugins/samplesink/testsink/testsinksettings.h +++ b/plugins/samplesink/testsink/testsinksettings.h @@ -27,6 +27,10 @@ struct TestSinkSettings { quint64 m_sampleRate; quint32 m_log2Interp; Serializable *m_spectrumGUI; + bool m_useReverseAPI; + QString m_reverseAPIAddress; + uint16_t m_reverseAPIPort; + uint16_t m_reverseAPIDeviceIndex; TestSinkSettings(); void resetToDefaults(); diff --git a/plugins/samplesink/usrpoutput/readme.md b/plugins/samplesink/usrpoutput/readme.md index 3500ad751..130aec688 100644 --- a/plugins/samplesink/usrpoutput/readme.md +++ b/plugins/samplesink/usrpoutput/readme.md @@ -6,6 +6,8 @@ This output sample sink plugin sends its samples to a [USRP device](https://www.

Interface

+The top and bottom bars of the device window are described [here](../../../sdrgui/device/readme.md) + ![USRP output plugin GUI](../../../doc/img/USRPOutput_plugin.png)

1: Start/Stop

@@ -18,7 +20,7 @@ Device start / stop button.

2A: Sample rate

-This is the sample rate at which IQ samples are transfered from SDRangel to the device, in kS/s (k) or MS/s (M). +This is the sample rate at which IQ samples are transfered from SDRangel to the device, in kS/s (k) or MS/s (M).

2B: Stream sample rate

diff --git a/plugins/samplesink/usrpoutput/usrpoutputgui.cpp b/plugins/samplesink/usrpoutput/usrpoutputgui.cpp index 7e8c52e24..64bb7fb97 100644 --- a/plugins/samplesink/usrpoutput/usrpoutputgui.cpp +++ b/plugins/samplesink/usrpoutput/usrpoutputgui.cpp @@ -18,11 +18,11 @@ #include #include +#include #include "ui_usrpoutputgui.h" #include "gui/colormapper.h" #include "gui/glspectrum.h" -#include "gui/crightclickenabler.h" #include "gui/basicdevicesettingsdialog.h" #include "dsp/dspengine.h" #include "dsp/dspcommands.h" @@ -33,7 +33,6 @@ USRPOutputGUI::USRPOutputGUI(DeviceUISet *deviceUISet, QWidget* parent) : DeviceGUI(parent), ui(new Ui::USRPOutputGUI), - m_deviceUISet(deviceUISet), m_settings(), m_sampleRateMode(true), m_sampleRate(0), @@ -43,9 +42,14 @@ USRPOutputGUI::USRPOutputGUI(DeviceUISet *deviceUISet, QWidget* parent) : m_statusCounter(0), m_deviceStatusCounter(0) { + m_deviceUISet = deviceUISet; + setAttribute(Qt::WA_DeleteOnClose, true); m_usrpOutput = (USRPOutput*) m_deviceUISet->m_deviceAPI->getSampleSink(); - ui->setupUi(this); + ui->setupUi(getContents()); + setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); + getContents()->setStyleSheet("#USRPOutputGUI { background-color: rgb(64, 64, 64); }"); + m_helpURL = "plugins/samplesink/usrpoutput/readme.md"; float minF, maxF; @@ -82,11 +86,10 @@ USRPOutputGUI::USRPOutputGUI(DeviceUISet *deviceUISet, QWidget* parent) : sprintf(recFileNameCStr, "test_%d.sdriq", m_deviceUISet->m_deviceAPI->getDeviceUID()); connect(&m_inputMessageQueue, SIGNAL(messageEnqueued()), this, SLOT(handleInputMessages()), Qt::QueuedConnection); - - CRightClickEnabler *startStopRightClickEnabler = new CRightClickEnabler(ui->startStop); - connect(startStopRightClickEnabler, SIGNAL(rightClick(const QPoint &)), this, SLOT(openDeviceSettingsDialog(const QPoint &))); + connect(this, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(openDeviceSettingsDialog(const QPoint &))); sendSettings(); + makeUIConnections(); } USRPOutputGUI::~USRPOutputGUI() @@ -149,6 +152,12 @@ bool USRPOutputGUI::deserialize(const QByteArray& data) } } +void USRPOutputGUI::resizeEvent(QResizeEvent* size) +{ + adjustSize(); + size->accept(); +} + void USRPOutputGUI::updateFrequencyLimits() { // values in kHz @@ -558,19 +567,39 @@ void USRPOutputGUI::on_sampleRateMode_toggled(bool checked) void USRPOutputGUI::openDeviceSettingsDialog(const QPoint& p) { - BasicDeviceSettingsDialog dialog(this); - dialog.setUseReverseAPI(m_settings.m_useReverseAPI); - dialog.setReverseAPIAddress(m_settings.m_reverseAPIAddress); - dialog.setReverseAPIPort(m_settings.m_reverseAPIPort); - dialog.setReverseAPIDeviceIndex(m_settings.m_reverseAPIDeviceIndex); + if (m_contextMenuType == ContextMenuDeviceSettings) + { + BasicDeviceSettingsDialog dialog(this); + dialog.setUseReverseAPI(m_settings.m_useReverseAPI); + dialog.setReverseAPIAddress(m_settings.m_reverseAPIAddress); + dialog.setReverseAPIPort(m_settings.m_reverseAPIPort); + dialog.setReverseAPIDeviceIndex(m_settings.m_reverseAPIDeviceIndex); - dialog.move(p); - dialog.exec(); + dialog.move(p); + dialog.exec(); - m_settings.m_useReverseAPI = dialog.useReverseAPI(); - m_settings.m_reverseAPIAddress = dialog.getReverseAPIAddress(); - m_settings.m_reverseAPIPort = dialog.getReverseAPIPort(); - m_settings.m_reverseAPIDeviceIndex = dialog.getReverseAPIDeviceIndex(); + m_settings.m_useReverseAPI = dialog.useReverseAPI(); + m_settings.m_reverseAPIAddress = dialog.getReverseAPIAddress(); + m_settings.m_reverseAPIPort = dialog.getReverseAPIPort(); + m_settings.m_reverseAPIDeviceIndex = dialog.getReverseAPIDeviceIndex(); - sendSettings(); + sendSettings(); + } + + resetContextMenuType(); +} + +void USRPOutputGUI::makeUIConnections() +{ + QObject::connect(ui->startStop, &ButtonSwitch::toggled, this, &USRPOutputGUI::on_startStop_toggled); + QObject::connect(ui->centerFrequency, &ValueDial::changed, this, &USRPOutputGUI::on_centerFrequency_changed); + QObject::connect(ui->sampleRate, &ValueDial::changed, this, &USRPOutputGUI::on_sampleRate_changed); + QObject::connect(ui->swInterp, QOverload::of(&QComboBox::currentIndexChanged), this, &USRPOutputGUI::on_swInterp_currentIndexChanged); + QObject::connect(ui->lpf, &ValueDial::changed, this, &USRPOutputGUI::on_lpf_changed); + QObject::connect(ui->loOffset, &ValueDialZ::changed, this, &USRPOutputGUI::on_loOffset_changed); + QObject::connect(ui->gain, &QSlider::valueChanged, this, &USRPOutputGUI::on_gain_valueChanged); + QObject::connect(ui->antenna, QOverload::of(&QComboBox::currentIndexChanged), this, &USRPOutputGUI::on_antenna_currentIndexChanged); + QObject::connect(ui->clockSource, QOverload::of(&QComboBox::currentIndexChanged), this, &USRPOutputGUI::on_clockSource_currentIndexChanged); + QObject::connect(ui->transverter, &TransverterButton::clicked, this, &USRPOutputGUI::on_transverter_clicked); + QObject::connect(ui->sampleRateMode, &QToolButton::toggled, this, &USRPOutputGUI::on_sampleRateMode_toggled); } diff --git a/plugins/samplesink/usrpoutput/usrpoutputgui.h b/plugins/samplesink/usrpoutput/usrpoutputgui.h index 1f337e40f..1a7ce6ba6 100644 --- a/plugins/samplesink/usrpoutput/usrpoutputgui.h +++ b/plugins/samplesink/usrpoutput/usrpoutputgui.h @@ -53,10 +53,12 @@ public: virtual MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; } virtual bool handleMessage(const Message& message); +protected: + void resizeEvent(QResizeEvent* size); + private: Ui::USRPOutputGUI* ui; - DeviceUISet* m_deviceUISet; USRPOutput* m_usrpOutput; //!< Same object as above but gives easy access to USRPOutput methods and attributes that are used intensively USRPOutputSettings m_settings; bool m_sampleRateMode; //!< true: device, false: base band sample rate update mode @@ -80,6 +82,7 @@ private: void updateSampleRate(); void updateFrequencyLimits(); void blockApplySettings(bool block); + void makeUIConnections(); private slots: void handleInputMessages(); diff --git a/plugins/samplesink/usrpoutput/usrpoutputgui.ui b/plugins/samplesink/usrpoutput/usrpoutputgui.ui index 3e0d3ba25..7acddfa8d 100644 --- a/plugins/samplesink/usrpoutput/usrpoutputgui.ui +++ b/plugins/samplesink/usrpoutput/usrpoutputgui.ui @@ -7,11 +7,11 @@ 0 0 360 - 290 + 214
- + 0 0 @@ -19,7 +19,13 @@ 360 - 290 + 163 + + + + + 380 + 214 @@ -138,7 +144,7 @@ Liberation Mono - 20 + 16 @@ -705,44 +711,20 @@ - - - - Qt::Horizontal - - - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - ButtonSwitch - QToolButton -
gui/buttonswitch.h
-
ValueDial QWidget
gui/valuedial.h
1
+ + ButtonSwitch + QToolButton +
gui/buttonswitch.h
+
ValueDialZ QWidget diff --git a/plugins/samplesink/xtrxoutput/readme.md b/plugins/samplesink/xtrxoutput/readme.md index c641f7d4a..5676003f5 100644 --- a/plugins/samplesink/xtrxoutput/readme.md +++ b/plugins/samplesink/xtrxoutput/readme.md @@ -40,9 +40,12 @@ For a group the syntax is the same but the group name is prefixed with `@` like: ``` @realtime - rtprio 99 @realtime - memlock unlimited +```

Interface

+The top and bottom bars of the device window are described [here](../../../sdrgui/device/readme.md) + ![XTRX output plugin GUI](../../../doc/img/XTRXOutput_plugin.png)

1: Start/Stop

diff --git a/plugins/samplesink/xtrxoutput/xtrxoutputgui.cpp b/plugins/samplesink/xtrxoutput/xtrxoutputgui.cpp index e1e9454d4..01ba67f2b 100644 --- a/plugins/samplesink/xtrxoutput/xtrxoutputgui.cpp +++ b/plugins/samplesink/xtrxoutput/xtrxoutputgui.cpp @@ -19,11 +19,11 @@ #include #include +#include #include "ui_xtrxoutputgui.h" #include "gui/colormapper.h" #include "gui/glspectrum.h" -#include "gui/crightclickenabler.h" #include "gui/basicdevicesettingsdialog.h" #include "dsp/dspengine.h" #include "dsp/dspcommands.h" @@ -34,7 +34,6 @@ XTRXOutputGUI::XTRXOutputGUI(DeviceUISet *deviceUISet, QWidget* parent) : DeviceGUI(parent), ui(new Ui::XTRXOutputGUI), - m_deviceUISet(deviceUISet), m_settings(), m_sampleRateMode(true), m_sampleRate(0), @@ -44,9 +43,14 @@ XTRXOutputGUI::XTRXOutputGUI(DeviceUISet *deviceUISet, QWidget* parent) : m_statusCounter(0), m_deviceStatusCounter(0) { + m_deviceUISet = deviceUISet; + setAttribute(Qt::WA_DeleteOnClose, true); m_XTRXOutput = (XTRXOutput*) m_deviceUISet->m_deviceAPI->getSampleSink(); - ui->setupUi(this); + ui->setupUi(getContents()); + setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); + getContents()->setStyleSheet("#XTRXOutputGUI { background-color: rgb(64, 64, 64); }"); + m_helpURL = "plugins/samplesink/xtrxoutput/readme.md"; float minF, maxF, stepF; @@ -70,10 +74,10 @@ XTRXOutputGUI::XTRXOutputGUI(DeviceUISet *deviceUISet, QWidget* parent) : connect(&m_statusTimer, SIGNAL(timeout()), this, SLOT(updateStatus())); m_statusTimer.start(500); - CRightClickEnabler *startStopRightClickEnabler = new CRightClickEnabler(ui->startStop); - connect(startStopRightClickEnabler, SIGNAL(rightClick(const QPoint &)), this, SLOT(openDeviceSettingsDialog(const QPoint &))); + connect(this, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(openDeviceSettingsDialog(const QPoint &))); displaySettings(); + makeUIConnections(); connect(&m_inputMessageQueue, SIGNAL(messageEnqueued()), this, SLOT(handleInputMessages()), Qt::QueuedConnection); } @@ -116,6 +120,12 @@ bool XTRXOutputGUI::deserialize(const QByteArray& data) } } +void XTRXOutputGUI::resizeEvent(QResizeEvent* size) +{ + adjustSize(); + size->accept(); +} + bool XTRXOutputGUI::handleMessage(const Message& message) { @@ -549,19 +559,41 @@ void XTRXOutputGUI::on_sampleRateMode_toggled(bool checked) void XTRXOutputGUI::openDeviceSettingsDialog(const QPoint& p) { - BasicDeviceSettingsDialog dialog(this); - dialog.setUseReverseAPI(m_settings.m_useReverseAPI); - dialog.setReverseAPIAddress(m_settings.m_reverseAPIAddress); - dialog.setReverseAPIPort(m_settings.m_reverseAPIPort); - dialog.setReverseAPIDeviceIndex(m_settings.m_reverseAPIDeviceIndex); + if (m_contextMenuType == ContextMenuDeviceSettings) + { + BasicDeviceSettingsDialog dialog(this); + dialog.setUseReverseAPI(m_settings.m_useReverseAPI); + dialog.setReverseAPIAddress(m_settings.m_reverseAPIAddress); + dialog.setReverseAPIPort(m_settings.m_reverseAPIPort); + dialog.setReverseAPIDeviceIndex(m_settings.m_reverseAPIDeviceIndex); - dialog.move(p); - dialog.exec(); + dialog.move(p); + dialog.exec(); - m_settings.m_useReverseAPI = dialog.useReverseAPI(); - m_settings.m_reverseAPIAddress = dialog.getReverseAPIAddress(); - m_settings.m_reverseAPIPort = dialog.getReverseAPIPort(); - m_settings.m_reverseAPIDeviceIndex = dialog.getReverseAPIDeviceIndex(); + m_settings.m_useReverseAPI = dialog.useReverseAPI(); + m_settings.m_reverseAPIAddress = dialog.getReverseAPIAddress(); + m_settings.m_reverseAPIPort = dialog.getReverseAPIPort(); + m_settings.m_reverseAPIDeviceIndex = dialog.getReverseAPIDeviceIndex(); - sendSettings(); + sendSettings(); + } + + resetContextMenuType(); +} + +void XTRXOutputGUI::makeUIConnections() +{ + QObject::connect(ui->startStop, &ButtonSwitch::toggled, this, &XTRXOutputGUI::on_startStop_toggled); + QObject::connect(ui->centerFrequency, &ValueDial::changed, this, &XTRXOutputGUI::on_centerFrequency_changed); + QObject::connect(ui->ncoFrequency, &ValueDialZ::changed, this, &XTRXOutputGUI::on_ncoFrequency_changed); + QObject::connect(ui->ncoEnable, &ButtonSwitch::toggled, this, &XTRXOutputGUI::on_ncoEnable_toggled); + QObject::connect(ui->sampleRate, &ValueDial::changed, this, &XTRXOutputGUI::on_sampleRate_changed); + QObject::connect(ui->hwInterp, QOverload::of(&QComboBox::currentIndexChanged), this, &XTRXOutputGUI::on_hwInterp_currentIndexChanged); + QObject::connect(ui->swInterp, QOverload::of(&QComboBox::currentIndexChanged), this, &XTRXOutputGUI::on_swInterp_currentIndexChanged); + QObject::connect(ui->lpf, &ValueDial::changed, this, &XTRXOutputGUI::on_lpf_changed); + QObject::connect(ui->gain, &QSlider::valueChanged, this, &XTRXOutputGUI::on_gain_valueChanged); + QObject::connect(ui->antenna, QOverload::of(&QComboBox::currentIndexChanged), this, &XTRXOutputGUI::on_antenna_currentIndexChanged); + QObject::connect(ui->extClock, &ExternalClockButton::clicked, this, &XTRXOutputGUI::on_extClock_clicked); + QObject::connect(ui->pwrmode, QOverload::of(&QComboBox::currentIndexChanged), this, &XTRXOutputGUI::on_pwrmode_currentIndexChanged); + QObject::connect(ui->sampleRateMode, &QToolButton::toggled, this, &XTRXOutputGUI::on_sampleRateMode_toggled); } diff --git a/plugins/samplesink/xtrxoutput/xtrxoutputgui.h b/plugins/samplesink/xtrxoutput/xtrxoutputgui.h index b53d1c0f4..cfec0e87e 100644 --- a/plugins/samplesink/xtrxoutput/xtrxoutputgui.h +++ b/plugins/samplesink/xtrxoutput/xtrxoutputgui.h @@ -45,10 +45,12 @@ public: bool deserialize(const QByteArray& data); virtual MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; } +protected: + void resizeEvent(QResizeEvent* size); + private: Ui::XTRXOutputGUI* ui; - DeviceUISet* m_deviceUISet; XTRXOutput* m_XTRXOutput; //!< Same object as above but gives easy access to XTRXInput methods and attributes that are used intensively XTRXOutputSettings m_settings; bool m_sampleRateMode; //!< true: device, false: base band sample rate update mode @@ -73,6 +75,7 @@ private: void updateDACRate(); void blockApplySettings(bool block); bool handleMessage(const Message& message); + void makeUIConnections(); private slots: void handleInputMessages(); diff --git a/plugins/samplesink/xtrxoutput/xtrxoutputgui.ui b/plugins/samplesink/xtrxoutput/xtrxoutputgui.ui index c04dd6267..44d32e25c 100644 --- a/plugins/samplesink/xtrxoutput/xtrxoutputgui.ui +++ b/plugins/samplesink/xtrxoutput/xtrxoutputgui.ui @@ -6,12 +6,12 @@ 0 0 - 370 - 290 + 360 + 207
- + 0 0 @@ -19,7 +19,13 @@ 360 - 290 + 207 + + + + + 380 + 264 @@ -128,7 +134,7 @@ Liberation Mono - 20 + 16 50 false @@ -820,6 +826,7 @@ + Liberation Sans 8 @@ -876,30 +883,6 @@ QToolTip{background-color: white; color: black;} - - - - Qt::Horizontal - - - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - @@ -914,17 +897,17 @@ QToolTip{background-color: white; color: black;} QToolButton
gui/buttonswitch.h
- - ExternalClockButton - QToolButton -
gui/externalclockbutton.h
-
ValueDialZ QWidget
gui/valuedialz.h
1
+ + ExternalClockButton + QToolButton +
gui/externalclockbutton.h
+
diff --git a/plugins/samplesource/airspy/airspygui.cpp b/plugins/samplesource/airspy/airspygui.cpp index 06ab05bd1..b5a8b7e8b 100644 --- a/plugins/samplesource/airspy/airspygui.cpp +++ b/plugins/samplesource/airspy/airspygui.cpp @@ -18,6 +18,7 @@ #include #include #include +#include #include @@ -29,7 +30,6 @@ #include "ui_airspygui.h" #include "gui/colormapper.h" #include "gui/glspectrum.h" -#include "gui/crightclickenabler.h" #include "gui/basicdevicesettingsdialog.h" #include "dsp/dspengine.h" #include "dsp/dspcommands.h" @@ -37,16 +37,19 @@ AirspyGui::AirspyGui(DeviceUISet *deviceUISet, QWidget* parent) : DeviceGUI(parent), ui(new Ui::AirspyGui), - m_deviceUISet(deviceUISet), m_doApplySettings(true), m_forceSettings(true), m_settings(), m_sampleSource(0), m_lastEngineState(DeviceAPI::StNotStarted) { + m_deviceUISet = deviceUISet; + setAttribute(Qt::WA_DeleteOnClose, true); m_sampleSource = (AirspyInput*) m_deviceUISet->m_deviceAPI->getSampleSource(); - ui->setupUi(this); + ui->setupUi(getContents()); + setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); + getContents()->setStyleSheet("#AirspyGui { background-color: rgb(64, 64, 64); }"); ui->centerFrequency->setColorMapper(ColorMapper(ColorMapper::GrayGold)); updateFrequencyLimits(); @@ -54,8 +57,7 @@ AirspyGui::AirspyGui(DeviceUISet *deviceUISet, QWidget* parent) : connect(&m_statusTimer, SIGNAL(timeout()), this, SLOT(updateStatus())); m_statusTimer.start(500); - CRightClickEnabler *startStopRightClickEnabler = new CRightClickEnabler(ui->startStop); - connect(startStopRightClickEnabler, SIGNAL(rightClick(const QPoint &)), this, SLOT(openDeviceSettingsDialog(const QPoint &))); + connect(this, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(openDeviceSettingsDialog(const QPoint &))); displaySettings(); @@ -65,6 +67,7 @@ AirspyGui::AirspyGui(DeviceUISet *deviceUISet, QWidget* parent) : m_sampleSource->setMessageQueueToGUI(&m_inputMessageQueue); sendSettings(); + makeUIConnections(); } AirspyGui::~AirspyGui() @@ -102,6 +105,12 @@ bool AirspyGui::deserialize(const QByteArray& data) } } +void AirspyGui::resizeEvent(QResizeEvent* size) +{ + adjustSize(); + size->accept(); +} + bool AirspyGui::handleMessage(const Message& message) { if (AirspyInput::MsgConfigureAirspy::match(message)) @@ -431,19 +440,43 @@ int AirspyGui::getDevSampleRateIndex(uint32_t sampeRate) void AirspyGui::openDeviceSettingsDialog(const QPoint& p) { - BasicDeviceSettingsDialog dialog(this); - dialog.setUseReverseAPI(m_settings.m_useReverseAPI); - dialog.setReverseAPIAddress(m_settings.m_reverseAPIAddress); - dialog.setReverseAPIPort(m_settings.m_reverseAPIPort); - dialog.setReverseAPIDeviceIndex(m_settings.m_reverseAPIDeviceIndex); + if (m_contextMenuType == ContextMenuDeviceSettings) + { + BasicDeviceSettingsDialog dialog(this); + dialog.setUseReverseAPI(m_settings.m_useReverseAPI); + dialog.setReverseAPIAddress(m_settings.m_reverseAPIAddress); + dialog.setReverseAPIPort(m_settings.m_reverseAPIPort); + dialog.setReverseAPIDeviceIndex(m_settings.m_reverseAPIDeviceIndex); - dialog.move(p); - dialog.exec(); + dialog.move(p); + dialog.exec(); - m_settings.m_useReverseAPI = dialog.useReverseAPI(); - m_settings.m_reverseAPIAddress = dialog.getReverseAPIAddress(); - m_settings.m_reverseAPIPort = dialog.getReverseAPIPort(); - m_settings.m_reverseAPIDeviceIndex = dialog.getReverseAPIDeviceIndex(); + m_settings.m_useReverseAPI = dialog.useReverseAPI(); + m_settings.m_reverseAPIAddress = dialog.getReverseAPIAddress(); + m_settings.m_reverseAPIPort = dialog.getReverseAPIPort(); + m_settings.m_reverseAPIDeviceIndex = dialog.getReverseAPIDeviceIndex(); - sendSettings(); + sendSettings(); + } + + resetContextMenuType(); +} + +void AirspyGui::makeUIConnections() +{ + QObject::connect(ui->centerFrequency, &ValueDial::changed, this, &AirspyGui::on_centerFrequency_changed); + QObject::connect(ui->LOppm, &QSlider::valueChanged, this, &AirspyGui::on_LOppm_valueChanged); + QObject::connect(ui->dcOffset, &ButtonSwitch::toggled, this, &AirspyGui::on_dcOffset_toggled); + QObject::connect(ui->iqImbalance, &ButtonSwitch::toggled, this, &AirspyGui::on_iqImbalance_toggled); + QObject::connect(ui->sampleRate, QOverload::of(&QComboBox::currentIndexChanged), this, &AirspyGui::on_sampleRate_currentIndexChanged); + QObject::connect(ui->biasT, &QCheckBox::stateChanged, this, &AirspyGui::on_biasT_stateChanged); + QObject::connect(ui->decim, QOverload::of(&QComboBox::currentIndexChanged), this, &AirspyGui::on_decim_currentIndexChanged); + QObject::connect(ui->fcPos, QOverload::of(&QComboBox::currentIndexChanged), this, &AirspyGui::on_fcPos_currentIndexChanged); + QObject::connect(ui->lna, &QSlider::valueChanged, this, &AirspyGui::on_lna_valueChanged); + QObject::connect(ui->mix, &QSlider::valueChanged, this, &AirspyGui::on_mix_valueChanged); + QObject::connect(ui->vga, &QSlider::valueChanged, this, &AirspyGui::on_vga_valueChanged); + QObject::connect(ui->lnaAGC, &QCheckBox::stateChanged, this, &AirspyGui::on_lnaAGC_stateChanged); + QObject::connect(ui->mixAGC, &QCheckBox::stateChanged, this, &AirspyGui::on_mixAGC_stateChanged); + QObject::connect(ui->startStop, &ButtonSwitch::toggled, this, &AirspyGui::on_startStop_toggled); + QObject::connect(ui->transverter, &TransverterButton::clicked, this, &AirspyGui::on_transverter_clicked); } diff --git a/plugins/samplesource/airspy/airspygui.h b/plugins/samplesource/airspy/airspygui.h index 3f52caef6..2f7de1f48 100644 --- a/plugins/samplesource/airspy/airspygui.h +++ b/plugins/samplesource/airspy/airspygui.h @@ -44,13 +44,16 @@ public: QByteArray serialize() const; bool deserialize(const QByteArray& data); virtual MessageQueue* getInputMessageQueue() { return &m_inputMessageQueue; } + uint32_t getDevSampleRate(unsigned int index); int getDevSampleRateIndex(uint32_t sampleRate); +protected: + void resizeEvent(QResizeEvent* size); + private: Ui::AirspyGui* ui; - DeviceUISet* m_deviceUISet; bool m_doApplySettings; bool m_forceSettings; AirspySettings m_settings; @@ -70,6 +73,7 @@ private: void updateSampleRateAndFrequency(); void updateFrequencyLimits(); bool handleMessage(const Message& message); + void makeUIConnections(); private slots: void on_centerFrequency_changed(quint64 value); diff --git a/plugins/samplesource/airspy/airspygui.ui b/plugins/samplesource/airspy/airspygui.ui index 1cf50415d..d729442ad 100644 --- a/plugins/samplesource/airspy/airspygui.ui +++ b/plugins/samplesource/airspy/airspygui.ui @@ -6,20 +6,26 @@ 0 0 - 280 - 220 + 360 + 187
- + 0 0 - 280 - 220 + 360 + 187 + + + + + 380 + 244 @@ -122,7 +128,7 @@ Liberation Mono - 20 + 16 @@ -286,7 +292,7 @@ - + 0 0 @@ -427,13 +433,6 @@ - - - - Qt::Horizontal - - - @@ -616,23 +615,6 @@ - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - diff --git a/plugins/samplesource/airspyhf/airspyhfgui.cpp b/plugins/samplesource/airspyhf/airspyhfgui.cpp index 93da0660d..a056e7ae0 100644 --- a/plugins/samplesource/airspyhf/airspyhfgui.cpp +++ b/plugins/samplesource/airspyhf/airspyhfgui.cpp @@ -18,6 +18,7 @@ #include #include #include +#include #include @@ -27,7 +28,6 @@ #include "ui_airspyhfgui.h" #include "gui/colormapper.h" #include "gui/glspectrum.h" -#include "gui/crightclickenabler.h" #include "gui/basicdevicesettingsdialog.h" #include "dsp/dspengine.h" #include "dsp/dspcommands.h" @@ -36,16 +36,20 @@ AirspyHFGui::AirspyHFGui(DeviceUISet *deviceUISet, QWidget* parent) : DeviceGUI(parent), ui(new Ui::AirspyHFGui), - m_deviceUISet(deviceUISet), m_doApplySettings(true), m_forceSettings(true), m_settings(), m_sampleSource(0), m_lastEngineState(DeviceAPI::StNotStarted) { + m_deviceUISet = deviceUISet; + setAttribute(Qt::WA_DeleteOnClose, true); m_sampleSource = (AirspyHFInput*) m_deviceUISet->m_deviceAPI->getSampleSource(); - ui->setupUi(this); + ui->setupUi(getContents()); + setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); + getContents()->setStyleSheet("#AirspyHFGui { background-color: rgb(64, 64, 64); }"); + m_helpURL = "plugins/samplesource/airspyhf/readme.md"; ui->centerFrequency->setColorMapper(ColorMapper(ColorMapper::GrayGold)); updateFrequencyLimits(); @@ -53,8 +57,7 @@ AirspyHFGui::AirspyHFGui(DeviceUISet *deviceUISet, QWidget* parent) : connect(&m_statusTimer, SIGNAL(timeout()), this, SLOT(updateStatus())); m_statusTimer.start(500); - CRightClickEnabler *startStopRightClickEnabler = new CRightClickEnabler(ui->startStop); - connect(startStopRightClickEnabler, SIGNAL(rightClick(const QPoint &)), this, SLOT(openDeviceSettingsDialog(const QPoint &))); + connect(this, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(openDeviceSettingsDialog(const QPoint &))); displaySettings(); @@ -64,6 +67,7 @@ AirspyHFGui::AirspyHFGui(DeviceUISet *deviceUISet, QWidget* parent) : m_sampleSource->setMessageQueueToGUI(&m_inputMessageQueue); sendSettings(); + makeUIConnections(); } AirspyHFGui::~AirspyHFGui() @@ -101,6 +105,12 @@ bool AirspyHFGui::deserialize(const QByteArray& data) } } +void AirspyHFGui::resizeEvent(QResizeEvent* size) +{ + adjustSize(); + size->accept(); +} + bool AirspyHFGui::handleMessage(const Message& message) { if (AirspyHFInput::MsgConfigureAirspyHF::match(message)) @@ -450,19 +460,42 @@ int AirspyHFGui::getDevSampleRateIndex(uint32_t sampeRate) void AirspyHFGui::openDeviceSettingsDialog(const QPoint& p) { - BasicDeviceSettingsDialog dialog(this); - dialog.setUseReverseAPI(m_settings.m_useReverseAPI); - dialog.setReverseAPIAddress(m_settings.m_reverseAPIAddress); - dialog.setReverseAPIPort(m_settings.m_reverseAPIPort); - dialog.setReverseAPIDeviceIndex(m_settings.m_reverseAPIDeviceIndex); + if (m_contextMenuType == ContextMenuDeviceSettings) + { + BasicDeviceSettingsDialog dialog(this); + dialog.setUseReverseAPI(m_settings.m_useReverseAPI); + dialog.setReverseAPIAddress(m_settings.m_reverseAPIAddress); + dialog.setReverseAPIPort(m_settings.m_reverseAPIPort); + dialog.setReverseAPIDeviceIndex(m_settings.m_reverseAPIDeviceIndex); - dialog.move(p); - dialog.exec(); + dialog.move(p); + dialog.exec(); - m_settings.m_useReverseAPI = dialog.useReverseAPI(); - m_settings.m_reverseAPIAddress = dialog.getReverseAPIAddress(); - m_settings.m_reverseAPIPort = dialog.getReverseAPIPort(); - m_settings.m_reverseAPIDeviceIndex = dialog.getReverseAPIDeviceIndex(); + m_settings.m_useReverseAPI = dialog.useReverseAPI(); + m_settings.m_reverseAPIAddress = dialog.getReverseAPIAddress(); + m_settings.m_reverseAPIPort = dialog.getReverseAPIPort(); + m_settings.m_reverseAPIDeviceIndex = dialog.getReverseAPIDeviceIndex(); - sendSettings(); + sendSettings(); + } + + resetContextMenuType(); +} + +void AirspyHFGui::makeUIConnections() +{ + QObject::connect(ui->centerFrequency, &ValueDial::changed, this, &AirspyHFGui::on_centerFrequency_changed); + QObject::connect(ui->LOppm, &QSlider::valueChanged, this, &AirspyHFGui::on_LOppm_valueChanged); + QObject::connect(ui->resetLOppm, &QPushButton::clicked, this, &AirspyHFGui::on_resetLOppm_clicked); + QObject::connect(ui->dcOffset, &ButtonSwitch::toggled, this, &AirspyHFGui::on_dcOffset_toggled); + QObject::connect(ui->iqImbalance, &ButtonSwitch::toggled, this, &AirspyHFGui::on_iqImbalance_toggled); + QObject::connect(ui->sampleRate, QOverload::of(&QComboBox::currentIndexChanged), this, &AirspyHFGui::on_sampleRate_currentIndexChanged); + QObject::connect(ui->decim, QOverload::of(&QComboBox::currentIndexChanged), this, &AirspyHFGui::on_decim_currentIndexChanged); + QObject::connect(ui->startStop, &ButtonSwitch::toggled, this, &AirspyHFGui::on_startStop_toggled); + QObject::connect(ui->transverter, &TransverterButton::clicked, this, &AirspyHFGui::on_transverter_clicked); + QObject::connect(ui->band, QOverload::of(&QComboBox::currentIndexChanged), this, &AirspyHFGui::on_band_currentIndexChanged); + QObject::connect(ui->dsp, &ButtonSwitch::toggled, this, &AirspyHFGui::on_dsp_toggled); + QObject::connect(ui->lna, &ButtonSwitch::toggled, this, &AirspyHFGui::on_lna_toggled); + QObject::connect(ui->agc, QOverload::of(&QComboBox::currentIndexChanged), this, &AirspyHFGui::on_agc_currentIndexChanged); + QObject::connect(ui->att, QOverload::of(&QComboBox::currentIndexChanged), this, &AirspyHFGui::on_att_currentIndexChanged); } diff --git a/plugins/samplesource/airspyhf/airspyhfgui.h b/plugins/samplesource/airspyhf/airspyhfgui.h index 6c92f3bc2..d02356f5a 100644 --- a/plugins/samplesource/airspyhf/airspyhfgui.h +++ b/plugins/samplesource/airspyhf/airspyhfgui.h @@ -45,13 +45,16 @@ public: QByteArray serialize() const; bool deserialize(const QByteArray& data); virtual MessageQueue* getInputMessageQueue() { return &m_inputMessageQueue; } + uint32_t getDevSampleRate(unsigned int index); int getDevSampleRateIndex(uint32_t sampleRate); +protected: + void resizeEvent(QResizeEvent* size); + private: Ui::AirspyHFGui* ui; - DeviceUISet* m_deviceUISet; bool m_doApplySettings; bool m_forceSettings; AirspyHFSettings m_settings; @@ -72,6 +75,7 @@ private: void updateSampleRateAndFrequency(); void updateFrequencyLimits(); bool handleMessage(const Message& message); + void makeUIConnections(); private slots: void on_centerFrequency_changed(quint64 value); diff --git a/plugins/samplesource/airspyhf/airspyhfgui.ui b/plugins/samplesource/airspyhf/airspyhfgui.ui index 40463d73b..ab1849681 100644 --- a/plugins/samplesource/airspyhf/airspyhfgui.ui +++ b/plugins/samplesource/airspyhf/airspyhfgui.ui @@ -6,20 +6,26 @@ 0 0 - 320 - 160 + 360 + 137 - + 0 0 - 320 - 160 + 360 + 137 + + + + + 380 + 177 @@ -49,9 +55,6 @@ - - 4 - @@ -122,7 +125,7 @@ Liberation Mono - 20 + 16 @@ -581,37 +584,20 @@ - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - ButtonSwitch - QToolButton -
gui/buttonswitch.h
-
ValueDial QWidget
gui/valuedial.h
1
+ + ButtonSwitch + QToolButton +
gui/buttonswitch.h
+
TransverterButton QPushButton diff --git a/plugins/samplesource/airspyhf/airspyhfinput.cpp b/plugins/samplesource/airspyhf/airspyhfinput.cpp index 6704350be..70f509899 100644 --- a/plugins/samplesource/airspyhf/airspyhfinput.cpp +++ b/plugins/samplesource/airspyhf/airspyhfinput.cpp @@ -48,7 +48,7 @@ const qint64 AirspyHFInput::loHighLimitFreqVHF = 260000000L; AirspyHFInput::AirspyHFInput(DeviceAPI *deviceAPI) : m_deviceAPI(deviceAPI), m_settings(), - m_dev(0), + m_dev(nullptr), m_airspyHFWorker(nullptr), m_deviceDescription("AirspyHF"), m_running(false) @@ -89,7 +89,7 @@ void AirspyHFInput::destroy() bool AirspyHFInput::openDevice() { - if (m_dev != 0) + if (m_dev) { closeDevice(); } @@ -105,7 +105,7 @@ bool AirspyHFInput::openDevice() if ((m_dev = open_airspyhf_from_serial(m_deviceAPI->getSamplingDeviceSerial())) == 0) { qCritical("AirspyHFInput::openDevice: could not open Airspy HF with serial %s", qPrintable(m_deviceAPI->getSamplingDeviceSerial())); - m_dev = 0; + m_dev = nullptr; return false; } else @@ -226,11 +226,11 @@ void AirspyHFInput::stopWorker() void AirspyHFInput::closeDevice() { - if (m_dev != 0) + if (m_dev) { airspyhf_stop(m_dev); airspyhf_close(m_dev); - m_dev = 0; + m_dev = nullptr; } m_deviceDescription.clear(); @@ -445,7 +445,7 @@ bool AirspyHFInput::applySettings(const AirspyHFSettings& settings, bool force) sampleRateIndex = m_sampleRates.size() - 1; } - if ((m_dev != 0) && (sampleRateIndex >= 0)) + if (m_dev && (sampleRateIndex >= 0)) { rc = (airspyhf_error) airspyhf_set_samplerate(m_dev, sampleRateIndex); @@ -486,7 +486,7 @@ bool AirspyHFInput::applySettings(const AirspyHFSettings& settings, bool force) { reverseAPIKeys.append("LOppmTenths"); - if (m_dev != 0) + if (m_dev) { rc = (airspyhf_error) airspyhf_set_calibration(m_dev, settings.m_LOppmTenths * 100); @@ -520,7 +520,7 @@ bool AirspyHFInput::applySettings(const AirspyHFSettings& settings, bool force) deviceCenterFrequency = deviceCenterFrequency < 0 ? 0 : deviceCenterFrequency; qint64 f_img = deviceCenterFrequency; - if ((m_dev != 0) && (sampleRateIndex >= 0)) + if (m_dev && (sampleRateIndex >= 0)) { quint32 devSampleRate = m_sampleRates[sampleRateIndex]; setDeviceCenterFrequency(deviceCenterFrequency, settings); @@ -539,7 +539,7 @@ bool AirspyHFInput::applySettings(const AirspyHFSettings& settings, bool force) { reverseAPIKeys.append("useAGC"); - if (m_dev != 0) + if (m_dev) { rc = (airspyhf_error) airspyhf_set_hf_agc(m_dev, settings.m_useAGC ? 1 : 0); @@ -555,7 +555,7 @@ bool AirspyHFInput::applySettings(const AirspyHFSettings& settings, bool force) { reverseAPIKeys.append("agcHigh"); - if (m_dev != 0) + if (m_dev) { rc = (airspyhf_error) airspyhf_set_hf_agc_threshold(m_dev, settings.m_agcHigh ? 1 : 0); @@ -571,7 +571,7 @@ bool AirspyHFInput::applySettings(const AirspyHFSettings& settings, bool force) { reverseAPIKeys.append("useDSP"); - if (m_dev != 0) + if (m_dev) { rc = (airspyhf_error) airspyhf_set_lib_dsp(m_dev, settings.m_useDSP ? 1 : 0); @@ -587,7 +587,7 @@ bool AirspyHFInput::applySettings(const AirspyHFSettings& settings, bool force) { reverseAPIKeys.append("useLNA"); - if (m_dev != 0) + if (m_dev) { rc = (airspyhf_error) airspyhf_set_hf_lna(m_dev, settings.m_useLNA ? 1 : 0); @@ -603,7 +603,7 @@ bool AirspyHFInput::applySettings(const AirspyHFSettings& settings, bool force) { reverseAPIKeys.append("attenuatorSteps"); - if (m_dev != 0) + if (m_dev) { rc = (airspyhf_error) airspyhf_set_hf_att(m_dev, settings.m_attenuatorSteps); @@ -615,7 +615,7 @@ bool AirspyHFInput::applySettings(const AirspyHFSettings& settings, bool force) } } - if (forwardChange && (sampleRateIndex >= 0)) + if (forwardChange && (m_sampleRates.size() != 0) && (sampleRateIndex >= 0)) { int sampleRate = m_sampleRates[sampleRateIndex]/(1<Interface +The top and bottom bars of the device window are described [here](../../../sdrgui/device/readme.md) + For controls 10 to 13 to be effective you will need a recent version (up to date in January 2019) of both libairspy and the firmware. ![AirspyHF input plugin GUI](../../../doc/img/AirspyHFInput_plugin.png) diff --git a/plugins/samplesource/audioinput/audioinputgui.cpp b/plugins/samplesource/audioinput/audioinputgui.cpp index 10983f562..71544fe44 100644 --- a/plugins/samplesource/audioinput/audioinputgui.cpp +++ b/plugins/samplesource/audioinput/audioinputgui.cpp @@ -18,11 +18,11 @@ #include #include +#include #include "ui_audioinputgui.h" #include "gui/colormapper.h" #include "gui/glspectrum.h" -#include "gui/crightclickenabler.h" #include "gui/basicdevicesettingsdialog.h" #include "dsp/dspengine.h" #include "dsp/dspcommands.h" @@ -34,22 +34,25 @@ AudioInputGui::AudioInputGui(DeviceUISet *deviceUISet, QWidget* parent) : DeviceGUI(parent), ui(new Ui::AudioInputGui), - m_deviceUISet(deviceUISet), m_forceSettings(true), m_settings(), m_sampleSource(nullptr), m_centerFrequency(0) { + m_deviceUISet = deviceUISet; + setAttribute(Qt::WA_DeleteOnClose, true); m_sampleSource = (AudioInput*) m_deviceUISet->m_deviceAPI->getSampleSource(); - ui->setupUi(this); + ui->setupUi(getContents()); + setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); + getContents()->setStyleSheet("#AudioInputGui { background-color: rgb(64, 64, 64); }"); + m_helpURL = "plugins/samplesource/audioinput/readme.md"; connect(&m_updateTimer, SIGNAL(timeout()), this, SLOT(updateHardware())); - - CRightClickEnabler *startStopRightClickEnabler = new CRightClickEnabler(ui->startStop); - connect(startStopRightClickEnabler, SIGNAL(rightClick(const QPoint &)), this, SLOT(openDeviceSettingsDialog(const QPoint &))); + connect(this, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(openDeviceSettingsDialog(const QPoint &))); displaySettings(); + makeUIConnections(); connect(&m_inputMessageQueue, SIGNAL(messageEnqueued()), this, SLOT(handleInputMessages()), Qt::QueuedConnection); m_sampleSource->setMessageQueueToGUI(&m_inputMessageQueue); @@ -93,6 +96,12 @@ bool AudioInputGui::deserialize(const QByteArray& data) } } +void AudioInputGui::resizeEvent(QResizeEvent* size) +{ + adjustSize(); + size->accept(); +} + bool AudioInputGui::handleMessage(const Message& message) { if (AudioInput::MsgConfigureAudioInput::match(message)) @@ -290,19 +299,34 @@ void AudioInputGui::updateHardware() void AudioInputGui::openDeviceSettingsDialog(const QPoint& p) { - BasicDeviceSettingsDialog dialog(this); - dialog.setUseReverseAPI(m_settings.m_useReverseAPI); - dialog.setReverseAPIAddress(m_settings.m_reverseAPIAddress); - dialog.setReverseAPIPort(m_settings.m_reverseAPIPort); - dialog.setReverseAPIDeviceIndex(m_settings.m_reverseAPIDeviceIndex); + if (m_contextMenuType == ContextMenuDeviceSettings) + { + BasicDeviceSettingsDialog dialog(this); + dialog.setUseReverseAPI(m_settings.m_useReverseAPI); + dialog.setReverseAPIAddress(m_settings.m_reverseAPIAddress); + dialog.setReverseAPIPort(m_settings.m_reverseAPIPort); + dialog.setReverseAPIDeviceIndex(m_settings.m_reverseAPIDeviceIndex); - dialog.move(p); - dialog.exec(); + dialog.move(p); + dialog.exec(); - m_settings.m_useReverseAPI = dialog.useReverseAPI(); - m_settings.m_reverseAPIAddress = dialog.getReverseAPIAddress(); - m_settings.m_reverseAPIPort = dialog.getReverseAPIPort(); - m_settings.m_reverseAPIDeviceIndex = dialog.getReverseAPIDeviceIndex(); + m_settings.m_useReverseAPI = dialog.useReverseAPI(); + m_settings.m_reverseAPIAddress = dialog.getReverseAPIAddress(); + m_settings.m_reverseAPIPort = dialog.getReverseAPIPort(); + m_settings.m_reverseAPIDeviceIndex = dialog.getReverseAPIDeviceIndex(); - sendSettings(); + sendSettings(); + } + + resetContextMenuType(); +} + +void AudioInputGui::makeUIConnections() +{ + QObject::connect(ui->device, QOverload::of(&QComboBox::currentIndexChanged), this, &AudioInputGui::on_device_currentIndexChanged); + QObject::connect(ui->sampleRate, QOverload::of(&QComboBox::currentIndexChanged), this, &AudioInputGui::on_sampleRate_currentIndexChanged); + QObject::connect(ui->decim, QOverload::of(&QComboBox::currentIndexChanged), this, &AudioInputGui::on_decim_currentIndexChanged); + QObject::connect(ui->volume, &QDial::valueChanged, this, &AudioInputGui::on_volume_valueChanged); + QObject::connect(ui->channels, QOverload::of(&QComboBox::currentIndexChanged), this, &AudioInputGui::on_channels_currentIndexChanged); + QObject::connect(ui->startStop, &ButtonSwitch::toggled, this, &AudioInputGui::on_startStop_toggled); } diff --git a/plugins/samplesource/audioinput/audioinputgui.h b/plugins/samplesource/audioinput/audioinputgui.h index 1976091d4..fd50166f4 100644 --- a/plugins/samplesource/audioinput/audioinputgui.h +++ b/plugins/samplesource/audioinput/audioinputgui.h @@ -47,10 +47,12 @@ public: bool deserialize(const QByteArray& data); virtual MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; } +protected: + void resizeEvent(QResizeEvent* size); + private: Ui::AudioInputGui* ui; - DeviceUISet* m_deviceUISet; bool m_doApplySettings; bool m_forceSettings; AudioInputSettings m_settings; @@ -68,6 +70,7 @@ private: void sendSettings(); void updateSampleRateAndFrequency(); bool handleMessage(const Message& message); + void makeUIConnections(); private slots: void handleInputMessages(); diff --git a/plugins/samplesource/audioinput/audioinputgui.ui b/plugins/samplesource/audioinput/audioinputgui.ui index f2081a25e..0559cd88e 100644 --- a/plugins/samplesource/audioinput/audioinputgui.ui +++ b/plugins/samplesource/audioinput/audioinputgui.ui @@ -6,20 +6,26 @@ 0 0 - 320 - 350 + 360 + 191
- + 0 0 - 320 - 350 + 360 + 191 + + + + + 380 + 191 @@ -29,7 +35,7 @@
- FunCubeDongle + Audio @@ -49,15 +55,18 @@ - - 4 - + + + 0 + 0 + + start/stop acquisition @@ -105,6 +114,31 @@ + + + + + 0 + 0 + + + + + 5 + 32 + + + + + 5 + 32 + + + + + + + @@ -358,23 +392,6 @@ - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - diff --git a/plugins/samplesource/audioinput/readme.md b/plugins/samplesource/audioinput/readme.md index 9767705b4..08e70b8c9 100644 --- a/plugins/samplesource/audioinput/readme.md +++ b/plugins/samplesource/audioinput/readme.md @@ -6,6 +6,8 @@ This input sample source plugin gets its samples from an audio device.

Interface

+The top and bottom bars of the device window are described [here](../../../sdrgui/device/readme.md) + ![Audio input plugin GUI](../../../doc/img/AudioInput_plugin.png)

1: Start/Stop

diff --git a/plugins/samplesource/bladerf1input/bladerf1inputgui.cpp b/plugins/samplesource/bladerf1input/bladerf1inputgui.cpp index 8745d2622..e5fadcdbd 100644 --- a/plugins/samplesource/bladerf1input/bladerf1inputgui.cpp +++ b/plugins/samplesource/bladerf1input/bladerf1inputgui.cpp @@ -18,13 +18,13 @@ #include #include #include +#include #include #include "ui_bladerf1inputgui.h" #include "gui/colormapper.h" #include "gui/glspectrum.h" -#include "gui/crightclickenabler.h" #include "gui/basicdevicesettingsdialog.h" #include "dsp/dspengine.h" #include "dsp/dspcommands.h" @@ -36,7 +36,6 @@ Bladerf1InputGui::Bladerf1InputGui(DeviceUISet *deviceUISet, QWidget* parent) : DeviceGUI(parent), ui(new Ui::Bladerf1InputGui), - m_deviceUISet(deviceUISet), m_forceSettings(true), m_doApplySettings(true), m_settings(), @@ -45,9 +44,14 @@ Bladerf1InputGui::Bladerf1InputGui(DeviceUISet *deviceUISet, QWidget* parent) : m_sampleRate(0), m_lastEngineState(DeviceAPI::StNotStarted) { + m_deviceUISet = deviceUISet; + setAttribute(Qt::WA_DeleteOnClose, true); m_sampleSource = (Bladerf1Input*) m_deviceUISet->m_deviceAPI->getSampleSource(); - ui->setupUi(this); + ui->setupUi(getContents()); + setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); + getContents()->setStyleSheet("#Bladerf1InputGui { background-color: rgb(64, 64, 64); }"); + m_helpURL = "plugins/samplesource/bladerf1input/readme.md"; ui->centerFrequency->setColorMapper(ColorMapper(ColorMapper::GrayGold)); ui->centerFrequency->setValueRange(7, BLADERF_FREQUENCY_MIN_XB200/1000, BLADERF_FREQUENCY_MAX/1000); @@ -65,8 +69,7 @@ Bladerf1InputGui::Bladerf1InputGui(DeviceUISet *deviceUISet, QWidget* parent) : connect(&m_statusTimer, SIGNAL(timeout()), this, SLOT(updateStatus())); m_statusTimer.start(500); - CRightClickEnabler *startStopRightClickEnabler = new CRightClickEnabler(ui->startStop); - connect(startStopRightClickEnabler, SIGNAL(rightClick(const QPoint &)), this, SLOT(openDeviceSettingsDialog(const QPoint &))); + connect(this, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(openDeviceSettingsDialog(const QPoint &))); displaySettings(); @@ -74,6 +77,7 @@ Bladerf1InputGui::Bladerf1InputGui(DeviceUISet *deviceUISet, QWidget* parent) : m_sampleSource->setMessageQueueToGUI(&m_inputMessageQueue); sendSettings(); + makeUIConnections(); } Bladerf1InputGui::~Bladerf1InputGui() @@ -111,6 +115,12 @@ bool Bladerf1InputGui::deserialize(const QByteArray& data) } } +void Bladerf1InputGui::resizeEvent(QResizeEvent* size) +{ + adjustSize(); + size->accept(); +} + bool Bladerf1InputGui::handleMessage(const Message& message) { if (Bladerf1Input::MsgConfigureBladerf1::match(message)) @@ -509,19 +519,38 @@ unsigned int Bladerf1InputGui::getXb200Index(bool xb_200, bladerf_xb200_path xb2 void Bladerf1InputGui::openDeviceSettingsDialog(const QPoint& p) { - BasicDeviceSettingsDialog dialog(this); - dialog.setUseReverseAPI(m_settings.m_useReverseAPI); - dialog.setReverseAPIAddress(m_settings.m_reverseAPIAddress); - dialog.setReverseAPIPort(m_settings.m_reverseAPIPort); - dialog.setReverseAPIDeviceIndex(m_settings.m_reverseAPIDeviceIndex); + if (m_contextMenuType == ContextMenuDeviceSettings) + { + BasicDeviceSettingsDialog dialog(this); + dialog.setUseReverseAPI(m_settings.m_useReverseAPI); + dialog.setReverseAPIAddress(m_settings.m_reverseAPIAddress); + dialog.setReverseAPIPort(m_settings.m_reverseAPIPort); + dialog.setReverseAPIDeviceIndex(m_settings.m_reverseAPIDeviceIndex); - dialog.move(p); - dialog.exec(); + dialog.move(p); + dialog.exec(); - m_settings.m_useReverseAPI = dialog.useReverseAPI(); - m_settings.m_reverseAPIAddress = dialog.getReverseAPIAddress(); - m_settings.m_reverseAPIPort = dialog.getReverseAPIPort(); - m_settings.m_reverseAPIDeviceIndex = dialog.getReverseAPIDeviceIndex(); + m_settings.m_useReverseAPI = dialog.useReverseAPI(); + m_settings.m_reverseAPIAddress = dialog.getReverseAPIAddress(); + m_settings.m_reverseAPIPort = dialog.getReverseAPIPort(); + m_settings.m_reverseAPIDeviceIndex = dialog.getReverseAPIDeviceIndex(); - sendSettings(); + sendSettings(); + } + + resetContextMenuType(); +} + +void Bladerf1InputGui::makeUIConnections() +{ + QObject::connect(ui->centerFrequency, &ValueDial::changed, this, &Bladerf1InputGui::on_centerFrequency_changed); + QObject::connect(ui->sampleRate, &ValueDial::changed, this, &Bladerf1InputGui::on_sampleRate_changed); + QObject::connect(ui->dcOffset, &ButtonSwitch::toggled, this, &Bladerf1InputGui::on_dcOffset_toggled); + QObject::connect(ui->iqImbalance, &ButtonSwitch::toggled, this, &Bladerf1InputGui::on_iqImbalance_toggled); + QObject::connect(ui->bandwidth, QOverload::of(&QComboBox::currentIndexChanged), this, &Bladerf1InputGui::on_bandwidth_currentIndexChanged); + QObject::connect(ui->decim, QOverload::of(&QComboBox::currentIndexChanged), this, &Bladerf1InputGui::on_decim_currentIndexChanged); + QObject::connect(ui->lna, QOverload::of(&QComboBox::currentIndexChanged), this, &Bladerf1InputGui::on_lna_currentIndexChanged); + QObject::connect(ui->fcPos, QOverload::of(&QComboBox::currentIndexChanged), this, &Bladerf1InputGui::on_fcPos_currentIndexChanged); + QObject::connect(ui->startStop, &ButtonSwitch::toggled, this, &Bladerf1InputGui::on_startStop_toggled); + QObject::connect(ui->sampleRateMode, &QToolButton::toggled, this, &Bladerf1InputGui::on_sampleRateMode_toggled); } diff --git a/plugins/samplesource/bladerf1input/bladerf1inputgui.h b/plugins/samplesource/bladerf1input/bladerf1inputgui.h index 27ea2d695..106afe231 100644 --- a/plugins/samplesource/bladerf1input/bladerf1inputgui.h +++ b/plugins/samplesource/bladerf1input/bladerf1inputgui.h @@ -48,7 +48,6 @@ public: private: Ui::Bladerf1InputGui* ui; - DeviceUISet* m_deviceUISet; bool m_forceSettings; bool m_doApplySettings; BladeRF1InputSettings m_settings; @@ -70,6 +69,10 @@ private: void updateSampleRateAndFrequency(); void blockApplySettings(bool block); bool handleMessage(const Message& message); + void makeUIConnections(); + +protected: + void resizeEvent(QResizeEvent* size); private slots: void handleInputMessages(); diff --git a/plugins/samplesource/bladerf1input/bladerf1inputgui.ui b/plugins/samplesource/bladerf1input/bladerf1inputgui.ui index c0321330a..239cbe106 100644 --- a/plugins/samplesource/bladerf1input/bladerf1inputgui.ui +++ b/plugins/samplesource/bladerf1input/bladerf1inputgui.ui @@ -6,19 +6,25 @@ 0 0 - 310 - 265 + 360 + 173 - + 0 0 - 310 + 360 + 173 + + + + + 380 250 @@ -122,7 +128,7 @@ Liberation Mono - 20 + 16 @@ -681,30 +687,6 @@
- - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - - - Qt::Horizontal - - - diff --git a/plugins/samplesource/bladerf1input/readme.md b/plugins/samplesource/bladerf1input/readme.md index 1e3157fa0..adc814a03 100644 --- a/plugins/samplesource/bladerf1input/readme.md +++ b/plugins/samplesource/bladerf1input/readme.md @@ -19,6 +19,8 @@ The BladeRF Host library is also provided by many Linux distributions (check its

Interface

+The top and bottom bars of the device window are described [here](../../../sdrgui/device/readme.md) + ![BladeRF1 input plugin GUI](../../../doc/img/BladeRF1Input_plugin.png)

1: Common stream parameters

diff --git a/plugins/samplesource/bladerf2input/bladerf2inputgui.cpp b/plugins/samplesource/bladerf2input/bladerf2inputgui.cpp index 1705b0a8f..6511b955f 100644 --- a/plugins/samplesource/bladerf2input/bladerf2inputgui.cpp +++ b/plugins/samplesource/bladerf2input/bladerf2inputgui.cpp @@ -18,13 +18,13 @@ #include #include #include +#include #include #include "ui_bladerf2inputgui.h" #include "gui/colormapper.h" #include "gui/glspectrum.h" -#include "gui/crightclickenabler.h" #include "gui/basicdevicesettingsdialog.h" #include "dsp/dspengine.h" #include "dsp/dspcommands.h" @@ -36,7 +36,6 @@ BladeRF2InputGui::BladeRF2InputGui(DeviceUISet *deviceUISet, QWidget* parent) : DeviceGUI(parent), ui(new Ui::Bladerf2InputGui), - m_deviceUISet(deviceUISet), m_forceSettings(true), m_doApplySettings(true), m_settings(), @@ -45,12 +44,17 @@ BladeRF2InputGui::BladeRF2InputGui(DeviceUISet *deviceUISet, QWidget* parent) : m_sampleRate(0), m_lastEngineState(DeviceAPI::StNotStarted) { + m_deviceUISet = deviceUISet; + setAttribute(Qt::WA_DeleteOnClose, true); m_sampleSource = (BladeRF2Input*) m_deviceUISet->m_deviceAPI->getSampleSource(); int max, min, step; float scale; uint64_t f_min, f_max; - ui->setupUi(this); + ui->setupUi(getContents()); + setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); + getContents()->setStyleSheet("#Bladerf2InputGui { background-color: rgb(64, 64, 64); }"); + m_helpURL = "plugins/samplesource/bladerf2input/readme.md"; m_sampleSource->getFrequencyRange(f_min, f_max, step, scale); ui->centerFrequency->setColorMapper(ColorMapper(ColorMapper::GrayGold)); @@ -87,8 +91,7 @@ BladeRF2InputGui::BladeRF2InputGui(DeviceUISet *deviceUISet, QWidget* parent) : connect(&m_statusTimer, SIGNAL(timeout()), this, SLOT(updateStatus())); m_statusTimer.start(500); - CRightClickEnabler *startStopRightClickEnabler = new CRightClickEnabler(ui->startStop); - connect(startStopRightClickEnabler, SIGNAL(rightClick(const QPoint &)), this, SLOT(openDeviceSettingsDialog(const QPoint &))); + connect(this, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(openDeviceSettingsDialog(const QPoint &))); displaySettings(); @@ -96,6 +99,7 @@ BladeRF2InputGui::BladeRF2InputGui(DeviceUISet *deviceUISet, QWidget* parent) : m_sampleSource->setMessageQueueToGUI(&m_inputMessageQueue); sendSettings(); + makeUIConnections(); } BladeRF2InputGui::~BladeRF2InputGui() @@ -133,6 +137,12 @@ bool BladeRF2InputGui::deserialize(const QByteArray& data) } } +void BladeRF2InputGui::resizeEvent(QResizeEvent* size) +{ + adjustSize(); + size->accept(); +} + void BladeRF2InputGui::updateFrequencyLimits() { // values in kHz @@ -510,21 +520,26 @@ void BladeRF2InputGui::updateStatus() void BladeRF2InputGui::openDeviceSettingsDialog(const QPoint& p) { - BasicDeviceSettingsDialog dialog(this); - dialog.setUseReverseAPI(m_settings.m_useReverseAPI); - dialog.setReverseAPIAddress(m_settings.m_reverseAPIAddress); - dialog.setReverseAPIPort(m_settings.m_reverseAPIPort); - dialog.setReverseAPIDeviceIndex(m_settings.m_reverseAPIDeviceIndex); + if (m_contextMenuType == ContextMenuDeviceSettings) + { + BasicDeviceSettingsDialog dialog(this); + dialog.setUseReverseAPI(m_settings.m_useReverseAPI); + dialog.setReverseAPIAddress(m_settings.m_reverseAPIAddress); + dialog.setReverseAPIPort(m_settings.m_reverseAPIPort); + dialog.setReverseAPIDeviceIndex(m_settings.m_reverseAPIDeviceIndex); - dialog.move(p); - dialog.exec(); + dialog.move(p); + dialog.exec(); - m_settings.m_useReverseAPI = dialog.useReverseAPI(); - m_settings.m_reverseAPIAddress = dialog.getReverseAPIAddress(); - m_settings.m_reverseAPIPort = dialog.getReverseAPIPort(); - m_settings.m_reverseAPIDeviceIndex = dialog.getReverseAPIDeviceIndex(); + m_settings.m_useReverseAPI = dialog.useReverseAPI(); + m_settings.m_reverseAPIAddress = dialog.getReverseAPIAddress(); + m_settings.m_reverseAPIPort = dialog.getReverseAPIPort(); + m_settings.m_reverseAPIDeviceIndex = dialog.getReverseAPIDeviceIndex(); - sendSettings(); + sendSettings(); + } + + resetContextMenuType(); } float BladeRF2InputGui::getGainDB(int gainValue) @@ -542,3 +557,21 @@ int BladeRF2InputGui::getGainValue(float gainDB) // gainDB, m_gainMin, m_gainMax, m_gainStep, m_gainScale, gain); return gain; } + +void BladeRF2InputGui::makeUIConnections() +{ + QObject::connect(ui->centerFrequency, &ValueDial::changed, this, &BladeRF2InputGui::on_centerFrequency_changed); + QObject::connect(ui->LOppm, &QSlider::valueChanged, this, &BladeRF2InputGui::on_LOppm_valueChanged); + QObject::connect(ui->sampleRate, &ValueDial::changed, this, &BladeRF2InputGui::on_sampleRate_changed); + QObject::connect(ui->dcOffset, &ButtonSwitch::toggled, this, &BladeRF2InputGui::on_dcOffset_toggled); + QObject::connect(ui->iqImbalance, &ButtonSwitch::toggled, this, &BladeRF2InputGui::on_iqImbalance_toggled); + QObject::connect(ui->biasTee, &ButtonSwitch::toggled, this, &BladeRF2InputGui::on_biasTee_toggled); + QObject::connect(ui->bandwidth, &ValueDial::changed, this, &BladeRF2InputGui::on_bandwidth_changed); + QObject::connect(ui->decim, QOverload::of(&QComboBox::currentIndexChanged), this, &BladeRF2InputGui::on_decim_currentIndexChanged); + QObject::connect(ui->fcPos, QOverload::of(&QComboBox::currentIndexChanged), this, &BladeRF2InputGui::on_fcPos_currentIndexChanged); + QObject::connect(ui->gainMode, QOverload::of(&QComboBox::currentIndexChanged), this, &BladeRF2InputGui::on_gainMode_currentIndexChanged); + QObject::connect(ui->gain, &QSlider::valueChanged, this, &BladeRF2InputGui::on_gain_valueChanged); + QObject::connect(ui->transverter, &TransverterButton::clicked, this, &BladeRF2InputGui::on_transverter_clicked); + QObject::connect(ui->startStop, &ButtonSwitch::toggled, this, &BladeRF2InputGui::on_startStop_toggled); + QObject::connect(ui->sampleRateMode, &QToolButton::toggled, this, &BladeRF2InputGui::on_sampleRateMode_toggled); +} diff --git a/plugins/samplesource/bladerf2input/bladerf2inputgui.h b/plugins/samplesource/bladerf2input/bladerf2inputgui.h index 98b24b8ed..517e21f3e 100644 --- a/plugins/samplesource/bladerf2input/bladerf2inputgui.h +++ b/plugins/samplesource/bladerf2input/bladerf2inputgui.h @@ -48,7 +48,6 @@ public: private: Ui::Bladerf2InputGui* ui; - DeviceUISet* m_deviceUISet; bool m_forceSettings; bool m_doApplySettings; BladeRF2InputSettings m_settings; @@ -77,6 +76,10 @@ private: int getGainValue(float gainDB); void blockApplySettings(bool block); bool handleMessage(const Message& message); + void makeUIConnections(); + +protected: + void resizeEvent(QResizeEvent* size); private slots: void handleInputMessages(); diff --git a/plugins/samplesource/bladerf2input/bladerf2inputgui.ui b/plugins/samplesource/bladerf2input/bladerf2inputgui.ui index 7ec663a32..d66972d0d 100644 --- a/plugins/samplesource/bladerf2input/bladerf2inputgui.ui +++ b/plugins/samplesource/bladerf2input/bladerf2inputgui.ui @@ -6,20 +6,26 @@ 0 0 - 350 - 220 + 360 + 172 - + 0 0 - 350 - 220 + 360 + 172 + + + + + 380 + 209 @@ -122,7 +128,7 @@ Liberation Mono - 20 + 16 @@ -549,30 +555,6 @@ - - - - Qt::Horizontal - - - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - diff --git a/plugins/samplesource/bladerf2input/readme.md b/plugins/samplesource/bladerf2input/readme.md index 99b66e1a1..30cf214ba 100644 --- a/plugins/samplesource/bladerf2input/readme.md +++ b/plugins/samplesource/bladerf2input/readme.md @@ -14,6 +14,8 @@ The BladeRF Host library is also provided by many Linux distributions (check its

Interface

+The top and bottom bars of the device window are described [here](../../../sdrgui/device/readme.md) + ![BladeRF2 input plugin GUI](../../../doc/img/BladeRF2Input_plugin.png)

1: Common stream parameters

diff --git a/plugins/samplesource/fcdpro/fcdprogui.cpp b/plugins/samplesource/fcdpro/fcdprogui.cpp index 64c1e18a9..5aa11fd48 100644 --- a/plugins/samplesource/fcdpro/fcdprogui.cpp +++ b/plugins/samplesource/fcdpro/fcdprogui.cpp @@ -17,11 +17,11 @@ #include #include +#include #include "ui_fcdprogui.h" #include "gui/colormapper.h" #include "gui/glspectrum.h" -#include "gui/crightclickenabler.h" #include "gui/basicdevicesettingsdialog.h" #include "dsp/dspengine.h" #include "dsp/dspcommands.h" @@ -35,15 +35,19 @@ FCDProGui::FCDProGui(DeviceUISet *deviceUISet, QWidget* parent) : DeviceGUI(parent), ui(new Ui::FCDProGui), - m_deviceUISet(deviceUISet), m_forceSettings(true), m_settings(), m_sampleSource(NULL), m_lastEngineState(DeviceAPI::StNotStarted) { + m_deviceUISet = deviceUISet; + setAttribute(Qt::WA_DeleteOnClose, true); m_sampleSource = (FCDProInput*) m_deviceUISet->m_deviceAPI->getSampleSource(); - ui->setupUi(this); + ui->setupUi(getContents()); + setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); + getContents()->setStyleSheet("#FCDProGui { background-color: rgb(64, 64, 64); }"); + m_helpURL = "plugins/samplesource/fcdpro/readme.md"; ui->centerFrequency->setColorMapper(ColorMapper(ColorMapper::GrayGold)); updateFrequencyLimits(); @@ -147,10 +151,10 @@ FCDProGui::FCDProGui(DeviceUISet *deviceUISet, QWidget* parent) : connect(&m_statusTimer, SIGNAL(timeout()), this, SLOT(updateStatus())); m_statusTimer.start(500); - CRightClickEnabler *startStopRightClickEnabler = new CRightClickEnabler(ui->startStop); - connect(startStopRightClickEnabler, SIGNAL(rightClick(const QPoint &)), this, SLOT(openDeviceSettingsDialog(const QPoint &))); + connect(this, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(openDeviceSettingsDialog(const QPoint &))); displaySettings(); + makeUIConnections(); connect(&m_inputMessageQueue, SIGNAL(messageEnqueued()), this, SLOT(handleInputMessages()), Qt::QueuedConnection); m_sampleSource->setMessageQueueToGUI(&m_inputMessageQueue); @@ -194,6 +198,12 @@ bool FCDProGui::deserialize(const QByteArray& data) } } +void FCDProGui::resizeEvent(QResizeEvent* size) +{ + adjustSize(); + size->accept(); +} + bool FCDProGui::handleMessage(const Message& message) { if (FCDProInput::MsgConfigureFCDPro::match(message)) @@ -534,19 +544,47 @@ void FCDProGui::updateHardware() void FCDProGui::openDeviceSettingsDialog(const QPoint& p) { - BasicDeviceSettingsDialog dialog(this); - dialog.setUseReverseAPI(m_settings.m_useReverseAPI); - dialog.setReverseAPIAddress(m_settings.m_reverseAPIAddress); - dialog.setReverseAPIPort(m_settings.m_reverseAPIPort); - dialog.setReverseAPIDeviceIndex(m_settings.m_reverseAPIDeviceIndex); + if (m_contextMenuType == ContextMenuDeviceSettings) + { + BasicDeviceSettingsDialog dialog(this); + dialog.setUseReverseAPI(m_settings.m_useReverseAPI); + dialog.setReverseAPIAddress(m_settings.m_reverseAPIAddress); + dialog.setReverseAPIPort(m_settings.m_reverseAPIPort); + dialog.setReverseAPIDeviceIndex(m_settings.m_reverseAPIDeviceIndex); - dialog.move(p); - dialog.exec(); + dialog.move(p); + dialog.exec(); - m_settings.m_useReverseAPI = dialog.useReverseAPI(); - m_settings.m_reverseAPIAddress = dialog.getReverseAPIAddress(); - m_settings.m_reverseAPIPort = dialog.getReverseAPIPort(); - m_settings.m_reverseAPIDeviceIndex = dialog.getReverseAPIDeviceIndex(); + m_settings.m_useReverseAPI = dialog.useReverseAPI(); + m_settings.m_reverseAPIAddress = dialog.getReverseAPIAddress(); + m_settings.m_reverseAPIPort = dialog.getReverseAPIPort(); + m_settings.m_reverseAPIDeviceIndex = dialog.getReverseAPIDeviceIndex(); - sendSettings(); + sendSettings(); + } + + resetContextMenuType(); +} + +void FCDProGui::makeUIConnections() +{ + QObject::connect(ui->centerFrequency, &ValueDial::changed, this, &FCDProGui::on_centerFrequency_changed); + QObject::connect(ui->ppm, &QSlider::valueChanged, this, &FCDProGui::on_ppm_valueChanged); + QObject::connect(ui->dcOffset, &ButtonSwitch::toggled, this, &FCDProGui::on_dcOffset_toggled); + QObject::connect(ui->iqImbalance, &ButtonSwitch::toggled, this, &FCDProGui::on_iqImbalance_toggled); + QObject::connect(ui->lnaGain, QOverload::of(&QComboBox::currentIndexChanged), this, &FCDProGui::on_lnaGain_currentIndexChanged); + QObject::connect(ui->rfFilter, QOverload::of(&QComboBox::currentIndexChanged), this, &FCDProGui::on_rfFilter_currentIndexChanged); + QObject::connect(ui->lnaEnhance, QOverload::of(&QComboBox::currentIndexChanged), this, &FCDProGui::on_lnaEnhance_currentIndexChanged); + QObject::connect(ui->band, QOverload::of(&QComboBox::currentIndexChanged), this, &FCDProGui::on_band_currentIndexChanged); + QObject::connect(ui->mixGain, QOverload::of(&QComboBox::currentIndexChanged), this, &FCDProGui::on_mixGain_currentIndexChanged); + QObject::connect(ui->mixFilter, QOverload::of(&QComboBox::currentIndexChanged), this, &FCDProGui::on_mixFilter_currentIndexChanged); + QObject::connect(ui->bias, QOverload::of(&QComboBox::currentIndexChanged), this, &FCDProGui::on_bias_currentIndexChanged); + QObject::connect(ui->mode, QOverload::of(&QComboBox::currentIndexChanged), this, &FCDProGui::on_mode_currentIndexChanged); + QObject::connect(ui->rcFilter, QOverload::of(&QComboBox::currentIndexChanged), this, &FCDProGui::on_rcFilter_currentIndexChanged); + QObject::connect(ui->ifFilter, QOverload::of(&QComboBox::currentIndexChanged), this, &FCDProGui::on_ifFilter_currentIndexChanged); + QObject::connect(ui->decim, QOverload::of(&QComboBox::currentIndexChanged), this, &FCDProGui::on_decim_currentIndexChanged); + QObject::connect(ui->fcPos, QOverload::of(&QComboBox::currentIndexChanged), this, &FCDProGui::on_fcPos_currentIndexChanged); + QObject::connect(ui->setDefaults, &QPushButton::clicked, this, &FCDProGui::on_setDefaults_clicked); + QObject::connect(ui->startStop, &ButtonSwitch::toggled, this, &FCDProGui::on_startStop_toggled); + QObject::connect(ui->transverter, &TransverterButton::clicked, this, &FCDProGui::on_transverter_clicked); } diff --git a/plugins/samplesource/fcdpro/fcdprogui.h b/plugins/samplesource/fcdpro/fcdprogui.h index 304dc6273..83ebe7b7f 100644 --- a/plugins/samplesource/fcdpro/fcdprogui.h +++ b/plugins/samplesource/fcdpro/fcdprogui.h @@ -49,7 +49,6 @@ public: private: Ui::FCDProGui* ui; - DeviceUISet* m_deviceUISet; bool m_doApplySettings; bool m_forceSettings; FCDProSettings m_settings; @@ -68,6 +67,10 @@ private: void updateSampleRateAndFrequency(); void updateFrequencyLimits(); bool handleMessage(const Message& message); + void makeUIConnections(); + +protected: + void resizeEvent(QResizeEvent* size); private slots: void handleInputMessages(); diff --git a/plugins/samplesource/fcdpro/fcdprogui.ui b/plugins/samplesource/fcdpro/fcdprogui.ui index feae1eeb4..394b09a1d 100644 --- a/plugins/samplesource/fcdpro/fcdprogui.ui +++ b/plugins/samplesource/fcdpro/fcdprogui.ui @@ -6,20 +6,26 @@ 0 0 - 320 - 350 + 360 + 394
- + 0 0 - 320 - 350 + 360 + 394 + + + + + 380 + 443 @@ -122,7 +128,7 @@ Liberation Mono - 20 + 16 @@ -610,23 +616,6 @@ - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - diff --git a/plugins/samplesource/fcdpro/readme.md b/plugins/samplesource/fcdpro/readme.md index 8d1f12e92..5a117c858 100644 --- a/plugins/samplesource/fcdpro/readme.md +++ b/plugins/samplesource/fcdpro/readme.md @@ -6,6 +6,8 @@ This input sample source plugin gets its samples from a [FunCube Dongle (FCD) Pr

Interface

+The top and bottom bars of the device window are described [here](../../../sdrgui/device/readme.md) + ![FCD Pro input plugin GUI](../../../doc/img/FCDPro_plugin.png)

1: Common stream parameters

diff --git a/plugins/samplesource/fcdproplus/fcdproplusgui.cpp b/plugins/samplesource/fcdproplus/fcdproplusgui.cpp index deac61bfd..8040b546e 100644 --- a/plugins/samplesource/fcdproplus/fcdproplusgui.cpp +++ b/plugins/samplesource/fcdproplus/fcdproplusgui.cpp @@ -18,11 +18,11 @@ #include #include #include +#include #include "ui_fcdproplusgui.h" #include "gui/colormapper.h" #include "gui/glspectrum.h" -#include "gui/crightclickenabler.h" #include "gui/basicdevicesettingsdialog.h" #include "dsp/dspengine.h" #include "dsp/dspcommands.h" @@ -36,15 +36,19 @@ FCDProPlusGui::FCDProPlusGui(DeviceUISet *deviceUISet, QWidget* parent) : DeviceGUI(parent), ui(new Ui::FCDProPlusGui), - m_deviceUISet(deviceUISet), m_forceSettings(true), m_settings(), m_sampleSource(NULL), m_lastEngineState(DeviceAPI::StNotStarted) { + m_deviceUISet = deviceUISet; + setAttribute(Qt::WA_DeleteOnClose, true); m_sampleSource = (FCDProPlusInput*) m_deviceUISet->m_deviceAPI->getSampleSource(); - ui->setupUi(this); + ui->setupUi(getContents()); + setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); + getContents()->setStyleSheet("#FCDProPlusGui { background-color: rgb(64, 64, 64); }"); + m_helpURL = "plugins/samplesource/fcdproplus/readme.md"; ui->centerFrequency->setColorMapper(ColorMapper(ColorMapper::GrayGold)); updateFrequencyLimits(); @@ -65,10 +69,10 @@ FCDProPlusGui::FCDProPlusGui(DeviceUISet *deviceUISet, QWidget* parent) : connect(&m_statusTimer, SIGNAL(timeout()), this, SLOT(updateStatus())); m_statusTimer.start(500); - CRightClickEnabler *startStopRightClickEnabler = new CRightClickEnabler(ui->startStop); - connect(startStopRightClickEnabler, SIGNAL(rightClick(const QPoint &)), this, SLOT(openDeviceSettingsDialog(const QPoint &))); + connect(this, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(openDeviceSettingsDialog(const QPoint &))); displaySettings(); + makeUIConnections(); connect(&m_inputMessageQueue, SIGNAL(messageEnqueued()), this, SLOT(handleInputMessages()), Qt::QueuedConnection); m_sampleSource->setMessageQueueToGUI(&m_inputMessageQueue); @@ -112,6 +116,12 @@ bool FCDProPlusGui::deserialize(const QByteArray& data) } } +void FCDProPlusGui::resizeEvent(QResizeEvent* size) +{ + adjustSize(); + size->accept(); +} + bool FCDProPlusGui::handleMessage(const Message& message) { if (FCDProPlusInput::MsgConfigureFCDProPlus::match(message)) @@ -356,19 +366,42 @@ void FCDProPlusGui::on_transverter_clicked() void FCDProPlusGui::openDeviceSettingsDialog(const QPoint& p) { - BasicDeviceSettingsDialog dialog(this); - dialog.setUseReverseAPI(m_settings.m_useReverseAPI); - dialog.setReverseAPIAddress(m_settings.m_reverseAPIAddress); - dialog.setReverseAPIPort(m_settings.m_reverseAPIPort); - dialog.setReverseAPIDeviceIndex(m_settings.m_reverseAPIDeviceIndex); + if (m_contextMenuType == ContextMenuDeviceSettings) + { + BasicDeviceSettingsDialog dialog(this); + dialog.setUseReverseAPI(m_settings.m_useReverseAPI); + dialog.setReverseAPIAddress(m_settings.m_reverseAPIAddress); + dialog.setReverseAPIPort(m_settings.m_reverseAPIPort); + dialog.setReverseAPIDeviceIndex(m_settings.m_reverseAPIDeviceIndex); - dialog.move(p); - dialog.exec(); + dialog.move(p); + dialog.exec(); - m_settings.m_useReverseAPI = dialog.useReverseAPI(); - m_settings.m_reverseAPIAddress = dialog.getReverseAPIAddress(); - m_settings.m_reverseAPIPort = dialog.getReverseAPIPort(); - m_settings.m_reverseAPIDeviceIndex = dialog.getReverseAPIDeviceIndex(); + m_settings.m_useReverseAPI = dialog.useReverseAPI(); + m_settings.m_reverseAPIAddress = dialog.getReverseAPIAddress(); + m_settings.m_reverseAPIPort = dialog.getReverseAPIPort(); + m_settings.m_reverseAPIDeviceIndex = dialog.getReverseAPIDeviceIndex(); - sendSettings(); + sendSettings(); + } + + resetContextMenuType(); +} + +void FCDProPlusGui::makeUIConnections() +{ + QObject::connect(ui->centerFrequency, &ValueDial::changed, this, &FCDProPlusGui::on_centerFrequency_changed); + QObject::connect(ui->decim, QOverload::of(&QComboBox::currentIndexChanged), this, &FCDProPlusGui::on_decim_currentIndexChanged); + QObject::connect(ui->fcPos, QOverload::of(&QComboBox::currentIndexChanged), this, &FCDProPlusGui::on_fcPos_currentIndexChanged); + QObject::connect(ui->dcOffset, &ButtonSwitch::toggled, this, &FCDProPlusGui::on_dcOffset_toggled); + QObject::connect(ui->iqImbalance, &ButtonSwitch::toggled, this, &FCDProPlusGui::on_iqImbalance_toggled); + QObject::connect(ui->checkBoxG, &QCheckBox::stateChanged, this, &FCDProPlusGui::on_checkBoxG_stateChanged); + QObject::connect(ui->checkBoxB, &QCheckBox::stateChanged, this, &FCDProPlusGui::on_checkBoxB_stateChanged); + QObject::connect(ui->mixGain, &QCheckBox::stateChanged, this, &FCDProPlusGui::on_mixGain_stateChanged); + QObject::connect(ui->ifGain, &QSlider::valueChanged, this, &FCDProPlusGui::on_ifGain_valueChanged); + QObject::connect(ui->filterRF, QOverload::of(&QComboBox::currentIndexChanged), this, &FCDProPlusGui::on_filterRF_currentIndexChanged); + QObject::connect(ui->filterIF, QOverload::of(&QComboBox::currentIndexChanged), this, &FCDProPlusGui::on_filterIF_currentIndexChanged); + QObject::connect(ui->ppm, &QSlider::valueChanged, this, &FCDProPlusGui::on_ppm_valueChanged); + QObject::connect(ui->startStop, &ButtonSwitch::toggled, this, &FCDProPlusGui::on_startStop_toggled); + QObject::connect(ui->transverter, &TransverterButton::clicked, this, &FCDProPlusGui::on_transverter_clicked); } diff --git a/plugins/samplesource/fcdproplus/fcdproplusgui.h b/plugins/samplesource/fcdproplus/fcdproplusgui.h index 5a628f218..9cbae0f75 100644 --- a/plugins/samplesource/fcdproplus/fcdproplusgui.h +++ b/plugins/samplesource/fcdproplus/fcdproplusgui.h @@ -48,7 +48,6 @@ public: private: Ui::FCDProPlusGui* ui; - DeviceUISet* m_deviceUISet; bool m_doApplySettings; bool m_forceSettings; FCDProPlusSettings m_settings; @@ -67,6 +66,10 @@ private: void updateSampleRateAndFrequency(); void updateFrequencyLimits(); bool handleMessage(const Message& message); + void makeUIConnections(); + +protected: + void resizeEvent(QResizeEvent* size); private slots: void handleInputMessages(); diff --git a/plugins/samplesource/fcdproplus/fcdproplusgui.ui b/plugins/samplesource/fcdproplus/fcdproplusgui.ui index 8c414c5ed..6c70b2ab0 100644 --- a/plugins/samplesource/fcdproplus/fcdproplusgui.ui +++ b/plugins/samplesource/fcdproplus/fcdproplusgui.ui @@ -6,20 +6,26 @@ 0 0 - 320 - 180 + 360 + 162
- + 0 0 - 320 - 180 + 360 + 162 + + + + + 380 + 219 @@ -122,7 +128,7 @@ Liberation Mono - 20 + 16 @@ -452,23 +458,6 @@ - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - diff --git a/plugins/samplesource/fcdproplus/readme.md b/plugins/samplesource/fcdproplus/readme.md index 3a775ada1..8c75e2783 100644 --- a/plugins/samplesource/fcdproplus/readme.md +++ b/plugins/samplesource/fcdproplus/readme.md @@ -6,6 +6,8 @@ This input sample source plugin gets its samples from a [FunCube Dongle (FCD) Pr

Interface

+The top and bottom bars of the device window are described [here](../../../sdrgui/device/readme.md) + ![FCD Pro+ input plugin GUI](../../../doc/img/FCDProPlus_plugin.png)

1: Common stream parameters

@@ -80,4 +82,4 @@ This controls the tuner filter (band) used:

11: IF filter

-Selects the IF filter bandwidth \ No newline at end of file +Selects the IF filter bandwidth diff --git a/plugins/samplesource/fileinput/fileinputgui.cpp b/plugins/samplesource/fileinput/fileinputgui.cpp index 15ee71c2b..4e0d95d7e 100644 --- a/plugins/samplesource/fileinput/fileinputgui.cpp +++ b/plugins/samplesource/fileinput/fileinputgui.cpp @@ -22,12 +22,12 @@ #include #include #include +#include #include "ui_fileinputgui.h" #include "plugin/pluginapi.h" #include "gui/colormapper.h" #include "gui/glspectrum.h" -#include "gui/crightclickenabler.h" #include "gui/basicdevicesettingsdialog.h" #include "dsp/dspengine.h" #include "dsp/dspcommands.h" @@ -41,7 +41,6 @@ FileInputGUI::FileInputGUI(DeviceUISet *deviceUISet, QWidget* parent) : DeviceGUI(parent), ui(new Ui::FileInputGUI), - m_deviceUISet(deviceUISet), m_settings(), m_doApplySettings(true), m_sampleSource(0), @@ -55,15 +54,19 @@ FileInputGUI::FileInputGUI(DeviceUISet *deviceUISet, QWidget* parent) : m_enableNavTime(false), m_lastEngineState(DeviceAPI::StNotStarted) { - ui->setupUi(this); + m_deviceUISet = deviceUISet; + setAttribute(Qt::WA_DeleteOnClose, true); + ui->setupUi(getContents()); + setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); + getContents()->setStyleSheet("#FileInputGUI { background-color: rgb(64, 64, 64); }"); + m_helpURL = "plugins/samplesource/fileinput/readme.md"; ui->crcLabel->setStyleSheet("QLabel { background:rgb(79,79,79); }"); connect(&(m_deviceUISet->m_deviceAPI->getMasterTimer()), SIGNAL(timeout()), this, SLOT(tick())); connect(&m_statusTimer, SIGNAL(timeout()), this, SLOT(updateStatus())); m_statusTimer.start(500); - CRightClickEnabler *startStopRightClickEnabler = new CRightClickEnabler(ui->startStop); - connect(startStopRightClickEnabler, SIGNAL(rightClick(const QPoint &)), this, SLOT(openDeviceSettingsDialog(const QPoint &))); + connect(this, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(openDeviceSettingsDialog(const QPoint &))); setAccelerationCombo(); displaySettings(); @@ -75,11 +78,15 @@ FileInputGUI::FileInputGUI(DeviceUISet *deviceUISet, QWidget* parent) : connect(&m_inputMessageQueue, SIGNAL(messageEnqueued()), this, SLOT(handleInputMessages()), Qt::QueuedConnection); m_sampleSource->setMessageQueueToGUI(&m_inputMessageQueue); + + makeUIConnections(); } FileInputGUI::~FileInputGUI() { + qDebug("FileInputGUI::~FileInputGUI"); delete ui; + qDebug("FileInputGUI::~FileInputGUI: end"); } void FileInputGUI::destroy() @@ -111,6 +118,12 @@ bool FileInputGUI::deserialize(const QByteArray& data) } } +void FileInputGUI::resizeEvent(QResizeEvent* size) +{ + adjustSize(); + size->accept(); +} + void FileInputGUI::handleInputMessages() { Message* message; @@ -428,19 +441,34 @@ void FileInputGUI::setNumberStr(int n, QString& s) void FileInputGUI::openDeviceSettingsDialog(const QPoint& p) { - BasicDeviceSettingsDialog dialog(this); - dialog.setUseReverseAPI(m_settings.m_useReverseAPI); - dialog.setReverseAPIAddress(m_settings.m_reverseAPIAddress); - dialog.setReverseAPIPort(m_settings.m_reverseAPIPort); - dialog.setReverseAPIDeviceIndex(m_settings.m_reverseAPIDeviceIndex); + if (m_contextMenuType == ContextMenuDeviceSettings) + { + BasicDeviceSettingsDialog dialog(this); + dialog.setUseReverseAPI(m_settings.m_useReverseAPI); + dialog.setReverseAPIAddress(m_settings.m_reverseAPIAddress); + dialog.setReverseAPIPort(m_settings.m_reverseAPIPort); + dialog.setReverseAPIDeviceIndex(m_settings.m_reverseAPIDeviceIndex); - dialog.move(p); - dialog.exec(); + dialog.move(p); + dialog.exec(); - m_settings.m_useReverseAPI = dialog.useReverseAPI(); - m_settings.m_reverseAPIAddress = dialog.getReverseAPIAddress(); - m_settings.m_reverseAPIPort = dialog.getReverseAPIPort(); - m_settings.m_reverseAPIDeviceIndex = dialog.getReverseAPIDeviceIndex(); + m_settings.m_useReverseAPI = dialog.useReverseAPI(); + m_settings.m_reverseAPIAddress = dialog.getReverseAPIAddress(); + m_settings.m_reverseAPIPort = dialog.getReverseAPIPort(); + m_settings.m_reverseAPIDeviceIndex = dialog.getReverseAPIDeviceIndex(); - sendSettings(); + sendSettings(); + } + + resetContextMenuType(); +} + +void FileInputGUI::makeUIConnections() +{ + QObject::connect(ui->startStop, &ButtonSwitch::toggled, this, &FileInputGUI::on_startStop_toggled); + QObject::connect(ui->playLoop, &ButtonSwitch::toggled, this, &FileInputGUI::on_playLoop_toggled); + QObject::connect(ui->play, &ButtonSwitch::toggled, this, &FileInputGUI::on_play_toggled); + QObject::connect(ui->navTimeSlider, &QSlider::valueChanged, this, &FileInputGUI::on_navTimeSlider_valueChanged); + QObject::connect(ui->showFileDialog, &QPushButton::clicked, this, &FileInputGUI::on_showFileDialog_clicked); + QObject::connect(ui->acceleration, QOverload::of(&QComboBox::currentIndexChanged), this, &FileInputGUI::on_acceleration_currentIndexChanged); } diff --git a/plugins/samplesource/fileinput/fileinputgui.h b/plugins/samplesource/fileinput/fileinputgui.h index 2b5dae4b9..78dc0b338 100644 --- a/plugins/samplesource/fileinput/fileinputgui.h +++ b/plugins/samplesource/fileinput/fileinputgui.h @@ -37,7 +37,7 @@ class FileInputGUI : public DeviceGUI { Q_OBJECT public: - explicit FileInputGUI(DeviceUISet *deviceUISet, QWidget* parent = 0); + explicit FileInputGUI(DeviceUISet *deviceUISet, QWidget* parent = nullptr); virtual ~FileInputGUI(); virtual void destroy(); @@ -47,10 +47,12 @@ public: virtual MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; } virtual bool handleMessage(const Message& message); +protected: + void resizeEvent(QResizeEvent* size); + private: Ui::FileInputGUI* ui; - DeviceUISet* m_deviceUISet; FileInputSettings m_settings; bool m_doApplySettings; QTimer m_statusTimer; @@ -81,6 +83,7 @@ private: void updateWithStreamTime(); void setAccelerationCombo(); void setNumberStr(int n, QString& s); + void makeUIConnections(); private slots: void handleInputMessages(); diff --git a/plugins/samplesource/fileinput/fileinputgui.ui b/plugins/samplesource/fileinput/fileinputgui.ui index 6d9c9bbde..75136ae6e 100644 --- a/plugins/samplesource/fileinput/fileinputgui.ui +++ b/plugins/samplesource/fileinput/fileinputgui.ui @@ -6,20 +6,26 @@ 0 0 - 377 - 190 + 360 + 202
- + 0 0 - 246 - 190 + 360 + 202 + + + + + 380 + 202 @@ -52,9 +58,6 @@ - - 4 - @@ -592,23 +595,6 @@ - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - diff --git a/plugins/samplesource/fileinput/readme.md b/plugins/samplesource/fileinput/readme.md index 447d7de8e..f0dad6dd3 100644 --- a/plugins/samplesource/fileinput/readme.md +++ b/plugins/samplesource/fileinput/readme.md @@ -48,6 +48,8 @@ The header takes an integer number of 16 (4 bytes) or 24 (8 bytes) bits samples.

Interface

+The top and bottom bars of the device window are described [here](../../../sdrgui/device/readme.md) + ![File input plugin GUI](../../../doc/img/FileInput_plugin.png)

1: Start/Stop

diff --git a/plugins/samplesource/hackrfinput/hackrfinput.cpp b/plugins/samplesource/hackrfinput/hackrfinput.cpp index 9f7b4bcd9..4eb5a4ead 100644 --- a/plugins/samplesource/hackrfinput/hackrfinput.cpp +++ b/plugins/samplesource/hackrfinput/hackrfinput.cpp @@ -87,7 +87,7 @@ void HackRFInput::destroy() bool HackRFInput::openDevice() { - if (m_dev != 0) + if (m_dev) { closeDevice(); } @@ -109,7 +109,7 @@ bool HackRFInput::openDevice() return false; } - if (buddySharedParams->m_dev == 0) // device is not opened by buddy + if (buddySharedParams->m_dev == nullptr) // device is not opened by buddy { qCritical("HackRFInput::openDevice: could not get HackRF handle from buddy"); return false; @@ -123,12 +123,14 @@ bool HackRFInput::openDevice() if ((m_dev = DeviceHackRF::open_hackrf(qPrintable(m_deviceAPI->getSamplingDeviceSerial()))) == 0) { qCritical("HackRFInput::openDevice: could not open HackRF %s", qPrintable(m_deviceAPI->getSamplingDeviceSerial())); + m_dev = nullptr; return false; } m_sharedParams.m_dev = m_dev; } + qDebug("HackRFInput::openDevice: success"); return true; } @@ -172,7 +174,7 @@ void HackRFInput::closeDevice() { qDebug("HackRFInput::closeDevice: closing device since Tx side is not open"); - if(m_dev != 0) // close BladeRF + if (m_dev) // close HackRF { hackrf_close(m_dev); //hackrf_exit(); // TODO: this may not work if several HackRF Devices are running concurrently. It should be handled globally in the application @@ -180,7 +182,7 @@ void HackRFInput::closeDevice() } m_sharedParams.m_dev = 0; - m_dev = 0; + m_dev = nullptr; } void HackRFInput::stop() diff --git a/plugins/samplesource/hackrfinput/hackrfinputgui.cpp b/plugins/samplesource/hackrfinput/hackrfinputgui.cpp index dda1e7139..9f0c04c44 100644 --- a/plugins/samplesource/hackrfinput/hackrfinputgui.cpp +++ b/plugins/samplesource/hackrfinput/hackrfinputgui.cpp @@ -20,12 +20,12 @@ #include #include #include +#include #include #include "gui/colormapper.h" #include "gui/glspectrum.h" -#include "gui/crightclickenabler.h" #include "gui/basicdevicesettingsdialog.h" #include "dsp/dspengine.h" #include "dsp/dspcommands.h" @@ -38,7 +38,6 @@ HackRFInputGui::HackRFInputGui(DeviceUISet *deviceUISet, QWidget* parent) : DeviceGUI(parent), ui(new Ui::HackRFInputGui), - m_deviceUISet(deviceUISet), m_settings(), m_sampleRateMode(true), m_forceSettings(true), @@ -46,9 +45,14 @@ HackRFInputGui::HackRFInputGui(DeviceUISet *deviceUISet, QWidget* parent) : m_sampleSource(NULL), m_lastEngineState(DeviceAPI::StNotStarted) { + m_deviceUISet = deviceUISet; + setAttribute(Qt::WA_DeleteOnClose, true); m_sampleSource = (HackRFInput*) m_deviceUISet->m_deviceAPI->getSampleSource(); - ui->setupUi(this); + ui->setupUi(getContents()); + setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); + getContents()->setStyleSheet("#HackRFInputGui { background-color: rgb(64, 64, 64); }"); + m_helpURL = "plugins/samplesource/hackrfinput/readme.md"; ui->centerFrequency->setColorMapper(ColorMapper(ColorMapper::GrayGold)); ui->centerFrequency->setValueRange(7, 0U, 7250000U); @@ -59,8 +63,7 @@ HackRFInputGui::HackRFInputGui(DeviceUISet *deviceUISet, QWidget* parent) : connect(&m_statusTimer, SIGNAL(timeout()), this, SLOT(updateStatus())); m_statusTimer.start(500); - CRightClickEnabler *startStopRightClickEnabler = new CRightClickEnabler(ui->startStop); - connect(startStopRightClickEnabler, SIGNAL(rightClick(const QPoint &)), this, SLOT(openDeviceSettingsDialog(const QPoint &))); + connect(this, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(openDeviceSettingsDialog(const QPoint &))); displaySettings(); displayBandwidths(); @@ -69,11 +72,14 @@ HackRFInputGui::HackRFInputGui(DeviceUISet *deviceUISet, QWidget* parent) : m_sampleSource->setMessageQueueToGUI(&m_inputMessageQueue); sendSettings(); + makeUIConnections(); } HackRFInputGui::~HackRFInputGui() { + qDebug("HackRFInputGui::~HackRFInputGui"); delete ui; + qDebug("HackRFInputGui::~HackRFInputGui: end"); } void HackRFInputGui::destroy() @@ -109,6 +115,12 @@ bool HackRFInputGui::deserialize(const QByteArray& data) } } +void HackRFInputGui::resizeEvent(QResizeEvent* size) +{ + adjustSize(); + size->accept(); +} + bool HackRFInputGui::handleMessage(const Message& message) { if (HackRFInput::MsgConfigureHackRF::match(message)) @@ -490,19 +502,44 @@ void HackRFInputGui::updateStatus() void HackRFInputGui::openDeviceSettingsDialog(const QPoint& p) { - BasicDeviceSettingsDialog dialog(this); - dialog.setUseReverseAPI(m_settings.m_useReverseAPI); - dialog.setReverseAPIAddress(m_settings.m_reverseAPIAddress); - dialog.setReverseAPIPort(m_settings.m_reverseAPIPort); - dialog.setReverseAPIDeviceIndex(m_settings.m_reverseAPIDeviceIndex); + if (m_contextMenuType == ContextMenuDeviceSettings) + { + BasicDeviceSettingsDialog dialog(this); + dialog.setUseReverseAPI(m_settings.m_useReverseAPI); + dialog.setReverseAPIAddress(m_settings.m_reverseAPIAddress); + dialog.setReverseAPIPort(m_settings.m_reverseAPIPort); + dialog.setReverseAPIDeviceIndex(m_settings.m_reverseAPIDeviceIndex); - dialog.move(p); - dialog.exec(); + dialog.move(p); + dialog.exec(); - m_settings.m_useReverseAPI = dialog.useReverseAPI(); - m_settings.m_reverseAPIAddress = dialog.getReverseAPIAddress(); - m_settings.m_reverseAPIPort = dialog.getReverseAPIPort(); - m_settings.m_reverseAPIDeviceIndex = dialog.getReverseAPIDeviceIndex(); + m_settings.m_useReverseAPI = dialog.useReverseAPI(); + m_settings.m_reverseAPIAddress = dialog.getReverseAPIAddress(); + m_settings.m_reverseAPIPort = dialog.getReverseAPIPort(); + m_settings.m_reverseAPIDeviceIndex = dialog.getReverseAPIDeviceIndex(); - sendSettings(); + sendSettings(); + } + + resetContextMenuType(); +} + +void HackRFInputGui::makeUIConnections() +{ + QObject::connect(ui->centerFrequency, &ValueDial::changed, this, &HackRFInputGui::on_centerFrequency_changed); + QObject::connect(ui->sampleRate, &ValueDial::changed, this, &HackRFInputGui::on_sampleRate_changed); + QObject::connect(ui->LOppm, &QSlider::valueChanged, this, &HackRFInputGui::on_LOppm_valueChanged); + QObject::connect(ui->dcOffset, &ButtonSwitch::toggled, this, &HackRFInputGui::on_dcOffset_toggled); + QObject::connect(ui->iqImbalance, &ButtonSwitch::toggled, this, &HackRFInputGui::on_iqImbalance_toggled); + QObject::connect(ui->autoBBF, &ButtonSwitch::toggled, this, &HackRFInputGui::on_autoBBF_toggled); + QObject::connect(ui->biasT, &QCheckBox::stateChanged, this, &HackRFInputGui::on_biasT_stateChanged); + QObject::connect(ui->decim, QOverload::of(&QComboBox::currentIndexChanged), this, &HackRFInputGui::on_decim_currentIndexChanged); + QObject::connect(ui->fcPos, QOverload::of(&QComboBox::currentIndexChanged), this, &HackRFInputGui::on_fcPos_currentIndexChanged); + QObject::connect(ui->lnaExt, &QCheckBox::stateChanged, this, &HackRFInputGui::on_lnaExt_stateChanged); + QObject::connect(ui->lna, &QSlider::valueChanged, this, &HackRFInputGui::on_lna_valueChanged); + QObject::connect(ui->bbFilter, QOverload::of(&QComboBox::currentIndexChanged), this, &HackRFInputGui::on_bbFilter_currentIndexChanged); + QObject::connect(ui->vga, &QSlider::valueChanged, this, &HackRFInputGui::on_vga_valueChanged); + QObject::connect(ui->startStop, &ButtonSwitch::toggled, this, &HackRFInputGui::on_startStop_toggled); + QObject::connect(ui->sampleRateMode, &QToolButton::toggled, this, &HackRFInputGui::on_sampleRateMode_toggled); + QObject::connect(ui->transverter, &TransverterButton::clicked, this, &HackRFInputGui::on_transverter_clicked); } diff --git a/plugins/samplesource/hackrfinput/hackrfinputgui.h b/plugins/samplesource/hackrfinput/hackrfinputgui.h index 758837920..74e293a0f 100644 --- a/plugins/samplesource/hackrfinput/hackrfinputgui.h +++ b/plugins/samplesource/hackrfinput/hackrfinputgui.h @@ -55,10 +55,12 @@ public: bool deserialize(const QByteArray& data); virtual MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; } +protected: + void resizeEvent(QResizeEvent* size); + private: Ui::HackRFInputGui* ui; - DeviceUISet* m_deviceUISet; HackRFInputSettings m_settings; bool m_sampleRateMode; //!< true: device, false: base band sample rate update mode bool m_forceSettings; @@ -80,6 +82,7 @@ private: void updateFrequencyLimits(); void blockApplySettings(bool block); bool handleMessage(const Message& message); + void makeUIConnections(); private slots: void handleInputMessages(); diff --git a/plugins/samplesource/hackrfinput/hackrfinputgui.ui b/plugins/samplesource/hackrfinput/hackrfinputgui.ui index 65d063e37..691547490 100644 --- a/plugins/samplesource/hackrfinput/hackrfinputgui.ui +++ b/plugins/samplesource/hackrfinput/hackrfinputgui.ui @@ -6,20 +6,26 @@ 0 0 - 310 - 300 + 360 + 230
- + 0 0 - 310 - 300 + 360 + 230 + + + + + 380 + 272 @@ -116,13 +122,13 @@ 32 - 50 + 0 Liberation Mono - 20 + 16 @@ -243,7 +249,7 @@ - + Bandpass Filter auto select @@ -658,23 +664,6 @@ - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - diff --git a/plugins/samplesource/hackrfinput/readme.md b/plugins/samplesource/hackrfinput/readme.md index f256e06e9..c45712d0c 100644 --- a/plugins/samplesource/hackrfinput/readme.md +++ b/plugins/samplesource/hackrfinput/readme.md @@ -6,6 +6,8 @@ This input sample source plugin gets its samples from a [HackRF device](https://

Interface

+The top and bottom bars of the device window are described [here](../../../sdrgui/device/readme.md) + ![HackRF input plugin GUI](../../../doc/img/HackRFInput_plugin.png)

1: Common stream parameters

@@ -113,4 +115,4 @@ When a device set for the same physical device is present the device center freq When the center frequency position Fc (control 8) is set to center (Cen) in both Rx and Tx the actual frequency of reception and transmission are the same. -In other cases for both frequencies to match you have to set the same sample rate and Fc position (either Inf or Sup) in the Rx and Tx. \ No newline at end of file +In other cases for both frequencies to match you have to set the same sample rate and Fc position (either Inf or Sup) in the Rx and Tx. diff --git a/plugins/samplesource/kiwisdr/kiwisdrgui.cpp b/plugins/samplesource/kiwisdr/kiwisdrgui.cpp index 886d08851..231e11c1b 100644 --- a/plugins/samplesource/kiwisdr/kiwisdrgui.cpp +++ b/plugins/samplesource/kiwisdr/kiwisdrgui.cpp @@ -23,12 +23,12 @@ #include #include #include +#include #include "ui_kiwisdrgui.h" #include "plugin/pluginapi.h" #include "gui/colormapper.h" #include "gui/glspectrum.h" -#include "gui/crightclickenabler.h" #include "gui/basicdevicesettingsdialog.h" #include "dsp/dspengine.h" #include "dsp/dspcommands.h" @@ -43,7 +43,6 @@ KiwiSDRGui::KiwiSDRGui(DeviceUISet *deviceUISet, QWidget* parent) : DeviceGUI(parent), ui(new Ui::KiwiSDRGui), - m_deviceUISet(deviceUISet), m_settings(), m_doApplySettings(true), m_forceSettings(true), @@ -52,6 +51,8 @@ KiwiSDRGui::KiwiSDRGui(DeviceUISet *deviceUISet, QWidget* parent) : m_lastEngineState(DeviceAPI::StNotStarted) { qDebug("KiwiSDRGui::KiwiSDRGui"); + m_deviceUISet = deviceUISet; + setAttribute(Qt::WA_DeleteOnClose, true); m_sampleSource = m_deviceUISet->m_deviceAPI->getSampleSource(); m_statusTooltips.push_back("Idle"); // 0 @@ -66,11 +67,15 @@ KiwiSDRGui::KiwiSDRGui(DeviceUISet *deviceUISet, QWidget* parent) : m_statusColors.push_back("rgb(232, 85, 85)"); // Error (red) m_statusColors.push_back("rgb(232, 85, 232)"); // Disconnected (magenta) - ui->setupUi(this); + ui->setupUi(getContents()); + setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); + getContents()->setStyleSheet("#KiwiSDRGui { background-color: rgb(64, 64, 64); }"); + m_helpURL = "plugins/samplesource/kiwisdr/readme.md"; ui->centerFrequency->setColorMapper(ColorMapper(ColorMapper::GrayGold)); ui->centerFrequency->setValueRange(7, 0, 9999999); displaySettings(); + makeUIConnections(); connect(&m_updateTimer, SIGNAL(timeout()), this, SLOT(updateHardware())); connect(&m_statusTimer, SIGNAL(timeout()), this, SLOT(updateStatus())); @@ -79,8 +84,7 @@ KiwiSDRGui::KiwiSDRGui(DeviceUISet *deviceUISet, QWidget* parent) : connect(&m_inputMessageQueue, SIGNAL(messageEnqueued()), this, SLOT(handleInputMessages()), Qt::QueuedConnection); m_sampleSource->setMessageQueueToGUI(&m_inputMessageQueue); - CRightClickEnabler *startStopRightClickEnabler = new CRightClickEnabler(ui->startStop); - connect(startStopRightClickEnabler, SIGNAL(rightClick(const QPoint &)), this, SLOT(openDeviceSettingsDialog(const QPoint &))); + connect(this, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(openDeviceSettingsDialog(const QPoint &))); } KiwiSDRGui::~KiwiSDRGui() @@ -118,6 +122,12 @@ bool KiwiSDRGui::deserialize(const QByteArray& data) } } +void KiwiSDRGui::resizeEvent(QResizeEvent* size) +{ + adjustSize(); + size->accept(); +} + void KiwiSDRGui::on_startStop_toggled(bool checked) { if (m_doApplySettings) @@ -297,19 +307,35 @@ void KiwiSDRGui::updateSampleRateAndFrequency() void KiwiSDRGui::openDeviceSettingsDialog(const QPoint& p) { - BasicDeviceSettingsDialog dialog(this); - dialog.setUseReverseAPI(m_settings.m_useReverseAPI); - dialog.setReverseAPIAddress(m_settings.m_reverseAPIAddress); - dialog.setReverseAPIPort(m_settings.m_reverseAPIPort); - dialog.setReverseAPIDeviceIndex(m_settings.m_reverseAPIDeviceIndex); + if (m_contextMenuType == ContextMenuDeviceSettings) + { + BasicDeviceSettingsDialog dialog(this); + dialog.setUseReverseAPI(m_settings.m_useReverseAPI); + dialog.setReverseAPIAddress(m_settings.m_reverseAPIAddress); + dialog.setReverseAPIPort(m_settings.m_reverseAPIPort); + dialog.setReverseAPIDeviceIndex(m_settings.m_reverseAPIDeviceIndex); - dialog.move(p); - dialog.exec(); + dialog.move(p); + dialog.exec(); - m_settings.m_useReverseAPI = dialog.useReverseAPI(); - m_settings.m_reverseAPIAddress = dialog.getReverseAPIAddress(); - m_settings.m_reverseAPIPort = dialog.getReverseAPIPort(); - m_settings.m_reverseAPIDeviceIndex = dialog.getReverseAPIDeviceIndex(); + m_settings.m_useReverseAPI = dialog.useReverseAPI(); + m_settings.m_reverseAPIAddress = dialog.getReverseAPIAddress(); + m_settings.m_reverseAPIPort = dialog.getReverseAPIPort(); + m_settings.m_reverseAPIDeviceIndex = dialog.getReverseAPIDeviceIndex(); - sendSettings(); + sendSettings(); + } + + resetContextMenuType(); +} + +void KiwiSDRGui::makeUIConnections() +{ + QObject::connect(ui->startStop, &ButtonSwitch::toggled, this, &KiwiSDRGui::on_startStop_toggled); + QObject::connect(ui->centerFrequency, &ValueDial::changed, this, &KiwiSDRGui::on_centerFrequency_changed); + QObject::connect(ui->gain, &QSlider::valueChanged, this, &KiwiSDRGui::on_gain_valueChanged); + QObject::connect(ui->agc, &QToolButton::toggled, this, &KiwiSDRGui::on_agc_toggled); + QObject::connect(ui->serverAddress, &QLineEdit::returnPressed, this, &KiwiSDRGui::on_serverAddress_returnPressed); + QObject::connect(ui->serverAddressApplyButton, &QPushButton::clicked, this, &KiwiSDRGui::on_serverAddressApplyButton_clicked); + QObject::connect(ui->dcBlock, &ButtonSwitch::toggled, this, &KiwiSDRGui::on_dcBlock_toggled); } diff --git a/plugins/samplesource/kiwisdr/kiwisdrgui.h b/plugins/samplesource/kiwisdr/kiwisdrgui.h index f0b08d9b2..385426c7c 100644 --- a/plugins/samplesource/kiwisdr/kiwisdrgui.h +++ b/plugins/samplesource/kiwisdr/kiwisdrgui.h @@ -47,10 +47,12 @@ public: bool deserialize(const QByteArray& data); virtual MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; } +protected: + void resizeEvent(QResizeEvent* size); + private: Ui::KiwiSDRGui* ui; - DeviceUISet* m_deviceUISet; KiwiSDRSettings m_settings; QTimer m_updateTimer; QTimer m_statusTimer; @@ -70,6 +72,7 @@ private: void sendSettings(); void updateSampleRateAndFrequency(); bool handleMessage(const Message& message); + void makeUIConnections(); private slots: void handleInputMessages(); diff --git a/plugins/samplesource/kiwisdr/kiwisdrgui.ui b/plugins/samplesource/kiwisdr/kiwisdrgui.ui index bbf6bec05..3c0cfda1d 100644 --- a/plugins/samplesource/kiwisdr/kiwisdrgui.ui +++ b/plugins/samplesource/kiwisdr/kiwisdrgui.ui @@ -7,11 +7,11 @@ 0 0 360 - 120 + 106
- + 0 0 @@ -19,7 +19,13 @@ 360 - 120 + 106 + + + + + 380 + 143 @@ -52,9 +58,6 @@ - - 4 - @@ -131,7 +134,10 @@ Liberation Mono - 20 + 16 + 50 + false + false @@ -308,19 +314,6 @@ - - - - Qt::Vertical - - - - 20 - 40 - - - - diff --git a/plugins/samplesource/kiwisdr/readme.md b/plugins/samplesource/kiwisdr/readme.md index f9896ea3d..fb0ce4998 100644 --- a/plugins/samplesource/kiwisdr/readme.md +++ b/plugins/samplesource/kiwisdr/readme.md @@ -6,6 +6,8 @@ This plugin is designed to enable connection to publicly available [KiwiSDR](htt

Interface

+The top and bottom bars of the device window are described [here](../../../sdrgui/device/readme.md) + ![KiwiSDR input plugin GUI](../../../doc/img/KiwiSDRInput_plugin.png)

1: Start/Stop

diff --git a/plugins/samplesource/limesdrinput/limesdrinputgui.cpp b/plugins/samplesource/limesdrinput/limesdrinputgui.cpp index fafdac5b8..7d71754ef 100644 --- a/plugins/samplesource/limesdrinput/limesdrinputgui.cpp +++ b/plugins/samplesource/limesdrinput/limesdrinputgui.cpp @@ -20,13 +20,13 @@ #include #include #include +#include #include #include "ui_limesdrinputgui.h" #include "gui/colormapper.h" #include "gui/glspectrum.h" -#include "gui/crightclickenabler.h" #include "gui/basicdevicesettingsdialog.h" #include "dsp/dspengine.h" #include "dsp/dspcommands.h" @@ -36,7 +36,6 @@ LimeSDRInputGUI::LimeSDRInputGUI(DeviceUISet *deviceUISet, QWidget* parent) : DeviceGUI(parent), ui(new Ui::LimeSDRInputGUI), - m_deviceUISet(deviceUISet), m_settings(), m_sampleRateMode(true), m_sampleRate(0), @@ -46,9 +45,14 @@ LimeSDRInputGUI::LimeSDRInputGUI(DeviceUISet *deviceUISet, QWidget* parent) : m_statusCounter(0), m_deviceStatusCounter(0) { + m_deviceUISet = deviceUISet; + setAttribute(Qt::WA_DeleteOnClose, true); m_limeSDRInput = (LimeSDRInput*) m_deviceUISet->m_deviceAPI->getSampleSource(); - ui->setupUi(this); + ui->setupUi(getContents()); + setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); + getContents()->setStyleSheet("#LimeSDRInputGUI { background-color: rgb(64, 64, 64); }"); + m_helpURL = "plugins/samplesource/limesdrinput/readme.md"; float minF, maxF; @@ -93,12 +97,12 @@ LimeSDRInputGUI::LimeSDRInputGUI(DeviceUISet *deviceUISet, QWidget* parent) : m_statusTimer.start(500); displaySettings(); + makeUIConnections(); connect(&m_inputMessageQueue, SIGNAL(messageEnqueued()), this, SLOT(handleInputMessages()), Qt::QueuedConnection); m_limeSDRInput->setMessageQueueToGUI(&m_inputMessageQueue); - CRightClickEnabler *startStopRightClickEnabler = new CRightClickEnabler(ui->startStop); - connect(startStopRightClickEnabler, SIGNAL(rightClick(const QPoint &)), this, SLOT(openDeviceSettingsDialog(const QPoint &))); + connect(this, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(openDeviceSettingsDialog(const QPoint &))); } LimeSDRInputGUI::~LimeSDRInputGUI() @@ -139,6 +143,12 @@ bool LimeSDRInputGUI::deserialize(const QByteArray& data) } } +void LimeSDRInputGUI::resizeEvent(QResizeEvent* size) +{ + adjustSize(); + size->accept(); +} + bool LimeSDRInputGUI::handleMessage(const Message& message) { if (LimeSDRInput::MsgConfigureLimeSDR::match(message)) @@ -702,19 +712,49 @@ void LimeSDRInputGUI::on_sampleRateMode_toggled(bool checked) void LimeSDRInputGUI::openDeviceSettingsDialog(const QPoint& p) { - BasicDeviceSettingsDialog dialog(this); - dialog.setUseReverseAPI(m_settings.m_useReverseAPI); - dialog.setReverseAPIAddress(m_settings.m_reverseAPIAddress); - dialog.setReverseAPIPort(m_settings.m_reverseAPIPort); - dialog.setReverseAPIDeviceIndex(m_settings.m_reverseAPIDeviceIndex); + if (m_contextMenuType == ContextMenuDeviceSettings) + { + BasicDeviceSettingsDialog dialog(this); + dialog.setUseReverseAPI(m_settings.m_useReverseAPI); + dialog.setReverseAPIAddress(m_settings.m_reverseAPIAddress); + dialog.setReverseAPIPort(m_settings.m_reverseAPIPort); + dialog.setReverseAPIDeviceIndex(m_settings.m_reverseAPIDeviceIndex); - dialog.move(p); - dialog.exec(); + dialog.move(p); + dialog.exec(); - m_settings.m_useReverseAPI = dialog.useReverseAPI(); - m_settings.m_reverseAPIAddress = dialog.getReverseAPIAddress(); - m_settings.m_reverseAPIPort = dialog.getReverseAPIPort(); - m_settings.m_reverseAPIDeviceIndex = dialog.getReverseAPIDeviceIndex(); + m_settings.m_useReverseAPI = dialog.useReverseAPI(); + m_settings.m_reverseAPIAddress = dialog.getReverseAPIAddress(); + m_settings.m_reverseAPIPort = dialog.getReverseAPIPort(); + m_settings.m_reverseAPIDeviceIndex = dialog.getReverseAPIDeviceIndex(); - sendSettings(); + sendSettings(); + } + + resetContextMenuType(); +} + +void LimeSDRInputGUI::makeUIConnections() +{ + QObject::connect(ui->startStop, &ButtonSwitch::toggled, this, &LimeSDRInputGUI::on_startStop_toggled); + QObject::connect(ui->centerFrequency, &ValueDial::changed, this, &LimeSDRInputGUI::on_centerFrequency_changed); + QObject::connect(ui->ncoFrequency, &ValueDialZ::changed, this, &LimeSDRInputGUI::on_ncoFrequency_changed); + QObject::connect(ui->ncoEnable, &ButtonSwitch::toggled, this, &LimeSDRInputGUI::on_ncoEnable_toggled); + QObject::connect(ui->dcOffset, &ButtonSwitch::toggled, this, &LimeSDRInputGUI::on_dcOffset_toggled); + QObject::connect(ui->iqImbalance, &ButtonSwitch::toggled, this, &LimeSDRInputGUI::on_iqImbalance_toggled); + QObject::connect(ui->sampleRate, &ValueDial::changed, this, &LimeSDRInputGUI::on_sampleRate_changed); + QObject::connect(ui->hwDecim, QOverload::of(&QComboBox::currentIndexChanged), this, &LimeSDRInputGUI::on_hwDecim_currentIndexChanged); + QObject::connect(ui->swDecim, QOverload::of(&QComboBox::currentIndexChanged), this, &LimeSDRInputGUI::on_swDecim_currentIndexChanged); + QObject::connect(ui->lpf, &ValueDial::changed, this, &LimeSDRInputGUI::on_lpf_changed); + QObject::connect(ui->lpFIREnable, &ButtonSwitch::toggled, this, &LimeSDRInputGUI::on_lpFIREnable_toggled); + QObject::connect(ui->lpFIR, &ValueDial::changed, this, &LimeSDRInputGUI::on_lpFIR_changed); + QObject::connect(ui->gainMode, QOverload::of(&QComboBox::currentIndexChanged), this, &LimeSDRInputGUI::on_gainMode_currentIndexChanged); + QObject::connect(ui->gain, &QDial::valueChanged, this, &LimeSDRInputGUI::on_gain_valueChanged); + QObject::connect(ui->lnaGain, &QDial::valueChanged, this, &LimeSDRInputGUI::on_lnaGain_valueChanged); + QObject::connect(ui->tiaGain, QOverload::of(&QComboBox::currentIndexChanged), this, &LimeSDRInputGUI::on_tiaGain_currentIndexChanged); + QObject::connect(ui->pgaGain, &QDial::valueChanged, this, &LimeSDRInputGUI::on_pgaGain_valueChanged); + QObject::connect(ui->antenna, QOverload::of(&QComboBox::currentIndexChanged), this, &LimeSDRInputGUI::on_antenna_currentIndexChanged); + QObject::connect(ui->extClock, &ExternalClockButton::clicked, this, &LimeSDRInputGUI::on_extClock_clicked); + QObject::connect(ui->transverter, &TransverterButton::clicked, this, &LimeSDRInputGUI::on_transverter_clicked); + QObject::connect(ui->sampleRateMode, &QToolButton::toggled, this, &LimeSDRInputGUI::on_sampleRateMode_toggled); } diff --git a/plugins/samplesource/limesdrinput/limesdrinputgui.h b/plugins/samplesource/limesdrinput/limesdrinputgui.h index 894230e4b..401f334cb 100644 --- a/plugins/samplesource/limesdrinput/limesdrinputgui.h +++ b/plugins/samplesource/limesdrinput/limesdrinputgui.h @@ -45,10 +45,12 @@ public: bool deserialize(const QByteArray& data); virtual MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; } +protected: + void resizeEvent(QResizeEvent* size); + private: Ui::LimeSDRInputGUI* ui; - DeviceUISet* m_deviceUISet; LimeSDRInput* m_limeSDRInput; //!< Same object as above but gives easy access to LimeSDRInput methods and attributes that are used intensively LimeSDRInputSettings m_settings; bool m_sampleRateMode; //!< true: device, false: base band sample rate update mode @@ -74,6 +76,7 @@ private: void updateFrequencyLimits(); void blockApplySettings(bool block); bool handleMessage(const Message& message); + void makeUIConnections(); private slots: void handleInputMessages(); diff --git a/plugins/samplesource/limesdrinput/limesdrinputgui.ui b/plugins/samplesource/limesdrinput/limesdrinputgui.ui index 2d9d98b37..6c18b71f2 100644 --- a/plugins/samplesource/limesdrinput/limesdrinputgui.ui +++ b/plugins/samplesource/limesdrinput/limesdrinputgui.ui @@ -6,8 +6,8 @@ 0 0 - 360 - 290 + 370 + 209
@@ -18,8 +18,14 @@ - 360 - 290 + 370 + 209 + + + + + 390 + 266 @@ -128,7 +134,7 @@ Liberation Mono - 20 + 16 50 false @@ -1080,6 +1086,7 @@ + Ubuntu 8 @@ -1153,30 +1160,6 @@ QToolTip{background-color: white; color: black;} - - - - Qt::Horizontal - - - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - @@ -1191,11 +1174,6 @@ QToolTip{background-color: white; color: black;} QToolButton
gui/buttonswitch.h
- - ExternalClockButton - QToolButton -
gui/externalclockbutton.h
-
ValueDialZ QWidget @@ -1207,6 +1185,11 @@ QToolTip{background-color: white; color: black;} QPushButton
gui/transverterbutton.h
+ + ExternalClockButton + QToolButton +
gui/externalclockbutton.h
+
diff --git a/plugins/samplesource/limesdrinput/limesdrinputsettings.cpp b/plugins/samplesource/limesdrinput/limesdrinputsettings.cpp index da822b06c..01d7340c0 100644 --- a/plugins/samplesource/limesdrinput/limesdrinputsettings.cpp +++ b/plugins/samplesource/limesdrinput/limesdrinputsettings.cpp @@ -86,6 +86,7 @@ QByteArray LimeSDRInputSettings::serialize() const s.writeU32(26, m_reverseAPIPort); s.writeU32(27, m_reverseAPIDeviceIndex); s.writeBool(28, m_iqOrder); + return s.final(); } diff --git a/plugins/samplesource/limesdrinput/readme.md b/plugins/samplesource/limesdrinput/readme.md index 0b5464233..9c86f4687 100644 --- a/plugins/samplesource/limesdrinput/readme.md +++ b/plugins/samplesource/limesdrinput/readme.md @@ -12,6 +12,8 @@ LimeSDR is a 2x2 MIMO device so it has two receiving channels that can run concu

Interface

+The top and bottom bars of the device window are described [here](../../../sdrgui/device/readme.md) + ![LimeSDR input plugin GUI](../../../doc/img/LimeSDRInput_plugin.png)

1: Common stream parameters

@@ -204,4 +206,4 @@ This is the board temperature in degrees Celsius updated every ~5s. Before the f

15: GPIO pins status

-This is the hexadecimal representation of the 8 available GPIO pins of the on board LimeSDR GPIO header. \ No newline at end of file +This is the hexadecimal representation of the 8 available GPIO pins of the on board LimeSDR GPIO header. diff --git a/plugins/samplesource/localinput/localinputgui.cpp b/plugins/samplesource/localinput/localinputgui.cpp index 3221a3de9..9eb721982 100644 --- a/plugins/samplesource/localinput/localinputgui.cpp +++ b/plugins/samplesource/localinput/localinputgui.cpp @@ -29,11 +29,11 @@ #include #include #include +#include #include "ui_localinputgui.h" #include "gui/colormapper.h" #include "gui/glspectrum.h" -#include "gui/crightclickenabler.h" #include "gui/basicdevicesettingsdialog.h" #include "dsp/dspengine.h" #include "dsp/dspcommands.h" @@ -47,7 +47,6 @@ LocalInputGui::LocalInputGui(DeviceUISet *deviceUISet, QWidget* parent) : DeviceGUI(parent), ui(new Ui::LocalInputGui), - m_deviceUISet(deviceUISet), m_settings(), m_sampleSource(0), m_acquisition(false), @@ -70,16 +69,21 @@ LocalInputGui::LocalInputGui(DeviceUISet *deviceUISet, QWidget* parent) : m_doApplySettings(true), m_forceSettings(true) { + m_deviceUISet = deviceUISet; + setAttribute(Qt::WA_DeleteOnClose, true); m_paletteGreenText.setColor(QPalette::WindowText, Qt::green); m_paletteWhiteText.setColor(QPalette::WindowText, Qt::white); m_startingTimeStampms = 0; - ui->setupUi(this); + ui->setupUi(getContents()); + setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); + getContents()->setStyleSheet("#LocalInputGui { background-color: rgb(64, 64, 64); }"); + m_helpURL = "plugins/samplesource/localinput/readme.md"; - CRightClickEnabler *startStopRightClickEnabler = new CRightClickEnabler(ui->startStop); - connect(startStopRightClickEnabler, SIGNAL(rightClick(const QPoint &)), this, SLOT(openDeviceSettingsDialog(const QPoint &))); + connect(this, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(openDeviceSettingsDialog(const QPoint &))); displaySettings(); + makeUIConnections(); connect(&m_statusTimer, SIGNAL(timeout()), this, SLOT(updateStatus())); m_statusTimer.start(500); @@ -140,6 +144,12 @@ bool LocalInputGui::deserialize(const QByteArray& data) } } +void LocalInputGui::resizeEvent(QResizeEvent* size) +{ + adjustSize(); + size->accept(); +} + bool LocalInputGui::handleMessage(const Message& message) { if (LocalInput::MsgConfigureLocalInput::match(message)) @@ -305,19 +315,31 @@ void LocalInputGui::updateStatus() void LocalInputGui::openDeviceSettingsDialog(const QPoint& p) { - BasicDeviceSettingsDialog dialog(this); - dialog.setUseReverseAPI(m_settings.m_useReverseAPI); - dialog.setReverseAPIAddress(m_settings.m_reverseAPIAddress); - dialog.setReverseAPIPort(m_settings.m_reverseAPIPort); - dialog.setReverseAPIDeviceIndex(m_settings.m_reverseAPIDeviceIndex); + if (m_contextMenuType == ContextMenuDeviceSettings) + { + BasicDeviceSettingsDialog dialog(this); + dialog.setUseReverseAPI(m_settings.m_useReverseAPI); + dialog.setReverseAPIAddress(m_settings.m_reverseAPIAddress); + dialog.setReverseAPIPort(m_settings.m_reverseAPIPort); + dialog.setReverseAPIDeviceIndex(m_settings.m_reverseAPIDeviceIndex); - dialog.move(p); - dialog.exec(); + dialog.move(p); + dialog.exec(); - m_settings.m_useReverseAPI = dialog.useReverseAPI(); - m_settings.m_reverseAPIAddress = dialog.getReverseAPIAddress(); - m_settings.m_reverseAPIPort = dialog.getReverseAPIPort(); - m_settings.m_reverseAPIDeviceIndex = dialog.getReverseAPIDeviceIndex(); + m_settings.m_useReverseAPI = dialog.useReverseAPI(); + m_settings.m_reverseAPIAddress = dialog.getReverseAPIAddress(); + m_settings.m_reverseAPIPort = dialog.getReverseAPIPort(); + m_settings.m_reverseAPIDeviceIndex = dialog.getReverseAPIDeviceIndex(); - sendSettings(); + sendSettings(); + } + + resetContextMenuType(); +} + +void LocalInputGui::makeUIConnections() +{ + QObject::connect(ui->dcOffset, &ButtonSwitch::toggled, this, &LocalInputGui::on_dcOffset_toggled); + QObject::connect(ui->iqImbalance, &ButtonSwitch::toggled, this, &LocalInputGui::on_iqImbalance_toggled); + QObject::connect(ui->startStop, &ButtonSwitch::toggled, this, &LocalInputGui::on_startStop_toggled); } diff --git a/plugins/samplesource/localinput/localinputgui.h b/plugins/samplesource/localinput/localinputgui.h index 0f5472d3e..11ef79cc8 100644 --- a/plugins/samplesource/localinput/localinputgui.h +++ b/plugins/samplesource/localinput/localinputgui.h @@ -47,10 +47,12 @@ public: bool deserialize(const QByteArray& data); virtual MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; } +protected: + void resizeEvent(QResizeEvent* size); + private: Ui::LocalInputGui* ui; - DeviceUISet* m_deviceUISet; LocalInputSettings m_settings; //!< current settings LocalInput* m_sampleSource; bool m_acquisition; @@ -100,6 +102,7 @@ private: void sendSettings(); void updateSampleRateAndFrequency(); bool handleMessage(const Message& message); + void makeUIConnections(); private slots: void handleInputMessages(); diff --git a/plugins/samplesource/localinput/localinputgui.ui b/plugins/samplesource/localinput/localinputgui.ui index 39b4ca876..084a027f6 100644 --- a/plugins/samplesource/localinput/localinputgui.ui +++ b/plugins/samplesource/localinput/localinputgui.ui @@ -7,13 +7,25 @@ 0 0 360 - 100 + 80
+ + + 0 + 0 + + 360 - 100 + 80 + + + + + 380 + 110 @@ -43,15 +55,24 @@ - - 4 - + + + 0 + 0 + + + + + 26 + 16777215 + + start/stop acquisition @@ -199,23 +220,6 @@ - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - diff --git a/plugins/samplesource/localinput/localinputsettings.cpp b/plugins/samplesource/localinput/localinputsettings.cpp index 62782c894..f567857ab 100644 --- a/plugins/samplesource/localinput/localinputsettings.cpp +++ b/plugins/samplesource/localinput/localinputsettings.cpp @@ -75,6 +75,7 @@ bool LocalInputSettings::deserialize(const QByteArray& data) d.readU32(6, &uintval, 0); m_reverseAPIDeviceIndex = uintval > 99 ? 99 : uintval; + return true; } else diff --git a/plugins/samplesource/localinput/readme.md b/plugins/samplesource/localinput/readme.md index 119d5abb7..bc58afcba 100644 --- a/plugins/samplesource/localinput/readme.md +++ b/plugins/samplesource/localinput/readme.md @@ -6,6 +6,8 @@ This input sample source plugin gets its samples from a Local Sink channel in an

Interface

+The top and bottom bars of the device window are described [here](../../../sdrgui/device/readme.md) + ![SDR Local input plugin GUI](../../../doc/img/LocalInput_plugin.png)

1: Start/Stop

diff --git a/plugins/samplesource/perseus/perseusgui.cpp b/plugins/samplesource/perseus/perseusgui.cpp index 21cfb8759..d4d951ee8 100644 --- a/plugins/samplesource/perseus/perseusgui.cpp +++ b/plugins/samplesource/perseus/perseusgui.cpp @@ -18,6 +18,7 @@ #include #include #include +#include #include "device/deviceapi.h" #include "device/deviceuiset.h" @@ -25,7 +26,6 @@ #include "ui_perseusgui.h" #include "gui/colormapper.h" #include "gui/glspectrum.h" -#include "gui/crightclickenabler.h" #include "gui/basicdevicesettingsdialog.h" #include "dsp/dspengine.h" #include "dsp/dspcommands.h" @@ -34,16 +34,20 @@ PerseusGui::PerseusGui(DeviceUISet *deviceUISet, QWidget* parent) : DeviceGUI(parent), ui(new Ui::PerseusGui), - m_deviceUISet(deviceUISet), m_doApplySettings(true), m_forceSettings(true), m_settings(), m_sampleSource(0), m_lastEngineState(DeviceAPI::StNotStarted) { + m_deviceUISet = deviceUISet; + setAttribute(Qt::WA_DeleteOnClose, true); m_sampleSource = (PerseusInput*) m_deviceUISet->m_deviceAPI->getSampleSource(); - ui->setupUi(this); + ui->setupUi(getContents()); + setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); + getContents()->setStyleSheet("#PerseusGui { background-color: rgb(64, 64, 64); }"); + m_helpURL = "plugins/samplesource/perseus/readme.md"; ui->centerFrequency->setColorMapper(ColorMapper(ColorMapper::GrayGold)); updateFrequencyLimits(); @@ -51,8 +55,7 @@ PerseusGui::PerseusGui(DeviceUISet *deviceUISet, QWidget* parent) : connect(&m_statusTimer, SIGNAL(timeout()), this, SLOT(updateStatus())); m_statusTimer.start(500); - CRightClickEnabler *startStopRightClickEnabler = new CRightClickEnabler(ui->startStop); - connect(startStopRightClickEnabler, SIGNAL(rightClick(const QPoint &)), this, SLOT(openDeviceSettingsDialog(const QPoint &))); + connect(this, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(openDeviceSettingsDialog(const QPoint &))); displaySettings(); @@ -62,6 +65,7 @@ PerseusGui::PerseusGui(DeviceUISet *deviceUISet, QWidget* parent) : m_sampleSource->setMessageQueueToGUI(&m_inputMessageQueue); sendSettings(); + makeUIConnections(); } PerseusGui::~PerseusGui() @@ -99,6 +103,13 @@ bool PerseusGui::deserialize(const QByteArray& data) } } +void PerseusGui::resizeEvent(QResizeEvent* size) +{ + adjustSize(); + size->accept(); +} + + bool PerseusGui::handleMessage(const Message& message) { // Returned messages to update the GUI (usually from web interface) @@ -374,19 +385,39 @@ int PerseusGui::getDevSampleRateIndex(uint32_t sampeRate) void PerseusGui::openDeviceSettingsDialog(const QPoint& p) { - BasicDeviceSettingsDialog dialog(this); - dialog.setUseReverseAPI(m_settings.m_useReverseAPI); - dialog.setReverseAPIAddress(m_settings.m_reverseAPIAddress); - dialog.setReverseAPIPort(m_settings.m_reverseAPIPort); - dialog.setReverseAPIDeviceIndex(m_settings.m_reverseAPIDeviceIndex); + if (m_contextMenuType == ContextMenuDeviceSettings) + { + BasicDeviceSettingsDialog dialog(this); + dialog.setUseReverseAPI(m_settings.m_useReverseAPI); + dialog.setReverseAPIAddress(m_settings.m_reverseAPIAddress); + dialog.setReverseAPIPort(m_settings.m_reverseAPIPort); + dialog.setReverseAPIDeviceIndex(m_settings.m_reverseAPIDeviceIndex); - dialog.move(p); - dialog.exec(); + dialog.move(p); + dialog.exec(); - m_settings.m_useReverseAPI = dialog.useReverseAPI(); - m_settings.m_reverseAPIAddress = dialog.getReverseAPIAddress(); - m_settings.m_reverseAPIPort = dialog.getReverseAPIPort(); - m_settings.m_reverseAPIDeviceIndex = dialog.getReverseAPIDeviceIndex(); + m_settings.m_useReverseAPI = dialog.useReverseAPI(); + m_settings.m_reverseAPIAddress = dialog.getReverseAPIAddress(); + m_settings.m_reverseAPIPort = dialog.getReverseAPIPort(); + m_settings.m_reverseAPIDeviceIndex = dialog.getReverseAPIDeviceIndex(); - sendSettings(); + sendSettings(); + } + + resetContextMenuType(); +} + +void PerseusGui::makeUIConnections() +{ + QObject::connect(ui->centerFrequency, &ValueDial::changed, this, &PerseusGui::on_centerFrequency_changed); + QObject::connect(ui->LOppm, &QSlider::valueChanged, this, &PerseusGui::on_LOppm_valueChanged); + QObject::connect(ui->resetLOppm, &QPushButton::clicked, this, &PerseusGui::on_resetLOppm_clicked); + QObject::connect(ui->sampleRate, QOverload::of(&QComboBox::currentIndexChanged), this, &PerseusGui::on_sampleRate_currentIndexChanged); + QObject::connect(ui->wideband, &ButtonSwitch::toggled, this, &PerseusGui::on_wideband_toggled); + QObject::connect(ui->decim, QOverload::of(&QComboBox::currentIndexChanged), this, &PerseusGui::on_decim_currentIndexChanged); + QObject::connect(ui->startStop, &ButtonSwitch::toggled, this, &PerseusGui::on_startStop_toggled); + QObject::connect(ui->transverter, &TransverterButton::clicked, this, &PerseusGui::on_transverter_clicked); + QObject::connect(ui->attenuator, QOverload::of(&QComboBox::currentIndexChanged), this, &PerseusGui::on_attenuator_currentIndexChanged); + QObject::connect(ui->adcDither, &ButtonSwitch::toggled, this, &PerseusGui::on_adcDither_toggled); + QObject::connect(ui->adcPreamp, &ButtonSwitch::toggled, this, &PerseusGui::on_adcPreamp_toggled); } diff --git a/plugins/samplesource/perseus/perseusgui.h b/plugins/samplesource/perseus/perseusgui.h index 0e217ded6..4298b6992 100644 --- a/plugins/samplesource/perseus/perseusgui.h +++ b/plugins/samplesource/perseus/perseusgui.h @@ -44,13 +44,16 @@ public: QByteArray serialize() const; bool deserialize(const QByteArray& data); virtual MessageQueue* getInputMessageQueue() { return &m_inputMessageQueue; } + uint32_t getDevSampleRate(unsigned int index); int getDevSampleRateIndex(uint32_t sampleRate); +protected: + void resizeEvent(QResizeEvent* size); + private: Ui::PerseusGui* ui; - DeviceUISet* m_deviceUISet; bool m_doApplySettings; bool m_forceSettings; PerseusSettings m_settings; @@ -70,6 +73,7 @@ private: void sendSettings(); void updateSampleRateAndFrequency(); bool handleMessage(const Message& message); + void makeUIConnections(); private slots: void on_centerFrequency_changed(quint64 value); diff --git a/plugins/samplesource/perseus/perseusgui.ui b/plugins/samplesource/perseus/perseusgui.ui index 1d457ba29..a5a056d8b 100644 --- a/plugins/samplesource/perseus/perseusgui.ui +++ b/plugins/samplesource/perseus/perseusgui.ui @@ -6,20 +6,26 @@ 0 0 - 324 - 132 + 360 + 136
- + 0 0 - 320 - 132 + 360 + 136 + + + + + 380 + 182 @@ -122,7 +128,7 @@ Liberation Mono - 20 + 16 @@ -455,23 +461,6 @@ - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - diff --git a/plugins/samplesource/perseus/readme.md b/plugins/samplesource/perseus/readme.md index dcc224458..787a6d8ad 100644 --- a/plugins/samplesource/perseus/readme.md +++ b/plugins/samplesource/perseus/readme.md @@ -17,6 +17,8 @@ If you build it from source and install it in a custom location say: `/opt/insta

Interface

+The top and bottom bars of the device window are described [here](../../../sdrgui/device/readme.md) + It has a limited number of controls compared to other source interfaces. This is because a lot of things are handled automatically within the Perseus: - gains diff --git a/plugins/samplesource/plutosdrinput/plutosdrinputgui.cpp b/plugins/samplesource/plutosdrinput/plutosdrinputgui.cpp index b57538799..8ea5458c8 100644 --- a/plugins/samplesource/plutosdrinput/plutosdrinputgui.cpp +++ b/plugins/samplesource/plutosdrinput/plutosdrinputgui.cpp @@ -19,11 +19,11 @@ #include #include #include +#include #include "dsp/dspengine.h" #include "dsp/dspcommands.h" #include "gui/glspectrum.h" -#include "gui/crightclickenabler.h" #include "gui/basicdevicesettingsdialog.h" #include "device/deviceapi.h" #include "device/deviceuiset.h" @@ -35,7 +35,6 @@ PlutoSDRInputGui::PlutoSDRInputGui(DeviceUISet *deviceUISet, QWidget* parent) : DeviceGUI(parent), ui(new Ui::PlutoSDRInputGUI), - m_deviceUISet(deviceUISet), m_settings(), m_sampleRateMode(true), m_forceSettings(true), @@ -46,9 +45,14 @@ PlutoSDRInputGui::PlutoSDRInputGui(DeviceUISet *deviceUISet, QWidget* parent) : m_doApplySettings(true), m_statusCounter(0) { + m_deviceUISet = deviceUISet; + setAttribute(Qt::WA_DeleteOnClose, true); m_sampleSource = (PlutoSDRInput*) m_deviceUISet->m_deviceAPI->getSampleSource(); - ui->setupUi(this); + ui->setupUi(getContents()); + setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); + getContents()->setStyleSheet("#PlutoSDRInputGUI { background-color: rgb(64, 64, 64); }"); + m_helpURL = "plugins/samplesource/plutosdrinput/readme.md"; ui->centerFrequency->setColorMapper(ColorMapper(ColorMapper::GrayGold)); updateFrequencyLimits(); @@ -67,11 +71,11 @@ PlutoSDRInputGui::PlutoSDRInputGui(DeviceUISet *deviceUISet, QWidget* parent) : ui->swDecimLabel->setText(QString::fromUtf8("S\u2193")); ui->lpFIRDecimationLabel->setText(QString::fromUtf8("\u2193")); - CRightClickEnabler *startStopRightClickEnabler = new CRightClickEnabler(ui->startStop); - connect(startStopRightClickEnabler, SIGNAL(rightClick(const QPoint &)), this, SLOT(openDeviceSettingsDialog(const QPoint &))); + connect(this, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(openDeviceSettingsDialog(const QPoint &))); blockApplySettings(true); displaySettings(); + makeUIConnections(); blockApplySettings(false); connect(&m_updateTimer, SIGNAL(timeout()), this, SLOT(updateHardware())); @@ -119,6 +123,12 @@ bool PlutoSDRInputGui::deserialize(const QByteArray& data) } } +void PlutoSDRInputGui::resizeEvent(QResizeEvent* size) +{ + adjustSize(); + size->accept(); +} + bool PlutoSDRInputGui::handleMessage(const Message& message) { if (PlutoSDRInput::MsgConfigurePlutoSDR::match(message)) @@ -549,19 +559,49 @@ void PlutoSDRInputGui::updateSampleRateAndFrequency() void PlutoSDRInputGui::openDeviceSettingsDialog(const QPoint& p) { - BasicDeviceSettingsDialog dialog(this); - dialog.setUseReverseAPI(m_settings.m_useReverseAPI); - dialog.setReverseAPIAddress(m_settings.m_reverseAPIAddress); - dialog.setReverseAPIPort(m_settings.m_reverseAPIPort); - dialog.setReverseAPIDeviceIndex(m_settings.m_reverseAPIDeviceIndex); + if (m_contextMenuType == ContextMenuDeviceSettings) + { + BasicDeviceSettingsDialog dialog(this); + dialog.setUseReverseAPI(m_settings.m_useReverseAPI); + dialog.setReverseAPIAddress(m_settings.m_reverseAPIAddress); + dialog.setReverseAPIPort(m_settings.m_reverseAPIPort); + dialog.setReverseAPIDeviceIndex(m_settings.m_reverseAPIDeviceIndex); - dialog.move(p); - dialog.exec(); + dialog.move(p); + dialog.exec(); - m_settings.m_useReverseAPI = dialog.useReverseAPI(); - m_settings.m_reverseAPIAddress = dialog.getReverseAPIAddress(); - m_settings.m_reverseAPIPort = dialog.getReverseAPIPort(); - m_settings.m_reverseAPIDeviceIndex = dialog.getReverseAPIDeviceIndex(); + m_settings.m_useReverseAPI = dialog.useReverseAPI(); + m_settings.m_reverseAPIAddress = dialog.getReverseAPIAddress(); + m_settings.m_reverseAPIPort = dialog.getReverseAPIPort(); + m_settings.m_reverseAPIDeviceIndex = dialog.getReverseAPIDeviceIndex(); - sendSettings(); + sendSettings(); + } + + resetContextMenuType(); +} + +void PlutoSDRInputGui::makeUIConnections() +{ + QObject::connect(ui->startStop, &ButtonSwitch::toggled, this, &PlutoSDRInputGui::on_startStop_toggled); + QObject::connect(ui->centerFrequency, &ValueDial::changed, this, &PlutoSDRInputGui::on_centerFrequency_changed); + QObject::connect(ui->loPPM, &QSlider::valueChanged, this, &PlutoSDRInputGui::on_loPPM_valueChanged); + QObject::connect(ui->dcOffset, &ButtonSwitch::toggled, this, &PlutoSDRInputGui::on_dcOffset_toggled); + QObject::connect(ui->rfDCOffset, &ButtonSwitch::toggled, this, &PlutoSDRInputGui::on_rfDCOffset_toggled); + QObject::connect(ui->bbDCOffset, &ButtonSwitch::toggled, this, &PlutoSDRInputGui::on_bbDCOffset_toggled); + QObject::connect(ui->hwIQImbalance, &ButtonSwitch::toggled, this, &PlutoSDRInputGui::on_hwIQImbalance_toggled); + QObject::connect(ui->iqImbalance, &ButtonSwitch::toggled, this, &PlutoSDRInputGui::on_iqImbalance_toggled); + QObject::connect(ui->swDecim, QOverload::of(&QComboBox::currentIndexChanged), this, &PlutoSDRInputGui::on_swDecim_currentIndexChanged); + QObject::connect(ui->fcPos, QOverload::of(&QComboBox::currentIndexChanged), this, &PlutoSDRInputGui::on_fcPos_currentIndexChanged); + QObject::connect(ui->sampleRate, &ValueDial::changed, this, &PlutoSDRInputGui::on_sampleRate_changed); + QObject::connect(ui->lpf, &ValueDial::changed, this, &PlutoSDRInputGui::on_lpf_changed); + QObject::connect(ui->lpFIREnable, &ButtonSwitch::toggled, this, &PlutoSDRInputGui::on_lpFIREnable_toggled); + QObject::connect(ui->lpFIR, &ValueDial::changed, this, &PlutoSDRInputGui::on_lpFIR_changed); + QObject::connect(ui->lpFIRDecimation, QOverload::of(&QComboBox::currentIndexChanged), this, &PlutoSDRInputGui::on_lpFIRDecimation_currentIndexChanged); + QObject::connect(ui->lpFIRGain, QOverload::of(&QComboBox::currentIndexChanged), this, &PlutoSDRInputGui::on_lpFIRGain_currentIndexChanged); + QObject::connect(ui->gainMode, QOverload::of(&QComboBox::currentIndexChanged), this, &PlutoSDRInputGui::on_gainMode_currentIndexChanged); + QObject::connect(ui->gain, &QDial::valueChanged, this, &PlutoSDRInputGui::on_gain_valueChanged); + QObject::connect(ui->antenna, QOverload::of(&QComboBox::currentIndexChanged), this, &PlutoSDRInputGui::on_antenna_currentIndexChanged); + QObject::connect(ui->transverter, &TransverterButton::clicked, this, &PlutoSDRInputGui::on_transverter_clicked); + QObject::connect(ui->sampleRateMode, &QToolButton::toggled, this, &PlutoSDRInputGui::on_sampleRateMode_toggled); } diff --git a/plugins/samplesource/plutosdrinput/plutosdrinputgui.h b/plugins/samplesource/plutosdrinput/plutosdrinputgui.h index abd0f7e84..6a0841295 100644 --- a/plugins/samplesource/plutosdrinput/plutosdrinputgui.h +++ b/plugins/samplesource/plutosdrinput/plutosdrinputgui.h @@ -48,9 +48,11 @@ public: virtual bool deserialize(const QByteArray& data); virtual MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; } +protected: + void resizeEvent(QResizeEvent* size); + private: Ui::PlutoSDRInputGUI* ui; - DeviceUISet* m_deviceUISet; PlutoSDRInputSettings m_settings; bool m_sampleRateMode; //!< true: device, false: base band sample rate update mode bool m_forceSettings; @@ -74,6 +76,7 @@ private: void setSampleRateLimits(); void updateFrequencyLimits(); bool handleMessage(const Message& message); + void makeUIConnections(); private slots: void on_startStop_toggled(bool checked); diff --git a/plugins/samplesource/plutosdrinput/plutosdrinputgui.ui b/plugins/samplesource/plutosdrinput/plutosdrinputgui.ui index 336794851..96300f189 100644 --- a/plugins/samplesource/plutosdrinput/plutosdrinputgui.ui +++ b/plugins/samplesource/plutosdrinput/plutosdrinputgui.ui @@ -6,20 +6,26 @@ 0 0 - 350 - 260 + 360 + 240
- + 0 0 - 350 - 260 + 360 + 240 + + + + + 380 + 291 @@ -128,7 +134,7 @@ Liberation Mono - 20 + 16 @@ -1007,23 +1013,6 @@ - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - diff --git a/plugins/samplesource/plutosdrinput/readme.md b/plugins/samplesource/plutosdrinput/readme.md index b0cf00bef..33226490c 100644 --- a/plugins/samplesource/plutosdrinput/readme.md +++ b/plugins/samplesource/plutosdrinput/readme.md @@ -27,6 +27,8 @@ Then add the following defines on `cmake` command line when compiling SDRangel:

Interface

+The top and bottom bars of the device window are described [here](../../../sdrgui/device/readme.md) + ![PlutoSDR input plugin GUI](../../../doc/img/PlutoSDRInput_plugin.png)

1: Common stream parameters

diff --git a/plugins/samplesource/remoteinput/readme.md b/plugins/samplesource/remoteinput/readme.md index 142f2db1d..0f614bd9f 100644 --- a/plugins/samplesource/remoteinput/readme.md +++ b/plugins/samplesource/remoteinput/readme.md @@ -18,6 +18,8 @@ The plugin will be built only if the [CM256cc library](https://github.com/f4exb/

Interface

+The top and bottom bars of the device window are described [here](../../../sdrgui/device/readme.md) + ![SDR Remote input plugin GUI](../../../doc/img/RemoteInput_plugin.png)

1: Start/Stop

diff --git a/plugins/samplesource/remoteinput/remoteinputgui.cpp b/plugins/samplesource/remoteinput/remoteinputgui.cpp index 41c173d5b..289427346 100644 --- a/plugins/samplesource/remoteinput/remoteinputgui.cpp +++ b/plugins/samplesource/remoteinput/remoteinputgui.cpp @@ -25,11 +25,11 @@ #include #include #include +#include #include "ui_remoteinputgui.h" #include "gui/colormapper.h" #include "gui/glspectrum.h" -#include "gui/crightclickenabler.h" #include "gui/basicdevicesettingsdialog.h" #include "dsp/dspengine.h" #include "dsp/dspcommands.h" @@ -44,7 +44,6 @@ RemoteInputGui::RemoteInputGui(DeviceUISet *deviceUISet, QWidget* parent) : DeviceGUI(parent), ui(new Ui::RemoteInputGui), - m_deviceUISet(deviceUISet), m_settings(), m_sampleSource(0), m_acquisition(false), @@ -67,17 +66,21 @@ RemoteInputGui::RemoteInputGui(DeviceUISet *deviceUISet, QWidget* parent) : m_doApplySettings(true), m_forceSettings(true) { + m_deviceUISet = deviceUISet; + setAttribute(Qt::WA_DeleteOnClose, true); m_paletteGreenText.setColor(QPalette::WindowText, Qt::green); m_paletteWhiteText.setColor(QPalette::WindowText, Qt::white); m_startingTimeStampms = 0; - ui->setupUi(this); + ui->setupUi(getContents()); + setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); + getContents()->setStyleSheet("#RemoteInputGui { background-color: rgb(64, 64, 64); }"); + m_helpURL = "plugins/samplesource/remoteinput/readme.md"; ui->remoteDeviceFrequency->setColorMapper(ColorMapper(ColorMapper::GrayGold)); ui->remoteDeviceFrequency->setValueRange(8, 0, 99999999); - CRightClickEnabler *startStopRightClickEnabler = new CRightClickEnabler(ui->startStop); - connect(startStopRightClickEnabler, SIGNAL(rightClick(const QPoint &)), this, SLOT(openDeviceSettingsDialog(const QPoint &))); + connect(this, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(openDeviceSettingsDialog(const QPoint &))); displaySettings(); @@ -97,6 +100,7 @@ RemoteInputGui::RemoteInputGui(DeviceUISet *deviceUISet, QWidget* parent) : m_forceSettings = true; sendSettings(); + makeUIConnections(); } RemoteInputGui::~RemoteInputGui() @@ -145,6 +149,12 @@ bool RemoteInputGui::deserialize(const QByteArray& data) } } +void RemoteInputGui::resizeEvent(QResizeEvent* size) +{ + adjustSize(); + size->accept(); +} + bool RemoteInputGui::handleMessage(const Message& message) { if (RemoteInput::MsgConfigureRemoteInput::match(message)) @@ -668,19 +678,43 @@ void RemoteInputGui::updateStatus() void RemoteInputGui::openDeviceSettingsDialog(const QPoint& p) { - BasicDeviceSettingsDialog dialog(this); - dialog.setUseReverseAPI(m_settings.m_useReverseAPI); - dialog.setReverseAPIAddress(m_settings.m_reverseAPIAddress); - dialog.setReverseAPIPort(m_settings.m_reverseAPIPort); - dialog.setReverseAPIDeviceIndex(m_settings.m_reverseAPIDeviceIndex); + if (m_contextMenuType == ContextMenuDeviceSettings) + { + BasicDeviceSettingsDialog dialog(this); + dialog.setUseReverseAPI(m_settings.m_useReverseAPI); + dialog.setReverseAPIAddress(m_settings.m_reverseAPIAddress); + dialog.setReverseAPIPort(m_settings.m_reverseAPIPort); + dialog.setReverseAPIDeviceIndex(m_settings.m_reverseAPIDeviceIndex); - dialog.move(p); - dialog.exec(); + dialog.move(p); + dialog.exec(); - m_settings.m_useReverseAPI = dialog.useReverseAPI(); - m_settings.m_reverseAPIAddress = dialog.getReverseAPIAddress(); - m_settings.m_reverseAPIPort = dialog.getReverseAPIPort(); - m_settings.m_reverseAPIDeviceIndex = dialog.getReverseAPIDeviceIndex(); + m_settings.m_useReverseAPI = dialog.useReverseAPI(); + m_settings.m_reverseAPIAddress = dialog.getReverseAPIAddress(); + m_settings.m_reverseAPIPort = dialog.getReverseAPIPort(); + m_settings.m_reverseAPIDeviceIndex = dialog.getReverseAPIDeviceIndex(); - sendSettings(); + sendSettings(); + } + + resetContextMenuType(); +} + +void RemoteInputGui::makeUIConnections() +{ + QObject::connect(ui->remoteDeviceFrequency, &ValueDial::changed, this, &RemoteInputGui::on_remoteDeviceFrequency_changed); + QObject::connect(ui->decimationFactor, QOverload::of(&QComboBox::currentIndexChanged), this, &RemoteInputGui::on_decimationFactor_currentIndexChanged); + QObject::connect(ui->position, &QSlider::valueChanged, this, &RemoteInputGui::on_position_valueChanged); + QObject::connect(ui->apiApplyButton, &QPushButton::clicked, this, &RemoteInputGui::on_apiApplyButton_clicked); + QObject::connect(ui->dataApplyButton, &QPushButton::clicked, this, &RemoteInputGui::on_dataApplyButton_clicked); + QObject::connect(ui->dcOffset, &ButtonSwitch::toggled, this, &RemoteInputGui::on_dcOffset_toggled); + QObject::connect(ui->iqImbalance, &ButtonSwitch::toggled, this, &RemoteInputGui::on_iqImbalance_toggled); + QObject::connect(ui->apiAddress, &QLineEdit::editingFinished, this, &RemoteInputGui::on_apiAddress_editingFinished); + QObject::connect(ui->apiPort, &QLineEdit::editingFinished, this, &RemoteInputGui::on_apiPort_editingFinished); + QObject::connect(ui->dataAddress, &QLineEdit::editingFinished, this, &RemoteInputGui::on_dataAddress_editingFinished); + QObject::connect(ui->dataPort, &QLineEdit::editingFinished, this, &RemoteInputGui::on_dataPort_editingFinished); + QObject::connect(ui->multicastAddress, &QLineEdit::editingFinished, this, &RemoteInputGui::on_multicastAddress_editingFinished); + QObject::connect(ui->multicastJoin, &ButtonSwitch::toggled, this, &RemoteInputGui::on_multicastJoin_toggled); + QObject::connect(ui->startStop, &ButtonSwitch::toggled, this, &RemoteInputGui::on_startStop_toggled); + QObject::connect(ui->eventCountsReset, &QPushButton::clicked, this, &RemoteInputGui::on_eventCountsReset_clicked); } diff --git a/plugins/samplesource/remoteinput/remoteinputgui.h b/plugins/samplesource/remoteinput/remoteinputgui.h index 1aaa91f14..d6266ceda 100644 --- a/plugins/samplesource/remoteinput/remoteinputgui.h +++ b/plugins/samplesource/remoteinput/remoteinputgui.h @@ -49,10 +49,12 @@ public: bool deserialize(const QByteArray& data); virtual MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; } +protected: + void resizeEvent(QResizeEvent* size); + private: Ui::RemoteInputGui* ui; - DeviceUISet* m_deviceUISet; RemoteInputSettings m_settings; //!< current settings RemoteInput::RemoteChannelSettings m_remoteChannelSettings; double m_remoteShiftFrequencyFactor; //!< Remote channel frequency shift factor @@ -116,6 +118,7 @@ private: void applyPosition(); void applyRemoteSettings(); bool handleMessage(const Message& message); + void makeUIConnections(); private slots: void handleInputMessages(); diff --git a/plugins/samplesource/remoteinput/remoteinputgui.ui b/plugins/samplesource/remoteinput/remoteinputgui.ui index ca3982d22..b3dc8729c 100644 --- a/plugins/samplesource/remoteinput/remoteinputgui.ui +++ b/plugins/samplesource/remoteinput/remoteinputgui.ui @@ -6,14 +6,26 @@ 0 0 - 400 - 480 + 360 + 380
+ + + 0 + 0 + + 360 - 480 + 380 + + + + + 380 + 400 @@ -757,13 +769,6 @@ - - - - Qt::Horizontal - - - @@ -1040,6 +1045,13 @@ + + + + Qt::Horizontal + + + @@ -1062,37 +1074,20 @@ - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - ButtonSwitch - QToolButton -
gui/buttonswitch.h
-
ValueDial QWidget
gui/valuedial.h
1
+ + ButtonSwitch + QToolButton +
gui/buttonswitch.h
+
diff --git a/plugins/samplesource/remoteinput/remoteinputsettings.cpp b/plugins/samplesource/remoteinput/remoteinputsettings.cpp index a731506f6..c581c397f 100644 --- a/plugins/samplesource/remoteinput/remoteinputsettings.cpp +++ b/plugins/samplesource/remoteinput/remoteinputsettings.cpp @@ -95,6 +95,7 @@ bool RemoteInputSettings::deserialize(const QByteArray& data) d.readU32(14, &uintval, 0); m_reverseAPIDeviceIndex = uintval > 99 ? 99 : uintval; + return true; } else diff --git a/plugins/samplesource/rtlsdr/readme.md b/plugins/samplesource/rtlsdr/readme.md index 6d8b1eee7..3d5920854 100644 --- a/plugins/samplesource/rtlsdr/readme.md +++ b/plugins/samplesource/rtlsdr/readme.md @@ -12,6 +12,8 @@ If you want to benefit from the direct sampling you will have to compile and ins

Interface

+The top and bottom bars of the device window are described [here](../../../sdrgui/device/readme.md) + ![RTLSDR input plugin GUI](../../../doc/img/RTLSDR_plugin.png)

1: Common stream parameters

diff --git a/plugins/samplesource/rtlsdr/rtlsdrgui.cpp b/plugins/samplesource/rtlsdr/rtlsdrgui.cpp index 228bbf3b7..5118993f9 100644 --- a/plugins/samplesource/rtlsdr/rtlsdrgui.cpp +++ b/plugins/samplesource/rtlsdr/rtlsdrgui.cpp @@ -18,6 +18,7 @@ #include #include #include +#include #include "rtlsdrgui.h" @@ -27,7 +28,6 @@ #include "ui_rtlsdrgui.h" #include "gui/colormapper.h" #include "gui/glspectrum.h" -#include "gui/crightclickenabler.h" #include "gui/basicdevicesettingsdialog.h" #include "dsp/dspengine.h" #include "dsp/dspcommands.h" @@ -35,7 +35,6 @@ RTLSDRGui::RTLSDRGui(DeviceUISet *deviceUISet, QWidget* parent) : DeviceGUI(parent), ui(new Ui::RTLSDRGui), - m_deviceUISet(deviceUISet), m_doApplySettings(true), m_forceSettings(true), m_settings(), @@ -43,9 +42,14 @@ RTLSDRGui::RTLSDRGui(DeviceUISet *deviceUISet, QWidget* parent) : m_sampleSource(0), m_lastEngineState(DeviceAPI::StNotStarted) { + m_deviceUISet = deviceUISet; + setAttribute(Qt::WA_DeleteOnClose, true); m_sampleSource = (RTLSDRInput*) m_deviceUISet->m_deviceAPI->getSampleSource(); - ui->setupUi(this); + ui->setupUi(getContents()); + setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); + getContents()->setStyleSheet("#RTLSDRGui { background-color: rgb(64, 64, 64); }"); + m_helpURL = "plugins/samplesource/rtlsdr/readme.md"; ui->centerFrequency->setColorMapper(ColorMapper(ColorMapper::GrayGold)); updateFrequencyLimits(); @@ -54,25 +58,26 @@ RTLSDRGui::RTLSDRGui(DeviceUISet *deviceUISet, QWidget* parent) : ui->rfBW->setColorMapper(ColorMapper(ColorMapper::GrayYellow)); ui->rfBW->setValueRange(4, 0, 10000); + connect(this, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(openDeviceSettingsDialog(const QPoint &))); connect(&m_updateTimer, SIGNAL(timeout()), this, SLOT(updateHardware())); connect(&m_statusTimer, SIGNAL(timeout()), this, SLOT(updateStatus())); m_statusTimer.start(500); displaySettings(); + makeUIConnections(); m_gains = m_sampleSource->getGains(); displayGains(); connect(&m_inputMessageQueue, SIGNAL(messageEnqueued()), this, SLOT(handleInputMessages()), Qt::QueuedConnection); m_sampleSource->setMessageQueueToGUI(&m_inputMessageQueue); - - CRightClickEnabler *startStopRightClickEnabler = new CRightClickEnabler(ui->startStop); - connect(startStopRightClickEnabler, SIGNAL(rightClick(const QPoint &)), this, SLOT(openDeviceSettingsDialog(const QPoint &))); } RTLSDRGui::~RTLSDRGui() { + qDebug("RTLSDRGui::~RTLSDRGui"); delete ui; + qDebug("RTLSDRGui::~RTLSDRGui: end"); } void RTLSDRGui::destroy() @@ -121,6 +126,12 @@ bool RTLSDRGui::deserialize(const QByteArray& data) } } +void RTLSDRGui::resizeEvent(QResizeEvent* size) +{ + adjustSize(); + size->accept(); +} + bool RTLSDRGui::handleMessage(const Message& message) { if (RTLSDRInput::MsgConfigureRTLSDR::match(message)) @@ -517,19 +528,45 @@ void RTLSDRGui::on_lowSampleRate_toggled(bool checked) void RTLSDRGui::openDeviceSettingsDialog(const QPoint& p) { - BasicDeviceSettingsDialog dialog(this); - dialog.setUseReverseAPI(m_settings.m_useReverseAPI); - dialog.setReverseAPIAddress(m_settings.m_reverseAPIAddress); - dialog.setReverseAPIPort(m_settings.m_reverseAPIPort); - dialog.setReverseAPIDeviceIndex(m_settings.m_reverseAPIDeviceIndex); + if (m_contextMenuType == ContextMenuDeviceSettings) + { + BasicDeviceSettingsDialog dialog(this); + dialog.setUseReverseAPI(m_settings.m_useReverseAPI); + dialog.setReverseAPIAddress(m_settings.m_reverseAPIAddress); + dialog.setReverseAPIPort(m_settings.m_reverseAPIPort); + dialog.setReverseAPIDeviceIndex(m_settings.m_reverseAPIDeviceIndex); - dialog.move(p); - dialog.exec(); + dialog.move(p); + dialog.exec(); - m_settings.m_useReverseAPI = dialog.useReverseAPI(); - m_settings.m_reverseAPIAddress = dialog.getReverseAPIAddress(); - m_settings.m_reverseAPIPort = dialog.getReverseAPIPort(); - m_settings.m_reverseAPIDeviceIndex = dialog.getReverseAPIDeviceIndex(); + m_settings.m_useReverseAPI = dialog.useReverseAPI(); + m_settings.m_reverseAPIAddress = dialog.getReverseAPIAddress(); + m_settings.m_reverseAPIPort = dialog.getReverseAPIPort(); + m_settings.m_reverseAPIDeviceIndex = dialog.getReverseAPIDeviceIndex(); - sendSettings(); + sendSettings(); + } + + resetContextMenuType(); +} + +void RTLSDRGui::makeUIConnections() +{ + QObject::connect(ui->centerFrequency, &ValueDial::changed, this, &RTLSDRGui::on_centerFrequency_changed); + QObject::connect(ui->sampleRate, &ValueDial::changed, this, &RTLSDRGui::on_sampleRate_changed); + QObject::connect(ui->offsetTuning, &QCheckBox::toggled, this, &RTLSDRGui::on_offsetTuning_toggled); + QObject::connect(ui->rfBW, &ValueDial::changed, this, &RTLSDRGui::on_rfBW_changed); + QObject::connect(ui->lowSampleRate, &ButtonSwitch::toggled, this, &RTLSDRGui::on_lowSampleRate_toggled); + QObject::connect(ui->dcOffset, &ButtonSwitch::toggled, this, &RTLSDRGui::on_dcOffset_toggled); + QObject::connect(ui->iqImbalance, &ButtonSwitch::toggled, this, &RTLSDRGui::on_iqImbalance_toggled); + QObject::connect(ui->decim, QOverload::of(&QComboBox::currentIndexChanged), this, &RTLSDRGui::on_decim_currentIndexChanged); + QObject::connect(ui->fcPos, QOverload::of(&QComboBox::currentIndexChanged), this, &RTLSDRGui::on_fcPos_currentIndexChanged); + QObject::connect(ui->ppm, &QSlider::valueChanged, this, &RTLSDRGui::on_ppm_valueChanged); + QObject::connect(ui->gain, &QSlider::valueChanged, this, &RTLSDRGui::on_gain_valueChanged); + QObject::connect(ui->checkBox, &QCheckBox::stateChanged, this, &RTLSDRGui::on_checkBox_stateChanged); + QObject::connect(ui->agc, &QCheckBox::stateChanged, this, &RTLSDRGui::on_agc_stateChanged); + QObject::connect(ui->startStop, &ButtonSwitch::toggled, this, &RTLSDRGui::on_startStop_toggled); + QObject::connect(ui->transverter, &TransverterButton::clicked, this, &RTLSDRGui::on_transverter_clicked); + QObject::connect(ui->sampleRateMode, &QToolButton::toggled, this, &RTLSDRGui::on_sampleRateMode_toggled); + QObject::connect(ui->biasT, &QCheckBox::stateChanged, this, &RTLSDRGui::on_biasT_stateChanged); } diff --git a/plugins/samplesource/rtlsdr/rtlsdrgui.h b/plugins/samplesource/rtlsdr/rtlsdrgui.h index 9c09d10e3..09a26f3cd 100644 --- a/plugins/samplesource/rtlsdr/rtlsdrgui.h +++ b/plugins/samplesource/rtlsdr/rtlsdrgui.h @@ -47,10 +47,12 @@ public: bool deserialize(const QByteArray& data); virtual MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; } +protected: + void resizeEvent(QResizeEvent* size); + private: Ui::RTLSDRGui* ui; - DeviceUISet* m_deviceUISet; bool m_doApplySettings; bool m_forceSettings; RTLSDRSettings m_settings; @@ -73,6 +75,7 @@ private: void updateFrequencyLimits(); void blockApplySettings(bool block); bool handleMessage(const Message& message); + void makeUIConnections(); private slots: void handleInputMessages(); diff --git a/plugins/samplesource/rtlsdr/rtlsdrgui.ui b/plugins/samplesource/rtlsdr/rtlsdrgui.ui index bdbe8b255..97977c5b7 100644 --- a/plugins/samplesource/rtlsdr/rtlsdrgui.ui +++ b/plugins/samplesource/rtlsdr/rtlsdrgui.ui @@ -6,20 +6,26 @@ 0 0 - 320 - 220 + 360 + 217
- + 0 0 - 320 - 220 + 360 + 217 + + + + + 380 + 229 @@ -122,7 +128,7 @@ Liberation Mono - 20 + 16 @@ -251,6 +257,12 @@ + + + 55 + 0 + + 50 @@ -636,44 +648,20 @@ - - - - Qt::Horizontal - - - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - ButtonSwitch - QToolButton -
gui/buttonswitch.h
-
ValueDial QWidget
gui/valuedial.h
1
+ + ButtonSwitch + QToolButton +
gui/buttonswitch.h
+
TransverterButton QPushButton diff --git a/plugins/samplesource/sdrplay/readme.md b/plugins/samplesource/sdrplay/readme.md index 629ea597b..16838f31f 100644 --- a/plugins/samplesource/sdrplay/readme.md +++ b/plugins/samplesource/sdrplay/readme.md @@ -4,7 +4,7 @@ This plugin supports input from SDRplay RSP1 devices. SDRplay is based on the MSi001 and MSi2500 chips from Mirics. The standard API provided by Mirics is closed source moreover it could not be implemented successfully in SDRangel. An open source API libmirisdr-2 has been written by Miroslav Slugen and later amended by Leif Asbrink SM5BSZ. This API uses a new flavour called [libmirisdr-4](https://github.com/f4exb/libmirisdr-4) in this very same Github space. It contains enhancements and bug fixes. -No Windows support +No Windows support Driver is too unstable in Windows randomly stopping the application and causing BSOD. @@ -14,6 +14,8 @@ As mentioned already the plugin depends on libmirisdr-4. You will have to compil

Interface

+The top and bottom bars of the device window are described [here](../../../sdrgui/device/readme.md) + ![SDRplay plugin GUI](../../../doc/img/SDRPlay_plugin.png)

1. Common controls

@@ -40,7 +42,7 @@ This selects a frequency range corresponding to the hardware path in the SDRplay - 250 MHz to 380 MHz - 380 MHz to 1 GHz - 1 GHz to 2 GHz - +

5. IF bandwidth

This selects the IF filter. Following bandwidths are available according to MSi001 specs: @@ -61,8 +63,8 @@ This selects the IF frequency between these values: - 0 for zero IF - 450 kHz: you have to set sample rate to 1792 kHz (7) and use decimation (8) with an infradyne position (9) - 1620 kHz: you have to set sample rate to 6400 kHz (7) and use decimation (8) with an infradyne position (9) - - 2048 kHz: you have to set sample rate to 8192 kHz (7) and use decimation (8) with an infradyne position (9) - + - 2048 kHz: you have to set sample rate to 8192 kHz (7) and use decimation (8) with an infradyne position (9) +

7. Sample rate

You have the choice between various sample rates from 1536 to 8192 kHz. Some values have a special destination: @@ -70,7 +72,7 @@ You have the choice between various sample rates from 1536 to 8192 kHz. Some val - 1792 kHz: for use with an IF of 450 kHz. - 6400 kHz: for use with an IF of 1620 kHz. - 8192 kHz: for use with an IF of 2048 kHz. - +

8. Decimation

Decimation in powers of two from 1 (no decimation) to 64. @@ -78,24 +80,24 @@ Decimation in powers of two from 1 (no decimation) to 64.

9: Decimated bandpass center frequency position relative the SDRplay center frequency

- **Cen**: the decimation operation takes place around the SDRplay center frequency Fs - - **Inf**: the decimation operation takes place around Fs - Fc. + - **Inf**: the decimation operation takes place around Fs - Fc. - **Sup**: the decimation operation takes place around Fs + Fc. - -With SR as the sample rate before decimation Fc is calculated as: + +With SR as the sample rate before decimation Fc is calculated as: - if decimation n is 4 or lower: Fc = SR/2^(log2(n)-1). The device center frequency is on the side of the baseband. You need a RF filter bandwidth at least twice the baseband. - if decimation n is 8 or higher: Fc = SR/n. The device center frequency is half the baseband away from the side of the baseband. You need a RF filter bandwidth at least 3 times the baseband. - +

10. Tuner gain mode

-Use this radiobutton to select a mode where the gain of the LNA (or mixer buffer below 50 MHz), mixer and baseband amplifiers are automatically selected depending on the tuner gain index (11). This index is the gain value in dB at the nominal gain of all amplifiers. This is not the exact gain at all frequencies because the LNA gain decreases significantly at higher frequencies. +Use this radiobutton to select a mode where the gain of the LNA (or mixer buffer below 50 MHz), mixer and baseband amplifiers are automatically selected depending on the tuner gain index (11). This index is the gain value in dB at the nominal gain of all amplifiers. This is not the exact gain at all frequencies because the LNA gain decreases significantly at higher frequencies.

11. Tuner gain setting

The tuner gain index can be set between 0 and 102 points (corresponds to dB in the nominal case).

12. Manual gain mode

- + Use this radiobutton to select a mode where the gain of all amplifiers can be set independently

13. LNA toggle

diff --git a/plugins/samplesource/sdrplay/sdrplaygui.cpp b/plugins/samplesource/sdrplay/sdrplaygui.cpp index a214a0b54..df6ec645a 100644 --- a/plugins/samplesource/sdrplay/sdrplaygui.cpp +++ b/plugins/samplesource/sdrplay/sdrplaygui.cpp @@ -18,6 +18,7 @@ #include #include #include +#include #include "sdrplaygui.h" @@ -27,7 +28,6 @@ #include "ui_sdrplaygui.h" #include "gui/colormapper.h" #include "gui/glspectrum.h" -#include "gui/crightclickenabler.h" #include "gui/basicdevicesettingsdialog.h" #include "dsp/dspengine.h" #include "dsp/dspcommands.h" @@ -36,13 +36,17 @@ SDRPlayGui::SDRPlayGui(DeviceUISet *deviceUISet, QWidget* parent) : DeviceGUI(parent), ui(new Ui::SDRPlayGui), - m_deviceUISet(deviceUISet), m_doApplySettings(true), m_forceSettings(true) { + m_deviceUISet = deviceUISet; + setAttribute(Qt::WA_DeleteOnClose, true); m_sampleSource = (SDRPlayInput*) m_deviceUISet->m_deviceAPI->getSampleSource(); - ui->setupUi(this); + ui->setupUi(getContents()); + setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); + getContents()->setStyleSheet("#SDRPlayGui { background-color: rgb(64, 64, 64); }"); + m_helpURL = "plugins/samplesource/sdrplay/readme.md"; ui->centerFrequency->setColorMapper(ColorMapper(ColorMapper::GrayGold)); ui->centerFrequency->setValueRange(7, 10U, 12000U); @@ -74,10 +78,10 @@ SDRPlayGui::SDRPlayGui(DeviceUISet *deviceUISet, QWidget* parent) : connect(&m_statusTimer, SIGNAL(timeout()), this, SLOT(updateStatus())); m_statusTimer.start(500); - CRightClickEnabler *startStopRightClickEnabler = new CRightClickEnabler(ui->startStop); - connect(startStopRightClickEnabler, SIGNAL(rightClick(const QPoint &)), this, SLOT(openDeviceSettingsDialog(const QPoint &))); + connect(this, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(openDeviceSettingsDialog(const QPoint &))); displaySettings(); + makeUIConnections(); connect(&m_inputMessageQueue, SIGNAL(messageEnqueued()), this, SLOT(handleInputMessages()), Qt::QueuedConnection); m_sampleSource->setMessageQueueToGUI(&m_inputMessageQueue); @@ -121,6 +125,12 @@ bool SDRPlayGui::deserialize(const QByteArray& data) } } +void SDRPlayGui::resizeEvent(QResizeEvent* size) +{ + adjustSize(); + size->accept(); +} + bool SDRPlayGui::handleMessage(const Message& message) { if (SDRPlayInput::MsgConfigureSDRPlay::match(message)) @@ -440,19 +450,45 @@ void SDRPlayGui::on_startStop_toggled(bool checked) void SDRPlayGui::openDeviceSettingsDialog(const QPoint& p) { - BasicDeviceSettingsDialog dialog(this); - dialog.setUseReverseAPI(m_settings.m_useReverseAPI); - dialog.setReverseAPIAddress(m_settings.m_reverseAPIAddress); - dialog.setReverseAPIPort(m_settings.m_reverseAPIPort); - dialog.setReverseAPIDeviceIndex(m_settings.m_reverseAPIDeviceIndex); + if (m_contextMenuType == ContextMenuDeviceSettings) + { + BasicDeviceSettingsDialog dialog(this); + dialog.setUseReverseAPI(m_settings.m_useReverseAPI); + dialog.setReverseAPIAddress(m_settings.m_reverseAPIAddress); + dialog.setReverseAPIPort(m_settings.m_reverseAPIPort); + dialog.setReverseAPIDeviceIndex(m_settings.m_reverseAPIDeviceIndex); - dialog.move(p); - dialog.exec(); + dialog.move(p); + dialog.exec(); - m_settings.m_useReverseAPI = dialog.useReverseAPI(); - m_settings.m_reverseAPIAddress = dialog.getReverseAPIAddress(); - m_settings.m_reverseAPIPort = dialog.getReverseAPIPort(); - m_settings.m_reverseAPIDeviceIndex = dialog.getReverseAPIDeviceIndex(); + m_settings.m_useReverseAPI = dialog.useReverseAPI(); + m_settings.m_reverseAPIAddress = dialog.getReverseAPIAddress(); + m_settings.m_reverseAPIPort = dialog.getReverseAPIPort(); + m_settings.m_reverseAPIDeviceIndex = dialog.getReverseAPIDeviceIndex(); - sendSettings(); + sendSettings(); + } + + resetContextMenuType(); +} + +void SDRPlayGui::makeUIConnections() +{ + QObject::connect(ui->centerFrequency, &ValueDial::changed, this, &SDRPlayGui::on_centerFrequency_changed); + QObject::connect(ui->ppm, &QSlider::valueChanged, this, &SDRPlayGui::on_ppm_valueChanged); + QObject::connect(ui->dcOffset, &ButtonSwitch::toggled, this, &SDRPlayGui::on_dcOffset_toggled); + QObject::connect(ui->iqImbalance, &ButtonSwitch::toggled, this, &SDRPlayGui::on_iqImbalance_toggled); + QObject::connect(ui->fBand, QOverload::of(&QComboBox::currentIndexChanged), this, &SDRPlayGui::on_fBand_currentIndexChanged); + QObject::connect(ui->bandwidth, QOverload::of(&QComboBox::currentIndexChanged), this, &SDRPlayGui::on_bandwidth_currentIndexChanged); + QObject::connect(ui->samplerate, QOverload::of(&QComboBox::currentIndexChanged), this, &SDRPlayGui::on_samplerate_currentIndexChanged); + QObject::connect(ui->ifFrequency, QOverload::of(&QComboBox::currentIndexChanged), this, &SDRPlayGui::on_ifFrequency_currentIndexChanged); + QObject::connect(ui->decim, QOverload::of(&QComboBox::currentIndexChanged), this, &SDRPlayGui::on_decim_currentIndexChanged); + QObject::connect(ui->fcPos, QOverload::of(&QComboBox::currentIndexChanged), this, &SDRPlayGui::on_fcPos_currentIndexChanged); + QObject::connect(ui->gainTunerOn, &QRadioButton::toggled, this, &SDRPlayGui::on_gainTunerOn_toggled); + QObject::connect(ui->gainTuner, &QDial::valueChanged, this, &SDRPlayGui::on_gainTuner_valueChanged); + QObject::connect(ui->gainManualOn, &QRadioButton::toggled, this, &SDRPlayGui::on_gainManualOn_toggled); + QObject::connect(ui->gainLNA, &ButtonSwitch::toggled, this, &SDRPlayGui::on_gainLNA_toggled); + QObject::connect(ui->gainMixer, &ButtonSwitch::toggled, this, &SDRPlayGui::on_gainMixer_toggled); + QObject::connect(ui->gainBaseband, &QDial::valueChanged, this, &SDRPlayGui::on_gainBaseband_valueChanged); + QObject::connect(ui->startStop, &ButtonSwitch::toggled, this, &SDRPlayGui::on_startStop_toggled); } diff --git a/plugins/samplesource/sdrplay/sdrplaygui.h b/plugins/samplesource/sdrplay/sdrplaygui.h index 0e0595f04..0ffa73f46 100644 --- a/plugins/samplesource/sdrplay/sdrplaygui.h +++ b/plugins/samplesource/sdrplay/sdrplaygui.h @@ -47,10 +47,12 @@ public: virtual bool deserialize(const QByteArray& data); virtual MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; } +protected: + void resizeEvent(QResizeEvent* size); + private: Ui::SDRPlayGui* ui; - DeviceUISet* m_deviceUISet; bool m_doApplySettings; bool m_forceSettings; SDRPlaySettings m_settings; @@ -67,6 +69,7 @@ private: void sendSettings(); void updateSampleRateAndFrequency(); bool handleMessage(const Message& message); + void makeUIConnections(); private slots: void updateHardware(); diff --git a/plugins/samplesource/sdrplay/sdrplaygui.ui b/plugins/samplesource/sdrplay/sdrplaygui.ui index e9d07e273..296236f62 100644 --- a/plugins/samplesource/sdrplay/sdrplaygui.ui +++ b/plugins/samplesource/sdrplay/sdrplaygui.ui @@ -6,20 +6,26 @@ 0 0 - 307 - 210 + 360 + 202
- + 0 0 - 0 - 210 + 360 + 202 + + + + + 380 + 251 @@ -122,7 +128,7 @@ Liberation Mono - 20 + 16 @@ -642,37 +648,6 @@ - - - - Qt::Horizontal - - - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - - - Qt::Horizontal - - - diff --git a/plugins/samplesource/sdrplayv3/readme.md b/plugins/samplesource/sdrplayv3/readme.md index a24083e4c..903336b8b 100644 --- a/plugins/samplesource/sdrplayv3/readme.md +++ b/plugins/samplesource/sdrplayv3/readme.md @@ -10,6 +10,8 @@ This plugin requires the SDRplay API V3.07 to have been installed and for the se

Interface

+The top and bottom bars of the device window are described [here](../../../sdrgui/device/readme.md) + ![SDRplay v3 plugin GUI](../../../doc/img/SDRPlayV3_plugin.png)

1: Start/Stop

diff --git a/plugins/samplesource/sdrplayv3/sdrplayv3gui.cpp b/plugins/samplesource/sdrplayv3/sdrplayv3gui.cpp index 7b78455b4..c057ab815 100644 --- a/plugins/samplesource/sdrplayv3/sdrplayv3gui.cpp +++ b/plugins/samplesource/sdrplayv3/sdrplayv3gui.cpp @@ -18,6 +18,7 @@ #include #include +#include #include "sdrplayv3gui.h" #include "sdrplayv3input.h" @@ -28,7 +29,6 @@ #include "ui_sdrplayv3gui.h" #include "gui/colormapper.h" #include "gui/glspectrum.h" -#include "gui/crightclickenabler.h" #include "gui/basicdevicesettingsdialog.h" #include "dsp/dspengine.h" #include "dsp/dspcommands.h" @@ -36,13 +36,17 @@ SDRPlayV3Gui::SDRPlayV3Gui(DeviceUISet *deviceUISet, QWidget* parent) : DeviceGUI(parent), ui(new Ui::SDRPlayV3Gui), - m_deviceUISet(deviceUISet), m_doApplySettings(true), m_forceSettings(true) { + m_deviceUISet = deviceUISet; + setAttribute(Qt::WA_DeleteOnClose, true); m_sdrPlayV3Input = (SDRPlayV3Input*) m_deviceUISet->m_deviceAPI->getSampleSource(); - ui->setupUi(this); + ui->setupUi(getContents()); + setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); + getContents()->setStyleSheet("#SDRPlayV3Gui { background-color: rgb(64, 64, 64); }"); + m_helpURL = "plugins/samplesource/sdrplayv3/readme.md"; ui->centerFrequency->setColorMapper(ColorMapper(ColorMapper::GrayGold)); updateFrequencyLimits(); @@ -65,8 +69,7 @@ SDRPlayV3Gui::SDRPlayV3Gui(DeviceUISet *deviceUISet, QWidget* parent) : connect(&m_statusTimer, SIGNAL(timeout()), this, SLOT(updateStatus())); m_statusTimer.start(500); - CRightClickEnabler *startStopRightClickEnabler = new CRightClickEnabler(ui->startStop); - connect(startStopRightClickEnabler, SIGNAL(rightClick(const QPoint &)), this, SLOT(openDeviceSettingsDialog(const QPoint &))); + connect(this, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(openDeviceSettingsDialog(const QPoint &))); ui->tuner->blockSignals(true); ui->antenna->blockSignals(true); @@ -114,6 +117,7 @@ SDRPlayV3Gui::SDRPlayV3Gui(DeviceUISet *deviceUISet, QWidget* parent) : ui->antenna->blockSignals(false); displaySettings(); + makeUIConnections(); connect(&m_inputMessageQueue, SIGNAL(messageEnqueued()), this, SLOT(handleInputMessages()), Qt::QueuedConnection); m_sdrPlayV3Input->setMessageQueueToGUI(&m_inputMessageQueue); @@ -157,6 +161,12 @@ bool SDRPlayV3Gui::deserialize(const QByteArray& data) } } +void SDRPlayV3Gui::resizeEvent(QResizeEvent* size) +{ + adjustSize(); + size->accept(); +} + bool SDRPlayV3Gui::handleMessage(const Message& message) { if (SDRPlayV3Input::MsgConfigureSDRPlayV3::match(message)) @@ -504,19 +514,49 @@ void SDRPlayV3Gui::on_transverter_clicked() void SDRPlayV3Gui::openDeviceSettingsDialog(const QPoint& p) { - BasicDeviceSettingsDialog dialog(this); - dialog.setUseReverseAPI(m_settings.m_useReverseAPI); - dialog.setReverseAPIAddress(m_settings.m_reverseAPIAddress); - dialog.setReverseAPIPort(m_settings.m_reverseAPIPort); - dialog.setReverseAPIDeviceIndex(m_settings.m_reverseAPIDeviceIndex); + if (m_contextMenuType == ContextMenuDeviceSettings) + { + BasicDeviceSettingsDialog dialog(this); + dialog.setUseReverseAPI(m_settings.m_useReverseAPI); + dialog.setReverseAPIAddress(m_settings.m_reverseAPIAddress); + dialog.setReverseAPIPort(m_settings.m_reverseAPIPort); + dialog.setReverseAPIDeviceIndex(m_settings.m_reverseAPIDeviceIndex); - dialog.move(p); - dialog.exec(); + dialog.move(p); + dialog.exec(); - m_settings.m_useReverseAPI = dialog.useReverseAPI(); - m_settings.m_reverseAPIAddress = dialog.getReverseAPIAddress(); - m_settings.m_reverseAPIPort = dialog.getReverseAPIPort(); - m_settings.m_reverseAPIDeviceIndex = dialog.getReverseAPIDeviceIndex(); + m_settings.m_useReverseAPI = dialog.useReverseAPI(); + m_settings.m_reverseAPIAddress = dialog.getReverseAPIAddress(); + m_settings.m_reverseAPIPort = dialog.getReverseAPIPort(); + m_settings.m_reverseAPIDeviceIndex = dialog.getReverseAPIDeviceIndex(); - sendSettings(); + sendSettings(); + } + + resetContextMenuType(); +} + +void SDRPlayV3Gui::makeUIConnections() +{ + QObject::connect(ui->centerFrequency, &ValueDial::changed, this, &SDRPlayV3Gui::on_centerFrequency_changed); + QObject::connect(ui->ppm, &QSlider::valueChanged, this, &SDRPlayV3Gui::on_ppm_valueChanged); + QObject::connect(ui->tuner, QOverload::of(&QComboBox::currentIndexChanged), this, &SDRPlayV3Gui::on_tuner_currentIndexChanged); + QObject::connect(ui->antenna, QOverload::of(&QComboBox::currentIndexChanged), this, &SDRPlayV3Gui::on_antenna_currentIndexChanged); + QObject::connect(ui->dcOffset, &ButtonSwitch::toggled, this, &SDRPlayV3Gui::on_dcOffset_toggled); + QObject::connect(ui->iqImbalance, &ButtonSwitch::toggled, this, &SDRPlayV3Gui::on_iqImbalance_toggled); + QObject::connect(ui->extRef, &ButtonSwitch::toggled, this, &SDRPlayV3Gui::on_extRef_toggled); + QObject::connect(ui->biasTee, &ButtonSwitch::toggled, this, &SDRPlayV3Gui::on_biasTee_toggled); + QObject::connect(ui->amNotch, &ButtonSwitch::toggled, this, &SDRPlayV3Gui::on_amNotch_toggled); + QObject::connect(ui->fmNotch, &ButtonSwitch::toggled, this, &SDRPlayV3Gui::on_fmNotch_toggled); + QObject::connect(ui->dabNotch, &ButtonSwitch::toggled, this, &SDRPlayV3Gui::on_dabNotch_toggled); + QObject::connect(ui->bandwidth, QOverload::of(&QComboBox::currentIndexChanged), this, &SDRPlayV3Gui::on_bandwidth_currentIndexChanged); + QObject::connect(ui->samplerate, &ValueDial::changed, this, &SDRPlayV3Gui::on_samplerate_changed); + QObject::connect(ui->ifFrequency, QOverload::of(&QComboBox::currentIndexChanged), this, &SDRPlayV3Gui::on_ifFrequency_currentIndexChanged); + QObject::connect(ui->decim, QOverload::of(&QComboBox::currentIndexChanged), this, &SDRPlayV3Gui::on_decim_currentIndexChanged); + QObject::connect(ui->fcPos, QOverload::of(&QComboBox::currentIndexChanged), this, &SDRPlayV3Gui::on_fcPos_currentIndexChanged); + QObject::connect(ui->gainLNA, QOverload::of(&QComboBox::currentIndexChanged), this, &SDRPlayV3Gui::on_gainLNA_currentIndexChanged); + QObject::connect(ui->gainIFAGC, &ButtonSwitch::toggled, this, &SDRPlayV3Gui::on_gainIFAGC_toggled); + QObject::connect(ui->gainIF, &QDial::valueChanged, this, &SDRPlayV3Gui::on_gainIF_valueChanged); + QObject::connect(ui->startStop, &ButtonSwitch::toggled, this, &SDRPlayV3Gui::on_startStop_toggled); + QObject::connect(ui->transverter, &TransverterButton::clicked, this, &SDRPlayV3Gui::on_transverter_clicked); } diff --git a/plugins/samplesource/sdrplayv3/sdrplayv3gui.h b/plugins/samplesource/sdrplayv3/sdrplayv3gui.h index 0c790c961..fc16fd029 100644 --- a/plugins/samplesource/sdrplayv3/sdrplayv3gui.h +++ b/plugins/samplesource/sdrplayv3/sdrplayv3gui.h @@ -47,10 +47,12 @@ public: virtual bool deserialize(const QByteArray& data); virtual MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; } +protected: + void resizeEvent(QResizeEvent* size); + private: Ui::SDRPlayV3Gui* ui; - DeviceUISet* m_deviceUISet; bool m_doApplySettings; bool m_forceSettings; SDRPlayV3Settings m_settings; @@ -69,6 +71,7 @@ private: void updateSampleRateAndFrequency(); void updateFrequencyLimits(); bool handleMessage(const Message& message); + void makeUIConnections(); private slots: void updateHardware(); diff --git a/plugins/samplesource/sdrplayv3/sdrplayv3gui.ui b/plugins/samplesource/sdrplayv3/sdrplayv3gui.ui index f4665f4f5..2dae1e0bc 100644 --- a/plugins/samplesource/sdrplayv3/sdrplayv3gui.ui +++ b/plugins/samplesource/sdrplayv3/sdrplayv3gui.ui @@ -6,20 +6,26 @@ 0 0 - 409 - 260 + 360 + 234
- + 0 0 - 0 - 260 + 360 + 234 + + + + + 409 + 297 @@ -122,7 +128,7 @@ Liberation Mono - 20 + 16 @@ -186,13 +192,6 @@ - - - - LO ppm - - - @@ -212,10 +211,10 @@ - - - - Qt::Horizontal + + + + LO ppm @@ -765,51 +764,20 @@ - - - - Qt::Horizontal - - - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - - - Qt::Horizontal - - - - - ButtonSwitch - QToolButton -
gui/buttonswitch.h
-
ValueDial QWidget
gui/valuedial.h
1
+ + ButtonSwitch + QToolButton +
gui/buttonswitch.h
+
TransverterButton QPushButton diff --git a/plugins/samplesource/sigmffileinput/readme.md b/plugins/samplesource/sigmffileinput/readme.md index 996eb0383..62dab8880 100644 --- a/plugins/samplesource/sigmffileinput/readme.md +++ b/plugins/samplesource/sigmffileinput/readme.md @@ -12,6 +12,8 @@ Note: this plugin is officially supported since version 6.

Interface

+The top and bottom bars of the device window are described [here](../../../sdrgui/device/readme.md) + ![SigMF File input plugin GUI](../../../doc/img/SigMFFileInput_plugin.png)

1: Start/Stop

diff --git a/plugins/samplesource/sigmffileinput/sigmffileinputgui.cpp b/plugins/samplesource/sigmffileinput/sigmffileinputgui.cpp index 2e60cef5d..2970f6227 100644 --- a/plugins/samplesource/sigmffileinput/sigmffileinputgui.cpp +++ b/plugins/samplesource/sigmffileinput/sigmffileinputgui.cpp @@ -22,12 +22,12 @@ #include #include #include +#include #include "ui_sigmffileinputgui.h" #include "plugin/pluginapi.h" #include "gui/colormapper.h" #include "gui/glspectrum.h" -#include "gui/crightclickenabler.h" #include "gui/basicdevicesettingsdialog.h" #include "dsp/dspengine.h" #include "dsp/dspcommands.h" @@ -43,7 +43,6 @@ SigMFFileInputGUI::SigMFFileInputGUI(DeviceUISet *deviceUISet, QWidget* parent) : DeviceGUI(parent), ui(new Ui::SigMFFileInputGUI), - m_deviceUISet(deviceUISet), m_settings(), m_currentTrackIndex(0), m_doApplySettings(true), @@ -61,7 +60,13 @@ SigMFFileInputGUI::SigMFFileInputGUI(DeviceUISet *deviceUISet, QWidget* parent) m_enableFullNavTime(false), m_lastEngineState(DeviceAPI::StNotStarted) { - ui->setupUi(this); + m_deviceUISet = deviceUISet; + setAttribute(Qt::WA_DeleteOnClose, true); + m_helpURL = "plugins/samplesource/sigmffileinput/readme.md"; + QWidget *contents = getContents(); + ui->setupUi(contents); + setSizePolicy(contents->sizePolicy()); + contents->setStyleSheet("#SigMFFileInputGUI { background-color: rgb(64, 64, 64); }"); ui->fileNameText->setText(m_metaFileName); ui->crcLabel->setStyleSheet("QLabel { background:rgb(79,79,79); }"); @@ -71,11 +76,11 @@ SigMFFileInputGUI::SigMFFileInputGUI(DeviceUISet *deviceUISet, QWidget* parent) connect(&m_statusTimer, SIGNAL(timeout()), this, SLOT(updateStatus())); m_statusTimer.start(500); - CRightClickEnabler *startStopRightClickEnabler = new CRightClickEnabler(ui->startStop); - connect(startStopRightClickEnabler, SIGNAL(rightClick(const QPoint &)), this, SLOT(openDeviceSettingsDialog(const QPoint &))); + connect(this, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(openDeviceSettingsDialog(const QPoint &))); setAccelerationCombo(); displaySettings(); + makeUIConnections(); updateStartStop(); ui->trackNavTimeSlider->setEnabled(false); @@ -663,19 +668,39 @@ void SigMFFileInputGUI::setNumberStr(int n, QString& s) void SigMFFileInputGUI::openDeviceSettingsDialog(const QPoint& p) { - BasicDeviceSettingsDialog dialog(this); - dialog.setUseReverseAPI(m_settings.m_useReverseAPI); - dialog.setReverseAPIAddress(m_settings.m_reverseAPIAddress); - dialog.setReverseAPIPort(m_settings.m_reverseAPIPort); - dialog.setReverseAPIDeviceIndex(m_settings.m_reverseAPIDeviceIndex); + if (m_contextMenuType == ContextMenuDeviceSettings) + { + BasicDeviceSettingsDialog dialog(this); + dialog.setUseReverseAPI(m_settings.m_useReverseAPI); + dialog.setReverseAPIAddress(m_settings.m_reverseAPIAddress); + dialog.setReverseAPIPort(m_settings.m_reverseAPIPort); + dialog.setReverseAPIDeviceIndex(m_settings.m_reverseAPIDeviceIndex); - dialog.move(p); - dialog.exec(); + dialog.move(p); + dialog.exec(); - m_settings.m_useReverseAPI = dialog.useReverseAPI(); - m_settings.m_reverseAPIAddress = dialog.getReverseAPIAddress(); - m_settings.m_reverseAPIPort = dialog.getReverseAPIPort(); - m_settings.m_reverseAPIDeviceIndex = dialog.getReverseAPIDeviceIndex(); + m_settings.m_useReverseAPI = dialog.useReverseAPI(); + m_settings.m_reverseAPIAddress = dialog.getReverseAPIAddress(); + m_settings.m_reverseAPIPort = dialog.getReverseAPIPort(); + m_settings.m_reverseAPIDeviceIndex = dialog.getReverseAPIDeviceIndex(); - sendSettings(); + sendSettings(); + } + + resetContextMenuType(); +} + +void SigMFFileInputGUI::makeUIConnections() +{ + QObject::connect(ui->startStop, &ButtonSwitch::toggled, this, &SigMFFileInputGUI::on_startStop_toggled); + QObject::connect(ui->infoDetails, &QPushButton::clicked, this, &SigMFFileInputGUI::on_infoDetails_clicked); + QObject::connect(ui->captureTable, &QTableWidget::itemSelectionChanged, this, &SigMFFileInputGUI::on_captureTable_itemSelectionChanged); + QObject::connect(ui->trackNavTimeSlider, &QSlider::valueChanged, this, &SigMFFileInputGUI::on_trackNavTimeSlider_valueChanged); + QObject::connect(ui->playTrack, &ButtonSwitch::toggled, this, &SigMFFileInputGUI::on_playTrack_toggled); + QObject::connect(ui->playTrackLoop, &ButtonSwitch::toggled, this, &SigMFFileInputGUI::on_playTrackLoop_toggled); + QObject::connect(ui->fullNavTimeSlider, &QSlider::valueChanged, this, &SigMFFileInputGUI::on_fullNavTimeSlider_valueChanged); + QObject::connect(ui->playFull, &ButtonSwitch::toggled, this, &SigMFFileInputGUI::on_playFull_toggled); + QObject::connect(ui->playFullLoop, &ButtonSwitch::toggled, this, &SigMFFileInputGUI::on_playFullLoop_toggled); + QObject::connect(ui->showFileDialog, &QPushButton::clicked, this, &SigMFFileInputGUI::on_showFileDialog_clicked); + QObject::connect(ui->acceleration, QOverload::of(&QComboBox::currentIndexChanged), this, &SigMFFileInputGUI::on_acceleration_currentIndexChanged); } diff --git a/plugins/samplesource/sigmffileinput/sigmffileinputgui.h b/plugins/samplesource/sigmffileinput/sigmffileinputgui.h index fea452537..b2a72848e 100644 --- a/plugins/samplesource/sigmffileinput/sigmffileinputgui.h +++ b/plugins/samplesource/sigmffileinput/sigmffileinputgui.h @@ -50,7 +50,6 @@ public: private: Ui::SigMFFileInputGUI* ui; - DeviceUISet* m_deviceUISet; SigMFFileInputSettings m_settings; int m_currentTrackIndex; bool m_doApplySettings; @@ -94,6 +93,7 @@ private: void setAccelerationCombo(); void setNumberStr(int n, QString& s); bool handleMessage(const Message& message); + void makeUIConnections(); private slots: void handleInputMessages(); diff --git a/plugins/samplesource/sigmffileinput/sigmffileinputgui.ui b/plugins/samplesource/sigmffileinput/sigmffileinputgui.ui index 8db2c990b..1c50bcce2 100644 --- a/plugins/samplesource/sigmffileinput/sigmffileinputgui.ui +++ b/plugins/samplesource/sigmffileinput/sigmffileinputgui.ui @@ -6,20 +6,26 @@ 0 0 - 360 - 420 + 450 + 436
- + 0 0 - 360 - 420 + 450 + 436 + + + + + 470 + 16777215 @@ -823,23 +829,6 @@ - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - diff --git a/plugins/samplesource/soapysdrinput/readme.md b/plugins/samplesource/soapysdrinput/readme.md index 05b8b6fab..31b116333 100644 --- a/plugins/samplesource/soapysdrinput/readme.md +++ b/plugins/samplesource/soapysdrinput/readme.md @@ -73,6 +73,8 @@ When installed the Red Pitaya SoapySDR plugin lists a Red Pitaya device even if

Interface

+The top and bottom bars of the device window are described [here](../../../sdrgui/device/readme.md) + ![SoapySDR input plugin GUI](../../../doc/img/SoapySDRInput_plugin1.png) The top part described by number tags is common for all devices. The bottom part under the "A" tag depends on the SoapySDR device implementation. The corresponding widgets are stacked vertically inside a scrollable area as there may be many controls depending on how the device interface is implemented in SoapySDR. Move the slider on the right to see all parameters available. diff --git a/plugins/samplesource/soapysdrinput/soapysdrinputgui.cpp b/plugins/samplesource/soapysdrinput/soapysdrinputgui.cpp index b4b60e20d..d8f074d48 100644 --- a/plugins/samplesource/soapysdrinput/soapysdrinputgui.cpp +++ b/plugins/samplesource/soapysdrinput/soapysdrinputgui.cpp @@ -18,6 +18,7 @@ #include #include #include +#include #include "dsp/dspengine.h" #include "dsp/dspcommands.h" @@ -25,7 +26,6 @@ #include "device/deviceuiset.h" #include "util/simpleserializer.h" #include "gui/glspectrum.h" -#include "gui/crightclickenabler.h" #include "gui/basicdevicesettingsdialog.h" #include "soapygui/discreterangegui.h" #include "soapygui/intervalrangegui.h" @@ -42,7 +42,6 @@ SoapySDRInputGui::SoapySDRInputGui(DeviceUISet *deviceUISet, QWidget* parent) : DeviceGUI(parent), ui(new Ui::SoapySDRInputGui), - m_deviceUISet(deviceUISet), m_forceSettings(true), m_doApplySettings(true), m_sampleSource(0), @@ -59,8 +58,13 @@ SoapySDRInputGui::SoapySDRInputGui(DeviceUISet *deviceUISet, QWidget* parent) : m_autoDCCorrection(0), m_autoIQCorrection(0) { + m_deviceUISet = deviceUISet; + setAttribute(Qt::WA_DeleteOnClose, true); m_sampleSource = (SoapySDRInput*) m_deviceUISet->m_deviceAPI->getSampleSource(); - ui->setupUi(this); + ui->setupUi(getContents()); + setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Expanding); + getContents()->setStyleSheet("#SoapySDRInputGui { background-color: rgb(64, 64, 64); }"); + m_helpURL = "plugins/samplesource/soapysdrinput/readme.md"; ui->centerFrequency->setColorMapper(ColorMapper(ColorMapper::GrayGold)); uint64_t f_min, f_max; @@ -92,8 +96,7 @@ SoapySDRInputGui::SoapySDRInputGui(DeviceUISet *deviceUISet, QWidget* parent) : connect(&m_statusTimer, SIGNAL(timeout()), this, SLOT(updateStatus())); m_statusTimer.start(500); - CRightClickEnabler *startStopRightClickEnabler = new CRightClickEnabler(ui->startStop); - connect(startStopRightClickEnabler, SIGNAL(rightClick(const QPoint &)), this, SLOT(openDeviceSettingsDialog(const QPoint &))); + connect(this, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(openDeviceSettingsDialog(const QPoint &))); displaySettings(); @@ -101,6 +104,7 @@ SoapySDRInputGui::SoapySDRInputGui(DeviceUISet *deviceUISet, QWidget* parent) : m_sampleSource->setMessageQueueToGUI(&m_inputMessageQueue); sendSettings(); + makeUIConnections(); } SoapySDRInputGui::~SoapySDRInputGui() @@ -444,6 +448,12 @@ bool SoapySDRInputGui::deserialize(const QByteArray& data) } } +void SoapySDRInputGui::resizeEvent(QResizeEvent* size) +{ + resize(360, height()); + size->accept(); +} + bool SoapySDRInputGui::handleMessage(const Message& message) { if (SoapySDRInput::MsgConfigureSoapySDRInput::match(message)) @@ -908,19 +918,36 @@ void SoapySDRInputGui::updateStatus() void SoapySDRInputGui::openDeviceSettingsDialog(const QPoint& p) { - BasicDeviceSettingsDialog dialog(this); - dialog.setUseReverseAPI(m_settings.m_useReverseAPI); - dialog.setReverseAPIAddress(m_settings.m_reverseAPIAddress); - dialog.setReverseAPIPort(m_settings.m_reverseAPIPort); - dialog.setReverseAPIDeviceIndex(m_settings.m_reverseAPIDeviceIndex); + if (m_contextMenuType == ContextMenuDeviceSettings) + { + BasicDeviceSettingsDialog dialog(this); + dialog.setUseReverseAPI(m_settings.m_useReverseAPI); + dialog.setReverseAPIAddress(m_settings.m_reverseAPIAddress); + dialog.setReverseAPIPort(m_settings.m_reverseAPIPort); + dialog.setReverseAPIDeviceIndex(m_settings.m_reverseAPIDeviceIndex); - dialog.move(p); - dialog.exec(); + dialog.move(p); + dialog.exec(); - m_settings.m_useReverseAPI = dialog.useReverseAPI(); - m_settings.m_reverseAPIAddress = dialog.getReverseAPIAddress(); - m_settings.m_reverseAPIPort = dialog.getReverseAPIPort(); - m_settings.m_reverseAPIDeviceIndex = dialog.getReverseAPIDeviceIndex(); + m_settings.m_useReverseAPI = dialog.useReverseAPI(); + m_settings.m_reverseAPIAddress = dialog.getReverseAPIAddress(); + m_settings.m_reverseAPIPort = dialog.getReverseAPIPort(); + m_settings.m_reverseAPIDeviceIndex = dialog.getReverseAPIDeviceIndex(); - sendSettings(); + sendSettings(); + } + + resetContextMenuType(); +} + +void SoapySDRInputGui::makeUIConnections() +{ + QObject::connect(ui->centerFrequency, &ValueDial::changed, this, &SoapySDRInputGui::on_centerFrequency_changed); + QObject::connect(ui->LOppm, &QSlider::valueChanged, this, &SoapySDRInputGui::on_LOppm_valueChanged); + QObject::connect(ui->dcOffset, &ButtonSwitch::toggled, this, &SoapySDRInputGui::on_dcOffset_toggled); + QObject::connect(ui->iqImbalance, &ButtonSwitch::toggled, this, &SoapySDRInputGui::on_iqImbalance_toggled); + QObject::connect(ui->decim, QOverload::of(&QComboBox::currentIndexChanged), this, &SoapySDRInputGui::on_decim_currentIndexChanged); + QObject::connect(ui->fcPos, QOverload::of(&QComboBox::currentIndexChanged), this, &SoapySDRInputGui::on_fcPos_currentIndexChanged); + QObject::connect(ui->transverter, &TransverterButton::clicked, this, &SoapySDRInputGui::on_transverter_clicked); + QObject::connect(ui->startStop, &ButtonSwitch::toggled, this, &SoapySDRInputGui::on_startStop_toggled); } diff --git a/plugins/samplesource/soapysdrinput/soapysdrinputgui.h b/plugins/samplesource/soapysdrinput/soapysdrinputgui.h index 56bd33042..b21db63b7 100644 --- a/plugins/samplesource/soapysdrinput/soapysdrinputgui.h +++ b/plugins/samplesource/soapysdrinput/soapysdrinputgui.h @@ -52,6 +52,9 @@ public: virtual bool deserialize(const QByteArray& data); virtual MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; } +protected: + void resizeEvent(QResizeEvent* size); + private: void createRangesControl( ItemSettingGUI **settingGUI, @@ -64,10 +67,10 @@ private: void createIndividualGainsControl(const std::vector& individualGainsList); void createCorrectionsControl(); void createArgumentsControl(const SoapySDR::ArgInfoList& argInfoList, bool deviceArguments); + void makeUIConnections(); Ui::SoapySDRInputGui* ui; - DeviceUISet* m_deviceUISet; bool m_forceSettings; bool m_doApplySettings; SoapySDRInputSettings m_settings; diff --git a/plugins/samplesource/soapysdrinput/soapysdrinputgui.ui b/plugins/samplesource/soapysdrinput/soapysdrinputgui.ui index ee59b8d69..9c3494e51 100644 --- a/plugins/samplesource/soapysdrinput/soapysdrinputgui.ui +++ b/plugins/samplesource/soapysdrinput/soapysdrinputgui.ui @@ -6,14 +6,26 @@ 0 0 - 324 - 176 + 360 + 238
+ + + 0 + 0 + + - 320 - 132 + 360 + 0 + + + + + 380 + 16777215 @@ -116,7 +128,7 @@ Liberation Mono - 20 + 16 @@ -363,6 +375,18 @@ + + + 0 + 0 + + + + + 356 + 0 + + Qt::ScrollBarAsNeeded @@ -374,8 +398,8 @@ 0 0 - 318 - 49 + 352 + 83 diff --git a/plugins/samplesource/testsource/testsourcegui.cpp b/plugins/samplesource/testsource/testsourcegui.cpp index b13a30f4d..404546566 100644 --- a/plugins/samplesource/testsource/testsourcegui.cpp +++ b/plugins/samplesource/testsource/testsourcegui.cpp @@ -22,12 +22,12 @@ #include #include #include +#include #include "ui_testsourcegui.h" #include "plugin/pluginapi.h" #include "gui/colormapper.h" #include "gui/glspectrum.h" -#include "gui/crightclickenabler.h" #include "gui/basicdevicesettingsdialog.h" #include "dsp/dspengine.h" #include "dsp/dspcommands.h" @@ -42,7 +42,6 @@ TestSourceGui::TestSourceGui(DeviceUISet *deviceUISet, QWidget* parent) : DeviceGUI(parent), ui(new Ui::TestSourceGui), - m_deviceUISet(deviceUISet), m_settings(), m_doApplySettings(true), m_forceSettings(true), @@ -51,9 +50,14 @@ TestSourceGui::TestSourceGui(DeviceUISet *deviceUISet, QWidget* parent) : m_lastEngineState(DeviceAPI::StNotStarted) { qDebug("TestSourceGui::TestSourceGui"); + m_deviceUISet = deviceUISet; + setAttribute(Qt::WA_DeleteOnClose, true); m_sampleSource = m_deviceUISet->m_deviceAPI->getSampleSource(); - ui->setupUi(this); + ui->setupUi(getContents()); + setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); + getContents()->setStyleSheet("#TestSourceGui { background-color: rgb(64, 64, 64); }"); + m_helpURL = "plugins/samplesource/testsource/readme.md"; ui->centerFrequency->setColorMapper(ColorMapper(ColorMapper::GrayGold)); ui->centerFrequency->setValueRange(7, 0, 9999999); ui->sampleRate->setColorMapper(ColorMapper(ColorMapper::GrayGreenYellow)); @@ -63,6 +67,7 @@ TestSourceGui::TestSourceGui(DeviceUISet *deviceUISet, QWidget* parent) : ui->frequencyShiftLabel->setText(QString("%1").arg(QChar(0x94, 0x03))); displaySettings(); + makeUIConnections(); connect(&m_updateTimer, SIGNAL(timeout()), this, SLOT(updateHardware())); connect(&m_statusTimer, SIGNAL(timeout()), this, SLOT(updateStatus())); @@ -71,8 +76,7 @@ TestSourceGui::TestSourceGui(DeviceUISet *deviceUISet, QWidget* parent) : connect(&m_inputMessageQueue, SIGNAL(messageEnqueued()), this, SLOT(handleInputMessages()), Qt::QueuedConnection); m_sampleSource->setMessageQueueToGUI(&m_inputMessageQueue); - CRightClickEnabler *startStopRightClickEnabler = new CRightClickEnabler(ui->startStop); - connect(startStopRightClickEnabler, SIGNAL(rightClick(const QPoint &)), this, SLOT(openDeviceSettingsDialog(const QPoint &))); + connect(this, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(openDeviceSettingsDialog(const QPoint &))); } TestSourceGui::~TestSourceGui() @@ -110,6 +114,12 @@ bool TestSourceGui::deserialize(const QByteArray& data) } } +void TestSourceGui::resizeEvent(QResizeEvent* size) +{ + adjustSize(); + size->accept(); +} + void TestSourceGui::on_startStop_toggled(bool checked) { if (m_doApplySettings) @@ -487,19 +497,46 @@ void TestSourceGui::updateSampleRateAndFrequency() void TestSourceGui::openDeviceSettingsDialog(const QPoint& p) { - BasicDeviceSettingsDialog dialog(this); - dialog.setUseReverseAPI(m_settings.m_useReverseAPI); - dialog.setReverseAPIAddress(m_settings.m_reverseAPIAddress); - dialog.setReverseAPIPort(m_settings.m_reverseAPIPort); - dialog.setReverseAPIDeviceIndex(m_settings.m_reverseAPIDeviceIndex); + if (m_contextMenuType == ContextMenuDeviceSettings) + { + BasicDeviceSettingsDialog dialog(this); + dialog.setUseReverseAPI(m_settings.m_useReverseAPI); + dialog.setReverseAPIAddress(m_settings.m_reverseAPIAddress); + dialog.setReverseAPIPort(m_settings.m_reverseAPIPort); + dialog.setReverseAPIDeviceIndex(m_settings.m_reverseAPIDeviceIndex); - dialog.move(p); - dialog.exec(); + dialog.move(p); + dialog.exec(); - m_settings.m_useReverseAPI = dialog.useReverseAPI(); - m_settings.m_reverseAPIAddress = dialog.getReverseAPIAddress(); - m_settings.m_reverseAPIPort = dialog.getReverseAPIPort(); - m_settings.m_reverseAPIDeviceIndex = dialog.getReverseAPIDeviceIndex(); + m_settings.m_useReverseAPI = dialog.useReverseAPI(); + m_settings.m_reverseAPIAddress = dialog.getReverseAPIAddress(); + m_settings.m_reverseAPIPort = dialog.getReverseAPIPort(); + m_settings.m_reverseAPIDeviceIndex = dialog.getReverseAPIDeviceIndex(); - sendSettings(); + sendSettings(); + } + + resetContextMenuType(); +} + +void TestSourceGui::makeUIConnections() +{ + QObject::connect(ui->startStop, &ButtonSwitch::toggled, this, &TestSourceGui::on_startStop_toggled); + QObject::connect(ui->centerFrequency, &ValueDial::changed, this, &TestSourceGui::on_centerFrequency_changed); + QObject::connect(ui->autoCorr, QOverload::of(&QComboBox::currentIndexChanged), this, &TestSourceGui::on_autoCorr_currentIndexChanged); + QObject::connect(ui->frequencyShift, &ValueDialZ::changed, this, &TestSourceGui::on_frequencyShift_changed); + QObject::connect(ui->decimation, QOverload::of(&QComboBox::currentIndexChanged), this, &TestSourceGui::on_decimation_currentIndexChanged); + QObject::connect(ui->fcPos, QOverload::of(&QComboBox::currentIndexChanged), this, &TestSourceGui::on_fcPos_currentIndexChanged); + QObject::connect(ui->sampleRate, &ValueDial::changed, this, &TestSourceGui::on_sampleRate_changed); + QObject::connect(ui->sampleSize, QOverload::of(&QComboBox::currentIndexChanged), this, &TestSourceGui::on_sampleSize_currentIndexChanged); + QObject::connect(ui->amplitudeCoarse, &QSlider::valueChanged, this, &TestSourceGui::on_amplitudeCoarse_valueChanged); + QObject::connect(ui->amplitudeFine, &QSlider::valueChanged, this, &TestSourceGui::on_amplitudeFine_valueChanged); + QObject::connect(ui->modulation, QOverload::of(&QComboBox::currentIndexChanged), this, &TestSourceGui::on_modulation_currentIndexChanged); + QObject::connect(ui->modulationFrequency, &QDial::valueChanged, this, &TestSourceGui::on_modulationFrequency_valueChanged); + QObject::connect(ui->amModulation, &QDial::valueChanged, this, &TestSourceGui::on_amModulation_valueChanged); + QObject::connect(ui->fmDeviation, &QDial::valueChanged, this, &TestSourceGui::on_fmDeviation_valueChanged); + QObject::connect(ui->dcBias, &QSlider::valueChanged, this, &TestSourceGui::on_dcBias_valueChanged); + QObject::connect(ui->iBias, &QSlider::valueChanged, this, &TestSourceGui::on_iBias_valueChanged); + QObject::connect(ui->qBias, &QSlider::valueChanged, this, &TestSourceGui::on_qBias_valueChanged); + QObject::connect(ui->phaseImbalance, &QSlider::valueChanged, this, &TestSourceGui::on_phaseImbalance_valueChanged); } diff --git a/plugins/samplesource/testsource/testsourcegui.h b/plugins/samplesource/testsource/testsourcegui.h index f4fad8d1d..ead209b5d 100644 --- a/plugins/samplesource/testsource/testsourcegui.h +++ b/plugins/samplesource/testsource/testsourcegui.h @@ -46,10 +46,12 @@ public: bool deserialize(const QByteArray& data); virtual MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; } +protected: + void resizeEvent(QResizeEvent* size); + private: Ui::TestSourceGui* ui; - DeviceUISet* m_deviceUISet; TestSourceSettings m_settings; QTimer m_updateTimer; QTimer m_statusTimer; @@ -71,6 +73,7 @@ private: void updateAmpFineLimit(); void updateFrequencyShiftLimit(); bool handleMessage(const Message& message); + void makeUIConnections(); private slots: void handleInputMessages(); diff --git a/plugins/samplesource/testsource/testsourcegui.ui b/plugins/samplesource/testsource/testsourcegui.ui index d5768cdd8..4852944ea 100644 --- a/plugins/samplesource/testsource/testsourcegui.ui +++ b/plugins/samplesource/testsource/testsourcegui.ui @@ -7,11 +7,11 @@ 0 0 360 - 300 + 331 - + 0 0 @@ -19,7 +19,13 @@ 360 - 300 + 331 + + + + + 386 + 343 @@ -131,7 +137,10 @@ Liberation Mono - 20 + 16 + 50 + false + false @@ -269,6 +278,12 @@ + + + 55 + 0 + + 50 @@ -403,6 +418,9 @@ Liberation Mono 12 + 50 + false + false @@ -559,6 +577,9 @@ Liberation Mono 12 + 50 + false + false @@ -686,17 +707,16 @@ - - - - Qt::Horizontal - - - + + + 0 + 22 + + Amp fine @@ -710,6 +730,12 @@ 0 + + + 0 + 22 + + Amp coarse @@ -808,6 +834,12 @@ + + + 0 + 22 + + Q bias @@ -829,6 +861,12 @@ + + + 0 + 22 + + I bias @@ -873,6 +911,12 @@ + + + 0 + 22 + + DC bias @@ -917,6 +961,12 @@ + + + 0 + 22 + + Phase @@ -967,9 +1017,6 @@ - - - diff --git a/plugins/samplesource/testsource/testsourcesettings.cpp b/plugins/samplesource/testsource/testsourcesettings.cpp index 2c343f242..b94d7e044 100644 --- a/plugins/samplesource/testsource/testsourcesettings.cpp +++ b/plugins/samplesource/testsource/testsourcesettings.cpp @@ -71,6 +71,7 @@ QByteArray TestSourceSettings::serialize() const s.writeString(19, m_reverseAPIAddress); s.writeU32(20, m_reverseAPIPort); s.writeU32(21, m_reverseAPIDeviceIndex); + return s.final(); } diff --git a/plugins/samplesource/usrpinput/readme.md b/plugins/samplesource/usrpinput/readme.md index be639aa92..3d57a4803 100644 --- a/plugins/samplesource/usrpinput/readme.md +++ b/plugins/samplesource/usrpinput/readme.md @@ -6,8 +6,9 @@ This input sample source plugin gets its samples from a [USRP device](https://ww

Interface

-![USRP input plugin GUI](../../../doc/img/USRPInput_plugin.png) +The top and bottom bars of the device window are described [here](../../../sdrgui/device/readme.md) +![USRP input plugin GUI](../../../doc/img/USRPInput_plugin.png)

1: Start/Stop

@@ -19,7 +20,7 @@ Device start / stop button.

2A: Sample rate

-This is the sample rate at which IQ samples are transfered the device to SDRangel, in kS/s (k) or MS/s (M). +This is the sample rate at which IQ samples are transfered the device to SDRangel, in kS/s (k) or MS/s (M).

2B: Stream sample rate

@@ -130,7 +131,7 @@ This label turns green when data is being received from the device. - **O**: turns red if stream experiences overruns - **T**: turns red if stream experiences timeouts - + The stream warning indicators are reset when the acqusition is started.

Dependendices

diff --git a/plugins/samplesource/usrpinput/usrpinputgui.cpp b/plugins/samplesource/usrpinput/usrpinputgui.cpp index db606d134..39a085e8d 100644 --- a/plugins/samplesource/usrpinput/usrpinputgui.cpp +++ b/plugins/samplesource/usrpinput/usrpinputgui.cpp @@ -21,13 +21,13 @@ #include #include #include +#include #include #include "ui_usrpinputgui.h" #include "gui/colormapper.h" #include "gui/glspectrum.h" -#include "gui/crightclickenabler.h" #include "gui/basicdevicesettingsdialog.h" #include "dsp/dspengine.h" #include "dsp/dspcommands.h" @@ -37,7 +37,6 @@ USRPInputGUI::USRPInputGUI(DeviceUISet *deviceUISet, QWidget* parent) : DeviceGUI(parent), ui(new Ui::USRPInputGUI), - m_deviceUISet(deviceUISet), m_settings(), m_sampleRateMode(true), m_sampleRate(0), @@ -47,9 +46,14 @@ USRPInputGUI::USRPInputGUI(DeviceUISet *deviceUISet, QWidget* parent) : m_statusCounter(0), m_deviceStatusCounter(0) { + m_deviceUISet = deviceUISet; + setAttribute(Qt::WA_DeleteOnClose, true); m_usrpInput = (USRPInput*) m_deviceUISet->m_deviceAPI->getSampleSource(); - ui->setupUi(this); + ui->setupUi(getContents()); + setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); + getContents()->setStyleSheet("#USRPInputGUI { background-color: rgb(64, 64, 64); }"); + m_helpURL = "plugins/samplesource/usrpinput/readme.md"; float minF, maxF; @@ -81,12 +85,12 @@ USRPInputGUI::USRPInputGUI(DeviceUISet *deviceUISet, QWidget* parent) : m_statusTimer.start(500); displaySettings(); + makeUIConnections(); connect(&m_inputMessageQueue, SIGNAL(messageEnqueued()), this, SLOT(handleInputMessages()), Qt::QueuedConnection); m_usrpInput->setMessageQueueToGUI(&m_inputMessageQueue); - CRightClickEnabler *startStopRightClickEnabler = new CRightClickEnabler(ui->startStop); - connect(startStopRightClickEnabler, SIGNAL(rightClick(const QPoint &)), this, SLOT(openDeviceSettingsDialog(const QPoint &))); + connect(this, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(openDeviceSettingsDialog(const QPoint &))); } USRPInputGUI::~USRPInputGUI() @@ -149,6 +153,12 @@ bool USRPInputGUI::deserialize(const QByteArray& data) } } +void USRPInputGUI::resizeEvent(QResizeEvent* size) +{ + adjustSize(); + size->accept(); +} + bool USRPInputGUI::handleMessage(const Message& message) { if (USRPInput::MsgConfigureUSRP::match(message)) @@ -604,19 +614,42 @@ void USRPInputGUI::on_sampleRateMode_toggled(bool checked) void USRPInputGUI::openDeviceSettingsDialog(const QPoint& p) { - BasicDeviceSettingsDialog dialog(this); - dialog.setUseReverseAPI(m_settings.m_useReverseAPI); - dialog.setReverseAPIAddress(m_settings.m_reverseAPIAddress); - dialog.setReverseAPIPort(m_settings.m_reverseAPIPort); - dialog.setReverseAPIDeviceIndex(m_settings.m_reverseAPIDeviceIndex); + if (m_contextMenuType == ContextMenuDeviceSettings) + { + BasicDeviceSettingsDialog dialog(this); + dialog.setUseReverseAPI(m_settings.m_useReverseAPI); + dialog.setReverseAPIAddress(m_settings.m_reverseAPIAddress); + dialog.setReverseAPIPort(m_settings.m_reverseAPIPort); + dialog.setReverseAPIDeviceIndex(m_settings.m_reverseAPIDeviceIndex); - dialog.move(p); - dialog.exec(); + dialog.move(p); + dialog.exec(); - m_settings.m_useReverseAPI = dialog.useReverseAPI(); - m_settings.m_reverseAPIAddress = dialog.getReverseAPIAddress(); - m_settings.m_reverseAPIPort = dialog.getReverseAPIPort(); - m_settings.m_reverseAPIDeviceIndex = dialog.getReverseAPIDeviceIndex(); + m_settings.m_useReverseAPI = dialog.useReverseAPI(); + m_settings.m_reverseAPIAddress = dialog.getReverseAPIAddress(); + m_settings.m_reverseAPIPort = dialog.getReverseAPIPort(); + m_settings.m_reverseAPIDeviceIndex = dialog.getReverseAPIDeviceIndex(); - sendSettings(); + sendSettings(); + } + + resetContextMenuType(); +} + +void USRPInputGUI::makeUIConnections() +{ + QObject::connect(ui->startStop, &ButtonSwitch::toggled, this, &USRPInputGUI::on_startStop_toggled); + QObject::connect(ui->centerFrequency, &ValueDial::changed, this, &USRPInputGUI::on_centerFrequency_changed); + QObject::connect(ui->dcOffset, &ButtonSwitch::toggled, this, &USRPInputGUI::on_dcOffset_toggled); + QObject::connect(ui->iqImbalance, &ButtonSwitch::toggled, this, &USRPInputGUI::on_iqImbalance_toggled); + QObject::connect(ui->sampleRate, &ValueDial::changed, this, &USRPInputGUI::on_sampleRate_changed); + QObject::connect(ui->swDecim, QOverload::of(&QComboBox::currentIndexChanged), this, &USRPInputGUI::on_swDecim_currentIndexChanged); + QObject::connect(ui->lpf, &ValueDial::changed, this, &USRPInputGUI::on_lpf_changed); + QObject::connect(ui->loOffset, &ValueDialZ::changed, this, &USRPInputGUI::on_loOffset_changed); + QObject::connect(ui->gainMode, QOverload::of(&QComboBox::currentIndexChanged), this, &USRPInputGUI::on_gainMode_currentIndexChanged); + QObject::connect(ui->gain, &QSlider::valueChanged, this, &USRPInputGUI::on_gain_valueChanged); + QObject::connect(ui->antenna, QOverload::of(&QComboBox::currentIndexChanged), this, &USRPInputGUI::on_antenna_currentIndexChanged); + QObject::connect(ui->clockSource, QOverload::of(&QComboBox::currentIndexChanged), this, &USRPInputGUI::on_clockSource_currentIndexChanged); + QObject::connect(ui->transverter, &TransverterButton::clicked, this, &USRPInputGUI::on_transverter_clicked); + QObject::connect(ui->sampleRateMode, &QToolButton::toggled, this, &USRPInputGUI::on_sampleRateMode_toggled); } diff --git a/plugins/samplesource/usrpinput/usrpinputgui.h b/plugins/samplesource/usrpinput/usrpinputgui.h index 9790d7fb2..84aa4e271 100644 --- a/plugins/samplesource/usrpinput/usrpinputgui.h +++ b/plugins/samplesource/usrpinput/usrpinputgui.h @@ -50,12 +50,13 @@ public: QByteArray serialize() const; bool deserialize(const QByteArray& data); virtual MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; } - virtual bool handleMessage(const Message& message); + +protected: + void resizeEvent(QResizeEvent* size); private: Ui::USRPInputGUI* ui; - DeviceUISet* m_deviceUISet; USRPInput* m_usrpInput; //!< Same object as above but gives easy access to USRPInput methods and attributes that are used intensively USRPInputSettings m_settings; bool m_sampleRateMode; //!< true: device, false: base band sample rate update mode @@ -79,6 +80,8 @@ private: void updateSampleRate(); void updateFrequencyLimits(); void blockApplySettings(bool block); + bool handleMessage(const Message& message); + void makeUIConnections(); private slots: void handleInputMessages(); diff --git a/plugins/samplesource/usrpinput/usrpinputgui.ui b/plugins/samplesource/usrpinput/usrpinputgui.ui index 80be6c42a..0d6c974d7 100644 --- a/plugins/samplesource/usrpinput/usrpinputgui.ui +++ b/plugins/samplesource/usrpinput/usrpinputgui.ui @@ -7,11 +7,11 @@ 0 0 360 - 290 + 174
- + 0 0 @@ -19,7 +19,13 @@ 360 - 290 + 174 + + + + + 380 + 221 @@ -138,7 +144,7 @@ Liberation Mono - 20 + 16 50 false @@ -771,44 +777,20 @@ - - - - Qt::Horizontal - - - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - ButtonSwitch - QToolButton -
gui/buttonswitch.h
-
ValueDial QWidget
gui/valuedial.h
1
+ + ButtonSwitch + QToolButton +
gui/buttonswitch.h
+
ValueDialZ QWidget diff --git a/plugins/samplesource/usrpinput/usrpinputsettings.cpp b/plugins/samplesource/usrpinput/usrpinputsettings.cpp index 1a7c0b2be..9cd5210de 100644 --- a/plugins/samplesource/usrpinput/usrpinputsettings.cpp +++ b/plugins/samplesource/usrpinput/usrpinputsettings.cpp @@ -66,6 +66,7 @@ QByteArray USRPInputSettings::serialize() const s.writeU32(14, m_reverseAPIPort); s.writeU32(15, m_reverseAPIDeviceIndex); s.writeS32(16, m_loOffset); + return s.final(); } diff --git a/plugins/samplesource/xtrxinput/readme.md b/plugins/samplesource/xtrxinput/readme.md index 57c63f134..b82329800 100644 --- a/plugins/samplesource/xtrxinput/readme.md +++ b/plugins/samplesource/xtrxinput/readme.md @@ -44,6 +44,8 @@ For a group the syntax is the same but the group name is prefixed with `@` like:

Interface

+The top and bottom bars of the device window are described [here](../../../sdrgui/device/readme.md) + ![LimeSDR input plugin GUI](../../../doc/img/XTRXInput_plugin.png)

1: Common stream parameters

diff --git a/plugins/samplesource/xtrxinput/xtrxinputgui.cpp b/plugins/samplesource/xtrxinput/xtrxinputgui.cpp index 5065b0db9..35ad4668d 100644 --- a/plugins/samplesource/xtrxinput/xtrxinputgui.cpp +++ b/plugins/samplesource/xtrxinput/xtrxinputgui.cpp @@ -21,13 +21,13 @@ #include #include #include +#include #include #include "ui_xtrxinputgui.h" #include "gui/colormapper.h" #include "gui/glspectrum.h" -#include "gui/crightclickenabler.h" #include "gui/basicdevicesettingsdialog.h" #include "dsp/dspengine.h" #include "dsp/dspcommands.h" @@ -37,7 +37,6 @@ XTRXInputGUI::XTRXInputGUI(DeviceUISet *deviceUISet, QWidget* parent) : DeviceGUI(parent), ui(new Ui::XTRXInputGUI), - m_deviceUISet(deviceUISet), m_settings(), m_sampleRateMode(true), m_sampleRate(0), @@ -47,9 +46,14 @@ XTRXInputGUI::XTRXInputGUI(DeviceUISet *deviceUISet, QWidget* parent) : m_statusCounter(0), m_deviceStatusCounter(0) { + m_deviceUISet = deviceUISet; + setAttribute(Qt::WA_DeleteOnClose, true); m_XTRXInput = (XTRXInput*) m_deviceUISet->m_deviceAPI->getSampleSource(); - ui->setupUi(this); + ui->setupUi(getContents()); + setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); + getContents()->setStyleSheet("#XTRXInputGUI { background-color: rgb(64, 64, 64); }"); + m_helpURL = "plugins/samplesource/xtrxinput/readme.md"; float minF, maxF, stepF; @@ -73,10 +77,10 @@ XTRXInputGUI::XTRXInputGUI(DeviceUISet *deviceUISet, QWidget* parent) : connect(&m_statusTimer, SIGNAL(timeout()), this, SLOT(updateStatus())); m_statusTimer.start(500); - CRightClickEnabler *startStopRightClickEnabler = new CRightClickEnabler(ui->startStop); - connect(startStopRightClickEnabler, SIGNAL(rightClick(const QPoint &)), this, SLOT(openDeviceSettingsDialog(const QPoint &))); + connect(this, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(openDeviceSettingsDialog(const QPoint &))); displaySettings(); + makeUIConnections(); connect(&m_inputMessageQueue, SIGNAL(messageEnqueued()), this, SLOT(handleInputMessages()), Qt::QueuedConnection); } @@ -119,6 +123,12 @@ bool XTRXInputGUI::deserialize(const QByteArray& data) } } +void XTRXInputGUI::resizeEvent(QResizeEvent* size) +{ + adjustSize(); + size->accept(); +} + bool XTRXInputGUI::handleMessage(const Message& message) { @@ -631,19 +641,47 @@ void XTRXInputGUI::on_sampleRateMode_toggled(bool checked) void XTRXInputGUI::openDeviceSettingsDialog(const QPoint& p) { - BasicDeviceSettingsDialog dialog(this); - dialog.setUseReverseAPI(m_settings.m_useReverseAPI); - dialog.setReverseAPIAddress(m_settings.m_reverseAPIAddress); - dialog.setReverseAPIPort(m_settings.m_reverseAPIPort); - dialog.setReverseAPIDeviceIndex(m_settings.m_reverseAPIDeviceIndex); + if (m_contextMenuType == ContextMenuDeviceSettings) + { + BasicDeviceSettingsDialog dialog(this); + dialog.setUseReverseAPI(m_settings.m_useReverseAPI); + dialog.setReverseAPIAddress(m_settings.m_reverseAPIAddress); + dialog.setReverseAPIPort(m_settings.m_reverseAPIPort); + dialog.setReverseAPIDeviceIndex(m_settings.m_reverseAPIDeviceIndex); - dialog.move(p); - dialog.exec(); + dialog.move(p); + dialog.exec(); - m_settings.m_useReverseAPI = dialog.useReverseAPI(); - m_settings.m_reverseAPIAddress = dialog.getReverseAPIAddress(); - m_settings.m_reverseAPIPort = dialog.getReverseAPIPort(); - m_settings.m_reverseAPIDeviceIndex = dialog.getReverseAPIDeviceIndex(); + m_settings.m_useReverseAPI = dialog.useReverseAPI(); + m_settings.m_reverseAPIAddress = dialog.getReverseAPIAddress(); + m_settings.m_reverseAPIPort = dialog.getReverseAPIPort(); + m_settings.m_reverseAPIDeviceIndex = dialog.getReverseAPIDeviceIndex(); - sendSettings(); + sendSettings(); + } + + resetContextMenuType(); +} + +void XTRXInputGUI::makeUIConnections() +{ + QObject::connect(ui->startStop, &ButtonSwitch::toggled, this, &XTRXInputGUI::on_startStop_toggled); + QObject::connect(ui->centerFrequency, &ValueDial::changed, this, &XTRXInputGUI::on_centerFrequency_changed); + QObject::connect(ui->ncoFrequency, &ValueDialZ::changed, this, &XTRXInputGUI::on_ncoFrequency_changed); + QObject::connect(ui->ncoEnable, &ButtonSwitch::toggled, this, &XTRXInputGUI::on_ncoEnable_toggled); + QObject::connect(ui->dcOffset, &ButtonSwitch::toggled, this, &XTRXInputGUI::on_dcOffset_toggled); + QObject::connect(ui->iqImbalance, &ButtonSwitch::toggled, this, &XTRXInputGUI::on_iqImbalance_toggled); + QObject::connect(ui->sampleRate, &ValueDial::changed, this, &XTRXInputGUI::on_sampleRate_changed); + QObject::connect(ui->hwDecim, QOverload::of(&QComboBox::currentIndexChanged), this, &XTRXInputGUI::on_hwDecim_currentIndexChanged); + QObject::connect(ui->swDecim, QOverload::of(&QComboBox::currentIndexChanged), this, &XTRXInputGUI::on_swDecim_currentIndexChanged); + QObject::connect(ui->lpf, &ValueDial::changed, this, &XTRXInputGUI::on_lpf_changed); + QObject::connect(ui->gainMode, QOverload::of(&QComboBox::currentIndexChanged), this, &XTRXInputGUI::on_gainMode_currentIndexChanged); + QObject::connect(ui->gain, &QDial::valueChanged, this, &XTRXInputGUI::on_gain_valueChanged); + QObject::connect(ui->lnaGain, &QDial::valueChanged, this, &XTRXInputGUI::on_lnaGain_valueChanged); + QObject::connect(ui->tiaGain, QOverload::of(&QComboBox::currentIndexChanged), this, &XTRXInputGUI::on_tiaGain_currentIndexChanged); + QObject::connect(ui->pgaGain, &QDial::valueChanged, this, &XTRXInputGUI::on_pgaGain_valueChanged); + QObject::connect(ui->antenna, QOverload::of(&QComboBox::currentIndexChanged), this, &XTRXInputGUI::on_antenna_currentIndexChanged); + QObject::connect(ui->extClock, &ExternalClockButton::clicked, this, &XTRXInputGUI::on_extClock_clicked); + QObject::connect(ui->pwrmode, QOverload::of(&QComboBox::currentIndexChanged), this, &XTRXInputGUI::on_pwrmode_currentIndexChanged); + QObject::connect(ui->sampleRateMode, &QToolButton::toggled, this, &XTRXInputGUI::on_sampleRateMode_toggled); } diff --git a/plugins/samplesource/xtrxinput/xtrxinputgui.h b/plugins/samplesource/xtrxinput/xtrxinputgui.h index 36a793791..5973d816c 100644 --- a/plugins/samplesource/xtrxinput/xtrxinputgui.h +++ b/plugins/samplesource/xtrxinput/xtrxinputgui.h @@ -46,10 +46,12 @@ public: bool deserialize(const QByteArray& data); virtual MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; } +protected: + void resizeEvent(QResizeEvent* size); + private: Ui::XTRXInputGUI* ui; - DeviceUISet* m_deviceUISet; XTRXInput* m_XTRXInput; //!< Same object as above but gives easy access to XTRXInput methods and attributes that are used intensively XTRXInputSettings m_settings; bool m_sampleRateMode; //!< true: device, false: base band sample rate update mode @@ -74,6 +76,7 @@ private: void updateADCRate(); void blockApplySettings(bool block); bool handleMessage(const Message& message); + void makeUIConnections(); private slots: void handleInputMessages(); diff --git a/plugins/samplesource/xtrxinput/xtrxinputgui.ui b/plugins/samplesource/xtrxinput/xtrxinputgui.ui index de4b9edce..4146cc88f 100644 --- a/plugins/samplesource/xtrxinput/xtrxinputgui.ui +++ b/plugins/samplesource/xtrxinput/xtrxinputgui.ui @@ -7,19 +7,25 @@ 0 0 370 - 290 + 207
- + 0 0 - 360 - 290 + 370 + 207 + + + + + 390 + 264 @@ -128,7 +134,7 @@ Liberation Mono - 20 + 16 50 false @@ -1012,6 +1018,7 @@ + Liberation Sans 8 @@ -1068,30 +1075,6 @@ QToolTip{background-color: white; color: black;} - - - - Qt::Horizontal - - - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - @@ -1106,17 +1089,17 @@ QToolTip{background-color: white; color: black;} QToolButton
gui/buttonswitch.h
- - ExternalClockButton - QToolButton -
gui/externalclockbutton.h
-
ValueDialZ QWidget
gui/valuedialz.h
1
+ + ExternalClockButton + QToolButton +
gui/externalclockbutton.h
+
diff --git a/sdrbase/CMakeLists.txt b/sdrbase/CMakeLists.txt index 899bd7bdc..c8be0d4b8 100644 --- a/sdrbase/CMakeLists.txt +++ b/sdrbase/CMakeLists.txt @@ -176,6 +176,7 @@ set(sdrbase_SOURCES pipes/objectpipe.cpp pipes/objectpipesregistrations.cpp + settings/configuration.cpp settings/featuresetpreset.cpp settings/preferences.cpp settings/preset.cpp @@ -389,6 +390,7 @@ set(sdrbase_HEADERS plugin/pluginapi.h plugin/pluginmanager.h + settings/configuration.h settings/featuresetpreset.h settings/preferences.h settings/preset.h diff --git a/sdrbase/channel/channelapi.cpp b/sdrbase/channel/channelapi.cpp index 557359d4a..861507547 100644 --- a/sdrbase/channel/channelapi.cpp +++ b/sdrbase/channel/channelapi.cpp @@ -28,7 +28,6 @@ ChannelAPI::ChannelAPI(const QString& uri, StreamType streamType) : m_uri(uri), m_indexInDeviceSet(-1), m_deviceSetIndex(0), - m_deviceAPI(0), m_uid(UidCalculator::getNewObjectId()) { connect(&m_inputMessageQueue, SIGNAL(messageEnqueued()), this, SLOT(handleInputMessages())); diff --git a/sdrbase/channel/channelapi.h b/sdrbase/channel/channelapi.h index dd284db0a..8bdb4a9d0 100644 --- a/sdrbase/channel/channelapi.h +++ b/sdrbase/channel/channelapi.h @@ -37,6 +37,7 @@ namespace SWGSDRangel class SWGChannelSettings; class SWGChannelReport; class SWGChannelActions; + class SWGWorkspaceInfo; } class SDRBASE_API ChannelAPI : public QObject { @@ -52,6 +53,8 @@ public: ChannelAPI(const QString& name, StreamType streamType); virtual ~ChannelAPI() {} virtual void destroy() = 0; + virtual void setDeviceAPI(DeviceAPI*) = 0; + virtual DeviceAPI *getDeviceAPI() = 0; virtual void getIdentifier(QString& id) = 0; virtual QString getIdentifier() const = 0; @@ -119,6 +122,17 @@ public: errorMessage = "Not implemented"; return 501; } + /** + * API adapter for the channel UI workspace GET requests + */ + virtual int webapiWorkspaceGet( + SWGSDRangel::SWGWorkspaceInfo& query, + QString& errorMessage) + { + (void) query; + errorMessage = "Not implemented"; return 501; + } + int getIndexInDeviceSet() const { return m_indexInDeviceSet; } void setIndexInDeviceSet(int indexInDeviceSet) @@ -129,8 +143,6 @@ public: int getDeviceSetIndex() const { return m_deviceSetIndex; } void setDeviceSetIndex(int deviceSetIndex) { m_deviceSetIndex = deviceSetIndex; } - DeviceAPI *getDeviceAPI() { return m_deviceAPI; } - void setDeviceAPI(DeviceAPI *deviceAPI) { m_deviceAPI = deviceAPI; } uint64_t getUID() const { return m_uid; } // MIMO support @@ -167,7 +179,6 @@ private: int m_indexInDeviceSet; int m_deviceSetIndex; - DeviceAPI *m_deviceAPI; uint64_t m_uid; signals: diff --git a/sdrbase/commands/command.h b/sdrbase/commands/command.h index 194f99d3f..8010b2360 100644 --- a/sdrbase/commands/command.h +++ b/sdrbase/commands/command.h @@ -58,7 +58,7 @@ public: bool getRelease() const { return m_release; } QString getKeyLabel() const; - void run(const QString& apiAddress, int apiPort, int deviceSetIndex); + void run(const QString& apiAddress, int apiPort, int deviceSetIndex = 0); void kill(); QProcess::ProcessState getLastProcessState() const; bool getLastProcessError(QProcess::ProcessError& error) const; diff --git a/sdrbase/device/deviceapi.cpp b/sdrbase/device/deviceapi.cpp index c8a1448f0..e6da31bae 100644 --- a/sdrbase/device/deviceapi.cpp +++ b/sdrbase/device/deviceapi.cpp @@ -44,6 +44,7 @@ DeviceAPI::DeviceAPI( m_pluginInterface(nullptr), m_masterTimer(DSPEngine::instance()->getMasterTimer()), m_samplingDeviceSequence(0), + m_workspaceIndex(0), m_buddySharedPtr(nullptr), m_isBuddyLeader(false), m_deviceSourceEngine(deviceSourceEngine), @@ -819,3 +820,9 @@ void DeviceAPI::renumerateChannels() } } } + +void DeviceAPI::setDeviceSetIndex(int deviceSetIndex) +{ + m_deviceTabIndex = deviceSetIndex; + renumerateChannels(); +} diff --git a/sdrbase/device/deviceapi.h b/sdrbase/device/deviceapi.h index b11766a0d..f2477b10b 100644 --- a/sdrbase/device/deviceapi.h +++ b/sdrbase/device/deviceapi.h @@ -117,12 +117,16 @@ public: uint32_t getSamplingDeviceSequence() const { return m_samplingDeviceSequence; } const QString& getHardwareUserArguments() const { return m_hardwareUserArguments; } + void setWorkspaceIndex(int index) { m_workspaceIndex = index; } + int getWorkspaceIndex() const { return m_workspaceIndex; } + void setDeviceNbItems(uint32_t nbItems); void setDeviceItemIndex(uint32_t index); uint32_t getDeviceNbItems() const { return m_deviceNbItems; } uint32_t getDeviceItemIndex() const { return m_deviceItemIndex; } int getDeviceSetIndex() const { return m_deviceTabIndex; } + void setDeviceSetIndex(int deviceSetIndex); PluginInterface *getPluginInterface() { return m_pluginInterface; } void getDeviceEngineStateStr(QString& state, int subsystemIndex = 0); @@ -182,6 +186,7 @@ protected: QString m_samplingDeviceDisplayName; //!< The human readable name identifying this instance uint32_t m_samplingDeviceSequence; //!< The device sequence. >0 when more than one device of the same type is connected QString m_hardwareUserArguments; //!< User given arguments to be used at hardware level i.e. for the hardware device and device sequence + int m_workspaceIndex; //!< Used only by the GUI but accessible via web API // Buddies (single Rx or single Tx) diff --git a/sdrbase/device/deviceenumerator.cpp b/sdrbase/device/deviceenumerator.cpp index c0ddec020..f4ecd56c9 100644 --- a/sdrbase/device/deviceenumerator.cpp +++ b/sdrbase/device/deviceenumerator.cpp @@ -506,3 +506,92 @@ int DeviceEnumerator::getMIMOSamplingDeviceIndex(const QString& deviceId, int se return -1; } + +int DeviceEnumerator::getBestRxSamplingDeviceIndex(const QString& deviceId, const QString& deviceSerial, int deviceSequence, int deviceItemIndex) +{ + return getBestSamplingDeviceIndex(m_rxEnumeration, deviceId, deviceSerial, deviceSequence, deviceItemIndex); +} + +int DeviceEnumerator::getBestTxSamplingDeviceIndex(const QString& deviceId, const QString& deviceSerial, int deviceSequence, int deviceItemIndex) +{ + return getBestSamplingDeviceIndex(m_txEnumeration, deviceId, deviceSerial, deviceSequence, deviceItemIndex); +} + +int DeviceEnumerator::getBestMIMOSamplingDeviceIndex(const QString& deviceId, const QString& deviceSerial, int deviceSequence) +{ + return getBestSamplingDeviceIndex(m_mimoEnumeration, deviceId, deviceSerial, deviceSequence, -1); +} + +int DeviceEnumerator::getBestSamplingDeviceIndex( + const DevicesEnumeration& devicesEnumeration, + const QString& deviceId, + const QString& deviceSerial, + int deviceSequence, + int deviceItemIndex +) +{ + DevicesEnumeration::const_iterator it = devicesEnumeration.begin(); + DevicesEnumeration::const_iterator itFirstOfKind = devicesEnumeration.end(); + DevicesEnumeration::const_iterator itMatchSequence = devicesEnumeration.end(); + + for (; it != devicesEnumeration.end(); ++it) + { + if ((it->m_samplingDevice.id == deviceId) && + ( + ((deviceItemIndex < 0) || (deviceItemIndex > it->m_samplingDevice.deviceNbItems)) || // take first if item index is negative or out of range + ((deviceItemIndex <= it->m_samplingDevice.deviceNbItems) && (deviceItemIndex == it->m_samplingDevice.deviceItemIndex)) // take exact item index if in range + ) + ) + { + if (itFirstOfKind == devicesEnumeration.end()) { + itFirstOfKind = it; + } + + if (deviceSerial.isNull() || deviceSerial.isEmpty()) + { + if (it->m_samplingDevice.sequence == deviceSequence) { + break; + } + } + else + { + if (it->m_samplingDevice.serial == deviceSerial) { + break; + } else if(it->m_samplingDevice.sequence == deviceSequence) { + itMatchSequence = it; + } + } + } + } + + if (it == devicesEnumeration.end()) // no exact match + { + if (itMatchSequence != devicesEnumeration.end()) // match sequence and device type ? + { + qDebug("DeviceEnumerator::getBestSamplingDeviceIndex: sequence matched: id: %s ser: %s seq: %d", + qPrintable(itMatchSequence->m_samplingDevice.id), + qPrintable(itMatchSequence->m_samplingDevice.serial), + itMatchSequence->m_samplingDevice.sequence); + return itMatchSequence - devicesEnumeration.begin(); + } + else if (itFirstOfKind != devicesEnumeration.end()) // match just device type ? + { + qDebug("DeviceEnumerator::getBestSamplingDeviceIndex: first of kind matched: id: %s ser: %s seq: %d", + qPrintable(itFirstOfKind->m_samplingDevice.id), + qPrintable(itFirstOfKind->m_samplingDevice.serial), + itFirstOfKind->m_samplingDevice.sequence); + return itFirstOfKind - devicesEnumeration.begin(); + } + else // definitely not found ! + { + qDebug("DeviceEnumerator::getBestSamplingDeviceIndex: no match"); + return -1; + } + } + else // exact match + { + qDebug("DeviceEnumerator::getBestSamplingDeviceIndex: serial matched (exact): id: %s ser: %s", + qPrintable(it->m_samplingDevice.id), qPrintable(it->m_samplingDevice.serial)); + return it - devicesEnumeration.begin(); + } +} diff --git a/sdrbase/device/deviceenumerator.h b/sdrbase/device/deviceenumerator.h index 3ef4f0489..3cd7e68d4 100644 --- a/sdrbase/device/deviceenumerator.h +++ b/sdrbase/device/deviceenumerator.h @@ -62,6 +62,9 @@ public: int getRxSamplingDeviceIndex(const QString& deviceId, int sequence, int deviceItemIndex); int getTxSamplingDeviceIndex(const QString& deviceId, int sequence, int deviceItemIndex); int getMIMOSamplingDeviceIndex(const QString& deviceId, int sequence); + int getBestRxSamplingDeviceIndex(const QString& deviceId, const QString& serial, int sequence, int deviceItemIndex); + int getBestTxSamplingDeviceIndex(const QString& deviceId, const QString& serial, int sequence, int deviceItemIndex); + int getBestMIMOSamplingDeviceIndex(const QString& deviceId, const QString& serial, int sequence); private: struct DeviceEnumeration @@ -91,6 +94,13 @@ private: bool isRxEnumerated(const QString& deviceHwId, int deviceSequence); bool isTxEnumerated(const QString& deviceHwId, int deviceSequence); bool isMIMOEnumerated(const QString& deviceHwId, int deviceSequence); + int getBestSamplingDeviceIndex( + const DevicesEnumeration& devicesEnumeration, + const QString& deviceId, + const QString& serial, + int sequence, + int deviceItemIndex + ); }; #endif /* SDRBASE_DEVICE_DEVICEENUMERATOR_H_ */ diff --git a/sdrbase/device/deviceset.h b/sdrbase/device/deviceset.h index c4c981d03..d697f1b85 100644 --- a/sdrbase/device/deviceset.h +++ b/sdrbase/device/deviceset.h @@ -51,6 +51,7 @@ public: int getNumberOfChannels() const { return m_channelInstanceRegistrations.size(); } int getIndex() const { return m_deviceTabIndex; } + void setIndex(int index) { m_deviceTabIndex = index; } void freeChannels(); const ChannelAPI *getChannelAt(int channelIndex) const; ChannelAPI *getChannelAt(int channelIndex); diff --git a/sdrbase/dsp/dspengine.cpp b/sdrbase/dsp/dspengine.cpp index 4685a4707..de1561cd3 100644 --- a/sdrbase/dsp/dspengine.cpp +++ b/sdrbase/dsp/dspengine.cpp @@ -40,7 +40,7 @@ DSPEngine::DSPEngine() : DSPEngine::~DSPEngine() { - std::vector::iterator it = m_deviceSourceEngines.begin(); + QList::iterator it = m_deviceSourceEngines.begin(); while (it != m_deviceSourceEngines.end()) { @@ -63,6 +63,7 @@ DSPDeviceSourceEngine *DSPEngine::addDeviceSourceEngine() { m_deviceSourceEngines.push_back(new DSPDeviceSourceEngine(m_deviceSourceEnginesUIDSequence)); m_deviceSourceEnginesUIDSequence++; + m_deviceEngineReferences.push_back(DeviceEngineReference{0, m_deviceSourceEngines.back(), nullptr, nullptr}); return m_deviceSourceEngines.back(); } @@ -73,7 +74,15 @@ void DSPEngine::removeLastDeviceSourceEngine() DSPDeviceSourceEngine *lastDeviceEngine = m_deviceSourceEngines.back(); delete lastDeviceEngine; m_deviceSourceEngines.pop_back(); - m_deviceSourceEnginesUIDSequence--; + + for (int i = 0; i < m_deviceEngineReferences.size(); i++) + { + if (m_deviceEngineReferences[i].m_deviceSourceEngine == lastDeviceEngine) + { + m_deviceEngineReferences.removeAt(i); + break; + } + } } } @@ -81,6 +90,7 @@ DSPDeviceSinkEngine *DSPEngine::addDeviceSinkEngine() { m_deviceSinkEngines.push_back(new DSPDeviceSinkEngine(m_deviceSinkEnginesUIDSequence)); m_deviceSinkEnginesUIDSequence++; + m_deviceEngineReferences.push_back(DeviceEngineReference{1, nullptr, m_deviceSinkEngines.back(), nullptr}); return m_deviceSinkEngines.back(); } @@ -91,7 +101,15 @@ void DSPEngine::removeLastDeviceSinkEngine() DSPDeviceSinkEngine *lastDeviceEngine = m_deviceSinkEngines.back(); delete lastDeviceEngine; m_deviceSinkEngines.pop_back(); - m_deviceSinkEnginesUIDSequence--; + + for (int i = 0; i < m_deviceEngineReferences.size(); i++) + { + if (m_deviceEngineReferences[i].m_deviceSinkEngine == lastDeviceEngine) + { + m_deviceEngineReferences.removeAt(i); + break; + } + } } } @@ -99,6 +117,7 @@ DSPDeviceMIMOEngine *DSPEngine::addDeviceMIMOEngine() { m_deviceMIMOEngines.push_back(new DSPDeviceMIMOEngine(m_deviceMIMOEnginesUIDSequence)); m_deviceMIMOEnginesUIDSequence++; + m_deviceEngineReferences.push_back(DeviceEngineReference{2, nullptr, nullptr, m_deviceMIMOEngines.back()}); return m_deviceMIMOEngines.back(); } @@ -109,56 +128,44 @@ void DSPEngine::removeLastDeviceMIMOEngine() DSPDeviceMIMOEngine *lastDeviceEngine = m_deviceMIMOEngines.back(); delete lastDeviceEngine; m_deviceMIMOEngines.pop_back(); - m_deviceMIMOEnginesUIDSequence--; + + for (int i = 0; i < m_deviceEngineReferences.size(); i++) + { + if (m_deviceEngineReferences[i].m_deviceMIMOEngine == lastDeviceEngine) + { + m_deviceEngineReferences.removeAt(i); + break; + } + } } } -DSPDeviceSourceEngine *DSPEngine::getDeviceSourceEngineByUID(uint uid) +void DSPEngine::removeDeviceEngineAt(int deviceIndex) { - std::vector::iterator it = m_deviceSourceEngines.begin(); - - while (it != m_deviceSourceEngines.end()) - { - if ((*it)->getUID() == uid) { - return *it; - } - - ++it; + if (deviceIndex >= m_deviceEngineReferences.size()) { + return; } - return nullptr; -} - -DSPDeviceSinkEngine *DSPEngine::getDeviceSinkEngineByUID(uint uid) -{ - std::vector::iterator it = m_deviceSinkEngines.begin(); - - while (it != m_deviceSinkEngines.end()) + if (m_deviceEngineReferences[deviceIndex].m_deviceEngineType == 0) // source { - if ((*it)->getUID() == uid) { - return *it; - } - - ++it; + DSPDeviceSourceEngine *deviceEngine = m_deviceEngineReferences[deviceIndex].m_deviceSourceEngine; + delete deviceEngine; + m_deviceSourceEngines.removeAll(deviceEngine); + } + else if (m_deviceEngineReferences[deviceIndex].m_deviceEngineType == 1) // sink + { + DSPDeviceSinkEngine *deviceEngine = m_deviceEngineReferences[deviceIndex].m_deviceSinkEngine; + delete deviceEngine; + m_deviceSinkEngines.removeAll(deviceEngine); + } + else if (m_deviceEngineReferences[deviceIndex].m_deviceEngineType == 2) // MIMO + { + DSPDeviceMIMOEngine *deviceEngine = m_deviceEngineReferences[deviceIndex].m_deviceMIMOEngine; + delete deviceEngine; + m_deviceMIMOEngines.removeAll(deviceEngine); } - return nullptr; -} - -DSPDeviceMIMOEngine *DSPEngine::getDeviceMIMOEngineByUID(uint uid) -{ - std::vector::iterator it = m_deviceMIMOEngines.begin(); - - while (it != m_deviceMIMOEngines.end()) - { - if ((*it)->getUID() == uid) { - return *it; - } - - ++it; - } - - return nullptr; + m_deviceEngineReferences.removeAt(deviceIndex); } bool DSPEngine::hasDVSerialSupport() @@ -200,4 +207,4 @@ void DSPEngine::createFFTFactory(const QString& fftWisdomFileName) void DSPEngine::preAllocateFFTs() { m_fftFactory->preallocate(7, 10, 1, 0); // pre-acllocate forward FFT only 1 per size from 128 to 1024 -} \ No newline at end of file +} diff --git a/sdrbase/dsp/dspengine.h b/sdrbase/dsp/dspengine.h index 832b68da2..1f1bafbd1 100644 --- a/sdrbase/dsp/dspengine.h +++ b/sdrbase/dsp/dspengine.h @@ -52,20 +52,19 @@ public: DSPDeviceMIMOEngine *addDeviceMIMOEngine(); void removeLastDeviceMIMOEngine(); + void removeDeviceEngineAt(int deviceIndex); + AudioDeviceManager *getAudioDeviceManager() { return &m_audioDeviceManager; } AMBEEngine *getAMBEEngine() { return &m_ambeEngine; } uint32_t getDeviceSourceEnginesNumber() const { return m_deviceSourceEngines.size(); } - DSPDeviceSourceEngine *getDeviceSourceEngineByIndex(uint deviceIndex) { return m_deviceSourceEngines[deviceIndex]; } - DSPDeviceSourceEngine *getDeviceSourceEngineByUID(uint uid); + DSPDeviceSourceEngine *getDeviceSourceEngineByIndex(unsigned int deviceIndex) { return m_deviceSourceEngines[deviceIndex]; } uint32_t getDeviceSinkEnginesNumber() const { return m_deviceSinkEngines.size(); } - DSPDeviceSinkEngine *getDeviceSinkEngineByIndex(uint deviceIndex) { return m_deviceSinkEngines[deviceIndex]; } - DSPDeviceSinkEngine *getDeviceSinkEngineByUID(uint uid); + DSPDeviceSinkEngine *getDeviceSinkEngineByIndex(unsigned int deviceIndex) { return m_deviceSinkEngines[deviceIndex]; } uint32_t getDeviceMIMOEnginesNumber() const { return m_deviceMIMOEngines.size(); } - DSPDeviceMIMOEngine *getDeviceMIMOEngineByIndex(uint deviceIndex) { return m_deviceMIMOEngines[deviceIndex]; } - DSPDeviceMIMOEngine *getDeviceMIMOEngineByUID(uint uid); + DSPDeviceMIMOEngine *getDeviceMIMOEngineByIndex(unsigned int deviceIndex) { return m_deviceMIMOEngines[deviceIndex]; } // Serial DV methods: @@ -89,12 +88,21 @@ public: FFTFactory *getFFTFactory() { return m_fftFactory; } private: - std::vector m_deviceSourceEngines; - uint m_deviceSourceEnginesUIDSequence; - std::vector m_deviceSinkEngines; - uint m_deviceSinkEnginesUIDSequence; - std::vector m_deviceMIMOEngines; - uint m_deviceMIMOEnginesUIDSequence; + struct DeviceEngineReference + { + int m_deviceEngineType; //!< 0: Rx, 1: Tx, 2: MIMO + DSPDeviceSourceEngine *m_deviceSourceEngine; + DSPDeviceSinkEngine *m_deviceSinkEngine; + DSPDeviceMIMOEngine *m_deviceMIMOEngine; + }; + + QList m_deviceSourceEngines; + unsigned int m_deviceSourceEnginesUIDSequence; + QList m_deviceSinkEngines; + unsigned int m_deviceSinkEnginesUIDSequence; + QList m_deviceMIMOEngines; + unsigned int m_deviceMIMOEnginesUIDSequence; + QList m_deviceEngineReferences; AudioDeviceManager m_audioDeviceManager; int m_audioInputDeviceIndex; int m_audioOutputDeviceIndex; diff --git a/sdrbase/dsp/spectrumvis.cpp b/sdrbase/dsp/spectrumvis.cpp index 6b2f094a1..b5705f8cf 100644 --- a/sdrbase/dsp/spectrumvis.cpp +++ b/sdrbase/dsp/spectrumvis.cpp @@ -27,13 +27,6 @@ #include "spectrumvis.h" -#ifndef LINUX -inline double log2(double n) -{ - return log(n) / log(2.0); -} -#endif - MESSAGE_CLASS_DEFINITION(SpectrumVis::MsgConfigureSpectrumVis, Message) MESSAGE_CLASS_DEFINITION(SpectrumVis::MsgConfigureScalingFactor, Message) MESSAGE_CLASS_DEFINITION(SpectrumVis::MsgConfigureWSpectrumOpenClose, Message) diff --git a/sdrbase/dsp/spectrumvis.h b/sdrbase/dsp/spectrumvis.h index 9fab52eab..e214062a3 100644 --- a/sdrbase/dsp/spectrumvis.h +++ b/sdrbase/dsp/spectrumvis.h @@ -139,6 +139,8 @@ public: virtual ~SpectrumVis(); void setGLSpectrum(GLSpectrumInterface* glSpectrum) { m_glSpectrum = glSpectrum; } + void setWorkspaceIndex(int index) { m_workspaceIndex = index; } + int getWorkspaceIndex() const { return m_workspaceIndex; } void setScalef(Real scalef); void configureWSSpectrum(const QString& address, uint16_t port); @@ -211,6 +213,7 @@ private: FFTEngine* m_fft; FFTWindow m_window; unsigned int m_fftEngineSequence; + int m_workspaceIndex; std::vector m_fftBuffer; std::vector m_powerSpectrum; //!< displayable power spectrum diff --git a/sdrbase/feature/feature.h b/sdrbase/feature/feature.h index 7f04633cc..0529b3846 100644 --- a/sdrbase/feature/feature.h +++ b/sdrbase/feature/feature.h @@ -150,6 +150,8 @@ public: MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; } //!< Get the queue for asynchronous inbound communication void setMessageQueueToGUI(MessageQueue *queue) { m_guiMessageQueue = queue; } MessageQueue *getMessageQueueToGUI() { return m_guiMessageQueue; } + void setWorkspaceIndex(int index) { m_workspaceIndex = index; } + int getWorkspaceIndex() const { return m_workspaceIndex; } protected: MessageQueue m_inputMessageQueue; @@ -169,6 +171,7 @@ private: QString m_uri; //!< Unique non modifiable identifier attached to channel type uint64_t m_uid; int m_indexInFeatureSet; + int m_workspaceIndex; signals: void indexInFeatureSetChanged(int index); diff --git a/sdrbase/maincore.cpp b/sdrbase/maincore.cpp index f1a7f99a5..242faa779 100644 --- a/sdrbase/maincore.cpp +++ b/sdrbase/maincore.cpp @@ -24,6 +24,7 @@ #include "feature/featureset.h" #include "feature/feature.h" #include "device/deviceset.h" +#include "device/deviceapi.h" #include "channel/channelapi.h" #include "maincore.h" @@ -34,6 +35,11 @@ MESSAGE_CLASS_DEFINITION(MainCore::MsgDeleteInstance, Message) MESSAGE_CLASS_DEFINITION(MainCore::MsgLoadPreset, Message) MESSAGE_CLASS_DEFINITION(MainCore::MsgSavePreset, Message) MESSAGE_CLASS_DEFINITION(MainCore::MsgDeletePreset, Message) +MESSAGE_CLASS_DEFINITION(MainCore::MsgLoadConfiguration, Message) +MESSAGE_CLASS_DEFINITION(MainCore::MsgSaveConfiguration, Message) +MESSAGE_CLASS_DEFINITION(MainCore::MsgDeleteConfiguration, Message) +MESSAGE_CLASS_DEFINITION(MainCore::MsgAddWorkspace, Message) +MESSAGE_CLASS_DEFINITION(MainCore::MsgDeleteEmptyWorkspaces, Message) MESSAGE_CLASS_DEFINITION(MainCore::MsgLoadFeatureSetPreset, Message) MESSAGE_CLASS_DEFINITION(MainCore::MsgSaveFeatureSetPreset, Message) MESSAGE_CLASS_DEFINITION(MainCore::MsgDeleteFeatureSetPreset, Message) @@ -51,6 +57,10 @@ MESSAGE_CLASS_DEFINITION(MainCore::MsgChannelReport, Message) MESSAGE_CLASS_DEFINITION(MainCore::MsgChannelSettings, Message) MESSAGE_CLASS_DEFINITION(MainCore::MsgChannelDemodReport, Message) MESSAGE_CLASS_DEFINITION(MainCore::MsgChannelDemodQuery, Message) +MESSAGE_CLASS_DEFINITION(MainCore::MsgMoveDeviceUIToWorkspace, Message) +MESSAGE_CLASS_DEFINITION(MainCore::MsgMoveMainSpectrumUIToWorkspace, Message) +MESSAGE_CLASS_DEFINITION(MainCore::MsgMoveFeatureUIToWorkspace, Message) +MESSAGE_CLASS_DEFINITION(MainCore::MsgMoveChannelUIToWorkspace, Message) MESSAGE_CLASS_DEFINITION(MainCore::MsgMapItem, Message) MESSAGE_CLASS_DEFINITION(MainCore::MsgPacket, Message) MESSAGE_CLASS_DEFINITION(MainCore::MsgTargetAzimuthElevation, Message) @@ -197,6 +207,24 @@ void MainCore::removeLastDeviceSet() } } +void MainCore::removeDeviceSet(int deviceSetIndex) +{ + if (deviceSetIndex < (int) m_deviceSets.size()) + { + DeviceSet *deviceSet = m_deviceSets[deviceSetIndex]; + m_deviceSetsMap.remove(deviceSet); + m_deviceSets.erase(m_deviceSets.begin() + deviceSetIndex); + delete deviceSet; + } + + // Renumerate + for (int i = 0; i < (int) m_deviceSets.size(); i++) + { + m_deviceSets[i]->m_deviceAPI->setDeviceSetIndex(i); + m_deviceSets[i]->setIndex(i); + } +} + void MainCore::addChannelInstance(DeviceSet *deviceSet, ChannelAPI *channelAPI) { m_channelsMap.insert(channelAPI, deviceSet); diff --git a/sdrbase/maincore.h b/sdrbase/maincore.h index 37ca9d563..18b29e7a0 100644 --- a/sdrbase/maincore.h +++ b/sdrbase/maincore.h @@ -167,6 +167,99 @@ public: { } }; + class SDRBASE_API MsgLoadConfiguration : public Message { + MESSAGE_CLASS_DECLARATION + + public: + const Configuration *getConfiguration() const { return m_configuration; } + + static MsgLoadConfiguration* create(const Configuration *configuration) + { + return new MsgLoadConfiguration(configuration); + } + + private: + const Configuration *m_configuration; + + MsgLoadConfiguration(const Configuration *configuration) : + Message(), + m_configuration(configuration) + { } + }; + + class SDRBASE_API MsgSaveConfiguration : public Message { + MESSAGE_CLASS_DECLARATION + + public: + Configuration *getConfiguration() const { return m_configuration; } + bool isNewConfiguration() const { return m_newConfiguration; } + + static MsgSaveConfiguration* create(Configuration *configuration, bool newConfiguration) + { + return new MsgSaveConfiguration(configuration, newConfiguration); + } + + private: + Configuration *m_configuration; + bool m_newConfiguration; + + MsgSaveConfiguration(Configuration *configuration, bool newConfiguration) : + Message(), + m_configuration(configuration), + m_newConfiguration(newConfiguration) + { } + }; + + class SDRBASE_API MsgDeleteConfiguration : public Message { + MESSAGE_CLASS_DECLARATION + + public: + const Configuration *getConfiguration() const { return m_configuration; } + + static MsgDeleteConfiguration* create(const Configuration *configuration) + { + return new MsgDeleteConfiguration(configuration); + } + + private: + const Configuration *m_configuration; + + MsgDeleteConfiguration(const Configuration *configuration) : + Message(), + m_configuration(configuration) + { } + }; + + class SDRBASE_API MsgAddWorkspace : public Message { + MESSAGE_CLASS_DECLARATION + + public: + static MsgAddWorkspace* create() + { + return new MsgAddWorkspace(); + } + + private: + MsgAddWorkspace() : + Message() + { } + }; + + class SDRBASE_API MsgDeleteEmptyWorkspaces : public Message { + MESSAGE_CLASS_DECLARATION + + public: + static MsgDeleteEmptyWorkspaces* create() + { + return new MsgDeleteEmptyWorkspaces(); + } + + private: + MsgDeleteEmptyWorkspaces() : + Message() + { } + }; + class SDRBASE_API MsgLoadFeatureSetPreset : public Message { MESSAGE_CLASS_DECLARATION @@ -547,6 +640,97 @@ public: { } }; + class SDRBASE_API MsgMoveDeviceUIToWorkspace : public Message { + MESSAGE_CLASS_DECLARATION + + public: + int getDeviceSetIndex() const { return m_deviceSetIndex; } + int getWorkspaceIndex() const { return m_workspaceIndex; } + + static MsgMoveDeviceUIToWorkspace* create(int deviceSetIndex, int workspceIndex) { + return new MsgMoveDeviceUIToWorkspace(deviceSetIndex, workspceIndex); + } + + private: + int m_deviceSetIndex; + int m_workspaceIndex; + + MsgMoveDeviceUIToWorkspace(int deviceSetIndex, int workspceIndex) : + Message(), + m_deviceSetIndex(deviceSetIndex), + m_workspaceIndex(workspceIndex) + { } + }; + + class SDRBASE_API MsgMoveMainSpectrumUIToWorkspace : public Message { + MESSAGE_CLASS_DECLARATION + + public: + int getDeviceSetIndex() const { return m_deviceSetIndex; } + int getWorkspaceIndex() const { return m_workspaceIndex; } + + static MsgMoveMainSpectrumUIToWorkspace* create(int deviceSetIndex, int workspceIndex) { + return new MsgMoveMainSpectrumUIToWorkspace(deviceSetIndex, workspceIndex); + } + + private: + int m_deviceSetIndex; + int m_workspaceIndex; + + MsgMoveMainSpectrumUIToWorkspace(int deviceSetIndex, int workspceIndex) : + Message(), + m_deviceSetIndex(deviceSetIndex), + m_workspaceIndex(workspceIndex) + { } + }; + + class SDRBASE_API MsgMoveFeatureUIToWorkspace : public Message { + MESSAGE_CLASS_DECLARATION + + public: + int getFeatureIndex() const { return m_featureIndex; } + int getWorkspaceIndex() const { return m_workspaceIndex; } + + static MsgMoveFeatureUIToWorkspace* create(int featureIndex, int workspceIndex) { + return new MsgMoveFeatureUIToWorkspace(featureIndex, workspceIndex); + } + + private: + int m_featureIndex; + int m_workspaceIndex; + + MsgMoveFeatureUIToWorkspace(int featureIndex, int workspceIndex) : + Message(), + m_featureIndex(featureIndex), + m_workspaceIndex(workspceIndex) + { } + }; + + class SDRBASE_API MsgMoveChannelUIToWorkspace : public Message { + MESSAGE_CLASS_DECLARATION + + public: + int getDeviceSetIndex() const { return m_deviceSetIndex; } + int getChannelIndex() const { return m_channelIndex; } + int getWorkspaceIndex() const { return m_workspaceIndex; } + + static MsgMoveChannelUIToWorkspace* create(int deviceSetIndex, int channelIndex, int workspceIndex) { + return new MsgMoveChannelUIToWorkspace(deviceSetIndex, channelIndex, workspceIndex); + } + + private: + int m_deviceSetIndex; + int m_channelIndex; + int m_workspaceIndex; + + MsgMoveChannelUIToWorkspace(int deviceSetIndex, int channelIndex, int workspceIndex) : + Message(), + m_deviceSetIndex(deviceSetIndex), + m_channelIndex(channelIndex), + m_workspaceIndex(workspceIndex) + { } + }; + // Message to Map feature to display an item on the map class SDRBASE_API MsgMapItem : public Message { MESSAGE_CLASS_DECLARATION @@ -725,6 +909,7 @@ public: void removeLastFeatureSet(); void appendDeviceSet(int deviceType); void removeLastDeviceSet(); + void removeDeviceSet(int deviceSetIndex); // slave mode - channels void addChannelInstance(DeviceSet *deviceSet, ChannelAPI *channelAPI); void removeChannelInstanceAt(DeviceSet *deviceSet, int channelIndex); @@ -742,6 +927,9 @@ public: friend class MainServer; friend class MainWindow; friend class WebAPIAdapter; + friend class CommandsDialog; + friend class DeviceSetPresetsDialog; + friend class ConfigurationsDialog; signals: void deviceSetAdded(int index, DeviceAPI *device); diff --git a/sdrbase/mainparser.cpp b/sdrbase/mainparser.cpp index ef3cf48b2..fa96f6033 100644 --- a/sdrbase/mainparser.cpp +++ b/sdrbase/mainparser.cpp @@ -34,11 +34,15 @@ MainParser::MainParser() : m_fftwfWisdomOption(QStringList() << "w" << "fftwf-wisdom", "FFTW Wisdom file.", "file", - "") + ""), + m_scratchOption("scratch", "Start from scratch (no current config)."), + m_soapyOption("soapy", "Activate Soapy SDR support.") { + m_serverAddress = ""; // Bind to any address m_serverPort = 8091; - m_mimoSupport = false; + m_scratch = false; + m_soapy = false; m_fftwfWindowFileName = ""; m_parser.setApplicationDescription("Software Defined Radio application"); @@ -48,6 +52,8 @@ MainParser::MainParser() : m_parser.addOption(m_serverAddressOption); m_parser.addOption(m_serverPortOption); m_parser.addOption(m_fftwfWisdomOption); + m_parser.addOption(m_scratchOption); + m_parser.addOption(m_soapyOption); } MainParser::~MainParser() @@ -91,21 +97,11 @@ void MainParser::parse(const QCoreApplication& app) } // FFTWF wisdom file - m_fftwfWindowFileName = m_parser.value(m_fftwfWisdomOption); - // MIMO - from version + // Scratch mode + m_scratch = m_parser.isSet(m_scratchOption); - QStringList versionParts = app.applicationVersion().split("."); - - if (versionParts.size() > 0) - { - bool ok; - int maj = versionParts.at(0).toInt(&ok); - m_mimoSupport = ok && (maj > 4); - } - else - { - m_mimoSupport = false; - } + // Soapy SDR support + m_soapy = m_parser.isSet(m_soapyOption); } diff --git a/sdrbase/mainparser.h b/sdrbase/mainparser.h index 100752798..f472d2733 100644 --- a/sdrbase/mainparser.h +++ b/sdrbase/mainparser.h @@ -34,19 +34,23 @@ public: const QString& getServerAddress() const { return m_serverAddress; } uint16_t getServerPort() const { return m_serverPort; } - bool getMIMOSupport() const { return m_mimoSupport; } + bool getScratch() const { return m_scratch; } + bool getSoapy() const { return m_soapy; } const QString& getFFTWFWisdomFileName() const { return m_fftwfWindowFileName; } private: QString m_serverAddress; uint16_t m_serverPort; QString m_fftwfWindowFileName; - bool m_mimoSupport; //!< obtained from major version + bool m_scratch; + bool m_soapy; QCommandLineParser m_parser; QCommandLineOption m_serverAddressOption; QCommandLineOption m_serverPortOption; QCommandLineOption m_fftwfWisdomOption; + QCommandLineOption m_scratchOption; + QCommandLineOption m_soapyOption; }; diff --git a/sdrbase/pipes/messagepipeslegacy.cpp b/sdrbase/pipes/messagepipeslegacy.cpp new file mode 100644 index 000000000..6d9355bba --- /dev/null +++ b/sdrbase/pipes/messagepipeslegacy.cpp @@ -0,0 +1,78 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2020 Edouard Griffiths, F4EXB // +// // +// This program is free software; you can redistribute it and/or modify // +// it under the terms of the GNU General Public License as published by // +// the Free Software Foundation as version 3 of the License, or // +// (at your option) any later version. // +// // +// This program is distributed in the hope that it will be useful, // +// but WITHOUT ANY WARRANTY; without even the implied warranty of // +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // +// GNU General Public License V3 for more details. // +// // +// You should have received a copy of the GNU General Public License // +// along with this program. If not, see . // +/////////////////////////////////////////////////////////////////////////////////// + +#include + +#include "util/messagequeue.h" + +#include "messagepipeslegacygcworker.h" +#include "messagepipeslegacy.h" +#include "pipeendpoint.h" + +MessagePipesLegacy::MessagePipesLegacy() +{ + m_gcWorker = new MessagePipesLegacyGCWorker(); + m_gcWorker->setC2FRegistrations( + m_registrations.getMutex(), + m_registrations.getElements(), + m_registrations.getConsumers() + ); + m_gcWorker->moveToThread(&m_gcThread); + startGC(); +} + +MessagePipesLegacy::~MessagePipesLegacy() +{ + if (m_gcWorker->isRunning()) { + stopGC(); + } +} + +MessageQueue *MessagePipesLegacy::registerChannelToFeature(const PipeEndPoint *source, PipeEndPoint *dest, const QString& type) +{ + qDebug("MessagePipesLegacy::registerChannelToFeature: %p %p %s", source, dest, qPrintable(type)); + return m_registrations.registerProducerToConsumer(source, dest, type); +} + +MessageQueue *MessagePipesLegacy::unregisterChannelToFeature(const PipeEndPoint *source, PipeEndPoint *dest, const QString& type) +{ + qDebug("MessagePipesLegacy::unregisterChannelToFeature: %p %p %s", source, dest, qPrintable(type)); + MessageQueue *messageQueue = m_registrations.unregisterProducerToConsumer(source, dest, type); + m_gcWorker->addMessageQueueToDelete(messageQueue); + return messageQueue; +} + +QList* MessagePipesLegacy::getMessageQueues(const PipeEndPoint *source, const QString& type) +{ + //qDebug("MessagePipesLegacy::getMessageQueues: %p %s", source, qPrintable(type)); + return m_registrations.getElements(source, type); +} + +void MessagePipesLegacy::startGC() +{ + qDebug("MessagePipesLegacy::startGC"); + m_gcWorker->startWork(); + m_gcThread.start(); +} + +void MessagePipesLegacy::stopGC() +{ + qDebug("MessagePipesLegacy::stopGC"); + m_gcWorker->stopWork(); + m_gcThread.quit(); + m_gcThread.wait(); +} diff --git a/sdrbase/pipes/messagepipeslegacy.h b/sdrbase/pipes/messagepipeslegacy.h new file mode 100644 index 000000000..562e582a8 --- /dev/null +++ b/sdrbase/pipes/messagepipeslegacy.h @@ -0,0 +1,59 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2020 Edouard Griffiths, F4EXB // +// // +// This program is free software; you can redistribute it and/or modify // +// it under the terms of the GNU General Public License as published by // +// the Free Software Foundation as version 3 of the License, or // +// (at your option) any later version. // +// // +// This program is distributed in the hope that it will be useful, // +// but WITHOUT ANY WARRANTY; without even the implied warranty of // +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // +// GNU General Public License V3 for more details. // +// // +// You should have received a copy of the GNU General Public License // +// along with this program. If not, see . // +/////////////////////////////////////////////////////////////////////////////////// + +#ifndef SDRBASE_PIPES_MESSAGEPIPESLEGACY_H_ +#define SDRBASE_PIPES_MESSAGEPIPESLEGACY_H_ + +#include +#include +#include +#include +#include + +#include "export.h" + +#include "messagepipeslegacycommon.h" +#include "elementpipesregistrations.h" + +class PipeEndPoint; +class MessagePipesLegacyGCWorker; +class MessageQueue; + +class SDRBASE_API MessagePipesLegacy : public QObject +{ + Q_OBJECT +public: + MessagePipesLegacy(); + MessagePipesLegacy(const MessagePipesLegacy&) = delete; + MessagePipesLegacy& operator=(const MessagePipesLegacy&) = delete; + ~MessagePipesLegacy(); + + // FIXME: Names of these functions should probably change, as we now support channel or feature at either end + MessageQueue *registerChannelToFeature(const PipeEndPoint *source, PipeEndPoint *dest, const QString& type); + MessageQueue *unregisterChannelToFeature(const PipeEndPoint *source, PipeEndPoint *dest, const QString& type); + QList* getMessageQueues(const PipeEndPoint *source, const QString& type); + +private: + ElementPipesRegistrations m_registrations; + QThread m_gcThread; //!< Garbage collector thread + MessagePipesLegacyGCWorker *m_gcWorker; //!< Garbage collector + + void startGC(); //!< Start garbage collector + void stopGC(); //!< Stop garbage collector +}; + +#endif // SDRBASE_PIPES_MESSAGEPIPESLEGACY_H_ diff --git a/sdrgui/gui/featurewindow.h b/sdrbase/pipes/messagepipeslegacycommon.cpp similarity index 70% rename from sdrgui/gui/featurewindow.h rename to sdrbase/pipes/messagepipeslegacycommon.cpp index 09889d5e9..984a452d5 100644 --- a/sdrgui/gui/featurewindow.h +++ b/sdrbase/pipes/messagepipeslegacycommon.cpp @@ -15,32 +15,6 @@ // along with this program. If not, see . // /////////////////////////////////////////////////////////////////////////////////// -#ifndef INCLUDE_FEATUREWINDOW_H -#define INCLUDE_FEATUREWINDOW_H +#include "messagepipeslegacycommon.h" -#include -#include - -#include "export.h" -#include "featurelayout.h" - -class QBoxLayout; -class QSpacerItem; -class RollupWidget; - -class SDRGUI_API FeatureWindow : public QScrollArea { - Q_OBJECT - -public: - FeatureWindow(QWidget* parent = nullptr); - void addRollupWidget(QWidget* rollupWidget); - -protected: - QWidget* m_container; - FeatureLayout* m_layout; - QSplitter* m_splitter; - - void resizeEvent(QResizeEvent* event); -}; - -#endif // INCLUDE_FEATUREWINDOW_H +MESSAGE_CLASS_DEFINITION(MessagePipesLegacyCommon::MsgReportChannelDeleted, Message) diff --git a/sdrbase/pipes/messagepipeslegacycommon.h b/sdrbase/pipes/messagepipeslegacycommon.h new file mode 100644 index 000000000..42f3b9600 --- /dev/null +++ b/sdrbase/pipes/messagepipeslegacycommon.h @@ -0,0 +1,61 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2020 Edouard Griffiths, F4EXB // +// // +// This program is free software; you can redistribute it and/or modify // +// it under the terms of the GNU General Public License as published by // +// the Free Software Foundation as version 3 of the License, or // +// (at your option) any later version. // +// // +// This program is distributed in the hope that it will be useful, // +// but WITHOUT ANY WARRANTY; without even the implied warranty of // +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // +// GNU General Public License V3 for more details. // +// // +// You should have received a copy of the GNU General Public License // +// along with this program. If not, see . // +/////////////////////////////////////////////////////////////////////////////////// + +#ifndef SDRBASE_PIPES_MESSAGEPIPESLEGACYCOMON_H_ +#define SDRBASE_PIPES_MESSAGEPIPESLEGACYCOMON_H_ + +#include +#include +#include + +#include "export.h" +#include "util/message.h" +#include "elementpipescommon.h" + +class PipeEndPoint; +class MessageQueue; + +class SDRBASE_API MessagePipesLegacyCommon +{ +public: + typedef ElementPipesCommon::RegistrationKey ChannelRegistrationKey; + + /** Send this message to stakeholders when the garbage collector finds that a channel was deleted */ + class SDRBASE_API MsgReportChannelDeleted : public Message { + MESSAGE_CLASS_DECLARATION + + public: + const MessageQueue *getMessageQueue() const { return m_messageQueue; } + const ChannelRegistrationKey& getChannelRegistrationKey() const { return m_channelRegistrationKey; } + + static MsgReportChannelDeleted* create(const MessageQueue *messageQueue, const ChannelRegistrationKey& channelRegistrationKey) { + return new MsgReportChannelDeleted(messageQueue, channelRegistrationKey); + } + + private: + const MessageQueue *m_messageQueue; + ChannelRegistrationKey m_channelRegistrationKey; + + MsgReportChannelDeleted(const MessageQueue *messageQueue, const ChannelRegistrationKey& channelRegistrationKey) : + Message(), + m_messageQueue(messageQueue), + m_channelRegistrationKey(channelRegistrationKey) + { } + }; +}; + +#endif // SDRBASE_PIPES_MESSAGEPIPESLEGACYCOMON_H_ diff --git a/sdrbase/pipes/messagepipeslegacygcworker.cpp b/sdrbase/pipes/messagepipeslegacygcworker.cpp new file mode 100644 index 000000000..f05c65bc3 --- /dev/null +++ b/sdrbase/pipes/messagepipeslegacygcworker.cpp @@ -0,0 +1,78 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2020 Edouard Griffiths, F4EXB // +// // +// This program is free software; you can redistribute it and/or modify // +// it under the terms of the GNU General Public License as published by // +// the Free Software Foundation as version 3 of the License, or // +// (at your option) any later version. // +// // +// This program is distributed in the hope that it will be useful, // +// but WITHOUT ANY WARRANTY; without even the implied warranty of // +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // +// GNU General Public License V3 for more details. // +// // +// You should have received a copy of the GNU General Public License // +// along with this program. If not, see . // +/////////////////////////////////////////////////////////////////////////////////// + +#include "channel/channelapi.h" +#include "feature/feature.h" +#include "util/messagequeue.h" +#include "maincore.h" +#include "messagepipeslegacycommon.h" +#include "messagepipeslegacygcworker.h" + +bool MessagePipesLegacyGCWorker::MessagePipesGC::existsProducer(const PipeEndPoint *pipeEndPoint) +{ + return MainCore::instance()->existsChannel((const ChannelAPI *)pipeEndPoint) + || MainCore::instance()->existsFeature((const Feature *)pipeEndPoint); +} + +bool MessagePipesLegacyGCWorker::MessagePipesGC::existsConsumer(const PipeEndPoint *pipeEndPoint) +{ + return MainCore::instance()->existsChannel((const ChannelAPI *)pipeEndPoint) + || MainCore::instance()->existsFeature((const Feature *)pipeEndPoint); +} + +void MessagePipesLegacyGCWorker::MessagePipesGC::sendMessageToConsumer( + const MessageQueue *, + MessagePipesLegacyCommon::ChannelRegistrationKey, + PipeEndPoint *) +{ +} + +MessagePipesLegacyGCWorker::MessagePipesLegacyGCWorker() : + m_running(false) +{} + +MessagePipesLegacyGCWorker::~MessagePipesLegacyGCWorker() +{} + +void MessagePipesLegacyGCWorker::startWork() +{ + connect(&m_gcTimer, SIGNAL(timeout()), this, SLOT(processGC())); + m_gcTimer.start(10000); // collect garbage every 10s + m_running = true; +} + +void MessagePipesLegacyGCWorker::stopWork() +{ + m_running = false; + m_gcTimer.stop(); + disconnect(&m_gcTimer, SIGNAL(timeout()), this, SLOT(processGC())); +} + +void MessagePipesLegacyGCWorker::addMessageQueueToDelete(MessageQueue *messageQueue) +{ + if (messageQueue) + { + m_gcTimer.start(10000); // restart GC to make sure deletion is postponed + m_messagePipesGC.addElementToDelete(messageQueue); + } +} + +void MessagePipesLegacyGCWorker::processGC() +{ + // qDebug("MessagePipesLegacyGCWorker::processGC"); + m_messagePipesGC.processGC(); +} diff --git a/sdrbase/pipes/messagepipeslegacygcworker.h b/sdrbase/pipes/messagepipeslegacygcworker.h new file mode 100644 index 000000000..309b13125 --- /dev/null +++ b/sdrbase/pipes/messagepipeslegacygcworker.h @@ -0,0 +1,69 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2020 Edouard Griffiths, F4EXB // +// // +// This program is free software; you can redistribute it and/or modify // +// it under the terms of the GNU General Public License as published by // +// the Free Software Foundation as version 3 of the License, or // +// (at your option) any later version. // +// // +// This program is distributed in the hope that it will be useful, // +// but WITHOUT ANY WARRANTY; without even the implied warranty of // +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // +// GNU General Public License V3 for more details. // +// // +// You should have received a copy of the GNU General Public License // +// along with this program. If not, see . // +/////////////////////////////////////////////////////////////////////////////////// + +#ifndef SDRBASE_PIPES_MESSAGEPIPESLEGACYGCWORKER_H_ +#define SDRBASE_PIPES_MESSAGEPIPESLEGACYGCWORKER_H_ + +#include +#include + +#include "export.h" + +#include "messagepipeslegacycommon.h" +#include "elementpipesgc.h" + +class QMutex; + +class SDRBASE_API MessagePipesLegacyGCWorker : public QObject +{ + Q_OBJECT +public: + MessagePipesLegacyGCWorker(); + ~MessagePipesLegacyGCWorker(); + + void setC2FRegistrations( + QMutex *c2fMutex, + QMap> *c2fQueues, + QMap> *c2fPipeEndPoints + ) + { + m_messagePipesGC.setRegistrations(c2fMutex, c2fQueues, c2fPipeEndPoints); + } + + void startWork(); + void stopWork(); + void addMessageQueueToDelete(MessageQueue *messageQueue); + bool isRunning() const { return m_running; } + +private: + class MessagePipesGC : public ElementPipesGC + { + private: + virtual bool existsProducer(const PipeEndPoint *pipeEndPoint); + virtual bool existsConsumer(const PipeEndPoint *pipeEndPoint); + virtual void sendMessageToConsumer(const MessageQueue *messageQueue, MessagePipesLegacyCommon::ChannelRegistrationKey key, PipeEndPoint *pipeEndPoint); + }; + + MessagePipesGC m_messagePipesGC; + bool m_running; + QTimer m_gcTimer; + +private slots: + void processGC(); //!< Collect garbage +}; + +#endif // SDRBASE_PIPES_MESSAGEPIPESLEGACYGCWORKER_H_ diff --git a/sdrbase/pipes/pipeendpoint.cpp b/sdrbase/pipes/pipeendpoint.cpp new file mode 100644 index 000000000..9a3ba38eb --- /dev/null +++ b/sdrbase/pipes/pipeendpoint.cpp @@ -0,0 +1,185 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2021 Jon Beniston, M7RCE // +// // +// This program is free software; you can redistribute it and/or modify // +// it under the terms of the GNU General Public License as published by // +// the Free Software Foundation as version 3 of the License, or // +// (at your option) any later version. // +// // +// This program is distributed in the hope that it will be useful, // +// but WITHOUT ANY WARRANTY; without even the implied warranty of // +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // +// GNU General Public License V3 for more details. // +// // +// You should have received a copy of the GNU General Public License // +// along with this program. If not, see . // +/////////////////////////////////////////////////////////////////////////////////// + +#include + +#include +#include + +#include "dsp/dspengine.h" +#include "device/deviceset.h" +#include "channel/channelapi.h" +#include "feature/featureset.h" +#include "feature/feature.h" +#include "maincore.h" + +#include "pipeendpoint.h" + +MESSAGE_CLASS_DEFINITION(PipeEndPoint::MsgReportPipes, Message) + +QList PipeEndPoint::updateAvailablePipeSources(QString pipeName, QStringList pipeTypes, QStringList pipeURIs, PipeEndPoint *destination) +{ + MainCore *mainCore = MainCore::instance(); + MessagePipesLegacy& messagePipes = mainCore->getMessagePipesLegacy(); + std::vector& deviceSets = mainCore->getDeviceSets(); + QHash availablePipes; + + // Source is a channel + int deviceIndex = 0; + for (std::vector::const_iterator it = deviceSets.begin(); it != deviceSets.end(); ++it, deviceIndex++) + { + DSPDeviceSourceEngine *deviceSourceEngine = (*it)->m_deviceSourceEngine; + DSPDeviceSinkEngine *deviceSinkEngine = (*it)->m_deviceSinkEngine; + + if (deviceSourceEngine || deviceSinkEngine) + { + for (int chi = 0; chi < (*it)->getNumberOfChannels(); chi++) + { + ChannelAPI *channel = (*it)->getChannelAt(chi); + int i = pipeURIs.indexOf(channel->getURI()); + + if (i >= 0) + { + if (!availablePipes.contains(channel)) + { + MessageQueue *messageQueue = messagePipes.registerChannelToFeature(channel, destination, pipeName); + if (MainCore::instance()->existsFeature((const Feature *)destination)) + { + // Destination is feature + Feature *featureDest = (Feature *)destination; + QObject::connect( + messageQueue, + &MessageQueue::messageEnqueued, + featureDest, + [=](){ featureDest->handlePipeMessageQueue(messageQueue); }, + Qt::QueuedConnection + ); + } + else + { + // Destination is a channel + // Can't use Qt::QueuedConnection because ChannelAPI isn't a QObject + ChannelAPI *channelDest = (ChannelAPI *)destination; + QObject::connect( + messageQueue, + &MessageQueue::messageEnqueued, + [=](){ channelDest->handlePipeMessageQueue(messageQueue); } + ); + } + } + + AvailablePipeSource availablePipe = + AvailablePipeSource{ + deviceSinkEngine != nullptr ? AvailablePipeSource::TX : AvailablePipeSource::RX, + deviceIndex, + chi, + channel, + pipeTypes.at(i) + }; + availablePipes[channel] = availablePipe; + } + } + } + } + + // Source is a feature + std::vector& featureSets = mainCore->getFeatureeSets(); + int featureIndex = 0; + for (std::vector::const_iterator it = featureSets.begin(); it != featureSets.end(); ++it, featureIndex++) + { + for (int fi = 0; fi < (*it)->getNumberOfFeatures(); fi++) + { + Feature *feature = (*it)->getFeatureAt(fi); + int i = pipeURIs.indexOf(feature->getURI()); + + if (i >= 0) + { + if (!availablePipes.contains(feature)) + { + MessageQueue *messageQueue = messagePipes.registerChannelToFeature(feature, destination, pipeName); + if (MainCore::instance()->existsFeature((const Feature *)destination)) + { + // Destination is feature + Feature *featureDest = (Feature *)destination; + QObject::connect( + messageQueue, + &MessageQueue::messageEnqueued, + featureDest, + [=](){ featureDest->handlePipeMessageQueue(messageQueue); }, + Qt::QueuedConnection + ); + } + else + { + // Destination is a channel + // Can't use Qt::QueuedConnection because ChannelAPI isn't a QObject + ChannelAPI *channelDest = (ChannelAPI *)destination; + QObject::connect( + messageQueue, + &MessageQueue::messageEnqueued, + [=](){ channelDest->handlePipeMessageQueue(messageQueue); } + ); + } + } + + AvailablePipeSource availablePipe = + AvailablePipeSource{ + AvailablePipeSource::Feature, + featureIndex, + fi, + feature, + pipeTypes.at(i) + }; + availablePipes[feature] = availablePipe; + } + } + } + + QList availablePipeList; + QHash::iterator it = availablePipes.begin(); + + for (; it != availablePipes.end(); ++it) { + availablePipeList.push_back(*it); + } + return availablePipeList; +} + +PipeEndPoint *PipeEndPoint::getPipeEndPoint(const QString name, const QList &availablePipeSources) +{ + QRegExp re("([TRF])([0-9]+):([0-9]+) ([a-zA-Z0-9]+)"); + if (re.exactMatch(name)) + { + QString type = re.capturedTexts()[1]; + int setIndex = re.capturedTexts()[2].toInt(); + int index = re.capturedTexts()[3].toInt(); + QString id = re.capturedTexts()[4]; + + QListIterator itr(availablePipeSources); + while (itr.hasNext()) + { + AvailablePipeSource p = itr.next(); + if ((p.m_setIndex == setIndex) && (p.m_index == index) && (id == p.m_id)) { + return p.m_source; + } + } + } + else + { + qDebug() << "PipeEndPoint::getPipeEndPoint: " << name << " is malformed"; + } + return nullptr; +} diff --git a/sdrbase/pipes/pipeendpoint.h b/sdrbase/pipes/pipeendpoint.h new file mode 100644 index 000000000..5de230b09 --- /dev/null +++ b/sdrbase/pipes/pipeendpoint.h @@ -0,0 +1,100 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2021 Jon Beniston, M7RCE // +// // +// Parent for ChannelAPI and Features, where either can be used. // +// // +// This program is free software; you can redistribute it and/or modify // +// it under the terms of the GNU General Public License as published by // +// the Free Software Foundation as version 3 of the License, or // +// (at your option) any later version. // +// // +// This program is distributed in the hope that it will be useful, // +// but WITHOUT ANY WARRANTY; without even the implied warranty of // +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // +// GNU General Public License V3 for more details. // +// // +// You should have received a copy of the GNU General Public License // +// along with this program. If not, see . // +/////////////////////////////////////////////////////////////////////////////////// + +#ifndef SDRBASE_PIPES_PIPEENDPOINT_H_ +#define SDRBASE_PIPES_PIPEENDPOINT_H_ + +#include +#include +#include + +#include "util/message.h" +#include "export.h" + +class Feature; + +class SDRBASE_API PipeEndPoint { +public: + + // Used by pipe sinks (channels or features) to record details about available pipe sources (channels or features) + struct AvailablePipeSource + { + enum {RX, TX, Feature} m_type; + int m_setIndex; + int m_index; + PipeEndPoint *m_source; + QString m_id; + + AvailablePipeSource() = default; + AvailablePipeSource(const AvailablePipeSource&) = default; + AvailablePipeSource& operator=(const AvailablePipeSource&) = default; + friend bool operator==(const AvailablePipeSource &lhs, const AvailablePipeSource &rhs) + { + return (lhs.m_type == rhs.m_type) + && (lhs.m_setIndex == rhs.m_setIndex) + && (lhs.m_source == rhs.m_source) + && (lhs.m_id == rhs.m_id); + } + + QString getTypeName() const + { + QStringList typeNames = {"R", "T", "F"}; + return typeNames[m_type]; + } + + // Name for use in GUI combo boxes and WebAPI + QString getName() const + { + QString type; + + return QString("%1%2:%3 %4").arg(getTypeName()) + .arg(m_setIndex) + .arg(m_index) + .arg(m_id); + } + }; + + class SDRBASE_API MsgReportPipes : public Message { + MESSAGE_CLASS_DECLARATION + + public: + QList& getAvailablePipes() { return m_availablePipes; } + + static MsgReportPipes* create() { + return new MsgReportPipes(); + } + + private: + QList m_availablePipes; + + MsgReportPipes() : + Message() + {} + }; + + +protected: + + // Utility functions for pipe sinks to manage list of sources + QList updateAvailablePipeSources(QString pipeName, QStringList pipeTypes, QStringList pipeURIs, PipeEndPoint *destination); + PipeEndPoint *getPipeEndPoint(const QString name, const QList &availablePipeSources); + +}; + +#endif // SDRBASE_PIPES_PIPEENDPOINT_H_ diff --git a/sdrbase/plugin/pluginmanager.cpp b/sdrbase/plugin/pluginmanager.cpp index 79073b952..0f0a48fc9 100644 --- a/sdrbase/plugin/pluginmanager.cpp +++ b/sdrbase/plugin/pluginmanager.cpp @@ -53,7 +53,8 @@ const QString PluginManager::m_testMIMODeviceTypeID = "sdrangel.samplemimo.testm PluginManager::PluginManager(QObject* parent) : QObject(parent), - m_pluginAPI(this) + m_pluginAPI(this), + m_enableSoapy(false) { } @@ -216,6 +217,12 @@ void PluginManager::loadPluginsDir(const QDir& dir) { if (QLibrary::isLibrary(fileName)) { + if (!m_enableSoapy && fileName.contains("soapysdr")) + { + qInfo("PluginManager::loadPluginsDir: Soapy SDR disabled skipping %s", qPrintable(fileName)); + continue; + } + qDebug("PluginManager::loadPluginsDir: fileName: %s", qPrintable(fileName)); QPluginLoader* pluginLoader = new QPluginLoader(pluginsDir.absoluteFilePath(fileName)); diff --git a/sdrbase/plugin/pluginmanager.h b/sdrbase/plugin/pluginmanager.h index 71713810c..763af09e9 100644 --- a/sdrbase/plugin/pluginmanager.h +++ b/sdrbase/plugin/pluginmanager.h @@ -57,6 +57,7 @@ public: ~PluginManager(); PluginAPI *getPluginAPI() { return &m_pluginAPI; } + void setEnableSoapy(bool enableSoapy) { m_enableSoapy = enableSoapy; } void loadPlugins(const QString& pluginsSubDir); void loadPluginsPart(const QString& pluginsSubDir); void loadPluginsFinal(); @@ -124,6 +125,7 @@ private: PluginAPI m_pluginAPI; Plugins m_plugins; + bool m_enableSoapy; PluginAPI::ChannelRegistrations m_rxChannelRegistrations; //!< Channel plugins register here PluginAPI::ChannelRegistrations m_txChannelRegistrations; //!< Channel plugins register here diff --git a/sdrbase/resources/webapi.qrc b/sdrbase/resources/webapi.qrc index 4a374828d..219ac5fc7 100644 --- a/sdrbase/resources/webapi.qrc +++ b/sdrbase/resources/webapi.qrc @@ -109,7 +109,6 @@ webapi/doc/swagger/include/USRP.yaml webapi/doc/swagger/include/VORDemod.yaml webapi/doc/swagger/include/VORLocalizer.yaml - webapi/doc/swagger/include/VORDemodSC.yaml webapi/doc/swagger/include/WFMDemod.yaml webapi/doc/swagger/include/WFMMod.yaml webapi/doc/swagger/include/Xtrx.yaml diff --git a/sdrbase/resources/webapi/doc/html2/index.html b/sdrbase/resources/webapi/doc/html2/index.html index b7c351ce8..ef261f77e 100644 --- a/sdrbase/resources/webapi/doc/html2/index.html +++ b/sdrbase/resources/webapi/doc/html2/index.html @@ -2502,6 +2502,16 @@ margin-bottom: 20px; } }, "description" : "A bandwidth expressed in Hertz (Hz)" +}; + defs.Base64Blob = { + "required" : [ "blob" ], + "properties" : { + "blob" : { + "type" : "string", + "description" : "Blob in base64" + } + }, + "description" : "Binary blob in base64 format" }; defs.BeamSteeringCWModSettings = { "properties" : { @@ -3380,9 +3390,6 @@ margin-bottom: 20px; "VORDemodReport" : { "$ref" : "#/definitions/VORDemodReport" }, - "VORDemodSCReport" : { - "$ref" : "#/definitions/VORDemodSCReport" - }, "WFMDemodReport" : { "$ref" : "#/definitions/WFMDemodReport" }, @@ -3541,9 +3548,6 @@ margin-bottom: 20px; "VORDemodSettings" : { "$ref" : "#/definitions/VORDemodSettings" }, - "VORDemodSCSettings" : { - "$ref" : "#/definitions/VORDemodSCSettings" - }, "WFMDemodSettings" : { "$ref" : "#/definitions/WFMDemodSettings" }, @@ -4011,6 +4015,79 @@ margin-bottom: 20px; } }, "description" : "A complex number" +}; + defs.ConfigurationGroup = { + "required" : [ "groupName" ], + "properties" : { + "groupName" : { + "type" : "string", + "description" : "Name of the configuration group" + }, + "nbConfigurations" : { + "type" : "integer", + "description" : "Number of configurations in the group" + }, + "configurations" : { + "type" : "array", + "items" : { + "$ref" : "#/definitions/ConfigurationItem" + } + } + }, + "description" : "Group of configuration" +}; + defs.ConfigurationIdentifier = { + "required" : [ "groupName", "name" ], + "properties" : { + "groupName" : { + "type" : "string", + "description" : "Name of the preset group" + }, + "name" : { + "type" : "string", + "description" : "Descriptive name of the preset" + } + }, + "description" : "Configuration item" +}; + defs.ConfigurationImportExport = { + "properties" : { + "filePath" : { + "type" : "string", + "description" : "Path of the import file" + }, + "configuration" : { + "description" : "On import new configuration details. On export configuration to export from", + "$ref" : "#/definitions/ConfigurationIdentifier" + } + }, + "description" : "Details to impprt/export a configuration from/to file" +}; + defs.ConfigurationItem = { + "required" : [ "name" ], + "properties" : { + "name" : { + "type" : "string", + "description" : "Descriptive name of the configuration" + } + }, + "description" : "Configuration preset item" +}; + defs.Configurations = { + "required" : [ "nbGroups" ], + "properties" : { + "nbGroups" : { + "type" : "integer", + "description" : "Number of configuration groups" + }, + "groups" : { + "type" : "array", + "items" : { + "$ref" : "#/definitions/ConfigurationGroup" + } + } + }, + "description" : "Configuration presets" }; defs.DABDemodSettings = { "properties" : { @@ -5357,12 +5434,8 @@ margin-bottom: 20px; "description" : "Base feature report. Only the feature report corresponding to the feature specified in the featureType field is or should be present." }; defs.FeatureSet = { - "required" : [ "featurecount", "index" ], + "required" : [ "featurecount" ], "properties" : { - "index" : { - "type" : "integer", - "description" : "Index in the list of feature sets opened in this instance" - }, "featurecount" : { "type" : "integer", "description" : "Number of features in the set" @@ -5376,22 +5449,6 @@ margin-bottom: 20px; } }, "description" : "Grouping of features" -}; - defs.FeatureSetList = { - "required" : [ "featuresetcount" ], - "properties" : { - "featuresetcount" : { - "type" : "integer", - "description" : "Number of feature sets opened in this instance" - }, - "featureSets" : { - "type" : "array", - "items" : { - "$ref" : "#/definitions/FeatureSet" - } - } - }, - "description" : "List of feature sets opened in this instance" }; defs.FeatureSetPreset = { "properties" : { @@ -5564,6 +5621,16 @@ margin-bottom: 20px; } }, "description" : "FileInput" +}; + defs.FilePath = { + "required" : [ "filePath" ], + "properties" : { + "filePath" : { + "type" : "string", + "description" : "File path" + } + }, + "description" : "File path" }; defs.FileSinkActions = { "properties" : { @@ -6873,8 +6940,8 @@ margin-bottom: 20px; "devicesetlist" : { "$ref" : "#/definitions/DeviceSetList" }, - "featuresetlist" : { - "$ref" : "#/definitions/FeatureSetList" + "featureset" : { + "$ref" : "#/definitions/FeatureSet" } }, "description" : "Summarized information about this SDRangel instance" @@ -9837,13 +9904,14 @@ margin-bottom: 20px; "properties" : { "filePath" : { "type" : "string", - "description" : "Path of the import file" + "description" : "Path of the export file" }, "preset" : { + "description" : "Preset to export", "$ref" : "#/definitions/PresetIdentifier" } }, - "description" : "Details to export a preset to file" + "description" : "Details to export a preset to a file" }; defs.PresetGroup = { "required" : [ "groupName", "nbPresets" ], @@ -9891,20 +9959,16 @@ margin-bottom: 20px; defs.PresetImport = { "required" : [ "filePath" ], "properties" : { - "groupName" : { - "type" : "string", - "description" : "If present overrides imported preset group name with this name" - }, - "description" : { - "type" : "string", - "description" : "If present overrides imported preset description with this description" + "preset" : { + "description" : "New preset details", + "$ref" : "#/definitions/PresetIdentifier" }, "filePath" : { "type" : "string", "description" : "Path of the import file" } }, - "description" : "Details to import preset from file in preset list" + "description" : "Details to import new preset from file" }; defs.PresetItem = { "required" : [ "centerFrequency", "name", "type" ], @@ -13617,23 +13681,6 @@ margin-bottom: 20px; "description" : "USRP" }; defs.VORDemodReport = { - "properties" : { - "channelPowerDB" : { - "type" : "number", - "format" : "float", - "description" : "power received in channel (dB)" - }, - "squelch" : { - "type" : "integer", - "description" : "squelch status (1 if open else 0)" - }, - "audioSampleRate" : { - "type" : "integer" - } - }, - "description" : "VORDemod" -}; - defs.VORDemodSCReport = { "properties" : { "channelPowerDB" : { "type" : "number", @@ -13687,9 +13734,9 @@ margin-bottom: 20px; "description" : "current identification morse code transcript" } }, - "description" : "VORDemodSC" + "description" : "VORDemod" }; - defs.VORDemodSCSettings = { + defs.VORDemodSettings = { "properties" : { "inputFrequencyOffset" : { "type" : "integer", @@ -13751,66 +13798,6 @@ margin-bottom: 20px; "$ref" : "#/definitions/RollupState" } }, - "description" : "VORDemodSC" -}; - defs.VORDemodSettings = { - "properties" : { - "squelch" : { - "type" : "number", - "format" : "float", - "description" : "power squelch threshold in decibels" - }, - "volume" : { - "type" : "number", - "format" : "float" - }, - "audioMute" : { - "type" : "integer" - }, - "rgbColor" : { - "type" : "integer" - }, - "title" : { - "type" : "string" - }, - "audioDeviceName" : { - "type" : "string" - }, - "streamIndex" : { - "type" : "integer", - "description" : "MIMO channel. Not relevant when connected to SI (single Rx)." - }, - "useReverseAPI" : { - "type" : "integer", - "description" : "Synchronize with reverse API (1 for yes, 0 for no)" - }, - "reverseAPIAddress" : { - "type" : "string" - }, - "reverseAPIPort" : { - "type" : "integer" - }, - "reverseAPIDeviceIndex" : { - "type" : "integer" - }, - "reverseAPIChannelIndex" : { - "type" : "integer" - }, - "identThreshold" : { - "type" : "integer", - "description" : "Morse code ident threshold (linear SNR)" - }, - "magDecAdjust" : { - "type" : "integer", - "description" : "Adjust radial lines on map for magnetic declination of VOR" - }, - "channelMarker" : { - "$ref" : "#/definitions/ChannelMarker" - }, - "rollupState" : { - "$ref" : "#/definitions/RollupState" - } - }, "description" : "VORDemod" }; defs.VORLocalizerActions = { @@ -14052,6 +14039,16 @@ margin-bottom: 20px; } }, "description" : "WFMMod" +}; + defs.WorkspaceInfo = { + "required" : [ "index" ], + "properties" : { + "index" : { + "type" : "integer", + "description" : "index of workspace in the list of workspaces" + } + }, + "description" : "Workspace information" }; defs.XtrxInputReport = { "properties" : { @@ -14504,6 +14501,12 @@ margin-bottom: 20px;
  • devicesetChannelSettingsPut
  • +
  • + devicesetChannelWorkspaceGet +
  • +
  • + devicesetChannelWorkspacePut +
  • devicesetChannelsReportGet
  • @@ -14543,6 +14546,12 @@ margin-bottom: 20px;
  • devicesetDeviceSubsystemRunPost
  • +
  • + devicesetDeviceWorkspaceGet +
  • +
  • + devicesetDeviceWorkspacePut +
  • devicesetFocusPatch
  • @@ -14567,6 +14576,12 @@ margin-bottom: 20px;
  • devicesetSpectrumSettingsPut
  • +
  • + devicesetSpectrumWorkspaceGet +
  • +
  • + devicesetSpectrumWorkspacePut +
  • instanceDeviceSetDelete
  • @@ -14604,6 +14619,12 @@ margin-bottom: 20px;
  • featuresetFeatureSettingsPatch
  • +
  • + featuresetFeatureWorkspaceGet +
  • +
  • + featuresetFeatureWorkspacePut +
  • featuresetGet
  • @@ -14616,12 +14637,6 @@ margin-bottom: 20px;
  • featuresetPresetPut
  • -
  • - instanceFeatureSetDelete -
  • -
  • - instanceFeatureSetPost -
  • instanceAMBEDevicesDelete @@ -14671,6 +14686,33 @@ margin-bottom: 20px;
  • instanceConfigPut
  • +
  • + instanceConfigurationBlobPost +
  • +
  • + instanceConfigurationBlobPut +
  • +
  • + instanceConfigurationDelete +
  • +
  • + instanceConfigurationFilePost +
  • +
  • + instanceConfigurationFilePut +
  • +
  • + instanceConfigurationPatch +
  • +
  • + instanceConfigurationPost +
  • +
  • + instanceConfigurationPut +
  • +
  • + instanceConfigurationsGet +
  • instanceDelete
  • @@ -14686,9 +14728,6 @@ margin-bottom: 20px;
  • instanceFeaturePresetGet
  • -
  • - instanceFeatureSetsGet -
  • instanceFeatures
  • @@ -14719,6 +14758,12 @@ margin-bottom: 20px;
  • instanceLoggingPut
  • +
  • + instancePresetBlobPost +
  • +
  • + instancePresetBlobPut +
  • instancePresetDelete
  • @@ -14743,6 +14788,13 @@ margin-bottom: 20px;
  • instanceSummary
  • + +
  • + instanceWorkspaceAdd +
  • +
  • + instanceWorkspacesDeleteEmpty +
  • @@ -18409,6 +18461,960 @@ $(document).ready(function() {
    +
    +
    +
    +

    devicesetChannelWorkspaceGet

    +

    +
    +
    +
    +

    +

    get channel UI workspace information (GUI)

    +

    +
    +
    /sdrangel/deviceset/{deviceSetIndex}/channel/{channelIndex}/workspace
    +

    +

    Usage and SDK Samples

    +

    + + +
    +
    +
    curl -X GET "http://localhost/sdrangel/deviceset/{deviceSetIndex}/channel/{channelIndex}/workspace"
    +
    +
    +
    import SWGSDRangel.*;
    +import SWGSDRangel.auth.*;
    +import SWGSDRangel.model.*;
    +import SWGSDRangel.api.DeviceSetApi;
    +
    +import java.io.File;
    +import java.util.*;
    +
    +public class DeviceSetApiExample {
    +
    +    public static void main(String[] args) {
    +        
    +        DeviceSetApi apiInstance = new DeviceSetApi();
    +        Integer deviceSetIndex = 56; // Integer | Index of device set in the device set list
    +        Integer channelIndex = 56; // Integer | Index of the channel in the channels list for this device set
    +        try {
    +            WorkspaceInfo result = apiInstance.devicesetChannelWorkspaceGet(deviceSetIndex, channelIndex);
    +            System.out.println(result);
    +        } catch (ApiException e) {
    +            System.err.println("Exception when calling DeviceSetApi#devicesetChannelWorkspaceGet");
    +            e.printStackTrace();
    +        }
    +    }
    +}
    +
    + +
    +
    import SWGSDRangel.api.DeviceSetApi;
    +
    +public class DeviceSetApiExample {
    +
    +    public static void main(String[] args) {
    +        DeviceSetApi apiInstance = new DeviceSetApi();
    +        Integer deviceSetIndex = 56; // Integer | Index of device set in the device set list
    +        Integer channelIndex = 56; // Integer | Index of the channel in the channels list for this device set
    +        try {
    +            WorkspaceInfo result = apiInstance.devicesetChannelWorkspaceGet(deviceSetIndex, channelIndex);
    +            System.out.println(result);
    +        } catch (ApiException e) {
    +            System.err.println("Exception when calling DeviceSetApi#devicesetChannelWorkspaceGet");
    +            e.printStackTrace();
    +        }
    +    }
    +}
    +
    + +
    +
    Integer *deviceSetIndex = 56; // Index of device set in the device set list
    +Integer *channelIndex = 56; // Index of the channel in the channels list for this device set
    +
    +DeviceSetApi *apiInstance = [[DeviceSetApi alloc] init];
    +
    +[apiInstance devicesetChannelWorkspaceGetWith:deviceSetIndex
    +    channelIndex:channelIndex
    +              completionHandler: ^(WorkspaceInfo output, NSError* error) {
    +                            if (output) {
    +                                NSLog(@"%@", output);
    +                            }
    +                            if (error) {
    +                                NSLog(@"Error: %@", error);
    +                            }
    +                        }];
    +
    +
    + +
    +
    var SdRangel = require('sd_rangel');
    +
    +var api = new SdRangel.DeviceSetApi()
    +
    +var deviceSetIndex = 56; // {Integer} Index of device set in the device set list
    +
    +var channelIndex = 56; // {Integer} Index of the channel in the channels list for this device set
    +
    +
    +var callback = function(error, data, response) {
    +  if (error) {
    +    console.error(error);
    +  } else {
    +    console.log('API called successfully. Returned data: ' + data);
    +  }
    +};
    +api.devicesetChannelWorkspaceGet(deviceSetIndex, channelIndex, callback);
    +
    +
    + + +
    +
    using System;
    +using System.Diagnostics;
    +using SWGSDRangel.Api;
    +using SWGSDRangel.Client;
    +using SWGSDRangel.Model;
    +
    +namespace Example
    +{
    +    public class devicesetChannelWorkspaceGetExample
    +    {
    +        public void main()
    +        {
    +            
    +            var apiInstance = new DeviceSetApi();
    +            var deviceSetIndex = 56;  // Integer | Index of device set in the device set list
    +            var channelIndex = 56;  // Integer | Index of the channel in the channels list for this device set
    +
    +            try
    +            {
    +                WorkspaceInfo result = apiInstance.devicesetChannelWorkspaceGet(deviceSetIndex, channelIndex);
    +                Debug.WriteLine(result);
    +            }
    +            catch (Exception e)
    +            {
    +                Debug.Print("Exception when calling DeviceSetApi.devicesetChannelWorkspaceGet: " + e.Message );
    +            }
    +        }
    +    }
    +}
    +
    +
    + +
    +
    <?php
    +require_once(__DIR__ . '/vendor/autoload.php');
    +
    +$api_instance = new Swagger\Client\Api\DeviceSetApi();
    +$deviceSetIndex = 56; // Integer | Index of device set in the device set list
    +$channelIndex = 56; // Integer | Index of the channel in the channels list for this device set
    +
    +try {
    +    $result = $api_instance->devicesetChannelWorkspaceGet($deviceSetIndex, $channelIndex);
    +    print_r($result);
    +} catch (Exception $e) {
    +    echo 'Exception when calling DeviceSetApi->devicesetChannelWorkspaceGet: ', $e->getMessage(), PHP_EOL;
    +}
    +?>
    +
    + +
    +
    use Data::Dumper;
    +use SWGSDRangel::Configuration;
    +use SWGSDRangel::DeviceSetApi;
    +
    +my $api_instance = SWGSDRangel::DeviceSetApi->new();
    +my $deviceSetIndex = 56; # Integer | Index of device set in the device set list
    +my $channelIndex = 56; # Integer | Index of the channel in the channels list for this device set
    +
    +eval { 
    +    my $result = $api_instance->devicesetChannelWorkspaceGet(deviceSetIndex => $deviceSetIndex, channelIndex => $channelIndex);
    +    print Dumper($result);
    +};
    +if ($@) {
    +    warn "Exception when calling DeviceSetApi->devicesetChannelWorkspaceGet: $@\n";
    +}
    +
    + +
    +
    from __future__ import print_statement
    +import time
    +import swagger_sdrangel
    +from swagger_sdrangel.rest import ApiException
    +from pprint import pprint
    +
    +# create an instance of the API class
    +api_instance = swagger_sdrangel.DeviceSetApi()
    +deviceSetIndex = 56 # Integer | Index of device set in the device set list
    +channelIndex = 56 # Integer | Index of the channel in the channels list for this device set
    +
    +try: 
    +    api_response = api_instance.deviceset_channel_workspace_get(deviceSetIndex, channelIndex)
    +    pprint(api_response)
    +except ApiException as e:
    +    print("Exception when calling DeviceSetApi->devicesetChannelWorkspaceGet: %s\n" % e)
    +
    +
    + +

    Parameters

    + +
    Path parameters
    + + + + + + + + + + + + + +
    NameDescription
    deviceSetIndex* + + +
    +
    +
    + + Integer + + +
    + Index of device set in the device set list +
    +
    +
    + Required +
    +
    +
    +
    channelIndex* + + +
    +
    +
    + + Integer + + +
    + Index of the channel in the channels list for this device set +
    +
    +
    + Required +
    +
    +
    +
    + + + + + +

    Responses

    +

    Status: 200 - On success return workspace information

    + + + +
    +
    +
    + +
    + +
    +
    + +

    Status: 400 - Invalid device set index

    + + + +
    +
    +
    + +
    + +
    +
    + +

    Status: 500 - Error

    + + + +
    +
    +
    + +
    + +
    +
    + +

    Status: 501 - Function not implemented

    + + + +
    +
    +
    + +
    + +
    +
    + +
    +
    +
    +
    +
    +
    +

    devicesetChannelWorkspacePut

    +

    +
    +
    +
    +

    +

    move channel UI to workspace (GUI)

    +

    +
    +
    /sdrangel/deviceset/{deviceSetIndex}/channel/{channelIndex}/workspace
    +

    +

    Usage and SDK Samples

    +

    + + +
    +
    +
    curl -X PUT "http://localhost/sdrangel/deviceset/{deviceSetIndex}/channel/{channelIndex}/workspace"
    +
    +
    +
    import SWGSDRangel.*;
    +import SWGSDRangel.auth.*;
    +import SWGSDRangel.model.*;
    +import SWGSDRangel.api.DeviceSetApi;
    +
    +import java.io.File;
    +import java.util.*;
    +
    +public class DeviceSetApiExample {
    +
    +    public static void main(String[] args) {
    +        
    +        DeviceSetApi apiInstance = new DeviceSetApi();
    +        Integer deviceSetIndex = 56; // Integer | Index of device set in the device set list
    +        Integer channelIndex = 56; // Integer | Index of the channel in the channels list for this device set
    +        WorkspaceInfo body = ; // WorkspaceInfo | Destination workspace information
    +        try {
    +            SuccessResponse result = apiInstance.devicesetChannelWorkspacePut(deviceSetIndex, channelIndex, body);
    +            System.out.println(result);
    +        } catch (ApiException e) {
    +            System.err.println("Exception when calling DeviceSetApi#devicesetChannelWorkspacePut");
    +            e.printStackTrace();
    +        }
    +    }
    +}
    +
    + +
    +
    import SWGSDRangel.api.DeviceSetApi;
    +
    +public class DeviceSetApiExample {
    +
    +    public static void main(String[] args) {
    +        DeviceSetApi apiInstance = new DeviceSetApi();
    +        Integer deviceSetIndex = 56; // Integer | Index of device set in the device set list
    +        Integer channelIndex = 56; // Integer | Index of the channel in the channels list for this device set
    +        WorkspaceInfo body = ; // WorkspaceInfo | Destination workspace information
    +        try {
    +            SuccessResponse result = apiInstance.devicesetChannelWorkspacePut(deviceSetIndex, channelIndex, body);
    +            System.out.println(result);
    +        } catch (ApiException e) {
    +            System.err.println("Exception when calling DeviceSetApi#devicesetChannelWorkspacePut");
    +            e.printStackTrace();
    +        }
    +    }
    +}
    +
    + +
    +
    Integer *deviceSetIndex = 56; // Index of device set in the device set list
    +Integer *channelIndex = 56; // Index of the channel in the channels list for this device set
    +WorkspaceInfo *body = ; // Destination workspace information
    +
    +DeviceSetApi *apiInstance = [[DeviceSetApi alloc] init];
    +
    +[apiInstance devicesetChannelWorkspacePutWith:deviceSetIndex
    +    channelIndex:channelIndex
    +    body:body
    +              completionHandler: ^(SuccessResponse output, NSError* error) {
    +                            if (output) {
    +                                NSLog(@"%@", output);
    +                            }
    +                            if (error) {
    +                                NSLog(@"Error: %@", error);
    +                            }
    +                        }];
    +
    +
    + +
    +
    var SdRangel = require('sd_rangel');
    +
    +var api = new SdRangel.DeviceSetApi()
    +
    +var deviceSetIndex = 56; // {Integer} Index of device set in the device set list
    +
    +var channelIndex = 56; // {Integer} Index of the channel in the channels list for this device set
    +
    +var body = ; // {WorkspaceInfo} Destination workspace information
    +
    +
    +var callback = function(error, data, response) {
    +  if (error) {
    +    console.error(error);
    +  } else {
    +    console.log('API called successfully. Returned data: ' + data);
    +  }
    +};
    +api.devicesetChannelWorkspacePut(deviceSetIndex, channelIndex, body, callback);
    +
    +
    + + +
    +
    using System;
    +using System.Diagnostics;
    +using SWGSDRangel.Api;
    +using SWGSDRangel.Client;
    +using SWGSDRangel.Model;
    +
    +namespace Example
    +{
    +    public class devicesetChannelWorkspacePutExample
    +    {
    +        public void main()
    +        {
    +            
    +            var apiInstance = new DeviceSetApi();
    +            var deviceSetIndex = 56;  // Integer | Index of device set in the device set list
    +            var channelIndex = 56;  // Integer | Index of the channel in the channels list for this device set
    +            var body = new WorkspaceInfo(); // WorkspaceInfo | Destination workspace information
    +
    +            try
    +            {
    +                SuccessResponse result = apiInstance.devicesetChannelWorkspacePut(deviceSetIndex, channelIndex, body);
    +                Debug.WriteLine(result);
    +            }
    +            catch (Exception e)
    +            {
    +                Debug.Print("Exception when calling DeviceSetApi.devicesetChannelWorkspacePut: " + e.Message );
    +            }
    +        }
    +    }
    +}
    +
    +
    + +
    +
    <?php
    +require_once(__DIR__ . '/vendor/autoload.php');
    +
    +$api_instance = new Swagger\Client\Api\DeviceSetApi();
    +$deviceSetIndex = 56; // Integer | Index of device set in the device set list
    +$channelIndex = 56; // Integer | Index of the channel in the channels list for this device set
    +$body = ; // WorkspaceInfo | Destination workspace information
    +
    +try {
    +    $result = $api_instance->devicesetChannelWorkspacePut($deviceSetIndex, $channelIndex, $body);
    +    print_r($result);
    +} catch (Exception $e) {
    +    echo 'Exception when calling DeviceSetApi->devicesetChannelWorkspacePut: ', $e->getMessage(), PHP_EOL;
    +}
    +?>
    +
    + +
    +
    use Data::Dumper;
    +use SWGSDRangel::Configuration;
    +use SWGSDRangel::DeviceSetApi;
    +
    +my $api_instance = SWGSDRangel::DeviceSetApi->new();
    +my $deviceSetIndex = 56; # Integer | Index of device set in the device set list
    +my $channelIndex = 56; # Integer | Index of the channel in the channels list for this device set
    +my $body = SWGSDRangel::Object::WorkspaceInfo->new(); # WorkspaceInfo | Destination workspace information
    +
    +eval { 
    +    my $result = $api_instance->devicesetChannelWorkspacePut(deviceSetIndex => $deviceSetIndex, channelIndex => $channelIndex, body => $body);
    +    print Dumper($result);
    +};
    +if ($@) {
    +    warn "Exception when calling DeviceSetApi->devicesetChannelWorkspacePut: $@\n";
    +}
    +
    + +
    +
    from __future__ import print_statement
    +import time
    +import swagger_sdrangel
    +from swagger_sdrangel.rest import ApiException
    +from pprint import pprint
    +
    +# create an instance of the API class
    +api_instance = swagger_sdrangel.DeviceSetApi()
    +deviceSetIndex = 56 # Integer | Index of device set in the device set list
    +channelIndex = 56 # Integer | Index of the channel in the channels list for this device set
    +body =  # WorkspaceInfo | Destination workspace information
    +
    +try: 
    +    api_response = api_instance.deviceset_channel_workspace_put(deviceSetIndex, channelIndex, body)
    +    pprint(api_response)
    +except ApiException as e:
    +    print("Exception when calling DeviceSetApi->devicesetChannelWorkspacePut: %s\n" % e)
    +
    +
    + +

    Parameters

    + +
    Path parameters
    + + + + + + + + + + + + + +
    NameDescription
    deviceSetIndex* + + +
    +
    +
    + + Integer + + +
    + Index of device set in the device set list +
    +
    +
    + Required +
    +
    +
    +
    channelIndex* + + +
    +
    +
    + + Integer + + +
    + Index of the channel in the channels list for this device set +
    +
    +
    + Required +
    +
    +
    +
    + + +
    Body parameters
    + + + + + + + + + +
    NameDescription
    body * + + + +
    +
    + + + +

    Responses

    +

    Status: 202 - Message to perform action was sent successfully

    + + + +
    +
    +
    + +
    + +
    +
    + +

    Status: 400 - Invalid device set or workspace index

    + + + +
    +
    +
    + +
    + +
    +
    + +

    Status: 500 - Error

    + + + +
    +
    +
    + +
    + +
    +
    + +

    Status: 501 - Function not implemented

    + + + +
    +
    +
    + +
    + +
    +
    + +
    +
    +
    @@ -19678,7 +20684,7 @@ $(document).ready(function() {

    Responses

    -

    Status: 202 - On successful semdomg of the message it returns the details of the device being set

    +

    Status: 202 - On successful semding of the message it returns the details of the device being set

    + +
    + + +

    Status: 400 - Invalid device set index

    + + + +
    +
    +
    + +
    + +
    +
    + +

    Status: 500 - Error

    + + + +
    +
    +
    + +
    + +
    +
    + +

    Status: 501 - Function not implemented

    + + + +
    +
    +
    + +
    + +
    +
    + + + +
    +
    +
    +
    +

    devicesetDeviceWorkspacePut

    +

    +
    +
    +
    +

    +

    move device UI to workspace (GUI)

    +

    +
    +
    /sdrangel/deviceset/{deviceSetIndex}/device/workspace
    +

    +

    Usage and SDK Samples

    +

    + + +
    +
    +
    curl -X PUT "http://localhost/sdrangel/deviceset/{deviceSetIndex}/device/workspace"
    +
    +
    +
    import SWGSDRangel.*;
    +import SWGSDRangel.auth.*;
    +import SWGSDRangel.model.*;
    +import SWGSDRangel.api.DeviceSetApi;
    +
    +import java.io.File;
    +import java.util.*;
    +
    +public class DeviceSetApiExample {
    +
    +    public static void main(String[] args) {
    +        
    +        DeviceSetApi apiInstance = new DeviceSetApi();
    +        Integer deviceSetIndex = 56; // Integer | Index of device set in the device set list
    +        WorkspaceInfo body = ; // WorkspaceInfo | Destination workspace information
    +        try {
    +            SuccessResponse result = apiInstance.devicesetDeviceWorkspacePut(deviceSetIndex, body);
    +            System.out.println(result);
    +        } catch (ApiException e) {
    +            System.err.println("Exception when calling DeviceSetApi#devicesetDeviceWorkspacePut");
    +            e.printStackTrace();
    +        }
    +    }
    +}
    +
    + +
    +
    import SWGSDRangel.api.DeviceSetApi;
    +
    +public class DeviceSetApiExample {
    +
    +    public static void main(String[] args) {
    +        DeviceSetApi apiInstance = new DeviceSetApi();
    +        Integer deviceSetIndex = 56; // Integer | Index of device set in the device set list
    +        WorkspaceInfo body = ; // WorkspaceInfo | Destination workspace information
    +        try {
    +            SuccessResponse result = apiInstance.devicesetDeviceWorkspacePut(deviceSetIndex, body);
    +            System.out.println(result);
    +        } catch (ApiException e) {
    +            System.err.println("Exception when calling DeviceSetApi#devicesetDeviceWorkspacePut");
    +            e.printStackTrace();
    +        }
    +    }
    +}
    +
    + +
    +
    Integer *deviceSetIndex = 56; // Index of device set in the device set list
    +WorkspaceInfo *body = ; // Destination workspace information
    +
    +DeviceSetApi *apiInstance = [[DeviceSetApi alloc] init];
    +
    +[apiInstance devicesetDeviceWorkspacePutWith:deviceSetIndex
    +    body:body
    +              completionHandler: ^(SuccessResponse output, NSError* error) {
    +                            if (output) {
    +                                NSLog(@"%@", output);
    +                            }
    +                            if (error) {
    +                                NSLog(@"Error: %@", error);
    +                            }
    +                        }];
    +
    +
    + +
    +
    var SdRangel = require('sd_rangel');
    +
    +var api = new SdRangel.DeviceSetApi()
    +
    +var deviceSetIndex = 56; // {Integer} Index of device set in the device set list
    +
    +var body = ; // {WorkspaceInfo} Destination workspace information
    +
    +
    +var callback = function(error, data, response) {
    +  if (error) {
    +    console.error(error);
    +  } else {
    +    console.log('API called successfully. Returned data: ' + data);
    +  }
    +};
    +api.devicesetDeviceWorkspacePut(deviceSetIndex, body, callback);
    +
    +
    + + +
    +
    using System;
    +using System.Diagnostics;
    +using SWGSDRangel.Api;
    +using SWGSDRangel.Client;
    +using SWGSDRangel.Model;
    +
    +namespace Example
    +{
    +    public class devicesetDeviceWorkspacePutExample
    +    {
    +        public void main()
    +        {
    +            
    +            var apiInstance = new DeviceSetApi();
    +            var deviceSetIndex = 56;  // Integer | Index of device set in the device set list
    +            var body = new WorkspaceInfo(); // WorkspaceInfo | Destination workspace information
    +
    +            try
    +            {
    +                SuccessResponse result = apiInstance.devicesetDeviceWorkspacePut(deviceSetIndex, body);
    +                Debug.WriteLine(result);
    +            }
    +            catch (Exception e)
    +            {
    +                Debug.Print("Exception when calling DeviceSetApi.devicesetDeviceWorkspacePut: " + e.Message );
    +            }
    +        }
    +    }
    +}
    +
    +
    + +
    +
    <?php
    +require_once(__DIR__ . '/vendor/autoload.php');
    +
    +$api_instance = new Swagger\Client\Api\DeviceSetApi();
    +$deviceSetIndex = 56; // Integer | Index of device set in the device set list
    +$body = ; // WorkspaceInfo | Destination workspace information
    +
    +try {
    +    $result = $api_instance->devicesetDeviceWorkspacePut($deviceSetIndex, $body);
    +    print_r($result);
    +} catch (Exception $e) {
    +    echo 'Exception when calling DeviceSetApi->devicesetDeviceWorkspacePut: ', $e->getMessage(), PHP_EOL;
    +}
    +?>
    +
    + +
    +
    use Data::Dumper;
    +use SWGSDRangel::Configuration;
    +use SWGSDRangel::DeviceSetApi;
    +
    +my $api_instance = SWGSDRangel::DeviceSetApi->new();
    +my $deviceSetIndex = 56; # Integer | Index of device set in the device set list
    +my $body = SWGSDRangel::Object::WorkspaceInfo->new(); # WorkspaceInfo | Destination workspace information
    +
    +eval { 
    +    my $result = $api_instance->devicesetDeviceWorkspacePut(deviceSetIndex => $deviceSetIndex, body => $body);
    +    print Dumper($result);
    +};
    +if ($@) {
    +    warn "Exception when calling DeviceSetApi->devicesetDeviceWorkspacePut: $@\n";
    +}
    +
    + +
    +
    from __future__ import print_statement
    +import time
    +import swagger_sdrangel
    +from swagger_sdrangel.rest import ApiException
    +from pprint import pprint
    +
    +# create an instance of the API class
    +api_instance = swagger_sdrangel.DeviceSetApi()
    +deviceSetIndex = 56 # Integer | Index of device set in the device set list
    +body =  # WorkspaceInfo | Destination workspace information
    +
    +try: 
    +    api_response = api_instance.deviceset_device_workspace_put(deviceSetIndex, body)
    +    pprint(api_response)
    +except ApiException as e:
    +    print("Exception when calling DeviceSetApi->devicesetDeviceWorkspacePut: %s\n" % e)
    +
    +
    + +

    Parameters

    + +
    Path parameters
    + + + + + + + + + +
    NameDescription
    deviceSetIndex* + + +
    +
    +
    + + Integer + + +
    + Index of device set in the device set list +
    +
    +
    + Required +
    +
    +
    +
    + + +
    Body parameters
    + + + + + + + + + +
    NameDescription
    body * + + + +
    +
    + + + +

    Responses

    +

    Status: 202 - Message to perform action was sent successfully

    + + + +
    +
    +
    + +
    + +
    +
    + +

    Status: 400 - Invalid device set or workspace index

    + + + +
    +
    +
    + +
    + +
    +
    + +

    Status: 500 - Error

    + + + +
    +
    +
    + +
    + +
    +
    + +

    Status: 501 - Function not implemented

    + + + +
    +
    +
    + +
    + +
    +
    + +
    +
    +
    @@ -28369,6 +30263,894 @@ $(document).ready(function() {

    +
    +
    +
    +

    devicesetSpectrumWorkspaceGet

    +

    +
    +
    +
    +

    +

    Get main spectrum UI workspace information (GUI)

    +

    +
    +
    /sdrangel/deviceset/{deviceSetIndex}/spectrum/workspace
    +

    +

    Usage and SDK Samples

    +

    + + +
    +
    +
    curl -X GET "http://localhost/sdrangel/deviceset/{deviceSetIndex}/spectrum/workspace"
    +
    +
    +
    import SWGSDRangel.*;
    +import SWGSDRangel.auth.*;
    +import SWGSDRangel.model.*;
    +import SWGSDRangel.api.DeviceSetApi;
    +
    +import java.io.File;
    +import java.util.*;
    +
    +public class DeviceSetApiExample {
    +
    +    public static void main(String[] args) {
    +        
    +        DeviceSetApi apiInstance = new DeviceSetApi();
    +        Integer deviceSetIndex = 56; // Integer | Index of device set in the device set list
    +        try {
    +            WorkspaceInfo result = apiInstance.devicesetSpectrumWorkspaceGet(deviceSetIndex);
    +            System.out.println(result);
    +        } catch (ApiException e) {
    +            System.err.println("Exception when calling DeviceSetApi#devicesetSpectrumWorkspaceGet");
    +            e.printStackTrace();
    +        }
    +    }
    +}
    +
    + +
    +
    import SWGSDRangel.api.DeviceSetApi;
    +
    +public class DeviceSetApiExample {
    +
    +    public static void main(String[] args) {
    +        DeviceSetApi apiInstance = new DeviceSetApi();
    +        Integer deviceSetIndex = 56; // Integer | Index of device set in the device set list
    +        try {
    +            WorkspaceInfo result = apiInstance.devicesetSpectrumWorkspaceGet(deviceSetIndex);
    +            System.out.println(result);
    +        } catch (ApiException e) {
    +            System.err.println("Exception when calling DeviceSetApi#devicesetSpectrumWorkspaceGet");
    +            e.printStackTrace();
    +        }
    +    }
    +}
    +
    + +
    +
    Integer *deviceSetIndex = 56; // Index of device set in the device set list
    +
    +DeviceSetApi *apiInstance = [[DeviceSetApi alloc] init];
    +
    +[apiInstance devicesetSpectrumWorkspaceGetWith:deviceSetIndex
    +              completionHandler: ^(WorkspaceInfo output, NSError* error) {
    +                            if (output) {
    +                                NSLog(@"%@", output);
    +                            }
    +                            if (error) {
    +                                NSLog(@"Error: %@", error);
    +                            }
    +                        }];
    +
    +
    + +
    +
    var SdRangel = require('sd_rangel');
    +
    +var api = new SdRangel.DeviceSetApi()
    +
    +var deviceSetIndex = 56; // {Integer} Index of device set in the device set list
    +
    +
    +var callback = function(error, data, response) {
    +  if (error) {
    +    console.error(error);
    +  } else {
    +    console.log('API called successfully. Returned data: ' + data);
    +  }
    +};
    +api.devicesetSpectrumWorkspaceGet(deviceSetIndex, callback);
    +
    +
    + + +
    +
    using System;
    +using System.Diagnostics;
    +using SWGSDRangel.Api;
    +using SWGSDRangel.Client;
    +using SWGSDRangel.Model;
    +
    +namespace Example
    +{
    +    public class devicesetSpectrumWorkspaceGetExample
    +    {
    +        public void main()
    +        {
    +            
    +            var apiInstance = new DeviceSetApi();
    +            var deviceSetIndex = 56;  // Integer | Index of device set in the device set list
    +
    +            try
    +            {
    +                WorkspaceInfo result = apiInstance.devicesetSpectrumWorkspaceGet(deviceSetIndex);
    +                Debug.WriteLine(result);
    +            }
    +            catch (Exception e)
    +            {
    +                Debug.Print("Exception when calling DeviceSetApi.devicesetSpectrumWorkspaceGet: " + e.Message );
    +            }
    +        }
    +    }
    +}
    +
    +
    + +
    +
    <?php
    +require_once(__DIR__ . '/vendor/autoload.php');
    +
    +$api_instance = new Swagger\Client\Api\DeviceSetApi();
    +$deviceSetIndex = 56; // Integer | Index of device set in the device set list
    +
    +try {
    +    $result = $api_instance->devicesetSpectrumWorkspaceGet($deviceSetIndex);
    +    print_r($result);
    +} catch (Exception $e) {
    +    echo 'Exception when calling DeviceSetApi->devicesetSpectrumWorkspaceGet: ', $e->getMessage(), PHP_EOL;
    +}
    +?>
    +
    + +
    +
    use Data::Dumper;
    +use SWGSDRangel::Configuration;
    +use SWGSDRangel::DeviceSetApi;
    +
    +my $api_instance = SWGSDRangel::DeviceSetApi->new();
    +my $deviceSetIndex = 56; # Integer | Index of device set in the device set list
    +
    +eval { 
    +    my $result = $api_instance->devicesetSpectrumWorkspaceGet(deviceSetIndex => $deviceSetIndex);
    +    print Dumper($result);
    +};
    +if ($@) {
    +    warn "Exception when calling DeviceSetApi->devicesetSpectrumWorkspaceGet: $@\n";
    +}
    +
    + +
    +
    from __future__ import print_statement
    +import time
    +import swagger_sdrangel
    +from swagger_sdrangel.rest import ApiException
    +from pprint import pprint
    +
    +# create an instance of the API class
    +api_instance = swagger_sdrangel.DeviceSetApi()
    +deviceSetIndex = 56 # Integer | Index of device set in the device set list
    +
    +try: 
    +    api_response = api_instance.deviceset_spectrum_workspace_get(deviceSetIndex)
    +    pprint(api_response)
    +except ApiException as e:
    +    print("Exception when calling DeviceSetApi->devicesetSpectrumWorkspaceGet: %s\n" % e)
    +
    +
    + +

    Parameters

    + +
    Path parameters
    + + + + + + + + + +
    NameDescription
    deviceSetIndex* + + +
    +
    +
    + + Integer + + +
    + Index of device set in the device set list +
    +
    +
    + Required +
    +
    +
    +
    + + + + + +

    Responses

    +

    Status: 200 - On success return main spectrum UI workspace index

    + + + +
    +
    +
    + +
    + +
    +
    + +

    Status: 404 - Invalid index

    + + + +
    +
    +
    + +
    + +
    +
    + +

    Status: 500 - Error

    + + + +
    +
    +
    + +
    + +
    +
    + +

    Status: 501 - Function not implemented

    + + + +
    +
    +
    + +
    + +
    +
    + +
    +
    +
    +
    +
    +
    +

    devicesetSpectrumWorkspacePut

    +

    +
    +
    +
    +

    +

    move main spectrum UI to workspace (GUI)

    +

    +
    +
    /sdrangel/deviceset/{deviceSetIndex}/spectrum/workspace
    +

    +

    Usage and SDK Samples

    +

    + + +
    +
    +
    curl -X PUT "http://localhost/sdrangel/deviceset/{deviceSetIndex}/spectrum/workspace"
    +
    +
    +
    import SWGSDRangel.*;
    +import SWGSDRangel.auth.*;
    +import SWGSDRangel.model.*;
    +import SWGSDRangel.api.DeviceSetApi;
    +
    +import java.io.File;
    +import java.util.*;
    +
    +public class DeviceSetApiExample {
    +
    +    public static void main(String[] args) {
    +        
    +        DeviceSetApi apiInstance = new DeviceSetApi();
    +        Integer deviceSetIndex = 56; // Integer | Index of device set in the device set list
    +        WorkspaceInfo body = ; // WorkspaceInfo | Destination workspace information
    +        try {
    +            SuccessResponse result = apiInstance.devicesetSpectrumWorkspacePut(deviceSetIndex, body);
    +            System.out.println(result);
    +        } catch (ApiException e) {
    +            System.err.println("Exception when calling DeviceSetApi#devicesetSpectrumWorkspacePut");
    +            e.printStackTrace();
    +        }
    +    }
    +}
    +
    + +
    +
    import SWGSDRangel.api.DeviceSetApi;
    +
    +public class DeviceSetApiExample {
    +
    +    public static void main(String[] args) {
    +        DeviceSetApi apiInstance = new DeviceSetApi();
    +        Integer deviceSetIndex = 56; // Integer | Index of device set in the device set list
    +        WorkspaceInfo body = ; // WorkspaceInfo | Destination workspace information
    +        try {
    +            SuccessResponse result = apiInstance.devicesetSpectrumWorkspacePut(deviceSetIndex, body);
    +            System.out.println(result);
    +        } catch (ApiException e) {
    +            System.err.println("Exception when calling DeviceSetApi#devicesetSpectrumWorkspacePut");
    +            e.printStackTrace();
    +        }
    +    }
    +}
    +
    + +
    +
    Integer *deviceSetIndex = 56; // Index of device set in the device set list
    +WorkspaceInfo *body = ; // Destination workspace information
    +
    +DeviceSetApi *apiInstance = [[DeviceSetApi alloc] init];
    +
    +[apiInstance devicesetSpectrumWorkspacePutWith:deviceSetIndex
    +    body:body
    +              completionHandler: ^(SuccessResponse output, NSError* error) {
    +                            if (output) {
    +                                NSLog(@"%@", output);
    +                            }
    +                            if (error) {
    +                                NSLog(@"Error: %@", error);
    +                            }
    +                        }];
    +
    +
    + +
    +
    var SdRangel = require('sd_rangel');
    +
    +var api = new SdRangel.DeviceSetApi()
    +
    +var deviceSetIndex = 56; // {Integer} Index of device set in the device set list
    +
    +var body = ; // {WorkspaceInfo} Destination workspace information
    +
    +
    +var callback = function(error, data, response) {
    +  if (error) {
    +    console.error(error);
    +  } else {
    +    console.log('API called successfully. Returned data: ' + data);
    +  }
    +};
    +api.devicesetSpectrumWorkspacePut(deviceSetIndex, body, callback);
    +
    +
    + + +
    +
    using System;
    +using System.Diagnostics;
    +using SWGSDRangel.Api;
    +using SWGSDRangel.Client;
    +using SWGSDRangel.Model;
    +
    +namespace Example
    +{
    +    public class devicesetSpectrumWorkspacePutExample
    +    {
    +        public void main()
    +        {
    +            
    +            var apiInstance = new DeviceSetApi();
    +            var deviceSetIndex = 56;  // Integer | Index of device set in the device set list
    +            var body = new WorkspaceInfo(); // WorkspaceInfo | Destination workspace information
    +
    +            try
    +            {
    +                SuccessResponse result = apiInstance.devicesetSpectrumWorkspacePut(deviceSetIndex, body);
    +                Debug.WriteLine(result);
    +            }
    +            catch (Exception e)
    +            {
    +                Debug.Print("Exception when calling DeviceSetApi.devicesetSpectrumWorkspacePut: " + e.Message );
    +            }
    +        }
    +    }
    +}
    +
    +
    + +
    +
    <?php
    +require_once(__DIR__ . '/vendor/autoload.php');
    +
    +$api_instance = new Swagger\Client\Api\DeviceSetApi();
    +$deviceSetIndex = 56; // Integer | Index of device set in the device set list
    +$body = ; // WorkspaceInfo | Destination workspace information
    +
    +try {
    +    $result = $api_instance->devicesetSpectrumWorkspacePut($deviceSetIndex, $body);
    +    print_r($result);
    +} catch (Exception $e) {
    +    echo 'Exception when calling DeviceSetApi->devicesetSpectrumWorkspacePut: ', $e->getMessage(), PHP_EOL;
    +}
    +?>
    +
    + +
    +
    use Data::Dumper;
    +use SWGSDRangel::Configuration;
    +use SWGSDRangel::DeviceSetApi;
    +
    +my $api_instance = SWGSDRangel::DeviceSetApi->new();
    +my $deviceSetIndex = 56; # Integer | Index of device set in the device set list
    +my $body = SWGSDRangel::Object::WorkspaceInfo->new(); # WorkspaceInfo | Destination workspace information
    +
    +eval { 
    +    my $result = $api_instance->devicesetSpectrumWorkspacePut(deviceSetIndex => $deviceSetIndex, body => $body);
    +    print Dumper($result);
    +};
    +if ($@) {
    +    warn "Exception when calling DeviceSetApi->devicesetSpectrumWorkspacePut: $@\n";
    +}
    +
    + +
    +
    from __future__ import print_statement
    +import time
    +import swagger_sdrangel
    +from swagger_sdrangel.rest import ApiException
    +from pprint import pprint
    +
    +# create an instance of the API class
    +api_instance = swagger_sdrangel.DeviceSetApi()
    +deviceSetIndex = 56 # Integer | Index of device set in the device set list
    +body =  # WorkspaceInfo | Destination workspace information
    +
    +try: 
    +    api_response = api_instance.deviceset_spectrum_workspace_put(deviceSetIndex, body)
    +    pprint(api_response)
    +except ApiException as e:
    +    print("Exception when calling DeviceSetApi->devicesetSpectrumWorkspacePut: %s\n" % e)
    +
    +
    + +

    Parameters

    + +
    Path parameters
    + + + + + + + + + +
    NameDescription
    deviceSetIndex* + + +
    +
    +
    + + Integer + + +
    + Index of device set in the device set list +
    +
    +
    + Required +
    +
    +
    +
    + + +
    Body parameters
    + + + + + + + + + +
    NameDescription
    body * + + + +
    +
    + + + +

    Responses

    +

    Status: 202 - Message to perform action was sent successfully

    + + + +
    +
    +
    + +
    + +
    +
    + +

    Status: 400 - Invalid device set or workspace index

    + + + +
    +
    +
    + +
    + +
    +
    + +

    Status: 500 - Error

    + + + +
    +
    +
    + +
    + +
    +
    + +

    Status: 501 - Function not implemented

    + + + +
    +
    +
    + +
    + +
    +
    + +
    +
    +
    @@ -29135,7 +31917,7 @@ except ApiException as e:

    apply all settings unconditionally (force)


    -
    /sdrangel/featureset/{featureSetIndex}/feature/{featureIndex}/settings
    +
    /sdrangel/featureset/feature/{featureIndex}/settings

    Usage and SDK Samples

    @@ -29155,7 +31937,7 @@ except ApiException as e:
    -
    curl -X PUT "http://localhost/sdrangel/featureset/{featureSetIndex}/feature/{featureIndex}/settings"
    +
    curl -X PUT "http://localhost/sdrangel/featureset/feature/{featureIndex}/settings"
    import SWGSDRangel.*;
    @@ -29171,11 +31953,10 @@ public class FeatureSetApiExample {
         public static void main(String[] args) {
             
             FeatureSetApi apiInstance = new FeatureSetApi();
    -        Integer featureSetIndex = 56; // Integer | Index of feature set in the feature set list
    -        Integer featureIndex = 56; // Integer | Index of the feature in the features list for this feature set
    +        Integer featureIndex = 56; // Integer | Index of the feature in the features list
             FeatureSettings body = ; // FeatureSettings | Feature settings to apply
             try {
    -            FeatureSettings result = apiInstance.featuresetFEatureSettingsPut(featureSetIndex, featureIndex, body);
    +            FeatureSettings result = apiInstance.featuresetFEatureSettingsPut(featureIndex, body);
                 System.out.println(result);
             } catch (ApiException e) {
                 System.err.println("Exception when calling FeatureSetApi#featuresetFEatureSettingsPut");
    @@ -29192,11 +31973,10 @@ public class FeatureSetApiExample {
     
         public static void main(String[] args) {
             FeatureSetApi apiInstance = new FeatureSetApi();
    -        Integer featureSetIndex = 56; // Integer | Index of feature set in the feature set list
    -        Integer featureIndex = 56; // Integer | Index of the feature in the features list for this feature set
    +        Integer featureIndex = 56; // Integer | Index of the feature in the features list
             FeatureSettings body = ; // FeatureSettings | Feature settings to apply
             try {
    -            FeatureSettings result = apiInstance.featuresetFEatureSettingsPut(featureSetIndex, featureIndex, body);
    +            FeatureSettings result = apiInstance.featuresetFEatureSettingsPut(featureIndex, body);
                 System.out.println(result);
             } catch (ApiException e) {
                 System.err.println("Exception when calling FeatureSetApi#featuresetFEatureSettingsPut");
    @@ -29210,14 +31990,12 @@ public class FeatureSetApiExample {
       
    Coming Soon!
    -->
    -
    Integer *featureSetIndex = 56; // Index of feature set in the feature set list
    -Integer *featureIndex = 56; // Index of the feature in the features list for this feature set
    +                              
    Integer *featureIndex = 56; // Index of the feature in the features list
     FeatureSettings *body = ; // Feature settings to apply
     
     FeatureSetApi *apiInstance = [[FeatureSetApi alloc] init];
     
    -[apiInstance featuresetFEatureSettingsPutWith:featureSetIndex
    -    featureIndex:featureIndex
    +[apiInstance featuresetFEatureSettingsPutWith:featureIndex
         body:body
                   completionHandler: ^(FeatureSettings output, NSError* error) {
                                 if (output) {
    @@ -29235,9 +32013,7 @@ FeatureSetApi *apiInstance = [[FeatureSetApi alloc] init];
     
     var api = new SdRangel.FeatureSetApi()
     
    -var featureSetIndex = 56; // {Integer} Index of feature set in the feature set list
    -
    -var featureIndex = 56; // {Integer} Index of the feature in the features list for this feature set
    +var featureIndex = 56; // {Integer} Index of the feature in the features list
     
     var body = ; // {FeatureSettings} Feature settings to apply
     
    @@ -29249,7 +32025,7 @@ var callback = function(error, data, response) {
         console.log('API called successfully. Returned data: ' + data);
       }
     };
    -api.featuresetFEatureSettingsPut(featureSetIndex, featureIndex, body, callback);
    +api.featuresetFEatureSettingsPut(featureIndex, body, callback);
     
    @@ -29271,13 +32047,12 @@ namespace Example { var apiInstance = new FeatureSetApi(); - var featureSetIndex = 56; // Integer | Index of feature set in the feature set list - var featureIndex = 56; // Integer | Index of the feature in the features list for this feature set + var featureIndex = 56; // Integer | Index of the feature in the features list var body = new FeatureSettings(); // FeatureSettings | Feature settings to apply try { - FeatureSettings result = apiInstance.featuresetFEatureSettingsPut(featureSetIndex, featureIndex, body); + FeatureSettings result = apiInstance.featuresetFEatureSettingsPut(featureIndex, body); Debug.WriteLine(result); } catch (Exception e) @@ -29295,12 +32070,11 @@ namespace Example require_once(__DIR__ . '/vendor/autoload.php'); $api_instance = new Swagger\Client\Api\FeatureSetApi(); -$featureSetIndex = 56; // Integer | Index of feature set in the feature set list -$featureIndex = 56; // Integer | Index of the feature in the features list for this feature set +$featureIndex = 56; // Integer | Index of the feature in the features list $body = ; // FeatureSettings | Feature settings to apply try { - $result = $api_instance->featuresetFEatureSettingsPut($featureSetIndex, $featureIndex, $body); + $result = $api_instance->featuresetFEatureSettingsPut($featureIndex, $body); print_r($result); } catch (Exception $e) { echo 'Exception when calling FeatureSetApi->featuresetFEatureSettingsPut: ', $e->getMessage(), PHP_EOL; @@ -29314,12 +32088,11 @@ use SWGSDRangel::Configuration; use SWGSDRangel::FeatureSetApi; my $api_instance = SWGSDRangel::FeatureSetApi->new(); -my $featureSetIndex = 56; # Integer | Index of feature set in the feature set list -my $featureIndex = 56; # Integer | Index of the feature in the features list for this feature set +my $featureIndex = 56; # Integer | Index of the feature in the features list my $body = SWGSDRangel::Object::FeatureSettings->new(); # FeatureSettings | Feature settings to apply eval { - my $result = $api_instance->featuresetFEatureSettingsPut(featureSetIndex => $featureSetIndex, featureIndex => $featureIndex, body => $body); + my $result = $api_instance->featuresetFEatureSettingsPut(featureIndex => $featureIndex, body => $body); print Dumper($result); }; if ($@) { @@ -29336,12 +32109,11 @@ from pprint import pprint # create an instance of the API class api_instance = swagger_sdrangel.FeatureSetApi() -featureSetIndex = 56 # Integer | Index of feature set in the feature set list -featureIndex = 56 # Integer | Index of the feature in the features list for this feature set +featureIndex = 56 # Integer | Index of the feature in the features list body = # FeatureSettings | Feature settings to apply try: - api_response = api_instance.featureset_f_eature_settings_put(featureSetIndex, featureIndex, body) + api_response = api_instance.featureset_f_eature_settings_put(featureIndex, body) pprint(api_response) except ApiException as e: print("Exception when calling FeatureSetApi->featuresetFEatureSettingsPut: %s\n" % e) @@ -29356,29 +32128,6 @@ except ApiException as e: Name Description - featureSetIndex* - - - -
    -
    -
    - - Integer - - -
    - Index of feature set in the feature set list -
    -
    -
    - Required -
    -
    -
    - - - featureIndex* @@ -29391,7 +32140,7 @@ except ApiException as e:
    - Index of the feature in the features list for this feature set + Index of the feature in the features list
    @@ -29494,7 +32243,7 @@ $(document).ready(function() {
    -

    Status: 400 - Invalid feature set or feature index

    +

    Status: 400 - Invalid feature index

    - - - -

    Status: 404 - Feature not found