1
0
mirror of https://github.com/f4exb/sdrangel.git synced 2026-06-02 06:04:39 -04:00

Merge branch 'master' of https://github.com/f4exb/sdrangel into osx

This commit is contained in:
ZigaS
2018-12-21 12:46:13 +01:00
617 changed files with 12037 additions and 2271 deletions
+2
View File
@@ -13,6 +13,8 @@ TARGET = inputairspy
CONFIG(MINGW32):LIBAIRSPYSRC = "C:\softs\libairspy"
CONFIG(MINGW64):LIBAIRSPYSRC = "C:\softs\libairspy"
CONFIG(MSVC):LIBAIRSPYSRC = "C:\softs\libairspy"
INCLUDEPATH += $$PWD
INCLUDEPATH += ../../../exports
INCLUDEPATH += ../../../sdrbase
+10 -5
View File
@@ -594,8 +594,9 @@ struct airspy_device *AirspyInput::open_airspy_from_sequence(int sequence)
int AirspyInput::webapiRunGet(
SWGSDRangel::SWGDeviceState& response,
QString& errorMessage __attribute__((unused)))
QString& errorMessage)
{
(void) errorMessage;
m_deviceAPI->getDeviceEngineStateStr(*response.getState());
return 200;
}
@@ -603,8 +604,9 @@ int AirspyInput::webapiRunGet(
int AirspyInput::webapiRun(
bool run,
SWGSDRangel::SWGDeviceState& response,
QString& errorMessage __attribute__((unused)))
QString& errorMessage)
{
(void) errorMessage;
m_deviceAPI->getDeviceEngineStateStr(*response.getState());
MsgStartStop *message = MsgStartStop::create(run);
m_inputMessageQueue.push(message);
@@ -620,8 +622,9 @@ int AirspyInput::webapiRun(
int AirspyInput::webapiSettingsGet(
SWGSDRangel::SWGDeviceSettings& response,
QString& errorMessage __attribute__((unused)))
QString& errorMessage)
{
(void) errorMessage;
response.setAirspySettings(new SWGSDRangel::SWGAirspySettings());
response.getAirspySettings()->init();
webapiFormatDeviceSettings(response, m_settings);
@@ -632,8 +635,9 @@ int AirspyInput::webapiSettingsPutPatch(
bool force,
const QStringList& deviceSettingsKeys,
SWGSDRangel::SWGDeviceSettings& response, // query + response
QString& errorMessage __attribute__((unused)))
QString& errorMessage)
{
(void) errorMessage;
AirspySettings settings = m_settings;
if (deviceSettingsKeys.contains("centerFrequency")) {
@@ -702,8 +706,9 @@ int AirspyInput::webapiSettingsPutPatch(
int AirspyInput::webapiReportGet(
SWGSDRangel::SWGDeviceReport& response,
QString& errorMessage __attribute__((unused)))
QString& errorMessage)
{
(void) errorMessage;
response.setAirspyReport(new SWGSDRangel::SWGAirspyReport());
response.getAirspyReport()->init();
webapiFormatDeviceReport(response);
@@ -13,6 +13,8 @@ TARGET = inputairspyhf
CONFIG(MINGW32):LIBAIRSPYHFSRC = "C:\softs\airspyhf"
CONFIG(MINGW64):LIBAIRSPYHFSRC = "C:\softs\airspyhf"
CONFIG(MSVC):LIBAIRSPYHFSRC = "C:\softs\airspyhf"
INCLUDEPATH += $$PWD
INCLUDEPATH += ../../../exports
INCLUDEPATH += ../../../sdrbase
@@ -486,8 +486,9 @@ airspyhf_device_t *AirspyHFInput::open_airspyhf_from_serial(const QString& seria
int AirspyHFInput::webapiSettingsGet(
SWGSDRangel::SWGDeviceSettings& response,
QString& errorMessage __attribute__((unused)))
QString& errorMessage)
{
(void) errorMessage;
response.setAirspyHfSettings(new SWGSDRangel::SWGAirspyHFSettings());
response.getAirspyHfSettings()->init();
webapiFormatDeviceSettings(response, m_settings);
@@ -498,8 +499,9 @@ int AirspyHFInput::webapiSettingsPutPatch(
bool force,
const QStringList& deviceSettingsKeys,
SWGSDRangel::SWGDeviceSettings& response, // query + response
QString& errorMessage __attribute__((unused)))
QString& errorMessage)
{
(void) errorMessage;
AirspyHFSettings settings = m_settings;
if (deviceSettingsKeys.contains("centerFrequency")) {
@@ -570,8 +572,9 @@ void AirspyHFInput::webapiFormatDeviceReport(SWGSDRangel::SWGDeviceReport& respo
int AirspyHFInput::webapiReportGet(
SWGSDRangel::SWGDeviceReport& response,
QString& errorMessage __attribute__((unused)))
QString& errorMessage)
{
(void) errorMessage;
response.setAirspyHfReport(new SWGSDRangel::SWGAirspyHFReport());
response.getAirspyHfReport()->init();
webapiFormatDeviceReport(response);
@@ -580,8 +583,9 @@ int AirspyHFInput::webapiReportGet(
int AirspyHFInput::webapiRunGet(
SWGSDRangel::SWGDeviceState& response,
QString& errorMessage __attribute__((unused)))
QString& errorMessage)
{
(void) errorMessage;
m_deviceAPI->getDeviceEngineStateStr(*response.getState());
return 200;
}
@@ -589,8 +593,9 @@ int AirspyHFInput::webapiRunGet(
int AirspyHFInput::webapiRun(
bool run,
SWGSDRangel::SWGDeviceState& response,
QString& errorMessage __attribute__((unused)))
QString& errorMessage)
{
(void) errorMessage;
m_deviceAPI->getDeviceEngineStateStr(*response.getState());
MsgStartStop *message = MsgStartStop::create(run);
m_inputMessageQueue.push(message);
@@ -609,8 +609,9 @@ bladerf_lna_gain Bladerf1Input::getLnaGain(int lnaGain)
int Bladerf1Input::webapiSettingsGet(
SWGSDRangel::SWGDeviceSettings& response,
QString& errorMessage __attribute__((unused)))
QString& errorMessage)
{
(void) errorMessage;
response.setBladeRf1InputSettings(new SWGSDRangel::SWGBladeRF1InputSettings());
response.getBladeRf1InputSettings()->init();
webapiFormatDeviceSettings(response, m_settings);
@@ -644,8 +645,9 @@ int Bladerf1Input::webapiSettingsPutPatch(
bool force,
const QStringList& deviceSettingsKeys,
SWGSDRangel::SWGDeviceSettings& response, // query + response
QString& errorMessage __attribute__((unused)))
QString& errorMessage)
{
(void) errorMessage;
BladeRF1InputSettings settings = m_settings;
if (deviceSettingsKeys.contains("centerFrequency")) {
@@ -706,8 +708,9 @@ int Bladerf1Input::webapiSettingsPutPatch(
int Bladerf1Input::webapiRunGet(
SWGSDRangel::SWGDeviceState& response,
QString& errorMessage __attribute__((unused)))
QString& errorMessage)
{
(void) errorMessage;
m_deviceAPI->getDeviceEngineStateStr(*response.getState());
return 200;
}
@@ -715,8 +718,9 @@ int Bladerf1Input::webapiRunGet(
int Bladerf1Input::webapiRun(
bool run,
SWGSDRangel::SWGDeviceState& response,
QString& errorMessage __attribute__((unused)))
QString& errorMessage)
{
(void) errorMessage;
m_deviceAPI->getDeviceEngineStateStr(*response.getState());
MsgStartStop *message = MsgStartStop::create(run);
m_inputMessageQueue.push(message);
@@ -17,15 +17,21 @@ DEFINES += USE_SSE4_1=1
QMAKE_CXXFLAGS += -msse4.1
QMAKE_CXXFLAGS += -std=c++11
CONFIG(MINGW32):LIBBLADERF = "C:\Programs\bladeRF"
CONFIG(MINGW64):LIBBLADERF = "C:\Programs\bladeRF"
INCLUDEPATH += $$PWD
INCLUDEPATH += ../../../exports
INCLUDEPATH += ../../../sdrbase
INCLUDEPATH += ../../../sdrgui
INCLUDEPATH += ../../../swagger/sdrangel/code/qt5/client
INCLUDEPATH += ../../../devices
INCLUDEPATH += $$LIBBLADERF/include
MINGW32 || MINGW64 {
LIBBLADERF = "C:\Programs\bladeRF"
INCLUDEPATH += $$LIBBLADERF/include
}
MSVC {
INCLUDEPATH += "C:\Program Files\PothosSDR\include"
}
CONFIG(Release):build_subdir = release
CONFIG(Debug):build_subdir = debug
@@ -47,7 +53,14 @@ FORMS += bladerf1inputgui.ui
LIBS += -L../../../sdrbase/$${build_subdir} -lsdrbase
LIBS += -L../../../sdrgui/$${build_subdir} -lsdrgui
LIBS += -L../../../swagger/$${build_subdir} -lswagger
LIBS += -L$$LIBBLADERF/lib -lbladeRF
LIBS += -L../../../devices/$${build_subdir} -ldevices
MINGW32 || MINGW64 {
LIBS += -L$$LIBBLADERF/lib -lbladeRF
}
MSVC {
LIBS += -L"C:\Program Files\PothosSDR\lib" -L"C:\Program Files\PothosSDR\bin" -lbladeRF
}
RESOURCES = ../../../sdrgui/resources/res.qrc
@@ -463,14 +463,10 @@ unsigned int Bladerf1InputGui::getXb200Index(bool xb_200, bladerf_xb200_path xb2
{
return 6;
}
else if (xb200Filter == BLADERF_XB200_222M)
else // xb200Filter == BLADERF_XB200_222M
{
return 7;
}
else
{
return 0;
}
}
}
else
@@ -329,6 +329,11 @@ bool BladeRF2Input::start()
((DeviceBladeRF2Shared*) (*it)->getBuddySharedPtr())->m_source->setThread(0);
}
// was used as temporary storage:
delete[] fifos;
delete[] log2Decims;
delete[] fcPoss;
needsStart = true;
}
else
@@ -470,6 +475,11 @@ void BladeRF2Input::stop()
if (stillActiveFIFO) {
bladerf2InputThread->startWork();
}
// was used as temporary storage:
delete[] fifos;
delete[] log2Decims;
delete[] fcPoss;
}
else // remove channel from existing thread
{
@@ -967,8 +977,9 @@ bool BladeRF2Input::applySettings(const BladeRF2InputSettings& settings, bool fo
int BladeRF2Input::webapiSettingsGet(
SWGSDRangel::SWGDeviceSettings& response,
QString& errorMessage __attribute__((unused)))
QString& errorMessage)
{
(void) errorMessage;
response.setBladeRf2InputSettings(new SWGSDRangel::SWGBladeRF2InputSettings());
response.getBladeRf2InputSettings()->init();
webapiFormatDeviceSettings(response, m_settings);
@@ -979,8 +990,9 @@ int BladeRF2Input::webapiSettingsPutPatch(
bool force,
const QStringList& deviceSettingsKeys,
SWGSDRangel::SWGDeviceSettings& response, // query + response
QString& errorMessage __attribute__((unused)))
QString& errorMessage)
{
(void) errorMessage;
BladeRF2InputSettings settings = m_settings;
if (deviceSettingsKeys.contains("centerFrequency")) {
@@ -1039,8 +1051,9 @@ int BladeRF2Input::webapiSettingsPutPatch(
return 200;
}
int BladeRF2Input::webapiReportGet(SWGSDRangel::SWGDeviceReport& response, QString& errorMessage __attribute__((unused)))
int BladeRF2Input::webapiReportGet(SWGSDRangel::SWGDeviceReport& response, QString& errorMessage)
{
(void) errorMessage;
response.setBladeRf2InputReport(new SWGSDRangel::SWGBladeRF2InputReport());
response.getBladeRf2InputReport()->init();
webapiFormatDeviceReport(response);
@@ -1123,8 +1136,9 @@ void BladeRF2Input::webapiFormatDeviceReport(SWGSDRangel::SWGDeviceReport& respo
int BladeRF2Input::webapiRunGet(
SWGSDRangel::SWGDeviceState& response,
QString& errorMessage __attribute__((unused)))
QString& errorMessage)
{
(void) errorMessage;
m_deviceAPI->getDeviceEngineStateStr(*response.getState());
return 200;
}
@@ -1132,8 +1146,9 @@ int BladeRF2Input::webapiRunGet(
int BladeRF2Input::webapiRun(
bool run,
SWGSDRangel::SWGDeviceState& response,
QString& errorMessage __attribute__((unused)))
QString& errorMessage)
{
(void) errorMessage;
m_deviceAPI->getDeviceEngineStateStr(*response.getState());
MsgStartStop *message = MsgStartStop::create(run);
m_inputMessageQueue.push(message);
@@ -17,15 +17,21 @@ DEFINES += USE_SSE4_1=1
QMAKE_CXXFLAGS += -msse4.1
QMAKE_CXXFLAGS += -std=c++11
CONFIG(MINGW32):LIBBLADERF = "C:\Programs\bladeRF"
CONFIG(MINGW64):LIBBLADERF = "C:\Programs\bladeRF"
INCLUDEPATH += $$PWD
INCLUDEPATH += ../../../exports
INCLUDEPATH += ../../../sdrbase
INCLUDEPATH += ../../../sdrgui
INCLUDEPATH += ../../../swagger/sdrangel/code/qt5/client
INCLUDEPATH += ../../../devices
INCLUDEPATH += $$LIBBLADERF/include
MINGW32 || MINGW64 {
LIBBLADERF = "C:\Programs\bladeRF"
INCLUDEPATH += $$LIBBLADERF/include
}
MSVC {
INCLUDEPATH += "C:\Program Files\PothosSDR\include"
}
CONFIG(Release):build_subdir = release
CONFIG(Debug):build_subdir = debug
@@ -47,7 +53,14 @@ FORMS += bladerf2inputgui.ui
LIBS += -L../../../sdrbase/$${build_subdir} -lsdrbase
LIBS += -L../../../sdrgui/$${build_subdir} -lsdrgui
LIBS += -L../../../swagger/$${build_subdir} -lswagger
LIBS += -L$$LIBBLADERF/lib -lbladeRF
LIBS += -L../../../devices/$${build_subdir} -ldevices
MINGW32 || MINGW64 {
LIBS += -L$$LIBBLADERF/lib -lbladeRF
}
MSVC {
LIBS += -L"C:\Program Files\PothosSDR\lib" -L"C:\Program Files\PothosSDR\bin" -lbladeRF
}
RESOURCES = ../../../sdrgui/resources/res.qrc
+3 -2
View File
@@ -209,7 +209,7 @@ bool FCDProGui::deserialize(const QByteArray& data)
}
}
bool FCDProGui::handleMessage(const Message& message __attribute__((unused)))
bool FCDProGui::handleMessage(const Message& message)
{
if (FCDProInput::MsgConfigureFCDPro::match(message))
{
@@ -434,8 +434,9 @@ void FCDProGui::on_gain6_currentIndexChanged(int index)
sendSettings();
}
void FCDProGui::on_setDefaults_clicked(bool checked __attribute__((unused)))
void FCDProGui::on_setDefaults_clicked(bool checked)
{
(void) checked;
m_settings.m_lnaGainIndex = 8; // +15 dB
//m_settings.rfFilterIndex = 0;
m_settings.m_mixerGainIndex = 1; // +12 dB
+83 -19
View File
@@ -31,9 +31,6 @@
<property name="windowTitle">
<string>FunCubeDongle</string>
</property>
<property name="toolTip">
<string>start/stop acquisition</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<property name="spacing">
<number>3</number>
@@ -61,6 +58,9 @@
<layout class="QHBoxLayout" name="deviceButtonsLayout">
<item>
<widget class="ButtonSwitch" name="startStop">
<property name="toolTip">
<string>start/stop acquisition</string>
</property>
<property name="text">
<string/>
</property>
@@ -287,7 +287,11 @@
</widget>
</item>
<item>
<widget class="QComboBox" name="lnaEnhance"/>
<widget class="QComboBox" name="lnaEnhance">
<property name="toolTip">
<string>LNA enhancement</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="bandLabel">
@@ -297,7 +301,11 @@
</widget>
</item>
<item>
<widget class="QComboBox" name="band"/>
<widget class="QComboBox" name="band">
<property name="toolTip">
<string>Band optimizations</string>
</property>
</widget>
</item>
</layout>
</item>
@@ -311,7 +319,11 @@
</widget>
</item>
<item>
<widget class="QComboBox" name="bias"/>
<widget class="QComboBox" name="bias">
<property name="toolTip">
<string>Band bias</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_2">
@@ -321,7 +333,11 @@
</widget>
</item>
<item>
<widget class="QComboBox" name="mode"/>
<widget class="QComboBox" name="mode">
<property name="toolTip">
<string>Mode ?</string>
</property>
</widget>
</item>
</layout>
</item>
@@ -335,7 +351,11 @@
</widget>
</item>
<item>
<widget class="QComboBox" name="lnaGain"/>
<widget class="QComboBox" name="lnaGain">
<property name="toolTip">
<string>LNA gain</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="rfFilterLabel">
@@ -345,7 +365,11 @@
</widget>
</item>
<item>
<widget class="QComboBox" name="rfFilter"/>
<widget class="QComboBox" name="rfFilter">
<property name="toolTip">
<string>RF filter selection</string>
</property>
</widget>
</item>
</layout>
</item>
@@ -359,7 +383,11 @@
</widget>
</item>
<item>
<widget class="QComboBox" name="mixGain"/>
<widget class="QComboBox" name="mixGain">
<property name="toolTip">
<string>Mixer gain</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="mixFilterLabel">
@@ -369,7 +397,11 @@
</widget>
</item>
<item>
<widget class="QComboBox" name="mixFilter"/>
<widget class="QComboBox" name="mixFilter">
<property name="toolTip">
<string>Mixer filter selection</string>
</property>
</widget>
</item>
</layout>
</item>
@@ -383,7 +415,11 @@
</widget>
</item>
<item>
<widget class="QComboBox" name="gain1"/>
<widget class="QComboBox" name="gain1">
<property name="toolTip">
<string>Gain block #1</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="rcFilterLabel">
@@ -393,7 +429,11 @@
</widget>
</item>
<item>
<widget class="QComboBox" name="rcFilter"/>
<widget class="QComboBox" name="rcFilter">
<property name="toolTip">
<string>Baseband RC filter selection</string>
</property>
</widget>
</item>
</layout>
</item>
@@ -407,7 +447,11 @@
</widget>
</item>
<item>
<widget class="QComboBox" name="gain2"/>
<widget class="QComboBox" name="gain2">
<property name="toolTip">
<string>Gain block #2</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="gain3Label">
@@ -417,7 +461,11 @@
</widget>
</item>
<item>
<widget class="QComboBox" name="gain3"/>
<widget class="QComboBox" name="gain3">
<property name="toolTip">
<string>Gain block #3</string>
</property>
</widget>
</item>
</layout>
</item>
@@ -431,7 +479,11 @@
</widget>
</item>
<item>
<widget class="QComboBox" name="gain4"/>
<widget class="QComboBox" name="gain4">
<property name="toolTip">
<string>Gain block #4</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_3">
@@ -441,7 +493,11 @@
</widget>
</item>
<item>
<widget class="QComboBox" name="ifFilter"/>
<widget class="QComboBox" name="ifFilter">
<property name="toolTip">
<string>IF filter selection</string>
</property>
</widget>
</item>
</layout>
</item>
@@ -455,7 +511,11 @@
</widget>
</item>
<item>
<widget class="QComboBox" name="gain5"/>
<widget class="QComboBox" name="gain5">
<property name="toolTip">
<string>Gain block #5</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="gain6Label">
@@ -465,7 +525,11 @@
</widget>
</item>
<item>
<widget class="QComboBox" name="gain6"/>
<widget class="QComboBox" name="gain6">
<property name="toolTip">
<string>Gain block #6</string>
</property>
</widget>
</item>
</layout>
</item>
+63 -20
View File
@@ -1,6 +1,5 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2012 maintech GmbH, Otto-Hahn-Str. 15, 97204 Hoechberg, Germany //
// written by Christian Daniel //
// Copyright (C) 2015-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 //
@@ -15,8 +14,6 @@
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
// FIXME: FCD is handled very badly!
#include <QDebug>
#include <string.h>
#include <errno.h>
@@ -27,10 +24,9 @@
#include "dsp/dspcommands.h"
#include "dsp/dspengine.h"
#include "dsp/filerecord.h"
#include "device/devicesourceapi.h"
#include "fcdproinput.h"
#include <device/devicesourceapi.h>
#include "fcdprothread.h"
#include "fcdtraits.h"
#include "fcdproconst.h"
@@ -47,6 +43,7 @@ FCDProInput::FCDProInput(DeviceSourceAPI *deviceAPI) :
m_deviceDescription(fcd_traits<Pro>::displayedName),
m_running(false)
{
m_fcdFIFO.setSize(20*fcd_traits<Pro>::convBufSize);
openDevice();
m_fileSink = new FileRecord(QString("test_%1.sdriq").arg(m_deviceAPI->getDeviceUID()));
m_deviceAPI->addSink(m_fileSink);
@@ -54,9 +51,13 @@ FCDProInput::FCDProInput(DeviceSourceAPI *deviceAPI) :
FCDProInput::~FCDProInput()
{
if (m_running) stop();
if (m_running) {
stop();
}
m_deviceAPI->removeSink(m_fileSink);
delete m_fileSink;
closeDevice();
}
@@ -67,15 +68,12 @@ void FCDProInput::destroy()
bool FCDProInput::openDevice()
{
int device = m_deviceAPI->getSampleSourceSequence();
if (m_dev != 0)
{
if (m_dev != 0) {
closeDevice();
}
int device = m_deviceAPI->getSampleSourceSequence();
qDebug() << "FCDProInput::openDevice with device #" << device;
m_dev = fcdOpen(fcd_traits<Pro>::vendorId, fcd_traits<Pro>::productId, device);
if (m_dev == 0)
@@ -117,7 +115,17 @@ bool FCDProInput::start()
return false;
}
m_FCDThread = new FCDProThread(&m_sampleFifo);
if (!openFCDAudio(fcd_traits<Pro>::qtDeviceName))
{
qCritical("FCDProInput::start: could not open FCD audio source");
return false;
}
else
{
qDebug("FCDProInput::start: FCD audio source opened");
}
m_FCDThread = new FCDProThread(&m_sampleFifo, &m_fcdFIFO);
m_FCDThread->startWork();
// mutexLocker.unlock();
@@ -139,6 +147,35 @@ void FCDProInput::closeDevice()
m_dev = 0;
}
bool FCDProInput::openFCDAudio(const char* cardname)
{
AudioDeviceManager *audioDeviceManager = DSPEngine::instance()->getAudioDeviceManager();
const QList<QAudioDeviceInfo>& audioList = audioDeviceManager->getInputDevices();
for (const auto &itAudio : audioList)
{
if (itAudio.deviceName().contains(QString(cardname)))
{
int fcdDeviceIndex = audioDeviceManager->getInputDeviceIndex(itAudio.deviceName());
m_fcdAudioInput.start(fcdDeviceIndex, fcd_traits<Pro>::sampleRate);
int fcdSampleRate = m_fcdAudioInput.getRate();
qDebug("FCDProPlusInput::openFCDAudio: %s index %d at %d S/s",
itAudio.deviceName().toStdString().c_str(), fcdDeviceIndex, fcdSampleRate);
m_fcdAudioInput.addFifo(&m_fcdFIFO);
return true;
}
}
qCritical("FCDProInput::openFCDAudio: device with name %s not found", cardname);
return false;
}
void FCDProInput::closeFCDAudio()
{
m_fcdAudioInput.removeFifo(&m_fcdFIFO);
m_fcdAudioInput.stop();
}
void FCDProInput::stop()
{
// QMutexLocker mutexLocker(&m_mutex);
@@ -148,7 +185,8 @@ void FCDProInput::stop()
m_FCDThread->stopWork();
// wait for thread to quit ?
delete m_FCDThread;
m_FCDThread = 0;
m_FCDThread = nullptr;
closeFCDAudio();
}
m_running = false;
@@ -493,8 +531,9 @@ void FCDProInput::set_center_freq(double freq)
}
void FCDProInput::set_bias_t(bool on __attribute__((unused)))
void FCDProInput::set_bias_t(bool on)
{
(void) on;
//quint8 cmd = on ? 1 : 0;
// TODO: use FCD Pro controls
@@ -749,8 +788,9 @@ void FCDProInput::set_lo_ppm()
int FCDProInput::webapiRunGet(
SWGSDRangel::SWGDeviceState& response,
QString& errorMessage __attribute__((unused)))
QString& errorMessage)
{
(void) errorMessage;
m_deviceAPI->getDeviceEngineStateStr(*response.getState());
return 200;
}
@@ -758,8 +798,9 @@ int FCDProInput::webapiRunGet(
int FCDProInput::webapiRun(
bool run,
SWGSDRangel::SWGDeviceState& response,
QString& errorMessage __attribute__((unused)))
QString& errorMessage)
{
(void) errorMessage;
m_deviceAPI->getDeviceEngineStateStr(*response.getState());
MsgStartStop *message = MsgStartStop::create(run);
m_inputMessageQueue.push(message);
@@ -775,8 +816,9 @@ int FCDProInput::webapiRun(
int FCDProInput::webapiSettingsGet(
SWGSDRangel::SWGDeviceSettings& response,
QString& errorMessage __attribute__((unused)))
QString& errorMessage)
{
(void) errorMessage;
response.setFcdProSettings(new SWGSDRangel::SWGFCDProSettings());
response.getFcdProSettings()->init();
webapiFormatDeviceSettings(response, m_settings);
@@ -787,8 +829,9 @@ int FCDProInput::webapiSettingsPutPatch(
bool force,
const QStringList& deviceSettingsKeys,
SWGSDRangel::SWGDeviceSettings& response, // query + response
QString& errorMessage __attribute__((unused)))
QString& errorMessage)
{
(void) errorMessage;
FCDProSettings settings = m_settings;
if (deviceSettingsKeys.contains("centerFrequency")) {
+9 -3
View File
@@ -1,6 +1,5 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2012 maintech GmbH, Otto-Hahn-Str. 15, 97204 Hoechberg, Germany //
// written by Christian Daniel //
// Copyright (C) 2015-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 //
@@ -22,7 +21,10 @@
#include <QByteArray>
#include <inttypes.h>
#include <dsp/devicesamplesource.h>
#include "dsp/devicesamplesource.h"
#include "audio/audioinput.h"
#include "audio/audiofifo.h"
#include "fcdprosettings.h"
#include "fcdhid.h"
@@ -158,6 +160,8 @@ public:
private:
bool openDevice();
void closeDevice();
bool openFCDAudio(const char *filename);
void closeFCDAudio();
void applySettings(const FCDProSettings& settings, bool force);
void set_lo_ppm();
@@ -165,6 +169,8 @@ private:
DeviceSourceAPI *m_deviceAPI;
hid_device *m_dev;
AudioInput m_fcdAudioInput;
AudioFifo m_fcdFIFO;
QMutex m_mutex;
FCDProSettings m_settings;
FCDProThread* m_FCDThread;
+22 -103
View File
@@ -18,16 +18,19 @@
#include <QDebug>
#include <stdio.h>
#include <errno.h>
#include "fcdprothread.h"
#include <chrono>
#include <thread>
#include "dsp/samplesinkfifo.h"
#include "fcdtraits.h"
#include "audio/audiofifo.h"
FCDProThread::FCDProThread(SampleSinkFifo* sampleFifo, QObject* parent) :
#include "fcdprothread.h"
FCDProThread::FCDProThread(SampleSinkFifo* sampleFifo, AudioFifo *fcdFIFO, QObject* parent) :
QThread(parent),
fcd_handle(NULL),
m_fcdFIFO(fcdFIFO),
m_running(false),
m_convertBuffer(fcd_traits<Pro>::convBufSize),
m_convertBuffer(fcd_traits<Pro>::convBufSize), // nb samples
m_sampleFifo(sampleFifo)
{
start();
@@ -59,107 +62,23 @@ void FCDProThread::stopWork()
void FCDProThread::run()
{
if ( !OpenSource(fcd_traits<Pro>::alsaDeviceName) )
{
qCritical() << "FCDThread::run: cannot open FCD sound card";
return;
}
// TODO: fallback to original fcd
m_running = true;
qDebug("FCDProThread::run: start running loop");
m_running = true;
while (m_running)
{
work(fcd_traits<Pro>::convBufSize);
std::this_thread::sleep_for(std::chrono::microseconds(200));
}
while(m_running)
{
if (work(fcd_traits<Pro>::convBufSize) < 0)
{
break;
}
}
CloseSource();
qDebug("FCDProThread::run: running loop stopped");
m_running = false;
}
bool FCDProThread::OpenSource(const char* cardname)
void FCDProThread::work(unsigned int n_items)
{
bool fail = false;
snd_pcm_hw_params_t* params;
//fcd_rate = FCDPP_RATE;
//fcd_channels =2;
//fcd_format = SND_PCM_SFMT_U16_LE;
snd_pcm_stream_t fcd_stream = SND_PCM_STREAM_CAPTURE;
if (fcd_handle)
{
return false;
}
if (snd_pcm_open(&fcd_handle, cardname, fcd_stream, 0) < 0)
{
qCritical("FCDThread::OpenSource: cannot open %s", cardname);
return false;
}
snd_pcm_hw_params_alloca(&params);
if (snd_pcm_hw_params_any(fcd_handle, params) < 0)
{
qCritical("FCDThread::OpenSource: snd_pcm_hw_params_any failed");
fail = true;
}
else if (snd_pcm_hw_params(fcd_handle, params) < 0)
{
qCritical("FCDThread::OpenSource: snd_pcm_hw_params failed");
fail = true;
// TODO: check actual samplerate, may be crippled firmware
}
else
{
if (snd_pcm_start(fcd_handle) < 0)
{
qCritical("FCDThread::OpenSource: snd_pcm_start failed");
fail = true;
}
}
if (fail)
{
snd_pcm_close( fcd_handle );
return false;
}
else
{
qDebug("FCDThread::OpenSource: Funcube stream started");
}
return true;
uint32_t nbRead = m_fcdFIFO->read((unsigned char *) m_buf, n_items); // number of samples
SampleVector::iterator it = m_convertBuffer.begin();
m_decimators.decimate1(&it, m_buf, 2*nbRead);
m_sampleFifo->write(m_convertBuffer.begin(), it);
}
void FCDProThread::CloseSource()
{
if (fcd_handle)
{
snd_pcm_close( fcd_handle );
}
fcd_handle = NULL;
}
int FCDProThread::work(int n_items)
{
int l;
SampleVector::iterator it;
void *out;
it = m_convertBuffer.begin();
out = (void *)&it[0];
l = snd_pcm_mmap_readi(fcd_handle, out, (snd_pcm_uframes_t)n_items);
if (l > 0)
m_sampleFifo->write(it, it + l);
if (l == -EPIPE) {
qDebug("FCD: Overrun detected");
return 0;
}
return l;
}
+12 -8
View File
@@ -1,5 +1,5 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2015 Edouard Griffiths, F4EXB //
// Copyright (C) 2015-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 //
@@ -20,33 +20,37 @@
#include <QThread>
#include <QMutex>
#include <QWaitCondition>
#include "dsp/inthalfbandfilter.h"
#include <alsa/asoundlib.h>
#include "dsp/samplesinkfifo.h"
#include "dsp/decimators.h"
#include "fcdtraits.h"
class AudioFifo;
class FCDProThread : public QThread {
Q_OBJECT
public:
FCDProThread(SampleSinkFifo* sampleFifo, QObject* parent = NULL);
FCDProThread(SampleSinkFifo* sampleFifo, AudioFifo *fcdFIFO, QObject* parent = nullptr);
~FCDProThread();
void startWork();
void stopWork();
bool OpenSource(const char *filename);
void CloseSource();
private:
snd_pcm_t* fcd_handle;
AudioFifo* m_fcdFIFO;
QMutex m_startWaitMutex;
QWaitCondition m_startWaiter;
bool m_running;
qint16 m_buf[fcd_traits<Pro>::convBufSize*2]; // stereo (I, Q)
SampleVector m_convertBuffer;
SampleSinkFifo* m_sampleFifo;
Decimators<qint32, qint16, SDR_RX_SAMP_SZ, 16> m_decimators;
void run();
int work(int n_items);
void work(unsigned int n_items);
};
#endif // INCLUDE_FCDPROTHREAD_H
@@ -127,7 +127,7 @@ bool FCDProPlusGui::deserialize(const QByteArray& data)
}
}
bool FCDProPlusGui::handleMessage(const Message& message __attribute__((unused)))
bool FCDProPlusGui::handleMessage(const Message& message)
{
if (FCDProPlusInput::MsgConfigureFCDProPlus::match(message))
{
@@ -159,18 +159,20 @@ void FCDProPlusGui::handleInputMessages()
while ((message = m_inputMessageQueue.pop()) != 0)
{
qDebug("RTLSDRGui::handleInputMessages: message: %s", message->getIdentifier());
if (DSPSignalNotification::match(*message))
{
DSPSignalNotification* notif = (DSPSignalNotification*) message;
m_sampleRate = notif->getSampleRate();
m_deviceCenterFrequency = notif->getCenterFrequency();
qDebug("RTLSDRGui::handleInputMessages: DSPSignalNotification: SampleRate:%d, CenterFrequency:%llu", notif->getSampleRate(), notif->getCenterFrequency());
qDebug("FCDProPlusGui::handleInputMessages: DSPSignalNotification: SampleRate:%d, CenterFrequency:%llu", notif->getSampleRate(), notif->getCenterFrequency());
updateSampleRateAndFrequency();
delete message;
}
else
{
qWarning("FCDProPlusGui::handleInputMessages: message: %s. No action.", message->getIdentifier());
}
}
}
@@ -322,11 +324,8 @@ void FCDProPlusGui::on_ppm_valueChanged(int value)
void FCDProPlusGui::on_startStop_toggled(bool checked)
{
if (m_doApplySettings)
{
FCDProPlusInput::MsgStartStop *message = FCDProPlusInput::MsgStartStop::create(checked);
m_sampleSource->getInputMessageQueue()->push(message);
}
FCDProPlusInput::MsgStartStop *message = FCDProPlusInput::MsgStartStop::create(checked);
m_sampleSource->getInputMessageQueue()->push(message);
}
void FCDProPlusGui::on_record_toggled(bool checked)
@@ -1,5 +1,5 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2016 Edouard Griffiths, F4EXB //
// Copyright (C) 2016-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 //
@@ -14,8 +14,6 @@
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
// FIXME: FCD is handled very badly!
#include <QDebug>
#include <string.h>
#include <errno.h>
@@ -25,11 +23,10 @@
#include "dsp/dspcommands.h"
#include "dsp/dspengine.h"
#include <dsp/filerecord.h>
#include "dsp/filerecord.h"
#include "device/devicesourceapi.h"
#include "fcdproplusinput.h"
#include <device/devicesourceapi.h>
#include "fcdproplusthread.h"
#include "fcdtraits.h"
#include "fcdproplusconst.h"
@@ -46,6 +43,7 @@ FCDProPlusInput::FCDProPlusInput(DeviceSourceAPI *deviceAPI) :
m_deviceDescription(fcd_traits<ProPlus>::displayedName),
m_running(false)
{
m_fcdFIFO.setSize(20*fcd_traits<ProPlus>::convBufSize);
openDevice();
m_fileSink = new FileRecord(QString("test_%1.sdriq").arg(m_deviceAPI->getDeviceUID()));
m_deviceAPI->addSink(m_fileSink);
@@ -53,9 +51,13 @@ FCDProPlusInput::FCDProPlusInput(DeviceSourceAPI *deviceAPI) :
FCDProPlusInput::~FCDProPlusInput()
{
if (m_running) stop();
if (m_running) {
stop();
}
m_deviceAPI->removeSink(m_fileSink);
delete m_fileSink;
closeDevice();
}
@@ -66,9 +68,12 @@ void FCDProPlusInput::destroy()
bool FCDProPlusInput::openDevice()
{
if (m_dev != 0) {
closeDevice();
}
int device = m_deviceAPI->getSampleSourceSequence();
qDebug() << "FCDProPlusInput::openDevice with device #" << device;
m_dev = fcdOpen(fcd_traits<ProPlus>::vendorId, fcd_traits<ProPlus>::productId, device);
if (m_dev == 0)
@@ -87,14 +92,15 @@ void FCDProPlusInput::init()
bool FCDProPlusInput::start()
{
// QMutexLocker mutexLocker(&m_mutex);
if (!m_dev) {
return false;
}
if (m_running) stop();
if (m_running) {
stop();
}
qDebug() << "FCDProPlusInput::start";
@@ -105,13 +111,23 @@ bool FCDProPlusInput::start()
//applySettings(m_settings, true);
if(!m_sampleFifo.setSize(96000*4))
if (!m_sampleFifo.setSize(96000*4))
{
qCritical("Could not allocate SampleFifo");
qCritical("FCDProPlusInput::start: could not allocate SampleFifo");
return false;
}
m_FCDThread = new FCDProPlusThread(&m_sampleFifo);
if (!openFCDAudio(fcd_traits<ProPlus>::qtDeviceName))
{
qCritical("FCDProPlusInput::start: could not open FCD audio source");
return false;
}
else
{
qDebug("FCDProPlusInput::start: FCD audio source opened");
}
m_FCDThread = new FCDProPlusThread(&m_sampleFifo, &m_fcdFIFO);
m_FCDThread->startWork();
// mutexLocker.unlock();
@@ -133,6 +149,35 @@ void FCDProPlusInput::closeDevice()
m_dev = 0;
}
bool FCDProPlusInput::openFCDAudio(const char* cardname)
{
AudioDeviceManager *audioDeviceManager = DSPEngine::instance()->getAudioDeviceManager();
const QList<QAudioDeviceInfo>& audioList = audioDeviceManager->getInputDevices();
for (const auto &itAudio : audioList)
{
if (itAudio.deviceName().contains(QString(cardname)))
{
int fcdDeviceIndex = audioDeviceManager->getInputDeviceIndex(itAudio.deviceName());
m_fcdAudioInput.start(fcdDeviceIndex, fcd_traits<ProPlus>::sampleRate);
int fcdSampleRate = m_fcdAudioInput.getRate();
qDebug("FCDProPlusInput::openFCDAudio: %s index %d at %d S/s",
itAudio.deviceName().toStdString().c_str(), fcdDeviceIndex, fcdSampleRate);
m_fcdAudioInput.addFifo(&m_fcdFIFO);
return true;
}
}
qCritical("FCDProPlusInput::openFCDAudio: device with name %s not found", cardname);
return false;
}
void FCDProPlusInput::closeFCDAudio()
{
m_fcdAudioInput.removeFifo(&m_fcdFIFO);
m_fcdAudioInput.stop();
}
void FCDProPlusInput::stop()
{
QMutexLocker mutexLocker(&m_mutex);
@@ -142,7 +187,8 @@ void FCDProPlusInput::stop()
m_FCDThread->stopWork();
// wait for thread to quit ?
delete m_FCDThread;
m_FCDThread = 0;
m_FCDThread = nullptr;
closeFCDAudio();
}
m_running = false;
@@ -217,7 +263,7 @@ bool FCDProPlusInput::handleMessage(const Message& message)
else if (MsgStartStop::match(message))
{
MsgStartStop& cmd = (MsgStartStop&) message;
qDebug() << "BladerfInput::handleMessage: MsgStartStop: " << (cmd.getStartStop() ? "start" : "stop");
qDebug() << "FCDProPlusInput::handleMessage: MsgStartStop: " << (cmd.getStartStop() ? "start" : "stop");
if (cmd.getStartStop())
{
@@ -460,8 +506,9 @@ void FCDProPlusInput::set_lo_ppm()
int FCDProPlusInput::webapiRunGet(
SWGSDRangel::SWGDeviceState& response,
QString& errorMessage __attribute__((unused)))
QString& errorMessage)
{
(void) errorMessage;
m_deviceAPI->getDeviceEngineStateStr(*response.getState());
return 200;
}
@@ -469,8 +516,9 @@ int FCDProPlusInput::webapiRunGet(
int FCDProPlusInput::webapiRun(
bool run,
SWGSDRangel::SWGDeviceState& response,
QString& errorMessage __attribute__((unused)))
QString& errorMessage)
{
(void) errorMessage;
m_deviceAPI->getDeviceEngineStateStr(*response.getState());
MsgStartStop *message = MsgStartStop::create(run);
m_inputMessageQueue.push(message);
@@ -486,8 +534,9 @@ int FCDProPlusInput::webapiRun(
int FCDProPlusInput::webapiSettingsGet(
SWGSDRangel::SWGDeviceSettings& response,
QString& errorMessage __attribute__((unused)))
QString& errorMessage)
{
(void) errorMessage;
response.setFcdProPlusSettings(new SWGSDRangel::SWGFCDProPlusSettings());
response.getFcdProPlusSettings()->init();
webapiFormatDeviceSettings(response, m_settings);
@@ -498,8 +547,9 @@ int FCDProPlusInput::webapiSettingsPutPatch(
bool force,
const QStringList& deviceSettingsKeys,
SWGSDRangel::SWGDeviceSettings& response, // query + response
QString& errorMessage __attribute__((unused)))
QString& errorMessage)
{
(void) errorMessage;
FCDProPlusSettings settings = m_settings;
if (deviceSettingsKeys.contains("centerFrequency")) {
@@ -1,5 +1,5 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2016 Edouard Griffiths, F4EXB //
// Copyright (C) 2016-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 //
@@ -21,7 +21,10 @@
#include <QByteArray>
#include <inttypes.h>
#include <dsp/devicesamplesource.h>
#include "dsp/devicesamplesource.h"
#include "audio/audioinput.h"
#include "audio/audiofifo.h"
#include "fcdproplussettings.h"
#include "fcdhid.h"
@@ -147,11 +150,15 @@ public:
private:
bool openDevice();
void closeDevice();
bool openFCDAudio(const char *filename);
void closeFCDAudio();
void applySettings(const FCDProPlusSettings& settings, bool force);
void webapiFormatDeviceSettings(SWGSDRangel::SWGDeviceSettings& response, const FCDProPlusSettings& settings);
DeviceSourceAPI *m_deviceAPI;
hid_device *m_dev;
AudioInput m_fcdAudioInput;
AudioFifo m_fcdFIFO;
QMutex m_mutex;
FCDProPlusSettings m_settings;
FCDProPlusThread* m_FCDThread;
@@ -1,321 +0,0 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2016 Edouard Griffiths, F4EXB //
// //
// This is a pure Qt (non ALSA) FCD sound card reader for Windows build //
// //
// 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 <QDebug>
#include <string.h>
#include <errno.h>
#include "dsp/dspcommands.h"
#include "dsp/dspengine.h"
#include "fcdproplusinputqt.h"
#include "fcdproplusgui.h"
#include "fcdproplusreader.h"
#include "fcdtraits.h"
#include "fcdproplusconst.h"
MESSAGE_CLASS_DEFINITION(FCDProPlusInput::MsgConfigureFCDProPlus, Message)
FCDProPlusInput::FCDProPlusInput() :
m_dev(0),
m_settings(),
m_deviceDescription(fcd_traits<ProPlus>::displayedName),
m_FCDThread(0),
m_running(false),
m_deviceAPI(0)
{
m_FCDReader = new FCDProPlusReader(&m_sampleFifo);
}
FCDProPlusInput::~FCDProPlusInput()
{
stop();
delete m_FCDReader;
}
bool FCDProPlusInput::init(const Message& cmd)
{
return false;
}
bool FCDProPlusInput::start(int device)
{
qDebug() << "FCDProPlusInput::start with device #" << device;
QMutexLocker mutexLocker(&m_mutex);
m_dev = fcdOpen(fcd_traits<ProPlus>::vendorId, fcd_traits<ProPlus>::productId, device);
if (m_dev == 0)
{
qCritical("FCDProPlusInput::start: could not open FCD");
return false;
}
/* Apply settings before streaming to avoid bus contention;
* there is very little spare bandwidth on a full speed USB device.
* Failure is harmless if no device is found
* ... This is rubbish...*/
//applySettings(m_settings, true);
if(!m_sampleFifo.setSize(96000*4))
{
qCritical("Could not allocate SampleFifo");
return false;
}
m_FCDReader->startWork();
mutexLocker.unlock();
applySettings(m_settings, true);
qDebug("FCDProPlusInput::started");
return true;
}
void FCDProPlusInput::stop()
{
QMutexLocker mutexLocker(&m_mutex);
m_FCDReader->stopWork();
fcdClose(m_dev);
m_dev = 0;
}
const QString& FCDProPlusInput::getDeviceDescription() const
{
return m_deviceDescription;
}
int FCDProPlusInput::getSampleRate() const
{
return fcd_traits<ProPlus>::sampleRate;
}
quint64 FCDProPlusInput::getCenterFrequency() const
{
return m_settings.m_centerFrequency;
}
bool FCDProPlusInput::handleMessage(const Message& message)
{
if(MsgConfigureFCDProPlus::match(message))
{
qDebug() << "FCDProPlusInput::handleMessage: MsgConfigureFCD";
MsgConfigureFCDProPlus& conf = (MsgConfigureFCDProPlus&) message;
applySettings(conf.getSettings(), false);
return true;
}
else
{
return false;
}
}
void FCDProPlusInput::applySettings(const FCDProPlusSettings& settings, bool force)
{
bool signalChange = false;
if ((m_settings.m_centerFrequency != settings.m_centerFrequency) || force)
{
qDebug() << "FCDProPlusInput::applySettings: fc: " << settings.m_centerFrequency;
m_settings.m_centerFrequency = settings.m_centerFrequency;
if (m_dev != 0)
{
set_center_freq((double) m_settings.m_centerFrequency);
}
signalChange = true;
}
if ((m_settings.m_lnaGain != settings.m_lnaGain) || force)
{
m_settings.m_lnaGain = settings.m_lnaGain;
if (m_dev != 0)
{
set_lna_gain(settings.m_lnaGain);
}
}
if ((m_settings.m_biasT != settings.m_biasT) || force)
{
m_settings.m_biasT = settings.m_biasT;
if (m_dev != 0)
{
set_bias_t(settings.m_biasT);
}
}
if ((m_settings.m_mixGain != settings.m_mixGain) || force)
{
m_settings.m_mixGain = settings.m_mixGain;
if (m_dev != 0)
{
set_mixer_gain(settings.m_mixGain);
}
}
if ((m_settings.m_ifGain != settings.m_ifGain) || force)
{
m_settings.m_ifGain = settings.m_ifGain;
if (m_dev != 0)
{
set_if_gain(settings.m_ifGain);
}
}
if ((m_settings.m_ifFilterIndex != settings.m_ifFilterIndex) || force)
{
m_settings.m_ifFilterIndex = settings.m_ifFilterIndex;
if (m_dev != 0)
{
set_if_filter(settings.m_ifFilterIndex);
}
}
if ((m_settings.m_rfFilterIndex != settings.m_rfFilterIndex) || force)
{
m_settings.m_rfFilterIndex = settings.m_rfFilterIndex;
if (m_dev != 0)
{
set_rf_filter(settings.m_rfFilterIndex);
}
}
if ((m_settings.m_LOppmTenths != settings.m_LOppmTenths) || force)
{
m_settings.m_LOppmTenths = settings.m_LOppmTenths;
if (m_dev != 0)
{
set_lo_ppm();
}
}
if ((m_settings.m_dcBlock != settings.m_dcBlock) || force)
{
m_settings.m_dcBlock = settings.m_dcBlock;
DSPEngine::instance()->configureCorrections(m_settings.m_dcBlock, m_settings.m_iqImbalance);
}
if ((m_settings.m_iqImbalance != settings.m_iqImbalance) || force)
{
m_settings.m_iqImbalance = settings.m_iqImbalance;
DSPEngine::instance()->configureCorrections(m_settings.m_dcBlock, m_settings.m_iqImbalance);
}
if (signalChange)
{
DSPSignalNotification *notif = new DSPSignalNotification(fcd_traits<ProPlus>::sampleRate, m_settings.m_centerFrequency);
DSPEngine::instance()->getInputMessageQueue()->push(notif);
}
}
void FCDProPlusInput::set_center_freq(double freq)
{
freq += freq*(((double) m_settings.m_LOppmTenths)/10000000.0);
if (fcdAppSetFreq(m_dev, freq) == FCD_MODE_NONE)
{
qDebug("No FCD HID found for frquency change");
}
}
void FCDProPlusInput::set_bias_t(bool on)
{
quint8 cmd = on ? 1 : 0;
fcdAppSetParam(m_dev, FCDPROPLUS_HID_CMD_SET_BIAS_TEE, &cmd, 1);
}
void FCDProPlusInput::set_lna_gain(bool on)
{
quint8 cmd = on ? 1 : 0;
fcdAppSetParam(m_dev, FCDPROPLUS_HID_CMD_SET_LNA_GAIN, &cmd, 1);
}
void FCDProPlusInput::set_mixer_gain(bool on)
{
quint8 cmd = on ? 1 : 0;
fcdAppSetParam(m_dev, FCDPROPLUS_HID_CMD_SET_MIXER_GAIN, &cmd, 1);
}
void FCDProPlusInput::set_if_gain(int gain)
{
if (gain < 0)
{
return;
}
quint8 cmd_value = gain;
if (fcdAppSetParam(m_dev, FCDPROPLUS_HID_CMD_SET_IF_GAIN, &cmd_value, 1) != FCD_MODE_APP)
{
qWarning() << "FCDProPlusInput::set_if_gain: failed to set at " << cmd_value;
}
}
void FCDProPlusInput::set_if_filter(int filterIndex)
{
if ((filterIndex < 0) || (filterIndex >= FCDProPlusConstants::fcdproplus_if_filter_nb_values()))
{
return;
}
quint8 cmd_value = FCDProPlusConstants::if_filters[filterIndex].value;
if (fcdAppSetParam(m_dev, FCDPROPLUS_HID_CMD_SET_IF_FILTER, &cmd_value, 1) != FCD_MODE_APP)
{
qWarning() << "FCDProPlusInput::set_if_filter: failed to set at " << cmd_value;
}
}
void FCDProPlusInput::set_rf_filter(int filterIndex)
{
if ((filterIndex < 0) || (filterIndex >= FCDProPlusConstants::fcdproplus_rf_filter_nb_values()))
{
return;
}
quint8 cmd_value = FCDProPlusConstants::rf_filters[filterIndex].value;
if (fcdAppSetParam(m_dev, FCDPROPLUS_HID_CMD_SET_RF_FILTER, &cmd_value, 1) != FCD_MODE_APP)
{
qWarning() << "FCDProPlusInput::set_rf_filter: failed to set at " << cmd_value;
}
}
void FCDProPlusInput::set_lo_ppm()
{
set_center_freq((double) m_settings.m_centerFrequency);
}
@@ -1,90 +0,0 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2016 Edouard Griffiths, F4EXB //
// //
// This is a pure Qt (non ALSA) FCD sound card reader for Windows build //
// //
// 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 INCLUDE_FCDINPUT_H
#define INCLUDE_FCDINPUT_H
#include <dsp/devicesamplesource.h>
#include "fcdproplussettings.h"
#include "fcdhid.h"
#include <QString>
#include <inttypes.h>
struct fcd_buffer {
void *start;
std::size_t length;
};
class FCDProPlusReader;
class FCDProPlusInput : public DeviceSampleSource {
public:
class MsgConfigureFCDProPlus : public Message {
MESSAGE_CLASS_DECLARATION
public:
const FCDProPlusSettings& getSettings() const { return m_settings; }
static MsgConfigureFCDProPlus* create(const FCDProPlusSettings& settings)
{
return new MsgConfigureFCDProPlus(settings);
}
private:
FCDProPlusSettings m_settings;
MsgConfigureFCD(const FCDProPlusSettings& settings) :
Message(),
m_settings(settings)
{ }
};
FCDProPlusInput();
virtual ~FCDProPlusInput();
virtual bool init(const Message& cmd);
virtual bool start(int device);
virtual void stop();
virtual const QString& getDeviceDescription() const;
virtual int getSampleRate() const;
virtual quint64 getCenterFrequency() const;
virtual bool handleMessage(const Message& message);
void set_center_freq(double freq);
void set_bias_t(bool on);
void set_lna_gain(bool on);
void set_mixer_gain(bool on);
void set_if_gain(int gain);
void set_rf_filter(int filterIndex);
void set_if_filter(int filterIndex);
void set_lo_ppm();
private:
void applySettings(const FCDProPlusSettings& settings, bool force);
hid_device *m_dev;
QMutex m_mutex;
FCDProPlusSettings m_settings;
FCDProPlusReader* m_FCDReader;
QString m_deviceDescription;
};
#endif // INCLUDE_FCD_H
@@ -1,146 +0,0 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2016 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 <QDebug>
#include <QAudio>
#include <QAudioDeviceInfo>
#include <QAudioInput>
#include <QAudioFormat>
#include <QIODevice>
#include <QList>
#include <stdio.h>
#include <errno.h>
#include "fcdproplusreader.h"
#include "dsp/samplesinkfifo.h"
#include "fcdtraits.h"
FCDProPlusReader::FCDProPlusReader(SampleSinkFifo* sampleFifo, QObject* parent) :
QObject(parent),
m_fcdAudioInput(0),
m_fcdInput(0),
m_running(false),
m_convertBuffer(fcd_traits<ProPlus>::convBufSize),
m_fcdBuffer(fcd_traits<ProPlus>::fcdBufSize, 0),
m_sampleFifo(sampleFifo)
{
}
FCDProPlusReader::~FCDProPlusReader()
{
if (m_fcdAudioInput) {
delete m_fcdAudioInput;
}
}
void FCDProPlusReader::startWork()
{
QList<QAudioDeviceInfo> audioDevices = QAudioDeviceInfo::availableDevices(QAudio::AudioInput);
QList<QAudioDeviceInfo>::iterator audioDeviceIt, fcdDeviceIt = audioDevices.end();
for (audioDeviceIt = audioDevices.begin(); audioDeviceIt != audioDevices.end(); ++audioDeviceIt)
{
QAudioFormat fcdAudioFormat = audioDeviceIt->preferredFormat();
int sampleRate = fcdAudioFormat.sampleRate();
int sampleBits = fcdAudioFormat.sampleSize();
if ((sampleRate == 192000) && (sampleBits == 16))
{
qDebug() << "FCDProPlusReader::startWork: found: " << audioDeviceIt->deviceName()
<< " sampleRate: " << fcdAudioFormat.sampleRate()
<< " sampleBits: " << fcdAudioFormat.sampleSize();
fcdDeviceIt = audioDeviceIt;
break;
}
}
if (fcdDeviceIt == audioDevices.end())
{
qCritical() << "FCDProPlusReader::startWork: FCD Pro+ sound card not found";
return;
}
openFcdAudio(*fcdDeviceIt);
if (!m_fcdAudioInput)
{
qCritical() << "FCDProPlusReader::startWork: cannot open FCD Pro+ sound card";
return;
}
m_fcdAudioInput->stop();
m_fcdInput = m_fcdAudioInput->start();
if (!m_fcdInput)
{
qCritical() << "FCDProPlusReader::startWork: cannot start FCD Pro+ sound card";
return;
}
connect(m_fcdInput, SIGNAL(readyRead()), this, SLOT(readFcdAudio()));
m_running = true;
qDebug() << "FCDProPlusReader::startWork: started";
}
void FCDProPlusReader::stopWork()
{
m_running = false;
disconnect(m_fcdInput, SIGNAL(readyRead()), this, SLOT(readFcdAudio()));
m_fcdAudioInput->stop();
qDebug() << "FCDProPlusReader::stopWork: stopped";
}
void FCDProPlusReader::openFcdAudio(const QAudioDeviceInfo& fcdAudioDeviceInfo)
{
QAudioFormat fcdAudioFormat = fcdAudioDeviceInfo.preferredFormat();
qDebug() << "FCDProPlusReader::openFcdAudio: device: " << fcdAudioDeviceInfo.deviceName()
<< " sampleRate: " << fcdAudioFormat.sampleRate()
<< " sampleBits: " << fcdAudioFormat.sampleSize();
m_fcdAudioInput = new QAudioInput(fcdAudioDeviceInfo, fcdAudioFormat, this);
//m_fcdAudioInput->setBufferSize(1<<14);
//m_fcdAudioInput->setNotifyInterval(50);
}
void FCDProPlusReader::readFcdAudio()
{
if (!m_fcdAudioInput) {
return;
}
int len = m_fcdAudioInput->bytesReady();
// qDebug() << "FCDProPlusReader::readFcdAudio:"
// << " buffer size: " << m_fcdAudioInput->bufferSize()
// << " interval: " << m_fcdAudioInput->notifyInterval()
// << " len: " << len;
if (len > fcd_traits<ProPlus>::fcdBufSize) {
len = fcd_traits<ProPlus>::fcdBufSize;
}
int readLen = m_fcdInput->read(m_fcdBuffer.data(), len);
if (readLen > 0) {
m_sampleFifo->write((const quint8*) m_fcdBuffer.constData(), (uint) readLen);
}
}
@@ -1,59 +0,0 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2016 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 INCLUDE_FCDPROPLUSREADER_H
#define INCLUDE_FCDPROPLUSREADER_H
#include <QObject>
#include <QMutex>
#include <QWaitCondition>
#include <QByteArray>
#include "dsp/samplesinkfifo.h"
#include "dsp/inthalfbandfilter.h"
class QAudioInput;
class QIODevice;
class QAudioDeviceInfo;
class FCDProPlusReader : public QObject {
Q_OBJECT
public:
FCDProPlusReader(SampleSinkFifo* sampleFifo, QObject* parent = NULL);
~FCDProPlusReader();
void startWork();
void stopWork();
private:
QAudioInput *m_fcdAudioInput;
QIODevice *m_fcdInput;
QMutex m_startWaitMutex;
QWaitCondition m_startWaiter;
bool m_running;
SampleVector m_convertBuffer;
QByteArray m_fcdBuffer;
SampleSinkFifo* m_sampleFifo;
void openFcdAudio(const QAudioDeviceInfo& fcdAudioDeviceInfo);
private slots:
void readFcdAudio();
};
#endif // INCLUDE_FCDPROPLUSREADER_H
@@ -1,6 +1,5 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2012 maintech GmbH, Otto-Hahn-Str. 15, 97204 Hoechberg, Germany //
// written by Christian Daniel //
// Copyright (C) 2016-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 //
@@ -18,16 +17,19 @@
#include <QDebug>
#include <stdio.h>
#include <errno.h>
#include "fcdproplusthread.h"
#include <chrono>
#include <thread>
#include "dsp/samplesinkfifo.h"
#include "fcdtraits.h"
#include "audio/audiofifo.h"
FCDProPlusThread::FCDProPlusThread(SampleSinkFifo* sampleFifo, QObject* parent) :
#include "fcdproplusthread.h"
FCDProPlusThread::FCDProPlusThread(SampleSinkFifo* sampleFifo, AudioFifo *fcdFIFO, QObject* parent) :
QThread(parent),
fcd_handle(NULL),
m_fcdFIFO(fcdFIFO),
m_running(false),
m_convertBuffer(fcd_traits<ProPlus>::convBufSize),
m_convertBuffer(fcd_traits<ProPlus>::convBufSize), // nb samples
m_sampleFifo(sampleFifo)
{
start();
@@ -59,107 +61,23 @@ void FCDProPlusThread::stopWork()
void FCDProPlusThread::run()
{
if ( !OpenSource(fcd_traits<ProPlus>::alsaDeviceName) )
{
qCritical() << "FCDThread::run: cannot open FCD sound card";
return;
}
// TODO: fallback to original fcd
m_running = true;
qDebug("FCDThread::run: start running loop");
while(m_running)
while (m_running)
{
if (work(fcd_traits<ProPlus>::convBufSize) < 0)
{
break;
}
work(fcd_traits<ProPlus>::convBufSize);
std::this_thread::sleep_for(std::chrono::microseconds(100));
}
CloseSource();
qDebug("FCDThread::run: running loop stopped");
m_running = false;
}
bool FCDProPlusThread::OpenSource(const char* cardname)
void FCDProPlusThread::work(unsigned int n_items)
{
bool fail = false;
snd_pcm_hw_params_t* params;
//fcd_rate = FCDPP_RATE;
//fcd_channels =2;
//fcd_format = SND_PCM_SFMT_U16_LE;
snd_pcm_stream_t fcd_stream = SND_PCM_STREAM_CAPTURE;
if (fcd_handle)
{
return false;
}
if (snd_pcm_open(&fcd_handle, cardname, fcd_stream, 0) < 0)
{
qCritical("FCDThread::OpenSource: cannot open %s", cardname);
return false;
}
snd_pcm_hw_params_alloca(&params);
if (snd_pcm_hw_params_any(fcd_handle, params) < 0)
{
qCritical("FCDProPlusThread::OpenSource: snd_pcm_hw_params_any failed");
fail = true;
}
else if (snd_pcm_hw_params(fcd_handle, params) < 0)
{
qCritical("FCDProPlusThread::OpenSource: snd_pcm_hw_params failed");
fail = true;
// TODO: check actual samplerate, may be crippled firmware
}
else
{
if (snd_pcm_start(fcd_handle) < 0)
{
qCritical("FCDProPlusThread::OpenSource: snd_pcm_start failed");
fail = true;
}
}
if (fail)
{
snd_pcm_close( fcd_handle );
return false;
}
else
{
qDebug("FCDProPlusThread::OpenSource: Funcube stream started");
}
return true;
uint32_t nbRead = m_fcdFIFO->read((unsigned char *) m_buf, n_items); // number of samples
SampleVector::iterator it = m_convertBuffer.begin();
m_decimators.decimate1(&it, m_buf, 2*nbRead);
m_sampleFifo->write(m_convertBuffer.begin(), it);
}
void FCDProPlusThread::CloseSource()
{
if (fcd_handle)
{
snd_pcm_close( fcd_handle );
}
fcd_handle = NULL;
}
int FCDProPlusThread::work(int n_items)
{
int l;
SampleVector::iterator it;
void *out;
it = m_convertBuffer.begin();
out = (void *)&it[0];
l = snd_pcm_mmap_readi(fcd_handle, out, (snd_pcm_uframes_t)n_items);
if (l > 0)
m_sampleFifo->write(it, it + l);
if (l == -EPIPE) {
qDebug("FCDProPlusThread::work: Overrun detected");
return 0;
}
return l;
}
@@ -21,33 +21,36 @@
#include <QThread>
#include <QMutex>
#include <QWaitCondition>
#include "dsp/inthalfbandfilter.h"
#include <alsa/asoundlib.h>
#include "dsp/samplesinkfifo.h"
#include "dsp/decimators.h"
#include "fcdtraits.h"
class AudioFifo;
class FCDProPlusThread : public QThread {
Q_OBJECT
public:
FCDProPlusThread(SampleSinkFifo* sampleFifo, QObject* parent = NULL);
FCDProPlusThread(SampleSinkFifo* sampleFifo, AudioFifo *fcdFIFO, QObject* parent = nullptr);
~FCDProPlusThread();
void startWork();
void stopWork();
bool OpenSource(const char *filename);
void CloseSource();
private:
snd_pcm_t* fcd_handle;
AudioFifo* m_fcdFIFO;
QMutex m_startWaitMutex;
QWaitCondition m_startWaiter;
bool m_running;
qint16 m_buf[fcd_traits<ProPlus>::convBufSize*2]; // stereo (I, Q)
SampleVector m_convertBuffer;
SampleSinkFifo* m_sampleFifo;
Decimators<qint32, qint16, SDR_RX_SAMP_SZ, 16> m_decimators;
void run();
int work(int n_items);
void work(unsigned int n_items);
};
#endif // INCLUDE_FCDTHREAD_H
@@ -310,8 +310,9 @@ void FileSourceGui::on_navTimeSlider_valueChanged(int value)
}
}
void FileSourceGui::on_showFileDialog_clicked(bool checked __attribute__((unused)))
void FileSourceGui::on_showFileDialog_clicked(bool checked)
{
(void) checked;
QString fileName = QFileDialog::getOpenFileName(this,
tr("Open I/Q record file"), ".", tr("SDR I/Q Files (*.sdriq)"), 0, QFileDialog::DontUseNativeDialog);
@@ -409,8 +409,9 @@ bool FileSourceInput::applySettings(const FileSourceSettings& settings, bool for
int FileSourceInput::webapiSettingsGet(
SWGSDRangel::SWGDeviceSettings& response,
QString& errorMessage __attribute__((unused)))
QString& errorMessage)
{
(void) errorMessage;
response.setFileSourceSettings(new SWGSDRangel::SWGFileSourceSettings());
response.getFileSourceSettings()->init();
webapiFormatDeviceSettings(response, m_settings);
@@ -421,8 +422,9 @@ int FileSourceInput::webapiSettingsPutPatch(
bool force,
const QStringList& deviceSettingsKeys,
SWGSDRangel::SWGDeviceSettings& response, // query + response
QString& errorMessage __attribute__((unused)))
QString& errorMessage)
{
(void) errorMessage;
FileSourceSettings settings = m_settings;
if (deviceSettingsKeys.contains("fileName")) {
@@ -450,8 +452,9 @@ int FileSourceInput::webapiSettingsPutPatch(
int FileSourceInput::webapiRunGet(
SWGSDRangel::SWGDeviceState& response,
QString& errorMessage __attribute__((unused)))
QString& errorMessage)
{
(void) errorMessage;
m_deviceAPI->getDeviceEngineStateStr(*response.getState());
return 200;
}
@@ -459,8 +462,9 @@ int FileSourceInput::webapiRunGet(
int FileSourceInput::webapiRun(
bool run,
SWGSDRangel::SWGDeviceState& response,
QString& errorMessage __attribute__((unused)))
QString& errorMessage)
{
(void) errorMessage;
m_deviceAPI->getDeviceEngineStateStr(*response.getState());
MsgStartStop *message = MsgStartStop::create(run);
m_inputMessageQueue.push(message);
@@ -476,8 +480,9 @@ int FileSourceInput::webapiRun(
int FileSourceInput::webapiReportGet(
SWGSDRangel::SWGDeviceReport& response,
QString& errorMessage __attribute__((unused)))
QString& errorMessage)
{
(void) errorMessage;
response.setFileSourceReport(new SWGSDRangel::SWGFileSourceReport());
response.getFileSourceReport()->init();
webapiFormatDeviceReport(response);
@@ -103,7 +103,7 @@ int FileSourceSettings::getAccelerationValue(int accelerationIndex)
unsigned int v = accelerationIndex - 1;
int m = pow(10.0, v/3 > m_accelerationMaxScale ? m_accelerationMaxScale : v/3);
int x;
int x = 1;
if (v % 3 == 0) {
x = 2;
@@ -528,8 +528,9 @@ bool HackRFInput::applySettings(const HackRFInputSettings& settings, bool force)
int HackRFInput::webapiSettingsGet(
SWGSDRangel::SWGDeviceSettings& response,
QString& errorMessage __attribute__((unused)))
QString& errorMessage)
{
(void) errorMessage;
response.setHackRfInputSettings(new SWGSDRangel::SWGHackRFInputSettings());
response.getHackRfInputSettings()->init();
webapiFormatDeviceSettings(response, m_settings);
@@ -540,8 +541,9 @@ int HackRFInput::webapiSettingsPutPatch(
bool force,
const QStringList& deviceSettingsKeys,
SWGSDRangel::SWGDeviceSettings& response, // query + response
QString& errorMessage __attribute__((unused)))
QString& errorMessage)
{
(void) errorMessage;
HackRFInputSettings settings = m_settings;
if (deviceSettingsKeys.contains("centerFrequency")) {
@@ -628,8 +630,9 @@ void HackRFInput::webapiFormatDeviceSettings(SWGSDRangel::SWGDeviceSettings& res
int HackRFInput::webapiRunGet(
SWGSDRangel::SWGDeviceState& response,
QString& errorMessage __attribute__((unused)))
QString& errorMessage)
{
(void) errorMessage;
m_deviceAPI->getDeviceEngineStateStr(*response.getState());
return 200;
}
@@ -637,8 +640,9 @@ int HackRFInput::webapiRunGet(
int HackRFInput::webapiRun(
bool run,
SWGSDRangel::SWGDeviceState& response,
QString& errorMessage __attribute__((unused)))
QString& errorMessage)
{
(void) errorMessage;
m_deviceAPI->getDeviceEngineStateStr(*response.getState());
MsgStartStop *message = MsgStartStop::create(run);
m_inputMessageQueue.push(message);
@@ -19,6 +19,8 @@ QMAKE_CXXFLAGS += -std=c++11
CONFIG(MINGW32):LIBHACKRFSRC = "C:\softs\hackrf\host"
CONFIG(MINGW64):LIBHACKRFSRC = "C:\softs\hackrf\host"
CONFIG(MSVC):LIBHACKRFSRC = "C:\softs\hackrf\host"
INCLUDEPATH += $$PWD
INCLUDEPATH += ../../../exports
INCLUDEPATH += ../../../sdrbase
@@ -18,7 +18,6 @@
#include <stdio.h>
#include <errno.h>
#include <unistd.h>
#include <algorithm>
#include "dsp/samplesinkfifo.h"
@@ -615,6 +615,17 @@ bool LimeSDRInput::handleMessage(const Message& message)
return true;
}
else if (DeviceLimeSDRShared::MsgReportGPIOChange::match(message))
{
DeviceLimeSDRShared::MsgReportGPIOChange& report = (DeviceLimeSDRShared::MsgReportGPIOChange&) message;
m_settings.m_gpioDir = report.getGPIODir();
m_settings.m_gpioPins = report.getGPIOPins();
// no GUI for the moment only REST API
return true;
}
else if (MsgGetStreamInfo::match(message))
{
// qDebug() << "LimeSDRInput::handleMessage: MsgGetStreamInfo";
@@ -660,19 +671,24 @@ bool LimeSDRInput::handleMessage(const Message& message)
else if (MsgGetDeviceInfo::match(message))
{
double temp = 0.0;
uint8_t gpioPins = 0;
if (m_deviceShared.m_deviceParams->getDevice() && (LMS_GetChipTemperature(m_deviceShared.m_deviceParams->getDevice(), 0, &temp) == 0))
{
//qDebug("LimeSDRInput::handleMessage: MsgGetDeviceInfo: temperature: %f", temp);
}
else
{
if (m_deviceShared.m_deviceParams->getDevice() && (LMS_GetChipTemperature(m_deviceShared.m_deviceParams->getDevice(), 0, &temp) != 0)) {
qDebug("LimeSDRInput::handleMessage: MsgGetDeviceInfo: cannot get temperature");
}
if ((m_deviceShared.m_deviceParams->m_type != DeviceLimeSDRParams::LimeMini)
&& (m_deviceShared.m_deviceParams->m_type != DeviceLimeSDRParams::LimeUndefined))
{
if (m_deviceShared.m_deviceParams->getDevice() && (LMS_GPIORead(m_deviceShared.m_deviceParams->getDevice(), &gpioPins, 1) != 0)) {
qDebug("LimeSDROutput::handleMessage: MsgGetDeviceInfo: cannot get GPIO pins values");
}
}
// send to oneself
if (m_deviceAPI->getSampleSourceGUIMessageQueue()) {
DeviceLimeSDRShared::MsgReportDeviceInfo *report = DeviceLimeSDRShared::MsgReportDeviceInfo::create(temp);
if (m_deviceAPI->getSampleSourceGUIMessageQueue())
{
DeviceLimeSDRShared::MsgReportDeviceInfo *report = DeviceLimeSDRShared::MsgReportDeviceInfo::create(temp, gpioPins);
m_deviceAPI->getSampleSourceGUIMessageQueue()->push(report);
}
@@ -684,7 +700,7 @@ bool LimeSDRInput::handleMessage(const Message& message)
{
if ((*itSource)->getSampleSourceGUIMessageQueue())
{
DeviceLimeSDRShared::MsgReportDeviceInfo *report = DeviceLimeSDRShared::MsgReportDeviceInfo::create(temp);
DeviceLimeSDRShared::MsgReportDeviceInfo *report = DeviceLimeSDRShared::MsgReportDeviceInfo::create(temp, gpioPins);
(*itSource)->getSampleSourceGUIMessageQueue()->push(report);
}
}
@@ -697,7 +713,7 @@ bool LimeSDRInput::handleMessage(const Message& message)
{
if ((*itSink)->getSampleSinkGUIMessageQueue())
{
DeviceLimeSDRShared::MsgReportDeviceInfo *report = DeviceLimeSDRShared::MsgReportDeviceInfo::create(temp);
DeviceLimeSDRShared::MsgReportDeviceInfo *report = DeviceLimeSDRShared::MsgReportDeviceInfo::create(temp, gpioPins);
(*itSink)->getSampleSinkGUIMessageQueue()->push(report);
}
}
@@ -757,6 +773,7 @@ bool LimeSDRInput::applySettings(const LimeSDRInputSettings& settings, bool forc
bool forwardChangeRxDSP = false;
bool forwardChangeAllDSP = false;
bool forwardClockSource = false;
bool forwardGPIOChange = false;
bool ownThreadWasRunning = false;
bool doCalibration = false;
bool doLPCalibration = false;
@@ -1093,6 +1110,36 @@ bool LimeSDRInput::applySettings(const LimeSDRInputSettings& settings, bool forc
}
}
if ((m_deviceShared.m_deviceParams->m_type != DeviceLimeSDRParams::LimeMini)
&& (m_deviceShared.m_deviceParams->m_type != DeviceLimeSDRParams::LimeUndefined))
{
if ((m_settings.m_gpioDir != settings.m_gpioDir) || force)
{
if (LMS_GPIODirWrite(m_deviceShared.m_deviceParams->getDevice(), &settings.m_gpioDir, 1) != 0)
{
qCritical("LimeSDROutput::applySettings: could not set GPIO directions to %u", settings.m_gpioDir);
}
else
{
forwardGPIOChange = true;
qDebug("LimeSDROutput::applySettings: GPIO directions set to %u", settings.m_gpioDir);
}
}
if ((m_settings.m_gpioPins != settings.m_gpioPins) || force)
{
if (LMS_GPIOWrite(m_deviceShared.m_deviceParams->getDevice(), &settings.m_gpioPins, 1) != 0)
{
qCritical("LimeSDROutput::applySettings: could not set GPIO pins to %u", settings.m_gpioPins);
}
else
{
forwardGPIOChange = true;
qDebug("LimeSDROutput::applySettings: GPIO pins set to %u", settings.m_gpioPins);
}
}
}
m_settings = settings;
double clockGenFreqAfter;
@@ -1250,6 +1297,31 @@ bool LimeSDRInput::applySettings(const LimeSDRInputSettings& settings, bool forc
}
}
if (forwardGPIOChange)
{
// send to source buddies
const std::vector<DeviceSourceAPI*>& sourceBuddies = m_deviceAPI->getSourceBuddies();
std::vector<DeviceSourceAPI*>::const_iterator itSource = sourceBuddies.begin();
for (; itSource != sourceBuddies.end(); ++itSource)
{
DeviceLimeSDRShared::MsgReportClockSourceChange *report = DeviceLimeSDRShared::MsgReportClockSourceChange::create(
m_settings.m_extClock, m_settings.m_extClockFreq);
(*itSource)->getSampleSourceInputMessageQueue()->push(report);
}
// send to sink buddies
const std::vector<DeviceSinkAPI*>& sinkBuddies = m_deviceAPI->getSinkBuddies();
std::vector<DeviceSinkAPI*>::const_iterator itSink = sinkBuddies.begin();
for (; itSink != sinkBuddies.end(); ++itSink)
{
DeviceLimeSDRShared::MsgReportClockSourceChange *report = DeviceLimeSDRShared::MsgReportClockSourceChange::create(
m_settings.m_extClock, m_settings.m_extClockFreq);
(*itSink)->getSampleSinkInputMessageQueue()->push(report);
}
}
QLocale loc;
qDebug().noquote() << "LimeSDRInput::applySettings: center freq: " << m_settings.m_centerFrequency << " Hz"
@@ -1270,6 +1342,8 @@ bool LimeSDRInput::applySettings(const LimeSDRInputSettings& settings, bool forc
<< " m_antennaPath: " << m_settings.m_antennaPath
<< " m_extClock: " << m_settings.m_extClock
<< " m_extClockFreq: " << loc.toString(m_settings.m_extClockFreq)
<< " m_gpioDir: " << m_settings.m_gpioDir
<< " m_gpioPins: " << m_settings.m_gpioPins
<< " force: " << force
<< " forceNCOFrequency: " << forceNCOFrequency
<< " doCalibration: " << doCalibration
@@ -1280,8 +1354,9 @@ bool LimeSDRInput::applySettings(const LimeSDRInputSettings& settings, bool forc
int LimeSDRInput::webapiSettingsGet(
SWGSDRangel::SWGDeviceSettings& response,
QString& errorMessage __attribute__((unused)))
QString& errorMessage)
{
(void) errorMessage;
response.setLimeSdrInputSettings(new SWGSDRangel::SWGLimeSdrInputSettings());
response.getLimeSdrInputSettings()->init();
webapiFormatDeviceSettings(response, m_settings);
@@ -1292,8 +1367,9 @@ int LimeSDRInput::webapiSettingsPutPatch(
bool force,
const QStringList& deviceSettingsKeys,
SWGSDRangel::SWGDeviceSettings& response, // query + response
QString& errorMessage __attribute__((unused)))
QString& errorMessage)
{
(void) errorMessage;
LimeSDRInputSettings settings = m_settings;
if (deviceSettingsKeys.contains("antennaPath")) {
@@ -1362,6 +1438,12 @@ int LimeSDRInput::webapiSettingsPutPatch(
if (deviceSettingsKeys.contains("fileRecordName")) {
settings.m_fileRecordName = *response.getLimeSdrInputSettings()->getFileRecordName();
}
if (deviceSettingsKeys.contains("gpioDir")) {
settings.m_gpioDir = response.getLimeSdrInputSettings()->getGpioDir() & 0xFF;
}
if (deviceSettingsKeys.contains("gpioPins")) {
settings.m_gpioPins = response.getLimeSdrInputSettings()->getGpioPins() & 0xFF;
}
MsgConfigureLimeSDR *msg = MsgConfigureLimeSDR::create(settings, force);
m_inputMessageQueue.push(msg);
@@ -1405,12 +1487,16 @@ void LimeSDRInput::webapiFormatDeviceSettings(SWGSDRangel::SWGDeviceSettings& re
} else {
response.getLimeSdrInputSettings()->setFileRecordName(new QString(settings.m_fileRecordName));
}
response.getLimeSdrInputSettings()->setGpioDir(settings.m_gpioDir);
response.getLimeSdrInputSettings()->setGpioPins(settings.m_gpioPins);
}
int LimeSDRInput::webapiReportGet(
SWGSDRangel::SWGDeviceReport& response,
QString& errorMessage __attribute__((unused)))
QString& errorMessage)
{
(void) errorMessage;
response.setLimeSdrInputReport(new SWGSDRangel::SWGLimeSdrInputReport());
response.getLimeSdrInputReport()->init();
webapiFormatDeviceReport(response);
@@ -1419,8 +1505,9 @@ int LimeSDRInput::webapiReportGet(
int LimeSDRInput::webapiRunGet(
SWGSDRangel::SWGDeviceState& response,
QString& errorMessage __attribute__((unused)))
QString& errorMessage)
{
(void) errorMessage;
m_deviceAPI->getDeviceEngineStateStr(*response.getState());
return 200;
}
@@ -1428,8 +1515,9 @@ int LimeSDRInput::webapiRunGet(
int LimeSDRInput::webapiRun(
bool run,
SWGSDRangel::SWGDeviceState& response,
QString& errorMessage __attribute__((unused)))
QString& errorMessage)
{
(void) errorMessage;
m_deviceAPI->getDeviceEngineStateStr(*response.getState());
MsgStartStop *message = MsgStartStop::create(run);
m_inputMessageQueue.push(message);
@@ -1447,6 +1535,8 @@ void LimeSDRInput::webapiFormatDeviceReport(SWGSDRangel::SWGDeviceReport& respon
{
bool success = false;
double temp = 0.0;
uint8_t gpioDir = 0;
uint8_t gpioPins = 0;
lms_stream_status_t status;
status.active = false;
status.fifoFilledCount = 0;
@@ -1469,9 +1559,14 @@ void LimeSDRInput::webapiFormatDeviceReport(SWGSDRangel::SWGDeviceReport& respon
response.getLimeSdrInputReport()->setLinkRate(status.linkRate);
response.getLimeSdrInputReport()->setHwTimestamp(status.timestamp);
if (m_deviceShared.m_deviceParams->getDevice()) {
if (m_deviceShared.m_deviceParams->getDevice())
{
LMS_GetChipTemperature(m_deviceShared.m_deviceParams->getDevice(), 0, &temp);
LMS_GPIODirRead(m_deviceShared.m_deviceParams->getDevice(), &gpioDir, 1);
LMS_GPIORead(m_deviceShared.m_deviceParams->getDevice(), &gpioPins, 1);
}
response.getLimeSdrInputReport()->setTemperature(temp);
response.getLimeSdrInputReport()->setGpioDir(gpioDir);
response.getLimeSdrInputReport()->setGpioPins(gpioPins);
}
@@ -28,17 +28,24 @@ INCLUDEPATH += ../../../sdrbase
INCLUDEPATH += ../../../sdrgui
INCLUDEPATH += ../../../swagger/sdrangel/code/qt5/client
INCLUDEPATH += ../../../devices
INCLUDEPATH += ../../../liblimesuite/srcmw
INCLUDEPATH += $$LIBLIMESUITESRC/src
INCLUDEPATH += $$LIBLIMESUITESRC/src/ADF4002
INCLUDEPATH += $$LIBLIMESUITESRC/src/ConnectionRegistry
INCLUDEPATH += $$LIBLIMESUITESRC/src/FPGA_common
INCLUDEPATH += $$LIBLIMESUITESRC/src/GFIR
INCLUDEPATH += $$LIBLIMESUITESRC/src/lms7002m
INCLUDEPATH += $$LIBLIMESUITESRC/src/lms7002m_mcu
INCLUDEPATH += $$LIBLIMESUITESRC/src/Si5351C
INCLUDEPATH += $$LIBLIMESUITESRC/src/protocols
INCLUDEPATH += $$LIBLIMESUITESRC/external/cpp-feather-ini-parser
MINGW32 || MINGW64 || macx {
INCLUDEPATH += ../../../liblimesuite/srcmw
INCLUDEPATH += $$LIBLIMESUITESRC/src
INCLUDEPATH += $$LIBLIMESUITESRC/src/ADF4002
INCLUDEPATH += $$LIBLIMESUITESRC/src/ConnectionRegistry
INCLUDEPATH += $$LIBLIMESUITESRC/src/FPGA_common
INCLUDEPATH += $$LIBLIMESUITESRC/src/GFIR
INCLUDEPATH += $$LIBLIMESUITESRC/src/lms7002m
INCLUDEPATH += $$LIBLIMESUITESRC/src/lms7002m_mcu
INCLUDEPATH += $$LIBLIMESUITESRC/src/Si5351C
INCLUDEPATH += $$LIBLIMESUITESRC/src/protocols
INCLUDEPATH += $$LIBLIMESUITESRC/external/cpp-feather-ini-parser
}
MSVC {
INCLUDEPATH += "C:\Program Files\PothosSDR\include"
}
CONFIG(Release):build_subdir = release
CONFIG(Debug):build_subdir = debug
@@ -60,7 +67,12 @@ FORMS += limesdrinputgui.ui
LIBS += -L../../../sdrbase/$${build_subdir} -lsdrbase
LIBS += -L../../../sdrgui/$${build_subdir} -lsdrgui
LIBS += -L../../../swagger/$${build_subdir} -lswagger
LIBS += -L../../../liblimesuite/$${build_subdir} -lliblimesuite
LIBS += -L../../../devices/$${build_subdir} -ldevices
MINGW32 || MINGW64 || macx {
LIBS += -L../../../liblimesuite/$${build_subdir} -lliblimesuite
}
MSVC {
LIBS += -L"C:\Program Files\PothosSDR\bin" -L"C:\Program Files\PothosSDR\lib" -lLimeSuite
}
RESOURCES = ../../../sdrgui/resources/res.qrc
@@ -226,6 +226,7 @@ bool LimeSDRInputGUI::handleMessage(const Message& message)
{
DeviceLimeSDRShared::MsgReportDeviceInfo& report = (DeviceLimeSDRShared::MsgReportDeviceInfo&) message;
ui->temperatureText->setText(tr("%1C").arg(QString::number(report.getTemperature(), 'f', 0)));
ui->gpioText->setText(tr("%1").arg(report.getGPIOPins(), 2, 16, QChar('0')).toUpper());
return true;
}
else if (LimeSDRInput::MsgStartStop::match(message))
@@ -1121,6 +1121,23 @@ QToolTip{background-color: white; color: black;}</string>
</property>
</widget>
</item>
<item>
<widget class="Line" name="line_5">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="gpioText">
<property name="toolTip">
<string>GPIO bits as hex value (LSB first)</string>
</property>
<property name="text">
<string>00</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_3">
<property name="orientation">
@@ -1193,6 +1210,39 @@ QToolTip{background-color: white; color: black;}</string>
</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>
@@ -33,7 +33,7 @@
const PluginDescriptor LimeSDRInputPlugin::m_pluginDescriptor = {
QString("LimeSDR Input"),
QString("4.2.4"),
QString("4.3.1"),
QString("(c) Edouard Griffiths, F4EXB"),
QString("https://github.com/f4exb/sdrangel"),
true,
@@ -46,6 +46,8 @@ void LimeSDRInputSettings::resetToDefaults()
m_transverterMode = false;
m_transverterDeltaFrequency = 0;
m_fileRecordName = "";
m_gpioDir = 0;
m_gpioPins = 0;
}
QByteArray LimeSDRInputSettings::serialize() const
@@ -72,6 +74,8 @@ QByteArray LimeSDRInputSettings::serialize() const
s.writeU32(19, m_extClockFreq);
s.writeBool(20, m_transverterMode);
s.writeS64(21, m_transverterDeltaFrequency);
s.writeU32(22, m_gpioDir);
s.writeU32(23, m_gpioPins);
return s.final();
}
@@ -89,6 +93,7 @@ bool LimeSDRInputSettings::deserialize(const QByteArray& data)
if (d.getVersion() == 1)
{
int intval;
uint32_t uintval;
d.readS32(1, &m_devSampleRate, 5000000);
d.readU32(2, &m_log2HardDecim, 2);
@@ -112,6 +117,10 @@ bool LimeSDRInputSettings::deserialize(const QByteArray& data)
d.readU32(19, &m_extClockFreq, 10000000);
d.readBool(20, &m_transverterMode, false);
d.readS64(21, &m_transverterDeltaFrequency, 0);
d.readU32(22, &uintval, 0);
m_gpioDir = uintval & 0xFF;
d.readU32(23, &uintval, 0);
m_gpioPins = uintval & 0xFF;
return true;
}
@@ -66,6 +66,8 @@ struct LimeSDRInputSettings
bool m_transverterMode;
qint64 m_transverterDeltaFrequency;
QString m_fileRecordName;
uint8_t m_gpioDir; //!< GPIO pin direction LSB first; 0 input, 1 output
uint8_t m_gpioPins; //!< GPIO pins to write; LSB first
LimeSDRInputSettings();
void resetToDefaults();
@@ -39,7 +39,7 @@ public:
virtual void startWork();
virtual void stopWork();
virtual void setDeviceSampleRate(int sampleRate __attribute__((unused))) {}
virtual void setDeviceSampleRate(int sampleRate) { (void) sampleRate; }
virtual bool isRunning() { return m_running; }
void setLog2Decimation(unsigned int log2_decim);
+10 -5
View File
@@ -402,8 +402,9 @@ bool PerseusInput::applySettings(const PerseusSettings& settings, bool force)
int PerseusInput::webapiRunGet(
SWGSDRangel::SWGDeviceState& response,
QString& errorMessage __attribute__((unused)))
QString& errorMessage)
{
(void) errorMessage;
m_deviceAPI->getDeviceEngineStateStr(*response.getState());
return 200;
}
@@ -411,8 +412,9 @@ int PerseusInput::webapiRunGet(
int PerseusInput::webapiRun(
bool run,
SWGSDRangel::SWGDeviceState& response,
QString& errorMessage __attribute__((unused)))
QString& errorMessage)
{
(void) errorMessage;
m_deviceAPI->getDeviceEngineStateStr(*response.getState());
MsgStartStop *message = MsgStartStop::create(run);
m_inputMessageQueue.push(message);
@@ -428,8 +430,9 @@ int PerseusInput::webapiRun(
int PerseusInput::webapiSettingsGet(
SWGSDRangel::SWGDeviceSettings& response,
QString& errorMessage __attribute__((unused)))
QString& errorMessage)
{
(void) errorMessage;
response.setPerseusSettings(new SWGSDRangel::SWGPerseusSettings());
response.getPerseusSettings()->init();
webapiFormatDeviceSettings(response, m_settings);
@@ -440,8 +443,9 @@ int PerseusInput::webapiSettingsPutPatch(
bool force,
const QStringList& deviceSettingsKeys,
SWGSDRangel::SWGDeviceSettings& response, // query + response
QString& errorMessage __attribute__((unused)))
QString& errorMessage)
{
(void) errorMessage;
PerseusSettings settings = m_settings;
if (deviceSettingsKeys.contains("centerFrequency")) {
@@ -495,8 +499,9 @@ int PerseusInput::webapiSettingsPutPatch(
int PerseusInput::webapiReportGet(
SWGSDRangel::SWGDeviceReport& response,
QString& errorMessage __attribute__((unused)))
QString& errorMessage)
{
(void) errorMessage;
response.setPerseusReport(new SWGSDRangel::SWGPerseusReport());
response.getPerseusReport()->init();
webapiFormatDeviceReport(response);
@@ -111,8 +111,9 @@ void PerseusThread::callback(const uint8_t* buf, qint32 len)
m_sampleFifo->write(m_convertBuffer.begin(), it);
}
int PerseusThread::rx_callback(void *buf, int buf_size, void *extra __attribute__((unused)))
int PerseusThread::rx_callback(void *buf, int buf_size, void *extra)
{
(void) extra;
qint32 nbIAndQ = buf_size / 3; // 3 bytes per I or Q
m_this->callback((uint8_t*) buf, nbIAndQ);
return 0;
@@ -619,8 +619,9 @@ float PlutoSDRInput::getTemperature()
int PlutoSDRInput::webapiRunGet(
SWGSDRangel::SWGDeviceState& response,
QString& errorMessage __attribute__((unused)))
QString& errorMessage)
{
(void) errorMessage;
m_deviceAPI->getDeviceEngineStateStr(*response.getState());
return 200;
}
@@ -628,8 +629,9 @@ int PlutoSDRInput::webapiRunGet(
int PlutoSDRInput::webapiRun(
bool run,
SWGSDRangel::SWGDeviceState& response,
QString& errorMessage __attribute__((unused)))
QString& errorMessage)
{
(void) errorMessage;
m_deviceAPI->getDeviceEngineStateStr(*response.getState());
MsgStartStop *message = MsgStartStop::create(run);
m_inputMessageQueue.push(message);
@@ -645,8 +647,9 @@ int PlutoSDRInput::webapiRun(
int PlutoSDRInput::webapiSettingsGet(
SWGSDRangel::SWGDeviceSettings& response,
QString& errorMessage __attribute__((unused)))
QString& errorMessage)
{
(void) errorMessage;
response.setPlutoSdrInputSettings(new SWGSDRangel::SWGPlutoSdrInputSettings());
response.getPlutoSdrInputSettings()->init();
webapiFormatDeviceSettings(response, m_settings);
@@ -657,8 +660,9 @@ int PlutoSDRInput::webapiSettingsPutPatch(
bool force,
const QStringList& deviceSettingsKeys,
SWGSDRangel::SWGDeviceSettings& response, // query + response
QString& errorMessage __attribute__((unused)))
QString& errorMessage)
{
(void) errorMessage;
PlutoSDRInputSettings settings = m_settings;
if (deviceSettingsKeys.contains("centerFrequency")) {
@@ -737,8 +741,9 @@ int PlutoSDRInput::webapiSettingsPutPatch(
int PlutoSDRInput::webapiReportGet(
SWGSDRangel::SWGDeviceReport& response,
QString& errorMessage __attribute__((unused)))
QString& errorMessage)
{
(void) errorMessage;
response.setPlutoSdrInputReport(new SWGSDRangel::SWGPlutoSdrInputReport());
response.getPlutoSdrInputReport()->init();
webapiFormatDeviceReport(response);
@@ -17,17 +17,22 @@ DEFINES += USE_SSE4_1=1
QMAKE_CXXFLAGS += -msse4.1
QMAKE_CXXFLAGS += -std=c++11
CONFIG(MINGW32):LIBIIOSRC = "C:\softs\libiio"
CONFIG(MINGW64):LIBIIOSRC = "C:\softs\libiio"
INCLUDEPATH += $$PWD
INCLUDEPATH += ../../../exports
INCLUDEPATH += ../../../sdrbase
INCLUDEPATH += ../../../sdrgui
INCLUDEPATH += ../../../swagger/sdrangel/code/qt5/client
INCLUDEPATH += ../../../devices
INCLUDEPATH += ../../../libiio/includemw
INCLUDEPATH += $$LIBIIOSRC
MINGW32 || MINGW64 {
LIBIIOSRC = "C:\softs\libiio"
INCLUDEPATH += ../../../libiio/includemw
INCLUDEPATH += $$LIBIIOSRC
}
MSVC {
INCLUDEPATH += "C:\Program Files\PothosSDR\include"
}
CONFIG(Release):build_subdir = release
CONFIG(Debug):build_subdir = debug
@@ -49,7 +54,14 @@ FORMS += plutosdrinputgui.ui
LIBS += -L../../../sdrbase/$${build_subdir} -lsdrbase
LIBS += -L../../../sdrgui/$${build_subdir} -lsdrgui
LIBS += -L../../../swagger/$${build_subdir} -lswagger
LIBS += -L../../../libiio/$${build_subdir} -llibiio
LIBS += -L../../../devices/$${build_subdir} -ldevices
MINGW32 || MINGW64 {
LIBS += -L../../../libiio/$${build_subdir} -llibiio
}
MSVC {
LIBS += -L"C:\Program Files\PothosSDR\bin" -L"C:\Program Files\PothosSDR\lib" -llibiio
}
RESOURCES = ../../../sdrgui/resources/res.qrc
@@ -130,7 +130,7 @@ bool PlutoSDRInputGui::deserialize(const QByteArray& data)
}
}
bool PlutoSDRInputGui::handleMessage(const Message& message __attribute__((unused)))
bool PlutoSDRInputGui::handleMessage(const Message& message)
{
if (PlutoSDRInput::MsgConfigurePlutoSDR::match(message))
{
@@ -30,7 +30,7 @@ class DeviceSourceAPI;
const PluginDescriptor PlutoSDRInputPlugin::m_pluginDescriptor = {
QString("PlutoSDR Input"),
QString("4.0.0"),
QString("4.3.1"),
QString("(c) Edouard Griffiths, F4EXB"),
QString("https://github.com/f4exb/sdrangel"),
true,
@@ -14,8 +14,6 @@
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#include <unistd.h>
#include "plutosdr/deviceplutosdrbox.h"
#include "plutosdrinputsettings.h"
#include "plutosdrinputthread.h"
@@ -37,7 +37,7 @@ public:
virtual void startWork();
virtual void stopWork();
virtual void setDeviceSampleRate(int sampleRate __attribute__((unused))) {}
virtual void setDeviceSampleRate(int sampleRate) { (void) sampleRate; }
virtual bool isRunning() { return m_running; }
void setLog2Decimation(unsigned int log2_decim);
void setFcPos(int fcPos);
+6 -2
View File
@@ -109,11 +109,15 @@ The I/Q stream from the RTLSDR ADC is downsampled by a power of two before being
Use this checkbox to activate the special RTLSDR direct sampling. This can be used to tune to HF frequencies.
<h3>9: RF bandwidth</h3>
<h3>9: Offset tuning</h3>
This controls the offset tuning. Some RF frontends like the obsolete E4000 implement this feature and it can seriously reduce the central DC peak without digital correction. This does not work for the R820T and R820T2 that are very popular on which it will produce no effect. However these RF frontends exhibit a central DC peak much smaller than on the E4000 and can be easly corrected digitally via control (3).
<h3>10: RF bandwidth</h3>
This controls the tuner filter bandwidth and can be varied from 350 kHz to 8 MHz. In practice depending on the value this appears to be larger and the filter center is slightly offset above the center frequency. This can still be very useful to eliminate or attenuate large signals outside the device to host I/Q stream passband.
<h3>10: RF gain and AGC</h2>
<h3>11: RF gain and AGC</h2>
The slider sets RF gain in dB. The values are defined in the RTLSDR device and generally are: 0.0, 0.9, 1.4, 2.7, 3.7, 7.7, 8.7, 12.5, 14.4, 15.7, 16.6, 19.7, 20.7, 22.9, 25.4, 28.0, 29.7, 32.8, 33.8, 36.4, 37.2, 38.6, 40.2, 42.1, 43.4, 43.9, 44.5, 48.0, 49.6
@@ -261,6 +261,7 @@ void RTLSDRGui::displaySettings()
ui->checkBox->setChecked(m_settings.m_noModMode);
ui->agc->setChecked(m_settings.m_agc);
ui->lowSampleRate->setChecked(m_settings.m_lowSampleRate);
ui->offsetTuning->setChecked(m_settings.m_offsetTuning);
}
void RTLSDRGui::sendSettings()
@@ -441,6 +442,12 @@ void RTLSDRGui::on_sampleRate_changed(quint64 value)
sendSettings();
}
void RTLSDRGui::on_offsetTuning_toggled(bool checked)
{
m_settings.m_offsetTuning = checked;
sendSettings();
}
void RTLSDRGui::on_rfBW_changed(quint64 value)
{
m_settings.m_rfBandwidth = value * 1000;
+1
View File
@@ -78,6 +78,7 @@ private slots:
void handleInputMessages();
void on_centerFrequency_changed(quint64 value);
void on_sampleRate_changed(quint64 value);
void on_offsetTuning_toggled(bool checked);
void on_rfBW_changed(quint64 value);
void on_lowSampleRate_toggled(bool checked);
void on_dcOffset_toggled(bool checked);
+10
View File
@@ -493,6 +493,16 @@
</property>
</spacer>
</item>
<item>
<widget class="QCheckBox" name="offsetTuning">
<property name="toolTip">
<string>Offset tuning (applies to some tuners only incl. E4000)</string>
</property>
<property name="text">
<string>Ofs</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="rfBWabel">
<property name="text">
+30 -10
View File
@@ -507,17 +507,28 @@ bool RTLSDRInput::applySettings(const RTLSDRSettings& settings, bool force)
if (m_dev != 0)
{
if (rtlsdr_set_tuner_bandwidth( m_dev, m_settings.m_rfBandwidth) != 0)
{
if (rtlsdr_set_tuner_bandwidth( m_dev, m_settings.m_rfBandwidth) != 0) {
qCritical("RTLSDRInput::applySettings: could not set RF bandwidth to %u", m_settings.m_rfBandwidth);
}
else
{
} else {
qDebug() << "RTLSDRInput::applySettings: set RF bandwidth to " << m_settings.m_rfBandwidth;
}
}
}
if ((m_settings.m_offsetTuning != settings.m_offsetTuning) || force)
{
m_settings.m_offsetTuning = settings.m_offsetTuning;
if (m_dev != 0)
{
if (rtlsdr_set_offset_tuning(m_dev, m_settings.m_offsetTuning ? 0 : 1) != 0) {
qCritical("RTLSDRInput::applySettings: could not set offset tuning to %s", m_settings.m_offsetTuning ? "on" : "off");
} else {
qDebug("RTLSDRInput::applySettings: offset tuning set to %s", m_settings.m_offsetTuning ? "on" : "off");
}
}
}
if (forwardChange)
{
int sampleRate = m_settings.m_devSampleRate/(1<<m_settings.m_log2Decim);
@@ -536,8 +547,9 @@ void RTLSDRInput::set_ds_mode(int on)
int RTLSDRInput::webapiSettingsGet(
SWGSDRangel::SWGDeviceSettings& response,
QString& errorMessage __attribute__((unused)))
QString& errorMessage)
{
(void) errorMessage;
response.setRtlSdrSettings(new SWGSDRangel::SWGRtlSdrSettings());
response.getRtlSdrSettings()->init();
webapiFormatDeviceSettings(response, m_settings);
@@ -548,8 +560,9 @@ int RTLSDRInput::webapiSettingsPutPatch(
bool force,
const QStringList& deviceSettingsKeys,
SWGSDRangel::SWGDeviceSettings& response, // query + response
QString& errorMessage __attribute__((unused)))
QString& errorMessage)
{
(void) errorMessage;
RTLSDRSettings settings = m_settings;
if (deviceSettingsKeys.contains("agc")) {
@@ -585,6 +598,9 @@ int RTLSDRInput::webapiSettingsPutPatch(
if (deviceSettingsKeys.contains("noModMode")) {
settings.m_noModMode = response.getRtlSdrSettings()->getNoModMode() != 0;
}
if (deviceSettingsKeys.contains("offsetTuning")) {
settings.m_offsetTuning = response.getRtlSdrSettings()->getOffsetTuning() != 0;
}
if (deviceSettingsKeys.contains("transverterDeltaFrequency")) {
settings.m_transverterDeltaFrequency = response.getRtlSdrSettings()->getTransverterDeltaFrequency();
}
@@ -625,6 +641,7 @@ void RTLSDRInput::webapiFormatDeviceSettings(SWGSDRangel::SWGDeviceSettings& res
response.getRtlSdrSettings()->setLog2Decim(settings.m_log2Decim);
response.getRtlSdrSettings()->setLowSampleRate(settings.m_lowSampleRate ? 1 : 0);
response.getRtlSdrSettings()->setNoModMode(settings.m_noModMode ? 1 : 0);
response.getRtlSdrSettings()->setOffsetTuning(settings.m_offsetTuning ? 1 : 0);
response.getRtlSdrSettings()->setTransverterDeltaFrequency(settings.m_transverterDeltaFrequency);
response.getRtlSdrSettings()->setTransverterMode(settings.m_transverterMode ? 1 : 0);
response.getRtlSdrSettings()->setRfBandwidth(settings.m_rfBandwidth);
@@ -638,8 +655,9 @@ void RTLSDRInput::webapiFormatDeviceSettings(SWGSDRangel::SWGDeviceSettings& res
int RTLSDRInput::webapiRunGet(
SWGSDRangel::SWGDeviceState& response,
QString& errorMessage __attribute__((unused)))
QString& errorMessage)
{
(void) errorMessage;
m_deviceAPI->getDeviceEngineStateStr(*response.getState());
return 200;
}
@@ -647,8 +665,9 @@ int RTLSDRInput::webapiRunGet(
int RTLSDRInput::webapiRun(
bool run,
SWGSDRangel::SWGDeviceState& response,
QString& errorMessage __attribute__((unused)))
QString& errorMessage)
{
(void) errorMessage;
m_deviceAPI->getDeviceEngineStateStr(*response.getState());
MsgStartStop *message = MsgStartStop::create(run);
m_inputMessageQueue.push(message);
@@ -664,8 +683,9 @@ int RTLSDRInput::webapiRun(
int RTLSDRInput::webapiReportGet(
SWGSDRangel::SWGDeviceReport& response,
QString& errorMessage __attribute__((unused)))
QString& errorMessage)
{
(void) errorMessage;
response.setRtlSdrReport(new SWGSDRangel::SWGRtlSdrReport());
response.getRtlSdrReport()->init();
webapiFormatDeviceReport(response);
+1 -1
View File
@@ -14,7 +14,7 @@
const PluginDescriptor RTLSDRPlugin::m_pluginDescriptor = {
QString("RTL-SDR Input"),
QString("4.0.6"),
QString("4.3.1"),
QString("(c) Edouard Griffiths, F4EXB"),
QString("https://github.com/f4exb/sdrangel"),
true,
@@ -40,6 +40,7 @@ void RTLSDRSettings::resetToDefaults()
m_transverterDeltaFrequency = 0;
m_rfBandwidth = 2500 * 1000; // Hz
m_fileRecordName = "";
m_offsetTuning = false;
}
QByteArray RTLSDRSettings::serialize() const
@@ -59,6 +60,7 @@ QByteArray RTLSDRSettings::serialize() const
s.writeBool(12, m_transverterMode);
s.writeS64(13, m_transverterDeltaFrequency);
s.writeU32(14, m_rfBandwidth);
s.writeBool(15, m_offsetTuning);
return s.final();
}
@@ -91,6 +93,7 @@ bool RTLSDRSettings::deserialize(const QByteArray& data)
d.readBool(12, &m_transverterMode, false);
d.readS64(13, &m_transverterDeltaFrequency, 0);
d.readU32(4, &m_rfBandwidth, 2500 * 1000);
d.readBool(15, &m_offsetTuning, false);
return true;
}
@@ -41,6 +41,7 @@ struct RTLSDRSettings {
qint64 m_transverterDeltaFrequency;
quint32 m_rfBandwidth; //!< RF filter bandwidth in Hz
QString m_fileRecordName;
bool m_offsetTuning;
RTLSDRSettings();
void resetToDefaults();
@@ -13,6 +13,7 @@ TARGET = inputsdrdaemonsource
CONFIG(MINGW32):LIBCM256CCSRC = "C:\softs\cm256cc"
CONFIG(MINGW64):LIBCM256CCSRC = "C:\softs\cm256cc"
CONFIG(MSVC):LIBCM256CCSRC = "C:\softs\cm256cc"
CONFIG(macx):LIBCM256CCSRC = "../../../../deps/cm256cc"
INCLUDEPATH += $$PWD
@@ -36,6 +37,7 @@ CONFIG(Debug):build_subdir = debug
CONFIG(MINGW32):INCLUDEPATH += "C:\softs\boost_1_66_0"
CONFIG(MINGW64):INCLUDEPATH += "C:\softs\boost_1_66_0"
CONFIG(MSVC):INCLUDEPATH += "C:\softs\boost_1_66_0"
CONFIG(macx):INCLUDEPATH += "../../../boost_1_64_0"
SOURCES += sdrdaemonsourcebuffer.cpp\
@@ -45,6 +45,7 @@ public:
// samples timestamp
uint32_t getTVOutSec() const { return m_tvOut_sec; }
uint32_t getTVOutUsec() const { return m_tvOut_usec; }
uint64_t getTVOutMSec() const { return (m_tvOut_sec * 1000LL) + (m_tvOut_usec/ 1000LL); }
// stats
@@ -71,8 +71,7 @@ SDRdaemonSourceGui::SDRdaemonSourceGui(DeviceUISet *deviceUISet, QWidget* parent
m_paletteGreenText.setColor(QPalette::WindowText, Qt::green);
m_paletteWhiteText.setColor(QPalette::WindowText, Qt::white);
m_startingTimeStamp.tv_sec = 0;
m_startingTimeStamp.tv_usec = 0;
m_startingTimeStampms = 0;
ui->setupUi(this);
ui->centerFrequency->setColorMapper(ColorMapper(ColorMapper::GrayGold));
@@ -163,8 +162,9 @@ qint64 SDRdaemonSourceGui::getCenterFrequency() const
return m_streamCenterFrequency;
}
void SDRdaemonSourceGui::setCenterFrequency(qint64 centerFrequency __attribute__((unused)))
void SDRdaemonSourceGui::setCenterFrequency(qint64 centerFrequency)
{
(void) centerFrequency;
}
bool SDRdaemonSourceGui::handleMessage(const Message& message)
@@ -186,20 +186,17 @@ bool SDRdaemonSourceGui::handleMessage(const Message& message)
}
else if (SDRdaemonSourceInput::MsgReportSDRdaemonSourceStreamData::match(message))
{
m_startingTimeStamp.tv_sec = ((SDRdaemonSourceInput::MsgReportSDRdaemonSourceStreamData&)message).get_tv_sec();
m_startingTimeStamp.tv_usec = ((SDRdaemonSourceInput::MsgReportSDRdaemonSourceStreamData&)message).get_tv_usec();
m_startingTimeStampms = ((SDRdaemonSourceInput::MsgReportSDRdaemonSourceStreamData&)message).get_tv_msec();
qDebug() << "SDRdaemonSourceGui::handleMessage: SDRdaemonSourceInput::MsgReportSDRdaemonSourceStreamData: "
<< " : " << m_startingTimeStamp.tv_sec
<< " : " << m_startingTimeStamp.tv_usec;
<< " : " << m_startingTimeStampms << " ms";
updateWithStreamTime();
return true;
}
else if (SDRdaemonSourceInput::MsgReportSDRdaemonSourceStreamTiming::match(message))
{
m_startingTimeStamp.tv_sec = ((SDRdaemonSourceInput::MsgReportSDRdaemonSourceStreamTiming&)message).get_tv_sec();
m_startingTimeStamp.tv_usec = ((SDRdaemonSourceInput::MsgReportSDRdaemonSourceStreamTiming&)message).get_tv_usec();
m_startingTimeStampms = ((SDRdaemonSourceInput::MsgReportSDRdaemonSourceStreamTiming&)message).get_tv_msec();
m_framesDecodingStatus = ((SDRdaemonSourceInput::MsgReportSDRdaemonSourceStreamTiming&)message).getFramesDecodingStatus();
m_allBlocksReceived = ((SDRdaemonSourceInput::MsgReportSDRdaemonSourceStreamTiming&)message).allBlocksReceived();
m_bufferLengthInSecs = ((SDRdaemonSourceInput::MsgReportSDRdaemonSourceStreamTiming&)message).getBufferLengthInSecs();
@@ -308,8 +305,9 @@ void SDRdaemonSourceGui::sendSettings()
m_updateTimer.start(100);
}
void SDRdaemonSourceGui::on_apiApplyButton_clicked(bool checked __attribute__((unused)))
void SDRdaemonSourceGui::on_apiApplyButton_clicked(bool checked)
{
(void) checked;
m_settings.m_apiAddress = ui->apiAddress->text();
bool ctlOk;
@@ -326,8 +324,9 @@ void SDRdaemonSourceGui::on_apiApplyButton_clicked(bool checked __attribute__((u
m_networkManager->get(m_networkRequest);
}
void SDRdaemonSourceGui::on_dataApplyButton_clicked(bool checked __attribute__((unused)))
void SDRdaemonSourceGui::on_dataApplyButton_clicked(bool checked)
{
(void) checked;
m_settings.m_dataAddress = ui->dataAddress->text();
bool dataOk;
@@ -427,8 +426,9 @@ void SDRdaemonSourceGui::on_record_toggled(bool checked)
m_sampleSource->getInputMessageQueue()->push(message);
}
void SDRdaemonSourceGui::on_eventCountsReset_clicked(bool checked __attribute__((unused)))
void SDRdaemonSourceGui::on_eventCountsReset_clicked(bool checked)
{
(void) checked;
m_countUnrecoverable = 0;
m_countRecovered = 0;
m_eventsTime.start();
@@ -460,8 +460,7 @@ void SDRdaemonSourceGui::updateWithAcquisition()
void SDRdaemonSourceGui::updateWithStreamTime()
{
bool updateEventCounts = false;
quint64 startingTimeStampMsec = ((quint64) m_startingTimeStamp.tv_sec * 1000LL) + ((quint64) m_startingTimeStamp.tv_usec / 1000LL);
QDateTime dt = QDateTime::fromMSecsSinceEpoch(startingTimeStampMsec);
QDateTime dt = QDateTime::fromMSecsSinceEpoch(m_startingTimeStampms);
QString s_date = dt.toString("yyyy-MM-dd HH:mm:ss.zzz");
ui->absTimeText->setText(s_date);
@@ -17,8 +17,6 @@
#ifndef INCLUDE_SDRDAEMONSOURCEGUI_H
#define INCLUDE_SDRDAEMONSOURCEGUI_H
#include <sys/time.h>
#include <QTimer>
#include <QWidget>
#include <QNetworkRequest>
@@ -72,7 +70,7 @@ private:
// int m_sampleRate;
// quint64 m_centerFrequency;
struct timeval m_startingTimeStamp;
uint64_t m_startingTimeStampms;
int m_framesDecodingStatus;
bool m_allBlocksReceived;
float m_bufferLengthInSecs;
@@ -16,7 +16,6 @@
#include <string.h>
#include <errno.h>
#include <sys/time.h>
#include <QDebug>
#include "SWGDeviceSettings.h"
@@ -134,8 +133,9 @@ quint64 SDRdaemonSourceInput::getCenterFrequency() const
return m_SDRdaemonUDPHandler->getCenterFrequency();
}
void SDRdaemonSourceInput::setCenterFrequency(qint64 centerFrequency __attribute__((unused)))
void SDRdaemonSourceInput::setCenterFrequency(qint64 centerFrequency)
{
(void) centerFrequency;
}
std::time_t SDRdaemonSourceInput::getStartingTimeStamp() const
@@ -241,8 +241,9 @@ void SDRdaemonSourceInput::applySettings(const SDRdaemonSourceSettings& settings
int SDRdaemonSourceInput::webapiRunGet(
SWGSDRangel::SWGDeviceState& response,
QString& errorMessage __attribute__((unused)))
QString& errorMessage)
{
(void) errorMessage;
m_deviceAPI->getDeviceEngineStateStr(*response.getState());
return 200;
}
@@ -250,8 +251,9 @@ int SDRdaemonSourceInput::webapiRunGet(
int SDRdaemonSourceInput::webapiRun(
bool run,
SWGSDRangel::SWGDeviceState& response,
QString& errorMessage __attribute__((unused)))
QString& errorMessage)
{
(void) errorMessage;
m_deviceAPI->getDeviceEngineStateStr(*response.getState());
MsgStartStop *message = MsgStartStop::create(run);
m_inputMessageQueue.push(message);
@@ -267,8 +269,9 @@ int SDRdaemonSourceInput::webapiRun(
int SDRdaemonSourceInput::webapiSettingsGet(
SWGSDRangel::SWGDeviceSettings& response,
QString& errorMessage __attribute__((unused)))
QString& errorMessage)
{
(void) errorMessage;
response.setSdrDaemonSourceSettings(new SWGSDRangel::SWGSDRdaemonSourceSettings());
response.getSdrDaemonSourceSettings()->init();
webapiFormatDeviceSettings(response, m_settings);
@@ -279,8 +282,9 @@ int SDRdaemonSourceInput::webapiSettingsPutPatch(
bool force,
const QStringList& deviceSettingsKeys,
SWGSDRangel::SWGDeviceSettings& response, // query + response
QString& errorMessage __attribute__((unused)))
QString& errorMessage)
{
(void) errorMessage;
SDRdaemonSourceSettings settings = m_settings;
if (deviceSettingsKeys.contains("apiAddress")) {
@@ -336,8 +340,9 @@ void SDRdaemonSourceInput::webapiFormatDeviceSettings(SWGSDRangel::SWGDeviceSett
int SDRdaemonSourceInput::webapiReportGet(
SWGSDRangel::SWGDeviceReport& response,
QString& errorMessage __attribute__((unused)))
QString& errorMessage)
{
(void) errorMessage;
response.setSdrDaemonSourceReport(new SWGSDRangel::SWGSDRdaemonSourceReport());
response.getSdrDaemonSourceReport()->init();
webapiFormatDeviceReport(response);
@@ -350,8 +355,7 @@ void SDRdaemonSourceInput::webapiFormatDeviceReport(SWGSDRangel::SWGDeviceReport
response.getSdrDaemonSourceReport()->setSampleRate(m_SDRdaemonUDPHandler->getSampleRate());
response.getSdrDaemonSourceReport()->setBufferRwBalance(m_SDRdaemonUDPHandler->getBufferGauge());
quint64 startingTimeStampMsec = ((quint64) m_SDRdaemonUDPHandler->getTVSec() * 1000LL) + ((quint64) m_SDRdaemonUDPHandler->getTVuSec() / 1000LL);
QDateTime dt = QDateTime::fromMSecsSinceEpoch(startingTimeStampMsec);
QDateTime dt = QDateTime::fromMSecsSinceEpoch(m_SDRdaemonUDPHandler->getTVmSec());
response.getSdrDaemonSourceReport()->setDaemonTimestamp(new QString(dt.toString("yyyy-MM-dd HH:mm:ss.zzz")));
response.getSdrDaemonSourceReport()->setMinNbBlocks(m_SDRdaemonUDPHandler->getMinNbBlocks());
@@ -99,26 +99,23 @@ public:
public:
int getSampleRate() const { return m_sampleRate; }
quint64 getCenterFrequency() const { return m_centerFrequency; }
uint32_t get_tv_sec() const { return m_tv_sec; }
uint32_t get_tv_usec() const { return m_tv_usec; }
uint32_t get_tv_msec() const { return m_tv_msec; }
static MsgReportSDRdaemonSourceStreamData* create(int sampleRate, quint64 centerFrequency, uint32_t tv_sec, uint32_t tv_usec)
static MsgReportSDRdaemonSourceStreamData* create(int sampleRate, quint64 centerFrequency, uint64_t tv_msec)
{
return new MsgReportSDRdaemonSourceStreamData(sampleRate, centerFrequency, tv_sec, tv_usec);
return new MsgReportSDRdaemonSourceStreamData(sampleRate, centerFrequency, tv_msec);
}
protected:
int m_sampleRate;
quint64 m_centerFrequency;
uint32_t m_tv_sec;
uint32_t m_tv_usec;
uint64_t m_tv_msec;
MsgReportSDRdaemonSourceStreamData(int sampleRate, quint64 centerFrequency, uint32_t tv_sec, uint32_t tv_usec) :
MsgReportSDRdaemonSourceStreamData(int sampleRate, quint64 centerFrequency, uint64_t tv_msec) :
Message(),
m_sampleRate(sampleRate),
m_centerFrequency(centerFrequency),
m_tv_sec(tv_sec),
m_tv_usec(tv_usec)
m_tv_msec(tv_msec)
{ }
};
@@ -126,8 +123,7 @@ public:
MESSAGE_CLASS_DECLARATION
public:
uint32_t get_tv_sec() const { return m_tv_sec; }
uint32_t get_tv_usec() const { return m_tv_usec; }
uint64_t get_tv_msec() const { return m_tv_msec; }
int getFramesDecodingStatus() const { return m_framesDecodingStatus; }
bool allBlocksReceived() const { return m_allBlocksReceived; }
float getBufferLengthInSecs() const { return m_bufferLenSec; }
@@ -143,8 +139,7 @@ public:
int getSampleBits() const { return m_sampleBits; }
int getSampleBytes() const { return m_sampleBytes; }
static MsgReportSDRdaemonSourceStreamTiming* create(uint32_t tv_sec,
uint32_t tv_usec,
static MsgReportSDRdaemonSourceStreamTiming* create(uint64_t tv_msec,
float bufferLenSec,
int32_t bufferGauge,
int framesDecodingStatus,
@@ -160,8 +155,7 @@ public:
int sampleBits,
int sampleBytes)
{
return new MsgReportSDRdaemonSourceStreamTiming(tv_sec,
tv_usec,
return new MsgReportSDRdaemonSourceStreamTiming(tv_msec,
bufferLenSec,
bufferGauge,
framesDecodingStatus,
@@ -179,8 +173,7 @@ public:
}
protected:
uint32_t m_tv_sec;
uint32_t m_tv_usec;
uint64_t m_tv_msec;
int m_framesDecodingStatus;
bool m_allBlocksReceived;
float m_bufferLenSec;
@@ -196,8 +189,7 @@ public:
int m_sampleBits;
int m_sampleBytes;
MsgReportSDRdaemonSourceStreamTiming(uint32_t tv_sec,
uint32_t tv_usec,
MsgReportSDRdaemonSourceStreamTiming(uint64_t tv_msec,
float bufferLenSec,
int32_t bufferGauge,
int framesDecodingStatus,
@@ -213,8 +205,7 @@ public:
int sampleBits,
int sampleBytes) :
Message(),
m_tv_sec(tv_sec),
m_tv_usec(tv_usec),
m_tv_msec(tv_msec),
m_framesDecodingStatus(framesDecodingStatus),
m_allBlocksReceived(allBlocksReceived),
m_bufferLenSec(bufferLenSec),
@@ -17,7 +17,6 @@
#include <QUdpSocket>
#include <QDebug>
#include <QTimer>
#include <unistd.h>
#include "dsp/dspcommands.h"
#include "dsp/dspengine.h"
@@ -42,8 +41,7 @@ SDRdaemonSourceUDPHandler::SDRdaemonSourceUDPHandler(SampleSinkFifo *sampleFifo,
m_sampleFifo(sampleFifo),
m_samplerate(0),
m_centerFrequency(0),
m_tv_sec(0),
m_tv_usec(0),
m_tv_msec(0),
m_outputMessageQueueToGUI(0),
m_tickCount(0),
m_samplesCount(0),
@@ -180,8 +178,7 @@ void SDRdaemonSourceUDPHandler::processData()
const SDRDaemonMetaDataFEC& metaData = m_sdrDaemonBuffer.getCurrentMeta();
bool change = false;
m_tv_sec = m_sdrDaemonBuffer.getTVOutSec();
m_tv_usec = m_sdrDaemonBuffer.getTVOutUsec();
m_tv_msec = m_sdrDaemonBuffer.getTVOutMSec();
if (m_centerFrequency != metaData.m_centerFrequency)
{
@@ -207,8 +204,7 @@ void SDRdaemonSourceUDPHandler::processData()
SDRdaemonSourceInput::MsgReportSDRdaemonSourceStreamData *report = SDRdaemonSourceInput::MsgReportSDRdaemonSourceStreamData::create(
m_samplerate,
m_centerFrequency * 1000, // Frequency in Hz for the GUI
m_tv_sec,
m_tv_usec);
m_tv_msec);
m_outputMessageQueueToGUI->push(report);
}
@@ -266,13 +262,7 @@ void SDRdaemonSourceUDPHandler::tick()
const SDRDaemonMetaDataFEC& metaData = m_sdrDaemonBuffer.getCurrentMeta();
m_readLength = m_readLengthSamples * (metaData.m_sampleBytes & 0xF) * 2;
if (SDR_RX_SAMP_SZ == metaData.m_sampleBits) // same sample size
{
// read samples directly feeding the SampleFifo (no callback)
m_sampleFifo->write(reinterpret_cast<quint8*>(m_sdrDaemonBuffer.readData(m_readLength)), m_readLength);
m_samplesCount += m_readLengthSamples;
}
else if (metaData.m_sampleBits == 16) // 16 -> 24 bits
if ((metaData.m_sampleBits == 16) && (SDR_RX_SAMP_SZ == 24)) // 16 -> 24 bits
{
if (m_readLengthSamples > m_converterBufferNbSamples)
{
@@ -292,7 +282,7 @@ void SDRdaemonSourceUDPHandler::tick()
m_sampleFifo->write(reinterpret_cast<quint8*>(m_converterBuffer), m_readLengthSamples*sizeof(Sample));
}
else if (metaData.m_sampleBits == 24) // 24 -> 16 bits
else if ((metaData.m_sampleBits == 24) && (SDR_RX_SAMP_SZ == 16)) // 24 -> 16 bits
{
if (m_readLengthSamples > m_converterBufferNbSamples)
{
@@ -311,7 +301,13 @@ void SDRdaemonSourceUDPHandler::tick()
m_sampleFifo->write(reinterpret_cast<quint8*>(m_converterBuffer), m_readLengthSamples*sizeof(Sample));
}
else
else if ((metaData.m_sampleBits == 16) || (metaData.m_sampleBits == 24)) // same sample size and valid size
{
// read samples directly feeding the SampleFifo (no callback)
m_sampleFifo->write(reinterpret_cast<quint8*>(m_sdrDaemonBuffer.readData(m_readLength)), m_readLength);
m_samplesCount += m_readLengthSamples;
}
else // invalid size
{
qWarning("SDRdaemonSourceUDPHandler::tick: unexpected sample size in stream: %d bits", (int) metaData.m_sampleBits);
}
@@ -344,8 +340,7 @@ void SDRdaemonSourceUDPHandler::tick()
}
SDRdaemonSourceInput::MsgReportSDRdaemonSourceStreamTiming *report = SDRdaemonSourceInput::MsgReportSDRdaemonSourceStreamTiming::create(
m_tv_sec,
m_tv_usec,
m_tv_msec,
m_sdrDaemonBuffer.getBufferLengthInSecs(),
m_sdrDaemonBuffer.getBufferGauge(),
framesDecodingStatus,
@@ -48,8 +48,7 @@ public:
int getSampleRate() const { return m_samplerate; }
int getCenterFrequency() const { return m_centerFrequency * 1000; }
int getBufferGauge() const { return m_sdrDaemonBuffer.getBufferGauge(); }
uint32_t getTVSec() const { return m_tv_sec; }
uint32_t getTVuSec() const { return m_tv_usec; }
uint64_t getTVmSec() const { return m_tv_msec; }
int getMinNbBlocks() { return m_sdrDaemonBuffer.getMinNbBlocks(); }
int getMaxNbRecovery() { return m_sdrDaemonBuffer.getMaxNbRecovery(); }
public slots:
@@ -72,8 +71,7 @@ private:
SampleSinkFifo *m_sampleFifo;
uint32_t m_samplerate;
uint32_t m_centerFrequency;
uint32_t m_tv_sec;
uint32_t m_tv_usec;
uint64_t m_tv_msec;
MessageQueue *m_outputMessageQueueToGUI;
uint32_t m_tickCount;
std::size_t m_samplesCount;
+10 -5
View File
@@ -625,8 +625,9 @@ bool SDRPlayInput::setDeviceCenterFrequency(quint64 freq_hz)
int SDRPlayInput::webapiRunGet(
SWGSDRangel::SWGDeviceState& response,
QString& errorMessage __attribute__((unused)))
QString& errorMessage)
{
(void) errorMessage;
m_deviceAPI->getDeviceEngineStateStr(*response.getState());
return 200;
}
@@ -634,8 +635,9 @@ int SDRPlayInput::webapiRunGet(
int SDRPlayInput::webapiRun(
bool run,
SWGSDRangel::SWGDeviceState& response,
QString& errorMessage __attribute__((unused)))
QString& errorMessage)
{
(void) errorMessage;
m_deviceAPI->getDeviceEngineStateStr(*response.getState());
MsgStartStop *message = MsgStartStop::create(run);
m_inputMessageQueue.push(message);
@@ -651,8 +653,9 @@ int SDRPlayInput::webapiRun(
int SDRPlayInput::webapiSettingsGet(
SWGSDRangel::SWGDeviceSettings& response,
QString& errorMessage __attribute__((unused)))
QString& errorMessage)
{
(void) errorMessage;
response.setSdrPlaySettings(new SWGSDRangel::SWGSDRPlaySettings());
response.getSdrPlaySettings()->init();
webapiFormatDeviceSettings(response, m_settings);
@@ -663,8 +666,9 @@ int SDRPlayInput::webapiSettingsPutPatch(
bool force,
const QStringList& deviceSettingsKeys,
SWGSDRangel::SWGDeviceSettings& response, // query + response
QString& errorMessage __attribute__((unused)))
QString& errorMessage)
{
(void) errorMessage;
SDRPlaySettings settings = m_settings;
if (deviceSettingsKeys.contains("centerFrequency")) {
@@ -759,8 +763,9 @@ void SDRPlayInput::webapiFormatDeviceSettings(SWGSDRangel::SWGDeviceSettings& re
int SDRPlayInput::webapiReportGet(
SWGSDRangel::SWGDeviceReport& response,
QString& errorMessage __attribute__((unused)))
QString& errorMessage)
{
(void) errorMessage;
response.setSdrPlayReport(new SWGSDRangel::SWGSDRPlayReport());
response.getSdrPlayReport()->init();
webapiFormatDeviceReport(response);
@@ -28,8 +28,8 @@ include_directories(
${CMAKE_CURRENT_BINARY_DIR}
${CMAKE_SOURCE_DIR}/swagger/sdrangel/code/qt5/client
${CMAKE_SOURCE_DIR}/devices
${SOAPYSDRSRC}/include
${SOAPYSDRSRC}/src
${SOAPYSDR_SOURCE_DIR}/include
${SOAPYSDR_SOURCE_DIR}/src
)
else (BUILD_DEBIAN)
include_directories(
@@ -56,7 +56,7 @@ add_library(inputsoapysdr SHARED
if (BUILD_DEBIAN)
target_link_libraries(inputsoapysdr
${QT_LIBRARIES}
bladerf
SoapySDR
sdrbase
sdrgui
swagger
@@ -0,0 +1,224 @@
<h1>SoapySDR input plugin</h1>
<h2>Introduction</h2>
This input sample source plugin gets its samples from a device interfaced with [SoapySDR](https://github.com/pothosware/SoapySDR/wiki).
SoapySDR is a [C/C++ API](https://github.com/pothosware/SoapySDR/blob/master/include/SoapySDR/Device.hpp) that interfaces SDR hardware on one side and application software on the other. Due to its very generic nature it was fairly difficult to implement and specific UI widgets were developped to handle specific types of parameters. The level of control depends on how the device API was implemented by the vendors. On application side some parts of the API have not been implemented and can be left as possible enhancements (see next). In any case it is recommended to use the native plugins if they are available.
SoapySDR devices appear in the list of available devices in the order they are listed in the API call to SoapySDR. If more than one device controlled by SoapySDR is listed then its sequence number is incremented like:
- SoapySDR[0:0] Generic RTL...
- SoapySDR[1:0] Generic RTL...
If the same device exposes several channels they appear as distinct devices with the channel number incremented like:
- SoapySDR[1:0] LimeSDR...
- SoapySDR[1:1] LimeSDR...
This works similarly to LimeSDR USB or BladeRF 2.0 micro
<h2>Binary distributions</h2>
The binary distributions provide only the SoapySDR base library. It is your responsibility to install SoapySDR in your system with the SoapySDR plugins suitable for your hardware.
<h2>SoapySDR API implementation</h2>
Not all parts are implemented. Currently the following have been left out:
- Frequency API tuning arguments. The tuning elements are of course supported.
- Clocking API
- Time API
- Sensor API
- Register API
- GPIO API
- I2C API
- SPI API
- UART API
<h2>Particular considerations concerning hardware</h2>
In general as previously stated you should choose the native plugins if they are available. These are:
- Airspy
- AirspyHF
- BladeRF
- HackRF
- LimeSDR
- PlutoSDR
- RTLSDR
- SDRplay RSP1
The following paragraphs list the known issues or oddities.
<h3>BladeRF</h3>
It is very important NOT to use SoapySDR. The default parameters are set to flash the FPGA but as this does not suceeds it results in a FPGA image wipe out and the device returns in "Cypress" mode. It is not too difficult to recover but there is no point risking the hassle.
<h3>SDRplay RSP2</h3>
Do not use sample rates lower than 2 MS/s
<h3>Red Pitaya</h3>
When installed the Red Pitaya SoapySDR plugin lists a Red Pitaya device even if there is no Red Pitaya attached. Trying to select and start it when there is no Red Pitaya will result in program crash.
<h2>Interface</h2>
![SoapySDR input plugin GUI](../../../doc/img/SoapySDRInput_plugin1.png)
The top part described by number tags is common for all devices. The bottom part under the "A" tag depends on the SoapySDR device implementation. The corresponding widgets are stacked vertically inside a scrollable area as there may be many controls depending on how the device interface is implemented in SoapySDR. Move the slider on the right to see all parameters available.
<h3>1: Common stream parameters</h3>
![SDR Daemon source input stream GUI](../../../doc/img/SDRdaemonSource_plugin_01.png)
<h4>1.1: Frequency</h4>
This is the center frequency of reception in kHz. The center frequency is usually the same for all Rx channels. The GUI of the sibling channel if present is adjusted automatically if necessary. This control corresponds to the first SoapySDR tuning element usually labeled as "RF" and would generally control the main local oscillator (LO).
Use the wheels to adjust the value. 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.
<h4>1.2: Start/Stop</h4>
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, plug back in and start again. Check the console log for possible errors.
<h4>1.3: Record</h4>
Record baseband I/Q stream toggle button
<h4>1.4: Stream sample rate</h4>
Baseband I/Q sample rate in kS/s. This is the device sample rate (the "SR" SoapySDR control) divided by the decimation factor (4).
<h3>2: Software auto correction options</h3>
These buttons control the SDRangel internal DSP auto correction options:
- **DC**: auto remove DC component
- **IQ**: auto make I/Q balance. The DC correction must be enabled for this to be effective.
<h3>3: Baseband center frequency position relative the LO center frequency</h3>
Possible values are:
- **Cen**: the decimation operation takes place around the LO frequency Fs
- **Inf**: the decimation operation takes place around Fs - Fc.
- **Sup**: the decimation operation takes place around Fs + Fc.
With SR as the sample rate before decimation Fc is calculated as:
- if decimation n is 4 or lower: Fc = SR/2^(log2(n)-1). The device center frequency is on the side of the baseband. You need a RF filter bandwidth at least twice the baseband.
- if decimation n is 8 or higher: Fc = SR/n. The device center frequency is half the baseband away from the side of the baseband. You need a RF filter bandwidth at least 3 times the baseband.
<h3>4: Decimation factor</h3>
The I/Q stream from the SoapySDR I/Q stream is downsampled by a power of two before being sent to the passband. Possible values are increasing powers of two: 1 (no decimation), 2, 4, 8, 16, 32, 64.
<h3>5: Transverter mode open dialog</h3>
This button opens a dialog to set the transverter mode frequency translation options:
![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>5.1: Translating frequency</h4>
You can set the translating frequency in Hz with this dial. The manipulation of the dial is described in (1.1: Frequency).
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>5.2: Translating frequency enable/disable</h4>
Use this toggle button to activate or deactivate the frequency translation
<h4>5.3: Confirmation buttons</h4>
Use these buttons to confirm ("OK") or dismiss ("Cancel") your changes.
<h3>6: Software LO ppm correction</h3>
Use this slider to adjust SDRangel internal LO correction in ppm. It can be varied from -100.0 to 100.0 in 0.1 steps and is applied in software when calculating the frequency at which the LO should be set.
<h2>A: SoapySDR variable interface</h2>
The form of widgets is closely related to the type of setting defined in the [SoapySDR interface](https://github.com/pothosware/SoapySDR/blob/master/include/SoapySDR/Types.hpp). These are:
- Ranges
- Continuous range when maximum and minimum are different
- Discrete value when maximum and minimum are equal. Usually this appears in a range list to define a set of values
- List of ranges: more than one range applies to the same setting
- Arguments defined by
- type: boolean, integer, floating point, string
- nature: continuous or discrete
- String list
<h3>A.1: Continuous range</h3>
If the range is all in the positive domain the unsigned variation is used:
![SoapySDR input plugin GUI](../../../doc/img/SoapySDR_range_pos.png)
Note that the same widget is used for single ranges and ranges list. In this case the range selection combo on the right is disabled. The manipulation of the dial is described in (1.1: Frequency)
If the range is in both the positive and negative domains the signed variation is used:
![SoapySDR input plugin GUI](../../../doc/img/SoapySDR_range_neg.png)
If the range applies to a gain a slider is used:
![SoapySDR input plugin GUI](../../../doc/img/SoapySDR_range_gain.png)
<h3>A.2: Discrete range</h3>
Appears with a combo box to select a discrete value:
![SoapySDR input plugin GUI](../../../doc/img/SoapySDR_range_discrete.png)
<h3>A.3: List of ranges</h3>
In this case the range selection combo on the right is enabled:
![SoapySDR input plugin GUI](../../../doc/img/SoapySDR_range_list1.png)
<h3>A.4: Boolean argument</h3>
A checkbox is used to control boolean values:
![SoapySDR input plugin GUI](../../../doc/img/SoapySDR_arg_bool2.png)
For AGC, Auto DC and Auto IQ corrections the checkbox has its text label on the right:
![SoapySDR input plugin GUI](../../../doc/img/SoapySDR_arg_bool1.png)
When set (true) a checkbox is lit in orange:
![SoapySDR input plugin GUI](../../../doc/img/SoapySDR_arg_bool3.png)
<h3>A.5: Int, Float and String arguments</h3>
For all these types of values a line editor is used. Numerical values are parsed from string:
![SoapySDR input plugin GUI](../../../doc/img/SoapySDR_arg_str.png)
<h3>A.6 String lists</h3>
Some parameters like the antenna ports are expressed as a list of possible string values. These are presented in a combo box:
![SoapySDR input plugin GUI](../../../doc/img/SoapySDR_arg_strlist.png)
@@ -18,6 +18,12 @@
#include "util/simpleserializer.h"
#include "SWGDeviceSettings.h"
#include "SWGSoapySDRInputSettings.h"
#include "SWGDeviceState.h"
#include "SWGDeviceReport.h"
#include "SWGSoapySDRReport.h"
#include "device/devicesourceapi.h"
#include "device/devicesinkapi.h"
#include "dsp/dspcommands.h"
@@ -42,6 +48,9 @@ SoapySDRInput::SoapySDRInput(DeviceSourceAPI *deviceAPI) :
{
openDevice();
initGainSettings(m_settings);
initTunableElementsSettings(m_settings);
initStreamArgSettings(m_settings);
initDeviceArgSettings(m_settings);
m_fileSink = new FileRecord(QString("test_%1.sdriq").arg(m_deviceAPI->getDeviceUID()));
m_deviceAPI->addSink(m_fileSink);
@@ -269,6 +278,17 @@ const std::vector<DeviceSoapySDRParams::GainSetting>& SoapySDRInput::getIndividu
return channelSettings->m_gainSettings;
}
const SoapySDR::ArgInfoList& SoapySDRInput::getStreamArgInfoList()
{
const DeviceSoapySDRParams::ChannelSettings* channelSettings = m_deviceShared.m_deviceParams->getRxChannelSettings(m_deviceShared.m_channel);
return channelSettings->m_streamSettingsArgs;
}
const SoapySDR::ArgInfoList& SoapySDRInput::getDeviceArgInfoList()
{
return m_deviceShared.m_deviceParams->getDeviceArgs();
}
void SoapySDRInput::initGainSettings(SoapySDRInputSettings& settings)
{
const DeviceSoapySDRParams::ChannelSettings* channelSettings = m_deviceShared.m_deviceParams->getRxChannelSettings(m_deviceShared.m_channel);
@@ -282,6 +302,63 @@ void SoapySDRInput::initGainSettings(SoapySDRInputSettings& settings)
updateGains(m_deviceShared.m_device, m_deviceShared.m_channel, settings);
}
void SoapySDRInput::initTunableElementsSettings(SoapySDRInputSettings& settings)
{
const DeviceSoapySDRParams::ChannelSettings* channelSettings = m_deviceShared.m_deviceParams->getRxChannelSettings(m_deviceShared.m_channel);
settings.m_tunableElements.clear();
bool first = true;
for (const auto &it : channelSettings->m_frequencySettings)
{
if (first)
{
first = false;
continue;
}
settings.m_tunableElements[QString(it.m_name.c_str())] = 0.0;
}
updateTunableElements(m_deviceShared.m_device, m_deviceShared.m_channel, settings);
}
void SoapySDRInput::initStreamArgSettings(SoapySDRInputSettings& settings)
{
const DeviceSoapySDRParams::ChannelSettings* channelSettings = m_deviceShared.m_deviceParams->getRxChannelSettings(m_deviceShared.m_channel);
settings.m_streamArgSettings.clear();
for (const auto &it : channelSettings->m_streamSettingsArgs)
{
if (it.type == SoapySDR::ArgInfo::BOOL) {
settings.m_streamArgSettings[QString(it.key.c_str())] = QVariant(it.value == "true");
} else if (it.type == SoapySDR::ArgInfo::INT) {
settings.m_streamArgSettings[QString(it.key.c_str())] = QVariant(atoi(it.value.c_str()));
} else if (it.type == SoapySDR::ArgInfo::FLOAT) {
settings.m_streamArgSettings[QString(it.key.c_str())] = QVariant(atof(it.value.c_str()));
} else if (it.type == SoapySDR::ArgInfo::STRING) {
settings.m_streamArgSettings[QString(it.key.c_str())] = QVariant(it.value.c_str());
}
}
}
void SoapySDRInput::initDeviceArgSettings(SoapySDRInputSettings& settings)
{
settings.m_deviceArgSettings.clear();
for (const auto &it : m_deviceShared.m_deviceParams->getDeviceArgs())
{
if (it.type == SoapySDR::ArgInfo::BOOL) {
settings.m_deviceArgSettings[QString(it.key.c_str())] = QVariant(it.value == "true");
} else if (it.type == SoapySDR::ArgInfo::INT) {
settings.m_deviceArgSettings[QString(it.key.c_str())] = QVariant(atoi(it.value.c_str()));
} else if (it.type == SoapySDR::ArgInfo::FLOAT) {
settings.m_deviceArgSettings[QString(it.key.c_str())] = QVariant(atof(it.value.c_str()));
} else if (it.type == SoapySDR::ArgInfo::STRING) {
settings.m_deviceArgSettings[QString(it.key.c_str())] = QVariant(it.value.c_str());
}
}
}
bool SoapySDRInput::hasDCAutoCorrection()
{
const DeviceSoapySDRParams::ChannelSettings* channelSettings = m_deviceShared.m_deviceParams->getRxChannelSettings(m_deviceShared.m_channel);
@@ -592,8 +669,9 @@ QByteArray SoapySDRInput::serialize() const
return s.final();
}
bool SoapySDRInput::deserialize(const QByteArray& data __attribute__((unused)))
bool SoapySDRInput::deserialize(const QByteArray& data)
{
(void) data;
return false;
}
@@ -613,7 +691,7 @@ quint64 SoapySDRInput::getCenterFrequency() const
return m_settings.m_centerFrequency;
}
void SoapySDRInput::setCenterFrequency(qint64 centerFrequency __attribute__((unused)))
void SoapySDRInput::setCenterFrequency(qint64 centerFrequency)
{
SoapySDRInputSettings settings = m_settings;
settings.m_centerFrequency = centerFrequency;
@@ -662,7 +740,18 @@ void SoapySDRInput::updateGains(SoapySDR::Device *dev, int requestedChannel, Soa
}
}
bool SoapySDRInput::handleMessage(const Message& message __attribute__((unused)))
void SoapySDRInput::updateTunableElements(SoapySDR::Device *dev, int requestedChannel, SoapySDRInputSettings& settings)
{
if (dev == 0) {
return;
}
for (const auto &name : settings.m_tunableElements.keys()) {
settings.m_tunableElements[name] = dev->getFrequency(SOAPY_SDR_RX, requestedChannel, name.toStdString());
}
}
bool SoapySDRInput::handleMessage(const Message& message)
{
if (MsgConfigureSoapySDRInput::match(message))
{
@@ -751,6 +840,33 @@ bool SoapySDRInput::handleMessage(const Message& message __attribute__((unused))
return true;
}
else if (DeviceSoapySDRShared::MsgReportDeviceArgsChange::match(message))
{
DeviceSoapySDRShared::MsgReportDeviceArgsChange& report = (DeviceSoapySDRShared::MsgReportDeviceArgsChange&) message;
QMap<QString, QVariant> deviceArgSettings = report.getDeviceArgSettings();
for (const auto &oname : m_settings.m_deviceArgSettings.keys())
{
auto nvalue = deviceArgSettings.find(oname);
if (nvalue != deviceArgSettings.end() && (m_settings.m_deviceArgSettings[oname] != *nvalue))
{
m_settings.m_deviceArgSettings[oname] = *nvalue;
qDebug("SoapySDRInput::handleMessage: MsgReportDeviceArgsChange: device argument %s set to %s",
oname.toStdString().c_str(), nvalue->toString().toStdString().c_str());
}
}
// propagate settings to GUI if any
if (getMessageQueueToGUI())
{
DeviceSoapySDRShared::MsgReportDeviceArgsChange *reportToGUI = DeviceSoapySDRShared::MsgReportDeviceArgsChange::create(
m_settings.m_deviceArgSettings);
getMessageQueueToGUI()->push(reportToGUI);
}
return true;
}
else
{
return false;
@@ -763,6 +879,7 @@ bool SoapySDRInput::applySettings(const SoapySDRInputSettings& settings, bool fo
bool forwardChangeToBuddies = false;
bool globalGainChanged = false;
bool individualGainsChanged = false;
bool deviceArgsChanged = false;
SoapySDR::Device *dev = m_deviceShared.m_device;
SoapySDRInputThread *inputThread = findThread();
@@ -892,7 +1009,7 @@ bool SoapySDRInput::applySettings(const SoapySDRInputSettings& settings, bool fo
{
auto nvalue = settings.m_tunableElements.find(oname);
if (nvalue != settings.m_tunableElements.end() && (m_settings.m_tunableElements[oname] != *nvalue))
if (nvalue != settings.m_tunableElements.end() && ((m_settings.m_tunableElements[oname] != *nvalue) ||force))
{
if (dev != 0)
{
@@ -1021,6 +1138,57 @@ bool SoapySDRInput::applySettings(const SoapySDRInputSettings& settings, bool fo
}
}
for (const auto &oname : m_settings.m_streamArgSettings.keys())
{
auto nvalue = settings.m_streamArgSettings.find(oname);
if (nvalue != settings.m_streamArgSettings.end() && ((m_settings.m_streamArgSettings[oname] != *nvalue) || force))
{
if (dev != 0)
{
try
{
dev->writeSetting(SOAPY_SDR_RX, requestedChannel, oname.toStdString(), nvalue->toString().toStdString());
qDebug("SoapySDRInput::applySettings: stream argument %s set to %s",
oname.toStdString().c_str(), nvalue->toString().toStdString().c_str());
}
catch (const std::exception &ex)
{
qCritical("SoapySDRInput::applySettings: cannot set stream argument %s to %s: %s",
oname.toStdString().c_str(), nvalue->toString().toStdString().c_str(), ex.what());
}
}
m_settings.m_streamArgSettings[oname] = *nvalue;
}
}
for (const auto &oname : m_settings.m_deviceArgSettings.keys())
{
auto nvalue = settings.m_deviceArgSettings.find(oname);
if (nvalue != settings.m_deviceArgSettings.end() && ((m_settings.m_deviceArgSettings[oname] != *nvalue) || force))
{
if (dev != 0)
{
try
{
dev->writeSetting(oname.toStdString(), nvalue->toString().toStdString());
qDebug("SoapySDRInput::applySettings: device argument %s set to %s",
oname.toStdString().c_str(), nvalue->toString().toStdString().c_str());
}
catch (const std::exception &ex)
{
qCritical("SoapySDRInput::applySettings: cannot set device argument %s to %s: %s",
oname.toStdString().c_str(), nvalue->toString().toStdString().c_str(), ex.what());
}
}
m_settings.m_deviceArgSettings[oname] = *nvalue;
deviceArgsChanged = true;
}
}
if (forwardChangeOwnDSP)
{
int sampleRate = settings.m_devSampleRate/(1<<settings.m_log2Decim);
@@ -1031,7 +1199,7 @@ bool SoapySDRInput::applySettings(const SoapySDRInputSettings& settings, bool fo
if (forwardChangeToBuddies)
{
// send to source buddies
// send to buddies
const std::vector<DeviceSourceAPI*>& sourceBuddies = m_deviceAPI->getSourceBuddies();
const std::vector<DeviceSinkAPI*>& sinkBuddies = m_deviceAPI->getSinkBuddies();
@@ -1058,6 +1226,27 @@ bool SoapySDRInput::applySettings(const SoapySDRInputSettings& settings, bool fo
}
}
if (deviceArgsChanged)
{
// send to buddies
const std::vector<DeviceSourceAPI*>& sourceBuddies = m_deviceAPI->getSourceBuddies();
const std::vector<DeviceSinkAPI*>& sinkBuddies = m_deviceAPI->getSinkBuddies();
for (const auto &itSource : sourceBuddies)
{
DeviceSoapySDRShared::MsgReportDeviceArgsChange *report = DeviceSoapySDRShared::MsgReportDeviceArgsChange::create(
settings.m_deviceArgSettings);
itSource->getSampleSourceInputMessageQueue()->push(report);
}
for (const auto &itSink : sinkBuddies)
{
DeviceSoapySDRShared::MsgReportDeviceArgsChange *report = DeviceSoapySDRShared::MsgReportDeviceArgsChange::create(
settings.m_deviceArgSettings);
itSink->getSampleSinkInputMessageQueue()->push(report);
}
}
m_settings = settings;
if (globalGainChanged || individualGainsChanged)
@@ -1085,7 +1274,520 @@ bool SoapySDRInput::applySettings(const SoapySDRInputSettings& settings, bool fo
<< " m_softIQCorrection: " << m_settings.m_softIQCorrection
<< " m_antenna: " << m_settings.m_antenna
<< " m_bandwidth: " << m_settings.m_bandwidth
<< " m_globalGain: " << m_settings.m_globalGain;
<< " m_globalGain: " << m_settings.m_globalGain
<< " force: " << force;
QMap<QString, double>::const_iterator doubleIt = m_settings.m_individualGains.begin();
for(; doubleIt != m_settings.m_individualGains.end(); ++doubleIt) {
qDebug("SoapySDRInput::applySettings: m_individualGains[%s]: %lf", doubleIt.key().toStdString().c_str(), doubleIt.value());
}
doubleIt = m_settings.m_tunableElements.begin();
for(; doubleIt != m_settings.m_tunableElements.end(); ++doubleIt) {
qDebug("SoapySDRInput::applySettings: m_tunableElements[%s]: %lf", doubleIt.key().toStdString().c_str(), doubleIt.value());
}
QMap<QString, QVariant>::const_iterator varIt = m_settings.m_deviceArgSettings.begin();
for(; varIt != m_settings.m_deviceArgSettings.end(); ++varIt)
{
qDebug("SoapySDRInput::applySettings: m_deviceArgSettings[%s] (type %d): %s",
varIt.key().toStdString().c_str(),
(int) varIt.value().type(), // bool: 1, int: 2, double: 6, string: 10 (http://doc.qt.io/archives/qt-4.8/qvariant.html)
varIt.value().toString().toStdString().c_str());
}
varIt = m_settings.m_streamArgSettings.begin();
for(; varIt != m_settings.m_streamArgSettings.end(); ++varIt)
{
qDebug("SoapySDRInput::applySettings: m_streamArgSettings[%s] (type %d): %s",
varIt.key().toStdString().c_str(),
(int) varIt.value().type(),
varIt.value().toString().toStdString().c_str());
}
return true;
}
int SoapySDRInput::webapiSettingsGet(
SWGSDRangel::SWGDeviceSettings& response,
QString& errorMessage)
{
(void) errorMessage;
response.setSoapySdrInputSettings(new SWGSDRangel::SWGSoapySDRInputSettings());
response.getSoapySdrInputSettings()->init();
webapiFormatDeviceSettings(response, m_settings);
return 200;
}
int SoapySDRInput::webapiSettingsPutPatch(
bool force,
const QStringList& deviceSettingsKeys,
SWGSDRangel::SWGDeviceSettings& response, // query + response
QString& errorMessage)
{
(void) errorMessage;
SoapySDRInputSettings settings = m_settings;
if (deviceSettingsKeys.contains("centerFrequency")) {
settings.m_centerFrequency = response.getSoapySdrInputSettings()->getCenterFrequency();
}
if (deviceSettingsKeys.contains("LOppmTenths")) {
settings.m_LOppmTenths = response.getSoapySdrInputSettings()->getLOppmTenths();
}
if (deviceSettingsKeys.contains("devSampleRate")) {
settings.m_devSampleRate = response.getSoapySdrInputSettings()->getDevSampleRate();
}
if (deviceSettingsKeys.contains("bandwidth")) {
settings.m_bandwidth = response.getSoapySdrInputSettings()->getBandwidth();
}
if (deviceSettingsKeys.contains("log2Decim")) {
settings.m_log2Decim = response.getSoapySdrInputSettings()->getLog2Decim();
}
if (deviceSettingsKeys.contains("fcPos")) {
settings.m_fcPos = static_cast<SoapySDRInputSettings::fcPos_t>(response.getSoapySdrInputSettings()->getFcPos());
}
if (deviceSettingsKeys.contains("softDCCorrection")) {
settings.m_softDCCorrection = response.getSoapySdrInputSettings()->getSoftDcCorrection() != 0;
}
if (deviceSettingsKeys.contains("softIQCorrection")) {
settings.m_softIQCorrection = response.getSoapySdrInputSettings()->getSoftIqCorrection() != 0;
}
if (deviceSettingsKeys.contains("transverterDeltaFrequency")) {
settings.m_transverterDeltaFrequency = response.getSoapySdrInputSettings()->getTransverterDeltaFrequency();
}
if (deviceSettingsKeys.contains("transverterMode")) {
settings.m_transverterMode = response.getSoapySdrInputSettings()->getTransverterMode() != 0;
}
if (deviceSettingsKeys.contains("fileRecordName")) {
settings.m_fileRecordName = *response.getSoapySdrInputSettings()->getFileRecordName();
}
if (deviceSettingsKeys.contains("antenna")) {
settings.m_antenna = *response.getSoapySdrInputSettings()->getAntenna();
}
if (deviceSettingsKeys.contains("tunableElements"))
{
QList<SWGSDRangel::SWGArgValue*> *tunableElements = response.getSoapySdrInputSettings()->getTunableElements();
for (const auto &itArg : *tunableElements)
{
QMap<QString, double>::iterator itSettings = settings.m_tunableElements.find(*(itArg->getKey()));
if (itSettings != settings.m_tunableElements.end())
{
QVariant v = webapiVariantFromArgValue(itArg);
itSettings.value() = v.toDouble();
}
}
}
if (deviceSettingsKeys.contains("globalGain")) {
settings.m_globalGain = response.getSoapySdrInputSettings()->getGlobalGain();
}
if (deviceSettingsKeys.contains("individualGains"))
{
QList<SWGSDRangel::SWGArgValue*> *individualGains = response.getSoapySdrInputSettings()->getIndividualGains();
for (const auto &itArg : *individualGains)
{
QMap<QString, double>::iterator itSettings = settings.m_individualGains.find(*(itArg->getKey()));
if (itSettings != settings.m_individualGains.end())
{
QVariant v = webapiVariantFromArgValue(itArg);
itSettings.value() = v.toDouble();
}
}
}
if (deviceSettingsKeys.contains("autoGain")) {
settings.m_autoGain = response.getSoapySdrInputSettings()->getAutoGain() != 0;
}
if (deviceSettingsKeys.contains("autoDCCorrection")) {
settings.m_autoDCCorrection = response.getSoapySdrInputSettings()->getAutoDcCorrection() != 0;
}
if (deviceSettingsKeys.contains("autoIQCorrection")) {
settings.m_autoIQCorrection = response.getSoapySdrInputSettings()->getAutoIqCorrection() != 0;
}
if (deviceSettingsKeys.contains("dcCorrection"))
{
settings.m_dcCorrection.real(response.getSoapySdrInputSettings()->getDcCorrection()->getReal());
settings.m_dcCorrection.imag(response.getSoapySdrInputSettings()->getDcCorrection()->getImag());
}
if (deviceSettingsKeys.contains("iqCorrection"))
{
settings.m_iqCorrection.real(response.getSoapySdrInputSettings()->getIqCorrection()->getReal());
settings.m_iqCorrection.imag(response.getSoapySdrInputSettings()->getIqCorrection()->getImag());
}
if (deviceSettingsKeys.contains("streamArgSettings"))
{
QList<SWGSDRangel::SWGArgValue*> *streamArgSettings = response.getSoapySdrInputSettings()->getStreamArgSettings();
for (const auto itArg : *streamArgSettings)
{
QMap<QString, QVariant>::iterator itSettings = settings.m_streamArgSettings.find(*itArg->getKey());
if (itSettings != settings.m_streamArgSettings.end()) {
itSettings.value() = webapiVariantFromArgValue(itArg);
}
}
}
if (deviceSettingsKeys.contains("deviceArgSettings"))
{
QList<SWGSDRangel::SWGArgValue*> *deviceArgSettings = response.getSoapySdrInputSettings()->getDeviceArgSettings();
for (const auto itArg : *deviceArgSettings)
{
QMap<QString, QVariant>::iterator itSettings = settings.m_deviceArgSettings.find(*itArg->getKey());
if (itSettings != settings.m_deviceArgSettings.end()) {
itSettings.value() = webapiVariantFromArgValue(itArg);
}
}
}
MsgConfigureSoapySDRInput *msg = MsgConfigureSoapySDRInput::create(settings, force);
m_inputMessageQueue.push(msg);
if (m_guiMessageQueue) // forward to GUI if any
{
MsgConfigureSoapySDRInput *msgToGUI = MsgConfigureSoapySDRInput::create(settings, force);
m_guiMessageQueue->push(msgToGUI);
}
webapiFormatDeviceSettings(response, settings);
return 200;
}
int SoapySDRInput::webapiReportGet(SWGSDRangel::SWGDeviceReport& response, QString& errorMessage)
{
(void) errorMessage;
response.setSoapySdrInputReport(new SWGSDRangel::SWGSoapySDRReport());
response.getSoapySdrInputReport()->init();
webapiFormatDeviceReport(response);
return 200;
}
int SoapySDRInput::webapiRunGet(
SWGSDRangel::SWGDeviceState& response,
QString& errorMessage)
{
(void) errorMessage;
m_deviceAPI->getDeviceEngineStateStr(*response.getState());
return 200;
}
int SoapySDRInput::webapiRun(
bool run,
SWGSDRangel::SWGDeviceState& response,
QString& errorMessage)
{
(void) errorMessage;
m_deviceAPI->getDeviceEngineStateStr(*response.getState());
MsgStartStop *message = MsgStartStop::create(run);
m_inputMessageQueue.push(message);
if (m_guiMessageQueue) // forward to GUI if any
{
MsgStartStop *msgToGUI = MsgStartStop::create(run);
m_guiMessageQueue->push(msgToGUI);
}
return 200;
}
void SoapySDRInput::webapiFormatDeviceSettings(SWGSDRangel::SWGDeviceSettings& response, const SoapySDRInputSettings& settings)
{
response.getSoapySdrInputSettings()->setCenterFrequency(settings.m_centerFrequency);
response.getSoapySdrInputSettings()->setLOppmTenths(settings.m_LOppmTenths);
response.getSoapySdrInputSettings()->setDevSampleRate(settings.m_devSampleRate);
response.getSoapySdrInputSettings()->setLog2Decim(settings.m_log2Decim);
response.getSoapySdrInputSettings()->setFcPos((int) settings.m_fcPos);
response.getSoapySdrInputSettings()->setSoftDcCorrection(settings.m_softDCCorrection ? 1 : 0);
response.getSoapySdrInputSettings()->setSoftIqCorrection(settings.m_softIQCorrection ? 1 : 0);
response.getSoapySdrInputSettings()->setTransverterDeltaFrequency(settings.m_transverterDeltaFrequency);
response.getSoapySdrInputSettings()->setTransverterMode(settings.m_transverterMode ? 1 : 0);
if (response.getSoapySdrInputSettings()->getFileRecordName()) {
*response.getSoapySdrInputSettings()->getFileRecordName() = settings.m_fileRecordName;
} else {
response.getSoapySdrInputSettings()->setFileRecordName(new QString(settings.m_fileRecordName));
}
if (response.getSoapySdrInputSettings()->getAntenna()) {
*response.getSoapySdrInputSettings()->getAntenna() = settings.m_antenna;
} else {
response.getSoapySdrInputSettings()->setAntenna(new QString(settings.m_antenna));
}
if (response.getSoapySdrInputSettings()->getTunableElements()) {
response.getSoapySdrInputSettings()->getTunableElements()->clear();
} else {
response.getSoapySdrInputSettings()->setTunableElements(new QList<SWGSDRangel::SWGArgValue*>);
}
for (const auto itName : settings.m_tunableElements.keys())
{
response.getSoapySdrInputSettings()->getTunableElements()->append(new SWGSDRangel::SWGArgValue);
response.getSoapySdrInputSettings()->getTunableElements()->back()->setKey(new QString(itName));
double value = settings.m_tunableElements.value(itName);
response.getSoapySdrInputSettings()->getTunableElements()->back()->setValueString(new QString(tr("%1").arg(value)));
response.getSoapySdrInputSettings()->getTunableElements()->back()->setValueType(new QString("float"));
}
response.getSoapySdrInputSettings()->setBandwidth(settings.m_bandwidth);
response.getSoapySdrInputSettings()->setGlobalGain(settings.m_globalGain);
if (response.getSoapySdrInputSettings()->getIndividualGains()) {
response.getSoapySdrInputSettings()->getIndividualGains()->clear();
} else {
response.getSoapySdrInputSettings()->setIndividualGains(new QList<SWGSDRangel::SWGArgValue*>);
}
for (const auto itName : settings.m_individualGains.keys())
{
response.getSoapySdrInputSettings()->getIndividualGains()->append(new SWGSDRangel::SWGArgValue);
response.getSoapySdrInputSettings()->getIndividualGains()->back()->setKey(new QString(itName));
double value = settings.m_individualGains.value(itName);
response.getSoapySdrInputSettings()->getIndividualGains()->back()->setValueString(new QString(tr("%1").arg(value)));
response.getSoapySdrInputSettings()->getIndividualGains()->back()->setValueType(new QString("float"));
}
response.getSoapySdrInputSettings()->setAutoGain(settings.m_autoGain ? 1 : 0);
response.getSoapySdrInputSettings()->setAutoDcCorrection(settings.m_autoDCCorrection ? 1 : 0);
response.getSoapySdrInputSettings()->setAutoIqCorrection(settings.m_autoIQCorrection ? 1 : 0);
if (!response.getSoapySdrInputSettings()->getDcCorrection()) {
response.getSoapySdrInputSettings()->setDcCorrection(new SWGSDRangel::SWGComplex());
}
response.getSoapySdrInputSettings()->getDcCorrection()->setReal(settings.m_dcCorrection.real());
response.getSoapySdrInputSettings()->getDcCorrection()->setImag(settings.m_dcCorrection.imag());
if (!response.getSoapySdrInputSettings()->getIqCorrection()) {
response.getSoapySdrInputSettings()->setIqCorrection(new SWGSDRangel::SWGComplex());
}
response.getSoapySdrInputSettings()->getIqCorrection()->setReal(settings.m_iqCorrection.real());
response.getSoapySdrInputSettings()->getIqCorrection()->setImag(settings.m_iqCorrection.imag());
if (response.getSoapySdrInputSettings()->getStreamArgSettings()) {
response.getSoapySdrInputSettings()->getStreamArgSettings()->clear();
} else {
response.getSoapySdrInputSettings()->setStreamArgSettings(new QList<SWGSDRangel::SWGArgValue*>);
}
for (const auto itName : settings.m_streamArgSettings.keys())
{
response.getSoapySdrInputSettings()->getStreamArgSettings()->append(new SWGSDRangel::SWGArgValue);
response.getSoapySdrInputSettings()->getStreamArgSettings()->back()->setKey(new QString(itName));
const QVariant& v = settings.m_streamArgSettings.value(itName);
webapiFormatArgValue(v, response.getSoapySdrInputSettings()->getStreamArgSettings()->back());
}
if (response.getSoapySdrInputSettings()->getDeviceArgSettings()) {
response.getSoapySdrInputSettings()->getDeviceArgSettings()->clear();
} else {
response.getSoapySdrInputSettings()->setDeviceArgSettings(new QList<SWGSDRangel::SWGArgValue*>);
}
for (const auto itName : settings.m_deviceArgSettings.keys())
{
response.getSoapySdrInputSettings()->getDeviceArgSettings()->append(new SWGSDRangel::SWGArgValue);
response.getSoapySdrInputSettings()->getDeviceArgSettings()->back()->setKey(new QString(itName));
const QVariant& v = settings.m_deviceArgSettings.value(itName);
webapiFormatArgValue(v, response.getSoapySdrInputSettings()->getDeviceArgSettings()->back());
}
}
void SoapySDRInput::webapiFormatDeviceReport(SWGSDRangel::SWGDeviceReport& response)
{
const DeviceSoapySDRParams::ChannelSettings* channelSettings = m_deviceShared.m_deviceParams->getRxChannelSettings(m_deviceShared.m_channel);
response.getSoapySdrInputReport()->setDeviceSettingsArgs(new QList<SWGSDRangel::SWGArgInfo*>);
for (const auto itArg : m_deviceShared.m_deviceParams->getDeviceArgs())
{
response.getSoapySdrInputReport()->getDeviceSettingsArgs()->append(new SWGSDRangel::SWGArgInfo());
webapiFormatArgInfo(itArg, response.getSoapySdrInputReport()->getDeviceSettingsArgs()->back());
}
response.getSoapySdrInputReport()->setStreamSettingsArgs(new QList<SWGSDRangel::SWGArgInfo*>);
for (const auto itArg : channelSettings->m_streamSettingsArgs)
{
response.getSoapySdrInputReport()->getStreamSettingsArgs()->append(new SWGSDRangel::SWGArgInfo());
webapiFormatArgInfo(itArg, response.getSoapySdrInputReport()->getStreamSettingsArgs()->back());
}
response.getSoapySdrInputReport()->setFrequencySettingsArgs(new QList<SWGSDRangel::SWGArgInfo*>);
for (const auto itArg : channelSettings->m_frequencySettingsArgs)
{
response.getSoapySdrInputReport()->getFrequencySettingsArgs()->append(new SWGSDRangel::SWGArgInfo());
webapiFormatArgInfo(itArg, response.getSoapySdrInputReport()->getFrequencySettingsArgs()->back());
}
response.getSoapySdrInputReport()->setHasAgc(channelSettings->m_hasAGC ? 1 : 0);
response.getSoapySdrInputReport()->setHasDcAutoCorrection(channelSettings->m_hasDCAutoCorrection ? 1 : 0);
response.getSoapySdrInputReport()->setHasDcOffsetValue(channelSettings->m_hasDCOffsetValue ? 1 : 0);
response.getSoapySdrInputReport()->setHasFrequencyCorrectionValue(channelSettings->m_hasFrequencyCorrectionValue ? 1 : 0);
response.getSoapySdrInputReport()->setHasIqBalanceValue(channelSettings->m_hasIQBalanceValue ? 1 : 0);
if (channelSettings->m_antennas.size() != 0)
{
response.getSoapySdrInputReport()->setAntennas(new QList<QString *>);
for (const auto itAntenna : channelSettings->m_antennas) {
response.getSoapySdrInputReport()->getAntennas()->append(new QString(itAntenna.c_str()));
}
}
if ((channelSettings->m_gainRange.maximum() != 0.0) || (channelSettings->m_gainRange.minimum() != 0.0))
{
response.getSoapySdrInputReport()->setGainRange(new SWGSDRangel::SWGRangeFloat());
response.getSoapySdrInputReport()->getGainRange()->setMin(channelSettings->m_gainRange.minimum());
response.getSoapySdrInputReport()->getGainRange()->setMax(channelSettings->m_gainRange.maximum());
}
if (channelSettings->m_gainSettings.size() != 0)
{
response.getSoapySdrInputReport()->setGainSettings(new QList<SWGSDRangel::SWGSoapySDRGainSetting*>);
for (const auto itGain : channelSettings->m_gainSettings)
{
response.getSoapySdrInputReport()->getGainSettings()->append(new SWGSDRangel::SWGSoapySDRGainSetting());
response.getSoapySdrInputReport()->getGainSettings()->back()->setRange(new SWGSDRangel::SWGRangeFloat());
response.getSoapySdrInputReport()->getGainSettings()->back()->getRange()->setMin(itGain.m_range.minimum());
response.getSoapySdrInputReport()->getGainSettings()->back()->getRange()->setMax(itGain.m_range.maximum());
response.getSoapySdrInputReport()->getGainSettings()->back()->setName(new QString(itGain.m_name.c_str()));
}
}
if (channelSettings->m_frequencySettings.size() != 0)
{
response.getSoapySdrInputReport()->setFrequencySettings(new QList<SWGSDRangel::SWGSoapySDRFrequencySetting*>);
for (const auto itFreq : channelSettings->m_frequencySettings)
{
response.getSoapySdrInputReport()->getFrequencySettings()->append(new SWGSDRangel::SWGSoapySDRFrequencySetting());
response.getSoapySdrInputReport()->getFrequencySettings()->back()->setRanges(new QList<SWGSDRangel::SWGRangeFloat*>);
for (const auto itRange : itFreq.m_ranges)
{
response.getSoapySdrInputReport()->getFrequencySettings()->back()->getRanges()->append(new SWGSDRangel::SWGRangeFloat());
response.getSoapySdrInputReport()->getFrequencySettings()->back()->getRanges()->back()->setMin(itRange.minimum());
response.getSoapySdrInputReport()->getFrequencySettings()->back()->getRanges()->back()->setMax(itRange.maximum());
}
response.getSoapySdrInputReport()->getFrequencySettings()->back()->setName(new QString(itFreq.m_name.c_str()));
}
}
if (channelSettings->m_ratesRanges.size() != 0)
{
response.getSoapySdrInputReport()->setRatesRanges(new QList<SWGSDRangel::SWGRangeFloat*>);
for (const auto itRange : channelSettings->m_ratesRanges)
{
response.getSoapySdrInputReport()->getRatesRanges()->append(new SWGSDRangel::SWGRangeFloat());
response.getSoapySdrInputReport()->getRatesRanges()->back()->setMin(itRange.minimum());
response.getSoapySdrInputReport()->getRatesRanges()->back()->setMax(itRange.maximum());
}
}
if (channelSettings->m_bandwidthsRanges.size() != 0)
{
response.getSoapySdrInputReport()->setBandwidthsRanges(new QList<SWGSDRangel::SWGRangeFloat*>);
for (const auto itBandwidth : channelSettings->m_bandwidthsRanges)
{
response.getSoapySdrInputReport()->getBandwidthsRanges()->append(new SWGSDRangel::SWGRangeFloat());
response.getSoapySdrInputReport()->getBandwidthsRanges()->back()->setMin(itBandwidth.minimum());
response.getSoapySdrInputReport()->getBandwidthsRanges()->back()->setMax(itBandwidth.maximum());
}
}
}
QVariant SoapySDRInput::webapiVariantFromArgValue(SWGSDRangel::SWGArgValue *argValue)
{
if (*argValue->getValueType() == "bool") {
return QVariant((bool) (*argValue->getValueString() == "1"));
} else if (*argValue->getValueType() == "int") {
return QVariant((int) (atoi(argValue->getValueString()->toStdString().c_str())));
} else if (*argValue->getValueType() == "float") {
return QVariant((double) (atof(argValue->getValueString()->toStdString().c_str())));
} else {
return QVariant(QString(*argValue->getValueString()));
}
}
void SoapySDRInput::webapiFormatArgValue(const QVariant& v, SWGSDRangel::SWGArgValue *argValue)
{
if (v.type() == QVariant::Bool)
{
argValue->setValueType(new QString("bool"));
argValue->setValueString(new QString(v.toBool() ? "1" : "0"));
}
else if (v.type() == QVariant::Int)
{
argValue->setValueType(new QString("int"));
argValue->setValueString(new QString(tr("%1").arg(v.toInt())));
}
else if (v.type() == QVariant::Double)
{
argValue->setValueType(new QString("float"));
argValue->setValueString(new QString(tr("%1").arg(v.toDouble())));
}
else
{
argValue->setValueType(new QString("string"));
argValue->setValueString(new QString(v.toString()));
}
}
void SoapySDRInput::webapiFormatArgInfo(const SoapySDR::ArgInfo& arg, SWGSDRangel::SWGArgInfo *argInfo)
{
argInfo->setKey(new QString(arg.key.c_str()));
if (arg.type == SoapySDR::ArgInfo::BOOL) {
argInfo->setValueType(new QString("bool"));
} else if (arg.type == SoapySDR::ArgInfo::INT) {
argInfo->setValueType(new QString("int"));
} else if (arg.type == SoapySDR::ArgInfo::FLOAT) {
argInfo->setValueType(new QString("float"));
} else {
argInfo->setValueType(new QString("string"));
}
argInfo->setValueString(new QString(arg.value.c_str()));
argInfo->setName(new QString(arg.name.c_str()));
argInfo->setDescription(new QString(arg.description.c_str()));
argInfo->setUnits(new QString(arg.units.c_str()));
if ((arg.range.minimum() != 0.0) || (arg.range.maximum() != 0.0))
{
argInfo->setRange(new SWGSDRangel::SWGRangeFloat());
argInfo->getRange()->setMin(arg.range.minimum());
argInfo->getRange()->setMax(arg.range.maximum());
}
argInfo->setValueOptions(new QList<QString*>);
for (const auto itOpt : arg.options) {
argInfo->getValueOptions()->append(new QString(itOpt.c_str()));
}
argInfo->setOptionNames(new QList<QString*>);
for (const auto itOpt : arg.optionNames) {
argInfo->getOptionNames()->append(new QString(itOpt.c_str()));
}
}
@@ -33,6 +33,13 @@ class FileRecord;
namespace SoapySDR
{
class Device;
class ArgInfo;
}
namespace SWGSDRangel
{
class SWGArgValue;
class SWGArgInfo;
}
class SoapySDRInput : public DeviceSampleSource
@@ -155,12 +162,40 @@ public:
int getAntennaIndex(const std::string& antenna);
const std::vector<DeviceSoapySDRParams::FrequencySetting>& getTunableElements();
const std::vector<DeviceSoapySDRParams::GainSetting>& getIndividualGainsRanges();
const SoapySDR::ArgInfoList& getStreamArgInfoList();
const SoapySDR::ArgInfoList& getDeviceArgInfoList();
void initGainSettings(SoapySDRInputSettings& settings);
void initTunableElementsSettings(SoapySDRInputSettings& settings);
void initStreamArgSettings(SoapySDRInputSettings& settings);
void initDeviceArgSettings(SoapySDRInputSettings& settings);
bool hasDCAutoCorrection();
bool hasDCCorrectionValue();
bool hasIQAutoCorrection() { return false; } // not in SoapySDR interface
bool hasIQCorrectionValue();
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);
private:
DeviceSourceAPI *m_deviceAPI;
QMutex m_mutex;
@@ -178,6 +213,12 @@ private:
bool applySettings(const SoapySDRInputSettings& settings, bool force = false);
bool setDeviceCenterFrequency(SoapySDR::Device *dev, int requestedChannel, quint64 freq_hz, int loPpmTenths);
void updateGains(SoapySDR::Device *dev, int requestedChannel, SoapySDRInputSettings& settings);
void updateTunableElements(SoapySDR::Device *dev, int requestedChannel, SoapySDRInputSettings& settings);
void webapiFormatDeviceSettings(SWGSDRangel::SWGDeviceSettings& response, const SoapySDRInputSettings& settings);
void webapiFormatDeviceReport(SWGSDRangel::SWGDeviceReport& response);
QVariant webapiVariantFromArgValue(SWGSDRangel::SWGArgValue *argValue);
void webapiFormatArgValue(const QVariant& v, SWGSDRangel::SWGArgValue *argValue);
void webapiFormatArgInfo(const SoapySDR::ArgInfo& arg, SWGSDRangel::SWGArgInfo *argInfo);
};
@@ -0,0 +1,43 @@
#-------------------------------------------------
#
# Pro file for Windows MSVC builds with Qt Creator
#
#-------------------------------------------------
TEMPLATE = lib
CONFIG += plugin
QT += core gui multimedia opengl
TARGET = inputsoapysdr
INCLUDEPATH += $$PWD
INCLUDEPATH += ../../../exports
INCLUDEPATH += ../../../sdrbase
INCLUDEPATH += ../../../sdrgui
INCLUDEPATH += ../../../devices
INCLUDEPATH += ../../../swagger/sdrangel/code/qt5/client
INCLUDEPATH += "C:\Program Files\PothosSDR\include"
CONFIG(Release):build_subdir = release
CONFIG(Debug):build_subdir = debug
SOURCES += soapysdrinput.cpp\
soapysdrinputgui.cpp\
soapysdrinputplugin.cpp\
soapysdrinputsettings.cpp\
soapysdrinputthread.cpp
HEADERS += soapysdrinput.h\
soapysdrinputgui.h\
soapysdrinputplugin.h\
soapysdrinputsettings.h\
soapysdrinputthread.h
FORMS += soapysdrinputgui.ui
LIBS += -L../../../sdrbase/$${build_subdir} -lsdrbase
LIBS += -L../../../sdrgui/$${build_subdir} -lsdrgui
LIBS += -L../../../swagger/$${build_subdir} -lswagger
LIBS += -L../../../devices/$${build_subdir} -ldevices
LIBS += -L"C:\Program Files\PothosSDR\bin" -L"C:\Program Files\PothosSDR\lib" -lSoapySDR
@@ -29,6 +29,8 @@
#include "soapygui/dynamicitemsettinggui.h"
#include "soapygui/intervalslidergui.h"
#include "soapygui/complexfactorgui.h"
#include "soapygui/arginfogui.h"
#include "soapygui/dynamicargsettinggui.h"
#include "ui_soapysdrinputgui.h"
#include "soapysdrinputgui.h"
@@ -68,7 +70,12 @@ SoapySDRInputGui::SoapySDRInputGui(DeviceUISet *deviceUISet, QWidget* parent) :
createTunableElementsControl(m_sampleSource->getTunableElements());
createGlobalGainControl();
createIndividualGainsControl(m_sampleSource->getIndividualGainsRanges());
createArgumentsControl(m_sampleSource->getDeviceArgInfoList(), true);
createArgumentsControl(m_sampleSource->getStreamArgInfoList(), false);
m_sampleSource->initGainSettings(m_settings);
m_sampleSource->initTunableElementsSettings(m_settings);
m_sampleSource->initStreamArgSettings(m_settings);
m_sampleSource->initDeviceArgSettings(m_settings);
if (m_sampleRateGUI) {
connect(m_sampleRateGUI, SIGNAL(valueChanged(double)), this, SLOT(sampleRateChanged(double)));
@@ -219,6 +226,7 @@ void SoapySDRInputGui::createGlobalGainControl()
{
m_autoGain = new QCheckBox(this);
m_autoGain->setText(QString("AGC"));
m_autoGain->setStyleSheet("QCheckBox::indicator::unchecked {background: rgb(79,79,79);} QCheckBox::indicator::checked {background: rgb(255, 157, 38);}");
layout->addWidget(m_autoGain);
connect(m_autoGain, SIGNAL(toggled(bool)), this, SLOT(autoGainChanged(bool)));
@@ -275,6 +283,7 @@ void SoapySDRInputGui::createCorrectionsControl()
m_autoDCCorrection = new QCheckBox(this);
m_autoDCCorrection->setText(QString("Auto DC corr"));
m_autoDCCorrection->setToolTip(QString("Automatic hardware DC offset correction"));
m_autoDCCorrection->setStyleSheet("QCheckBox::indicator::unchecked {background: rgb(79,79,79);} QCheckBox::indicator::checked {background: rgb(255, 157, 38);}");
layout->addWidget(m_autoDCCorrection);
connect(m_autoDCCorrection, SIGNAL(toggled(bool)), this, SLOT(autoDCCorrectionChanged(bool)));
@@ -300,12 +309,106 @@ void SoapySDRInputGui::createCorrectionsControl()
m_autoIQCorrection = new QCheckBox(this);
m_autoIQCorrection->setText(QString("Auto IQ corr"));
m_autoIQCorrection->setToolTip(QString("Automatic hardware IQ imbalance correction"));
m_autoIQCorrection->setStyleSheet("QCheckBox::indicator::unchecked {background: rgb(79,79,79);} QCheckBox::indicator::checked {background: rgb(255, 157, 38);}");
layout->addWidget(m_autoIQCorrection);
connect(m_autoIQCorrection, SIGNAL(toggled(bool)), this, SLOT(autoIQCorrectionChanged(bool)));
}
}
void SoapySDRInputGui::createArgumentsControl(const SoapySDR::ArgInfoList& argInfoList, bool deviceArguments)
{
if (argInfoList.size() == 0) { // return early if list is empty
return;
}
QVBoxLayout *layout = (QVBoxLayout *) ui->scrollAreaWidgetContents->layout();
QFrame *line = new QFrame(this);
line->setFrameShape(QFrame::HLine);
line->setFrameShadow(QFrame::Sunken);
layout->addWidget(line);
std::vector<SoapySDR::ArgInfo>::const_iterator it = argInfoList.begin();
for (; it != argInfoList.end(); ++it)
{
ArgInfoGUI::ArgInfoValueType valueType;
ArgInfoGUI *argGUI;
if (it->type == SoapySDR::ArgInfo::BOOL) {
valueType = ArgInfoGUI::ArgInfoValueBool;
} else if (it->type == SoapySDR::ArgInfo::INT) {
valueType = ArgInfoGUI::ArgInfoValueInt;
} else if (it->type == SoapySDR::ArgInfo::FLOAT) {
valueType = ArgInfoGUI::ArgInfoValueFloat;
} else if (it->type == SoapySDR::ArgInfo::STRING) {
valueType = ArgInfoGUI::ArgInfoValueString;
} else {
continue;
}
if (valueType == ArgInfoGUI::ArgInfoValueBool)
{
argGUI = new ArgInfoGUI(ArgInfoGUI::ArgInfoBinary, ArgInfoGUI::ArgInfoValueBool, this);
}
else if (it->options.size() == 0)
{
argGUI = new ArgInfoGUI(ArgInfoGUI::ArgInfoContinuous, valueType, this);
}
else
{
argGUI = new ArgInfoGUI(ArgInfoGUI::ArgInfoDiscrete, valueType, this);
std::vector<std::string>::const_iterator optionIt = it->options.begin();
std::vector<std::string>::const_iterator optionNameIt = it->optionNames.begin();
for (int i = 0; optionIt != it->options.end(); ++optionIt, i++)
{
QString name(optionNameIt == it->optionNames.end() ? optionIt->c_str() : optionNameIt->c_str());
if (optionNameIt != it->optionNames.end()) {
++optionNameIt;
}
if (valueType == ArgInfoGUI::ArgInfoValueInt) {
argGUI->addIntValue(name, atoi(optionIt->c_str()));
} else if (valueType == ArgInfoGUI::ArgInfoValueFloat) {
argGUI->addFloatValue(name, atof(optionIt->c_str()));
} else if (valueType == ArgInfoGUI::ArgInfoValueString) {
argGUI->addStringValue(name, QString(optionIt->c_str()));
}
}
}
if ((it->range.minimum() != 0) || (it->range.maximum() != 0)) {
argGUI->setRange(it->range.minimum(), it->range.maximum());
}
argGUI->setLabel(QString(it->name.size() == 0 ? it->key.c_str() : it->name.c_str()));
argGUI->setUnits(QString(it->units.c_str()));
if (it->description.size() != 0) {
argGUI->setToolTip(QString(it->description.c_str()));
}
layout->addWidget(argGUI);
DynamicArgSettingGUI *gui = new DynamicArgSettingGUI(argGUI, QString(it->key.c_str()));
// This could be made more elegant but let's make it more simple
if (deviceArguments)
{
m_deviceArgsGUIs.push_back(gui);
connect(gui, SIGNAL(valueChanged(QString, QVariant)), this, SLOT(deviceArgChanged(QString, QVariant)));
}
else
{
m_streamArgsGUIs.push_back(gui);
connect(gui, SIGNAL(valueChanged(QString, QVariant)), this, SLOT(streamArgChanged(QString, QVariant)));
}
}
}
void SoapySDRInputGui::setName(const QString& name)
{
setObjectName(name);
@@ -342,12 +445,15 @@ QByteArray SoapySDRInputGui::serialize() const
bool SoapySDRInputGui::deserialize(const QByteArray& data)
{
if(m_settings.deserialize(data)) {
if (m_settings.deserialize(data))
{
displaySettings();
m_forceSettings = true;
sendSettings();
return true;
} else {
}
else
{
resetToDefaults();
return false;
}
@@ -383,6 +489,14 @@ bool SoapySDRInputGui::handleMessage(const Message& message)
return true;
}
else if (DeviceSoapySDRShared::MsgReportDeviceArgsChange::match(message))
{
DeviceSoapySDRShared::MsgReportDeviceArgsChange& notif = (DeviceSoapySDRShared::MsgReportDeviceArgsChange&) message;
m_settings.m_deviceArgSettings = notif.getDeviceArgSettings();
displayDeviceArgsSettings();
return true;
}
else if (SoapySDRInput::MsgStartStop::match(message))
{
SoapySDRInput::MsgStartStop& notif = (SoapySDRInput::MsgStartStop&) message;
@@ -436,13 +550,13 @@ void SoapySDRInputGui::antennasChanged()
void SoapySDRInputGui::sampleRateChanged(double sampleRate)
{
m_settings.m_devSampleRate = sampleRate;
m_settings.m_devSampleRate = round(sampleRate);
sendSettings();
}
void SoapySDRInputGui::bandwidthChanged(double bandwidth)
{
m_settings.m_bandwidth = bandwidth;
m_settings.m_bandwidth = round(bandwidth);
sendSettings();
}
@@ -484,7 +598,7 @@ void SoapySDRInputGui::autoIQCorrectionChanged(bool set)
void SoapySDRInputGui::dcCorrectionModuleChanged(double value)
{
std::complex<float> dcCorrection = std::polar<float>(value, arg(m_settings.m_dcCorrection));
std::complex<double> dcCorrection = std::polar<double>(value, arg(m_settings.m_dcCorrection));
m_settings.m_dcCorrection = dcCorrection;
sendSettings();
}
@@ -492,14 +606,14 @@ void SoapySDRInputGui::dcCorrectionModuleChanged(double value)
void SoapySDRInputGui::dcCorrectionArgumentChanged(double value)
{
double angleInRadians = (value / 180.0) * M_PI;
std::complex<float> dcCorrection = std::polar<float>(abs(m_settings.m_dcCorrection), angleInRadians);
std::complex<double> dcCorrection = std::polar<double>(abs(m_settings.m_dcCorrection), angleInRadians);
m_settings.m_dcCorrection = dcCorrection;
sendSettings();
}
void SoapySDRInputGui::iqCorrectionModuleChanged(double value)
{
std::complex<float> iqCorrection = std::polar<float>(value, arg(m_settings.m_iqCorrection));
std::complex<double> iqCorrection = std::polar<double>(value, arg(m_settings.m_iqCorrection));
m_settings.m_iqCorrection = iqCorrection;
sendSettings();
}
@@ -507,11 +621,23 @@ void SoapySDRInputGui::iqCorrectionModuleChanged(double value)
void SoapySDRInputGui::iqCorrectionArgumentChanged(double value)
{
double angleInRadians = (value / 180.0) * M_PI;
std::complex<float> iqCorrection = std::polar<float>(abs(m_settings.m_iqCorrection), angleInRadians);
std::complex<double> iqCorrection = std::polar<double>(abs(m_settings.m_iqCorrection), angleInRadians);
m_settings.m_iqCorrection = iqCorrection;
sendSettings();
}
void SoapySDRInputGui::streamArgChanged(QString itemName, QVariant value)
{
m_settings.m_streamArgSettings[itemName] = value;
sendSettings();
}
void SoapySDRInputGui::deviceArgChanged(QString itemName, QVariant value)
{
m_settings.m_deviceArgSettings[itemName] = value;
sendSettings();
}
void SoapySDRInputGui::on_centerFrequency_changed(quint64 value)
{
m_settings.m_centerFrequency = value * 1000;
@@ -597,17 +723,22 @@ void SoapySDRInputGui::displaySettings()
ui->centerFrequency->setValue(m_settings.m_centerFrequency / 1000);
if (m_antennas) {
qDebug("SoapySDRInputGui::displaySettings: m_antenna: %s", m_settings.m_antenna.toStdString().c_str());
m_antennas->setValue(m_settings.m_antenna.toStdString());
}
if (m_sampleRateGUI) {
if (m_sampleRateGUI)
{
m_sampleRateGUI->setValue(m_settings.m_devSampleRate);
m_settings.m_devSampleRate = m_sampleRateGUI->getCurrentValue();
}
if (m_bandwidthGUI) {
if (m_bandwidthGUI)
{
m_bandwidthGUI->setValue(m_settings.m_bandwidth);
m_settings.m_bandwidth = m_bandwidthGUI->getCurrentValue();
}
if (m_gainSliderGUI) {
if (m_gainSliderGUI)
{
m_gainSliderGUI->setValue(m_settings.m_globalGain);
m_settings.m_globalGain = m_gainSliderGUI->getCurrentValue();
}
if (m_autoGain) {
m_autoGain->setChecked(m_settings.m_autoGain);
@@ -625,6 +756,8 @@ void SoapySDRInputGui::displaySettings()
displayTunableElementsControlSettings();
displayIndividualGainsControlSettings();
displayCorrectionsSettings();
displayStreamArgsSettings();
displayDeviceArgsSettings();
blockApplySettings(false);
}
@@ -645,10 +778,12 @@ void SoapySDRInputGui::displayIndividualGainsControlSettings()
{
for (const auto &it : m_individualGainsGUIs)
{
QMap<QString, double>::const_iterator elIt = m_settings.m_individualGains.find(it->getName());
QMap<QString, double>::iterator elIt = m_settings.m_individualGains.find(it->getName());
if (elIt != m_settings.m_individualGains.end()) {
if (elIt != m_settings.m_individualGains.end())
{
it->setValue(*elIt);
*elIt = it->getValue();
}
}
}
@@ -678,6 +813,34 @@ void SoapySDRInputGui::displayCorrectionsSettings()
}
}
void SoapySDRInputGui::displayStreamArgsSettings()
{
for (const auto &it : m_streamArgsGUIs)
{
QMap<QString, QVariant>::iterator elIt = m_settings.m_streamArgSettings.find(it->getName());
if (elIt != m_settings.m_streamArgSettings.end())
{
it->setValue(elIt.value());
*elIt = it->getValue();
}
}
}
void SoapySDRInputGui::displayDeviceArgsSettings()
{
for (const auto &it : m_deviceArgsGUIs)
{
QMap<QString, QVariant>::iterator elIt = m_settings.m_deviceArgSettings.find(it->getName());
if (elIt != m_settings.m_deviceArgSettings.end())
{
it->setValue(elIt.value());
*elIt = it->getValue();
}
}
}
void SoapySDRInputGui::sendSettings()
{
if (!m_updateTimer.isActive()) {
@@ -29,6 +29,7 @@ class DeviceUISet;
class ItemSettingGUI;
class StringRangeGUI;
class DynamicItemSettingGUI;
class DynamicArgSettingGUI;
class IntervalSliderGUI;
class QCheckBox;
class ComplexFactorGUI;
@@ -67,6 +68,7 @@ private:
void createGlobalGainControl();
void createIndividualGainsControl(const std::vector<DeviceSoapySDRParams::GainSetting>& individualGainsList);
void createCorrectionsControl();
void createArgumentsControl(const SoapySDR::ArgInfoList& argInfoList, bool deviceArguments);
Ui::SoapySDRInputGui* ui;
@@ -93,11 +95,15 @@ private:
ComplexFactorGUI *m_iqCorrectionGUI;
QCheckBox *m_autoDCCorrection;
QCheckBox *m_autoIQCorrection;
std::vector<DynamicArgSettingGUI*> m_streamArgsGUIs;
std::vector<DynamicArgSettingGUI*> m_deviceArgsGUIs;
void displaySettings();
void displayTunableElementsControlSettings();
void displayIndividualGainsControlSettings();
void displayCorrectionsSettings();
void displayStreamArgsSettings();
void displayDeviceArgsSettings();
void sendSettings();
void updateSampleRateAndFrequency();
void updateFrequencyLimits();
@@ -119,6 +125,8 @@ private slots:
void dcCorrectionArgumentChanged(double value);
void iqCorrectionModuleChanged(double value);
void iqCorrectionArgumentChanged(double value);
void streamArgChanged(QString itemName, QVariant value);
void deviceArgChanged(QString itemName, QVariant value);
void on_centerFrequency_changed(quint64 value);
void on_LOppm_valueChanged(int value);
@@ -30,7 +30,7 @@
const PluginDescriptor SoapySDRInputPlugin::m_pluginDescriptor = {
QString("SoapySDR Input"),
QString("4.3.0"),
QString("4.3.1"),
QString("(c) Edouard Griffiths, F4EXB"),
QString("https://github.com/f4exb/sdrangel"),
true,
@@ -71,6 +71,8 @@ QByteArray SoapySDRInputSettings::serialize() const
s.writeDouble(18, m_dcCorrection.imag());
s.writeDouble(19, m_iqCorrection.real());
s.writeDouble(20, m_iqCorrection.imag());
s.writeBlob(21, serializeArgumentMap(m_streamArgSettings));
s.writeBlob(22, serializeArgumentMap(m_deviceArgSettings));
return s.final();
}
@@ -116,6 +118,10 @@ bool SoapySDRInputSettings::deserialize(const QByteArray& data)
d.readDouble(19, &realval, 0);
d.readDouble(20, &imagval, 0);
m_iqCorrection = std::complex<double>{realval, imagval};
d.readBlob(21, &blob);
deserializeArgumentMap(blob, m_streamArgSettings);
d.readBlob(22, &blob);
deserializeArgumentMap(blob, m_deviceArgSettings);
return true;
}
@@ -142,3 +148,21 @@ void SoapySDRInputSettings::deserializeNamedElementMap(const QByteArray& data, Q
(*stream) >> map;
delete stream;
}
QByteArray SoapySDRInputSettings::serializeArgumentMap(const QMap<QString, QVariant>& map) const
{
QByteArray data;
QDataStream *stream = new QDataStream(&data, QIODevice::WriteOnly);
(*stream) << map;
delete stream;
return data;
}
void SoapySDRInputSettings::deserializeArgumentMap(const QByteArray& data, QMap<QString, QVariant>& map)
{
QDataStream *stream = new QDataStream(data);
(*stream) >> map;
delete stream;
}
@@ -19,6 +19,7 @@
#include <QtGlobal>
#include <QString>
#include <QVariant>
#include <QMap>
struct SoapySDRInputSettings {
@@ -48,6 +49,8 @@ struct SoapySDRInputSettings {
bool m_autoIQCorrection;
std::complex<double> m_dcCorrection;
std::complex<double> m_iqCorrection;
QMap<QString, QVariant> m_streamArgSettings;
QMap<QString, QVariant> m_deviceArgSettings;
SoapySDRInputSettings();
void resetToDefaults();
@@ -57,6 +60,8 @@ struct SoapySDRInputSettings {
private:
QByteArray serializeNamedElementMap(const QMap<QString, double>& map) const;
void deserializeNamedElementMap(const QByteArray& data, QMap<QString, double>& map);
QByteArray serializeArgumentMap(const QMap<QString, QVariant>& map) const;
void deserializeArgumentMap(const QByteArray& data, QMap<QString, QVariant>& map);
};
#endif /* PLUGINS_SAMPLESOURCE_SOAPYSDRINPUT_SOAPYSDRINPUTSETTINGS_H_ */
@@ -129,9 +129,11 @@ void SoapySDRInputThread::run()
int flags(0);
long long timeNs(0);
float blockTime = ((float) numElems) / (m_sampleRate <= 0 ? 1024000 : m_sampleRate);
long timeoutUs = 2000000 * blockTime; // 10 times the block time
long initialTtimeoutUs = 10000000 * blockTime; // 10 times the block time
long timeoutUs = initialTtimeoutUs < 250000 ? 250000 : initialTtimeoutUs; // 250ms minimum
qDebug("SoapySDRInputThread::run: numElems: %u elemSize: %u timeoutUs: %ld", numElems, elemSize, timeoutUs);
qDebug("SoapySDRInputThread::run: numElems: %u elemSize: %u initialTtimeoutUs: %ld timeoutUs: %ld",
numElems, elemSize, initialTtimeoutUs, timeoutUs);
qDebug("SoapySDRInputThread::run: start running loop");
while (m_running)
@@ -142,6 +144,10 @@ void SoapySDRInputThread::run()
{
qWarning("SoapySDRInputThread::run: timeout: flags: %d timeNs: %lld timeoutUs: %ld", flags, timeNs, timeoutUs);
}
else if (ret == SOAPY_SDR_OVERFLOW)
{
qWarning("SoapySDRInputThread::run: overflow: flags: %d timeNs: %lld timeoutUs: %ld", flags, timeNs, timeoutUs);
}
else if (ret < 0)
{
qCritical("SoapySDRInputThread::run: Unexpected read stream error: %s", SoapySDR::errToStr(ret));
@@ -198,16 +198,18 @@ void TestSourceGui::on_sampleSize_currentIndexChanged(int index)
sendSettings();
}
void TestSourceGui::on_amplitudeCoarse_valueChanged(int value __attribute__((unused)))
void TestSourceGui::on_amplitudeCoarse_valueChanged(int value)
{
(void) value;
updateAmpFineLimit();
displayAmplitude();
m_settings.m_amplitudeBits = ui->amplitudeCoarse->value() * 100 + ui->amplitudeFine->value();
sendSettings();
}
void TestSourceGui::on_amplitudeFine_valueChanged(int value __attribute__((unused)))
void TestSourceGui::on_amplitudeFine_valueChanged(int value)
{
(void) value;
displayAmplitude();
m_settings.m_amplitudeBits = ui->amplitudeCoarse->value() * 100 + ui->amplitudeFine->value();
sendSettings();
@@ -388,8 +388,9 @@ bool TestSourceInput::applySettings(const TestSourceSettings& settings, bool for
int TestSourceInput::webapiRunGet(
SWGSDRangel::SWGDeviceState& response,
QString& errorMessage __attribute__((unused)))
QString& errorMessage)
{
(void) errorMessage;
m_deviceAPI->getDeviceEngineStateStr(*response.getState());
return 200;
}
@@ -397,8 +398,9 @@ int TestSourceInput::webapiRunGet(
int TestSourceInput::webapiRun(
bool run,
SWGSDRangel::SWGDeviceState& response,
QString& errorMessage __attribute__((unused)))
QString& errorMessage)
{
(void) errorMessage;
m_deviceAPI->getDeviceEngineStateStr(*response.getState());
MsgStartStop *message = MsgStartStop::create(run);
m_inputMessageQueue.push(message);
@@ -414,8 +416,9 @@ int TestSourceInput::webapiRun(
int TestSourceInput::webapiSettingsGet(
SWGSDRangel::SWGDeviceSettings& response,
QString& errorMessage __attribute__((unused)))
QString& errorMessage)
{
(void) errorMessage;
response.setTestSourceSettings(new SWGSDRangel::SWGTestSourceSettings());
response.getTestSourceSettings()->init();
webapiFormatDeviceSettings(response, m_settings);
@@ -426,8 +429,9 @@ int TestSourceInput::webapiSettingsPutPatch(
bool force,
const QStringList& deviceSettingsKeys,
SWGSDRangel::SWGDeviceSettings& response, // query + response
QString& errorMessage __attribute__((unused)))
QString& errorMessage)
{
(void) errorMessage;
TestSourceSettings settings = m_settings;
if (deviceSettingsKeys.contains("centerFrequency")) {
@@ -14,6 +14,8 @@
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#define _USE_MATH_DEFINES
#include <math.h>
#include <stdio.h>
#include <errno.h>
#include "testsourcethread.h"