From ea98f2e1c9ea5afac6f71a8157bda111ef2f213f Mon Sep 17 00:00:00 2001 From: f4exb Date: Fri, 2 Nov 2018 02:33:04 +0100 Subject: [PATCH] SoapySDR support: input: center frequency and sample rate handling --- devices/soapysdr/devicesoapysdrparams.cpp | 36 +++ devices/soapysdr/devicesoapysdrparams.h | 3 + devices/soapysdr/devicesoapysdrshared.cpp | 2 + devices/soapysdr/devicesoapysdrshared.h | 48 +++ .../bladerf2input/bladerf2input.cpp | 8 +- .../bladerf2input/bladerf2input.h | 2 +- .../soapysdrinput/soapysdrinput.cpp | 299 +++++++++++++++++- .../soapysdrinput/soapysdrinput.h | 16 +- .../soapysdrinput/soapysdrinputgui.cpp | 69 +++- .../soapysdrinput/soapysdrinputgui.h | 2 + .../soapysdrinput/soapysdrinputgui.ui | 48 ++- .../soapysdrinput/soapysdrinputthread.cpp | 8 + 12 files changed, 527 insertions(+), 14 deletions(-) diff --git a/devices/soapysdr/devicesoapysdrparams.cpp b/devices/soapysdr/devicesoapysdrparams.cpp index 133f7efee..2caa0ba9e 100644 --- a/devices/soapysdr/devicesoapysdrparams.cpp +++ b/devices/soapysdr/devicesoapysdrparams.cpp @@ -31,6 +31,42 @@ DeviceSoapySDRParams::DeviceSoapySDRParams(SoapySDR::Device *device) : DeviceSoapySDRParams::~DeviceSoapySDRParams() {} +std::string DeviceSoapySDRParams::getRxChannelMainTunableElementName(uint32_t index) +{ + if (index < m_nbRx) + { + return std::string("RF"); + } + else + { + const ChannelSettings& channelSettings = m_RxChannelsSettings[index]; + + if (channelSettings.m_frequencySettings.size() > 0) { + return channelSettings.m_frequencySettings.front().m_name; + } else { + return std::string("RF"); + } + } +} + +std::string DeviceSoapySDRParams::getTxChannelMainTunableElementName(uint32_t index) +{ + if (index < m_nbRx) + { + return std::string("RF"); + } + else + { + const ChannelSettings& channelSettings = m_RxChannelsSettings[index]; + + if (channelSettings.m_frequencySettings.size() > 0) { + return channelSettings.m_frequencySettings.front().m_name; + } else { + return std::string("RF"); + } + } +} + void DeviceSoapySDRParams::fillParams() { m_deviceSettingsArgs = m_device->getSettingInfo(); diff --git a/devices/soapysdr/devicesoapysdrparams.h b/devices/soapysdr/devicesoapysdrparams.h index 67baf5cac..2489b8f85 100644 --- a/devices/soapysdr/devicesoapysdrparams.h +++ b/devices/soapysdr/devicesoapysdrparams.h @@ -86,6 +86,9 @@ public: } } + std::string getRxChannelMainTunableElementName(uint32_t index); + std::string getTxChannelMainTunableElementName(uint32_t index); + private: void fillParams(); void fillChannelParams(std::vector& channelSettings, int direction, unsigned int ichan); diff --git a/devices/soapysdr/devicesoapysdrshared.cpp b/devices/soapysdr/devicesoapysdrshared.cpp index 16a2ef64e..bbfabd460 100644 --- a/devices/soapysdr/devicesoapysdrshared.cpp +++ b/devices/soapysdr/devicesoapysdrshared.cpp @@ -16,6 +16,8 @@ #include "devicesoapysdrshared.h" +MESSAGE_CLASS_DEFINITION(DeviceSoapySDRShared::MsgReportBuddyChange, Message) + DeviceSoapySDRShared::DeviceSoapySDRShared() : m_device(0), m_channel(-1), diff --git a/devices/soapysdr/devicesoapysdrshared.h b/devices/soapysdr/devicesoapysdrshared.h index 8ab019ba1..36d54c2bc 100644 --- a/devices/soapysdr/devicesoapysdrshared.h +++ b/devices/soapysdr/devicesoapysdrshared.h @@ -19,6 +19,7 @@ #include +#include "util/message.h" #include "export.h" #include "devicesoapysdrparams.h" @@ -31,6 +32,53 @@ class SoapySDROutput; class DEVICES_API DeviceSoapySDRShared { public: + class MsgReportBuddyChange : public Message { + MESSAGE_CLASS_DECLARATION + + public: + uint64_t getCenterFrequency() const { return m_centerFrequency; } + int getLOppmTenths() const { return m_LOppmTenths; } + int getFcPos() const { return m_fcPos; } + int getDevSampleRate() const { return m_devSampleRate; } + bool getRxElseTx() const { return m_rxElseTx; } + + static MsgReportBuddyChange* create( + uint64_t centerFrequency, + int LOppmTenths, + int fcPos, + int devSampleRate, + bool rxElseTx) + { + return new MsgReportBuddyChange( + centerFrequency, + LOppmTenths, + fcPos, + devSampleRate, + rxElseTx); + } + + private: + uint64_t m_centerFrequency; //!< Center frequency + int m_LOppmTenths; //!< LO soft correction in tenths of ppm + int m_fcPos; //!< Center frequency position + int m_devSampleRate; //!< device/host sample rate + bool m_rxElseTx; //!< tells which side initiated the message + + MsgReportBuddyChange( + uint64_t centerFrequency, + int LOppmTenths, + int fcPos, + int devSampleRate, + bool rxElseTx) : + Message(), + m_centerFrequency(centerFrequency), + m_LOppmTenths(LOppmTenths), + m_fcPos(fcPos), + m_devSampleRate(devSampleRate), + m_rxElseTx(rxElseTx) + { } + }; + DeviceSoapySDRShared(); ~DeviceSoapySDRShared(); diff --git a/plugins/samplesource/bladerf2input/bladerf2input.cpp b/plugins/samplesource/bladerf2input/bladerf2input.cpp index 60387f70d..5142484e4 100644 --- a/plugins/samplesource/bladerf2input/bladerf2input.cpp +++ b/plugins/samplesource/bladerf2input/bladerf2input.cpp @@ -538,9 +538,9 @@ void BladeRF2Input::setCenterFrequency(qint64 centerFrequency) } } -bool BladeRF2Input::setDeviceCenterFrequency(struct bladerf *dev, int requestedChannel, quint64 freq_hz) +bool BladeRF2Input::setDeviceCenterFrequency(struct bladerf *dev, int requestedChannel, quint64 freq_hz, int loPpmTenths) { - qint64 df = ((qint64)freq_hz * m_settings.m_LOppmTenths) / 10000000LL; + qint64 df = ((qint64)freq_hz * loPpmTenths) / 10000000LL; freq_hz += df; int status = bladerf_set_frequency(dev, BLADERF_CHANNEL_RX(requestedChannel), freq_hz); @@ -661,7 +661,7 @@ bool BladeRF2Input::handleMessage(const Message& message) (DeviceSampleSource::fcPos_t) settings.m_fcPos, settings.m_devSampleRate); - if (setDeviceCenterFrequency(dev, requestedChannel, deviceCenterFrequency)) + if (setDeviceCenterFrequency(dev, requestedChannel, deviceCenterFrequency, settings.m_LOppmTenths)) { if (getMessageQueueToGUI()) { @@ -846,7 +846,7 @@ bool BladeRF2Input::applySettings(const BladeRF2InputSettings& settings, bool fo if (dev != 0) { - if (setDeviceCenterFrequency(dev, requestedChannel, deviceCenterFrequency)) + if (setDeviceCenterFrequency(dev, requestedChannel, deviceCenterFrequency, settings.m_LOppmTenths)) { if (getMessageQueueToGUI()) { diff --git a/plugins/samplesource/bladerf2input/bladerf2input.h b/plugins/samplesource/bladerf2input/bladerf2input.h index 9c5c0f81b..4b9a79561 100644 --- a/plugins/samplesource/bladerf2input/bladerf2input.h +++ b/plugins/samplesource/bladerf2input/bladerf2input.h @@ -192,7 +192,7 @@ private: BladeRF2InputThread *findThread(); void moveThreadToBuddy(); bool applySettings(const BladeRF2InputSettings& settings, bool force = false); - bool setDeviceCenterFrequency(struct bladerf *dev, int requestedChannel, quint64 freq_hz); + bool setDeviceCenterFrequency(struct bladerf *dev, int requestedChannel, quint64 freq_hz, int loPpmTenths); void webapiFormatDeviceSettings(SWGSDRangel::SWGDeviceSettings& response, const BladeRF2InputSettings& settings); void webapiFormatDeviceReport(SWGSDRangel::SWGDeviceReport& response); }; diff --git a/plugins/samplesource/soapysdrinput/soapysdrinput.cpp b/plugins/samplesource/soapysdrinput/soapysdrinput.cpp index a765e340a..c5a1ad31a 100644 --- a/plugins/samplesource/soapysdrinput/soapysdrinput.cpp +++ b/plugins/samplesource/soapysdrinput/soapysdrinput.cpp @@ -14,6 +14,8 @@ // along with this program. If not, see . // /////////////////////////////////////////////////////////////////////////////////// +#include + #include "util/simpleserializer.h" #include "device/devicesourceapi.h" @@ -26,17 +28,27 @@ #include "soapysdrinputthread.h" #include "soapysdrinput.h" +MESSAGE_CLASS_DEFINITION(SoapySDRInput::MsgConfigureSoapySDRInput, Message) +MESSAGE_CLASS_DEFINITION(SoapySDRInput::MsgFileRecord, Message) +MESSAGE_CLASS_DEFINITION(SoapySDRInput::MsgStartStop, Message) + SoapySDRInput::SoapySDRInput(DeviceSourceAPI *deviceAPI) : m_deviceAPI(deviceAPI), - m_thread(0), + m_settings(), m_deviceDescription("SoapySDRInput"), - m_running(false) + m_running(false), + m_thread(0) { openDevice(); + + m_fileSink = new FileRecord(QString("test_%1.sdriq").arg(m_deviceAPI->getDeviceUID())); + m_deviceAPI->addSink(m_fileSink); } SoapySDRInput::~SoapySDRInput() { + m_deviceAPI->removeSink(m_fileSink); + delete m_fileSink; } void SoapySDRInput::destroy() @@ -195,6 +207,38 @@ void SoapySDRInput::init() { } +SoapySDRInputThread *SoapySDRInput::findThread() +{ + if (m_thread == 0) // this does not own the thread + { + SoapySDRInputThread *soapySDRInputThread = 0; + + // find a buddy that has allocated the thread + const std::vector& sourceBuddies = m_deviceAPI->getSourceBuddies(); + std::vector::const_iterator it = sourceBuddies.begin(); + + for (; it != sourceBuddies.end(); ++it) + { + SoapySDRInput *buddySource = ((DeviceSoapySDRShared*) (*it)->getBuddySharedPtr())->m_source; + + if (buddySource) + { + soapySDRInputThread = buddySource->getThread(); + + if (soapySDRInputThread) { + break; + } + } + } + + return soapySDRInputThread; + } + else + { + return m_thread; // own thread + } +} + void SoapySDRInput::moveThreadToBuddy() { const std::vector& sourceBuddies = m_deviceAPI->getSourceBuddies(); @@ -251,7 +295,256 @@ void SoapySDRInput::setCenterFrequency(qint64 centerFrequency __attribute__((unu { } +bool SoapySDRInput::setDeviceCenterFrequency(SoapySDR::Device *dev, int requestedChannel, quint64 freq_hz, int loPpmTenths) +{ + qint64 df = ((qint64)freq_hz * loPpmTenths) / 10000000LL; + freq_hz += df; + + try + { + dev->setFrequency(SOAPY_SDR_RX, + requestedChannel, + m_deviceShared.m_deviceParams->getRxChannelMainTunableElementName(requestedChannel), + freq_hz); + qDebug("SoapySDRInput::setDeviceCenterFrequency: setFrequency(%llu)", freq_hz); + return true; + } + catch (const std::exception &ex) + { + qCritical("SoapySDRInput::applySettings: could not set frequency: %llu: %s", freq_hz, ex.what()); + return false; + } +} + bool SoapySDRInput::handleMessage(const Message& message __attribute__((unused))) { - return false; + if (MsgConfigureSoapySDRInput::match(message)) + { + MsgConfigureSoapySDRInput& conf = (MsgConfigureSoapySDRInput&) message; + qDebug() << "SoapySDRInput::handleMessage: MsgConfigureSoapySDRInput"; + + if (!applySettings(conf.getSettings(), conf.getForce())) { + qDebug("SoapySDRInput::handleMessage: MsgConfigureSoapySDRInput config error"); + } + + return true; + } + else if (MsgFileRecord::match(message)) + { + MsgFileRecord& conf = (MsgFileRecord&) message; + qDebug() << "SoapySDRInput::handleMessage: MsgFileRecord: " << conf.getStartStop(); + + if (conf.getStartStop()) + { + if (m_settings.m_fileRecordName.size() != 0) { + m_fileSink->setFileName(m_settings.m_fileRecordName); + } else { + m_fileSink->genUniqueFileName(m_deviceAPI->getDeviceUID()); + } + + m_fileSink->startRecording(); + } + else + { + m_fileSink->stopRecording(); + } + + return true; + } + else if (MsgStartStop::match(message)) + { + MsgStartStop& cmd = (MsgStartStop&) message; + qDebug() << "SoapySDRInput::handleMessage: MsgStartStop: " << (cmd.getStartStop() ? "start" : "stop"); + + if (cmd.getStartStop()) + { + if (m_deviceAPI->initAcquisition()) + { + m_deviceAPI->startAcquisition(); + } + } + else + { + m_deviceAPI->stopAcquisition(); + } + + return true; + } + else if (DeviceSoapySDRShared::MsgReportBuddyChange::match(message)) + { + int requestedChannel = m_deviceAPI->getItemIndex(); + DeviceSoapySDRShared::MsgReportBuddyChange& report = (DeviceSoapySDRShared::MsgReportBuddyChange&) message; + SoapySDRInputSettings settings = m_settings; + settings.m_fcPos = (SoapySDRInputSettings::fcPos_t) report.getFcPos(); + + settings.m_centerFrequency = m_deviceShared.m_device->getFrequency( + SOAPY_SDR_RX, + requestedChannel, + m_deviceShared.m_deviceParams->getRxChannelMainTunableElementName(requestedChannel)); + + settings.m_devSampleRate = m_deviceShared.m_device->getSampleRate(SOAPY_SDR_RX, requestedChannel); + + SoapySDRInputThread *inputThread = findThread(); + + if (inputThread) + { + inputThread->setFcPos(requestedChannel, (int) settings.m_fcPos); + } + + m_settings = settings; + + return true; + } + else + { + return false; + } +} + +bool SoapySDRInput::applySettings(const SoapySDRInputSettings& settings, bool force) +{ + bool forwardChangeOwnDSP = false; + bool forwardChangeToBuddies = false; + + SoapySDR::Device *dev = m_deviceShared.m_device; + SoapySDRInputThread *inputThread = findThread(); + int requestedChannel = m_deviceAPI->getItemIndex(); + qint64 xlatedDeviceCenterFrequency = settings.m_centerFrequency; + xlatedDeviceCenterFrequency -= settings.m_transverterMode ? settings.m_transverterDeltaFrequency : 0; + xlatedDeviceCenterFrequency = xlatedDeviceCenterFrequency < 0 ? 0 : xlatedDeviceCenterFrequency; + + if ((m_settings.m_dcBlock != settings.m_dcBlock) || + (m_settings.m_iqCorrection != settings.m_iqCorrection) || force) + { + m_deviceAPI->configureCorrections(settings.m_dcBlock, settings.m_iqCorrection); + } + + if ((m_settings.m_devSampleRate != settings.m_devSampleRate) || force) + { + forwardChangeOwnDSP = true; + forwardChangeToBuddies = true; + + if (dev != 0) + { + try + { + dev->setSampleRate(SOAPY_SDR_RX, requestedChannel, settings.m_devSampleRate); + qDebug() << "SoapySDRInput::applySettings: setSampleRate OK: " << settings.m_devSampleRate; + + if (inputThread) + { + bool wasRunning = inputThread->isRunning(); + inputThread->stopWork(); + inputThread->setSampleRate(settings.m_devSampleRate); + + if (wasRunning) { + inputThread->startWork(); + } + } + } + catch (const std::exception &ex) + { + qCritical("SoapySDRInput::applySettings: could not set sample rate: %d: %s", + settings.m_devSampleRate, ex.what()); + } + } + } + + if ((m_settings.m_fcPos != settings.m_fcPos) || force) + { + SoapySDRInputThread *inputThread = findThread(); + + if (inputThread != 0) + { + inputThread->setFcPos(requestedChannel, (int) settings.m_fcPos); + qDebug() << "SoapySDRInput::applySettings: set fc pos (enum) to " << (int) settings.m_fcPos; + } + } + + if ((m_settings.m_log2Decim != settings.m_log2Decim) || force) + { + forwardChangeOwnDSP = true; + SoapySDRInputThread *inputThread = findThread(); + + if (inputThread != 0) + { + inputThread->setLog2Decimation(requestedChannel, settings.m_log2Decim); + qDebug() << "SoapySDRInput::applySettings: set decimation to " << (1<handleMessage(*notif); // forward to file sink + m_deviceAPI->getDeviceEngineInputMessageQueue()->push(notif); + } + + if (forwardChangeToBuddies) + { + // send to source buddies + const std::vector& sourceBuddies = m_deviceAPI->getSourceBuddies(); + const std::vector& sinkBuddies = m_deviceAPI->getSinkBuddies(); + + for (const auto &itSource : sourceBuddies) + { + DeviceSoapySDRShared::MsgReportBuddyChange *report = DeviceSoapySDRShared::MsgReportBuddyChange::create( + settings.m_centerFrequency, + settings.m_LOppmTenths, + (int) settings.m_fcPos, + settings.m_devSampleRate, + true); + itSource->getSampleSourceInputMessageQueue()->push(report); + } + + for (const auto &itSink : sinkBuddies) + { + DeviceSoapySDRShared::MsgReportBuddyChange *report = DeviceSoapySDRShared::MsgReportBuddyChange::create( + settings.m_centerFrequency, + settings.m_LOppmTenths, + (int) settings.m_fcPos, + settings.m_devSampleRate, + true); + itSink->getSampleSinkInputMessageQueue()->push(report); + } + } + + m_settings = settings; + + qDebug() << "SoapySDRInput::applySettings: " + << " m_transverterMode: " << m_settings.m_transverterMode + << " m_transverterDeltaFrequency: " << m_settings.m_transverterDeltaFrequency + << " m_centerFrequency: " << m_settings.m_centerFrequency << " Hz" + << " m_LOppmTenths: " << m_settings.m_LOppmTenths + << " m_log2Decim: " << m_settings.m_log2Decim + << " m_fcPos: " << m_settings.m_fcPos + << " m_devSampleRate: " << m_settings.m_devSampleRate + << " m_dcBlock: " << m_settings.m_dcBlock + << " m_iqCorrection: " << m_settings.m_iqCorrection; + + return true; } diff --git a/plugins/samplesource/soapysdrinput/soapysdrinput.h b/plugins/samplesource/soapysdrinput/soapysdrinput.h index e7c184f62..3d5dffc1b 100644 --- a/plugins/samplesource/soapysdrinput/soapysdrinput.h +++ b/plugins/samplesource/soapysdrinput/soapysdrinput.h @@ -28,6 +28,12 @@ class DeviceSourceAPI; class SoapySDRInputThread; +class FileRecord; + +namespace SoapySDR +{ + class Device; +} class SoapySDRInput : public DeviceSampleSource { @@ -119,14 +125,20 @@ public: private: DeviceSourceAPI *m_deviceAPI; - DeviceSoapySDRShared m_deviceShared; - SoapySDRInputThread *m_thread; + QMutex m_mutex; + SoapySDRInputSettings m_settings; QString m_deviceDescription; bool m_running; + SoapySDRInputThread *m_thread; + DeviceSoapySDRShared m_deviceShared; + FileRecord *m_fileSink; //!< File sink to record device I/Q output bool openDevice(); void closeDevice(); + SoapySDRInputThread *findThread(); void moveThreadToBuddy(); + bool applySettings(const SoapySDRInputSettings& settings, bool force = false); + bool setDeviceCenterFrequency(SoapySDR::Device *dev, int requestedChannel, quint64 freq_hz, int loPpmTenths); }; diff --git a/plugins/samplesource/soapysdrinput/soapysdrinputgui.cpp b/plugins/samplesource/soapysdrinput/soapysdrinputgui.cpp index 6c0ea16de..9e7c2e0f7 100644 --- a/plugins/samplesource/soapysdrinput/soapysdrinputgui.cpp +++ b/plugins/samplesource/soapysdrinput/soapysdrinputgui.cpp @@ -49,6 +49,17 @@ SoapySDRInputGui::SoapySDRInputGui(DeviceUISet *deviceUISet, QWidget* parent) : ui->centerFrequency->setValueRange(7, f_min/1000, f_max/1000); createRangesControl(m_sampleSource->getRateRanges(), "SR", "kS/s"); + + connect(&m_updateTimer, SIGNAL(timeout()), this, SLOT(updateHardware())); + connect(&m_statusTimer, SIGNAL(timeout()), this, SLOT(updateStatus())); + m_statusTimer.start(500); + + displaySettings(); + + connect(&m_inputMessageQueue, SIGNAL(messageEnqueued()), this, SLOT(handleInputMessages()), Qt::QueuedConnection); + m_sampleSource->setMessageQueueToGUI(&m_inputMessageQueue); + + sendSettings(); } SoapySDRInputGui::~SoapySDRInputGui() @@ -170,17 +181,59 @@ bool SoapySDRInputGui::deserialize(const QByteArray& data __attribute__((unused) bool SoapySDRInputGui::handleMessage(const Message& message __attribute__((unused))) { - return false; + if (SoapySDRInput::MsgStartStop::match(message)) + { + SoapySDRInput::MsgStartStop& notif = (SoapySDRInput::MsgStartStop&) message; + blockApplySettings(true); + ui->startStop->setChecked(notif.getStartStop()); + blockApplySettings(false); + + return true; + } + else + { + return false; + } +} + +void SoapySDRInputGui::handleInputMessages() +{ + Message* message; + + while ((message = m_inputMessageQueue.pop()) != 0) + { + qDebug("SoapySDRInputGui::handleInputMessages: message: %s", message->getIdentifier()); + + if (DSPSignalNotification::match(*message)) + { + DSPSignalNotification* notif = (DSPSignalNotification*) message; + m_sampleRate = notif->getSampleRate(); + m_deviceCenterFrequency = notif->getCenterFrequency(); + qDebug("SoapySDRInputGui::handleInputMessages: DSPSignalNotification: SampleRate:%d, CenterFrequency:%llu", notif->getSampleRate(), notif->getCenterFrequency()); + updateSampleRateAndFrequency(); + + delete message; + } + else + { + if (handleMessage(*message)) + { + delete message; + } + } + } } void SoapySDRInputGui::sampleRateChanged(double sampleRate) { - qDebug("SoapySDRInputGui::sampleRateChanged: %lf", sampleRate); + m_settings.m_devSampleRate = sampleRate; + sendSettings(); } void SoapySDRInputGui::on_centerFrequency_changed(quint64 value) { - qDebug("SoapySDRInputGui::on_centerFrequency_changed: %llu", value); + m_settings.m_centerFrequency = value * 1000; + sendSettings(); } void SoapySDRInputGui::on_dcOffset_toggled(bool checked) @@ -227,6 +280,13 @@ void SoapySDRInputGui::on_transverter_clicked() sendSettings(); } +void SoapySDRInputGui::on_LOppm_valueChanged(int value) +{ + ui->LOppmText->setText(QString("%1").arg(QString::number(value/10.0, 'f', 1))); + m_settings.m_LOppmTenths = value; + sendSettings(); +} + void SoapySDRInputGui::on_startStop_toggled(bool checked) { if (m_doApplySettings) @@ -261,6 +321,9 @@ void SoapySDRInputGui::displaySettings() ui->decim->setCurrentIndex(m_settings.m_log2Decim); ui->fcPos->setCurrentIndex((int) m_settings.m_fcPos); + ui->LOppm->setValue(m_settings.m_LOppmTenths); + ui->LOppmText->setText(QString("%1").arg(QString::number(m_settings.m_LOppmTenths/10.0, 'f', 1))); + blockApplySettings(false); } diff --git a/plugins/samplesource/soapysdrinput/soapysdrinputgui.h b/plugins/samplesource/soapysdrinput/soapysdrinputgui.h index 1c86d5fbb..864546904 100644 --- a/plugins/samplesource/soapysdrinput/soapysdrinputgui.h +++ b/plugins/samplesource/soapysdrinput/soapysdrinputgui.h @@ -79,7 +79,9 @@ private: void blockApplySettings(bool block); private slots: + void handleInputMessages(); void on_centerFrequency_changed(quint64 value); + void on_LOppm_valueChanged(int value); void sampleRateChanged(double sampleRate); void on_dcOffset_toggled(bool checked); void on_iqImbalance_toggled(bool checked); diff --git a/plugins/samplesource/soapysdrinput/soapysdrinputgui.ui b/plugins/samplesource/soapysdrinput/soapysdrinputgui.ui index 2bb580f7a..b5e295eef 100644 --- a/plugins/samplesource/soapysdrinput/soapysdrinputgui.ui +++ b/plugins/samplesource/soapysdrinput/soapysdrinputgui.ui @@ -167,7 +167,7 @@ - + 6 @@ -319,6 +319,52 @@ + + + + + + LO ppm + + + + + + + Local Oscillator software ppm correction + + + -1000 + + + 1000 + + + 1 + + + Qt::Horizontal + + + + + + + + 40 + 0 + + + + -100.0 + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + diff --git a/plugins/samplesource/soapysdrinput/soapysdrinputthread.cpp b/plugins/samplesource/soapysdrinput/soapysdrinputthread.cpp index 96748ec87..f28cc0ea9 100644 --- a/plugins/samplesource/soapysdrinput/soapysdrinputthread.cpp +++ b/plugins/samplesource/soapysdrinput/soapysdrinputthread.cpp @@ -57,6 +57,10 @@ SoapySDRInputThread::~SoapySDRInputThread() void SoapySDRInputThread::startWork() { + if (m_running) { + return; + } + m_startWaitMutex.lock(); start(); @@ -69,6 +73,10 @@ void SoapySDRInputThread::startWork() void SoapySDRInputThread::stopWork() { + if (!m_running) { + return; + } + m_running = false; wait(); }