From 7b437e41ba68b5d79f983e2340f61b642c164254 Mon Sep 17 00:00:00 2001 From: f4exb Date: Wed, 6 Sep 2017 18:48:58 +0200 Subject: [PATCH] PlutoSDR input: implemented input class interim state (1) --- devices/plutosdr/deviceplutosdrbox.cpp | 34 +++- devices/plutosdr/deviceplutosdrbox.h | 13 ++ .../plutosdrinput/plutosdrinput.cpp | 146 +++++++++++++++--- .../plutosdrinput/plutosdrinput.h | 25 +++ .../plutosdrinput/plutosdrinputsettings.cpp | 9 ++ .../plutosdrinput/plutosdrinputsettings.h | 17 +- 6 files changed, 217 insertions(+), 27 deletions(-) diff --git a/devices/plutosdr/deviceplutosdrbox.cpp b/devices/plutosdr/deviceplutosdrbox.cpp index db6b4cb98..1c1903c3f 100644 --- a/devices/plutosdr/deviceplutosdrbox.cpp +++ b/devices/plutosdr/deviceplutosdrbox.cpp @@ -19,6 +19,7 @@ #include #include #include +#include #include "deviceplutosdrbox.h" @@ -327,7 +328,38 @@ char* DevicePlutoSDRBox::txBufferFirst() } } - +bool DevicePlutoSDRBox::parseSampleRates(const std::string& rateStr, SampleRates& sampleRates) +{ + // Rx: "BBPLL:983040000 ADC:245760000 R2:122880000 R1:61440000 RF:30720000 RXSAMP:30720000" + // Tx: "BBPLL:983040000 DAC:122880000 T2:122880000 T1:61440000 TF:30720000 TXSAMP:30720000" + std::regex desc_regex("BBPLL:(.+) ..C:(.+) .2:(.+) .1:(.+) .F:(.+) .XSAMP:(.+)"); + std::smatch desc_match; + std::regex_search(rateStr, desc_match, desc_regex); + std::string valueStr; + + if (desc_match.size() == 7) + { + try + { + sampleRates.m_bbRate = boost::lexical_cast(desc_match[1]); + sampleRates.m_addaConnvRate = boost::lexical_cast(desc_match[2]); + sampleRates.m_hb3Rate = boost::lexical_cast(desc_match[3]); + sampleRates.m_hb2Rate = boost::lexical_cast(desc_match[4]); + sampleRates.m_hb1Rate = boost::lexical_cast(desc_match[5]); + sampleRates.m_firRate = boost::lexical_cast(desc_match[6]); + return true; + } + catch (const boost::bad_lexical_cast &e) + { + qWarning("DevicePlutoSDRBox::parseSampleRates: bad conversion to numeric"); + return false; + } + } + else + { + return false; + } +} diff --git a/devices/plutosdr/deviceplutosdrbox.h b/devices/plutosdr/deviceplutosdrbox.h index be0e773d4..72e7d147d 100644 --- a/devices/plutosdr/deviceplutosdrbox.h +++ b/devices/plutosdr/deviceplutosdrbox.h @@ -36,6 +36,15 @@ public: int16_t q; }; + struct SampleRates { + uint32_t m_bbRate; //!< Baseband PLL rate (Hz) - used internally + uint32_t m_addaConnvRate; //!< A/D or D/A converter rate (Hz) - this is the HB3 working sample rate + uint32_t m_hb3Rate; //!< Rate of the HB3/(DEC3 or INT3) filter (Rx: out, Tx: in) - this is the HB2 working sample rate + uint32_t m_hb2Rate; //!< Rate of the HB2 filter (Rx: out, Tx: in) - this is the HB1 working sample rate + uint32_t m_hb1Rate; //!< Rate of the HB1 filter (Rx: out, Tx: in) - this is the FIR working sample rate + uint32_t m_firRate; //!< Rate of FIR filter (Rx: out, Tx: in) - this is the host/device communication sample rate + }; + DevicePlutoSDRBox(const std::string& uri); ~DevicePlutoSDRBox(); bool isValid() const { return m_valid; } @@ -62,6 +71,8 @@ public: std::ptrdiff_t txBufferStep(); char* txBufferEnd(); char* txBufferFirst(); + bool getRxSampleRates(SampleRates& sampleRates); + bool getTxSampleRates(SampleRates& sampleRates); private: struct iio_context *m_ctx; @@ -73,6 +84,8 @@ private: struct iio_buffer *m_rxBuf; struct iio_buffer *m_txBuf; bool m_valid; + + bool parseSampleRates(const std::string& rateStr, SampleRates& sampleRates); }; #endif /* DEVICES_PLUTOSDR_DEVICEPLUTOSDRBOX_H_ */ diff --git a/plugins/samplesource/plutosdrinput/plutosdrinput.cpp b/plugins/samplesource/plutosdrinput/plutosdrinput.cpp index fa1c5d7b3..5b90658cd 100644 --- a/plugins/samplesource/plutosdrinput/plutosdrinput.cpp +++ b/plugins/samplesource/plutosdrinput/plutosdrinput.cpp @@ -23,6 +23,7 @@ #include "plutosdr/deviceplutosdrbox.h" #include "plutosdrinput.h" +#include "plutosdrinputthread.h" #define PLUTOSDR_BLOCKSIZE (1024*1024) //complex samples per buffer @@ -33,7 +34,8 @@ PlutoSDRInput::PlutoSDRInput(DeviceSourceAPI *deviceAPI) : m_fileSink(0), m_deviceDescription("PlutoSDR"), m_running(false), - m_plutoRxBuffer(0) + m_plutoRxBuffer(0), + m_plutoSDRInputThread(0) { char recFileNameCStr[30]; sprintf(recFileNameCStr, "test_%d.sdriq", m_deviceAPI->getDeviceUID()); @@ -60,29 +62,37 @@ bool PlutoSDRInput::start() // start / stop streaming is done in the thread. -// if ((m_limeSDRInputThread = new LimeSDRInputThread(&m_streamId, &m_sampleFifo)) == 0) -// { -// qFatal("LimeSDRInput::start: cannot create thread"); -// stop(); -// return false; -// } -// else -// { -// qDebug("LimeSDRInput::start: thread created"); -// } -// -// m_limeSDRInputThread->setLog2Decimation(m_settings.m_log2SoftDecim); -// -// m_limeSDRInputThread->startWork(); -// -// m_deviceShared.m_thread = m_limeSDRInputThread; -// m_running = true; + if ((m_plutoSDRInputThread = new PlutoSDRInputThread(PLUTOSDR_BLOCKSIZE, m_deviceShared.m_deviceParams->getBox(), &m_sampleFifo)) == 0) + { + qFatal("PlutoSDRInput::start: cannot create thread"); + stop(); + return false; + } + else + { + qDebug("PlutoSDRInput::start: thread created"); + } + + m_plutoSDRInputThread->setLog2Decimation(m_settings.m_log2Decim); + m_plutoSDRInputThread->startWork(); + + m_deviceShared.m_thread = m_plutoSDRInputThread; + m_running = true; return true; } void PlutoSDRInput::stop() { + if (m_plutoSDRInputThread != 0) + { + m_plutoSDRInputThread->stopWork(); + delete m_plutoSDRInputThread; + m_plutoSDRInputThread = 0; + } + + m_deviceShared.m_thread = 0; + m_running = false; } const QString& PlutoSDRInput::getDeviceDescription() const @@ -102,7 +112,19 @@ quint64 PlutoSDRInput::getCenterFrequency() const bool PlutoSDRInput::handleMessage(const Message& message) { - if (MsgFileRecord::match(message)) + if (MsgConfigurePlutoSDR::match(message)) + { + MsgConfigurePlutoSDR& conf = (MsgConfigurePlutoSDR&) message; + qDebug() << "PlutoSDRInput::handleMessage: MsgConfigurePlutoSDR"; + + if (!applySettings(conf.getSettings(), conf.getForce())) + { + qDebug("PlutoSDRInput::handleMessage config error"); + } + + return true; + } + else if (MsgFileRecord::match(message)) { MsgFileRecord& conf = (MsgFileRecord&) message; qDebug() << "PlutoSDRInput::handleMessage: MsgFileRecord: " << conf.getStartStop(); @@ -219,5 +241,91 @@ void PlutoSDRInput::resumeBuddies() bool PlutoSDRInput::applySettings(const PlutoSDRInputSettings& settings, bool force) { + bool forwardChangeOwnDSP = false; + bool forwardChangeAllDSP = false; + bool suspendOwnThread = false; + bool ownThreadWasRunning = false; + bool suspendAllOtherThreads = false; // All others means Tx in fact + bool doCalibration = false; + + // determine if buddies threads or own thread need to be suspended + + // change of global baseband sample rate affecting all buddies can occur if + // - device to host sample rate is changed + // - rate governor is changed + // - FIR filter decimation is changed + if ((m_settings.m_devSampleRate != settings.m_devSampleRate) || + (m_settings.m_rateGovernor != settings.m_rateGovernor) || + (m_settings.m_lpfFIRlog2Decim != settings.m_lpfFIRlog2Decim) || force) + { + suspendAllOtherThreads = true; + suspendOwnThread = true; + } + else + { + suspendOwnThread = true; + } + + if (suspendAllOtherThreads) + { + const std::vector& sinkBuddies = m_deviceAPI->getSinkBuddies(); + std::vector::const_iterator itSink = sinkBuddies.begin(); + + for (; itSink != sinkBuddies.end(); ++itSink) + { + DevicePlutoSDRShared *buddySharedPtr = (DevicePlutoSDRShared *) (*itSink)->getBuddySharedPtr(); + + if (buddySharedPtr->m_thread) { + buddySharedPtr->m_thread->stopWork(); + buddySharedPtr->m_threadWasRunning = true; + } + else + { + buddySharedPtr->m_threadWasRunning = false; + } + } + } + + if (suspendOwnThread) + { + if (m_plutoSDRInputThread && m_plutoSDRInputThread->isRunning()) + { + m_plutoSDRInputThread->stopWork(); + ownThreadWasRunning = true; + } + } + + // TODO: apply settings (all cases) + + // Change affecting device baseband sample rate potentially affecting all buddies device/host sample rate + if ((m_settings.m_devSampleRate != settings.m_devSampleRate) || + (m_settings.m_rateGovernor != settings.m_rateGovernor) || + (m_settings.m_lpfFIRlog2Decim != settings.m_lpfFIRlog2Decim) || force) + { + forwardChangeAllDSP = true; + } + + if (suspendAllOtherThreads) + { + const std::vector& sinkBuddies = m_deviceAPI->getSinkBuddies(); + std::vector::const_iterator itSink = sinkBuddies.begin(); + + for (; itSink != sinkBuddies.end(); ++itSink) + { + DevicePlutoSDRShared *buddySharedPtr = (DevicePlutoSDRShared *) (*itSink)->getBuddySharedPtr(); + + if (buddySharedPtr->m_threadWasRunning) { + buddySharedPtr->m_thread->startWork(); + } + } + } + + if (suspendOwnThread) + { + if (ownThreadWasRunning) { + m_plutoSDRInputThread->startWork(); + } + } + return false; } diff --git a/plugins/samplesource/plutosdrinput/plutosdrinput.h b/plugins/samplesource/plutosdrinput/plutosdrinput.h index 660e21fd5..6d010df14 100644 --- a/plugins/samplesource/plutosdrinput/plutosdrinput.h +++ b/plugins/samplesource/plutosdrinput/plutosdrinput.h @@ -27,9 +27,33 @@ class DeviceSourceAPI; class FileRecord; +class PlutoSDRInputThread; class PlutoSDRInput : public DeviceSampleSource { public: + class MsgConfigurePlutoSDR : public Message { + MESSAGE_CLASS_DECLARATION + + public: + const PlutoSDRInputSettings& getSettings() const { return m_settings; } + bool getForce() const { return m_force; } + + static MsgConfigurePlutoSDR* create(const PlutoSDRInputSettings& settings, bool force) + { + return new MsgConfigurePlutoSDR(settings, force); + } + + private: + MsgConfigurePlutoSDR m_settings; + bool m_force; + + MsgConfigurePlutoSDR(const PlutoSDRInputSettings& settings, bool force) : + Message(), + m_settings(settings), + m_force(force) + { } + }; + class MsgFileRecord : public Message { MESSAGE_CLASS_DECLARATION @@ -70,6 +94,7 @@ public: bool m_running; DevicePlutoSDRShared m_deviceShared; struct iio_buffer *m_plutoRxBuffer; + PlutoSDRInputThread *m_plutoSDRInputThread; QMutex m_mutex; bool openDevice(); diff --git a/plugins/samplesource/plutosdrinput/plutosdrinputsettings.cpp b/plugins/samplesource/plutosdrinput/plutosdrinputsettings.cpp index ae69c2107..adb181f92 100644 --- a/plugins/samplesource/plutosdrinput/plutosdrinputsettings.cpp +++ b/plugins/samplesource/plutosdrinput/plutosdrinputsettings.cpp @@ -38,6 +38,7 @@ void PlutoSDRInputSettings::resetToDefaults() m_lpfBW = 1500000.0f; m_lpfFIREnable = false; m_lpfFIRBW = 500000.0f; + m_lpfFIRlog2Decim = 0; m_gain = 40; m_antennaPath = RFPATH_A_BAL; m_gainMode = GAIN_MANUAL; @@ -48,6 +49,7 @@ QByteArray PlutoSDRInputSettings::serialize() const SimpleSerializer s(1); s.writeS32(1, m_LOppmTenths); + s.writeU32(3, m_lpfFIRlog2Decim); s.writeU32(4, m_log2Decim); s.writeS32(5, m_fcPos); s.writeS32(6, m_rateGovernor); @@ -77,8 +79,15 @@ bool PlutoSDRInputSettings::deserialize(const QByteArray& data) if (d.getVersion() == 1) { int intval; + uint32_t uintval; d.readS32(1, &m_LOppmTenths, 0); + d.readU32(3, &uintval, 0); + if (uintval > 2) { + m_lpfFIRlog2Decim = 2; + } else { + m_lpfFIRlog2Decim = uintval; + } d.readU32(4, &m_log2Decim, 0); d.readS32(5, &intval, 0); if ((intval < 0) || (intval > 2)) { diff --git a/plugins/samplesource/plutosdrinput/plutosdrinputsettings.h b/plugins/samplesource/plutosdrinput/plutosdrinputsettings.h index 4a09192d6..7c13f3a69 100644 --- a/plugins/samplesource/plutosdrinput/plutosdrinputsettings.h +++ b/plugins/samplesource/plutosdrinput/plutosdrinputsettings.h @@ -58,18 +58,21 @@ struct PlutoSDRInputSettings { RATEGOV_END } RateGovernor; + // global settings to be saved quint64 m_centerFrequency; - fcPos_t m_fcPos; - qint32 m_LOppmTenths; - quint32 m_log2Decim; quint64 m_devSampleRate; RateGovernor m_rateGovernor; + // channel settings + fcPos_t m_fcPos; + qint32 m_LOppmTenths; bool m_dcBlock; bool m_iqCorrection; - float m_lpfBW; //!< analog lowpass filter bandwidth (Hz) - bool m_lpfFIREnable; //!< enable digital lowpass FIR filter - float m_lpfFIRBW; //!< digital lowpass FIR filter bandwidth (Hz) - uint32_t m_gain; //!< "hardware" gain + quint32 m_log2Decim; + float m_lpfBW; //!< analog lowpass filter bandwidth (Hz) + bool m_lpfFIREnable; //!< enable digital lowpass FIR filter + float m_lpfFIRBW; //!< digital lowpass FIR filter bandwidth (Hz) + quint32 m_lpfFIRlog2Decim; //!< digital lowpass FIR filter log2 of decimation factor (0..2) + uint32_t m_gain; //!< "hardware" gain RFPath m_antennaPath; GainMode m_gainMode;