mirror of
				https://github.com/f4exb/sdrangel.git
				synced 2025-10-31 13:00:26 -04:00 
			
		
		
		
	Remote output/source: use queue langth for rate control and derive rate from Tx side. Other fixes
This commit is contained in:
		
							parent
							
								
									1168eefcc9
								
							
						
					
					
						commit
						54866a1a1e
					
				| @ -28,6 +28,8 @@ | ||||
| #include "SWGRemoteSourceReport.h" | ||||
| 
 | ||||
| #include "dsp/devicesamplesink.h" | ||||
| #include "dsp/hbfilterchainconverter.h" | ||||
| #include "dsp/dspcommands.h" | ||||
| #include "device/deviceapi.h" | ||||
| #include "feature/feature.h" | ||||
| #include "settings/serializable.h" | ||||
| @ -40,13 +42,17 @@ | ||||
| MESSAGE_CLASS_DEFINITION(RemoteSource::MsgConfigureRemoteSource, Message) | ||||
| MESSAGE_CLASS_DEFINITION(RemoteSource::MsgQueryStreamData, Message) | ||||
| MESSAGE_CLASS_DEFINITION(RemoteSource::MsgReportStreamData, Message) | ||||
| MESSAGE_CLASS_DEFINITION(RemoteSource::MsgBasebandSampleRateNotification, Message) | ||||
| 
 | ||||
| const char* const RemoteSource::m_channelIdURI = "sdrangel.channeltx.remotesource"; | ||||
| const char* const RemoteSource::m_channelId ="RemoteSource"; | ||||
| 
 | ||||
| RemoteSource::RemoteSource(DeviceAPI *deviceAPI) : | ||||
|     ChannelAPI(m_channelIdURI, ChannelAPI::StreamSingleSource), | ||||
|     m_deviceAPI(deviceAPI) | ||||
|     m_deviceAPI(deviceAPI), | ||||
|     m_centerFrequency(0), | ||||
|     m_frequencyOffset(0), | ||||
|     m_basebandSampleRate(48000) | ||||
| { | ||||
|     setObjectName(m_channelId); | ||||
| 
 | ||||
| @ -96,7 +102,27 @@ void RemoteSource::pull(SampleVector::iterator& begin, unsigned int nbSamples) | ||||
| 
 | ||||
| bool RemoteSource::handleMessage(const Message& cmd) | ||||
| { | ||||
|     if (MsgConfigureRemoteSource::match(cmd)) | ||||
|     if (DSPSignalNotification::match(cmd)) | ||||
|     { | ||||
|         DSPSignalNotification& notif = (DSPSignalNotification&) cmd; | ||||
| 
 | ||||
|         qDebug() << "RemoteSource::handleMessage: DSPSignalNotification:" | ||||
|                 << " inputSampleRate: " << notif.getSampleRate() | ||||
|                 << " centerFrequency: " << notif.getCenterFrequency(); | ||||
| 
 | ||||
|         m_basebandSampleRate = notif.getSampleRate(); | ||||
|         calculateFrequencyOffset(m_settings.m_log2Interp, m_settings.m_filterChainHash); // This is when device sample rate changes
 | ||||
|         m_centerFrequency = notif.getCenterFrequency(); | ||||
| 
 | ||||
|         if (m_guiMessageQueue) | ||||
|         { | ||||
|             MsgBasebandSampleRateNotification *msg = MsgBasebandSampleRateNotification::create(notif.getSampleRate()); | ||||
|             m_guiMessageQueue->push(msg); | ||||
|         } | ||||
| 
 | ||||
|         return true; | ||||
|     } | ||||
|     else if (MsgConfigureRemoteSource::match(cmd)) | ||||
|     { | ||||
|         MsgConfigureRemoteSource& cfg = (MsgConfigureRemoteSource&) cmd; | ||||
|         qDebug() << "MsgConfigureRemoteSource::handleMessage: MsgConfigureRemoteSource"; | ||||
| @ -158,27 +184,39 @@ bool RemoteSource::deserialize(const QByteArray& data) | ||||
| void RemoteSource::applySettings(const RemoteSourceSettings& settings, bool force) | ||||
| { | ||||
|     qDebug() << "RemoteSource::applySettings:" | ||||
|             << " m_dataAddress: " << settings.m_dataAddress | ||||
|             << " m_dataPort: " << settings.m_dataPort | ||||
|             << " m_rgbColor: " << settings.m_rgbColor | ||||
|             << " m_title: " << settings.m_title | ||||
|             << " m_useReverseAPI: " << settings.m_useReverseAPI | ||||
|             << " m_reverseAPIAddress: " << settings.m_reverseAPIAddress | ||||
|             << " m_reverseAPIChannelIndex: " << settings.m_reverseAPIChannelIndex | ||||
|             << " m_reverseAPIDeviceIndex: " << settings.m_reverseAPIDeviceIndex | ||||
|             << " m_reverseAPIPort: " << settings.m_reverseAPIPort | ||||
|             << " force: " << force; | ||||
|             << "m_log2Interp:" << settings.m_log2Interp | ||||
|             << "m_filterChainHash:" << settings.m_filterChainHash | ||||
|             << "m_dataAddress:" << settings.m_dataAddress | ||||
|             << "m_dataPort:" << settings.m_dataPort | ||||
|             << "m_rgbColor:" << settings.m_rgbColor | ||||
|             << "m_title:" << settings.m_title | ||||
|             << "m_useReverseAPI:" << settings.m_useReverseAPI | ||||
|             << "m_reverseAPIAddress:" << settings.m_reverseAPIAddress | ||||
|             << "m_reverseAPIChannelIndex:" << settings.m_reverseAPIChannelIndex | ||||
|             << "m_reverseAPIDeviceIndex:" << settings.m_reverseAPIDeviceIndex | ||||
|             << "m_reverseAPIPort:" << settings.m_reverseAPIPort | ||||
|             << "force:" << force; | ||||
| 
 | ||||
|     QList<QString> reverseAPIKeys; | ||||
| 
 | ||||
|     if ((m_settings.m_log2Interp != settings.m_log2Interp) || force) { | ||||
|         reverseAPIKeys.append("log2Interp"); | ||||
|     } | ||||
|     if ((m_settings.m_filterChainHash != settings.m_filterChainHash) || force) { | ||||
|         reverseAPIKeys.append("filterChainHash"); | ||||
|     } | ||||
|     if ((m_settings.m_dataAddress != settings.m_dataAddress) || force) { | ||||
|         reverseAPIKeys.append("dataAddress"); | ||||
|     } | ||||
| 
 | ||||
|     if ((m_settings.m_dataPort != settings.m_dataPort) || force) { | ||||
|         reverseAPIKeys.append("dataPort"); | ||||
|     } | ||||
| 
 | ||||
|     if ((m_settings.m_log2Interp != settings.m_log2Interp) | ||||
|      || (m_settings.m_filterChainHash != settings.m_filterChainHash) || force) { | ||||
|         calculateFrequencyOffset(settings.m_log2Interp, settings.m_filterChainHash); | ||||
|     } | ||||
| 
 | ||||
|     if (m_settings.m_streamIndex != settings.m_streamIndex) | ||||
|     { | ||||
|         if (m_deviceAPI->getSampleMIMO()) // change of stream is possible for MIMO devices only
 | ||||
| @ -214,6 +252,23 @@ void RemoteSource::applySettings(const RemoteSourceSettings& settings, bool forc | ||||
|     m_settings = settings; | ||||
| } | ||||
| 
 | ||||
| void RemoteSource::validateFilterChainHash(RemoteSourceSettings& settings) | ||||
| { | ||||
|     unsigned int s = 1; | ||||
| 
 | ||||
|     for (unsigned int i = 0; i < settings.m_log2Interp; i++) { | ||||
|         s *= 3; | ||||
|     } | ||||
| 
 | ||||
|     settings.m_filterChainHash = settings.m_filterChainHash >= s ? s-1 : settings.m_filterChainHash; | ||||
| } | ||||
| 
 | ||||
| void RemoteSource::calculateFrequencyOffset(uint32_t log2Interp, uint32_t filterChainHash) | ||||
| { | ||||
|     double shiftFactor = HBFilterChainConverter::getShiftFactor(log2Interp, filterChainHash); | ||||
|     m_frequencyOffset = m_basebandSampleRate * shiftFactor; | ||||
| } | ||||
| 
 | ||||
| int RemoteSource::webapiSettingsGet( | ||||
|         SWGSDRangel::SWGChannelSettings& response, | ||||
|         QString& errorMessage) | ||||
| @ -274,6 +329,12 @@ void RemoteSource::webapiUpdateChannelSettings( | ||||
|     if (channelSettingsKeys.contains("title")) { | ||||
|         settings.m_title = *response.getRemoteSourceSettings()->getTitle(); | ||||
|     } | ||||
|     if (channelSettingsKeys.contains("log2Interp")) { | ||||
|         settings.m_log2Interp = response.getRemoteSourceSettings()->getLog2Interp(); | ||||
|     } | ||||
|     if (channelSettingsKeys.contains("filterChainHash")) { | ||||
|         settings.m_filterChainHash = response.getRemoteSourceSettings()->getFilterChainHash(); | ||||
|     } | ||||
|     if (channelSettingsKeys.contains("streamIndex")) { | ||||
|         settings.m_streamIndex = response.getRemoteSourceSettings()->getStreamIndex(); | ||||
|     } | ||||
| @ -325,6 +386,8 @@ void RemoteSource::webapiFormatChannelSettings(SWGSDRangel::SWGChannelSettings& | ||||
|         response.getRemoteSourceSettings()->setTitle(new QString(settings.m_title)); | ||||
|     } | ||||
| 
 | ||||
|     response.getRemoteSourceSettings()->setLog2Interp(settings.m_log2Interp); | ||||
|     response.getRemoteSourceSettings()->setFilterChainHash(settings.m_filterChainHash); | ||||
|     response.getRemoteSourceSettings()->setUseReverseApi(settings.m_useReverseAPI ? 1 : 0); | ||||
| 
 | ||||
|     if (response.getRemoteSourceSettings()->getReverseApiAddress()) { | ||||
| @ -367,8 +430,9 @@ void RemoteSource::webapiFormatChannelReport(SWGSDRangel::SWGChannelReport& resp | ||||
|     response.getRemoteSourceReport()->setUncorrectableErrorsCount(m_basebandSource->getNbUncorrectableErrors()); | ||||
|     response.getRemoteSourceReport()->setNbOriginalBlocks(currentMeta.m_nbOriginalBlocks); | ||||
|     response.getRemoteSourceReport()->setNbFecBlocks(currentMeta.m_nbFECBlocks); | ||||
|     response.getRemoteSourceReport()->setCenterFreq(currentMeta.m_centerFrequency); | ||||
|     response.getRemoteSourceReport()->setSampleRate(currentMeta.m_sampleRate); | ||||
|     response.getRemoteSourceReport()->setCenterFreq(m_frequencyOffset); | ||||
|     double channelSampleRate = ((double) m_basebandSampleRate) / (1<<m_settings.m_log2Interp); | ||||
|     response.getRemoteSourceReport()->setSampleRate(channelSampleRate); | ||||
|     response.getRemoteSourceReport()->setDeviceCenterFreq(m_deviceAPI->getSampleSink()->getCenterFrequency()); | ||||
|     response.getRemoteSourceReport()->setDeviceSampleRate(m_deviceAPI->getSampleSink()->getSampleRate()); | ||||
| } | ||||
| @ -445,6 +509,12 @@ void RemoteSource::webapiFormatChannelSettings( | ||||
|     if (channelSettingsKeys.contains("rgbColor") || force) { | ||||
|         swgRemoteSourceSettings->setRgbColor(settings.m_rgbColor); | ||||
|     } | ||||
|     if (channelSettingsKeys.contains("log2Interp") || force) { | ||||
|         swgRemoteSourceSettings->setLog2Interp(settings.m_log2Interp); | ||||
|     } | ||||
|     if (channelSettingsKeys.contains("filterChainHash") || force) { | ||||
|         swgRemoteSourceSettings->setFilterChainHash(settings.m_filterChainHash); | ||||
|     } | ||||
|     if (channelSettingsKeys.contains("title") || force) { | ||||
|         swgRemoteSourceSettings->setTitle(new QString(settings.m_title)); | ||||
|     } | ||||
|  | ||||
| @ -154,6 +154,27 @@ public: | ||||
|         { } | ||||
|     }; | ||||
| 
 | ||||
| 
 | ||||
|     class MsgBasebandSampleRateNotification : public Message { | ||||
|         MESSAGE_CLASS_DECLARATION | ||||
| 
 | ||||
|     public: | ||||
|         static MsgBasebandSampleRateNotification* create(int sampleRate) { | ||||
|             return new MsgBasebandSampleRateNotification(sampleRate); | ||||
|         } | ||||
| 
 | ||||
|         int getBasebandSampleRate() const { return m_sampleRate; } | ||||
| 
 | ||||
|     private: | ||||
| 
 | ||||
|         MsgBasebandSampleRateNotification(int sampleRate) : | ||||
|             Message(), | ||||
|             m_sampleRate(sampleRate) | ||||
|         { } | ||||
| 
 | ||||
|         int m_sampleRate; | ||||
|     }; | ||||
| 
 | ||||
|     RemoteSource(DeviceAPI *deviceAPI); | ||||
|     virtual ~RemoteSource(); | ||||
| 
 | ||||
| @ -218,7 +239,13 @@ private: | ||||
|     QNetworkAccessManager *m_networkManager; | ||||
|     QNetworkRequest m_networkRequest; | ||||
| 
 | ||||
|     uint64_t m_centerFrequency; | ||||
|     int64_t m_frequencyOffset; | ||||
|     uint32_t m_basebandSampleRate; | ||||
| 
 | ||||
|     void applySettings(const RemoteSourceSettings& settings, bool force = false); | ||||
|     static void validateFilterChainHash(RemoteSourceSettings& settings); | ||||
|     void calculateFrequencyOffset(uint32_t log2Interp, uint32_t filterChainHash); | ||||
|     void webapiFormatChannelReport(SWGSDRangel::SWGChannelReport& response); | ||||
|     void webapiReverseSendSettings(QList<QString>& channelSettingsKeys, const RemoteSourceSettings& settings, bool force); | ||||
|     void sendChannelSettings( | ||||
|  | ||||
| @ -164,15 +164,23 @@ bool RemoteSourceBaseband::handleMessage(const Message& cmd) | ||||
| void RemoteSourceBaseband::applySettings(const RemoteSourceSettings& settings, bool force) | ||||
| { | ||||
|     qDebug() << "RemoteSourceBaseband::applySettings:" | ||||
|             << " m_dataAddress: " << settings.m_dataAddress | ||||
|             << " m_dataPort: " << settings.m_dataPort | ||||
|             << " force: " << force; | ||||
|         << "m_log2Interp:" << settings.m_log2Interp | ||||
|         << "m_filterChainHash:" << settings.m_filterChainHash | ||||
|         << "m_dataAddress:" << settings.m_dataAddress | ||||
|         << "m_dataPort:" << settings.m_dataPort | ||||
|         << "force:" << force; | ||||
| 
 | ||||
|     if ((settings.m_dataAddress != m_settings.m_dataAddress) | ||||
|      || (settings.m_dataPort != m_settings.m_dataPort) || force) { | ||||
|         m_source.dataBind(settings.m_dataAddress, settings.m_dataPort); | ||||
|     } | ||||
| 
 | ||||
|     if ((m_settings.m_filterChainHash != settings.m_filterChainHash) | ||||
|      || (m_settings.m_log2Interp != settings.m_log2Interp) || force) | ||||
|     { | ||||
|         m_channelizer->setInterpolation(settings.m_log2Interp, settings.m_filterChainHash); | ||||
|     } | ||||
| 
 | ||||
|     m_settings = settings; | ||||
| } | ||||
| 
 | ||||
| @ -184,4 +192,4 @@ int RemoteSourceBaseband::getChannelSampleRate() const | ||||
| void RemoteSourceBaseband::newRemoteSampleRate(unsigned int sampleRate) | ||||
| { | ||||
|     m_channelizer->setChannelization(sampleRate, 0); // Adjust channelizer to match remote sample rate
 | ||||
| } | ||||
| } | ||||
|  | ||||
| @ -19,6 +19,7 @@ | ||||
| 
 | ||||
| #include "device/deviceapi.h" | ||||
| #include "device/deviceuiset.h" | ||||
| #include "dsp/hbfilterchainconverter.h" | ||||
| #include "gui/basicchannelsettingsdialog.h" | ||||
| #include "gui/devicestreamselectiondialog.h" | ||||
| #include "mainwindow.h" | ||||
| @ -65,7 +66,14 @@ bool RemoteSourceGUI::deserialize(const QByteArray& data) | ||||
| 
 | ||||
| bool RemoteSourceGUI::handleMessage(const Message& message) | ||||
| { | ||||
|     if (RemoteSource::MsgConfigureRemoteSource::match(message)) | ||||
|     if (RemoteSource::MsgBasebandSampleRateNotification::match(message)) | ||||
|     { | ||||
|         RemoteSource::MsgBasebandSampleRateNotification& notif = (RemoteSource::MsgBasebandSampleRateNotification&) message; | ||||
|         m_basebandSampleRate = notif.getBasebandSampleRate(); | ||||
|         displayRateAndShift(); | ||||
|         return true; | ||||
|     } | ||||
|     else if (RemoteSource::MsgConfigureRemoteSource::match(message)) | ||||
|     { | ||||
|         const RemoteSource::MsgConfigureRemoteSource& cfg = (RemoteSource::MsgConfigureRemoteSource&) message; | ||||
|         m_settings = cfg.getSettings(); | ||||
| @ -149,6 +157,8 @@ RemoteSourceGUI::RemoteSourceGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, | ||||
|         m_pluginAPI(pluginAPI), | ||||
|         m_deviceUISet(deviceUISet), | ||||
|         m_remoteSampleRate(48000), | ||||
|         m_basebandSampleRate(48000), | ||||
|         m_shiftFrequencyFactor(0.0), | ||||
|         m_countUnrecoverable(0), | ||||
|         m_countRecovered(0), | ||||
|         m_lastCountUnrecoverable(0), | ||||
| @ -189,6 +199,8 @@ RemoteSourceGUI::RemoteSourceGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, | ||||
|     m_time.start(); | ||||
| 
 | ||||
|     displaySettings(); | ||||
|     displayPosition(); | ||||
|     displayRateAndShift(); | ||||
|     applySettings(true); | ||||
| } | ||||
| 
 | ||||
| @ -233,6 +245,25 @@ void RemoteSourceGUI::displaySettings() | ||||
|     blockApplySettings(false); | ||||
| } | ||||
| 
 | ||||
| void RemoteSourceGUI::displayRateAndShift() | ||||
| { | ||||
|     int shift = m_shiftFrequencyFactor * m_basebandSampleRate; | ||||
|     double channelSampleRate = ((double) m_basebandSampleRate) / (1<<m_settings.m_log2Interp); | ||||
|     QLocale loc; | ||||
|     ui->offsetFrequencyText->setText(tr("%1 Hz").arg(loc.toString(shift))); | ||||
|     ui->channelRateText->setText(tr("%1k").arg(QString::number(channelSampleRate / 1000.0, 'g', 5))); | ||||
|     m_channelMarker.setCenterFrequency(shift); | ||||
|     m_channelMarker.setBandwidth(channelSampleRate); | ||||
| } | ||||
| 
 | ||||
| void RemoteSourceGUI::displayPosition() | ||||
| { | ||||
|     ui->filterChainIndex->setText(tr("%1").arg(m_settings.m_filterChainHash)); | ||||
|     QString s; | ||||
|     HBFilterChainConverter::convertToString(m_settings.m_log2Interp, m_settings.m_filterChainHash, s); | ||||
|     ui->filterChainText->setText(s); | ||||
| } | ||||
| 
 | ||||
| void RemoteSourceGUI::displayStreamIndex() | ||||
| { | ||||
|     if (m_deviceUISet->m_deviceMIMOEngine) { | ||||
| @ -319,6 +350,18 @@ void RemoteSourceGUI::onMenuDialogCalled(const QPoint &p) | ||||
|     resetContextMenuType(); | ||||
| } | ||||
| 
 | ||||
| void RemoteSourceGUI::on_interpolationFactor_currentIndexChanged(int index) | ||||
| { | ||||
|     m_settings.m_log2Interp = index; | ||||
|     applyInterpolation(); | ||||
| } | ||||
| 
 | ||||
| void RemoteSourceGUI::on_position_valueChanged(int value) | ||||
| { | ||||
|     m_settings.m_filterChainHash = value; | ||||
|     applyPosition(); | ||||
| } | ||||
| 
 | ||||
| void RemoteSourceGUI::on_dataAddress_returnPressed() | ||||
| { | ||||
|     m_settings.m_dataAddress = ui->dataAddress->text(); | ||||
| @ -364,6 +407,31 @@ void RemoteSourceGUI::on_eventCountsReset_clicked(bool checked) | ||||
|     displayEventTimer(); | ||||
| } | ||||
| 
 | ||||
| void RemoteSourceGUI::applyInterpolation() | ||||
| { | ||||
|     uint32_t maxHash = 1; | ||||
| 
 | ||||
|     for (uint32_t i = 0; i < m_settings.m_log2Interp; i++) { | ||||
|         maxHash *= 3; | ||||
|     } | ||||
| 
 | ||||
|     ui->position->setMaximum(maxHash-1); | ||||
|     ui->position->setValue(m_settings.m_filterChainHash); | ||||
|     m_settings.m_filterChainHash = ui->position->value(); | ||||
|     applyPosition(); | ||||
| } | ||||
| 
 | ||||
| void RemoteSourceGUI::applyPosition() | ||||
| { | ||||
|     ui->filterChainIndex->setText(tr("%1").arg(m_settings.m_filterChainHash)); | ||||
|     QString s; | ||||
|     m_shiftFrequencyFactor = HBFilterChainConverter::convertToString(m_settings.m_log2Interp, m_settings.m_filterChainHash, s); | ||||
|     ui->filterChainText->setText(s); | ||||
| 
 | ||||
|     displayRateAndShift(); | ||||
|     applySettings(); | ||||
| } | ||||
| 
 | ||||
| void RemoteSourceGUI::displayEventCounts() | ||||
| { | ||||
|     QString nstr = QString("%1").arg(m_countUnrecoverable, 3, 10, QChar('0')); | ||||
|  | ||||
| @ -57,7 +57,9 @@ private: | ||||
|     ChannelMarker m_channelMarker; | ||||
|     RemoteSourceSettings m_settings; | ||||
|     int m_remoteSampleRate; | ||||
|     int m_basebandSampleRate; | ||||
|     bool m_doApplySettings; | ||||
|     double m_shiftFrequencyFactor; //!< Channel frequency shift factor
 | ||||
| 
 | ||||
|     RemoteSource* m_remoteSrc; | ||||
|     MessageQueue m_inputMessageQueue; | ||||
| @ -78,6 +80,8 @@ private: | ||||
|     void blockApplySettings(bool block); | ||||
|     void applySettings(bool force = false); | ||||
|     void displaySettings(); | ||||
|     void displayRateAndShift(); | ||||
|     void displayPosition(); | ||||
|     void displayStreamIndex(); | ||||
|     bool handleMessage(const Message& message); | ||||
| 
 | ||||
| @ -88,8 +92,13 @@ private: | ||||
|     void displayEventStatus(int recoverableCount, int unrecoverableCount); | ||||
|     void displayEventTimer(); | ||||
| 
 | ||||
|     void applyInterpolation(); | ||||
|     void applyPosition(); | ||||
| 
 | ||||
| private slots: | ||||
|     void handleSourceMessages(); | ||||
|     void on_interpolationFactor_currentIndexChanged(int index); | ||||
|     void on_position_valueChanged(int value); | ||||
|     void on_dataAddress_returnPressed(); | ||||
|     void on_dataPort_returnPressed(); | ||||
|     void on_dataApplyButton_clicked(bool checked); | ||||
|  | ||||
| @ -7,7 +7,7 @@ | ||||
|     <x>0</x> | ||||
|     <y>0</y> | ||||
|     <width>320</width> | ||||
|     <height>140</height> | ||||
|     <height>221</height> | ||||
|    </rect> | ||||
|   </property> | ||||
|   <property name="sizePolicy"> | ||||
| @ -43,7 +43,7 @@ | ||||
|      <x>10</x> | ||||
|      <y>10</y> | ||||
|      <width>301</width> | ||||
|      <height>121</height> | ||||
|      <height>191</height> | ||||
|     </rect> | ||||
|    </property> | ||||
|    <property name="windowTitle"> | ||||
| @ -156,6 +156,188 @@ | ||||
|       </item> | ||||
|      </layout> | ||||
|     </item> | ||||
|     <item> | ||||
|      <layout class="QVBoxLayout" name="decimationLayer"> | ||||
|       <property name="spacing"> | ||||
|        <number>3</number> | ||||
|       </property> | ||||
|       <item> | ||||
|        <layout class="QHBoxLayout" name="decimationStageLayer"> | ||||
|         <item> | ||||
|          <widget class="QLabel" name="interpolationLabel"> | ||||
|           <property name="text"> | ||||
|            <string>Int</string> | ||||
|           </property> | ||||
|          </widget> | ||||
|         </item> | ||||
|         <item> | ||||
|          <widget class="QComboBox" name="interpolationFactor"> | ||||
|           <property name="maximumSize"> | ||||
|            <size> | ||||
|             <width>55</width> | ||||
|             <height>16777215</height> | ||||
|            </size> | ||||
|           </property> | ||||
|           <property name="toolTip"> | ||||
|            <string>Decimation factor</string> | ||||
|           </property> | ||||
|           <item> | ||||
|            <property name="text"> | ||||
|             <string>1</string> | ||||
|            </property> | ||||
|           </item> | ||||
|           <item> | ||||
|            <property name="text"> | ||||
|             <string>2</string> | ||||
|            </property> | ||||
|           </item> | ||||
|           <item> | ||||
|            <property name="text"> | ||||
|             <string>4</string> | ||||
|            </property> | ||||
|           </item> | ||||
|           <item> | ||||
|            <property name="text"> | ||||
|             <string>8</string> | ||||
|            </property> | ||||
|           </item> | ||||
|           <item> | ||||
|            <property name="text"> | ||||
|             <string>16</string> | ||||
|            </property> | ||||
|           </item> | ||||
|           <item> | ||||
|            <property name="text"> | ||||
|             <string>32</string> | ||||
|            </property> | ||||
|           </item> | ||||
|           <item> | ||||
|            <property name="text"> | ||||
|             <string>64</string> | ||||
|            </property> | ||||
|           </item> | ||||
|          </widget> | ||||
|         </item> | ||||
|         <item> | ||||
|          <widget class="QLabel" name="channelRateText"> | ||||
|           <property name="minimumSize"> | ||||
|            <size> | ||||
|             <width>50</width> | ||||
|             <height>0</height> | ||||
|            </size> | ||||
|           </property> | ||||
|           <property name="toolTip"> | ||||
|            <string>Effective channel rate (kS/s)</string> | ||||
|           </property> | ||||
|           <property name="text"> | ||||
|            <string>0000k</string> | ||||
|           </property> | ||||
|           <property name="alignment"> | ||||
|            <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> | ||||
|           </property> | ||||
|          </widget> | ||||
|         </item> | ||||
|         <item> | ||||
|          <widget class="QLabel" name="filterChainText"> | ||||
|           <property name="minimumSize"> | ||||
|            <size> | ||||
|             <width>50</width> | ||||
|             <height>0</height> | ||||
|            </size> | ||||
|           </property> | ||||
|           <property name="toolTip"> | ||||
|            <string>Filter chain stages left to right (L: low, C: center, H: high) </string> | ||||
|           </property> | ||||
|           <property name="text"> | ||||
|            <string>LLLLLL</string> | ||||
|           </property> | ||||
|          </widget> | ||||
|         </item> | ||||
|         <item> | ||||
|          <spacer name="horizontalSpacer_4"> | ||||
|           <property name="orientation"> | ||||
|            <enum>Qt::Horizontal</enum> | ||||
|           </property> | ||||
|           <property name="sizeHint" stdset="0"> | ||||
|            <size> | ||||
|             <width>40</width> | ||||
|             <height>20</height> | ||||
|            </size> | ||||
|           </property> | ||||
|          </spacer> | ||||
|         </item> | ||||
|         <item> | ||||
|          <widget class="QLabel" name="offsetFrequencyText"> | ||||
|           <property name="minimumSize"> | ||||
|            <size> | ||||
|             <width>85</width> | ||||
|             <height>0</height> | ||||
|            </size> | ||||
|           </property> | ||||
|           <property name="toolTip"> | ||||
|            <string>Offset frequency with thousands separator (Hz)</string> | ||||
|           </property> | ||||
|           <property name="text"> | ||||
|            <string>-9,999,999 Hz</string> | ||||
|           </property> | ||||
|           <property name="alignment"> | ||||
|            <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> | ||||
|           </property> | ||||
|          </widget> | ||||
|         </item> | ||||
|        </layout> | ||||
|       </item> | ||||
|       <item> | ||||
|        <layout class="QHBoxLayout" name="decimationShiftLayer"> | ||||
|         <property name="rightMargin"> | ||||
|          <number>10</number> | ||||
|         </property> | ||||
|         <item> | ||||
|          <widget class="QLabel" name="positionLabel"> | ||||
|           <property name="text"> | ||||
|            <string>Pos</string> | ||||
|           </property> | ||||
|          </widget> | ||||
|         </item> | ||||
|         <item> | ||||
|          <widget class="QSlider" name="position"> | ||||
|           <property name="toolTip"> | ||||
|            <string>Center frequency position</string> | ||||
|           </property> | ||||
|           <property name="maximum"> | ||||
|            <number>2</number> | ||||
|           </property> | ||||
|           <property name="pageStep"> | ||||
|            <number>1</number> | ||||
|           </property> | ||||
|           <property name="orientation"> | ||||
|            <enum>Qt::Horizontal</enum> | ||||
|           </property> | ||||
|          </widget> | ||||
|         </item> | ||||
|         <item> | ||||
|          <widget class="QLabel" name="filterChainIndex"> | ||||
|           <property name="minimumSize"> | ||||
|            <size> | ||||
|             <width>24</width> | ||||
|             <height>0</height> | ||||
|            </size> | ||||
|           </property> | ||||
|           <property name="toolTip"> | ||||
|            <string>Filter chain hash code</string> | ||||
|           </property> | ||||
|           <property name="text"> | ||||
|            <string>000</string> | ||||
|           </property> | ||||
|           <property name="alignment"> | ||||
|            <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> | ||||
|           </property> | ||||
|          </widget> | ||||
|         </item> | ||||
|        </layout> | ||||
|       </item> | ||||
|      </layout> | ||||
|     </item> | ||||
|     <item> | ||||
|      <layout class="QHBoxLayout" name="nominalValuesLayout"> | ||||
|       <item> | ||||
|  | ||||
| @ -34,6 +34,8 @@ void RemoteSourceSettings::resetToDefaults() | ||||
|     m_dataPort = 9090; | ||||
|     m_rgbColor = QColor(140, 4, 4).rgb(); | ||||
|     m_title = "Remote source"; | ||||
|     m_log2Interp = 0; | ||||
|     m_filterChainHash = 0; | ||||
|     m_channelMarker = nullptr; | ||||
|     m_streamIndex = 0; | ||||
|     m_useReverseAPI = false; | ||||
| @ -57,6 +59,8 @@ QByteArray RemoteSourceSettings::serialize() const | ||||
|     s.writeU32(9, m_reverseAPIChannelIndex); | ||||
|     s.writeS32(10, m_streamIndex); | ||||
|     s.writeBlob(11, m_rollupState); | ||||
|     s.writeU32(12, m_log2Interp); | ||||
|     s.writeU32(13, m_filterChainHash); | ||||
| 
 | ||||
|     return s.final(); | ||||
| } | ||||
| @ -103,6 +107,8 @@ bool RemoteSourceSettings::deserialize(const QByteArray& data) | ||||
|         m_reverseAPIChannelIndex = tmp > 99 ? 99 : tmp; | ||||
|         d.readS32(10, &m_streamIndex, 0); | ||||
|         d.readBlob(11, &m_rollupState); | ||||
|         d.readU32(13, &m_filterChainHash, 0); | ||||
|         d.readS32(14, &m_streamIndex, 0); | ||||
| 
 | ||||
|         return true; | ||||
|     } | ||||
|  | ||||
| @ -29,6 +29,8 @@ struct RemoteSourceSettings | ||||
|     uint16_t m_dataPort;    //!< Listening data port
 | ||||
|     quint32 m_rgbColor; | ||||
|     QString m_title; | ||||
|     uint32_t m_log2Interp; | ||||
|     uint32_t m_filterChainHash; | ||||
|     int m_streamIndex; | ||||
|     bool m_useReverseAPI; | ||||
|     QString m_reverseAPIAddress; | ||||
|  | ||||
| @ -46,8 +46,6 @@ MESSAGE_CLASS_DEFINITION(RemoteOutput::MsgReportRemoteData, Message) | ||||
| MESSAGE_CLASS_DEFINITION(RemoteOutput::MsgReportRemoteFixedData, Message) | ||||
| MESSAGE_CLASS_DEFINITION(RemoteOutput::MsgRequestFixedData, Message) | ||||
| 
 | ||||
| const uint32_t RemoteOutput::NbSamplesForRateCorrection = 5000000; | ||||
| 
 | ||||
| RemoteOutput::RemoteOutput(DeviceAPI *deviceAPI) : | ||||
|     m_deviceAPI(deviceAPI), | ||||
| 	m_settings(), | ||||
| @ -59,15 +57,7 @@ RemoteOutput::RemoteOutput(DeviceAPI *deviceAPI) : | ||||
| 	m_masterTimer(deviceAPI->getMasterTimer()), | ||||
| 	m_tickCount(0), | ||||
|     m_greaterTickCount(0), | ||||
|     m_tickMultiplier(1), | ||||
| 	m_lastRemoteSampleCount(0), | ||||
| 	m_lastSampleCount(0), | ||||
| 	m_lastRemoteTimestampRateCorrection(0), | ||||
| 	m_lastTimestampRateCorrection(0), | ||||
| 	m_lastQueueLength(-2), | ||||
| 	m_nbRemoteSamplesSinceRateCorrection(0), | ||||
| 	m_nbSamplesSinceRateCorrection(0), | ||||
| 	m_chunkSizeCorrection(0) | ||||
|     m_tickMultiplier(1) | ||||
| { | ||||
|     m_deviceAPI->setNbSinkStreams(1); | ||||
|     m_networkManager = new QNetworkAccessManager(); | ||||
| @ -102,14 +92,9 @@ bool RemoteOutput::start() | ||||
| 	m_remoteOutputWorker->connectTimer(m_masterTimer); | ||||
| 	startWorker(); | ||||
| 
 | ||||
| 	// restart auto rate correction
 | ||||
| 	m_lastRemoteTimestampRateCorrection = 0; | ||||
| 	m_lastTimestampRateCorrection = 0; | ||||
| 	m_lastQueueLength = -2; // set first value out of bounds
 | ||||
| 	m_chunkSizeCorrection = 0; | ||||
| 
 | ||||
| 	mutexLocker.unlock(); | ||||
| 	//applySettings(m_generalSettings, m_settings, true);
 | ||||
|     applySampleRate(); | ||||
| 
 | ||||
| 	qDebug("RemoteOutput::start: started"); | ||||
| 
 | ||||
| 	return true; | ||||
| @ -337,9 +322,9 @@ void RemoteOutput::applySampleRate() | ||||
|         m_remoteOutputWorker->setSamplerate(m_sampleRate); | ||||
|     } | ||||
| 
 | ||||
|     m_tickMultiplier = (21*NbSamplesForRateCorrection) / (2*m_sampleRate); // two times per sample filling period plus small extension
 | ||||
|     m_tickMultiplier /= 20; // greter tick (one per second)
 | ||||
|     m_tickMultiplier = m_tickMultiplier < 1 ? 1 : m_tickMultiplier; // not below 1 second
 | ||||
|     m_tickMultiplier = 480000 / m_sampleRate; | ||||
|     m_tickMultiplier = m_tickMultiplier < 1 ? 1 : m_tickMultiplier > 10 ? 10 : m_tickMultiplier; | ||||
|     m_greaterTickCount = 0; | ||||
| 
 | ||||
|     DSPSignalNotification *notif = new DSPSignalNotification(m_sampleRate, m_centerFrequency); | ||||
|     m_deviceAPI->getDeviceEngineInputMessageQueue()->push(notif); | ||||
| @ -548,7 +533,7 @@ void RemoteOutput::analyzeApiReply(const QJsonObject& jsonObject, const QString& | ||||
|     { | ||||
|         MsgReportRemoteData::RemoteData msgRemoteData; | ||||
|         QJsonObject report = jsonObject["RemoteSourceReport"].toObject(); | ||||
|         uint64_t centerFrequency = report["deviceCenterFreq"].toInt(); | ||||
|         uint64_t centerFrequency = report["deviceCenterFreq"].toInt() + report["centerFreq"].toInt(); | ||||
| 
 | ||||
|         if (centerFrequency != m_centerFrequency) | ||||
|         { | ||||
| @ -556,7 +541,7 @@ void RemoteOutput::analyzeApiReply(const QJsonObject& jsonObject, const QString& | ||||
|             applyCenterFrequency(); | ||||
|         } | ||||
| 
 | ||||
|         int remoteRate = report["deviceSampleRate"].toInt(); | ||||
|         int remoteRate = report["sampleRate"].toInt(); | ||||
| 
 | ||||
|         if (remoteRate != m_sampleRate) | ||||
|         { | ||||
| @ -572,7 +557,6 @@ void RemoteOutput::analyzeApiReply(const QJsonObject& jsonObject, const QString& | ||||
|         msgRemoteData.m_queueSize = queueSize; | ||||
|         int queueLength = report["queueLength"].toInt(); | ||||
|         msgRemoteData.m_queueLength = queueLength; | ||||
|         int queueLengthPercent = (queueLength*100)/queueSize; | ||||
|         uint64_t remoteTimestampUs = report["tvSec"].toInt()*1000000ULL + report["tvUSec"].toInt(); | ||||
|         msgRemoteData.m_timestampUs = remoteTimestampUs; | ||||
|         int intRemoteSampleCount = report["samplesCount"].toInt(); | ||||
| @ -593,62 +577,11 @@ void RemoteOutput::analyzeApiReply(const QJsonObject& jsonObject, const QString& | ||||
|             return; | ||||
|         } | ||||
| 
 | ||||
|         if (++m_greaterTickCount != m_tickMultiplier) { | ||||
|             return; | ||||
|         } | ||||
| 
 | ||||
|         uint32_t remoteSampleCountDelta; | ||||
| 
 | ||||
|         if (remoteSampleCount < m_lastRemoteSampleCount) { | ||||
|             remoteSampleCountDelta = (0xFFFFFFFFU - m_lastRemoteSampleCount) + remoteSampleCount + 1; | ||||
|         } else { | ||||
|             remoteSampleCountDelta = remoteSampleCount - m_lastRemoteSampleCount; | ||||
|         } | ||||
| 
 | ||||
|         uint32_t sampleCountDelta, sampleCount; | ||||
|         uint64_t timestampUs; | ||||
|         sampleCount = m_remoteOutputWorker->getSamplesCount(timestampUs); | ||||
| 
 | ||||
|         if (sampleCount < m_lastSampleCount) { | ||||
|             sampleCountDelta = (0xFFFFFFFFU - m_lastSampleCount) + sampleCount + 1; | ||||
|         } else { | ||||
|             sampleCountDelta = sampleCount - m_lastSampleCount; | ||||
|         } | ||||
| 
 | ||||
|         // on initial state wait for queue stabilization
 | ||||
|         if ((m_lastRemoteTimestampRateCorrection == 0) && (queueLength >= m_lastQueueLength-1) && (queueLength <= m_lastQueueLength+1)) | ||||
|         if (++m_greaterTickCount == m_tickMultiplier) | ||||
|         { | ||||
|             m_lastRemoteTimestampRateCorrection = remoteTimestampUs; | ||||
|             m_lastTimestampRateCorrection = timestampUs; | ||||
|             m_nbRemoteSamplesSinceRateCorrection = 0; | ||||
|             m_nbSamplesSinceRateCorrection = 0; | ||||
|             queueLengthCompensation(m_sampleRate, queueLength, queueSize); | ||||
|             m_greaterTickCount = 0; | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|             m_nbRemoteSamplesSinceRateCorrection += remoteSampleCountDelta; | ||||
|             m_nbSamplesSinceRateCorrection += sampleCountDelta; | ||||
| 
 | ||||
|             qDebug("RemoteOutput::analyzeApiReply: queueLengthPercent: %d m_nbSamplesSinceRateCorrection: %u", | ||||
|                 queueLengthPercent, | ||||
|                 m_nbRemoteSamplesSinceRateCorrection); | ||||
| 
 | ||||
|             if (m_nbRemoteSamplesSinceRateCorrection > NbSamplesForRateCorrection) | ||||
|             { | ||||
|                 sampleRateCorrection(remoteTimestampUs - m_lastRemoteTimestampRateCorrection, | ||||
|                         timestampUs - m_lastTimestampRateCorrection, | ||||
|                         m_nbRemoteSamplesSinceRateCorrection, | ||||
|                         m_nbSamplesSinceRateCorrection); | ||||
|                 m_lastRemoteTimestampRateCorrection = remoteTimestampUs; | ||||
|                 m_lastTimestampRateCorrection = timestampUs; | ||||
|                 m_nbRemoteSamplesSinceRateCorrection = 0; | ||||
|                 m_nbSamplesSinceRateCorrection = 0; | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         m_lastRemoteSampleCount = remoteSampleCount; | ||||
|         m_lastSampleCount = sampleCount; | ||||
|         m_lastQueueLength = queueLength; | ||||
|         m_greaterTickCount = 0; | ||||
|     } | ||||
|     else if (jsonObject.contains("remoteOutputSettings")) | ||||
|     { | ||||
| @ -685,16 +618,18 @@ void RemoteOutput::analyzeApiReply(const QJsonObject& jsonObject, const QString& | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void RemoteOutput::sampleRateCorrection(double remoteTimeDeltaUs, double timeDeltaUs, uint32_t remoteSampleCount, uint32_t sampleCount) | ||||
| void RemoteOutput::queueLengthCompensation( | ||||
|     int nominalSR, | ||||
|     int queueLength, | ||||
|     int queueSize | ||||
| ) | ||||
| { | ||||
|     double deltaSR = (remoteSampleCount/remoteTimeDeltaUs) - (sampleCount/timeDeltaUs); | ||||
|     double chunkCorr = 50000 * deltaSR; // for 50ms chunk intervals (50000us)
 | ||||
|     m_chunkSizeCorrection += roundf(chunkCorr); | ||||
| 
 | ||||
|     qDebug("RemoteOutput::sampleRateCorrection: remote: %u / %f us local: %u / %f us corr: %d (%f) samples", | ||||
|         remoteSampleCount, remoteTimeDeltaUs, sampleCount, timeDeltaUs, m_chunkSizeCorrection, chunkCorr); | ||||
| 
 | ||||
|     MsgConfigureRemoteOutputChunkCorrection* message = MsgConfigureRemoteOutputChunkCorrection::create(m_chunkSizeCorrection); | ||||
|     int deltaQueueBlocks = (queueSize/2) - queueLength; | ||||
|     int blockMultiplier = nominalSR / 4000; | ||||
|     blockMultiplier = blockMultiplier < 12 ? 12 : blockMultiplier; | ||||
|     int corr = deltaQueueBlocks * blockMultiplier; | ||||
|     qDebug("RemoteOutput::queueLengthCompensation: deltaQueueBlocks: %d corr: %d", deltaQueueBlocks, corr); | ||||
|     MsgConfigureRemoteOutputChunkCorrection* message = MsgConfigureRemoteOutputChunkCorrection::create(corr); | ||||
|     getInputMessageQueue()->push(message); | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -288,16 +288,6 @@ private: | ||||
|     QNetworkAccessManager *m_networkManager; | ||||
|     QNetworkRequest m_networkRequest; | ||||
| 
 | ||||
|     uint32_t m_lastRemoteSampleCount; | ||||
|     uint32_t m_lastSampleCount; | ||||
|     uint64_t m_lastRemoteTimestampRateCorrection; | ||||
|     uint64_t m_lastTimestampRateCorrection; | ||||
|     int m_lastQueueLength; | ||||
|     uint32_t m_nbRemoteSamplesSinceRateCorrection; | ||||
|     uint32_t m_nbSamplesSinceRateCorrection; | ||||
|     int m_chunkSizeCorrection; | ||||
|     static const uint32_t NbSamplesForRateCorrection; | ||||
| 
 | ||||
|     void startWorker(); | ||||
|     void stopWorker(); | ||||
| 	void applySettings(const RemoteOutputSettings& settings, bool force = false); | ||||
| @ -306,7 +296,11 @@ private: | ||||
|     void webapiFormatDeviceReport(SWGSDRangel::SWGDeviceReport& response); | ||||
| 
 | ||||
|     void analyzeApiReply(const QJsonObject& jsonObject, const QString& answer); | ||||
|     void sampleRateCorrection(double remoteTimeDeltaUs, double timeDeltaUs, uint32_t remoteSampleCount, uint32_t sampleCount); | ||||
|     void queueLengthCompensation( | ||||
|         int nominalSR, | ||||
|         int queueLength, | ||||
|         int queueSize | ||||
|     ); | ||||
|     void webapiReverseSendSettings(QList<QString>& deviceSettingsKeys, const RemoteOutputSettings& settings, bool force); | ||||
|     void webapiReverseSendStartStop(bool start); | ||||
| 
 | ||||
|  | ||||
| @ -91,13 +91,14 @@ void RemoteDataReadQueue::readSample(Sample& s, bool scaleForTx) | ||||
|             m_sampleIndex = 0; | ||||
|             convertDataToSample(s, m_blockIndex, m_sampleIndex, scaleForTx); | ||||
|             m_sampleIndex++; | ||||
|             m_sampleCount++; | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|             s = Sample{0, 0}; | ||||
|         } | ||||
| 
 | ||||
|         m_sampleCount++; | ||||
| 
 | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
|  | ||||
| @ -10004,6 +10004,12 @@ margin-bottom: 20px; | ||||
|     "title" : { | ||||
|       "type" : "string" | ||||
|     }, | ||||
|     "log2Interp" : { | ||||
|       "type" : "integer" | ||||
|     }, | ||||
|     "filterChainHash" : { | ||||
|       "type" : "integer" | ||||
|     }, | ||||
|     "streamIndex" : { | ||||
|       "type" : "integer", | ||||
|       "description" : "MIMO channel. Not relevant when connected to SI (single Rx)." | ||||
| @ -51597,7 +51603,7 @@ except ApiException as e: | ||||
|           </div> | ||||
|           <div id="generator"> | ||||
|             <div class="content"> | ||||
|               Generated 2021-12-12T19:10:03.240+01:00 | ||||
|               Generated 2021-12-12T22:32:39.234+01:00 | ||||
|             </div> | ||||
|           </div> | ||||
|       </div> | ||||
|  | ||||
| @ -11,6 +11,10 @@ RemoteSourceSettings: | ||||
|       type: integer | ||||
|     title: | ||||
|       type: string | ||||
|     log2Interp: | ||||
|       type: integer | ||||
|     filterChainHash: | ||||
|       type: integer | ||||
|     streamIndex: | ||||
|       description: MIMO channel. Not relevant when connected to SI (single Rx). | ||||
|       type: integer | ||||
|  | ||||
| @ -11,6 +11,10 @@ RemoteSourceSettings: | ||||
|       type: integer | ||||
|     title: | ||||
|       type: string | ||||
|     log2Interp: | ||||
|       type: integer | ||||
|     filterChainHash: | ||||
|       type: integer | ||||
|     streamIndex: | ||||
|       description: MIMO channel. Not relevant when connected to SI (single Rx). | ||||
|       type: integer | ||||
|  | ||||
| @ -10004,6 +10004,12 @@ margin-bottom: 20px; | ||||
|     "title" : { | ||||
|       "type" : "string" | ||||
|     }, | ||||
|     "log2Interp" : { | ||||
|       "type" : "integer" | ||||
|     }, | ||||
|     "filterChainHash" : { | ||||
|       "type" : "integer" | ||||
|     }, | ||||
|     "streamIndex" : { | ||||
|       "type" : "integer", | ||||
|       "description" : "MIMO channel. Not relevant when connected to SI (single Rx)." | ||||
| @ -51597,7 +51603,7 @@ except ApiException as e: | ||||
|           </div> | ||||
|           <div id="generator"> | ||||
|             <div class="content"> | ||||
|               Generated 2021-12-12T19:10:03.240+01:00 | ||||
|               Generated 2021-12-12T22:32:39.234+01:00 | ||||
|             </div> | ||||
|           </div> | ||||
|       </div> | ||||
|  | ||||
| @ -36,6 +36,10 @@ SWGRemoteSourceSettings::SWGRemoteSourceSettings() { | ||||
|     m_rgb_color_isSet = false; | ||||
|     title = nullptr; | ||||
|     m_title_isSet = false; | ||||
|     log2_interp = 0; | ||||
|     m_log2_interp_isSet = false; | ||||
|     filter_chain_hash = 0; | ||||
|     m_filter_chain_hash_isSet = false; | ||||
|     stream_index = 0; | ||||
|     m_stream_index_isSet = false; | ||||
|     use_reverse_api = 0; | ||||
| @ -66,6 +70,10 @@ SWGRemoteSourceSettings::init() { | ||||
|     m_rgb_color_isSet = false; | ||||
|     title = new QString(""); | ||||
|     m_title_isSet = false; | ||||
|     log2_interp = 0; | ||||
|     m_log2_interp_isSet = false; | ||||
|     filter_chain_hash = 0; | ||||
|     m_filter_chain_hash_isSet = false; | ||||
|     stream_index = 0; | ||||
|     m_stream_index_isSet = false; | ||||
|     use_reverse_api = 0; | ||||
| @ -94,6 +102,8 @@ SWGRemoteSourceSettings::cleanup() { | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
|     if(reverse_api_address != nullptr) {  | ||||
|         delete reverse_api_address; | ||||
|     } | ||||
| @ -124,6 +134,10 @@ SWGRemoteSourceSettings::fromJsonObject(QJsonObject &pJson) { | ||||
|      | ||||
|     ::SWGSDRangel::setValue(&title, pJson["title"], "QString", "QString"); | ||||
|      | ||||
|     ::SWGSDRangel::setValue(&log2_interp, pJson["log2Interp"], "qint32", ""); | ||||
|      | ||||
|     ::SWGSDRangel::setValue(&filter_chain_hash, pJson["filterChainHash"], "qint32", ""); | ||||
|      | ||||
|     ::SWGSDRangel::setValue(&stream_index, pJson["streamIndex"], "qint32", ""); | ||||
|      | ||||
|     ::SWGSDRangel::setValue(&use_reverse_api, pJson["useReverseAPI"], "qint32", ""); | ||||
| @ -166,6 +180,12 @@ SWGRemoteSourceSettings::asJsonObject() { | ||||
|     if(title != nullptr && *title != QString("")){ | ||||
|         toJsonValue(QString("title"), title, obj, QString("QString")); | ||||
|     } | ||||
|     if(m_log2_interp_isSet){ | ||||
|         obj->insert("log2Interp", QJsonValue(log2_interp)); | ||||
|     } | ||||
|     if(m_filter_chain_hash_isSet){ | ||||
|         obj->insert("filterChainHash", QJsonValue(filter_chain_hash)); | ||||
|     } | ||||
|     if(m_stream_index_isSet){ | ||||
|         obj->insert("streamIndex", QJsonValue(stream_index)); | ||||
|     } | ||||
| @ -231,6 +251,26 @@ SWGRemoteSourceSettings::setTitle(QString* title) { | ||||
|     this->m_title_isSet = true; | ||||
| } | ||||
| 
 | ||||
| qint32 | ||||
| SWGRemoteSourceSettings::getLog2Interp() { | ||||
|     return log2_interp; | ||||
| } | ||||
| void | ||||
| SWGRemoteSourceSettings::setLog2Interp(qint32 log2_interp) { | ||||
|     this->log2_interp = log2_interp; | ||||
|     this->m_log2_interp_isSet = true; | ||||
| } | ||||
| 
 | ||||
| qint32 | ||||
| SWGRemoteSourceSettings::getFilterChainHash() { | ||||
|     return filter_chain_hash; | ||||
| } | ||||
| void | ||||
| SWGRemoteSourceSettings::setFilterChainHash(qint32 filter_chain_hash) { | ||||
|     this->filter_chain_hash = filter_chain_hash; | ||||
|     this->m_filter_chain_hash_isSet = true; | ||||
| } | ||||
| 
 | ||||
| qint32 | ||||
| SWGRemoteSourceSettings::getStreamIndex() { | ||||
|     return stream_index; | ||||
| @ -318,6 +358,12 @@ SWGRemoteSourceSettings::isSet(){ | ||||
|         if(title && *title != QString("")){ | ||||
|             isObjectUpdated = true; break; | ||||
|         } | ||||
|         if(m_log2_interp_isSet){ | ||||
|             isObjectUpdated = true; break; | ||||
|         } | ||||
|         if(m_filter_chain_hash_isSet){ | ||||
|             isObjectUpdated = true; break; | ||||
|         } | ||||
|         if(m_stream_index_isSet){ | ||||
|             isObjectUpdated = true; break; | ||||
|         } | ||||
|  | ||||
| @ -55,6 +55,12 @@ public: | ||||
|     QString* getTitle(); | ||||
|     void setTitle(QString* title); | ||||
| 
 | ||||
|     qint32 getLog2Interp(); | ||||
|     void setLog2Interp(qint32 log2_interp); | ||||
| 
 | ||||
|     qint32 getFilterChainHash(); | ||||
|     void setFilterChainHash(qint32 filter_chain_hash); | ||||
| 
 | ||||
|     qint32 getStreamIndex(); | ||||
|     void setStreamIndex(qint32 stream_index); | ||||
| 
 | ||||
| @ -92,6 +98,12 @@ private: | ||||
|     QString* title; | ||||
|     bool m_title_isSet; | ||||
| 
 | ||||
|     qint32 log2_interp; | ||||
|     bool m_log2_interp_isSet; | ||||
| 
 | ||||
|     qint32 filter_chain_hash; | ||||
|     bool m_filter_chain_hash_isSet; | ||||
| 
 | ||||
|     qint32 stream_index; | ||||
|     bool m_stream_index_isSet; | ||||
| 
 | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user