SoapySDR support: input: bandwidth selection GUI

This commit is contained in:
f4exb 2018-11-05 02:19:40 +01:00
parent bf3fdcbfc2
commit 0d0b8c9618
14 changed files with 176 additions and 53 deletions

View File

@ -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<<settings.m_log2Interp);

View File

@ -25,6 +25,7 @@
#include "gui/glspectrum.h"
#include "soapygui/discreterangegui.h"
#include "soapygui/intervalrangegui.h"
#include "soapygui/stringrangegui.h"
#include "soapysdroutputgui.h"
@ -46,6 +47,7 @@ SoapySDROutputGui::SoapySDROutputGui(DeviceUISet *deviceUISet, QWidget* parent)
m_sampleSink->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<std::string>& 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;

View File

@ -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<std::string>& 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);

View File

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

View File

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

View File

@ -203,16 +203,22 @@ void SoapySDRInput::getFrequencyRange(uint64_t& min, uint64_t& max)
}
}
const std::vector<std::string>& 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<std::string>& 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<<settings.m_log2Decim);
@ -829,7 +855,8 @@ bool SoapySDRInput::applySettings(const SoapySDRInputSettings& settings, bool fo
<< " m_devSampleRate: " << m_settings.m_devSampleRate
<< " m_dcBlock: " << m_settings.m_dcBlock
<< " m_iqCorrection: " << m_settings.m_iqCorrection
<< " m_antenna: " << m_settings.m_antenna;
<< " m_antenna: " << m_settings.m_antenna
<< " m_bandwidth: " << m_settings.m_bandwidth;
return true;
}

View File

@ -121,8 +121,9 @@ public:
virtual bool handleMessage(const Message& message);
void getFrequencyRange(uint64_t& min, uint64_t& max);
const SoapySDR::RangeList& getRateRanges();
const std::vector<std::string>& getAntennas();
const SoapySDR::RangeList& getRateRanges();
const SoapySDR::RangeList& getBandwidthRanges();
int getAntennaIndex(const std::string& antenna);
private:

View File

@ -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<std::string>& 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);
}

View File

@ -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<std::string>& 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);

View File

@ -374,6 +374,9 @@
</item>
<item>
<widget class="QScrollArea" name="scrollArea">
<property name="verticalScrollBarPolicy">
<enum>Qt::ScrollBarAlwaysOn</enum>
</property>
<property name="widgetResizable">
<bool>true</bool>
</property>
@ -382,7 +385,7 @@
<rect>
<x>0</x>
<y>0</y>
<width>318</width>
<width>304</width>
<height>51</height>
</rect>
</property>

View File

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

View File

@ -38,6 +38,7 @@ struct SoapySDRInputSettings {
qint64 m_transverterDeltaFrequency;
QString m_fileRecordName;
QString m_antenna;
quint32 m_bandwidth;
SoapySDRInputSettings();
void resetToDefaults();

View File

@ -10,6 +10,18 @@
<height>30</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>0</width>
<height>30</height>
</size>
</property>
<property name="windowTitle">
<string>Form</string>
</property>

View File

@ -10,6 +10,18 @@
<height>30</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>0</width>
<height>30</height>
</size>
</property>
<property name="windowTitle">
<string>Form</string>
</property>