diff --git a/plugins/channelrx/demodbfm/bfmdemod.cpp b/plugins/channelrx/demodbfm/bfmdemod.cpp index 8e30626ca..eba835a49 100644 --- a/plugins/channelrx/demodbfm/bfmdemod.cpp +++ b/plugins/channelrx/demodbfm/bfmdemod.cpp @@ -37,6 +37,7 @@ #include "dsp/downchannelizer.h" #include "dsp/threadedbasebandsamplesink.h" #include "dsp/dspcommands.h" +#include "dsp/devicesamplemimo.h" #include "device/deviceapi.h" #include "util/db.h" @@ -124,6 +125,11 @@ BFMDemod::~BFMDemod() delete m_rfFilter; } +uint32_t BFMDemod::getNumberOfDeviceStreams() const +{ + return m_deviceAPI->getNbSourceStreams(); +} + void BFMDemod::feed(const SampleVector::const_iterator& begin, const SampleVector::const_iterator& end, bool firstOfBurst) { (void) firstOfBurst; @@ -460,6 +466,7 @@ void BFMDemod::applySettings(const BFMDemodSettings& settings, bool force) << " m_showPilot: " << settings.m_showPilot << " m_rdsActive: " << settings.m_rdsActive << " m_audioDeviceName: " << settings.m_audioDeviceName + << " m_streamIndex: " << settings.m_streamIndex << " m_useReverseAPI: " << settings.m_useReverseAPI << " force: " << force; @@ -542,6 +549,21 @@ void BFMDemod::applySettings(const BFMDemodSettings& settings, bool force) } } + if (m_settings.m_streamIndex != settings.m_streamIndex) + { + if (m_deviceAPI->getSampleMIMO()) // change of stream is possible for MIMO devices only + { + m_deviceAPI->removeChannelSinkAPI(this, m_settings.m_streamIndex); + m_deviceAPI->removeChannelSink(m_threadedChannelizer, m_settings.m_streamIndex); + m_deviceAPI->addChannelSink(m_threadedChannelizer, settings.m_streamIndex); + m_deviceAPI->addChannelSinkAPI(this, settings.m_streamIndex); + // apply stream sample rate to itself + applyChannelSettings(m_deviceAPI->getSampleMIMO()->getSourceSampleRate(settings.m_streamIndex), m_inputFrequencyOffset); + } + + reverseAPIKeys.append("streamIndex"); + } + if (settings.m_useReverseAPI) { bool fullUpdate = ((m_settings.m_useReverseAPI != settings.m_useReverseAPI) && settings.m_useReverseAPI) || @@ -661,6 +683,9 @@ void BFMDemod::webapiUpdateChannelSettings( if (channelSettingsKeys.contains("audioDeviceName")) { settings.m_audioDeviceName = *response.getBfmDemodSettings()->getAudioDeviceName(); } + if (channelSettingsKeys.contains("streamIndex")) { + settings.m_streamIndex = response.getBfmDemodSettings()->getStreamIndex(); + } if (channelSettingsKeys.contains("useReverseAPI")) { settings.m_useReverseAPI = response.getBfmDemodSettings()->getUseReverseApi() != 0; } @@ -714,6 +739,7 @@ void BFMDemod::webapiFormatChannelSettings(SWGSDRangel::SWGChannelSettings& resp response.getBfmDemodSettings()->setAudioDeviceName(new QString(settings.m_audioDeviceName)); } + response.getBfmDemodSettings()->setStreamIndex(settings.m_streamIndex); response.getBfmDemodSettings()->setUseReverseApi(settings.m_useReverseAPI ? 1 : 0); if (response.getBfmDemodSettings()->getReverseApiAddress()) { @@ -827,6 +853,9 @@ void BFMDemod::webapiReverseSendSettings(QList<QString>& channelSettingsKeys, co if (channelSettingsKeys.contains("audioDeviceName") || force) { swgBFMDemodSettings->setAudioDeviceName(new QString(settings.m_audioDeviceName)); } + if (channelSettingsKeys.contains("streamIndex") || force) { + swgBFMDemodSettings->setStreamIndex(settings.m_streamIndex); + } QString channelSettingsURL = QString("http://%1:%2/sdrangel/deviceset/%3/channel/%4/settings") .arg(settings.m_reverseAPIAddress) diff --git a/plugins/channelrx/demodbfm/bfmdemod.h b/plugins/channelrx/demodbfm/bfmdemod.h index f680b4d53..018209fca 100644 --- a/plugins/channelrx/demodbfm/bfmdemod.h +++ b/plugins/channelrx/demodbfm/bfmdemod.h @@ -212,6 +212,8 @@ public: } } + uint32_t getNumberOfDeviceStreams() const; + static const QString m_channelIdURI; static const QString m_channelId; diff --git a/plugins/channelrx/demodbfm/bfmdemodgui.cpp b/plugins/channelrx/demodbfm/bfmdemodgui.cpp index c6b92e8c1..d1251d5fc 100644 --- a/plugins/channelrx/demodbfm/bfmdemodgui.cpp +++ b/plugins/channelrx/demodbfm/bfmdemodgui.cpp @@ -36,6 +36,7 @@ #include "util/simpleserializer.h" #include "util/db.h" #include "gui/basicchannelsettingsdialog.h" +#include "gui/devicestreamselectiondialog.h" #include "gui/crightclickenabler.h" #include "gui/audioselectdialog.h" #include "mainwindow.h" @@ -344,6 +345,20 @@ void BFMDemodGUI::onMenuDialogCalled(const QPoint &p) applySettings(); } + else if ((m_contextMenuType == ContextMenuStreamSettings) && (m_deviceUISet->m_deviceMIMOEngine)) + { + DeviceStreamSelectionDialog dialog(this); + dialog.setNumberOfStreams(m_bfmDemod->getNumberOfDeviceStreams()); + dialog.setStreamIndex(m_settings.m_streamIndex); + dialog.move(p); + dialog.exec(); + + m_settings.m_streamIndex = dialog.getSelectedStreamIndex(); + m_channelMarker.clearStreamIndexes(); + m_channelMarker.addStreamIndex(m_settings.m_streamIndex); + displayStreamIndex(); + applySettings(); + } resetContextMenuType(); } @@ -483,9 +498,20 @@ void BFMDemodGUI::displaySettings() ui->showPilot->setChecked(m_settings.m_showPilot); ui->rds->setChecked(m_settings.m_rdsActive); + displayStreamIndex(); + blockApplySettings(false); } +void BFMDemodGUI::displayStreamIndex() +{ + if (m_deviceUISet->m_deviceMIMOEngine) { + setStreamIndicator(tr("%1").arg(m_settings.m_streamIndex)); + } else { + setStreamIndicator("S"); // single channel indicator + } +} + void BFMDemodGUI::leaveEvent(QEvent*) { m_channelMarker.setHighlighted(false); diff --git a/plugins/channelrx/demodbfm/bfmdemodgui.h b/plugins/channelrx/demodbfm/bfmdemodgui.h index b53d6992b..5ee15b131 100644 --- a/plugins/channelrx/demodbfm/bfmdemodgui.h +++ b/plugins/channelrx/demodbfm/bfmdemodgui.h @@ -81,6 +81,7 @@ private: void blockApplySettings(bool block); void applySettings(bool force = false); void displaySettings(); + void displayStreamIndex(); void rdsUpdate(bool force); void rdsUpdateFixedFields(); diff --git a/plugins/channelrx/demodbfm/bfmdemodsettings.cpp b/plugins/channelrx/demodbfm/bfmdemodsettings.cpp index 72449b5e5..91c1bfea7 100644 --- a/plugins/channelrx/demodbfm/bfmdemodsettings.cpp +++ b/plugins/channelrx/demodbfm/bfmdemodsettings.cpp @@ -49,6 +49,7 @@ void BFMDemodSettings::resetToDefaults() m_rgbColor = QColor(80, 120, 228).rgb(); m_title = "Broadcast FM Demod"; m_audioDeviceName = AudioDeviceManager::m_defaultDeviceName; + m_streamIndex = 0; m_useReverseAPI = false; m_reverseAPIAddress = "127.0.0.1"; m_reverseAPIPort = 8888; @@ -84,6 +85,7 @@ QByteArray BFMDemodSettings::serialize() const s.writeU32(16, m_reverseAPIPort); s.writeU32(17, m_reverseAPIDeviceIndex); s.writeU32(18, m_reverseAPIChannelIndex); + s.writeS32(19, m_streamIndex); return s.final(); } @@ -148,6 +150,7 @@ bool BFMDemodSettings::deserialize(const QByteArray& data) m_reverseAPIDeviceIndex = utmp > 99 ? 99 : utmp; d.readU32(18, &utmp, 0); m_reverseAPIChannelIndex = utmp > 99 ? 99 : utmp; + d.readS32(19, &m_streamIndex, 0); return true; } diff --git a/plugins/channelrx/demodbfm/bfmdemodsettings.h b/plugins/channelrx/demodbfm/bfmdemodsettings.h index ec795eb53..9e1d0a78a 100644 --- a/plugins/channelrx/demodbfm/bfmdemodsettings.h +++ b/plugins/channelrx/demodbfm/bfmdemodsettings.h @@ -36,6 +36,7 @@ struct BFMDemodSettings quint32 m_rgbColor; QString m_title; QString m_audioDeviceName; + int m_streamIndex; //!< MIMO channel. Not relevant when connected to SI (single Rx). bool m_useReverseAPI; QString m_reverseAPIAddress; uint16_t m_reverseAPIPort; diff --git a/plugins/channelrx/demoddsd/dsddemod.cpp b/plugins/channelrx/demoddsd/dsddemod.cpp index f2aca7cf7..8eef9a0d0 100644 --- a/plugins/channelrx/demoddsd/dsddemod.cpp +++ b/plugins/channelrx/demoddsd/dsddemod.cpp @@ -38,6 +38,7 @@ #include "dsp/threadedbasebandsamplesink.h" #include "dsp/downchannelizer.h" #include "dsp/dspcommands.h" +#include "dsp/devicesamplemimo.h" #include "device/deviceapi.h" #include "util/db.h" @@ -122,6 +123,11 @@ void DSDDemod::configureMyPosition(MessageQueue* messageQueue, float myLatitude, messageQueue->push(cmd); } +uint32_t DSDDemod::getNumberOfDeviceStreams() const +{ + return m_deviceAPI->getNbSourceStreams(); +} + void DSDDemod::feed(const SampleVector::const_iterator& begin, const SampleVector::const_iterator& end, bool firstOfBurst) { (void) firstOfBurst; @@ -492,6 +498,7 @@ void DSDDemod::applySettings(const DSDDemodSettings& settings, bool force) << " m_traceLengthMutliplier: " << settings.m_traceLengthMutliplier << " m_traceStroke: " << settings.m_traceStroke << " m_traceDecay: " << settings.m_traceDecay + << " m_streamIndex: " << settings.m_streamIndex << " force: " << force; QList<QString> reverseAPIKeys; @@ -603,6 +610,21 @@ void DSDDemod::applySettings(const DSDDemodSettings& settings, bool force) } } + if (m_settings.m_streamIndex != settings.m_streamIndex) + { + if (m_deviceAPI->getSampleMIMO()) // change of stream is possible for MIMO devices only + { + m_deviceAPI->removeChannelSinkAPI(this, m_settings.m_streamIndex); + m_deviceAPI->removeChannelSink(m_threadedChannelizer, m_settings.m_streamIndex); + m_deviceAPI->addChannelSink(m_threadedChannelizer, settings.m_streamIndex); + m_deviceAPI->addChannelSinkAPI(this, settings.m_streamIndex); + // apply stream sample rate to itself + applyChannelSettings(m_deviceAPI->getSampleMIMO()->getSourceSampleRate(settings.m_streamIndex), m_inputFrequencyOffset); + } + + reverseAPIKeys.append("streamIndex"); + } + if (settings.m_useReverseAPI) { bool fullUpdate = ((m_settings.m_useReverseAPI != settings.m_useReverseAPI) && settings.m_useReverseAPI) || @@ -941,6 +963,9 @@ void DSDDemod::webapiUpdateChannelSettings( if (channelSettingsKeys.contains("traceDecay")) { settings.m_traceDecay = response.getDsdDemodSettings()->getTraceDecay(); } + if (channelSettingsKeys.contains("streamIndex")) { + settings.m_streamIndex = response.getDsdDemodSettings()->getStreamIndex(); + } if (channelSettingsKeys.contains("useReverseAPI")) { settings.m_useReverseAPI = response.getDsdDemodSettings()->getUseReverseApi() != 0; } @@ -1004,6 +1029,7 @@ void DSDDemod::webapiFormatChannelSettings(SWGSDRangel::SWGChannelSettings& resp response.getDsdDemodSettings()->setTraceLengthMutliplier(settings.m_traceLengthMutliplier); response.getDsdDemodSettings()->setTraceStroke(settings.m_traceStroke); response.getDsdDemodSettings()->setTraceDecay(settings.m_traceDecay); + response.getDsdDemodSettings()->setStreamIndex(settings.m_streamIndex); response.getDsdDemodSettings()->setUseReverseApi(settings.m_useReverseAPI ? 1 : 0); if (response.getDsdDemodSettings()->getReverseApiAddress()) { @@ -1117,6 +1143,9 @@ void DSDDemod::webapiReverseSendSettings(QList<QString>& channelSettingsKeys, co if (channelSettingsKeys.contains("traceDecay") || force) { swgDSDDemodSettings->setTraceDecay(settings.m_traceDecay); } + if (channelSettingsKeys.contains("streamIndex") || force) { + swgDSDDemodSettings->setStreamIndex(settings.m_streamIndex); + } QString channelSettingsURL = QString("http://%1:%2/sdrangel/deviceset/%3/channel/%4/settings") .arg(settings.m_reverseAPIAddress) diff --git a/plugins/channelrx/demoddsd/dsddemod.h b/plugins/channelrx/demoddsd/dsddemod.h index b1fa6edce..6f4674c41 100644 --- a/plugins/channelrx/demoddsd/dsddemod.h +++ b/plugins/channelrx/demoddsd/dsddemod.h @@ -173,6 +173,8 @@ public: const QStringList& channelSettingsKeys, SWGSDRangel::SWGChannelSettings& response); + uint32_t getNumberOfDeviceStreams() const; + static const QString m_channelIdURI; static const QString m_channelId; diff --git a/plugins/channelrx/demoddsd/dsddemodgui.cpp b/plugins/channelrx/demoddsd/dsddemodgui.cpp index 377610be6..8cb29ed28 100644 --- a/plugins/channelrx/demoddsd/dsddemodgui.cpp +++ b/plugins/channelrx/demoddsd/dsddemodgui.cpp @@ -28,6 +28,7 @@ #include "util/simpleserializer.h" #include "util/db.h" #include "gui/basicchannelsettingsdialog.h" +#include "gui/devicestreamselectiondialog.h" #include "gui/crightclickenabler.h" #include "gui/audioselectdialog.h" #include "dsp/dspengine.h" @@ -298,6 +299,20 @@ void DSDDemodGUI::onMenuDialogCalled(const QPoint &p) applySettings(); } + else if ((m_contextMenuType == ContextMenuStreamSettings) && (m_deviceUISet->m_deviceMIMOEngine)) + { + DeviceStreamSelectionDialog dialog(this); + dialog.setNumberOfStreams(m_dsdDemod->getNumberOfDeviceStreams()); + dialog.setStreamIndex(m_settings.m_streamIndex); + dialog.move(p); + dialog.exec(); + + m_settings.m_streamIndex = dialog.getSelectedStreamIndex(); + m_channelMarker.clearStreamIndexes(); + m_channelMarker.addStreamIndex(m_settings.m_streamIndex); + displayStreamIndex(); + applySettings(); + } resetContextMenuType(); } @@ -465,9 +480,20 @@ void DSDDemodGUI::displaySettings() ui->traceDecayText->setText(QString("%1").arg(m_settings.m_traceDecay)); m_scopeVisXY->setDecay(m_settings.m_traceDecay); + displayStreamIndex(); + blockApplySettings(false); } +void DSDDemodGUI::displayStreamIndex() +{ + if (m_deviceUISet->m_deviceMIMOEngine) { + setStreamIndicator(tr("%1").arg(m_settings.m_streamIndex)); + } else { + setStreamIndicator("S"); // single channel indicator + } +} + void DSDDemodGUI::applySettings(bool force) { if (m_doApplySettings) diff --git a/plugins/channelrx/demoddsd/dsddemodgui.h b/plugins/channelrx/demoddsd/dsddemodgui.h index 64cc941bf..fa7251d1d 100644 --- a/plugins/channelrx/demoddsd/dsddemodgui.h +++ b/plugins/channelrx/demoddsd/dsddemodgui.h @@ -106,6 +106,7 @@ private: void blockApplySettings(bool block); void applySettings(bool force = false); void displaySettings(); + void displayStreamIndex(); void updateMyPosition(); void leaveEvent(QEvent*); diff --git a/plugins/channelrx/demoddsd/dsddemodsettings.cpp b/plugins/channelrx/demoddsd/dsddemodsettings.cpp index f30306881..fff5f20a9 100644 --- a/plugins/channelrx/demoddsd/dsddemodsettings.cpp +++ b/plugins/channelrx/demoddsd/dsddemodsettings.cpp @@ -53,6 +53,7 @@ void DSDDemodSettings::resetToDefaults() m_traceStroke = 100; m_traceDecay = 200; m_audioDeviceName = AudioDeviceManager::m_defaultDeviceName; + m_streamIndex = 0; m_useReverseAPI = false; m_reverseAPIAddress = "127.0.0.1"; m_reverseAPIPort = 8888; @@ -100,6 +101,7 @@ QByteArray DSDDemodSettings::serialize() const s.writeU32(27, m_reverseAPIDeviceIndex); s.writeU32(28, m_reverseAPIChannelIndex); s.writeBool(29, m_audioMute); + s.writeS32(30, m_streamIndex); return s.final(); } @@ -177,6 +179,7 @@ bool DSDDemodSettings::deserialize(const QByteArray& data) d.readU32(28, &utmp, 0); m_reverseAPIChannelIndex = utmp > 99 ? 99 : utmp; d.readBool(29, &m_audioMute, false); + d.readS32(30, &m_streamIndex, 0); return true; } diff --git a/plugins/channelrx/demoddsd/dsddemodsettings.h b/plugins/channelrx/demoddsd/dsddemodsettings.h index 1dec8ff02..0180193c1 100644 --- a/plugins/channelrx/demoddsd/dsddemodsettings.h +++ b/plugins/channelrx/demoddsd/dsddemodsettings.h @@ -46,6 +46,7 @@ struct DSDDemodSettings int m_traceStroke; // [0..255] int m_traceDecay; // [0..255] QString m_audioDeviceName; + int m_streamIndex; //!< MIMO channel. Not relevant when connected to SI (single Rx). bool m_useReverseAPI; QString m_reverseAPIAddress; uint16_t m_reverseAPIPort; diff --git a/plugins/channelrx/demodfreedv/freedvdemod.cpp b/plugins/channelrx/demodfreedv/freedvdemod.cpp index 4e6e79e66..894d6aa6f 100644 --- a/plugins/channelrx/demodfreedv/freedvdemod.cpp +++ b/plugins/channelrx/demodfreedv/freedvdemod.cpp @@ -36,6 +36,7 @@ #include "dsp/downchannelizer.h" #include "dsp/threadedbasebandsamplesink.h" #include "dsp/dspcommands.h" +#include "dsp/devicesamplemimo.h" #include "device/deviceapi.h" #include "util/db.h" @@ -252,6 +253,11 @@ void FreeDVDemod::configure(MessageQueue* messageQueue, messageQueue->push(cmd); } +uint32_t FreeDVDemod::getNumberOfDeviceStreams() const +{ + return m_deviceAPI->getNbSourceStreams(); +} + void FreeDVDemod::feed(const SampleVector::const_iterator& begin, const SampleVector::const_iterator& end, bool positiveOnly) { (void) positiveOnly; @@ -715,6 +721,7 @@ void FreeDVDemod::applySettings(const FreeDVDemodSettings& settings, bool force) << " m_audioMute: " << settings.m_audioMute << " m_agcActive: " << settings.m_agc << " m_audioDeviceName: " << settings.m_audioDeviceName + << " m_streamIndex: " << settings.m_streamIndex << " m_useReverseAPI: " << settings.m_useReverseAPI << " m_reverseAPIAddress: " << settings.m_reverseAPIAddress << " m_reverseAPIPort: " << settings.m_reverseAPIPort @@ -771,6 +778,21 @@ void FreeDVDemod::applySettings(const FreeDVDemodSettings& settings, bool force) m_audioMute = settings.m_audioMute; m_agcActive = settings.m_agc; + if (m_settings.m_streamIndex != settings.m_streamIndex) + { + if (m_deviceAPI->getSampleMIMO()) // change of stream is possible for MIMO devices only + { + m_deviceAPI->removeChannelSinkAPI(this, m_settings.m_streamIndex); + m_deviceAPI->removeChannelSink(m_threadedChannelizer, m_settings.m_streamIndex); + m_deviceAPI->addChannelSink(m_threadedChannelizer, settings.m_streamIndex); + m_deviceAPI->addChannelSinkAPI(this, settings.m_streamIndex); + // apply stream sample rate to itself + applyChannelSettings(m_deviceAPI->getSampleMIMO()->getSourceSampleRate(settings.m_streamIndex), m_inputFrequencyOffset); + } + + reverseAPIKeys.append("streamIndex"); + } + if (settings.m_useReverseAPI) { bool fullUpdate = ((m_settings.m_useReverseAPI != settings.m_useReverseAPI) && settings.m_useReverseAPI) || @@ -901,6 +923,9 @@ void FreeDVDemod::webapiUpdateChannelSettings( if (channelSettingsKeys.contains("audioDeviceName")) { settings.m_audioDeviceName = *response.getFreeDvDemodSettings()->getAudioDeviceName(); } + if (channelSettingsKeys.contains("streamIndex")) { + settings.m_streamIndex = response.getFreeDvDemodSettings()->getStreamIndex(); + } if (channelSettingsKeys.contains("useReverseAPI")) { settings.m_useReverseAPI = response.getFreeDvDemodSettings()->getUseReverseApi() != 0; } @@ -953,6 +978,7 @@ void FreeDVDemod::webapiFormatChannelSettings(SWGSDRangel::SWGChannelSettings& r response.getFreeDvDemodSettings()->setAudioDeviceName(new QString(settings.m_audioDeviceName)); } + response.getFreeDvDemodSettings()->setStreamIndex(settings.m_streamIndex); response.getFreeDvDemodSettings()->setUseReverseApi(settings.m_useReverseAPI ? 1 : 0); if (response.getFreeDvDemodSettings()->getReverseApiAddress()) { @@ -1020,6 +1046,9 @@ void FreeDVDemod::webapiReverseSendSettings(QList<QString>& channelSettingsKeys, if (channelSettingsKeys.contains("audioDeviceName") || force) { swgFreeDVDemodSettings->setAudioDeviceName(new QString(settings.m_audioDeviceName)); } + if (channelSettingsKeys.contains("streamIndex") || force) { + swgFreeDVDemodSettings->setStreamIndex(settings.m_streamIndex); + } QString channelSettingsURL = QString("http://%1:%2/sdrangel/deviceset/%3/channel/%4/settings") .arg(settings.m_reverseAPIAddress) diff --git a/plugins/channelrx/demodfreedv/freedvdemod.h b/plugins/channelrx/demodfreedv/freedvdemod.h index fa01105e7..954b1ddfa 100644 --- a/plugins/channelrx/demodfreedv/freedvdemod.h +++ b/plugins/channelrx/demodfreedv/freedvdemod.h @@ -203,6 +203,8 @@ public: const QStringList& channelSettingsKeys, SWGSDRangel::SWGChannelSettings& response); + uint32_t getNumberOfDeviceStreams() const; + static const QString m_channelIdURI; static const QString m_channelId; diff --git a/plugins/channelrx/demodfreedv/freedvdemodgui.cpp b/plugins/channelrx/demodfreedv/freedvdemodgui.cpp index 7164aaf22..be741cca9 100644 --- a/plugins/channelrx/demodfreedv/freedvdemodgui.cpp +++ b/plugins/channelrx/demodfreedv/freedvdemodgui.cpp @@ -26,6 +26,7 @@ #include "dsp/dspcommands.h" #include "gui/glspectrum.h" #include "gui/basicchannelsettingsdialog.h" +#include "gui/devicestreamselectiondialog.h" #include "plugin/pluginapi.h" #include "util/simpleserializer.h" #include "util/db.h" @@ -232,6 +233,20 @@ void FreeDVDemodGUI::onMenuDialogCalled(const QPoint &p) applySettings(); } + else if ((m_contextMenuType == ContextMenuStreamSettings) && (m_deviceUISet->m_deviceMIMOEngine)) + { + DeviceStreamSelectionDialog dialog(this); + dialog.setNumberOfStreams(m_freeDVDemod->getNumberOfDeviceStreams()); + dialog.setStreamIndex(m_settings.m_streamIndex); + dialog.move(p); + dialog.exec(); + + m_settings.m_streamIndex = dialog.getSelectedStreamIndex(); + m_channelMarker.clearStreamIndexes(); + m_channelMarker.addStreamIndex(m_settings.m_streamIndex); + displayStreamIndex(); + applySettings(); + } resetContextMenuType(); } @@ -399,9 +414,20 @@ void FreeDVDemodGUI::displaySettings() ui->volumeIn->setValue(m_settings.m_volumeIn * 10.0); ui->volumeInText->setText(QString("%1").arg(m_settings.m_volumeIn, 0, 'f', 1)); + displayStreamIndex(); + blockApplySettings(false); } +void FreeDVDemodGUI::displayStreamIndex() +{ + if (m_deviceUISet->m_deviceMIMOEngine) { + setStreamIndicator(tr("%1").arg(m_settings.m_streamIndex)); + } else { + setStreamIndicator("S"); // single channel indicator + } +} + void FreeDVDemodGUI::leaveEvent(QEvent*) { m_channelMarker.setHighlighted(false); diff --git a/plugins/channelrx/demodfreedv/freedvdemodgui.h b/plugins/channelrx/demodfreedv/freedvdemodgui.h index 198d949ad..a16ae3e9a 100644 --- a/plugins/channelrx/demodfreedv/freedvdemodgui.h +++ b/plugins/channelrx/demodfreedv/freedvdemodgui.h @@ -90,6 +90,7 @@ private: void applyBandwidths(int spanLog2, bool force = false); void displayBandwidths(int spanLog2); void displaySettings(); + void displayStreamIndex(); void leaveEvent(QEvent*); void enterEvent(QEvent*); diff --git a/plugins/channelrx/demodfreedv/freedvdemodsettings.cpp b/plugins/channelrx/demodfreedv/freedvdemodsettings.cpp index df82be177..63957edb9 100644 --- a/plugins/channelrx/demodfreedv/freedvdemodsettings.cpp +++ b/plugins/channelrx/demodfreedv/freedvdemodsettings.cpp @@ -49,6 +49,7 @@ void FreeDVDemodSettings::resetToDefaults() m_title = "FreeDV Demodulator"; m_audioDeviceName = AudioDeviceManager::m_defaultDeviceName; m_freeDVMode = FreeDVMode2400A; + m_streamIndex = 0; m_useReverseAPI = false; m_reverseAPIAddress = "127.0.0.1"; m_reverseAPIPort = 8888; @@ -78,6 +79,7 @@ QByteArray FreeDVDemodSettings::serialize() const s.writeU32(21, m_reverseAPIDeviceIndex); s.writeU32(22, m_reverseAPIChannelIndex); s.writeS32(23, (int) m_freeDVMode); + s.writeS32(24, m_streamIndex); return s.final(); } @@ -138,6 +140,8 @@ bool FreeDVDemodSettings::deserialize(const QByteArray& data) m_freeDVMode = (FreeDVMode) tmp; } + d.readS32(24, &m_streamIndex, 0); + return true; } else diff --git a/plugins/channelrx/demodfreedv/freedvdemodsettings.h b/plugins/channelrx/demodfreedv/freedvdemodsettings.h index c5e797e59..ba8101283 100644 --- a/plugins/channelrx/demodfreedv/freedvdemodsettings.h +++ b/plugins/channelrx/demodfreedv/freedvdemodsettings.h @@ -45,6 +45,7 @@ struct FreeDVDemodSettings QString m_title; QString m_audioDeviceName; FreeDVMode m_freeDVMode; + int m_streamIndex; //!< MIMO channel. Not relevant when connected to SI (single Rx). bool m_useReverseAPI; QString m_reverseAPIAddress; uint16_t m_reverseAPIPort; diff --git a/plugins/channelrx/demodnfm/nfmdemod.cpp b/plugins/channelrx/demodnfm/nfmdemod.cpp index 6c1032822..f750ec1b9 100644 --- a/plugins/channelrx/demodnfm/nfmdemod.cpp +++ b/plugins/channelrx/demodnfm/nfmdemod.cpp @@ -37,6 +37,7 @@ #include "dsp/dspengine.h" #include "dsp/threadedbasebandsamplesink.h" #include "dsp/dspcommands.h" +#include "dsp/devicesamplemimo.h" #include "device/deviceapi.h" #include "nfmdemod.h" @@ -147,6 +148,11 @@ Real angleDist(Real a, Real b) return dist; } +uint32_t NFMDemod::getNumberOfDeviceStreams() const +{ + return m_deviceAPI->getNbSourceStreams(); +} + void NFMDemod::feed(const SampleVector::const_iterator& begin, const SampleVector::const_iterator& end, bool firstOfBurst) { (void) firstOfBurst; @@ -521,6 +527,7 @@ void NFMDemod::applySettings(const NFMDemodSettings& settings, bool force) << " m_highPass: " << settings.m_highPass << " m_audioMute: " << settings.m_audioMute << " m_audioDeviceName: " << settings.m_audioDeviceName + << " m_streamIndex: " << settings.m_streamIndex << " m_useReverseAPI: " << settings.m_useReverseAPI << " m_reverseAPIAddress: " << settings.m_reverseAPIAddress << " m_reverseAPIPort: " << settings.m_reverseAPIPort @@ -630,6 +637,21 @@ void NFMDemod::applySettings(const NFMDemodSettings& settings, bool force) } } + if (m_settings.m_streamIndex != settings.m_streamIndex) + { + if (m_deviceAPI->getSampleMIMO()) // change of stream is possible for MIMO devices only + { + m_deviceAPI->removeChannelSinkAPI(this, m_settings.m_streamIndex); + m_deviceAPI->removeChannelSink(m_threadedChannelizer, m_settings.m_streamIndex); + m_deviceAPI->addChannelSink(m_threadedChannelizer, settings.m_streamIndex); + m_deviceAPI->addChannelSinkAPI(this, settings.m_streamIndex); + // apply stream sample rate to itself + applyChannelSettings(m_deviceAPI->getSampleMIMO()->getSourceSampleRate(settings.m_streamIndex), m_inputFrequencyOffset); + } + + reverseAPIKeys.append("streamIndex"); + } + if (settings.m_useReverseAPI) { bool fullUpdate = ((m_settings.m_useReverseAPI != settings.m_useReverseAPI) && settings.m_useReverseAPI) || @@ -760,6 +782,9 @@ void NFMDemod::webapiUpdateChannelSettings( if (channelSettingsKeys.contains("audioDeviceName")) { settings.m_audioDeviceName = *response.getNfmDemodSettings()->getAudioDeviceName(); } + if (channelSettingsKeys.contains("streamIndex")) { + settings.m_streamIndex = response.getNfmDemodSettings()->getStreamIndex(); + } if (channelSettingsKeys.contains("useReverseAPI")) { settings.m_useReverseAPI = response.getNfmDemodSettings()->getUseReverseApi() != 0; } @@ -816,6 +841,7 @@ void NFMDemod::webapiFormatChannelSettings(SWGSDRangel::SWGChannelSettings& resp response.getNfmDemodSettings()->setAudioDeviceName(new QString(settings.m_audioDeviceName)); } + response.getNfmDemodSettings()->setStreamIndex(settings.m_streamIndex); response.getNfmDemodSettings()->setUseReverseApi(settings.m_useReverseAPI ? 1 : 0); if (response.getNfmDemodSettings()->getReverseApiAddress()) { @@ -899,6 +925,9 @@ void NFMDemod::webapiReverseSendSettings(QList<QString>& channelSettingsKeys, co if (channelSettingsKeys.contains("audioDeviceName") || force) { swgNFMDemodSettings->setAudioDeviceName(new QString(settings.m_audioDeviceName)); } + if (channelSettingsKeys.contains("streamIndex") || force) { + swgNFMDemodSettings->setStreamIndex(settings.m_streamIndex); + } QString channelSettingsURL = QString("http://%1:%2/sdrangel/deviceset/%3/channel/%4/settings") .arg(settings.m_reverseAPIAddress) diff --git a/plugins/channelrx/demodnfm/nfmdemod.h b/plugins/channelrx/demodnfm/nfmdemod.h index aea270eb8..3b03d5cb2 100644 --- a/plugins/channelrx/demodnfm/nfmdemod.h +++ b/plugins/channelrx/demodnfm/nfmdemod.h @@ -195,6 +195,8 @@ public: m_magsqCount = 0; } + uint32_t getNumberOfDeviceStreams() const; + static const QString m_channelIdURI; static const QString m_channelId; diff --git a/plugins/channelrx/demodnfm/nfmdemodgui.cpp b/plugins/channelrx/demodnfm/nfmdemodgui.cpp index 010d9166f..7f474a314 100644 --- a/plugins/channelrx/demodnfm/nfmdemodgui.cpp +++ b/plugins/channelrx/demodnfm/nfmdemodgui.cpp @@ -10,6 +10,7 @@ #include "util/simpleserializer.h" #include "util/db.h" #include "gui/basicchannelsettingsdialog.h" +#include "gui/devicestreamselectiondialog.h" #include "gui/crightclickenabler.h" #include "gui/audioselectdialog.h" #include "dsp/dspengine.h" @@ -256,6 +257,20 @@ void NFMDemodGUI::onMenuDialogCalled(const QPoint &p) applySettings(); } + else if ((m_contextMenuType == ContextMenuStreamSettings) && (m_deviceUISet->m_deviceMIMOEngine)) + { + DeviceStreamSelectionDialog dialog(this); + dialog.setNumberOfStreams(m_nfmDemod->getNumberOfDeviceStreams()); + dialog.setStreamIndex(m_settings.m_streamIndex); + dialog.move(p); + dialog.exec(); + + m_settings.m_streamIndex = dialog.getSelectedStreamIndex(); + m_channelMarker.clearStreamIndexes(); + m_channelMarker.addStreamIndex(m_settings.m_streamIndex); + displayStreamIndex(); + applySettings(); + } resetContextMenuType(); } @@ -409,9 +424,20 @@ void NFMDemodGUI::displaySettings() ui->ctcss->setCurrentIndex(m_settings.m_ctcssIndex); + displayStreamIndex(); + blockApplySettings(false); } +void NFMDemodGUI::displayStreamIndex() +{ + if (m_deviceUISet->m_deviceMIMOEngine) { + setStreamIndicator(tr("%1").arg(m_settings.m_streamIndex)); + } else { + setStreamIndicator("S"); // single channel indicator + } +} + void NFMDemodGUI::leaveEvent(QEvent*) { m_channelMarker.setHighlighted(false); diff --git a/plugins/channelrx/demodnfm/nfmdemodgui.h b/plugins/channelrx/demodnfm/nfmdemodgui.h index 2c8ea09f2..ab3aff498 100644 --- a/plugins/channelrx/demodnfm/nfmdemodgui.h +++ b/plugins/channelrx/demodnfm/nfmdemodgui.h @@ -62,6 +62,7 @@ private: void blockApplySettings(bool block); void applySettings(bool force = false); void displaySettings(); + void displayStreamIndex(); void leaveEvent(QEvent*); void enterEvent(QEvent*); diff --git a/plugins/channelrx/demodnfm/nfmdemodsettings.cpp b/plugins/channelrx/demodnfm/nfmdemodsettings.cpp index 920e20dc1..55fb412c2 100644 --- a/plugins/channelrx/demodnfm/nfmdemodsettings.cpp +++ b/plugins/channelrx/demodnfm/nfmdemodsettings.cpp @@ -54,6 +54,7 @@ void NFMDemodSettings::resetToDefaults() m_title = "NFM Demodulator"; m_audioDeviceName = AudioDeviceManager::m_defaultDeviceName; m_highPass = true; + m_streamIndex = 0; m_useReverseAPI = false; m_reverseAPIAddress = "127.0.0.1"; m_reverseAPIPort = 8888; @@ -88,6 +89,7 @@ QByteArray NFMDemodSettings::serialize() const s.writeU32(18, m_reverseAPIPort); s.writeU32(19, m_reverseAPIDeviceIndex); s.writeU32(20, m_reverseAPIChannelIndex); + s.writeS32(21, m_streamIndex); return s.final(); } @@ -148,6 +150,7 @@ bool NFMDemodSettings::deserialize(const QByteArray& data) m_reverseAPIDeviceIndex = utmp > 99 ? 99 : utmp; d.readU32(20, &utmp, 0); m_reverseAPIChannelIndex = utmp > 99 ? 99 : utmp; + d.readS32(21, &m_streamIndex, 0); return true; } diff --git a/plugins/channelrx/demodnfm/nfmdemodsettings.h b/plugins/channelrx/demodnfm/nfmdemodsettings.h index bbad59173..6d2bc332f 100644 --- a/plugins/channelrx/demodnfm/nfmdemodsettings.h +++ b/plugins/channelrx/demodnfm/nfmdemodsettings.h @@ -43,6 +43,7 @@ struct NFMDemodSettings QString m_title; QString m_audioDeviceName; bool m_highPass; + int m_streamIndex; //!< MIMO channel. Not relevant when connected to SI (single Rx). bool m_useReverseAPI; QString m_reverseAPIAddress; uint16_t m_reverseAPIPort; diff --git a/plugins/channelrx/demodssb/ssbdemod.cpp b/plugins/channelrx/demodssb/ssbdemod.cpp index fc82fc20a..f870adbe6 100644 --- a/plugins/channelrx/demodssb/ssbdemod.cpp +++ b/plugins/channelrx/demodssb/ssbdemod.cpp @@ -36,6 +36,7 @@ #include "dsp/downchannelizer.h" #include "dsp/threadedbasebandsamplesink.h" #include "dsp/dspcommands.h" +#include "dsp/devicesamplemimo.h" #include "device/deviceapi.h" #include "util/db.h" @@ -154,6 +155,11 @@ void SSBDemod::configure(MessageQueue* messageQueue, messageQueue->push(cmd); } +uint32_t SSBDemod::getNumberOfDeviceStreams() const +{ + return m_deviceAPI->getNbSourceStreams(); +} + void SSBDemod::feed(const SampleVector::const_iterator& begin, const SampleVector::const_iterator& end, bool positiveOnly) { (void) positiveOnly; @@ -473,6 +479,7 @@ void SSBDemod::applySettings(const SSBDemodSettings& settings, bool force) << " agcPowerThreshold: " << settings.m_agcPowerThreshold << " agcThresholdGate: " << settings.m_agcThresholdGate << " m_audioDeviceName: " << settings.m_audioDeviceName + << " m_streamIndex: " << settings.m_streamIndex << " m_useReverseAPI: " << settings.m_useReverseAPI << " m_reverseAPIAddress: " << settings.m_reverseAPIAddress << " m_reverseAPIPort: " << settings.m_reverseAPIPort @@ -631,6 +638,21 @@ void SSBDemod::applySettings(const SSBDemodSettings& settings, bool force) m_audioMute = settings.m_audioMute; m_agcActive = settings.m_agc; + if (m_settings.m_streamIndex != settings.m_streamIndex) + { + if (m_deviceAPI->getSampleMIMO()) // change of stream is possible for MIMO devices only + { + m_deviceAPI->removeChannelSinkAPI(this, m_settings.m_streamIndex); + m_deviceAPI->removeChannelSink(m_threadedChannelizer, m_settings.m_streamIndex); + m_deviceAPI->addChannelSink(m_threadedChannelizer, settings.m_streamIndex); + m_deviceAPI->addChannelSinkAPI(this, settings.m_streamIndex); + // apply stream sample rate to itself + applyChannelSettings(m_deviceAPI->getSampleMIMO()->getSourceSampleRate(settings.m_streamIndex), m_inputFrequencyOffset); + } + + reverseAPIKeys.append("streamIndex"); + } + if (settings.m_useReverseAPI) { bool fullUpdate = ((m_settings.m_useReverseAPI != settings.m_useReverseAPI) && settings.m_useReverseAPI) || @@ -765,6 +787,9 @@ void SSBDemod::webapiUpdateChannelSettings( if (channelSettingsKeys.contains("audioDeviceName")) { settings.m_audioDeviceName = *response.getSsbDemodSettings()->getAudioDeviceName(); } + if (channelSettingsKeys.contains("streamIndex")) { + settings.m_streamIndex = response.getSsbDemodSettings()->getStreamIndex(); + } if (channelSettingsKeys.contains("useReverseAPI")) { settings.m_useReverseAPI = response.getSsbDemodSettings()->getUseReverseApi() != 0; } @@ -824,6 +849,7 @@ void SSBDemod::webapiFormatChannelSettings(SWGSDRangel::SWGChannelSettings& resp response.getSsbDemodSettings()->setAudioDeviceName(new QString(settings.m_audioDeviceName)); } + response.getSsbDemodSettings()->setStreamIndex(settings.m_streamIndex); response.getSsbDemodSettings()->setUseReverseApi(settings.m_useReverseAPI ? 1 : 0); if (response.getSsbDemodSettings()->getReverseApiAddress()) { @@ -912,6 +938,9 @@ void SSBDemod::webapiReverseSendSettings(QList<QString>& channelSettingsKeys, co if (channelSettingsKeys.contains("audioDeviceName") || force) { swgSSBDemodSettings->setAudioDeviceName(new QString(settings.m_audioDeviceName)); } + if (channelSettingsKeys.contains("streamIndex") || force) { + swgSSBDemodSettings->setStreamIndex(settings.m_streamIndex); + } QString channelSettingsURL = QString("http://%1:%2/sdrangel/deviceset/%3/channel/%4/settings") .arg(settings.m_reverseAPIAddress) diff --git a/plugins/channelrx/demodssb/ssbdemod.h b/plugins/channelrx/demodssb/ssbdemod.h index 08e3e5492..cfac77fb9 100644 --- a/plugins/channelrx/demodssb/ssbdemod.h +++ b/plugins/channelrx/demodssb/ssbdemod.h @@ -182,6 +182,8 @@ public: const QStringList& channelSettingsKeys, SWGSDRangel::SWGChannelSettings& response); + uint32_t getNumberOfDeviceStreams() const; + static const QString m_channelIdURI; static const QString m_channelId; diff --git a/plugins/channelrx/demodssb/ssbdemodgui.cpp b/plugins/channelrx/demodssb/ssbdemodgui.cpp index 2dc18d661..3bd249dea 100644 --- a/plugins/channelrx/demodssb/ssbdemodgui.cpp +++ b/plugins/channelrx/demodssb/ssbdemodgui.cpp @@ -10,6 +10,7 @@ #include "dsp/dspcommands.h" #include "gui/glspectrum.h" #include "gui/basicchannelsettingsdialog.h" +#include "gui/devicestreamselectiondialog.h" #include "plugin/pluginapi.h" #include "util/simpleserializer.h" #include "util/db.h" @@ -262,6 +263,20 @@ void SSBDemodGUI::onMenuDialogCalled(const QPoint &p) applySettings(); } + else if ((m_contextMenuType == ContextMenuStreamSettings) && (m_deviceUISet->m_deviceMIMOEngine)) + { + DeviceStreamSelectionDialog dialog(this); + dialog.setNumberOfStreams(m_ssbDemod->getNumberOfDeviceStreams()); + dialog.setStreamIndex(m_settings.m_streamIndex); + dialog.move(p); + dialog.exec(); + + m_settings.m_streamIndex = dialog.getSelectedStreamIndex(); + m_channelMarker.clearStreamIndexes(); + m_channelMarker.addStreamIndex(m_settings.m_streamIndex); + displayStreamIndex(); + applySettings(); + } resetContextMenuType(); } @@ -568,9 +583,20 @@ void SSBDemodGUI::displaySettings() displayAGCPowerThreshold(ui->agcPowerThreshold->value()); displayAGCThresholdGate(m_settings.m_agcThresholdGate); + displayStreamIndex(); + blockApplySettings(false); } +void SSBDemodGUI::displayStreamIndex() +{ + if (m_deviceUISet->m_deviceMIMOEngine) { + setStreamIndicator(tr("%1").arg(m_settings.m_streamIndex)); + } else { + setStreamIndicator("S"); // single channel indicator + } +} + void SSBDemodGUI::displayAGCPowerThreshold(int value) { if (value == SSBDemodSettings::m_minPowerThresholdDB) diff --git a/plugins/channelrx/demodssb/ssbdemodgui.h b/plugins/channelrx/demodssb/ssbdemodgui.h index 673e63dad..15d5865f5 100644 --- a/plugins/channelrx/demodssb/ssbdemodgui.h +++ b/plugins/channelrx/demodssb/ssbdemodgui.h @@ -73,6 +73,7 @@ private: void applyBandwidths(int spanLog2, bool force = false); int spanLog2Limit(int spanLog2); void displaySettings(); + void displayStreamIndex(); void displayAGCPowerThreshold(int value); void displayAGCThresholdGate(int value); diff --git a/plugins/channelrx/demodssb/ssbdemodsettings.cpp b/plugins/channelrx/demodssb/ssbdemodsettings.cpp index db57b8db2..99fcd1017 100644 --- a/plugins/channelrx/demodssb/ssbdemodsettings.cpp +++ b/plugins/channelrx/demodssb/ssbdemodsettings.cpp @@ -56,6 +56,7 @@ void SSBDemodSettings::resetToDefaults() m_rgbColor = QColor(0, 255, 0).rgb(); m_title = "SSB Demodulator"; m_audioDeviceName = AudioDeviceManager::m_defaultDeviceName; + m_streamIndex = 0; m_useReverseAPI = false; m_reverseAPIAddress = "127.0.0.1"; m_reverseAPIPort = 8888; @@ -92,6 +93,7 @@ QByteArray SSBDemodSettings::serialize() const s.writeU32(20, m_reverseAPIPort); s.writeU32(21, m_reverseAPIDeviceIndex); s.writeU32(22, m_reverseAPIChannelIndex); + s.writeS32(23, m_streamIndex); return s.final(); } @@ -152,6 +154,7 @@ bool SSBDemodSettings::deserialize(const QByteArray& data) m_reverseAPIDeviceIndex = utmp > 99 ? 99 : utmp; d.readU32(22, &utmp, 0); m_reverseAPIChannelIndex = utmp > 99 ? 99 : utmp; + d.readS32(23, &m_streamIndex, 0); return true; } diff --git a/plugins/channelrx/demodssb/ssbdemodsettings.h b/plugins/channelrx/demodssb/ssbdemodsettings.h index be9aaf0da..f880ecd90 100644 --- a/plugins/channelrx/demodssb/ssbdemodsettings.h +++ b/plugins/channelrx/demodssb/ssbdemodsettings.h @@ -41,6 +41,7 @@ struct SSBDemodSettings quint32 m_rgbColor; QString m_title; QString m_audioDeviceName; + int m_streamIndex; //!< MIMO channel. Not relevant when connected to SI (single Rx). bool m_useReverseAPI; QString m_reverseAPIAddress; uint16_t m_reverseAPIPort; diff --git a/plugins/channelrx/demodwfm/wfmdemod.cpp b/plugins/channelrx/demodwfm/wfmdemod.cpp index b8667f31e..eb93adbb1 100644 --- a/plugins/channelrx/demodwfm/wfmdemod.cpp +++ b/plugins/channelrx/demodwfm/wfmdemod.cpp @@ -37,6 +37,8 @@ #include "audio/audiooutput.h" #include "dsp/dspengine.h" #include "dsp/dspcommands.h" +#include "dsp/devicesamplemimo.h" +#include "device/deviceapi.h" #include "util/db.h" #include "wfmdemod.h" @@ -97,6 +99,11 @@ WFMDemod::~WFMDemod() delete m_rfFilter; } +uint32_t WFMDemod::getNumberOfDeviceStreams() const +{ + return m_deviceAPI->getNbSourceStreams(); +} + void WFMDemod::feed(const SampleVector::const_iterator& begin, const SampleVector::const_iterator& end, bool firstOfBurst) { (void) firstOfBurst; @@ -328,6 +335,7 @@ void WFMDemod::applySettings(const WFMDemodSettings& settings, bool force) << " m_squelch: " << settings.m_squelch << " m_audioDeviceName: " << settings.m_audioDeviceName << " m_audioMute: " << settings.m_audioMute + << " m_streamIndex: " << settings.m_streamIndex << " m_useReverseAPI: " << settings.m_useReverseAPI << " m_reverseAPIAddress: " << settings.m_reverseAPIAddress << " m_reverseAPIPort: " << settings.m_reverseAPIPort @@ -402,6 +410,21 @@ void WFMDemod::applySettings(const WFMDemodSettings& settings, bool force) } } + if (m_settings.m_streamIndex != settings.m_streamIndex) + { + if (m_deviceAPI->getSampleMIMO()) // change of stream is possible for MIMO devices only + { + m_deviceAPI->removeChannelSinkAPI(this, m_settings.m_streamIndex); + m_deviceAPI->removeChannelSink(m_threadedChannelizer, m_settings.m_streamIndex); + m_deviceAPI->addChannelSink(m_threadedChannelizer, settings.m_streamIndex); + m_deviceAPI->addChannelSinkAPI(this, settings.m_streamIndex); + // apply stream sample rate to itself + applyChannelSettings(m_deviceAPI->getSampleMIMO()->getSourceSampleRate(settings.m_streamIndex), m_inputFrequencyOffset); + } + + reverseAPIKeys.append("streamIndex"); + } + if (settings.m_useReverseAPI) { bool fullUpdate = ((m_settings.m_useReverseAPI != settings.m_useReverseAPI) && settings.m_useReverseAPI) || @@ -512,6 +535,9 @@ void WFMDemod::webapiUpdateChannelSettings( if (channelSettingsKeys.contains("audioDeviceName")) { settings.m_audioDeviceName = *response.getWfmDemodSettings()->getAudioDeviceName(); } + if (channelSettingsKeys.contains("streamIndex")) { + settings.m_streamIndex = response.getWfmDemodSettings()->getStreamIndex(); + } if (channelSettingsKeys.contains("useReverseAPI")) { settings.m_useReverseAPI = response.getWfmDemodSettings()->getUseReverseApi() != 0; } @@ -562,6 +588,7 @@ void WFMDemod::webapiFormatChannelSettings(SWGSDRangel::SWGChannelSettings& resp response.getWfmDemodSettings()->setAudioDeviceName(new QString(settings.m_audioDeviceName)); } + response.getWfmDemodSettings()->setStreamIndex(settings.m_streamIndex); response.getWfmDemodSettings()->setUseReverseApi(settings.m_useReverseAPI ? 1 : 0); if (response.getWfmDemodSettings()->getReverseApiAddress()) { @@ -626,6 +653,9 @@ void WFMDemod::webapiReverseSendSettings(QList<QString>& channelSettingsKeys, co if (channelSettingsKeys.contains("audioDeviceName") || force) { swgWFMDemodSettings->setAudioDeviceName(new QString(settings.m_audioDeviceName)); } + if (channelSettingsKeys.contains("streamIndex") || force) { + swgWFMDemodSettings->setStreamIndex(settings.m_streamIndex); + } QString channelSettingsURL = QString("http://%1:%2/sdrangel/deviceset/%3/channel/%4/settings") .arg(settings.m_reverseAPIAddress) diff --git a/plugins/channelrx/demodwfm/wfmdemod.h b/plugins/channelrx/demodwfm/wfmdemod.h index 3e1465562..147759ab7 100644 --- a/plugins/channelrx/demodwfm/wfmdemod.h +++ b/plugins/channelrx/demodwfm/wfmdemod.h @@ -173,6 +173,8 @@ public: } } + uint32_t getNumberOfDeviceStreams() const; + static const QString m_channelIdURI; static const QString m_channelId; diff --git a/plugins/channelrx/demodwfm/wfmdemodgui.cpp b/plugins/channelrx/demodwfm/wfmdemodgui.cpp index 575f6715d..c1438d0ed 100644 --- a/plugins/channelrx/demodwfm/wfmdemodgui.cpp +++ b/plugins/channelrx/demodwfm/wfmdemodgui.cpp @@ -13,6 +13,7 @@ #include "util/simpleserializer.h" #include "util/db.h" #include "gui/basicchannelsettingsdialog.h" +#include "gui/devicestreamselectiondialog.h" #include "gui/crightclickenabler.h" #include "gui/audioselectdialog.h" #include "mainwindow.h" @@ -194,6 +195,20 @@ void WFMDemodGUI::onMenuDialogCalled(const QPoint &p) applySettings(); } + else if ((m_contextMenuType == ContextMenuStreamSettings) && (m_deviceUISet->m_deviceMIMOEngine)) + { + DeviceStreamSelectionDialog dialog(this); + dialog.setNumberOfStreams(m_wfmDemod->getNumberOfDeviceStreams()); + dialog.setStreamIndex(m_settings.m_streamIndex); + dialog.move(p); + dialog.exec(); + + m_settings.m_streamIndex = dialog.getSelectedStreamIndex(); + m_channelMarker.clearStreamIndexes(); + m_channelMarker.addStreamIndex(m_settings.m_streamIndex); + displayStreamIndex(); + applySettings(); + } resetContextMenuType(); } @@ -301,9 +316,20 @@ void WFMDemodGUI::displaySettings() ui->squelchText->setText(QString("%1 dB").arg(m_settings.m_squelch)); ui->audioMute->setChecked(m_settings.m_audioMute); + displayStreamIndex(); + blockApplySettings(false); } +void WFMDemodGUI::displayStreamIndex() +{ + if (m_deviceUISet->m_deviceMIMOEngine) { + setStreamIndicator(tr("%1").arg(m_settings.m_streamIndex)); + } else { + setStreamIndicator("S"); // single channel indicator + } +} + void WFMDemodGUI::leaveEvent(QEvent*) { m_channelMarker.setHighlighted(false); diff --git a/plugins/channelrx/demodwfm/wfmdemodgui.h b/plugins/channelrx/demodwfm/wfmdemodgui.h index 650bfe535..a1a64ae25 100644 --- a/plugins/channelrx/demodwfm/wfmdemodgui.h +++ b/plugins/channelrx/demodwfm/wfmdemodgui.h @@ -59,6 +59,7 @@ private: void blockApplySettings(bool block); void applySettings(bool force = false); void displaySettings(); + void displayStreamIndex(); void leaveEvent(QEvent*); void enterEvent(QEvent*); diff --git a/plugins/channelrx/demodwfm/wfmdemodsettings.cpp b/plugins/channelrx/demodwfm/wfmdemodsettings.cpp index 50539a138..87cb26bb4 100644 --- a/plugins/channelrx/demodwfm/wfmdemodsettings.cpp +++ b/plugins/channelrx/demodwfm/wfmdemodsettings.cpp @@ -45,6 +45,7 @@ void WFMDemodSettings::resetToDefaults() m_rgbColor = QColor(0, 0, 255).rgb(); m_title = "WFM Demodulator"; m_audioDeviceName = AudioDeviceManager::m_defaultDeviceName; + m_streamIndex = 0; m_useReverseAPI = false; m_reverseAPIAddress = "127.0.0.1"; m_reverseAPIPort = 8888; @@ -73,6 +74,7 @@ QByteArray WFMDemodSettings::serialize() const s.writeU32(14, m_reverseAPIPort); s.writeU32(15, m_reverseAPIDeviceIndex); s.writeU32(16, m_reverseAPIChannelIndex); + s.writeS32(17, m_streamIndex); return s.final(); } @@ -128,6 +130,7 @@ bool WFMDemodSettings::deserialize(const QByteArray& data) m_reverseAPIDeviceIndex = utmp > 99 ? 99 : utmp; d.readU32(16, &utmp, 0); m_reverseAPIChannelIndex = utmp > 99 ? 99 : utmp; + d.readS32(17, &m_streamIndex, 0); return true; } diff --git a/plugins/channelrx/demodwfm/wfmdemodsettings.h b/plugins/channelrx/demodwfm/wfmdemodsettings.h index e0a4d1389..a56ac1323 100644 --- a/plugins/channelrx/demodwfm/wfmdemodsettings.h +++ b/plugins/channelrx/demodwfm/wfmdemodsettings.h @@ -34,6 +34,7 @@ struct WFMDemodSettings quint32 m_rgbColor; QString m_title; QString m_audioDeviceName; + int m_streamIndex; //!< MIMO channel. Not relevant when connected to SI (single Rx). bool m_useReverseAPI; QString m_reverseAPIAddress; uint16_t m_reverseAPIPort; diff --git a/plugins/channelrx/freqtracker/freqtracker.cpp b/plugins/channelrx/freqtracker/freqtracker.cpp index 3ca7fc2cf..586ad38d6 100644 --- a/plugins/channelrx/freqtracker/freqtracker.cpp +++ b/plugins/channelrx/freqtracker/freqtracker.cpp @@ -38,6 +38,7 @@ #include "dsp/threadedbasebandsamplesink.h" #include "dsp/dspcommands.h" #include "dsp/fftfilt.h" +#include "dsp/devicesamplemimo.h" #include "device/deviceapi.h" #include "util/db.h" #include "util/stepfunctions.h" @@ -109,6 +110,11 @@ FreqTracker::~FreqTracker() delete m_rrcFilter; } +uint32_t FreqTracker::getNumberOfDeviceStreams() const +{ + return m_deviceAPI->getNbSourceStreams(); +} + void FreqTracker::feed(const SampleVector::const_iterator& begin, const SampleVector::const_iterator& end, bool firstOfBurst) { (void) firstOfBurst; @@ -333,6 +339,7 @@ void FreqTracker::applySettings(const FreqTrackerSettings& settings, bool force) << " m_pllPskOrder: " << settings.m_pllPskOrder << " m_rrc: " << settings.m_rrc << " m_rrcRolloff: " << settings.m_rrcRolloff + << " m_streamIndex: " << settings.m_streamIndex << " m_useReverseAPI: " << settings.m_useReverseAPI << " m_reverseAPIAddress: " << settings.m_reverseAPIAddress << " m_reverseAPIPort: " << settings.m_reverseAPIPort @@ -434,6 +441,21 @@ void FreqTracker::applySettings(const FreqTrackerSettings& settings, bool force) updateInterpolator = true; } + if (m_settings.m_streamIndex != settings.m_streamIndex) + { + if (m_deviceAPI->getSampleMIMO()) // change of stream is possible for MIMO devices only + { + m_deviceAPI->removeChannelSinkAPI(this, m_settings.m_streamIndex); + m_deviceAPI->removeChannelSink(m_threadedChannelizer, m_settings.m_streamIndex); + m_deviceAPI->addChannelSink(m_threadedChannelizer, settings.m_streamIndex); + m_deviceAPI->addChannelSinkAPI(this, settings.m_streamIndex); + // apply stream sample rate to itself + applyChannelSettings(m_deviceAPI->getSampleMIMO()->getSourceSampleRate(settings.m_streamIndex), m_inputFrequencyOffset); + } + + reverseAPIKeys.append("streamIndex"); + } + if (settings.m_useReverseAPI) { bool fullUpdate = ((m_settings.m_useReverseAPI != settings.m_useReverseAPI) && settings.m_useReverseAPI) || @@ -618,6 +640,9 @@ void FreqTracker::webapiUpdateChannelSettings( if (channelSettingsKeys.contains("squelchGate")) { settings.m_squelchGate = response.getFreqTrackerSettings()->getSquelchGate(); } + if (channelSettingsKeys.contains("streamIndex")) { + settings.m_streamIndex = response.getFreqTrackerSettings()->getStreamIndex(); + } if (channelSettingsKeys.contains("useReverseAPI")) { settings.m_useReverseAPI = response.getFreqTrackerSettings()->getUseReverseApi() != 0; } @@ -667,6 +692,7 @@ void FreqTracker::webapiFormatChannelSettings(SWGSDRangel::SWGChannelSettings& r response.getFreqTrackerSettings()->setRrc(settings.m_rrc ? 1 : 0); response.getFreqTrackerSettings()->setRrcRolloff(settings.m_rrcRolloff); response.getFreqTrackerSettings()->setSquelchGate(settings.m_squelchGate); + response.getFreqTrackerSettings()->setStreamIndex(settings.m_streamIndex); response.getFreqTrackerSettings()->setUseReverseApi(settings.m_useReverseAPI ? 1 : 0); if (response.getFreqTrackerSettings()->getReverseApiAddress()) { @@ -722,6 +748,9 @@ void FreqTracker::webapiReverseSendSettings(QList<QString>& channelSettingsKeys, if (channelSettingsKeys.contains("trackerType") || force) { swgFreqTrackerSettings->setTrackerType((int) settings.m_trackerType); } + if (channelSettingsKeys.contains("streamIndex") || force) { + swgFreqTrackerSettings->setStreamIndex(settings.m_streamIndex); + } QString channelSettingsURL = QString("http://%1:%2/sdrangel/deviceset/%3/channel/%4/settings") .arg(settings.m_reverseAPIAddress) diff --git a/plugins/channelrx/freqtracker/freqtracker.h b/plugins/channelrx/freqtracker/freqtracker.h index 969076e75..d16388103 100644 --- a/plugins/channelrx/freqtracker/freqtracker.h +++ b/plugins/channelrx/freqtracker/freqtracker.h @@ -191,6 +191,8 @@ public: m_magsqCount = 0; } + uint32_t getNumberOfDeviceStreams() const; + static const QString m_channelIdURI; static const QString m_channelId; diff --git a/plugins/channelrx/freqtracker/freqtrackergui.cpp b/plugins/channelrx/freqtracker/freqtrackergui.cpp index 3cf9248b4..6b48f6277 100644 --- a/plugins/channelrx/freqtracker/freqtrackergui.cpp +++ b/plugins/channelrx/freqtracker/freqtrackergui.cpp @@ -30,6 +30,7 @@ #include "util/simpleserializer.h" #include "util/db.h" #include "gui/basicchannelsettingsdialog.h" +#include "gui/devicestreamselectiondialog.h" #include "dsp/dspengine.h" #include "mainwindow.h" #include "gui/crightclickenabler.h" @@ -271,6 +272,20 @@ void FreqTrackerGUI::onMenuDialogCalled(const QPoint &p) applySettings(); } + else if ((m_contextMenuType == ContextMenuStreamSettings) && (m_deviceUISet->m_deviceMIMOEngine)) + { + DeviceStreamSelectionDialog dialog(this); + dialog.setNumberOfStreams(m_freqTracker->getNumberOfDeviceStreams()); + dialog.setStreamIndex(m_settings.m_streamIndex); + dialog.move(p); + dialog.exec(); + + m_settings.m_streamIndex = dialog.getSelectedStreamIndex(); + m_channelMarker.clearStreamIndexes(); + m_channelMarker.addStreamIndex(m_settings.m_streamIndex); + displayStreamIndex(); + applySettings(); + } resetContextMenuType(); } @@ -383,9 +398,20 @@ void FreqTrackerGUI::displaySettings() ui->squelchGateText->setText(QString("%1").arg(m_settings.m_squelchGate * 10.0f, 0, 'f', 0)); ui->squelchGate->setValue(m_settings.m_squelchGate); + displayStreamIndex(); + blockApplySettings(false); } +void FreqTrackerGUI::displayStreamIndex() +{ + if (m_deviceUISet->m_deviceMIMOEngine) { + setStreamIndicator(tr("%1").arg(m_settings.m_streamIndex)); + } else { + setStreamIndicator("S"); // single channel indicator + } +} + void FreqTrackerGUI::leaveEvent(QEvent*) { m_channelMarker.setHighlighted(false); diff --git a/plugins/channelrx/freqtracker/freqtrackergui.h b/plugins/channelrx/freqtracker/freqtrackergui.h index 78cc3db04..ada35e14a 100644 --- a/plugins/channelrx/freqtracker/freqtrackergui.h +++ b/plugins/channelrx/freqtracker/freqtrackergui.h @@ -79,6 +79,7 @@ private: void blockApplySettings(bool block); void applySettings(bool force = false); void displaySettings(); + void displayStreamIndex(); void leaveEvent(QEvent*); void enterEvent(QEvent*); diff --git a/plugins/channelrx/freqtracker/freqtrackersettings.cpp b/plugins/channelrx/freqtracker/freqtrackersettings.cpp index 90712d06e..65f2c4f53 100644 --- a/plugins/channelrx/freqtracker/freqtrackersettings.cpp +++ b/plugins/channelrx/freqtracker/freqtrackersettings.cpp @@ -43,6 +43,7 @@ void FreqTrackerSettings::resetToDefaults() m_rrc = false; m_rrcRolloff = 35; m_squelchGate = 5; // 50 ms + m_streamIndex = 0; m_useReverseAPI = false; m_reverseAPIAddress = "127.0.0.1"; m_reverseAPIPort = 8888; @@ -76,6 +77,7 @@ QByteArray FreqTrackerSettings::serialize() const s.writeU32(19, m_reverseAPIDeviceIndex); s.writeU32(20, m_reverseAPIChannelIndex); s.writeS32(21, m_squelchGate); + s.writeS32(22, m_streamIndex); return s.final(); } @@ -140,6 +142,7 @@ bool FreqTrackerSettings::deserialize(const QByteArray& data) m_reverseAPIChannelIndex = utmp > 99 ? 99 : utmp; d.readS32(21, &tmp, 5); m_squelchGate = tmp < 0 ? 0 : tmp > 99 ? 99 : tmp; + d.readS32(22, &m_streamIndex, 0); return true; } diff --git a/plugins/channelrx/freqtracker/freqtrackersettings.h b/plugins/channelrx/freqtracker/freqtrackersettings.h index 72057c9e5..aabd85f7e 100644 --- a/plugins/channelrx/freqtracker/freqtrackersettings.h +++ b/plugins/channelrx/freqtracker/freqtrackersettings.h @@ -48,6 +48,7 @@ struct FreqTrackerSettings bool m_rrc; uint32_t m_rrcRolloff; //!< in 100ths int m_squelchGate; //!< in 10s of ms + int m_streamIndex; //!< MIMO channel. Not relevant when connected to SI (single Rx). bool m_useReverseAPI; QString m_reverseAPIAddress; uint16_t m_reverseAPIPort; diff --git a/plugins/channelrx/localsink/localsink.cpp b/plugins/channelrx/localsink/localsink.cpp index 4422685fd..faeed9e71 100644 --- a/plugins/channelrx/localsink/localsink.cpp +++ b/plugins/channelrx/localsink/localsink.cpp @@ -34,6 +34,7 @@ #include "dsp/dspengine.h" #include "dsp/devicesamplesource.h" #include "dsp/hbfilterchainconverter.h" +#include "dsp/devicesamplemimo.h" #include "device/deviceapi.h" #include "localsinkthread.h" @@ -76,6 +77,11 @@ LocalSink::~LocalSink() delete m_channelizer; } +uint32_t LocalSink::getNumberOfDeviceStreams() const +{ + return m_deviceAPI->getNbSourceStreams(); +} + void LocalSink::feed(const SampleVector::const_iterator& begin, const SampleVector::const_iterator& end, bool firstOfBurst) { (void) firstOfBurst; @@ -288,6 +294,7 @@ void LocalSink::applySettings(const LocalSinkSettings& settings, bool force) { qDebug() << "LocalSink::applySettings:" << " m_localDeviceIndex: " << settings.m_localDeviceIndex + << " m_streamIndex: " << settings.m_streamIndex << " force: " << force; QList<QString> reverseAPIKeys; @@ -311,6 +318,21 @@ void LocalSink::applySettings(const LocalSinkSettings& settings, bool force) } } + if (m_settings.m_streamIndex != settings.m_streamIndex) + { + if (m_deviceAPI->getSampleMIMO()) // change of stream is possible for MIMO devices only + { + m_deviceAPI->removeChannelSinkAPI(this, m_settings.m_streamIndex); + m_deviceAPI->removeChannelSink(m_threadedChannelizer, m_settings.m_streamIndex); + m_deviceAPI->addChannelSink(m_threadedChannelizer, settings.m_streamIndex); + m_deviceAPI->addChannelSinkAPI(this, settings.m_streamIndex); + // apply stream sample rate to itself + //applyChannelSettings(m_deviceAPI->getSampleMIMO()->getSourceSampleRate(settings.m_streamIndex), m_inputFrequencyOffset); + } + + reverseAPIKeys.append("streamIndex"); + } + if ((settings.m_useReverseAPI) && (reverseAPIKeys.size() != 0)) { bool fullUpdate = ((m_settings.m_useReverseAPI != settings.m_useReverseAPI) && settings.m_useReverseAPI) || @@ -407,6 +429,9 @@ void LocalSink::webapiUpdateChannelSettings( validateFilterChainHash(settings); } + if (channelSettingsKeys.contains("streamIndex")) { + settings.m_streamIndex = response.getLocalSinkSettings()->getStreamIndex(); + } if (channelSettingsKeys.contains("useReverseAPI")) { settings.m_useReverseAPI = response.getLocalSinkSettings()->getUseReverseApi() != 0; } @@ -437,6 +462,7 @@ void LocalSink::webapiFormatChannelSettings(SWGSDRangel::SWGChannelSettings& res response.getLocalSinkSettings()->setLog2Decim(settings.m_log2Decim); response.getLocalSinkSettings()->setFilterChainHash(settings.m_filterChainHash); + response.getLocalSinkSettings()->setStreamIndex(settings.m_streamIndex); response.getLocalSinkSettings()->setUseReverseApi(settings.m_useReverseAPI ? 1 : 0); if (response.getLocalSinkSettings()->getReverseApiAddress()) { @@ -477,6 +503,9 @@ void LocalSink::webapiReverseSendSettings(QList<QString>& channelSettingsKeys, c if (channelSettingsKeys.contains("filterChainHash") || force) { swgLocalSinkSettings->setFilterChainHash(settings.m_filterChainHash); } + if (channelSettingsKeys.contains("streamIndex") || force) { + swgLocalSinkSettings->setStreamIndex(settings.m_streamIndex); + } QString channelSettingsURL = QString("http://%1:%2/sdrangel/deviceset/%3/channel/%4/settings") .arg(settings.m_reverseAPIAddress) diff --git a/plugins/channelrx/localsink/localsink.h b/plugins/channelrx/localsink/localsink.h index 047ebff99..bbde80277 100644 --- a/plugins/channelrx/localsink/localsink.h +++ b/plugins/channelrx/localsink/localsink.h @@ -155,6 +155,7 @@ public: void setChannelizer(unsigned int log2Decim, unsigned int filterChainHash); void getLocalDevices(std::vector<uint32_t>& indexes); + uint32_t getNumberOfDeviceStreams() const; static const QString m_channelIdURI; static const QString m_channelId; diff --git a/plugins/channelrx/localsink/localsinkgui.cpp b/plugins/channelrx/localsink/localsinkgui.cpp index 30a11a121..ec462d095 100644 --- a/plugins/channelrx/localsink/localsinkgui.cpp +++ b/plugins/channelrx/localsink/localsinkgui.cpp @@ -19,6 +19,7 @@ #include "device/deviceuiset.h" #include "gui/basicchannelsettingsdialog.h" +#include "gui/devicestreamselectiondialog.h" #include "dsp/hbfilterchainconverter.h" #include "mainwindow.h" @@ -194,9 +195,19 @@ void LocalSinkGUI::displaySettings() blockApplySettings(true); ui->decimationFactor->setCurrentIndex(m_settings.m_log2Decim); applyDecimation(); + displayStreamIndex(); blockApplySettings(false); } +void LocalSinkGUI::displayStreamIndex() +{ + if (m_deviceUISet->m_deviceMIMOEngine) { + setStreamIndicator(tr("%1").arg(m_settings.m_streamIndex)); + } else { + setStreamIndicator("S"); // single channel indicator + } +} + void LocalSinkGUI::displayRateAndShift() { int shift = m_shiftFrequencyFactor * m_sampleRate; @@ -276,6 +287,20 @@ void LocalSinkGUI::onMenuDialogCalled(const QPoint &p) applySettings(); } + else if ((m_contextMenuType == ContextMenuStreamSettings) && (m_deviceUISet->m_deviceMIMOEngine)) + { + DeviceStreamSelectionDialog dialog(this); + dialog.setNumberOfStreams(m_localSink->getNumberOfDeviceStreams()); + dialog.setStreamIndex(m_settings.m_streamIndex); + dialog.move(p); + dialog.exec(); + + m_settings.m_streamIndex = dialog.getSelectedStreamIndex(); + m_channelMarker.clearStreamIndexes(); + m_channelMarker.addStreamIndex(m_settings.m_streamIndex); + displayStreamIndex(); + applySettings(); + } resetContextMenuType(); } diff --git a/plugins/channelrx/localsink/localsinkgui.h b/plugins/channelrx/localsink/localsinkgui.h index 2c6af1eea..123d8c101 100644 --- a/plugins/channelrx/localsink/localsinkgui.h +++ b/plugins/channelrx/localsink/localsinkgui.h @@ -79,6 +79,7 @@ private: void applySettings(bool force = false); void applyChannelSettings(); void displaySettings(); + void displayStreamIndex(); void displayRateAndShift(); void updateLocalDevices(); diff --git a/plugins/channelrx/localsink/localsinksettings.cpp b/plugins/channelrx/localsink/localsinksettings.cpp index 7d1300faa..bdda42e29 100644 --- a/plugins/channelrx/localsink/localsinksettings.cpp +++ b/plugins/channelrx/localsink/localsinksettings.cpp @@ -36,6 +36,7 @@ void LocalSinkSettings::resetToDefaults() m_log2Decim = 0; m_filterChainHash = 0; m_channelMarker = nullptr; + m_streamIndex = 0; m_useReverseAPI = false; m_reverseAPIAddress = "127.0.0.1"; m_reverseAPIPort = 8888; @@ -56,6 +57,7 @@ QByteArray LocalSinkSettings::serialize() const s.writeU32(11, m_reverseAPIChannelIndex); s.writeU32(12, m_log2Decim); s.writeU32(13, m_filterChainHash); + s.writeS32(14, m_streamIndex); return s.final(); } @@ -95,6 +97,7 @@ bool LocalSinkSettings::deserialize(const QByteArray& data) d.readU32(12, &tmp, 0); m_log2Decim = tmp > 6 ? 6 : tmp; d.readU32(13, &m_filterChainHash, 0); + d.readS32(14, &m_streamIndex, 0); return true; } diff --git a/plugins/channelrx/localsink/localsinksettings.h b/plugins/channelrx/localsink/localsinksettings.h index f0523d149..a3b5189b6 100644 --- a/plugins/channelrx/localsink/localsinksettings.h +++ b/plugins/channelrx/localsink/localsinksettings.h @@ -30,6 +30,7 @@ struct LocalSinkSettings QString m_title; uint32_t m_log2Decim; uint32_t m_filterChainHash; + int m_streamIndex; //!< MIMO channel. Not relevant when connected to SI (single Rx). bool m_useReverseAPI; QString m_reverseAPIAddress; uint16_t m_reverseAPIPort; diff --git a/plugins/channelrx/remotesink/remotesink.cpp b/plugins/channelrx/remotesink/remotesink.cpp index 32e38b5eb..60e6e2355 100644 --- a/plugins/channelrx/remotesink/remotesink.cpp +++ b/plugins/channelrx/remotesink/remotesink.cpp @@ -44,6 +44,7 @@ #include "dsp/downchannelizer.h" #include "dsp/dspcommands.h" #include "dsp/hbfilterchainconverter.h" +#include "dsp/devicesamplemimo.h" #include "device/deviceapi.h" #include "remotesinkthread.h" @@ -120,6 +121,11 @@ void RemoteSink::setNbBlocksFEC(int nbBlocksFEC) m_nbBlocksFEC = nbBlocksFEC; } +uint32_t RemoteSink::getNumberOfDeviceStreams() const +{ + return m_deviceAPI->getNbSourceStreams(); +} + void RemoteSink::feed(const SampleVector::const_iterator& begin, const SampleVector::const_iterator& end, bool firstOfBurst) { (void) firstOfBurst; @@ -370,6 +376,7 @@ void RemoteSink::applySettings(const RemoteSinkSettings& settings, bool force) << " m_txDelay: " << settings.m_txDelay << " m_dataAddress: " << settings.m_dataAddress << " m_dataPort: " << settings.m_dataPort + << " m_streamIndex: " << settings.m_streamIndex << " force: " << force; QList<QString> reverseAPIKeys; @@ -399,6 +406,21 @@ void RemoteSink::applySettings(const RemoteSinkSettings& settings, bool force) m_dataPort = settings.m_dataPort; } + if (m_settings.m_streamIndex != settings.m_streamIndex) + { + if (m_deviceAPI->getSampleMIMO()) // change of stream is possible for MIMO devices only + { + m_deviceAPI->removeChannelSinkAPI(this, m_settings.m_streamIndex); + m_deviceAPI->removeChannelSink(m_threadedChannelizer, m_settings.m_streamIndex); + m_deviceAPI->addChannelSink(m_threadedChannelizer, settings.m_streamIndex); + m_deviceAPI->addChannelSinkAPI(this, settings.m_streamIndex); + // apply stream sample rate to itself + //applyChannelSettings(m_deviceAPI->getSampleMIMO()->getSourceSampleRate(settings.m_streamIndex), m_inputFrequencyOffset); + } + + reverseAPIKeys.append("streamIndex"); + } + if ((settings.m_useReverseAPI) && (reverseAPIKeys.size() != 0)) { bool fullUpdate = ((m_settings.m_useReverseAPI != settings.m_useReverseAPI) && settings.m_useReverseAPI) || @@ -529,6 +551,10 @@ void RemoteSink::webapiUpdateChannelSettings( validateFilterChainHash(settings); } + if (channelSettingsKeys.contains("streamIndex")) { + settings.m_streamIndex = response.getRemoteSinkSettings()->getStreamIndex(); + } + if (channelSettingsKeys.contains("useReverseAPI")) { settings.m_useReverseAPI = response.getRemoteSinkSettings()->getUseReverseApi() != 0; } @@ -568,6 +594,7 @@ void RemoteSink::webapiFormatChannelSettings(SWGSDRangel::SWGChannelSettings& re response.getRemoteSinkSettings()->setLog2Decim(settings.m_log2Decim); response.getRemoteSinkSettings()->setFilterChainHash(settings.m_filterChainHash); + response.getRemoteSinkSettings()->setStreamIndex(settings.m_streamIndex); response.getRemoteSinkSettings()->setUseReverseApi(settings.m_useReverseAPI ? 1 : 0); if (response.getRemoteSinkSettings()->getReverseApiAddress()) { @@ -618,6 +645,9 @@ void RemoteSink::webapiReverseSendSettings(QList<QString>& channelSettingsKeys, if (channelSettingsKeys.contains("filterChainHash") || force) { swgRemoteSinkSettings->setFilterChainHash(settings.m_filterChainHash); } + if (channelSettingsKeys.contains("streamIndex") || force) { + swgRemoteSinkSettings->setStreamIndex(settings.m_streamIndex); + } QString channelSettingsURL = QString("http://%1:%2/sdrangel/deviceset/%3/channel/%4/settings") .arg(settings.m_reverseAPIAddress) diff --git a/plugins/channelrx/remotesink/remotesink.h b/plugins/channelrx/remotesink/remotesink.h index 81fcfb139..277b33df6 100644 --- a/plugins/channelrx/remotesink/remotesink.h +++ b/plugins/channelrx/remotesink/remotesink.h @@ -166,6 +166,8 @@ public: void setDataPort(uint16_t port) { m_dataPort = port; } void setChannelizer(unsigned int log2Decim, unsigned int filterChainHash); + uint32_t getNumberOfDeviceStreams() const; + static const QString m_channelIdURI; static const QString m_channelId; diff --git a/plugins/channelrx/remotesink/remotesinkgui.cpp b/plugins/channelrx/remotesink/remotesinkgui.cpp index f075b2548..3270d13a6 100644 --- a/plugins/channelrx/remotesink/remotesinkgui.cpp +++ b/plugins/channelrx/remotesink/remotesinkgui.cpp @@ -19,6 +19,7 @@ #include "device/deviceuiset.h" #include "gui/basicchannelsettingsdialog.h" +#include "gui/devicestreamselectiondialog.h" #include "dsp/hbfilterchainconverter.h" #include "mainwindow.h" @@ -202,9 +203,19 @@ void RemoteSinkGUI::displaySettings() ui->txDelay->setValue(m_settings.m_txDelay); updateTxDelayTime(); applyDecimation(); + displayStreamIndex(); blockApplySettings(false); } +void RemoteSinkGUI::displayStreamIndex() +{ + if (m_deviceUISet->m_deviceMIMOEngine) { + setStreamIndicator(tr("%1").arg(m_settings.m_streamIndex)); + } else { + setStreamIndicator("S"); // single channel indicator + } +} + void RemoteSinkGUI::displayRateAndShift() { int shift = m_shiftFrequencyFactor * m_sampleRate; @@ -272,6 +283,20 @@ void RemoteSinkGUI::onMenuDialogCalled(const QPoint &p) applySettings(); } + else if ((m_contextMenuType == ContextMenuStreamSettings) && (m_deviceUISet->m_deviceMIMOEngine)) + { + DeviceStreamSelectionDialog dialog(this); + dialog.setNumberOfStreams(m_remoteSink->getNumberOfDeviceStreams()); + dialog.setStreamIndex(m_settings.m_streamIndex); + dialog.move(p); + dialog.exec(); + + m_settings.m_streamIndex = dialog.getSelectedStreamIndex(); + m_channelMarker.clearStreamIndexes(); + m_channelMarker.addStreamIndex(m_settings.m_streamIndex); + displayStreamIndex(); + applySettings(); + } resetContextMenuType(); } diff --git a/plugins/channelrx/remotesink/remotesinkgui.h b/plugins/channelrx/remotesink/remotesinkgui.h index 693890a70..dd48ce0f7 100644 --- a/plugins/channelrx/remotesink/remotesinkgui.h +++ b/plugins/channelrx/remotesink/remotesinkgui.h @@ -80,6 +80,7 @@ private: void applySettings(bool force = false); void applyChannelSettings(); void displaySettings(); + void displayStreamIndex(); void displayRateAndShift(); void updateTxDelayTime(); diff --git a/plugins/channelrx/remotesink/remotesinksettings.cpp b/plugins/channelrx/remotesink/remotesinksettings.cpp index b07aa1db0..b6fdb8d31 100644 --- a/plugins/channelrx/remotesink/remotesinksettings.cpp +++ b/plugins/channelrx/remotesink/remotesinksettings.cpp @@ -45,6 +45,7 @@ void RemoteSinkSettings::resetToDefaults() m_log2Decim = 0; m_filterChainHash = 0; m_channelMarker = nullptr; + m_streamIndex = 0; m_useReverseAPI = false; m_reverseAPIAddress = "127.0.0.1"; m_reverseAPIPort = 8888; @@ -68,6 +69,7 @@ QByteArray RemoteSinkSettings::serialize() const s.writeU32(11, m_reverseAPIChannelIndex); s.writeU32(12, m_log2Decim); s.writeU32(13, m_filterChainHash); + s.writeS32(14, m_streamIndex); return s.final(); } @@ -124,6 +126,7 @@ bool RemoteSinkSettings::deserialize(const QByteArray& data) d.readU32(12, &tmp, 0); m_log2Decim = tmp > 6 ? 6 : tmp; d.readU32(13, &m_filterChainHash, 0); + d.readS32(14, &m_streamIndex, 0); return true; } diff --git a/plugins/channelrx/remotesink/remotesinksettings.h b/plugins/channelrx/remotesink/remotesinksettings.h index f82bf52b6..d2ce54b96 100644 --- a/plugins/channelrx/remotesink/remotesinksettings.h +++ b/plugins/channelrx/remotesink/remotesinksettings.h @@ -39,6 +39,7 @@ struct RemoteSinkSettings QString m_title; uint32_t m_log2Decim; uint32_t m_filterChainHash; + int m_streamIndex; //!< MIMO channel. Not relevant when connected to SI (single Rx). bool m_useReverseAPI; QString m_reverseAPIAddress; uint16_t m_reverseAPIPort; diff --git a/plugins/channelrx/udpsink/udpsink.cpp b/plugins/channelrx/udpsink/udpsink.cpp index 7101ba920..683cf332b 100644 --- a/plugins/channelrx/udpsink/udpsink.cpp +++ b/plugins/channelrx/udpsink/udpsink.cpp @@ -32,6 +32,7 @@ #include "dsp/downchannelizer.h" #include "dsp/threadedbasebandsamplesink.h" #include "dsp/dspcommands.h" +#include "dsp/devicesamplemimo.h" #include "device/deviceapi.h" #include "udpsink.h" @@ -142,6 +143,11 @@ void UDPSink::setSpectrum(MessageQueue* messageQueue, bool enabled) messageQueue->push(cmd); } +uint32_t UDPSink::getNumberOfDeviceStreams() const +{ + return m_deviceAPI->getNbSourceStreams(); +} + void UDPSink::feed(const SampleVector::const_iterator& begin, const SampleVector::const_iterator& end, bool positiveOnly) { Complex ci; @@ -512,6 +518,7 @@ void UDPSink::applySettings(const UDPSinkSettings& settings, bool force) << " m_udpAddressStr: " << settings.m_udpAddress << " m_udpPort: " << settings.m_udpPort << " m_audioPort: " << settings.m_audioPort + << " m_streamIndex: " << settings.m_streamIndex << " m_useReverseAPI: " << settings.m_useReverseAPI << " m_reverseAPIAddress: " << settings.m_reverseAPIAddress << " m_reverseAPIPort: " << settings.m_reverseAPIPort @@ -682,6 +689,21 @@ void UDPSink::applySettings(const UDPSinkSettings& settings, bool force) m_settingsMutex.unlock(); + if (m_settings.m_streamIndex != settings.m_streamIndex) + { + if (m_deviceAPI->getSampleMIMO()) // change of stream is possible for MIMO devices only + { + m_deviceAPI->removeChannelSinkAPI(this, m_settings.m_streamIndex); + m_deviceAPI->removeChannelSink(m_threadedChannelizer, m_settings.m_streamIndex); + m_deviceAPI->addChannelSink(m_threadedChannelizer, settings.m_streamIndex); + m_deviceAPI->addChannelSinkAPI(this, settings.m_streamIndex); + // apply stream sample rate to itself + applyChannelSettings(m_deviceAPI->getSampleMIMO()->getSourceSampleRate(settings.m_streamIndex), m_inputFrequencyOffset); + } + + reverseAPIKeys.append("streamIndex"); + } + if (settings.m_useReverseAPI) { bool fullUpdate = ((m_settings.m_useReverseAPI != settings.m_useReverseAPI) && settings.m_useReverseAPI) || @@ -823,6 +845,9 @@ void UDPSink::webapiUpdateChannelSettings( if (channelSettingsKeys.contains("title")) { settings.m_title = *response.getUdpSinkSettings()->getTitle(); } + if (channelSettingsKeys.contains("streamIndex")) { + settings.m_streamIndex = response.getUdpSinkSettings()->getStreamIndex(); + } if (channelSettingsKeys.contains("useReverseAPI")) { settings.m_useReverseAPI = response.getUdpSinkSettings()->getUseReverseApi() != 0; } @@ -884,6 +909,7 @@ void UDPSink::webapiFormatChannelSettings(SWGSDRangel::SWGChannelSettings& respo response.getUdpSinkSettings()->setTitle(new QString(settings.m_title)); } + response.getUdpSinkSettings()->setStreamIndex(settings.m_streamIndex); response.getUdpSinkSettings()->setUseReverseApi(settings.m_useReverseAPI ? 1 : 0); if (response.getUdpSinkSettings()->getReverseApiAddress()) { @@ -974,6 +1000,9 @@ void UDPSink::webapiReverseSendSettings(QList<QString>& channelSettingsKeys, con if (channelSettingsKeys.contains("title") || force) { swgUDPSinkSettings->setTitle(new QString(settings.m_title)); } + if (channelSettingsKeys.contains("streamIndex") || force) { + swgUDPSinkSettings->setStreamIndex(settings.m_streamIndex); + } QString channelSettingsURL = QString("http://%1:%2/sdrangel/deviceset/%3/channel/%4/settings") .arg(settings.m_reverseAPIAddress) diff --git a/plugins/channelrx/udpsink/udpsink.h b/plugins/channelrx/udpsink/udpsink.h index 49463e3f8..27e4a9ebe 100644 --- a/plugins/channelrx/udpsink/udpsink.h +++ b/plugins/channelrx/udpsink/udpsink.h @@ -151,6 +151,8 @@ public: const QStringList& channelSettingsKeys, SWGSDRangel::SWGChannelSettings& response); + uint32_t getNumberOfDeviceStreams() const; + static const QString m_channelIdURI; static const QString m_channelId; static const int udpBlockSize = 512; // UDP block size in number of bytes diff --git a/plugins/channelrx/udpsink/udpsinkgui.cpp b/plugins/channelrx/udpsink/udpsinkgui.cpp index 4fdbd823e..442439871 100644 --- a/plugins/channelrx/udpsink/udpsinkgui.cpp +++ b/plugins/channelrx/udpsink/udpsinkgui.cpp @@ -23,6 +23,7 @@ #include "util/simpleserializer.h" #include "util/db.h" #include "gui/basicchannelsettingsdialog.h" +#include "gui/devicestreamselectiondialog.h" #include "ui_udpsinkgui.h" #include "mainwindow.h" @@ -284,11 +285,22 @@ void UDPSinkGUI::displaySettings() ui->applyBtn->setEnabled(false); ui->applyBtn->setStyleSheet("QPushButton { background:rgb(79,79,79); }"); + displayStreamIndex(); + blockApplySettings(false); ui->glSpectrum->setSampleRate(m_settings.m_outputSampleRate); } +void UDPSinkGUI::displayStreamIndex() +{ + if (m_deviceUISet->m_deviceMIMOEngine) { + setStreamIndicator(tr("%1").arg(m_settings.m_streamIndex)); + } else { + setStreamIndicator("S"); // single channel indicator + } +} + void UDPSinkGUI::setSampleFormatIndex(const UDPSinkSettings::SampleFormat& sampleFormat) { switch(sampleFormat) @@ -640,6 +652,20 @@ void UDPSinkGUI::onMenuDialogCalled(const QPoint &p) applySettingsImmediate(); } + else if ((m_contextMenuType == ContextMenuStreamSettings) && (m_deviceUISet->m_deviceMIMOEngine)) + { + DeviceStreamSelectionDialog dialog(this); + dialog.setNumberOfStreams(m_udpSink->getNumberOfDeviceStreams()); + dialog.setStreamIndex(m_settings.m_streamIndex); + dialog.move(p); + dialog.exec(); + + m_settings.m_streamIndex = dialog.getSelectedStreamIndex(); + m_channelMarker.clearStreamIndexes(); + m_channelMarker.addStreamIndex(m_settings.m_streamIndex); + displayStreamIndex(); + applySettings(); + } resetContextMenuType(); } diff --git a/plugins/channelrx/udpsink/udpsinkgui.h b/plugins/channelrx/udpsink/udpsinkgui.h index 95034b123..4854ecb56 100644 --- a/plugins/channelrx/udpsink/udpsinkgui.h +++ b/plugins/channelrx/udpsink/udpsinkgui.h @@ -86,6 +86,7 @@ private: void applySettings(bool force = false); void applySettingsImmediate(bool force = false); void displaySettings(); + void displayStreamIndex(); void setSampleFormat(int index); void setSampleFormatIndex(const UDPSinkSettings::SampleFormat& sampleFormat); diff --git a/plugins/channelrx/udpsink/udpsinksettings.cpp b/plugins/channelrx/udpsink/udpsinksettings.cpp index 28d23b3b1..4113a548f 100644 --- a/plugins/channelrx/udpsink/udpsinksettings.cpp +++ b/plugins/channelrx/udpsink/udpsinksettings.cpp @@ -45,6 +45,7 @@ void UDPSinkSettings::resetToDefaults() m_audioActive = false; m_audioStereo = false; m_volume = 20; + m_streamIndex = 0; m_udpAddress = "127.0.0.1"; m_udpPort = 9998; m_audioPort = 9997; @@ -91,6 +92,7 @@ QByteArray UDPSinkSettings::serialize() const s.writeU32(25, m_reverseAPIPort); s.writeU32(26, m_reverseAPIDeviceIndex); s.writeU32(27, m_reverseAPIChannelIndex); + s.writeS32(28, m_streamIndex); return s.final(); @@ -180,6 +182,7 @@ bool UDPSinkSettings::deserialize(const QByteArray& data) m_reverseAPIDeviceIndex = u32tmp > 99 ? 99 : u32tmp; d.readU32(27, &u32tmp, 0); m_reverseAPIChannelIndex = u32tmp > 99 ? 99 : u32tmp; + d.readS32(28, &m_streamIndex, 0); return true; } diff --git a/plugins/channelrx/udpsink/udpsinksettings.h b/plugins/channelrx/udpsink/udpsinksettings.h index b87be4da5..822e52340 100644 --- a/plugins/channelrx/udpsink/udpsinksettings.h +++ b/plugins/channelrx/udpsink/udpsinksettings.h @@ -63,6 +63,7 @@ struct UDPSinkSettings QString m_title; + int m_streamIndex; //!< MIMO channel. Not relevant when connected to SI (single Rx). bool m_useReverseAPI; QString m_reverseAPIAddress; uint16_t m_reverseAPIPort;