mirror of
				https://github.com/f4exb/sdrangel.git
				synced 2025-10-31 04:50:29 -04:00 
			
		
		
		
	Add replay support to Lime Input
This commit is contained in:
		
							parent
							
								
									238a40b9e0
								
							
						
					
					
						commit
						2ac7cfd800
					
				| @ -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<QString>(), 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<<settings.m_log2HardDecim); | ||||
|             } | ||||
|             if (settings.m_devSampleRate != m_settings.m_devSampleRate) { | ||||
|                 m_replayBuffer.clear(); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
| @ -1168,6 +1178,18 @@ bool LimeSDRInput::applySettings(const LimeSDRInputSettings& settings, const QLi | ||||
|         m_settings.applySettings(settingsKeys, settings); | ||||
|     } | ||||
| 
 | ||||
|     if (settingsKeys.contains("replayLength") || settingsKeys.contains("devSampleRate") || force) { | ||||
|         m_replayBuffer.setSize(m_settings.m_replayLength, m_settings.m_devSampleRate); | ||||
|     } | ||||
| 
 | ||||
|     if (settingsKeys.contains("replayOffset") || settingsKeys.contains("devSampleRate")  || force) { | ||||
|         m_replayBuffer.setReadOffset(((unsigned)(m_settings.m_replayOffset * m_settings.m_devSampleRate)) * 2); | ||||
|     } | ||||
| 
 | ||||
|     if (settingsKeys.contains("replayLoop") || force) { | ||||
|         m_replayBuffer.setLoop(m_settings.m_replayLoop); | ||||
|     } | ||||
| 
 | ||||
|     double clockGenFreqAfter; | ||||
| 
 | ||||
|     if (LMS_GetClockFreq(m_deviceShared.m_deviceParams->getDevice(), LMS_CLOCK_CGEN, &clockGenFreqAfter) != 0) | ||||
|  | ||||
| @ -29,6 +29,7 @@ | ||||
| #include <QNetworkRequest> | ||||
| 
 | ||||
| #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<qint16> m_replayBuffer; | ||||
| 
 | ||||
|     bool openDevice(); | ||||
|     void closeDevice(); | ||||
|  | ||||
| @ -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); | ||||
| } | ||||
|  | ||||
| @ -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(); | ||||
|  | ||||
| @ -7,7 +7,7 @@ | ||||
|     <x>0</x> | ||||
|     <y>0</y> | ||||
|     <width>360</width> | ||||
|     <height>230</height> | ||||
|     <height>255</height> | ||||
|    </rect> | ||||
|   </property> | ||||
|   <property name="sizePolicy"> | ||||
| @ -19,13 +19,13 @@ | ||||
|   <property name="minimumSize"> | ||||
|    <size> | ||||
|     <width>360</width> | ||||
|     <height>230</height> | ||||
|     <height>255</height> | ||||
|    </size> | ||||
|   </property> | ||||
|   <property name="maximumSize"> | ||||
|    <size> | ||||
|     <width>380</width> | ||||
|     <height>266</height> | ||||
|     <width>386</width> | ||||
|     <height>280</height> | ||||
|    </size> | ||||
|   </property> | ||||
|   <property name="font"> | ||||
| @ -1169,6 +1169,104 @@ QToolTip{background-color: white; color: black;}</string> | ||||
|      </item> | ||||
|     </layout> | ||||
|    </item> | ||||
|    <item> | ||||
|     <layout class="QHBoxLayout" name="replayLayout"> | ||||
|      <item> | ||||
|       <widget class="QLabel" name="replayLabel"> | ||||
|        <property name="minimumSize"> | ||||
|         <size> | ||||
|          <width>65</width> | ||||
|          <height>0</height> | ||||
|         </size> | ||||
|        </property> | ||||
|        <property name="text"> | ||||
|         <string>Time Delay</string> | ||||
|        </property> | ||||
|       </widget> | ||||
|      </item> | ||||
|      <item> | ||||
|       <widget class="QSlider" name="replayOffset"> | ||||
|        <property name="toolTip"> | ||||
|         <string>Replay time delay in seconds</string> | ||||
|        </property> | ||||
|        <property name="maximum"> | ||||
|         <number>500</number> | ||||
|        </property> | ||||
|        <property name="orientation"> | ||||
|         <enum>Qt::Horizontal</enum> | ||||
|        </property> | ||||
|       </widget> | ||||
|      </item> | ||||
|      <item> | ||||
|       <widget class="QLabel" name="replayOffsetText"> | ||||
|        <property name="toolTip"> | ||||
|         <string>Replay time delay in seconds</string> | ||||
|        </property> | ||||
|        <property name="text"> | ||||
|         <string>0.0s</string> | ||||
|        </property> | ||||
|       </widget> | ||||
|      </item> | ||||
|      <item> | ||||
|       <widget class="QToolButton" name="replayNow"> | ||||
|        <property name="toolTip"> | ||||
|         <string>Set time delay to 0 seconds</string> | ||||
|        </property> | ||||
|        <property name="text"> | ||||
|         <string>Now</string> | ||||
|        </property> | ||||
|       </widget> | ||||
|      </item> | ||||
|      <item> | ||||
|       <widget class="QToolButton" name="replayPlus"> | ||||
|        <property name="toolTip"> | ||||
|         <string>Add displayed number of seconds to time delay</string> | ||||
|        </property> | ||||
|        <property name="text"> | ||||
|         <string>+5s</string> | ||||
|        </property> | ||||
|       </widget> | ||||
|      </item> | ||||
|      <item> | ||||
|       <widget class="QToolButton" name="replayMinus"> | ||||
|        <property name="toolTip"> | ||||
|         <string>Remove displayed number of seconds from time delay</string> | ||||
|        </property> | ||||
|        <property name="text"> | ||||
|         <string>-5s</string> | ||||
|        </property> | ||||
|       </widget> | ||||
|      </item> | ||||
|      <item> | ||||
|       <widget class="ButtonSwitch" name="replayLoop"> | ||||
|        <property name="toolTip"> | ||||
|         <string>Repeatedly replay data in replay buffer</string> | ||||
|        </property> | ||||
|        <property name="text"> | ||||
|         <string/> | ||||
|        </property> | ||||
|        <property name="icon"> | ||||
|         <iconset resource="../../../sdrgui/resources/res.qrc"> | ||||
|          <normaloff>:/playloop.png</normaloff>:/playloop.png</iconset> | ||||
|        </property> | ||||
|       </widget> | ||||
|      </item> | ||||
|      <item> | ||||
|       <widget class="QToolButton" name="replaySave"> | ||||
|        <property name="toolTip"> | ||||
|         <string>Save replay buffer to a file</string> | ||||
|        </property> | ||||
|        <property name="text"> | ||||
|         <string/> | ||||
|        </property> | ||||
|        <property name="icon"> | ||||
|         <iconset resource="../../../sdrgui/resources/res.qrc"> | ||||
|          <normaloff>:/save.png</normaloff>:/save.png</iconset> | ||||
|        </property> | ||||
|       </widget> | ||||
|      </item> | ||||
|     </layout> | ||||
|    </item> | ||||
|   </layout> | ||||
|  </widget> | ||||
|  <customwidgets> | ||||
|  | ||||
| @ -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; | ||||
|     } | ||||
|  | ||||
| @ -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; | ||||
|  | ||||
| @ -18,15 +18,18 @@ | ||||
| #include <errno.h> | ||||
| #include <algorithm> | ||||
| 
 | ||||
| #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<qint16> *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); | ||||
| } | ||||
|  | ||||
| @ -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<qint16> *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<qint16> *m_replayBuffer; | ||||
| 
 | ||||
|     unsigned int m_log2Decim; // soft decimation
 | ||||
|     bool m_iqOrder; | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user