From 0d0b8c9618b0097c6738fc9d5aced741588fa2e2 Mon Sep 17 00:00:00 2001 From: f4exb Date: Mon, 5 Nov 2018 02:19:40 +0100 Subject: [PATCH] SoapySDR support: input: bandwidth selection GUI --- .../soapysdroutput/soapysdroutput.cpp | 17 +++++ .../soapysdroutput/soapysdroutputgui.cpp | 40 +++++++++- .../soapysdroutput/soapysdroutputgui.h | 5 ++ .../soapysdroutput/soapysdroutputsettings.cpp | 3 + .../soapysdroutput/soapysdroutputsettings.h | 5 +- .../soapysdrinput/soapysdrinput.cpp | 33 +++++++- .../soapysdrinput/soapysdrinput.h | 3 +- .../soapysdrinput/soapysdrinputgui.cpp | 75 +++++++++---------- .../soapysdrinput/soapysdrinputgui.h | 15 +++- .../soapysdrinput/soapysdrinputgui.ui | 5 +- .../soapysdrinput/soapysdrinputsettings.cpp | 3 + .../soapysdrinput/soapysdrinputsettings.h | 1 + sdrgui/soapygui/discreterangegui.ui | 12 +++ sdrgui/soapygui/intervalrangegui.ui | 12 +++ 14 files changed, 176 insertions(+), 53 deletions(-) diff --git a/plugins/samplesink/soapysdroutput/soapysdroutput.cpp b/plugins/samplesink/soapysdroutput/soapysdroutput.cpp index 78d97fc1c..8272d92e9 100644 --- a/plugins/samplesink/soapysdroutput/soapysdroutput.cpp +++ b/plugins/samplesink/soapysdroutput/soapysdroutput.cpp @@ -717,6 +717,23 @@ bool SoapySDROutput::applySettings(const SoapySDROutputSettings& settings, bool } } + if ((m_settings.m_antenna != settings.m_antenna) || force) + { + if (dev != 0) + { + try + { + dev->setAntenna(SOAPY_SDR_TX, requestedChannel, settings.m_antenna.toStdString()); + qDebug("SoapySDROutput::applySettings: set antenna to %s", settings.m_antenna.toStdString().c_str()); + } + catch (const std::exception &ex) + { + qCritical("SoapySDROutput::applySettings: cannot set antenna to %s: %s", + settings.m_antenna.toStdString().c_str(), ex.what()); + } + } + } + if (forwardChangeOwnDSP) { int sampleRate = settings.m_devSampleRate/(1<getFrequencyRange(f_min, f_max); ui->centerFrequency->setValueRange(7, f_min/1000, f_max/1000); + createAntennasControl(m_sampleSink->getAntennas()); createRangesControl(m_sampleSink->getRateRanges(), "SR", "kS/s"); connect(&m_updateTimer, SIGNAL(timeout()), this, SLOT(updateHardware())); @@ -90,7 +92,7 @@ void SoapySDROutputGui::createRangesControl(const SoapySDR::RangeList& rangeList if (rangeDiscrete) { - DiscreteRangeGUI *rangeGUI = new DiscreteRangeGUI(ui->scrollAreaWidgetContents); + DiscreteRangeGUI *rangeGUI = new DiscreteRangeGUI(this); rangeGUI->setLabel(text); rangeGUI->setUnits(unit); @@ -99,11 +101,14 @@ void SoapySDROutputGui::createRangesControl(const SoapySDR::RangeList& rangeList } m_sampleRateGUI = rangeGUI; + QVBoxLayout *layout = (QVBoxLayout *) ui->scrollAreaWidgetContents->layout(); + layout->addWidget(rangeGUI); + connect(m_sampleRateGUI, SIGNAL(valueChanged(double)), this, SLOT(sampleRateChanged(double))); } else if (rangeInterval) { - IntervalRangeGUI *rangeGUI = new IntervalRangeGUI(ui->scrollAreaWidgetContents); + IntervalRangeGUI *rangeGUI = new IntervalRangeGUI(this); rangeGUI->setLabel(text); rangeGUI->setUnits(unit); @@ -114,10 +119,33 @@ void SoapySDROutputGui::createRangesControl(const SoapySDR::RangeList& rangeList rangeGUI->reset(); m_sampleRateGUI = rangeGUI; + QVBoxLayout *layout = (QVBoxLayout *) ui->scrollAreaWidgetContents->layout(); + layout->addWidget(rangeGUI); + connect(m_sampleRateGUI, SIGNAL(valueChanged(double)), this, SLOT(sampleRateChanged(double))); } } +void SoapySDROutputGui::createAntennasControl(const std::vector& antennaList) +{ + if (antennaList.size() == 0) { // return early if the antenna list is empty + return; + } + + m_antennas = new StringRangeGUI(this); + m_antennas->setLabel(QString("Antenna")); + m_antennas->setUnits(QString("Port")); + + for (const auto &it : antennaList) { + m_antennas->addItem(QString(it.c_str()), it); + } + + QVBoxLayout *layout = (QVBoxLayout *) ui->scrollAreaWidgetContents->layout(); + layout->addWidget(m_antennas); + + connect(m_antennas, SIGNAL(valueChanged()), this, SLOT(antennasChanged())); +} + void SoapySDROutputGui::setName(const QString& name) { setObjectName(name); @@ -227,6 +255,14 @@ void SoapySDROutputGui::sampleRateChanged(double sampleRate) sendSettings(); } +void SoapySDROutputGui::antennasChanged() +{ + const std::string& antennaStr = m_antennas->getCurrentValue(); + m_settings.m_antenna = QString(antennaStr.c_str()); + + sendSettings(); +} + void SoapySDROutputGui::on_centerFrequency_changed(quint64 value) { m_settings.m_centerFrequency = value * 1000; diff --git a/plugins/samplesink/soapysdroutput/soapysdroutputgui.h b/plugins/samplesink/soapysdroutput/soapysdroutputgui.h index 3d130f390..84b9250eb 100644 --- a/plugins/samplesink/soapysdroutput/soapysdroutputgui.h +++ b/plugins/samplesink/soapysdroutput/soapysdroutputgui.h @@ -29,6 +29,7 @@ class DeviceSampleSink; class DeviceUISet; class ItemSettingGUI; +class StringRangeGUI; namespace Ui { class SoapySDROutputGui; @@ -55,6 +56,8 @@ public: private: void createRangesControl(const SoapySDR::RangeList& rangeList, const QString& text, const QString& unit); + void createAntennasControl(const std::vector& antennaList); + Ui::SoapySDROutputGui* ui; DeviceUISet* m_deviceUISet; @@ -70,6 +73,7 @@ private: MessageQueue m_inputMessageQueue; ItemSettingGUI *m_sampleRateGUI; + StringRangeGUI *m_antennas; void blockApplySettings(bool block) { m_doApplySettings = !block; } void displaySettings(); @@ -83,6 +87,7 @@ private slots: void on_centerFrequency_changed(quint64 value); void on_LOppm_valueChanged(int value); void sampleRateChanged(double sampleRate); + void antennasChanged(); void on_interp_currentIndexChanged(int index); void on_transverter_clicked(); void on_startStop_toggled(bool checked); diff --git a/plugins/samplesink/soapysdroutput/soapysdroutputsettings.cpp b/plugins/samplesink/soapysdroutput/soapysdroutputsettings.cpp index 140212219..ec2e6c869 100644 --- a/plugins/samplesink/soapysdroutput/soapysdroutputsettings.cpp +++ b/plugins/samplesink/soapysdroutput/soapysdroutputsettings.cpp @@ -32,6 +32,7 @@ void SoapySDROutputSettings::resetToDefaults() m_log2Interp = 0; m_transverterMode = false; m_transverterDeltaFrequency = 0; + m_antenna = "NONE"; } QByteArray SoapySDROutputSettings::serialize() const @@ -43,6 +44,7 @@ QByteArray SoapySDROutputSettings::serialize() const s.writeU32(3, m_log2Interp); s.writeBool(4, m_transverterMode); s.writeS64(5, m_transverterDeltaFrequency); + s.writeString(6, m_antenna); return s.final(); } @@ -64,6 +66,7 @@ bool SoapySDROutputSettings::deserialize(const QByteArray& data) d.readU32(3, &m_log2Interp); d.readBool(4, &m_transverterMode, false); d.readS64(5, &m_transverterDeltaFrequency, 0); + d.readString(6, &m_antenna, "NONE"); return true; } diff --git a/plugins/samplesink/soapysdroutput/soapysdroutputsettings.h b/plugins/samplesink/soapysdroutput/soapysdroutputsettings.h index 1e6f190e2..a5a4b0181 100644 --- a/plugins/samplesink/soapysdroutput/soapysdroutputsettings.h +++ b/plugins/samplesink/soapysdroutput/soapysdroutputsettings.h @@ -24,8 +24,9 @@ struct SoapySDROutputSettings { int m_LOppmTenths; qint32 m_devSampleRate; quint32 m_log2Interp; - bool m_transverterMode; - qint64 m_transverterDeltaFrequency; + bool m_transverterMode; + qint64 m_transverterDeltaFrequency; + QString m_antenna; SoapySDROutputSettings(); void resetToDefaults(); diff --git a/plugins/samplesource/soapysdrinput/soapysdrinput.cpp b/plugins/samplesource/soapysdrinput/soapysdrinput.cpp index 30b5b7d23..97b6e2de2 100644 --- a/plugins/samplesource/soapysdrinput/soapysdrinput.cpp +++ b/plugins/samplesource/soapysdrinput/soapysdrinput.cpp @@ -203,16 +203,22 @@ void SoapySDRInput::getFrequencyRange(uint64_t& min, uint64_t& max) } } +const std::vector& SoapySDRInput::getAntennas() +{ + const DeviceSoapySDRParams::ChannelSettings* channelSettings = m_deviceShared.m_deviceParams->getRxChannelSettings(m_deviceShared.m_channel); + return channelSettings->m_antennas; +} + const SoapySDR::RangeList& SoapySDRInput::getRateRanges() { const DeviceSoapySDRParams::ChannelSettings* channelSettings = m_deviceShared.m_deviceParams->getRxChannelSettings(m_deviceShared.m_channel); return channelSettings->m_ratesRanges; } -const std::vector& SoapySDRInput::getAntennas() +const SoapySDR::RangeList& SoapySDRInput::getBandwidthRanges() { const DeviceSoapySDRParams::ChannelSettings* channelSettings = m_deviceShared.m_deviceParams->getRxChannelSettings(m_deviceShared.m_channel); - return channelSettings->m_antennas; + return channelSettings->m_bandwidthsRanges; } int SoapySDRInput::getAntennaIndex(const std::string& antenna) @@ -645,6 +651,7 @@ bool SoapySDRInput::handleMessage(const Message& message __attribute__((unused)) settings.m_centerFrequency = round(centerFrequency/1000.0) * 1000; settings.m_devSampleRate = round(m_deviceShared.m_device->getSampleRate(SOAPY_SDR_RX, requestedChannel)); + settings.m_bandwidth = round(m_deviceShared.m_device->getBandwidth(SOAPY_SDR_RX, requestedChannel)); SoapySDRInputThread *inputThread = findThread(); @@ -780,6 +787,25 @@ bool SoapySDRInput::applySettings(const SoapySDRInputSettings& settings, bool fo } } + if ((m_settings.m_bandwidth != settings.m_bandwidth) || force) + { + forwardChangeToBuddies = true; + + if (dev != 0) + { + try + { + dev->setBandwidth(SOAPY_SDR_RX, requestedChannel, settings.m_bandwidth); + qDebug("SoapySDRInput::applySettings: bandwidth set to %u", settings.m_bandwidth); + } + catch (const std::exception &ex) + { + qCritical("SoapySDRInput::applySettings: cannot set bandwidth to %u: %s", + settings.m_bandwidth, ex.what()); + } + } + } + if (forwardChangeOwnDSP) { int sampleRate = settings.m_devSampleRate/(1<& getAntennas(); + const SoapySDR::RangeList& getRateRanges(); + const SoapySDR::RangeList& getBandwidthRanges(); int getAntennaIndex(const std::string& antenna); private: diff --git a/plugins/samplesource/soapysdrinput/soapysdrinputgui.cpp b/plugins/samplesource/soapysdrinput/soapysdrinputgui.cpp index 7f749a4e9..8dea5e21b 100644 --- a/plugins/samplesource/soapysdrinput/soapysdrinputgui.cpp +++ b/plugins/samplesource/soapysdrinput/soapysdrinputgui.cpp @@ -38,7 +38,8 @@ SoapySDRInputGui::SoapySDRInputGui(DeviceUISet *deviceUISet, QWidget* parent) : m_sampleRate(0), m_deviceCenterFrequency(0), m_lastEngineState(DSPDeviceSourceEngine::StNotStarted), - m_sampleRateGUI(0) + m_sampleRateGUI(0), + m_bandwidthGUI(0) { m_sampleSource = (SoapySDRInput*) m_deviceUISet->m_deviceSourceAPI->getSampleSource(); ui->setupUi(this); @@ -48,8 +49,16 @@ SoapySDRInputGui::SoapySDRInputGui(DeviceUISet *deviceUISet, QWidget* parent) : m_sampleSource->getFrequencyRange(f_min, f_max); ui->centerFrequency->setValueRange(7, f_min/1000, f_max/1000); - createRangesControl(m_sampleSource->getRateRanges(), "SR", "kS/s"); createAntennasControl(m_sampleSource->getAntennas()); + createRangesControl(&m_sampleRateGUI, m_sampleSource->getRateRanges(), "SR", "S/s"); + createRangesControl(&m_bandwidthGUI, m_sampleSource->getBandwidthRanges(), "BW", "Hz"); + + if (m_sampleRateGUI) { + connect(m_sampleRateGUI, SIGNAL(valueChanged(double)), this, SLOT(sampleRateChanged(double))); + } + if (m_bandwidthGUI) { + connect(m_bandwidthGUI, SIGNAL(valueChanged(double)), this, SLOT(bandwidthChanged(double))); + } connect(&m_updateTimer, SIGNAL(timeout()), this, SLOT(updateHardware())); connect(&m_statusTimer, SIGNAL(timeout()), this, SLOT(updateStatus())); @@ -73,7 +82,11 @@ void SoapySDRInputGui::destroy() delete this; } -void SoapySDRInputGui::createRangesControl(const SoapySDR::RangeList& rangeList, const QString& text, const QString& unit) +void SoapySDRInputGui::createRangesControl( + ItemSettingGUI **settingGUI, + const SoapySDR::RangeList& rangeList, + const QString& text, + const QString& unit) { if (rangeList.size() == 0) { // return early if the range list is empty return; @@ -95,41 +108,15 @@ void SoapySDRInputGui::createRangesControl(const SoapySDR::RangeList& rangeList, { DiscreteRangeGUI *rangeGUI = new DiscreteRangeGUI(this); rangeGUI->setLabel(text); - rangeGUI->setUnits(unit); + rangeGUI->setUnits(QString("k%1").arg(unit)); for (const auto &it : rangeList) { rangeGUI->addItem(QString("%1").arg(QString::number(it.minimum()/1000.0, 'f', 0)), it.minimum()); } - m_sampleRateGUI = rangeGUI; + *settingGUI = rangeGUI; QVBoxLayout *layout = (QVBoxLayout *) ui->scrollAreaWidgetContents->layout(); layout->addWidget(rangeGUI); - - connect(m_sampleRateGUI, SIGNAL(valueChanged(double)), this, SLOT(sampleRateChanged(double))); -// QHBoxLayout *layout = new QHBoxLayout(); -// QLabel *rangeLabel = new QLabel(); -// rangeLabel->setText(text); -// QLabel *rangeUnit = new QLabel(); -// rangeUnit->setText(unit); -// QComboBox *rangeCombo = new QComboBox(); -// -// for (const auto &it : rangeList) { -// rangeCombo->addItem(QString("%1").arg(QString::number(it.minimum()/1000.0, 'f', 0))); -// } -// -// layout->addWidget(rangeLabel); -// layout->addWidget(rangeCombo); -// layout->addWidget(rangeUnit); -// layout->setMargin(0); -// layout->setSpacing(6); -// rangeLabel->show(); -// rangeCombo->show(); -// QWidget *window = new QWidget(ui->scrollAreaWidgetContents); -// window->setFixedWidth(300); -// window->setFixedHeight(30); -// window->setContentsMargins(0,0,0,0); -// //window->setStyleSheet("background-color:black;"); -// window->setLayout(layout); } else if (rangeInterval) { @@ -143,16 +130,18 @@ void SoapySDRInputGui::createRangesControl(const SoapySDR::RangeList& rangeList, rangeGUI->reset(); - m_sampleRateGUI = rangeGUI; + *settingGUI = rangeGUI; QVBoxLayout *layout = (QVBoxLayout *) ui->scrollAreaWidgetContents->layout(); layout->addWidget(rangeGUI); - - connect(m_sampleRateGUI, SIGNAL(valueChanged(double)), this, SLOT(sampleRateChanged(double))); } } void SoapySDRInputGui::createAntennasControl(const std::vector& antennaList) { + if (antennaList.size() == 0) { // return early if the antenna list is empty + return; + } + m_antennas = new StringRangeGUI(this); m_antennas->setLabel(QString("Antenna")); m_antennas->setUnits(QString("Port")); @@ -269,17 +258,23 @@ void SoapySDRInputGui::handleInputMessages() } } +void SoapySDRInputGui::antennasChanged() +{ + const std::string& antennaStr = m_antennas->getCurrentValue(); + m_settings.m_antenna = QString(antennaStr.c_str()); + + sendSettings(); +} + void SoapySDRInputGui::sampleRateChanged(double sampleRate) { m_settings.m_devSampleRate = sampleRate; sendSettings(); } -void SoapySDRInputGui::antennasChanged() +void SoapySDRInputGui::bandwidthChanged(double bandwidth) { - const std::string& antennaStr = m_antennas->getCurrentValue(); - m_settings.m_antenna = QString(antennaStr.c_str()); - + m_settings.m_bandwidth = bandwidth; sendSettings(); } @@ -366,7 +361,9 @@ void SoapySDRInputGui::displaySettings() blockApplySettings(true); ui->centerFrequency->setValue(m_settings.m_centerFrequency / 1000); + m_antennas->setValue(m_settings.m_antenna.toStdString()); m_sampleRateGUI->setValue(m_settings.m_devSampleRate); + m_bandwidthGUI->setValue(m_settings.m_bandwidth); ui->dcOffset->setChecked(m_settings.m_dcBlock); ui->iqImbalance->setChecked(m_settings.m_iqCorrection); @@ -377,8 +374,6 @@ void SoapySDRInputGui::displaySettings() ui->LOppm->setValue(m_settings.m_LOppmTenths); ui->LOppmText->setText(QString("%1").arg(QString::number(m_settings.m_LOppmTenths/10.0, 'f', 1))); - m_antennas->setValue(m_settings.m_antenna.toStdString()); - blockApplySettings(false); } diff --git a/plugins/samplesource/soapysdrinput/soapysdrinputgui.h b/plugins/samplesource/soapysdrinput/soapysdrinputgui.h index 8fbe09013..7a1ab29d4 100644 --- a/plugins/samplesource/soapysdrinput/soapysdrinputgui.h +++ b/plugins/samplesource/soapysdrinput/soapysdrinputgui.h @@ -28,6 +28,7 @@ class DeviceUISet; class ItemSettingGUI; +class StringRangeGUI; namespace Ui { class SoapySDRInputGui; @@ -53,7 +54,11 @@ public: virtual bool handleMessage(const Message& message); private: - void createRangesControl(const SoapySDR::RangeList& rangeList, const QString& text, const QString& unit); + void createRangesControl( + ItemSettingGUI **settingGUI, + const SoapySDR::RangeList& rangeList, + const QString& text, + const QString& unit); void createAntennasControl(const std::vector& antennaList); Ui::SoapySDRInputGui* ui; @@ -70,8 +75,9 @@ private: int m_lastEngineState; MessageQueue m_inputMessageQueue; - ItemSettingGUI *m_sampleRateGUI; StringRangeGUI *m_antennas; + ItemSettingGUI *m_sampleRateGUI; + ItemSettingGUI *m_bandwidthGUI; void displaySettings(); void sendSettings(); @@ -82,10 +88,11 @@ private: private slots: void handleInputMessages(); - void on_centerFrequency_changed(quint64 value); - void on_LOppm_valueChanged(int value); void sampleRateChanged(double sampleRate); void antennasChanged(); + void bandwidthChanged(double bandwidth); + void on_centerFrequency_changed(quint64 value); + void on_LOppm_valueChanged(int value); void on_dcOffset_toggled(bool checked); void on_iqImbalance_toggled(bool checked); void on_decim_currentIndexChanged(int index); diff --git a/plugins/samplesource/soapysdrinput/soapysdrinputgui.ui b/plugins/samplesource/soapysdrinput/soapysdrinputgui.ui index c6d29c657..89d9fa789 100644 --- a/plugins/samplesource/soapysdrinput/soapysdrinputgui.ui +++ b/plugins/samplesource/soapysdrinput/soapysdrinputgui.ui @@ -374,6 +374,9 @@ + + Qt::ScrollBarAlwaysOn + true @@ -382,7 +385,7 @@ 0 0 - 318 + 304 51 diff --git a/plugins/samplesource/soapysdrinput/soapysdrinputsettings.cpp b/plugins/samplesource/soapysdrinput/soapysdrinputsettings.cpp index 901c7f9dc..9489947b9 100644 --- a/plugins/samplesource/soapysdrinput/soapysdrinputsettings.cpp +++ b/plugins/samplesource/soapysdrinput/soapysdrinputsettings.cpp @@ -36,6 +36,7 @@ void SoapySDRInputSettings::resetToDefaults() m_transverterDeltaFrequency = 0; m_fileRecordName = ""; m_antenna = "NONE"; + m_bandwidth = 1000000; } QByteArray SoapySDRInputSettings::serialize() const @@ -51,6 +52,7 @@ QByteArray SoapySDRInputSettings::serialize() const s.writeBool(7, m_transverterMode); s.writeS64(8, m_transverterDeltaFrequency); s.writeString(9, m_antenna); + s.writeU32(10, m_bandwidth); return s.final(); } @@ -79,6 +81,7 @@ bool SoapySDRInputSettings::deserialize(const QByteArray& data) d.readBool(7, &m_transverterMode, false); d.readS64(8, &m_transverterDeltaFrequency, 0); d.readString(9, &m_antenna, "NONE"); + d.readU32(10, &m_bandwidth, 1000000); return true; } diff --git a/plugins/samplesource/soapysdrinput/soapysdrinputsettings.h b/plugins/samplesource/soapysdrinput/soapysdrinputsettings.h index 8991c8ec1..62a942814 100644 --- a/plugins/samplesource/soapysdrinput/soapysdrinputsettings.h +++ b/plugins/samplesource/soapysdrinput/soapysdrinputsettings.h @@ -38,6 +38,7 @@ struct SoapySDRInputSettings { qint64 m_transverterDeltaFrequency; QString m_fileRecordName; QString m_antenna; + quint32 m_bandwidth; SoapySDRInputSettings(); void resetToDefaults(); diff --git a/sdrgui/soapygui/discreterangegui.ui b/sdrgui/soapygui/discreterangegui.ui index b8f36aff0..97f17c230 100644 --- a/sdrgui/soapygui/discreterangegui.ui +++ b/sdrgui/soapygui/discreterangegui.ui @@ -10,6 +10,18 @@ 30 + + + 0 + 0 + + + + + 0 + 30 + + Form diff --git a/sdrgui/soapygui/intervalrangegui.ui b/sdrgui/soapygui/intervalrangegui.ui index f7dc19a5e..7bf944db1 100644 --- a/sdrgui/soapygui/intervalrangegui.ui +++ b/sdrgui/soapygui/intervalrangegui.ui @@ -10,6 +10,18 @@ 30 + + + 0 + 0 + + + + + 0 + 30 + + Form