SoapySDR support: GUI component to deal with ranges with discrete values

This commit is contained in:
f4exb 2018-11-01 02:32:26 +01:00
parent 9c459ca336
commit cc08f42ea6
11 changed files with 340 additions and 76 deletions

View File

@ -46,9 +46,9 @@ void DeviceSoapySDRParams::fillParams()
}
}
void DeviceSoapySDRParams::fillChannelParams(std::vector<ChannelSetting>& channelSettings, int direction, unsigned int ichan)
void DeviceSoapySDRParams::fillChannelParams(std::vector<ChannelSettings>& channelSettings, int direction, unsigned int ichan)
{
channelSettings.push_back(ChannelSetting());
channelSettings.push_back(ChannelSettings());
channelSettings.back().m_streamSettingsArgs = m_device->getStreamArgsInfo(direction, ichan);
channelSettings.back().m_antennas = m_device->listAntennas(direction, ichan);
@ -114,7 +114,7 @@ void DeviceSoapySDRParams::printParams()
}
}
void DeviceSoapySDRParams::printChannelParams(const ChannelSetting& channelSetting)
void DeviceSoapySDRParams::printChannelParams(const ChannelSettings& channelSetting)
{
qDebug() << "DeviceSoapySDRParams::printParams: m_streamSettingsArgs:\n" << argInfoListToString(channelSetting.m_streamSettingsArgs).c_str();
qDebug() << "DeviceSoapySDRParams::printParams:"
@ -236,25 +236,27 @@ std::string DeviceSoapySDRParams::rangeToString(const SoapySDR::Range &range)
std::string DeviceSoapySDRParams::rangeListToString(const SoapySDR::RangeList &range, const double scale)
{
const std::size_t MAXRLEN = 10; //for abbreviating long lists
std::stringstream ss;
for (std::size_t i = 0; i < range.size(); i++)
{
if (range.size() >= MAXRLEN and i >= MAXRLEN/2 and i < (range.size()-MAXRLEN/2))
{
if (i == MAXRLEN) ss << ", ...";
continue;
}
if (not ss.str().empty()) {
ss << ", ";
}
if (range[i].minimum() == range[i].maximum()) {
if (range[i].minimum() == range[i].maximum())
{
ss << (range[i].minimum()/scale);
} else {
ss << "[" << (range[i].minimum()/scale) << ", " << (range[i].maximum()/scale) << "]";
}
else
{
ss << "[" << (range[i].minimum()/scale) << ", " << (range[i].maximum()/scale);
if (range[i].step() != 0.0) {
ss << ", " << (range[i].step()/scale);
}
ss << "]";
}
}

View File

@ -48,7 +48,7 @@ public:
SoapySDR::RangeList m_ranges; //!< List of ranges of the tunable element
};
struct ChannelSetting
struct ChannelSettings
{
SoapySDR::ArgInfoList m_streamSettingsArgs; //!< common stream parameters
bool m_hasDCAutoCorrection; //!< DC offset auto correction flag
@ -68,11 +68,29 @@ public:
DeviceSoapySDRParams(SoapySDR::Device *device);
~DeviceSoapySDRParams();
const ChannelSettings* getRxChannelSettings(uint32_t index)
{
if (index < m_nbRx) {
return &m_RxChannelsSettings[index];
} else {
return 0;
}
}
const ChannelSettings* getTxChannelSettings(uint32_t index)
{
if (index < m_nbTx) {
return &m_TxChannelsSettings[index];
} else {
return 0;
}
}
private:
void fillParams();
void fillChannelParams(std::vector<ChannelSetting>& channelSettings, int direction, unsigned int ichan);
void fillChannelParams(std::vector<ChannelSettings>& channelSettings, int direction, unsigned int ichan);
void printParams();
void printChannelParams(const ChannelSetting& channelSetting);
void printChannelParams(const ChannelSettings& channelSetting);
// Printing functions copied from SoapySDR's SoapySDRProbe.cpp
std::string argInfoToString(const SoapySDR::ArgInfo &argInfo, const std::string indent = " ");
@ -105,8 +123,8 @@ private:
SoapySDR::ArgInfoList m_deviceSettingsArgs; //!< list (vector) of device settings arguments
uint32_t m_nbRx; //!< number of Rx channels
uint32_t m_nbTx; //!< number of Tx channels
std::vector<ChannelSetting> m_RxChannelsSettings;
std::vector<ChannelSetting> m_TxChannelsSettings;
std::vector<ChannelSettings> m_RxChannelsSettings;
std::vector<ChannelSettings> m_TxChannelsSettings;
};

View File

@ -8,6 +8,7 @@ set(soapysdrinput_SOURCES
soapysdrinputplugin.cpp
soapysdrinputsettings.cpp
soapysdrinputthread.cpp
discreterangegui.cpp
)
set(soapysdrinput_HEADERS
@ -16,10 +17,12 @@ set(soapysdrinput_HEADERS
soapysdrinputplugin.h
soapysdrinputsettings.h
soapysdrinputthread.h
discreterangegui.h
)
set(soapysdrinput_FORMS
soapysdrinputgui.ui
discreterangegui.ui
)
if (BUILD_DEBIAN)

View File

@ -0,0 +1,59 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2018 Edouard Griffiths, F4EXB //
// //
// This program is free software; you can redistribute it and/or modify //
// it under the terms of the GNU General Public License as published by //
// the Free Software Foundation as version 3 of the License, or //
// //
// This program is distributed in the hope that it will be useful, //
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
// GNU General Public License V3 for more details. //
// //
// You should have received a copy of the GNU General Public License //
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#include "ui_discreterangegui.h"
#include "discreterangegui.h"
DiscreteRangeGUI::DiscreteRangeGUI(QWidget* parent) :
QWidget(parent),
ui(new Ui::DiscreteRangeGUI)
{
ui->setupUi(this);
}
DiscreteRangeGUI::~DiscreteRangeGUI()
{
delete ui;
}
void DiscreteRangeGUI::setLabel(const QString& text)
{
ui->rangeLabel->setText(text);
}
void DiscreteRangeGUI::setUnits(const QString& units)
{
ui->rangeUnits->setText(units);
}
void DiscreteRangeGUI::addItem(const QString& itemStr, double itemValue)
{
ui->rangeCombo->blockSignals(true);
ui->rangeCombo->addItem(itemStr);
itemValues.push_back(itemValue);
ui->rangeCombo->blockSignals(false);
}
double DiscreteRangeGUI::getCurrentValue()
{
return itemValues[ui->rangeCombo->currentIndex()];
}
void DiscreteRangeGUI::on_rangeCombo_currentIndexChanged(int index)
{
double newRange = itemValues[index];
emit rangeChanged(newRange);
}

View File

@ -0,0 +1,52 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2018 Edouard Griffiths, F4EXB //
// //
// This program is free software; you can redistribute it and/or modify //
// it under the terms of the GNU General Public License as published by //
// the Free Software Foundation as version 3 of the License, or //
// //
// This program is distributed in the hope that it will be useful, //
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
// GNU General Public License V3 for more details. //
// //
// You should have received a copy of the GNU General Public License //
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#ifndef PLUGINS_SAMPLESOURCE_SOAPYSDRINPUT_DISCRETERANGEGUI_H_
#define PLUGINS_SAMPLESOURCE_SOAPYSDRINPUT_DISCRETERANGEGUI_H_
#include <QWidget>
#include <QString>
namespace Ui {
class DiscreteRangeGUI;
}
class DiscreteRangeGUI : public QWidget
{
Q_OBJECT
public:
explicit DiscreteRangeGUI(QWidget* parent = 0);
~DiscreteRangeGUI();
void setLabel(const QString& text);
void setUnits(const QString& units);
void addItem(const QString& itemStr, double itemValue);
double getCurrentValue();
signals:
void rangeChanged(double value);
private slots:
void on_rangeCombo_currentIndexChanged(int index);
private:
Ui::DiscreteRangeGUI* ui;
std::vector<double> itemValues;
};
#endif /* PLUGINS_SAMPLESOURCE_SOAPYSDRINPUT_DISCRETERANGEGUI_H_ */

View File

@ -0,0 +1,48 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>DiscreteRangeGUI</class>
<widget class="QWidget" name="DiscreteRangeGUI">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>203</width>
<height>30</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<widget class="QWidget" name="horizontalLayoutWidget">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>172</width>
<height>29</height>
</rect>
</property>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QLabel" name="rangeLabel">
<property name="text">
<string>Label</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="rangeCombo"/>
</item>
<item>
<widget class="QLabel" name="rangeUnits">
<property name="text">
<string>Unit</string>
</property>
</widget>
</item>
</layout>
</widget>
</widget>
<resources/>
<connections/>
</ui>

View File

@ -157,6 +157,40 @@ void SoapySDRInput::closeDevice()
}
}
void SoapySDRInput::getFrequencyRange(uint64_t& min, uint64_t& max)
{
const DeviceSoapySDRParams::ChannelSettings* channelSettings = m_deviceShared.m_deviceParams->getRxChannelSettings(m_deviceShared.m_channel);
if (channelSettings && (channelSettings->m_frequencySettings.size() > 0))
{
DeviceSoapySDRParams::FrequencySetting freqSettings = channelSettings->m_frequencySettings[0];
SoapySDR::RangeList rangeList = freqSettings.m_ranges;
if (rangeList.size() > 0) // TODO: handle multiple ranges
{
SoapySDR::Range range = rangeList[0];
min = range.minimum();
max = range.maximum();
}
else
{
min = 0;
max = 0;
}
}
else
{
min = 0;
max = 0;
}
}
const SoapySDR::RangeList& SoapySDRInput::getRateRanges()
{
const DeviceSoapySDRParams::ChannelSettings* channelSettings = m_deviceShared.m_deviceParams->getRxChannelSettings(m_deviceShared.m_channel);
return channelSettings->m_ratesRanges;
}
void SoapySDRInput::init()
{
}

View File

@ -24,12 +24,37 @@
#include "soapysdr/devicesoapysdrshared.h"
#include "dsp/devicesamplesource.h"
#include "soapysdrinputsettings.h"
class DeviceSourceAPI;
class SoapySDRInputThread;
class SoapySDRInput : public DeviceSampleSource
{
public:
class MsgConfigureSoapySDR : public Message {
MESSAGE_CLASS_DECLARATION
public:
const SoapySDRInputSettings& getSettings() const { return m_settings; }
bool getForce() const { return m_force; }
static MsgConfigureSoapySDR* create(const SoapySDRInputSettings& settings, bool force)
{
return new MsgConfigureSoapySDR(settings, force);
}
private:
SoapySDRInputSettings m_settings;
bool m_force;
MsgConfigureSoapySDR(const SoapySDRInputSettings& settings, bool force) :
Message(),
m_settings(settings),
m_force(force)
{ }
};
SoapySDRInput(DeviceSourceAPI *deviceAPI);
virtual ~SoapySDRInput();
virtual void destroy();
@ -51,6 +76,9 @@ public:
virtual bool handleMessage(const Message& message);
void getFrequencyRange(uint64_t& min, uint64_t& max);
const SoapySDR::RangeList& getRateRanges();
private:
DeviceSourceAPI *m_deviceAPI;
DeviceSoapySDRShared m_deviceShared;

View File

@ -21,6 +21,7 @@
#include "util/simpleserializer.h"
#include "ui_soapysdrinputgui.h"
#include "discreterangegui.h"
#include "soapysdrinputgui.h"
SoapySDRInputGui::SoapySDRInputGui(DeviceUISet *deviceUISet, QWidget* parent) :
@ -36,7 +37,13 @@ SoapySDRInputGui::SoapySDRInputGui(DeviceUISet *deviceUISet, QWidget* parent) :
{
m_sampleSource = (SoapySDRInput*) m_deviceUISet->m_deviceSourceAPI->getSampleSource();
ui->setupUi(this);
ui->centerFrequency->setColorMapper(ColorMapper(ColorMapper::GrayGold));
uint64_t f_min, f_max;
m_sampleSource->getFrequencyRange(f_min, f_max);
ui->centerFrequency->setValueRange(7, f_min/1000, f_max/1000);
createRangesControl(m_sampleSource->getRateRanges(), "Sample Rate", "kS/s");
}
SoapySDRInputGui::~SoapySDRInputGui()
@ -49,6 +56,61 @@ void SoapySDRInputGui::destroy()
delete this;
}
void SoapySDRInputGui::createRangesControl(const SoapySDR::RangeList& rangeList, const QString& text, const QString& unit)
{
if (rangeList.size() == 0) { // return early if the range list is empty
return;
}
bool rangeDiscrete = true; // discretes values
bool rangeInterval = true; // intervals
for (const auto &it : rangeList)
{
if (it.minimum() != it.maximum()) {
rangeDiscrete = false;
} else {
rangeInterval = false;
}
}
if (rangeDiscrete)
{
DiscreteRangeGUI *rangeGUI = new DiscreteRangeGUI(ui->scrollAreaWidgetContents);
rangeGUI->setLabel(text);
rangeGUI->setUnits(unit);
for (const auto &it : rangeList) {
rangeGUI->addItem(QString("%1").arg(QString::number(it.minimum()/1000.0, 'f', 0)), it.minimum());
}
// 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);
}
}
void SoapySDRInputGui::setName(const QString& name)
{
setObjectName(name);

View File

@ -20,6 +20,8 @@
#include <QTimer>
#include <QWidget>
#include <SoapySDR/Types.hpp>
#include "plugin/plugininstancegui.h"
#include "util/messagequeue.h"
@ -51,6 +53,7 @@ public:
virtual bool handleMessage(const Message& message);
private:
void createRangesControl(const SoapySDR::RangeList& rangeList, const QString& text, const QString& unit);
Ui::SoapySDRInputGui* ui;
DeviceUISet* m_deviceUISet;

View File

@ -7,15 +7,9 @@
<x>0</x>
<y>0</y>
<width>324</width>
<height>276</height>
<height>176</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Maximum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>320</width>
@ -190,15 +184,9 @@
<x>0</x>
<y>0</y>
<width>304</width>
<height>128</height>
<height>120</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<layout class="QVBoxLayout" name="verticalLayout_3">
<property name="spacing">
<number>3</number>
@ -314,6 +302,17 @@
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QLabel" name="label">
<property name="text">
<string>Tata</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_7">
<item>
@ -341,54 +340,10 @@
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_8">
<item>
<widget class="QLabel" name="label">
<property name="text">
<string>Didi</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="comboBox_3"/>
</item>
<item>
<spacer name="horizontalSpacer_4">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
</layout>
</widget>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="paddingLayout">
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
</layout>
</widget>
<customwidgets>