From 2ac7cfd800a63fc66374cf80ddfaaaf7cc41d0e7 Mon Sep 17 00:00:00 2001 From: srcejon Date: Wed, 6 Dec 2023 10:09:46 +0000 Subject: [PATCH] Add replay support to Lime Input --- .../limesdrinput/limesdrinput.cpp | 24 ++- .../samplesource/limesdrinput/limesdrinput.h | 23 ++- .../limesdrinput/limesdrinputgui.cpp | 110 ++++++++++++ .../limesdrinput/limesdrinputgui.h | 10 ++ .../limesdrinput/limesdrinputgui.ui | 106 +++++++++++- .../limesdrinput/limesdrinputsettings.cpp | 36 ++++ .../limesdrinput/limesdrinputsettings.h | 4 + .../limesdrinput/limesdrinputthread.cpp | 157 ++++++++++++------ .../limesdrinput/limesdrinputthread.h | 4 +- 9 files changed, 413 insertions(+), 61 deletions(-) diff --git a/plugins/samplesource/limesdrinput/limesdrinput.cpp b/plugins/samplesource/limesdrinput/limesdrinput.cpp index 9757df2c3..f0eaae215 100644 --- a/plugins/samplesource/limesdrinput/limesdrinput.cpp +++ b/plugins/samplesource/limesdrinput/limesdrinput.cpp @@ -48,6 +48,7 @@ MESSAGE_CLASS_DEFINITION(LimeSDRInput::MsgGetDeviceInfo, Message) MESSAGE_CLASS_DEFINITION(LimeSDRInput::MsgReportStreamInfo, Message) MESSAGE_CLASS_DEFINITION(LimeSDRInput::MsgStartStop, Message) MESSAGE_CLASS_DEFINITION(LimeSDRInput::MsgCalibrationResult, Message) +MESSAGE_CLASS_DEFINITION(LimeSDRInput::MsgSaveReplay, Message) LimeSDRInput::LimeSDRInput(DeviceAPI *deviceAPI) : m_deviceAPI(deviceAPI), @@ -422,7 +423,7 @@ bool LimeSDRInput::start() // start / stop streaming is done in the thread. - m_limeSDRInputThread = new LimeSDRInputThread(&m_streamId, &m_sampleFifo); + m_limeSDRInputThread = new LimeSDRInputThread(&m_streamId, &m_sampleFifo, &m_replayBuffer); qDebug("LimeSDRInput::start: thread created"); applySettings(m_settings, QList(), true); @@ -778,6 +779,12 @@ bool LimeSDRInput::handleMessage(const Message& message) return true; } + else if (MsgSaveReplay::match(message)) + { + MsgSaveReplay& cmd = (MsgSaveReplay&) message; + m_replayBuffer.save(cmd.getFilename(), m_settings.m_devSampleRate, getCenterFrequency()); + return true; + } else { return false; @@ -977,6 +984,9 @@ bool LimeSDRInput::applySettings(const LimeSDRInputSettings& settings, const QLi settings.m_devSampleRate, 1<getDevice(), LMS_CLOCK_CGEN, &clockGenFreqAfter) != 0) diff --git a/plugins/samplesource/limesdrinput/limesdrinput.h b/plugins/samplesource/limesdrinput/limesdrinput.h index 64df518b9..d86128e48 100644 --- a/plugins/samplesource/limesdrinput/limesdrinput.h +++ b/plugins/samplesource/limesdrinput/limesdrinput.h @@ -29,6 +29,7 @@ #include #include "dsp/devicesamplesource.h" +#include "dsp/replaybuffer.h" #include "limesdr/devicelimesdrshared.h" #include "limesdrinputsettings.h" @@ -209,7 +210,26 @@ public: { } }; - LimeSDRInput(DeviceAPI *deviceAPI); + class MsgSaveReplay : public Message { + MESSAGE_CLASS_DECLARATION + + public: + QString getFilename() const { return m_filename; } + + static MsgSaveReplay* create(const QString& filename) { + return new MsgSaveReplay(filename); + } + + protected: + QString m_filename; + + MsgSaveReplay(const QString& filename) : + Message(), + m_filename(filename) + { } + }; + + LimeSDRInput(DeviceAPI *deviceAPI); virtual ~LimeSDRInput(); virtual void destroy(); @@ -280,6 +300,7 @@ private: lms_stream_t m_streamId; QNetworkAccessManager *m_networkManager; QNetworkRequest m_networkRequest; + ReplayBuffer m_replayBuffer; bool openDevice(); void closeDevice(); diff --git a/plugins/samplesource/limesdrinput/limesdrinputgui.cpp b/plugins/samplesource/limesdrinput/limesdrinputgui.cpp index 3a387c44c..b5e72e3bf 100644 --- a/plugins/samplesource/limesdrinput/limesdrinputgui.cpp +++ b/plugins/samplesource/limesdrinput/limesdrinputgui.cpp @@ -469,6 +469,10 @@ void LimeSDRInputGUI::displaySettings() setNCODisplay(); ui->ncoEnable->setChecked(m_settings.m_ncoEnable); + displayReplayLength(); + displayReplayOffset(); + displayReplayStep(); + ui->replayLoop->setChecked(m_settings.m_replayLoop); } void LimeSDRInputGUI::setNCODisplay() @@ -805,6 +809,9 @@ void LimeSDRInputGUI::openDeviceSettingsDialog(const QPoint& p) if (m_contextMenuType == ContextMenuDeviceSettings) { BasicDeviceSettingsDialog dialog(this); + dialog.setReplayBytesPerSecond(m_settings.m_devSampleRate * 2 * sizeof(qint16)); + dialog.setReplayLength(m_settings.m_replayLength); + dialog.setReplayStep(m_settings.m_replayStep); dialog.setUseReverseAPI(m_settings.m_useReverseAPI); dialog.setReverseAPIAddress(m_settings.m_reverseAPIAddress); dialog.setReverseAPIPort(m_settings.m_reverseAPIPort); @@ -818,10 +825,17 @@ void LimeSDRInputGUI::openDeviceSettingsDialog(const QPoint& p) m_settings.m_reverseAPIAddress = dialog.getReverseAPIAddress(); m_settings.m_reverseAPIPort = dialog.getReverseAPIPort(); m_settings.m_reverseAPIDeviceIndex = dialog.getReverseAPIDeviceIndex(); + m_settings.m_replayLength = dialog.getReplayLength(); + m_settings.m_replayStep = dialog.getReplayStep(); + displayReplayLength(); + displayReplayOffset(); + displayReplayStep(); m_settingsKeys.append("useReverseAPI"); m_settingsKeys.append("reverseAPIAddress"); m_settingsKeys.append("reverseAPIPort"); m_settingsKeys.append("reverseAPIDeviceIndex"); + m_settingsKeys.append("replayLength"); + m_settingsKeys.append("replayStep"); sendSettings(); } @@ -829,6 +843,96 @@ void LimeSDRInputGUI::openDeviceSettingsDialog(const QPoint& p) resetContextMenuType(); } +void LimeSDRInputGUI::displayReplayLength() +{ + bool replayEnabled = m_settings.m_replayLength > 0.0f; + if (!replayEnabled) { + ui->replayOffset->setMaximum(0); + } else { + ui->replayOffset->setMaximum(m_settings.m_replayLength * 10 - 1); + } + ui->replayLabel->setEnabled(replayEnabled); + ui->replayOffset->setEnabled(replayEnabled); + ui->replayOffsetText->setEnabled(replayEnabled); + ui->replaySave->setEnabled(replayEnabled); +} + +void LimeSDRInputGUI::displayReplayOffset() +{ + bool replayEnabled = m_settings.m_replayLength > 0.0f; + ui->replayOffset->setValue(m_settings.m_replayOffset * 10); + ui->replayOffsetText->setText(QString("%1s").arg(m_settings.m_replayOffset, 0, 'f', 1)); + ui->replayNow->setEnabled(replayEnabled && (m_settings.m_replayOffset > 0.0f)); + ui->replayPlus->setEnabled(replayEnabled && (std::round(m_settings.m_replayOffset * 10) < ui->replayOffset->maximum())); + ui->replayMinus->setEnabled(replayEnabled && (m_settings.m_replayOffset > 0.0f)); +} + +void LimeSDRInputGUI::displayReplayStep() +{ + QString step; + float intpart; + float frac = modf(m_settings.m_replayStep, &intpart); + if (frac == 0.0f) { + step = QString::number((int)intpart); + } else { + step = QString::number(m_settings.m_replayStep, 'f', 1); + } + ui->replayPlus->setText(QString("+%1s").arg(step)); + ui->replayPlus->setToolTip(QString("Add %1 seconds to time delay").arg(step)); + ui->replayMinus->setText(QString("-%1s").arg(step)); + ui->replayMinus->setToolTip(QString("Remove %1 seconds from time delay").arg(step)); +} + +void LimeSDRInputGUI::on_replayOffset_valueChanged(int value) +{ + m_settings.m_replayOffset = value / 10.0f; + displayReplayOffset(); + m_settingsKeys.append("replayOffset"); + sendSettings(); +} + +void LimeSDRInputGUI::on_replayNow_clicked() +{ + ui->replayOffset->setValue(0); +} + +void LimeSDRInputGUI::on_replayPlus_clicked() +{ + ui->replayOffset->setValue(ui->replayOffset->value() + m_settings.m_replayStep * 10); +} + +void LimeSDRInputGUI::on_replayMinus_clicked() +{ + ui->replayOffset->setValue(ui->replayOffset->value() - m_settings.m_replayStep * 10); +} + +void LimeSDRInputGUI::on_replaySave_clicked() +{ + QFileDialog fileDialog(nullptr, "Select file to save IQ data to", "", "*.wav"); + fileDialog.setAcceptMode(QFileDialog::AcceptSave); + if (fileDialog.exec()) + { + QStringList fileNames = fileDialog.selectedFiles(); + if (fileNames.size() > 0) + { + LimeSDRInput::MsgSaveReplay *message = LimeSDRInput::MsgSaveReplay::create(fileNames[0]); + m_limeSDRInput->getInputMessageQueue()->push(message); + } + } +} + +void LimeSDRInputGUI::on_replayLoop_toggled(bool checked) +{ + m_settings.m_replayLoop = checked; + m_settingsKeys.append("replayLoop"); + sendSettings(); +} + +void LimeSDRInputGUI::setReplayTime(float time) +{ + ui->replayOffset->setValue(std::ceil(time * 10.0f)); +} + void LimeSDRInputGUI::makeUIConnections() { QObject::connect(ui->startStop, &ButtonSwitch::toggled, this, &LimeSDRInputGUI::on_startStop_toggled); @@ -852,4 +956,10 @@ void LimeSDRInputGUI::makeUIConnections() QObject::connect(ui->extClock, &ExternalClockButton::clicked, this, &LimeSDRInputGUI::on_extClock_clicked); QObject::connect(ui->transverter, &TransverterButton::clicked, this, &LimeSDRInputGUI::on_transverter_clicked); QObject::connect(ui->sampleRateMode, &QToolButton::toggled, this, &LimeSDRInputGUI::on_sampleRateMode_toggled); + QObject::connect(ui->replayOffset, &QSlider::valueChanged, this, &LimeSDRInputGUI::on_replayOffset_valueChanged); + QObject::connect(ui->replayNow, &QToolButton::clicked, this, &LimeSDRInputGUI::on_replayNow_clicked); + QObject::connect(ui->replayPlus, &QToolButton::clicked, this, &LimeSDRInputGUI::on_replayPlus_clicked); + QObject::connect(ui->replayMinus, &QToolButton::clicked, this, &LimeSDRInputGUI::on_replayMinus_clicked); + QObject::connect(ui->replaySave, &QToolButton::clicked, this, &LimeSDRInputGUI::on_replaySave_clicked); + QObject::connect(ui->replayLoop, &ButtonSwitch::toggled, this, &LimeSDRInputGUI::on_replayLoop_toggled); } diff --git a/plugins/samplesource/limesdrinput/limesdrinputgui.h b/plugins/samplesource/limesdrinput/limesdrinputgui.h index 8f49c22fa..3da20c14e 100644 --- a/plugins/samplesource/limesdrinput/limesdrinputgui.h +++ b/plugins/samplesource/limesdrinput/limesdrinputgui.h @@ -45,6 +45,7 @@ public: QByteArray serialize() const; bool deserialize(const QByteArray& data); virtual MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; } + void setReplayTime(float time) override; private: Ui::LimeSDRInputGUI* ui; @@ -66,6 +67,9 @@ private: void displaySettings(); void displaySampleRate(); + void displayReplayLength(); + void displayReplayOffset(); + void displayReplayStep(); void setNCODisplay(); void setCenterFrequencyDisplay(); void setCenterFrequencySetting(uint64_t kHzValue); @@ -101,6 +105,12 @@ private slots: void on_extClock_clicked(); void on_transverter_clicked(); void on_sampleRateMode_toggled(bool checked); + void on_replayOffset_valueChanged(int value); + void on_replayNow_clicked(); + void on_replayPlus_clicked(); + void on_replayMinus_clicked(); + void on_replaySave_clicked(); + void on_replayLoop_toggled(bool checked); void openDeviceSettingsDialog(const QPoint& p); void updateHardware(); diff --git a/plugins/samplesource/limesdrinput/limesdrinputgui.ui b/plugins/samplesource/limesdrinput/limesdrinputgui.ui index baba795b6..5ed2119ce 100644 --- a/plugins/samplesource/limesdrinput/limesdrinputgui.ui +++ b/plugins/samplesource/limesdrinput/limesdrinputgui.ui @@ -7,7 +7,7 @@ 0 0 360 - 230 + 255 @@ -19,13 +19,13 @@ 360 - 230 + 255 - 380 - 266 + 386 + 280 @@ -1169,6 +1169,104 @@ QToolTip{background-color: white; color: black;} + + + + + + + 65 + 0 + + + + Time Delay + + + + + + + Replay time delay in seconds + + + 500 + + + Qt::Horizontal + + + + + + + Replay time delay in seconds + + + 0.0s + + + + + + + Set time delay to 0 seconds + + + Now + + + + + + + Add displayed number of seconds to time delay + + + +5s + + + + + + + Remove displayed number of seconds from time delay + + + -5s + + + + + + + Repeatedly replay data in replay buffer + + + + + + + :/playloop.png:/playloop.png + + + + + + + Save replay buffer to a file + + + + + + + :/save.png:/save.png + + + + + diff --git a/plugins/samplesource/limesdrinput/limesdrinputsettings.cpp b/plugins/samplesource/limesdrinput/limesdrinputsettings.cpp index 1112d721c..088eafc0e 100644 --- a/plugins/samplesource/limesdrinput/limesdrinputsettings.cpp +++ b/plugins/samplesource/limesdrinput/limesdrinputsettings.cpp @@ -51,6 +51,10 @@ void LimeSDRInputSettings::resetToDefaults() m_iqOrder = true; m_gpioDir = 0; m_gpioPins = 0; + m_replayOffset = 0.0f; + m_replayLength = 20.0f; + m_replayStep = 5.0f; + m_replayLoop = false; m_useReverseAPI = false; m_reverseAPIAddress = "127.0.0.1"; m_reverseAPIPort = 8888; @@ -88,6 +92,10 @@ QByteArray LimeSDRInputSettings::serialize() const s.writeU32(26, m_reverseAPIPort); s.writeU32(27, m_reverseAPIDeviceIndex); s.writeBool(28, m_iqOrder); + s.writeFloat(29, m_replayOffset); + s.writeFloat(30, m_replayLength); + s.writeFloat(31, m_replayStep); + s.writeBool(32, m_replayLoop); return s.final(); } @@ -146,6 +154,10 @@ bool LimeSDRInputSettings::deserialize(const QByteArray& data) d.readU32(27, &uintval, 0); m_reverseAPIDeviceIndex = uintval > 99 ? 99 : uintval; d.readBool(28, &m_iqOrder, true); + d.readFloat(29, &m_replayOffset, 0.0f); + d.readFloat(30, &m_replayLength, 20.0f); + d.readFloat(31, &m_replayStep, 5.0f); + d.readBool(32, &m_replayLoop, false); return true; } @@ -231,6 +243,18 @@ void LimeSDRInputSettings::applySettings(const QStringList& settingsKeys, const if (settingsKeys.contains("gpioPins")) { m_gpioPins = settings.m_gpioPins; } + if (settingsKeys.contains("replayOffset")) { + m_replayOffset = settings.m_replayOffset; + } + if (settingsKeys.contains("replayLength")) { + m_replayLength = settings.m_replayLength; + } + if (settingsKeys.contains("replayStep")) { + m_replayStep = settings.m_replayStep; + } + if (settingsKeys.contains("replayLoop")) { + m_replayLoop = settings.m_replayLoop; + } if (settingsKeys.contains("useReverseAPI")) { m_useReverseAPI = settings.m_useReverseAPI; } @@ -321,6 +345,18 @@ QString LimeSDRInputSettings::getDebugString(const QStringList& settingsKeys, bo if (settingsKeys.contains("gpioPins") || force) { ostr << " m_gpioPins: " << m_gpioPins; } + if (settingsKeys.contains("replayOffset") || force) { + ostr << " m_replayOffset: " << m_replayOffset; + } + if (settingsKeys.contains("replayLength") || force) { + ostr << " m_replayLength: " << m_replayLength; + } + if (settingsKeys.contains("replayStep") || force) { + ostr << " m_replayStep: " << m_replayStep; + } + if (settingsKeys.contains("replayLoop") || force) { + ostr << " m_replayLoop: " << m_replayLoop; + } if (settingsKeys.contains("useReverseAPI") || force) { ostr << " m_useReverseAPI: " << m_useReverseAPI; } diff --git a/plugins/samplesource/limesdrinput/limesdrinputsettings.h b/plugins/samplesource/limesdrinput/limesdrinputsettings.h index 84c2a3a93..67b8a5c3c 100644 --- a/plugins/samplesource/limesdrinput/limesdrinputsettings.h +++ b/plugins/samplesource/limesdrinput/limesdrinputsettings.h @@ -71,6 +71,10 @@ struct LimeSDRInputSettings bool m_iqOrder; uint8_t m_gpioDir; //!< GPIO pin direction LSB first; 0 input, 1 output uint8_t m_gpioPins; //!< GPIO pins to write; LSB first + float m_replayOffset; //!< Replay offset in seconds + float m_replayLength; //!< Replay buffer size in seconds + float m_replayStep; //!< Replay forward/back step size in seconds + bool m_replayLoop; //!< Replay buffer repeatedly without recording new data bool m_useReverseAPI; QString m_reverseAPIAddress; uint16_t m_reverseAPIPort; diff --git a/plugins/samplesource/limesdrinput/limesdrinputthread.cpp b/plugins/samplesource/limesdrinput/limesdrinputthread.cpp index cb5df8c20..7ec9ebca0 100644 --- a/plugins/samplesource/limesdrinput/limesdrinputthread.cpp +++ b/plugins/samplesource/limesdrinput/limesdrinputthread.cpp @@ -18,15 +18,18 @@ #include #include +#include "dsp/replaybuffer.h" #include "limesdrinputsettings.h" #include "limesdrinputthread.h" -LimeSDRInputThread::LimeSDRInputThread(lms_stream_t* stream, SampleSinkFifo* sampleFifo, QObject* parent) : +LimeSDRInputThread::LimeSDRInputThread(lms_stream_t* stream, SampleSinkFifo* sampleFifo, + ReplayBuffer *replayBuffer, QObject* parent) : QThread(parent), m_running(false), m_stream(stream), m_convertBuffer(DeviceLimeSDR::blockSize), m_sampleFifo(sampleFifo), + m_replayBuffer(replayBuffer), m_log2Decim(0), m_iqOrder(true) { @@ -106,70 +109,116 @@ void LimeSDRInputThread::run() } // Decimate according to specified log2 (ex: log2=4 => decim=16) -void LimeSDRInputThread::callbackIQ(const qint16* buf, qint32 len) +void LimeSDRInputThread::callbackIQ(const qint16* inBuf, qint32 len) { SampleVector::iterator it = m_convertBuffer.begin(); - switch (m_log2Decim) - { - case 0: - m_decimatorsIQ.decimate1(&it, buf, len); - break; - case 1: - m_decimatorsIQ.decimate2_cen(&it, buf, len); - break; - case 2: - m_decimatorsIQ.decimate4_cen(&it, buf, len); - break; - case 3: - m_decimatorsIQ.decimate8_cen(&it, buf, len); - break; - case 4: - m_decimatorsIQ.decimate16_cen(&it, buf, len); - break; - case 5: - m_decimatorsIQ.decimate32_cen(&it, buf, len); - break; - case 6: - m_decimatorsIQ.decimate64_cen(&it, buf, len); - break; - default: - break; + // Save data to replay buffer + m_replayBuffer->lock(); + bool replayEnabled = m_replayBuffer->getSize() > 0; + if (replayEnabled) { + m_replayBuffer->write(inBuf, len); + } + + const qint16* buf = inBuf; + qint32 remaining = len; + + while (remaining > 0) + { + // Choose between live data or replayed data + if (replayEnabled && m_replayBuffer->useReplay()) { + len = m_replayBuffer->read(remaining, buf); + } else { + len = remaining; + } + remaining -= len; + + switch (m_log2Decim) + { + case 0: + m_decimatorsIQ.decimate1(&it, buf, len); + break; + case 1: + m_decimatorsIQ.decimate2_cen(&it, buf, len); + break; + case 2: + m_decimatorsIQ.decimate4_cen(&it, buf, len); + break; + case 3: + m_decimatorsIQ.decimate8_cen(&it, buf, len); + break; + case 4: + m_decimatorsIQ.decimate16_cen(&it, buf, len); + break; + case 5: + m_decimatorsIQ.decimate32_cen(&it, buf, len); + break; + case 6: + m_decimatorsIQ.decimate64_cen(&it, buf, len); + break; + default: + break; + } } + m_replayBuffer->unlock(); + m_sampleFifo->write(m_convertBuffer.begin(), it); } -void LimeSDRInputThread::callbackQI(const qint16* buf, qint32 len) +void LimeSDRInputThread::callbackQI(const qint16* inBuf, qint32 len) { SampleVector::iterator it = m_convertBuffer.begin(); - switch (m_log2Decim) - { - case 0: - m_decimatorsQI.decimate1(&it, buf, len); - break; - case 1: - m_decimatorsQI.decimate2_cen(&it, buf, len); - break; - case 2: - m_decimatorsQI.decimate4_cen(&it, buf, len); - break; - case 3: - m_decimatorsQI.decimate8_cen(&it, buf, len); - break; - case 4: - m_decimatorsQI.decimate16_cen(&it, buf, len); - break; - case 5: - m_decimatorsQI.decimate32_cen(&it, buf, len); - break; - case 6: - m_decimatorsQI.decimate64_cen(&it, buf, len); - break; - default: - break; - } + // Save data to replay buffer + m_replayBuffer->lock(); + bool replayEnabled = m_replayBuffer->getSize() > 0; + if (replayEnabled) { + m_replayBuffer->write(inBuf, len); + } + + const qint16* buf = inBuf; + qint32 remaining = len; + + while (remaining > 0) + { + // Choose between live data or replayed data + if (replayEnabled && m_replayBuffer->useReplay()) { + len = m_replayBuffer->read(remaining, buf); + } else { + len = remaining; + } + remaining -= len; + + switch (m_log2Decim) + { + case 0: + m_decimatorsQI.decimate1(&it, buf, len); + break; + case 1: + m_decimatorsQI.decimate2_cen(&it, buf, len); + break; + case 2: + m_decimatorsQI.decimate4_cen(&it, buf, len); + break; + case 3: + m_decimatorsQI.decimate8_cen(&it, buf, len); + break; + case 4: + m_decimatorsQI.decimate16_cen(&it, buf, len); + break; + case 5: + m_decimatorsQI.decimate32_cen(&it, buf, len); + break; + case 6: + m_decimatorsQI.decimate64_cen(&it, buf, len); + break; + default: + break; + } + } + + m_replayBuffer->unlock(); m_sampleFifo->write(m_convertBuffer.begin(), it); } diff --git a/plugins/samplesource/limesdrinput/limesdrinputthread.h b/plugins/samplesource/limesdrinput/limesdrinputthread.h index 7fe318494..1c473de40 100644 --- a/plugins/samplesource/limesdrinput/limesdrinputthread.h +++ b/plugins/samplesource/limesdrinput/limesdrinputthread.h @@ -37,7 +37,8 @@ class LimeSDRInputThread : public QThread, public DeviceLimeSDRShared::ThreadInt Q_OBJECT public: - LimeSDRInputThread(lms_stream_t* stream, SampleSinkFifo* sampleFifo, QObject* parent = 0); + LimeSDRInputThread(lms_stream_t* stream, SampleSinkFifo* sampleFifo, + ReplayBuffer *replayBuffer, QObject* parent = 0); ~LimeSDRInputThread(); virtual void startWork(); @@ -56,6 +57,7 @@ private: qint16 m_buf[2*DeviceLimeSDR::blockSize]; //must hold I+Q values of each sample hence 2xcomplex size SampleVector m_convertBuffer; SampleSinkFifo* m_sampleFifo; + ReplayBuffer *m_replayBuffer; unsigned int m_log2Decim; // soft decimation bool m_iqOrder;