1
0
mirror of https://github.com/f4exb/sdrangel.git synced 2026-06-03 06:24:48 -04:00

Add USRP device support.

This commit is contained in:
Jon Beniston
2020-10-02 22:45:28 +01:00
parent ad55211abb
commit d4aa5d75b5
427 changed files with 10621 additions and 378 deletions
+4
View File
@@ -58,4 +58,8 @@ if(ENABLE_SOAPYSDR AND SOAPYSDR_FOUND)
add_subdirectory(soapysdrinput)
endif()
if(ENABLE_USRP AND UHD_FOUND)
add_subdirectory(usrpinput)
endif()
add_subdirectory(kiwisdr)
@@ -0,0 +1,70 @@
if(WIN32)
link_directories(${BOOST_LIBRARYDIR})
endif()
project(usrpinput)
set(usrpinput_SOURCES
usrpinput.cpp
usrpinputplugin.cpp
usrpinputsettings.cpp
usrpinputwebapiadapter.cpp
usrpinputthread.cpp
)
set(usrpinput_HEADERS
usrpinput.h
usrpinputplugin.h
usrpinputsettings.h
usrpinputwebapiadapter.h
usrpinputthread.h
)
include_directories(
${CMAKE_SOURCE_DIR}/swagger/sdrangel/code/qt5/client
${CMAKE_SOURCE_DIR}/devices
${UHD_INCLUDE_DIR}
${Boost_INCLUDE_DIRS}
)
if(NOT SERVER_MODE)
set(usrpinput_SOURCES
${usrpinput_SOURCES}
usrpinputgui.cpp
usrpinputgui.ui
)
set(usrpinput_HEADERS
${usrpinput_HEADERS}
usrpinputgui.h
)
set(TARGET_NAME inputlusrp)
set(TARGET_LIB "Qt5::Widgets")
set(TARGET_LIB_GUI "sdrgui")
set(INSTALL_FOLDER ${INSTALL_PLUGINS_DIR})
else()
set(TARGET_NAME inputlusrpsrv)
set(TARGET_LIB "")
set(TARGET_LIB_GUI "")
set(INSTALL_FOLDER ${INSTALL_PLUGINSSRV_DIR})
endif()
add_library(${TARGET_NAME} SHARED
${usrpinput_SOURCES}
)
if(UHD_EXTERNAL)
add_dependencies(${TARGET_NAME} uhd)
endif()
target_link_libraries(${TARGET_NAME}
Qt5::Core
${TARGET_LIB}
sdrbase
${TARGET_LIB_GUI}
swagger
${UHD_LIBRARIES}
usrpdevice
)
install(TARGETS ${TARGET_NAME} DESTINATION ${INSTALL_FOLDER})
+130
View File
@@ -0,0 +1,130 @@
<h1>USRP input plugin</h1>
<h2>Introduction</h2>
This input sample source plugin gets its samples from a [USRP device](https://www.ettus.com/product-categories/usrp-bus-series/).
<h2>Interface</h2>
![USRP input plugin GUI](../../../doc/img/USRPInput_plugin.png)
<h3>1: Start/Stop</h3>
Device start / stop button.
- Blue triangle icon: device is ready and can be started
- Green square icon: device is running and can be stopped
- Magenta (or pink) square icon: an error occurred. In the case the device was accidentally disconnected you may click on the icon to stop, plug back in, check the source on the sampling devices control panel and start again.
<h3>2A: Sample rate</h3>
This is the sample rate at which IQ samples are transfered the device to SDRangel, in kS/s (k) or MS/s (M).
<h3>2B: Stream sample rate</h3>
In host to device sample rate input mode (8A) this is the baseband I/Q sample rate in kS/s. This is the host to device sample rate (10) divided by the software interpolation factor (9).
In baseband sample rate input mode (8A) this is the host to device sample rate in kS/s. This is the baseband sample rate (10) multiplied by the software interpolation factor (9)
<h3>3: Center frequency</h3>
This is the center frequency of reception in kHz.
<h3>3A: Center frequency units</h3>
This is the center frequency units thus kHz (fixed)
<h3>4: Channel number</h3>
USRP can support 2x2 MIMO device so it has two receiving channels. This shows the corresponding Rx channel index (0 or 1).
<h3>5: Antenna selection</h3>
Select the antenna to use. The supported antennas will depend upon the USRP device, but may include "TX/RX" and "RX2".
<h3>6: Transverter mode open dialog</h3>
This button opens a dialog to set the transverter mode frequency translation options:
![USRP source input stream transverter dialog](../../../doc/img/RTLSDR_plugin_xvrt.png)
Note that if you mouse over the button a tooltip appears that displays the translating frequency and if translation is enabled or disabled. When the frequency translation is enabled the button is lit.
<h4>7.1: Translating frequency</h4>
You can set the translating frequency in Hz with this dial. Use the wheels to adjust the sample rate. Left click on a digit sets the cursor position at this digit. Right click on a digit sets all digits on the right to zero. This effectively floors value at the digit position. Wheels are moved with the mousewheel while pointing at the wheel or by selecting the wheel with the left mouse click and using the keyboard arrows. Pressing shift simultaneously moves digit by 5 and pressing control moves it by 2.
The frequency set in the device is the frequency on the main dial (1) minus this frequency. Thus it is positive for down converters and negative for up converters.
For example a mixer at 120 MHz for HF operation you would set the value to -120,000,000 Hz so that if the main dial frequency is set at 7,130 kHz the PlutoSDR will be set to 127.130 MHz.
If you use a down converter to receive the 6 cm band narrowband center frequency of 5670 MHz at 432 MHz you would set the translating frequency to 5760 - 432 = 5328 MHz thus dial +5,328,000,000 Hz.
For bands even higher in the frequency spectrum the GHz digits are not really significant so you can have them set at 1 GHz. Thus to receive the 10368 MHz frequency at 432 MHz you would set the translating frequency to 1368 - 432 = 936 MHz. Note that in this case the frequency of the LO used in the mixer of the transverter is set at 9936 MHz.
The Hz precision allows a fine tuning of the transverter LO offset
<h4>7.2: Translating frequency enable/disable</h4>
Use this toggle button to activate or deactivate the frequency translation
<h4>7.3: Confirmation buttons</h4>
Use these buttons to confirm ("OK") or dismiss ("Cancel") your changes.
<h3>7: Clock source</h3>
Use this combo box to select the clock source for the device, such as "internal", "external" or "gpsdo". The available choices will depend upon the USRP device. If a selected clock is not detected, it will be reset back to "internal".
<h3>8: Sample rate</h3>
This is the device to/from host stream sample rate or baseband sample rate in samples per second (S/s). The control (8A) is used to switch between the two input modes. The device to/from host stream sample rate is the same for the Rx and Tx systems.
The limits are adjusted automatically. In baseband input mode the limits are driven by the software interpolation factor (9). You may need to increase this interpolation factor to be able to reach lower values.
This is the device to/from host stream sample rate in S/s. It is the same for the Rx and Tx systems.
Use the wheels to adjust the sample rate. 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. 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.
<h3>8A: Host to device sample rate / Baseband sample rate input toggle</h3>
Use this toggle button to switch the sample rate input next (8) between host to device sample rate and baseband sample rate input. The button shows the current mode:
- **SR**: device to host sample rate input mode. The baseband sample rate (2B) is the device to host sample rate (10) divided by the software interpolation factor (9).
- **BB**: baseband sample rate input mode. The device to host sample rate (2A) is the baseband sample rate (10) multiplied by the software interpolation factor (9).
<h3>9: Software decimation factor</h3>
The I/Q stream from the USRP device can be decimated by a power of two by software inside the plugin before being sent to the baseband. Possible values are increasing powers of two: 1 (no decimation), 2, 4, 8, 16, 32.
<h3>10: Gain Mode</h2>
Choose between automatic or manual gain control.
<h3>11: Gain</h2>
Use this slider to adjust the global gain of the Rx chain. The allowable values of gain depend upon the USRP device. The value in dB appears at the right of the slider.
<h3>12: DC offset correction</h2>
Check this button to enable DC offset correction.
<h3>13: IQ imbalance correction</h2>
Check this button to enable IQ imbalance correction.
<h3>14: Rx hardware filter bandwidth</h3>
This is the Rx hardware IF filter bandwidth in kHz for the given channel. Use the wheels to adjust the value. Pressing shift simultaneously moves digit by 5 and pressing control moves it by 2.
<h3>15: Stream status indicator</h3>
This label turns green when data is being received from the device.
<h3>16: Stream warning indicators</h3>
- **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.
File diff suppressed because it is too large Load Diff
+250
View File
@@ -0,0 +1,250 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2017 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 <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#ifndef PLUGINS_SAMPLESOURCE_USRPINPUT_USRPINPUT_H_
#define PLUGINS_SAMPLESOURCE_USRPINPUT_USRPINPUT_H_
#include <stdint.h>
#include <QString>
#include <QByteArray>
#include <QNetworkRequest>
#include <uhd/usrp/multi_usrp.hpp>
#include "dsp/devicesamplesource.h"
#include "usrp/deviceusrpshared.h"
#include "usrpinputsettings.h"
class DeviceAPI;
class USRPInputThread;
class QNetworkAccessManager;
class QNetworkReply;
class USRPInput : public DeviceSampleSource
{
Q_OBJECT
public:
class MsgConfigureUSRP : public Message {
MESSAGE_CLASS_DECLARATION
public:
const USRPInputSettings& getSettings() const { return m_settings; }
bool getForce() const { return m_force; }
static MsgConfigureUSRP* create(const USRPInputSettings& settings, bool force)
{
return new MsgConfigureUSRP(settings, force);
}
private:
USRPInputSettings m_settings;
bool m_force;
MsgConfigureUSRP(const USRPInputSettings& settings, bool force) :
Message(),
m_settings(settings),
m_force(force)
{ }
};
class MsgGetStreamInfo : public Message {
MESSAGE_CLASS_DECLARATION
public:
static MsgGetStreamInfo* create()
{
return new MsgGetStreamInfo();
}
private:
MsgGetStreamInfo() :
Message()
{ }
};
class MsgGetDeviceInfo : public Message {
MESSAGE_CLASS_DECLARATION
public:
static MsgGetDeviceInfo* create()
{
return new MsgGetDeviceInfo();
}
private:
MsgGetDeviceInfo() :
Message()
{ }
};
class MsgReportStreamInfo : public Message {
MESSAGE_CLASS_DECLARATION
public:
bool getSuccess() const { return m_success; }
bool getActive() const { return m_active; }
uint32_t getOverruns() const { return m_overruns; }
uint32_t getTimeouts() const { return m_timeouts; }
static MsgReportStreamInfo* create(
bool success,
bool active,
uint32_t overruns,
uint32_t timeouts
)
{
return new MsgReportStreamInfo(
success,
active,
overruns,
timeouts
);
}
private:
bool m_success;
bool m_active;
uint32_t m_overruns; //!< FIFO overrun count
uint32_t m_timeouts; //!< Number of dropped packets by HW
MsgReportStreamInfo(
bool success,
bool active,
uint32_t overruns,
uint32_t timeouts
) :
Message(),
m_success(success),
m_active(active),
m_overruns(overruns),
m_timeouts(timeouts)
{ }
};
class MsgStartStop : public Message {
MESSAGE_CLASS_DECLARATION
public:
bool getStartStop() const { return m_startStop; }
static MsgStartStop* create(bool startStop) {
return new MsgStartStop(startStop);
}
protected:
bool m_startStop;
MsgStartStop(bool startStop) :
Message(),
m_startStop(startStop)
{ }
};
USRPInput(DeviceAPI *deviceAPI);
virtual ~USRPInput();
virtual void destroy();
virtual void init();
virtual bool start();
virtual void stop();
virtual QByteArray serialize() const;
virtual bool deserialize(const QByteArray& data);
virtual void setMessageQueueToGUI(MessageQueue *queue) { m_guiMessageQueue = queue; }
virtual const QString& getDeviceDescription() const;
virtual int getSampleRate() const;
virtual void setSampleRate(int sampleRate) { (void) sampleRate; }
virtual quint64 getCenterFrequency() const;
virtual void setCenterFrequency(qint64 centerFrequency);
virtual bool handleMessage(const Message& message);
virtual int webapiSettingsGet(
SWGSDRangel::SWGDeviceSettings& response,
QString& errorMessage);
virtual int webapiSettingsPutPatch(
bool force,
const QStringList& deviceSettingsKeys,
SWGSDRangel::SWGDeviceSettings& response, // query + response
QString& errorMessage);
virtual int webapiReportGet(
SWGSDRangel::SWGDeviceReport& response,
QString& errorMessage);
virtual int webapiRunGet(
SWGSDRangel::SWGDeviceState& response,
QString& errorMessage);
virtual int webapiRun(
bool run,
SWGSDRangel::SWGDeviceState& response,
QString& errorMessage);
static void webapiFormatDeviceSettings(
SWGSDRangel::SWGDeviceSettings& response,
const USRPInputSettings& settings);
static void webapiUpdateDeviceSettings(
USRPInputSettings& settings,
const QStringList& deviceSettingsKeys,
SWGSDRangel::SWGDeviceSettings& response);
std::size_t getChannelIndex();
void getLORange(float& minF, float& maxF) const;
void getSRRange(float& minF, float& maxF) const;
void getLPRange(float& minF, float& maxF) const;
void getGainRange(float& minF, float& maxF) const;
QStringList getRxAntennas() const;
QStringList getRxGainNames() const;
QStringList getClockSources() const;
private:
DeviceAPI *m_deviceAPI;
QMutex m_mutex;
USRPInputSettings m_settings;
USRPInputThread* m_usrpInputThread;
QString m_deviceDescription;
bool m_running;
DeviceUSRPShared m_deviceShared;
bool m_channelAcquired;
uhd::rx_streamer::sptr m_streamId;
QNetworkAccessManager *m_networkManager;
QNetworkRequest m_networkRequest;
bool openDevice();
void closeDevice();
bool acquireChannel();
void releaseChannel();
void suspendRxBuddies();
void resumeRxBuddies();
void suspendTxBuddies();
void resumeTxBuddies();
bool applySettings(const USRPInputSettings& settings, bool force = false);
void webapiFormatDeviceReport(SWGSDRangel::SWGDeviceReport& response);
void webapiReverseSendSettings(QList<QString>& deviceSettingsKeys, const USRPInputSettings& settings, bool force);
void webapiReverseSendStartStop(bool start);
private slots:
void networkManagerFinished(QNetworkReply *reply);
};
#endif /* PLUGINS_SAMPLESOURCE_USRPINPUT_USRPINPUT_H_ */
@@ -0,0 +1,598 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2017 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 <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#include "usrpinputgui.h"
#include <QDebug>
#include <QMessageBox>
#include <QFileDialog>
#include <algorithm>
#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"
#include "device/deviceapi.h"
#include "device/deviceuiset.h"
USRPInputGUI::USRPInputGUI(DeviceUISet *deviceUISet, QWidget* parent) :
QWidget(parent),
ui(new Ui::USRPInputGUI),
m_deviceUISet(deviceUISet),
m_settings(),
m_sampleRateMode(true),
m_sampleRate(0),
m_lastEngineState(DeviceAPI::StNotStarted),
m_doApplySettings(true),
m_forceSettings(true),
m_statusCounter(0),
m_deviceStatusCounter(0)
{
m_usrpInput = (USRPInput*) m_deviceUISet->m_deviceAPI->getSampleSource();
ui->setupUi(this);
float minF, maxF;
m_usrpInput->getLORange(minF, maxF);
ui->centerFrequency->setColorMapper(ColorMapper(ColorMapper::GrayGold));
ui->centerFrequency->setValueRange(7, ((uint32_t) minF)/1000, ((uint32_t) maxF)/1000); // frequency dial is in kHz
m_usrpInput->getSRRange(minF, maxF);
ui->sampleRate->setColorMapper(ColorMapper(ColorMapper::GrayGreenYellow));
ui->sampleRate->setValueRange(8, (uint32_t) minF, (uint32_t) maxF);
m_usrpInput->getLPRange(minF, maxF);
ui->lpf->setColorMapper(ColorMapper(ColorMapper::GrayYellow));
ui->lpf->setValueRange(5, (minF/1000)+1, maxF/1000);
m_usrpInput->getGainRange(minF, maxF);
ui->gain->setRange((int)minF, (int)maxF);
ui->channelNumberText->setText(tr("#%1").arg(m_usrpInput->getChannelIndex()));
ui->antenna->addItems(m_usrpInput->getRxAntennas());
ui->clockSource->addItems(m_usrpInput->getClockSources());
connect(&m_updateTimer, SIGNAL(timeout()), this, SLOT(updateHardware()));
connect(&m_statusTimer, SIGNAL(timeout()), this, SLOT(updateStatus()));
m_statusTimer.start(500);
displaySettings();
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 &)));
}
USRPInputGUI::~USRPInputGUI()
{
delete ui;
}
void USRPInputGUI::destroy()
{
delete this;
}
void USRPInputGUI::setName(const QString& name)
{
setObjectName(name);
}
QString USRPInputGUI::getName() const
{
return objectName();
}
void USRPInputGUI::resetToDefaults()
{
m_settings.resetToDefaults();
displaySettings();
sendSettings();
}
qint64 USRPInputGUI::getCenterFrequency() const
{
return m_settings.m_centerFrequency;
}
void USRPInputGUI::setCenterFrequency(qint64 centerFrequency)
{
m_settings.m_centerFrequency = centerFrequency;
displaySettings();
sendSettings();
}
QByteArray USRPInputGUI::serialize() const
{
return m_settings.serialize();
}
bool USRPInputGUI::deserialize(const QByteArray& data)
{
if (m_settings.deserialize(data))
{
displaySettings();
m_forceSettings = true;
sendSettings();
return true;
}
else
{
resetToDefaults();
return false;
}
}
bool USRPInputGUI::handleMessage(const Message& message)
{
if (USRPInput::MsgConfigureUSRP::match(message))
{
const USRPInput::MsgConfigureUSRP& cfg = (USRPInput::MsgConfigureUSRP&) message;
m_settings = cfg.getSettings();
blockApplySettings(true);
displaySettings();
blockApplySettings(false);
return true;
}
else if (DeviceUSRPShared::MsgReportBuddyChange::match(message))
{
DeviceUSRPShared::MsgReportBuddyChange& report = (DeviceUSRPShared::MsgReportBuddyChange&) message;
m_settings.m_devSampleRate = report.getDevSampleRate();
if (report.getRxElseTx()) {
m_settings.m_centerFrequency = report.getCenterFrequency();
}
blockApplySettings(true);
displaySettings();
blockApplySettings(false);
return true;
}
else if (DeviceUSRPShared::MsgReportClockSourceChange::match(message))
{
qDebug("USRPInputGUI::handleMessage MsgReportClockSourceChange");
DeviceUSRPShared::MsgReportClockSourceChange& report = (DeviceUSRPShared::MsgReportClockSourceChange&) message;
m_settings.m_clockSource = report.getClockSource();
blockApplySettings(true);
ui->clockSource->setCurrentIndex(ui->clockSource->findText(m_settings.m_clockSource));
blockApplySettings(false);
return true;
}
else if (USRPInput::MsgReportStreamInfo::match(message))
{
USRPInput::MsgReportStreamInfo& report = (USRPInput::MsgReportStreamInfo&) message;
if (report.getSuccess())
{
if (report.getActive()) {
ui->streamStatusLabel->setStyleSheet("QLabel { background-color : green; }");
} else {
ui->streamStatusLabel->setStyleSheet("QLabel { background-color : blue; }");
}
if (report.getOverruns() > 0) {
ui->overrunLabel->setStyleSheet("QLabel { background-color : red; }");
} else {
ui->overrunLabel->setStyleSheet("QLabel { background:rgb(79,79,79); }");
}
if (report.getTimeouts() > 0) {
ui->timeoutLabel->setStyleSheet("QLabel { background-color : red; }");
} else {
ui->timeoutLabel->setStyleSheet("QLabel { background:rgb(79,79,79); }");
}
}
else
{
ui->streamStatusLabel->setStyleSheet("QLabel { background:rgb(79,79,79); }");
}
return true;
}
else if (USRPInput::MsgStartStop::match(message))
{
USRPInput::MsgStartStop& notif = (USRPInput::MsgStartStop&) message;
blockApplySettings(true);
ui->startStop->setChecked(notif.getStartStop());
blockApplySettings(false);
return true;
}
else
{
return false;
}
}
void USRPInputGUI::updateFrequencyLimits()
{
// values in kHz
float minF, maxF;
qint64 deltaFrequency = m_settings.m_transverterMode ? m_settings.m_transverterDeltaFrequency/1000 : 0;
m_usrpInput->getLORange(minF, maxF);
qint64 minLimit = minF/1000 + deltaFrequency;
qint64 maxLimit = maxF/1000 + deltaFrequency;
minLimit = minLimit < 0 ? 0 : minLimit > 9999999 ? 9999999 : minLimit;
maxLimit = maxLimit < 0 ? 0 : maxLimit > 9999999 ? 9999999 : maxLimit;
qDebug("USRPInputGUI::updateFrequencyLimits: delta: %lld min: %lld max: %lld", deltaFrequency, minLimit, maxLimit);
ui->centerFrequency->setValueRange(7, minLimit, maxLimit);
}
void USRPInputGUI::handleInputMessages()
{
Message* message;
while ((message = m_inputMessageQueue.pop()) != 0)
{
if (DSPSignalNotification::match(*message))
{
DSPSignalNotification* notif = (DSPSignalNotification*) message;
m_sampleRate = notif->getSampleRate();
m_deviceCenterFrequency = notif->getCenterFrequency();
qDebug("USRPInputGUI::handleInputMessages: DSPSignalNotification: SampleRate: %d, CenterFrequency: %llu", notif->getSampleRate(), notif->getCenterFrequency());
updateSampleRateAndFrequency();
delete message;
}
else if (USRPInput::MsgConfigureUSRP::match(*message))
{
const USRPInput::MsgConfigureUSRP& cfg = (USRPInput::MsgConfigureUSRP&) *message;
m_settings = cfg.getSettings();
displaySettings();
delete message;
}
else
{
if (handleMessage(*message)) {
delete message;
}
}
}
}
void USRPInputGUI::updateSampleRate()
{
uint32_t sr = m_settings.m_devSampleRate;
if (sr < 100000000) {
ui->sampleRateLabel->setText(tr("%1k").arg(QString::number(sr / 1000.0f, 'g', 5)));
} else {
ui->sampleRateLabel->setText(tr("%1M").arg(QString::number(sr / 1000000.0f, 'g', 5)));
}
}
void USRPInputGUI::updateSampleRateAndFrequency()
{
m_deviceUISet->getSpectrum()->setSampleRate(m_sampleRate);
m_deviceUISet->getSpectrum()->setCenterFrequency(m_deviceCenterFrequency);
displaySampleRate();
}
void USRPInputGUI::displaySampleRate()
{
float minF, maxF;
m_usrpInput->getSRRange(minF, maxF);
ui->sampleRate->blockSignals(true);
if (m_sampleRateMode)
{
ui->sampleRateMode->setStyleSheet("QToolButton { background:rgb(60,60,60); }");
ui->sampleRateMode->setText("SR");
ui->sampleRate->setValueRange(8, (uint32_t) minF, (uint32_t) maxF);
ui->sampleRate->setValue(m_settings.m_devSampleRate);
ui->sampleRate->setToolTip("Device to host sample rate (S/s)");
ui->deviceRateText->setToolTip("Baseband sample rate (S/s)");
uint32_t basebandSampleRate = m_settings.m_devSampleRate/(1<<m_settings.m_log2SoftDecim);
ui->deviceRateText->setText(tr("%1k").arg(QString::number(basebandSampleRate / 1000.0f, 'g', 5)));
}
else
{
ui->sampleRateMode->setStyleSheet("QToolButton { background:rgb(50,50,50); }");
ui->sampleRateMode->setText("BB");
ui->sampleRate->setValueRange(8, (uint32_t) minF/(1<<m_settings.m_log2SoftDecim), (uint32_t) maxF/(1<<m_settings.m_log2SoftDecim));
ui->sampleRate->setValue(m_settings.m_devSampleRate/(1<<m_settings.m_log2SoftDecim));
ui->sampleRate->setToolTip("Baseband sample rate (S/s)");
ui->deviceRateText->setToolTip("Device to host sample rate (S/s)");
ui->deviceRateText->setText(tr("%1k").arg(QString::number(m_settings.m_devSampleRate / 1000.0f, 'g', 5)));
}
ui->sampleRate->blockSignals(false);
}
void USRPInputGUI::displaySettings()
{
ui->transverter->setDeltaFrequency(m_settings.m_transverterDeltaFrequency);
ui->transverter->setDeltaFrequencyActive(m_settings.m_transverterMode);
ui->clockSource->setCurrentIndex(ui->clockSource->findText(m_settings.m_clockSource));
updateFrequencyLimits();
setCenterFrequencyDisplay();
displaySampleRate();
ui->dcOffset->setChecked(m_settings.m_dcBlock);
ui->iqImbalance->setChecked(m_settings.m_iqCorrection);
ui->swDecim->setCurrentIndex(m_settings.m_log2SoftDecim);
updateSampleRate();
ui->lpf->setValue(m_settings.m_lpfBW / 1000);
ui->gain->setValue(m_settings.m_gain);
ui->gainText->setText(tr("%1").arg(m_settings.m_gain));
ui->antenna->setCurrentIndex(ui->antenna->findText(m_settings.m_antennaPath));
ui->gainMode->setCurrentIndex((int) m_settings.m_gainMode);
if (m_settings.m_gainMode == USRPInputSettings::GAIN_AUTO)
{
ui->gain->setEnabled(false);
}
else
{
ui->gain->setEnabled(true);
}
}
void USRPInputGUI::setCenterFrequencyDisplay()
{
int64_t centerFrequency = m_settings.m_centerFrequency;
ui->centerFrequency->setToolTip(QString("Main center frequency in kHz (LO: %1 kHz)").arg(centerFrequency/1000));
ui->centerFrequency->blockSignals(true);
ui->centerFrequency->setValue(centerFrequency < 0 ? 0 : (uint64_t) centerFrequency/1000); // kHz
ui->centerFrequency->blockSignals(false);
}
void USRPInputGUI::setCenterFrequencySetting(uint64_t kHzValue)
{
int64_t centerFrequency = kHzValue*1000;
m_settings.m_centerFrequency = centerFrequency < 0 ? 0 : (uint64_t) centerFrequency;
ui->centerFrequency->setToolTip(QString("Main center frequency in kHz (LO: %1 kHz)").arg(centerFrequency/1000));
}
void USRPInputGUI::sendSettings()
{
if(!m_updateTimer.isActive())
m_updateTimer.start(100);
}
void USRPInputGUI::updateHardware()
{
if (m_doApplySettings)
{
qDebug() << "USRPInputGUI::updateHardware";
USRPInput::MsgConfigureUSRP* message = USRPInput::MsgConfigureUSRP::create(m_settings, m_forceSettings);
m_usrpInput->getInputMessageQueue()->push(message);
m_forceSettings = false;
m_updateTimer.stop();
}
}
void USRPInputGUI::updateStatus()
{
int state = m_deviceUISet->m_deviceAPI->state();
if(m_lastEngineState != state)
{
switch(state)
{
case DeviceAPI::StNotStarted:
ui->startStop->setStyleSheet("QToolButton { background:rgb(79,79,79); }");
break;
case DeviceAPI::StIdle:
ui->startStop->setStyleSheet("QToolButton { background-color : blue; }");
break;
case DeviceAPI::StRunning:
ui->startStop->setStyleSheet("QToolButton { background-color : green; }");
break;
case DeviceAPI::StError:
ui->startStop->setStyleSheet("QToolButton { background-color : red; }");
QMessageBox::information(this, tr("Message"), m_deviceUISet->m_deviceAPI->errorMessage());
break;
default:
break;
}
m_lastEngineState = state;
}
if (m_statusCounter < 1)
{
m_statusCounter++;
}
else
{
USRPInput::MsgGetStreamInfo* message = USRPInput::MsgGetStreamInfo::create();
m_usrpInput->getInputMessageQueue()->push(message);
m_statusCounter = 0;
}
if (m_deviceStatusCounter < 10)
{
m_deviceStatusCounter++;
}
else
{
if (m_deviceUISet->m_deviceAPI->isBuddyLeader())
{
USRPInput::MsgGetDeviceInfo* message = USRPInput::MsgGetDeviceInfo::create();
m_usrpInput->getInputMessageQueue()->push(message);
}
m_deviceStatusCounter = 0;
}
}
void USRPInputGUI::blockApplySettings(bool block)
{
m_doApplySettings = !block;
}
void USRPInputGUI::on_startStop_toggled(bool checked)
{
if (m_doApplySettings)
{
USRPInput::MsgStartStop *message = USRPInput::MsgStartStop::create(checked);
m_usrpInput->getInputMessageQueue()->push(message);
}
}
void USRPInputGUI::on_centerFrequency_changed(quint64 value)
{
setCenterFrequencySetting(value);
sendSettings();
}
void USRPInputGUI::on_dcOffset_toggled(bool checked)
{
m_settings.m_dcBlock = checked;
sendSettings();
}
void USRPInputGUI::on_iqImbalance_toggled(bool checked)
{
m_settings.m_iqCorrection = checked;
sendSettings();
}
void USRPInputGUI::on_sampleRate_changed(quint64 value)
{
if (m_sampleRateMode) {
m_settings.m_devSampleRate = value;
} else {
m_settings.m_devSampleRate = value * (1 << m_settings.m_log2SoftDecim);
}
updateSampleRate();
sendSettings();
}
void USRPInputGUI::on_swDecim_currentIndexChanged(int index)
{
if ((index <0) || (index > 6)) {
return;
}
m_settings.m_log2SoftDecim = index;
displaySampleRate();
if (m_sampleRateMode) {
m_settings.m_devSampleRate = ui->sampleRate->getValueNew();
} else {
m_settings.m_devSampleRate = ui->sampleRate->getValueNew() * (1 << m_settings.m_log2SoftDecim);
}
sendSettings();
}
void USRPInputGUI::on_lpf_changed(quint64 value)
{
m_settings.m_lpfBW = value * 1000;
sendSettings();
}
void USRPInputGUI::on_gainMode_currentIndexChanged(int index)
{
m_settings.m_gainMode = (USRPInputSettings::GainMode) index;
if (index == 0)
{
ui->gain->setEnabled(false);
}
else
{
ui->gain->setEnabled(true);
}
sendSettings();
}
void USRPInputGUI::on_gain_valueChanged(int value)
{
m_settings.m_gain = value;
ui->gainText->setText(tr("%1").arg(m_settings.m_gain));
sendSettings();
}
void USRPInputGUI::on_antenna_currentIndexChanged(int index)
{
m_settings.m_antennaPath = ui->antenna->currentText();
sendSettings();
}
void USRPInputGUI::on_clockSource_currentIndexChanged(int index)
{
m_settings.m_clockSource = ui->clockSource->currentText();
sendSettings();
}
void USRPInputGUI::on_transverter_clicked()
{
m_settings.m_transverterMode = ui->transverter->getDeltaFrequencyAcive();
m_settings.m_transverterDeltaFrequency = ui->transverter->getDeltaFrequency();
qDebug("USRPInputGUI::on_transverter_clicked: %lld Hz %s", m_settings.m_transverterDeltaFrequency, m_settings.m_transverterMode ? "on" : "off");
updateFrequencyLimits();
setCenterFrequencySetting(ui->centerFrequency->getValueNew());
sendSettings();
}
void USRPInputGUI::on_sampleRateMode_toggled(bool checked)
{
m_sampleRateMode = checked;
displaySampleRate();
}
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);
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();
}
@@ -0,0 +1,104 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2017 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 <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#ifndef PLUGINS_SAMPLESOURCE_USRPINPUT_USRPINPUTGUI_H_
#define PLUGINS_SAMPLESOURCE_USRPINPUT_USRPINPUTGUI_H_
#include <plugin/plugininstancegui.h>
#include <QTimer>
#include <QWidget>
#include "util/messagequeue.h"
#include "usrpinput.h"
class DeviceUISet;
namespace Ui {
class USRPInputGUI;
}
class USRPInputGUI : public QWidget, public PluginInstanceGUI {
Q_OBJECT
public:
explicit USRPInputGUI(DeviceUISet *deviceUISet, QWidget* parent = 0);
virtual ~USRPInputGUI();
virtual void destroy();
void setName(const QString& name);
QString getName() const;
void resetToDefaults();
virtual qint64 getCenterFrequency() const;
virtual void setCenterFrequency(qint64 centerFrequency);
QByteArray serialize() const;
bool deserialize(const QByteArray& data);
virtual MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; }
virtual bool handleMessage(const Message& message);
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
QTimer m_updateTimer;
QTimer m_statusTimer;
int m_sampleRate;
quint64 m_deviceCenterFrequency; //!< Center frequency in device
int m_lastEngineState;
bool m_doApplySettings;
bool m_forceSettings;
int m_statusCounter;
int m_deviceStatusCounter;
MessageQueue m_inputMessageQueue;
void displaySettings();
void displaySampleRate();
void setCenterFrequencyDisplay();
void setCenterFrequencySetting(uint64_t kHzValue);
void sendSettings();
void updateSampleRateAndFrequency();
void updateSampleRate();
void updateFrequencyLimits();
void blockApplySettings(bool block);
private slots:
void handleInputMessages();
void on_startStop_toggled(bool checked);
void on_centerFrequency_changed(quint64 value);
void on_dcOffset_toggled(bool checked);
void on_iqImbalance_toggled(bool checked);
void on_sampleRate_changed(quint64 value);
void on_swDecim_currentIndexChanged(int index);
void on_lpf_changed(quint64 value);
void on_gainMode_currentIndexChanged(int index);
void on_gain_valueChanged(int value);
void on_antenna_currentIndexChanged(int index);
void on_clockSource_currentIndexChanged(int index);
void on_transverter_clicked();
void on_sampleRateMode_toggled(bool checked);
void openDeviceSettingsDialog(const QPoint& p);
void updateHardware();
void updateStatus();
};
#endif /* PLUGINS_SAMPLESOURCE_USRPINPUT_USRPINPUTGUI_H_ */
@@ -0,0 +1,794 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>USRPInputGUI</class>
<widget class="QWidget" name="USRPInputGUI">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>360</width>
<height>290</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Minimum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>360</width>
<height>290</height>
</size>
</property>
<property name="font">
<font>
<family>Liberation Sans</family>
<pointsize>9</pointsize>
</font>
</property>
<property name="windowTitle">
<string>USRP Input</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<property name="spacing">
<number>3</number>
</property>
<property name="leftMargin">
<number>2</number>
</property>
<property name="topMargin">
<number>2</number>
</property>
<property name="rightMargin">
<number>2</number>
</property>
<property name="bottomMargin">
<number>2</number>
</property>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_freq">
<property name="topMargin">
<number>4</number>
</property>
<item>
<layout class="QVBoxLayout" name="freqLeftLayout">
<item>
<layout class="QHBoxLayout" name="freqLeftTopLayout">
<item>
<widget class="ButtonSwitch" name="startStop">
<property name="toolTip">
<string>start/stop acquisition</string>
</property>
<property name="text">
<string/>
</property>
<property name="icon">
<iconset resource="../../../sdrgui/resources/res.qrc">
<normaloff>:/play.png</normaloff>
<normalon>:/stop.png</normalon>:/play.png</iconset>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="freqLeftBotLayout">
<item>
<widget class="QLabel" name="sampleRateLabel">
<property name="minimumSize">
<size>
<width>54</width>
<height>0</height>
</size>
</property>
<property name="toolTip">
<string>Device to host sample rate (k or MS/s)</string>
</property>
<property name="text">
<string>00000k</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</item>
<item>
<spacer name="freqLeftSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="ValueDial" name="centerFrequency" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Maximum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>32</width>
<height>16</height>
</size>
</property>
<property name="font">
<font>
<family>Liberation Mono</family>
<pointsize>20</pointsize>
<weight>50</weight>
<bold>false</bold>
</font>
</property>
<property name="cursor">
<cursorShape>PointingHandCursor</cursorShape>
</property>
<property name="focusPolicy">
<enum>Qt::StrongFocus</enum>
</property>
<property name="toolTip">
<string>Main center frequency in kHz</string>
</property>
</widget>
</item>
<item>
<layout class="QVBoxLayout" name="freqRightLayout">
<property name="leftMargin">
<number>6</number>
</property>
<property name="rightMargin">
<number>6</number>
</property>
<item>
<layout class="QHBoxLayout" name="freqRightTopLayout">
<item>
<widget class="QLabel" name="freqUnits">
<property name="text">
<string> kHz</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="channelNumberText">
<property name="minimumSize">
<size>
<width>20</width>
<height>0</height>
</size>
</property>
<property name="toolTip">
<string>Channel number</string>
</property>
<property name="text">
<string>#0</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="freqRightBotLayout">
<item>
<widget class="QLabel" name="deviceRateText">
<property name="minimumSize">
<size>
<width>54</width>
<height>0</height>
</size>
</property>
<property name="toolTip">
<string>Baseband I/Q sample rate kS/s</string>
</property>
<property name="text">
<string>00000k</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<property name="topMargin">
<number>2</number>
</property>
<item>
<widget class="QLabel" name="antennaLabel">
<property name="pixmap">
<pixmap resource="../../../sdrgui/resources/res.qrc">:/antenna.png</pixmap>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="antenna">
<property name="minimumSize">
<size>
<width>70</width>
<height>0</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>50</width>
<height>16777215</height>
</size>
</property>
<property name="toolTip">
<string>Antenna select.</string>
</property>
</widget>
</item>
<item>
<widget class="TransverterButton" name="transverter">
<property name="maximumSize">
<size>
<width>24</width>
<height>24</height>
</size>
</property>
<property name="toolTip">
<string>Transverter frequency translation dialog</string>
</property>
<property name="text">
<string>X</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QLabel" name="clockSourceLabel">
<property name="text">
<string>Clock</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="clockSource">
<property name="toolTip">
<string>Clock source</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="Line" name="line_lna">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="ncoSampleRateLayout">
<property name="topMargin">
<number>2</number>
</property>
<item>
<widget class="QToolButton" name="sampleRateMode">
<property name="minimumSize">
<size>
<width>26</width>
<height>0</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>26</width>
<height>16777215</height>
</size>
</property>
<property name="toolTip">
<string>Toggle between device to host (SR) and base band (BB) sample rate input</string>
</property>
<property name="text">
<string>SR</string>
</property>
<property name="checkable">
<bool>true</bool>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="ValueDial" name="sampleRate" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Maximum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>32</width>
<height>16</height>
</size>
</property>
<property name="font">
<font>
<family>Liberation Mono</family>
<pointsize>12</pointsize>
<weight>50</weight>
<bold>false</bold>
</font>
</property>
<property name="cursor">
<cursorShape>PointingHandCursor</cursorShape>
</property>
<property name="toolTip">
<string>Device to host sample rate</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="samplerateUnit">
<property name="text">
<string>S/s</string>
</property>
</widget>
</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>
<item>
<widget class="QLabel" name="swDecimLabel">
<property name="text">
<string>Dec</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="swDecim">
<property name="maximumSize">
<size>
<width>50</width>
<height>16777215</height>
</size>
</property>
<property name="toolTip">
<string>Software decimation factor</string>
</property>
<property name="currentIndex">
<number>0</number>
</property>
<item>
<property name="text">
<string>1</string>
</property>
</item>
<item>
<property name="text">
<string>2</string>
</property>
</item>
<item>
<property name="text">
<string>4</string>
</property>
</item>
<item>
<property name="text">
<string>8</string>
</property>
</item>
<item>
<property name="text">
<string>16</string>
</property>
</item>
<item>
<property name="text">
<string>32</string>
</property>
</item>
<item>
<property name="text">
<string>64</string>
</property>
</item>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="gainLayout">
<property name="topMargin">
<number>2</number>
</property>
<property name="bottomMargin">
<number>2</number>
</property>
<item>
<widget class="QLabel" name="gainLabel">
<property name="text">
<string>Gain</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="gainMode">
<property name="maximumSize">
<size>
<width>54</width>
<height>16777215</height>
</size>
</property>
<property name="toolTip">
<string>Automatic or Manual gain selection</string>
</property>
<item>
<property name="text">
<string>Auto</string>
</property>
</item>
<item>
<property name="text">
<string>Man</string>
</property>
</item>
</widget>
</item>
<item>
<widget class="QSlider" name="gain">
<property name="toolTip">
<string>Global gain (dB)</string>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="gainText">
<property name="minimumSize">
<size>
<width>18</width>
<height>0</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>18</width>
<height>16777215</height>
</size>
</property>
<property name="toolTip">
<string>Automatic global gain</string>
</property>
<property name="text">
<string>20</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label">
<property name="text">
<string>dB</string>
</property>
</widget>
</item>
<item>
<widget class="Line" name="line_3">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_5">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="Line" name="line_4">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
</widget>
</item>
<item>
<widget class="ButtonSwitch" name="dcOffset">
<property name="toolTip">
<string>Automatic DC offset removal</string>
</property>
<property name="text">
<string>DC</string>
</property>
</widget>
</item>
<item>
<widget class="ButtonSwitch" name="iqImbalance">
<property name="toolTip">
<string>Automatic IQ imbalance correction</string>
</property>
<property name="text">
<string>IQ</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="Line" name="line_freq">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="lpfLayout">
<property name="topMargin">
<number>2</number>
</property>
<property name="bottomMargin">
<number>2</number>
</property>
<item>
<widget class="QLabel" name="lpfLabel">
<property name="text">
<string>LPF</string>
</property>
</widget>
</item>
<item>
<widget class="ValueDial" name="lpf" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Maximum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>32</width>
<height>16</height>
</size>
</property>
<property name="font">
<font>
<family>Liberation Mono</family>
<pointsize>12</pointsize>
<weight>50</weight>
<bold>false</bold>
</font>
</property>
<property name="cursor">
<cursorShape>PointingHandCursor</cursorShape>
</property>
<property name="toolTip">
<string>Analog lowpass filer bandwidth (kHz)</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="lpfUnits">
<property name="text">
<string>kHz</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QLabel" name="streamStatusLabel">
<property name="minimumSize">
<size>
<width>24</width>
<height>24</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>24</width>
<height>24</height>
</size>
</property>
<property name="toolTip">
<string>Green when stream is receiving data</string>
</property>
<property name="text">
<string/>
</property>
<property name="pixmap">
<pixmap resource="../../../sdrgui/resources/res.qrc">:/stream.png</pixmap>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="overrunLabel">
<property name="minimumSize">
<size>
<width>12</width>
<height>0</height>
</size>
</property>
<property name="toolTip">
<string>Red if overruns occured. Cleared when restarting acquisition</string>
</property>
<property name="styleSheet">
<string notr="true">background:rgb(79,79,79);</string>
</property>
<property name="text">
<string>O</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="timeoutLabel">
<property name="minimumSize">
<size>
<width>12</width>
<height>0</height>
</size>
</property>
<property name="toolTip">
<string>Red if timeouts occured. Cleared when restarting acquisition</string>
</property>
<property name="styleSheet">
<string notr="true">background:rgb(79,79,79);</string>
</property>
<property name="text">
<string>T</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="Line" name="line">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="padLayout">
<item>
<spacer name="verticalPadSpacer">
<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>
<customwidget>
<class>ButtonSwitch</class>
<extends>QToolButton</extends>
<header>gui/buttonswitch.h</header>
</customwidget>
<customwidget>
<class>ValueDial</class>
<extends>QWidget</extends>
<header>gui/valuedial.h</header>
<container>1</container>
</customwidget>
<customwidget>
<class>TransverterButton</class>
<extends>QPushButton</extends>
<header>gui/transverterbutton.h</header>
</customwidget>
</customwidgets>
<resources>
<include location="../../../sdrgui/resources/res.qrc"/>
<include location="../../../sdrgui/resources/res.qrc"/>
<include location="../../../sdrgui/resources/res.qrc"/>
<include location="../../../sdrgui/resources/res.qrc"/>
<include location="../../../sdrgui/resources/res.qrc"/>
<include location="../../../sdrgui/resources/res.qrc"/>
<include location="../../../sdrgui/resources/res.qrc"/>
<include location="../../../sdrgui/resources/res.qrc"/>
<include location="../../../sdrgui/resources/res.qrc"/>
<include location="../../../sdrgui/resources/res.qrc"/>
<include location="../../../sdrgui/resources/res.qrc"/>
<include location="../../../sdrgui/resources/res.qrc"/>
<include location="../../../sdrgui/resources/res.qrc"/>
<include location="../../../sdrgui/resources/res.qrc"/>
<include location="../../../sdrgui/resources/res.qrc"/>
<include location="../../../sdrgui/resources/res.qrc"/>
<include location="../../../sdrgui/resources/res.qrc"/>
<include location="../../../sdrgui/resources/res.qrc"/>
<include location="../../../sdrgui/resources/res.qrc"/>
<include location="../../../sdrgui/resources/res.qrc"/>
<include location="../../../sdrgui/resources/res.qrc"/>
<include location="../../../sdrgui/resources/res.qrc"/>
<include location="../../../sdrgui/resources/res.qrc"/>
<include location="../../../sdrgui/resources/res.qrc"/>
<include location="../../../sdrgui/resources/res.qrc"/>
<include location="../../../sdrgui/resources/res.qrc"/>
<include location="../../../sdrgui/resources/res.qrc"/>
<include location="../../../sdrgui/resources/res.qrc"/>
<include location="../../../sdrgui/resources/res.qrc"/>
<include location="../../../sdrgui/resources/res.qrc"/>
<include location="../../../sdrgui/resources/res.qrc"/>
<include location="../../../sdrgui/resources/res.qrc"/>
<include location="../../../sdrgui/resources/res.qrc"/>
<include location="../../../sdrgui/resources/res.qrc"/>
</resources>
<connections/>
</ui>
@@ -0,0 +1,150 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2015 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 <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#include <QtPlugin>
#include <string>
#include "plugin/pluginapi.h"
#include "util/simpleserializer.h"
#include "usrp/deviceusrp.h"
#ifdef SERVER_MODE
#include "usrpinput.h"
#else
#include "usrpinputgui.h"
#endif
#include "usrpinputplugin.h"
#include "usrpinputwebapiadapter.h"
const PluginDescriptor USRPInputPlugin::m_pluginDescriptor = {
QString("USRP"),
QString("USRP Input"),
QString("4.18.1"),
QString("(c) Jon Beniston, M7RCE and Edouard Griffiths, F4EXB"),
QString("https://github.com/f4exb/sdrangel"),
true,
QString("https://github.com/f4exb/sdrangel")
};
const QString USRPInputPlugin::m_hardwareID = "USRP";
const QString USRPInputPlugin::m_deviceTypeID = USRP_DEVICE_TYPE_ID;
USRPInputPlugin::USRPInputPlugin(QObject* parent) :
QObject(parent)
{
}
const PluginDescriptor& USRPInputPlugin::getPluginDescriptor() const
{
return m_pluginDescriptor;
}
void USRPInputPlugin::initPlugin(PluginAPI* pluginAPI)
{
pluginAPI->registerSampleSource(m_deviceTypeID, this);
}
void USRPInputPlugin::enumOriginDevices(QStringList& listedHwIds, OriginDevices& originDevices)
{
if (listedHwIds.contains(m_hardwareID)) { // check if it was done
return;
}
DeviceUSRP::enumOriginDevices(m_hardwareID, originDevices);
listedHwIds.append(m_hardwareID);
}
PluginInterface::SamplingDevices USRPInputPlugin::enumSampleSources(const OriginDevices& originDevices)
{
SamplingDevices result;
for (OriginDevices::const_iterator it = originDevices.begin(); it != originDevices.end(); ++it)
{
if (it->hardwareId == m_hardwareID)
{
for (unsigned int j = 0; j < it->nbRxStreams; j++)
{
qDebug("USRPInputPlugin::enumSampleSources: device #%d channel %u: %s", it->sequence, j, qPrintable(it->serial));
QString displayedName = it->displayableName;
displayedName.replace(QString("$1]"), QString("%1]").arg(j));
result.append(SamplingDevice(
displayedName,
it->hardwareId,
m_deviceTypeID,
it->serial,
it->sequence,
PluginInterface::SamplingDevice::PhysicalDevice,
PluginInterface::SamplingDevice::StreamSingleRx,
it->nbRxStreams,
j
));
}
}
}
return result;
}
#ifdef SERVER_MODE
PluginInstanceGUI* USRPInputPlugin::createSampleSourcePluginInstanceGUI(
const QString& sourceId,
QWidget **widget,
DeviceUISet *deviceUISet)
{
(void) sourceId;
(void) widget;
(void) deviceUISet;
return 0;
}
#else
PluginInstanceGUI* USRPInputPlugin::createSampleSourcePluginInstanceGUI(
const QString& sourceId,
QWidget **widget,
DeviceUISet *deviceUISet)
{
if(sourceId == m_deviceTypeID)
{
USRPInputGUI* gui = new USRPInputGUI(deviceUISet);
*widget = gui;
return gui;
}
else
{
return 0;
}
}
#endif
DeviceSampleSource *USRPInputPlugin::createSampleSourcePluginInstance(const QString& sourceId, DeviceAPI *deviceAPI)
{
if (sourceId == m_deviceTypeID)
{
USRPInput* input = new USRPInput(deviceAPI);
return input;
}
else
{
return 0;
}
}
DeviceWebAPIAdapter *USRPInputPlugin::createDeviceWebAPIAdapter() const
{
return new USRPInputWebAPIAdapter();
}
@@ -0,0 +1,57 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2017 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 <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#ifndef PLUGINS_SAMPLESOURCE_USRPINPUT_USRPINPUTPLUGIN_H_
#define PLUGINS_SAMPLESOURCE_USRPINPUT_USRPINPUTPLUGIN_H_
#include <QObject>
#include "plugin/plugininterface.h"
class PluginAPI;
#define USRP_DEVICE_TYPE_ID "sdrangel.samplesource.usrp"
class USRPInputPlugin : public QObject, public PluginInterface {
Q_OBJECT
Q_INTERFACES(PluginInterface)
Q_PLUGIN_METADATA(IID USRP_DEVICE_TYPE_ID)
public:
explicit USRPInputPlugin(QObject* parent = 0);
const PluginDescriptor& getPluginDescriptor() const;
void initPlugin(PluginAPI* pluginAPI);
virtual void enumOriginDevices(QStringList& listedHwIds, OriginDevices& originDevices);
virtual SamplingDevices enumSampleSources(const OriginDevices& originDevices);
virtual PluginInstanceGUI* createSampleSourcePluginInstanceGUI(
const QString& sourceId,
QWidget **widget,
DeviceUISet *deviceUISet);
virtual DeviceSampleSource* createSampleSourcePluginInstance(const QString& sourceId, DeviceAPI *deviceAPI);
virtual DeviceWebAPIAdapter* createDeviceWebAPIAdapter() const;
static const QString m_hardwareID;
static const QString m_deviceTypeID;
private:
static const PluginDescriptor m_pluginDescriptor;
};
#endif /* PLUGINS_SAMPLESOURCE_USRPINPUT_USRPINPUTPLUGIN_H_ */
@@ -0,0 +1,117 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2017 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 <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#include "util/simpleserializer.h"
#include "usrpinputsettings.h"
USRPInputSettings::USRPInputSettings()
{
resetToDefaults();
}
void USRPInputSettings::resetToDefaults()
{
m_centerFrequency = 435000*1000;
m_devSampleRate = 3000000;
m_dcBlock = false;
m_iqCorrection = false;
m_log2SoftDecim = 0;
m_lpfBW = 5.5e6f;
m_gain = 50;
m_antennaPath = "TX/RX";
m_gainMode = GAIN_AUTO;
m_clockSource = "internal";
m_transverterMode = false;
m_transverterDeltaFrequency = 0;
m_useReverseAPI = false;
m_reverseAPIAddress = "127.0.0.1";
m_reverseAPIPort = 8888;
m_reverseAPIDeviceIndex = 0;
}
QByteArray USRPInputSettings::serialize() const
{
SimpleSerializer s(1);
s.writeS32(1, m_devSampleRate);
s.writeBool(2, m_dcBlock);
s.writeBool(3, m_iqCorrection);
s.writeU32(4, m_log2SoftDecim);
s.writeFloat(5, m_lpfBW);
s.writeU32(6, m_gain);
s.writeString(7, m_antennaPath);
s.writeS32(8, (int) m_gainMode);
s.writeString(9, m_clockSource);
s.writeBool(10, m_transverterMode);
s.writeS64(11, m_transverterDeltaFrequency);
s.writeBool(12, m_useReverseAPI);
s.writeString(13, m_reverseAPIAddress);
s.writeU32(14, m_reverseAPIPort);
s.writeU32(15, m_reverseAPIDeviceIndex);
return s.final();
}
bool USRPInputSettings::deserialize(const QByteArray& data)
{
SimpleDeserializer d(data);
if (!d.isValid())
{
resetToDefaults();
return false;
}
if (d.getVersion() == 1)
{
int intval;
uint32_t uintval;
d.readS32(1, &m_devSampleRate, 5000000);
d.readBool(2, &m_dcBlock, false);
d.readBool(3, &m_iqCorrection, false);
d.readU32(4, &m_log2SoftDecim, 0);
d.readFloat(5, &m_lpfBW, 1.5e6);
d.readU32(6, &m_gain, 50);
d.readString(7, &m_antennaPath, "TX/RX");
d.readS32(8, &intval, 0);
m_gainMode = (GainMode) intval;
d.readString(9, &m_clockSource, "internal");
d.readBool(10, &m_transverterMode, false);
d.readS64(11, &m_transverterDeltaFrequency, 0);
d.readBool(12, &m_useReverseAPI, false);
d.readString(13, &m_reverseAPIAddress, "127.0.0.1");
d.readU32(14, &uintval, 0);
if ((uintval > 1023) && (uintval < 65535)) {
m_reverseAPIPort = uintval;
} else {
m_reverseAPIPort = 8888;
}
d.readU32(15, &uintval, 0);
m_reverseAPIDeviceIndex = uintval > 99 ? 99 : uintval;
return true;
}
else
{
resetToDefaults();
return false;
}
}
@@ -0,0 +1,62 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2017 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 <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#ifndef PLUGINS_SAMPLESOURCE_USRPINPUT_USRPINPUTSETTINGS_H_
#define PLUGINS_SAMPLESOURCE_USRPINPUT_USRPINPUTSETTINGS_H_
#include <QByteArray>
#include <QString>
#include <stdint.h>
/**
* These are the settings individual to each hardware channel or software Rx chain
* Plus the settings to be saved in the presets
*/
struct USRPInputSettings
{
typedef enum {
GAIN_AUTO,
GAIN_MANUAL
} GainMode;
// global settings to be saved
uint64_t m_centerFrequency;
int m_devSampleRate;
// channel settings
bool m_dcBlock;
bool m_iqCorrection;
uint32_t m_log2SoftDecim;
float m_lpfBW; //!< Analog lowpass filter bandwidth (Hz)
uint32_t m_gain; //!< Optimally distributed gain (dB)
QString m_antennaPath;
GainMode m_gainMode; //!< Gain mode: auto or manual
QString m_clockSource;
bool m_transverterMode;
qint64 m_transverterDeltaFrequency;
bool m_useReverseAPI;
QString m_reverseAPIAddress;
uint16_t m_reverseAPIPort;
uint16_t m_reverseAPIDeviceIndex;
USRPInputSettings();
void resetToDefaults();
QByteArray serialize() const;
bool deserialize(const QByteArray& data);
};
#endif /* PLUGINS_SAMPLESOURCE_USRPINPUT_USRPINPUTSETTINGS_H_ */
@@ -0,0 +1,202 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2017 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 <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#include <errno.h>
#include <algorithm>
#include <QDebug>
#include <uhd/types/stream_cmd.hpp>
#include "usrpinputsettings.h"
#include "usrpinputthread.h"
USRPInputThread::USRPInputThread(uhd::rx_streamer::sptr stream, SampleSinkFifo* sampleFifo, QObject* parent) :
QThread(parent),
m_running(false),
m_stream(stream),
m_convertBuffer(DeviceUSRP::blockSize),
m_sampleFifo(sampleFifo),
m_log2Decim(0)
{
std::fill(m_buf, m_buf + 2*DeviceUSRP::blockSize, 0);
}
USRPInputThread::~USRPInputThread()
{
stopWork();
}
void USRPInputThread::startWork()
{
if (m_running) return; // return if running already
try
{
uhd::stream_cmd_t stream_cmd(uhd::stream_cmd_t::STREAM_MODE_START_CONTINUOUS);
stream_cmd.num_samps = size_t(0);
stream_cmd.stream_now = true;
stream_cmd.time_spec = uhd::time_spec_t();
m_stream->issue_stream_cmd(stream_cmd);
// Reset stats
m_packets = 0;
m_overflows = 0;
m_timeouts = 0;
qDebug("USRPInputThread::startWork: stream started");
}
catch (std::exception& e)
{
qDebug() << "USRPInputThread::startWork: exception: " << e.what();
}
m_startWaitMutex.lock();
start();
while(!m_running)
m_startWaiter.wait(&m_startWaitMutex, 100);
m_startWaitMutex.unlock();
}
void USRPInputThread::stopWork()
{
if (!m_running) return; // return if not running
m_running = false;
wait();
try
{
uhd::rx_metadata_t md;
uhd::stream_cmd_t stream_cmd(uhd::stream_cmd_t::STREAM_MODE_STOP_CONTINUOUS);
stream_cmd.stream_now = true;
m_stream->issue_stream_cmd(stream_cmd);
// Clear out any data left in the stream, otherwise we'll get an
// exception 'recv buffer smaller than vrt packet offset' when restarting
while (!md.end_of_burst)
{
try
{
//qDebug() << "USRPInputThread::stopWork: recing until end of burst";
m_stream->recv(m_buf, DeviceUSRP::blockSize, md);
}
catch (std::exception& e)
{
qDebug() << "USRPInputThread::stopWork: exception ignored while flushing buffers: " << e.what();
}
}
qDebug("USRPInputThread::stopWork: stream stopped");
}
catch (std::exception& e)
{
qDebug() << "USRPInputThread::stopWork: exception: " << e.what();
}
}
void USRPInputThread::setLog2Decimation(unsigned int log2_decim)
{
m_log2Decim = log2_decim;
}
void USRPInputThread::run()
{
uhd::rx_metadata_t md;
m_running = true;
m_startWaiter.wakeAll();
try
{
while (m_running)
{
const size_t samples_received = m_stream->recv(m_buf, DeviceUSRP::blockSize, md);
m_packets++;
if (samples_received != DeviceUSRP::blockSize)
{
qDebug("USRPInputThread::run - received %d/%d samples", samples_received, DeviceUSRP::blockSize);
}
if (md.error_code == uhd::rx_metadata_t::ERROR_CODE_TIMEOUT)
{
qDebug("USRPInputThread::run - timeout - ending thread");
m_timeouts++;
// It seems we can't recover after a timeout, so stop thread
m_running = false;
}
else if (md.error_code == uhd::rx_metadata_t::ERROR_CODE_OVERFLOW)
{
qDebug("USRPInputThread::run - overflow");
m_overflows++;
}
callbackIQ(m_buf, 2 * samples_received);
}
}
catch (std::exception& e)
{
qDebug() << "USRPInputThread::run: exception: " << e.what();
}
m_running = false;
}
// Decimate according to specified log2 (ex: log2=4 => decim=16)
void USRPInputThread::callbackIQ(const qint16* buf, qint32 len)
{
SampleVector::iterator it = m_convertBuffer.begin();
switch (m_log2Decim)
{
case 0:
m_decimatorsIQ.decimate1(&it, buf, len);
break;
case 1:
m_decimatorsIQ.decimate2_cen(&it, buf, len);
break;
case 2:
m_decimatorsIQ.decimate4_cen(&it, buf, len);
break;
case 3:
m_decimatorsIQ.decimate8_cen(&it, buf, len);
break;
case 4:
m_decimatorsIQ.decimate16_cen(&it, buf, len);
break;
case 5:
m_decimatorsIQ.decimate32_cen(&it, buf, len);
break;
case 6:
m_decimatorsIQ.decimate64_cen(&it, buf, len);
break;
default:
break;
}
m_sampleFifo->write(m_convertBuffer.begin(), it);
}
void USRPInputThread::getStreamStatus(bool& active, quint32& overflows, quint32& timeouts)
{
//qDebug() << "USRPInputThread::getStreamStatus " << m_packets << " " << m_overflows << " " << m_timeouts;
active = m_packets > 0;
overflows = m_overflows;
timeouts = m_timeouts;
}
@@ -0,0 +1,73 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2017 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 <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#ifndef PLUGINS_SAMPLESOURCE_USRPINPUT_USRPINPUTTHREAD_H_
#define PLUGINS_SAMPLESOURCE_USRPINPUT_USRPINPUTTHREAD_H_
#include <QThread>
#include <QMutex>
#include <QWaitCondition>
#include <uhd/usrp/multi_usrp.hpp>
#include <uhd/types/metadata.hpp>
#include "dsp/samplesinkfifo.h"
#include "dsp/decimators.h"
#include "usrp/deviceusrpshared.h"
#include "usrp/deviceusrp.h"
class USRPInputThread : public QThread, public DeviceUSRPShared::ThreadInterface
{
Q_OBJECT
public:
USRPInputThread(uhd::rx_streamer::sptr stream, SampleSinkFifo* sampleFifo, QObject* parent = 0);
~USRPInputThread();
virtual void startWork();
virtual void stopWork();
virtual void setDeviceSampleRate(int sampleRate) { (void) sampleRate; }
virtual bool isRunning() { return m_running; }
void setLog2Decimation(unsigned int log2_decim);
void getStreamStatus(bool& active, quint32& overflows, quint32& m_timeouts);
private:
QMutex m_startWaitMutex;
QWaitCondition m_startWaiter;
bool m_running;
quint64 m_packets;
quint32 m_overflows;
quint32 m_timeouts;
uhd::rx_streamer::sptr m_stream;
qint16 m_buf[2*DeviceUSRP::blockSize]; //must hold I+Q values of each sample hence 2xcomplex size
SampleVector m_convertBuffer;
SampleSinkFifo* m_sampleFifo;
unsigned int m_log2Decim; // soft decimation
Decimators<qint32, qint16, SDR_RX_SAMP_SZ, 12, true> m_decimatorsIQ;
void run();
void callbackIQ(const qint16* buf, qint32 len);
};
#endif /* PLUGINS_SAMPLESOURCE_USRPINPUT_USRPINPUTTHREAD_H_ */
@@ -0,0 +1,52 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2019 Edouard Griffiths, F4EXB //
// Copyright (C) 2020 Jon Beniston, M7RCE //
// //
// Implementation of static web API adapters used for preset serialization and //
// deserialization //
// //
// 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 <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#include "SWGDeviceSettings.h"
#include "usrpinput.h"
#include "usrpinputwebapiadapter.h"
USRPInputWebAPIAdapter::USRPInputWebAPIAdapter()
{}
USRPInputWebAPIAdapter::~USRPInputWebAPIAdapter()
{}
int USRPInputWebAPIAdapter::webapiSettingsGet(
SWGSDRangel::SWGDeviceSettings& response,
QString& errorMessage)
{
(void) errorMessage;
response.setAirspyHfSettings(new SWGSDRangel::SWGAirspyHFSettings());
response.getAirspyHfSettings()->init();
USRPInput::webapiFormatDeviceSettings(response, m_settings);
return 200;
}
int USRPInputWebAPIAdapter::webapiSettingsPutPatch(
bool force,
const QStringList& deviceSettingsKeys,
SWGSDRangel::SWGDeviceSettings& response, // query + response
QString& errorMessage)
{
(void) errorMessage;
USRPInput::webapiUpdateDeviceSettings(m_settings, deviceSettingsKeys, response);
return 200;
}
@@ -0,0 +1,45 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2019 Edouard Griffiths, F4EXB //
// Copyright (C) 2020 Jon Beniston, M7RCE //
// //
// Implementation of static web API adapters used for preset serialization and //
// deserialization //
// //
// 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 <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#include "device/devicewebapiadapter.h"
#include "usrpinputsettings.h"
class USRPInputWebAPIAdapter : public DeviceWebAPIAdapter
{
public:
USRPInputWebAPIAdapter();
virtual ~USRPInputWebAPIAdapter();
virtual QByteArray serialize() { return m_settings.serialize(); }
virtual bool deserialize(const QByteArray& data) { return m_settings.deserialize(data); }
virtual int webapiSettingsGet(
SWGSDRangel::SWGDeviceSettings& response,
QString& errorMessage);
virtual int webapiSettingsPutPatch(
bool force,
const QStringList& deviceSettingsKeys,
SWGSDRangel::SWGDeviceSettings& response, // query + response
QString& errorMessage);
private:
USRPInputSettings m_settings;
};