From 62ffcde69f574c80078fd58933b412fe1959ddf1 Mon Sep 17 00:00:00 2001 From: f4exb Date: Sun, 12 May 2024 21:53:09 +0200 Subject: [PATCH] Interferometer: added possibility to send correlated IQ to a Local Input device --- .../interferometer/interferometer.cpp | 130 +++++++++++++++--- .../interferometer/interferometer.h | 6 +- .../interferometer/interferometerbaseband.cpp | 36 ++++- .../interferometer/interferometerbaseband.h | 24 ++++ .../interferometer/interferometergui.cpp | 38 +++++ .../interferometer/interferometergui.h | 3 + .../interferometer/interferometersettings.cpp | 7 + .../interferometer/interferometersettings.h | 3 +- 8 files changed, 224 insertions(+), 23 deletions(-) diff --git a/plugins/channelmimo/interferometer/interferometer.cpp b/plugins/channelmimo/interferometer/interferometer.cpp index 9d90933e6..8bddf5073 100644 --- a/plugins/channelmimo/interferometer/interferometer.cpp +++ b/plugins/channelmimo/interferometer/interferometer.cpp @@ -30,6 +30,7 @@ #include "dsp/dspcommands.h" #include "dsp/dspdevicesourceengine.h" #include "dsp/devicesamplesource.h" +#include "dsp/dspengine.h" #include "device/deviceset.h" #include "maincore.h" @@ -52,6 +53,7 @@ Interferometer::Interferometer(DeviceAPI *deviceAPI) : m_basebandSink(nullptr), m_running(false), m_guiMessageQueue(nullptr), + m_centerFrequency(0), m_frequencyOffset(0), m_deviceSampleRate(48000) { @@ -141,6 +143,11 @@ void Interferometer::startSinks() InterferometerBaseband::MsgConfigureChannelizer *msg = InterferometerBaseband::MsgConfigureChannelizer::create( m_settings.m_log2Decim, m_settings.m_filterChainHash); m_basebandSink->getInputMessageQueue()->push(msg); + + DeviceSampleSource *deviceSource = getLocalDevice(m_settings.m_localDeviceIndex); + InterferometerBaseband::MsgConfigureLocalDeviceSampleSource *msgDevice = + InterferometerBaseband::MsgConfigureLocalDeviceSampleSource::create(deviceSource); + m_basebandSink->getInputMessageQueue()->push(msgDevice); } void Interferometer::stopSinks() @@ -175,7 +182,7 @@ void Interferometer::pull(SampleVector::iterator& begin, unsigned int nbSamples, void Interferometer::applySettings(const InterferometerSettings& settings, const QList& settingsKeys, bool force) { - qDebug() << "LocalSink::applySettings:" << settings.getDebugString(settingsKeys, force) << "force: " << force; + qDebug() << "Interferometer::applySettings:" << settings.getDebugString(settingsKeys, force) << "force: " << force; if (m_running && (settingsKeys.contains("log2Decim") || settingsKeys.contains("filterChainHash") || force)) @@ -183,6 +190,8 @@ void Interferometer::applySettings(const InterferometerSettings& settings, const InterferometerBaseband::MsgConfigureChannelizer *msg = InterferometerBaseband::MsgConfigureChannelizer::create( settings.m_log2Decim, settings.m_filterChainHash); m_basebandSink->getInputMessageQueue()->push(msg); + calculateFrequencyOffset(settings.m_log2Decim, settings.m_filterChainHash); + propagateSampleRateAndFrequency(m_settings.m_localDeviceIndex, settings.m_log2Decim); } if (m_running && ((settingsKeys.contains("correlationType")) || force)) @@ -200,6 +209,23 @@ void Interferometer::applySettings(const InterferometerSettings& settings, const m_basebandSink->setGain(settings.m_gain); } + if (settingsKeys.contains("localDeviceIndex") || force) + { + propagateSampleRateAndFrequency(settings.m_localDeviceIndex, settings.m_log2Decim); + + if (m_running) + { + DeviceSampleSource *deviceSource = getLocalDevice(settings.m_localDeviceIndex); + InterferometerBaseband::MsgConfigureLocalDeviceSampleSource *msg = + InterferometerBaseband::MsgConfigureLocalDeviceSampleSource::create(deviceSource); + m_basebandSink->getInputMessageQueue()->push(msg); + } + } + + if (m_running && (settingsKeys.contains("play") || force)) { + m_basebandSink->play(settings.m_play); + } + QList pipes; MainCore::instance()->getMessagePipes().getMessagePipes(this, "settings", pipes); @@ -259,7 +285,11 @@ bool Interferometer::handleMessage(const Message& cmd) if (notif.getSourceOrSink()) // deals with source messages only { m_deviceSampleRate = notif.getSampleRate(); - calculateFrequencyOffset(); // This is when device sample rate changes + if (notif.getIndex() == 0) { // Take stream 0 (channel A) as the reference channel + m_centerFrequency = notif.getCenterFrequency(); + } + calculateFrequencyOffset(m_settings.m_log2Decim, m_settings.m_filterChainHash); // This is when device sample rate changes + propagateSampleRateAndFrequency(m_settings.m_localDeviceIndex, m_settings.m_log2Decim); // Notify baseband sink of input sample rate change if (m_running) @@ -322,9 +352,9 @@ void Interferometer::validateFilterChainHash(InterferometerSettings& settings) settings.m_filterChainHash = settings.m_filterChainHash >= s ? s-1 : settings.m_filterChainHash; } -void Interferometer::calculateFrequencyOffset() +void Interferometer::calculateFrequencyOffset(uint32_t log2Decim, uint32_t filterChainHash) { - double shiftFactor = HBFilterChainConverter::getShiftFactor(m_settings.m_log2Decim, m_settings.m_filterChainHash); + double shiftFactor = HBFilterChainConverter::getShiftFactor(log2Decim, filterChainHash); m_frequencyOffset = m_deviceSampleRate * shiftFactor; } @@ -345,9 +375,9 @@ void Interferometer::updateDeviceSetList() std::vector::const_iterator it = deviceSets.begin(); m_localInputDeviceIndexes.clear(); - unsigned int deviceIndex = 0; + unsigned int deviceSetIndex = 0; - for (; it != deviceSets.end(); ++it, deviceIndex++) + for (; it != deviceSets.end(); ++it, deviceSetIndex++) { DSPDeviceSourceEngine *deviceSourceEngine = (*it)->m_deviceSourceEngine; @@ -356,7 +386,7 @@ void Interferometer::updateDeviceSetList() DeviceSampleSource *deviceSource = deviceSourceEngine->getSource(); if (deviceSource->getDeviceDescription() == "LocalInput") { - m_localInputDeviceIndexes.append(deviceIndex); + m_localInputDeviceIndexes.append(deviceSetIndex); } } } @@ -371,19 +401,19 @@ void Interferometer::updateDeviceSetList() InterferometerSettings settings = m_settings; int newIndexInList; - if (it != deviceSets.begin()) + if (m_localInputDeviceIndexes.size() != 0) // there are some local input devices { - if (m_settings.m_localDeviceIndex < 0) { - newIndexInList = 0; - } else if (m_settings.m_localDeviceIndex >= m_localInputDeviceIndexes.size()) { - newIndexInList = m_localInputDeviceIndexes.size() - 1; - } else { + if (m_settings.m_localDeviceIndex < 0) { // not set before + newIndexInList = 0; // set to first device in list + } else if (m_settings.m_localDeviceIndex >= m_localInputDeviceIndexes.size()) { // past last device + newIndexInList = m_localInputDeviceIndexes.size() - 1; // set to last device in list + } else { // no change newIndexInList = m_settings.m_localDeviceIndex; } } - else + else // there are no local input devices { - newIndexInList = -1; + newIndexInList = -1; // set index to nothing } if (newIndexInList < 0) { @@ -392,7 +422,7 @@ void Interferometer::updateDeviceSetList() settings.m_localDeviceIndex = m_localInputDeviceIndexes[newIndexInList]; } - qDebug("LocalSink::updateDeviceSetLists: new device index: %d device: %d", newIndexInList, settings.m_localDeviceIndex); + qDebug("Interferometer::updateDeviceSetLists: new device index: %d device: %d", newIndexInList, settings.m_localDeviceIndex); applySettings(settings, QList{"localDeviceIndex"}); if (m_guiMessageQueue) @@ -402,6 +432,64 @@ void Interferometer::updateDeviceSetList() } } +DeviceSampleSource *Interferometer::getLocalDevice(int deviceSetIndex) +{ + if (deviceSetIndex < 0) { + return nullptr; + } + + MainCore *mainCore = MainCore::instance(); + std::vector& deviceSets = mainCore->getDeviceSets(); + + if (deviceSetIndex < (int) deviceSets.size()) + { + DeviceSet *sourceDeviceSet = deviceSets[deviceSetIndex]; + DSPDeviceSourceEngine *deviceSourceEngine = sourceDeviceSet->m_deviceSourceEngine; + + if (deviceSourceEngine) + { + DeviceSampleSource *deviceSource = deviceSourceEngine->getSource(); + + if (deviceSource->getDeviceDescription() == "LocalInput") { + return deviceSource; + } else { + qDebug("Interferometer::getLocalDevice: source device at index %u is not a Local Input source", deviceSetIndex); + } + } + else + { + qDebug("Interferometer::getLocalDevice: device set at index %d has not a source device", deviceSetIndex); + } + } + else + { + qDebug("Interferometer::getLocalDevice: non existent device set at index: %d", deviceSetIndex); + } + + return nullptr; +} + +void Interferometer::propagateSampleRateAndFrequency(int deviceSetIndex, uint32_t log2Decim) +{ + qDebug() << "Interferometer::propagateSampleRateAndFrequency:" + << " index: " << deviceSetIndex + << " baseband_freq: " << m_deviceSampleRate + << " log2Decim: " << log2Decim + << " frequency: " << m_centerFrequency + m_frequencyOffset; + + DeviceSampleSource *deviceSource = getLocalDevice(deviceSetIndex); + + if (deviceSource) + { + deviceSource->setSampleRate(m_deviceSampleRate / (1 << log2Decim)); + deviceSource->setCenterFrequency(m_centerFrequency + m_frequencyOffset); + } + else + { + qDebug("Interferometer::propagateSampleRateAndFrequency: no suitable device at index %u", deviceSetIndex); + } +} + int Interferometer::webapiSettingsGet( SWGSDRangel::SWGChannelSettings& response, QString& errorMessage) @@ -525,8 +613,8 @@ void Interferometer::webapiFormatChannelSettings(SWGSDRangel::SWGChannelSettings } response.getInterferometerSettings()->setReverseApiPort(settings.m_reverseAPIPort); - response.getInterferometerSettings()->setReverseApiDeviceIndex(settings.m_reverseAPIDeviceIndex); - response.getInterferometerSettings()->setReverseApiChannelIndex(settings.m_reverseAPIChannelIndex); + // response.getInterferometerSettings()->setReverseApiDeviceIndex(settings.m_reverseAPIDeviceIndex); + // response.getInterferometerSettings()->setReverseApiChannelIndex(settings.m_reverseAPIChannelIndex); if (settings.m_spectrumGUI) { @@ -666,6 +754,12 @@ void Interferometer::webapiFormatChannelSettings( if (channelSettingsKeys.contains("gain") || force) { swgInterferometerSettings->setGain(settings.m_gain); } + // if (channelSettingsKeys.contains("localDeviceIndex") || force) { + // swgInterferometerSettings->setLocalDeviceIndex(settings.m_localDeviceIndex); + // } + // if (channelSettingsKeys.contains("play") || force) { + // swgInterferometerSettings->setPlay(settings.m_play ? 1 : 0); + // } if (channelSettingsKeys.contains("filterChainHash") || force) { swgInterferometerSettings->setFilterChainHash(settings.m_filterChainHash); } diff --git a/plugins/channelmimo/interferometer/interferometer.h b/plugins/channelmimo/interferometer/interferometer.h index 63738aa3f..927282675 100644 --- a/plugins/channelmimo/interferometer/interferometer.h +++ b/plugins/channelmimo/interferometer/interferometer.h @@ -37,6 +37,7 @@ class InterferometerBaseband; class QNetworkReply; class QNetworkAccessManager; class ObjectPipe; +class DevieSampleSource; class Interferometer: public MIMOChannel, public ChannelAPI { public: @@ -192,6 +193,7 @@ private: QNetworkAccessManager *m_networkManager; QNetworkRequest m_networkRequest; + uint64_t m_centerFrequency; int64_t m_frequencyOffset; uint32_t m_deviceSampleRate; int m_count0, m_count1; @@ -201,8 +203,10 @@ private: virtual bool handleMessage(const Message& cmd); //!< Processing of a message. Returns true if message has actually been processed void applySettings(const InterferometerSettings& settings, const QList& settingsKeys, bool force = false); static void validateFilterChainHash(InterferometerSettings& settings); - void calculateFrequencyOffset(); + void calculateFrequencyOffset(uint32_t log2Decim, uint32_t filterChainHash); void updateDeviceSetList(); + DeviceSampleSource *getLocalDevice(int deviceSetIndex); + void propagateSampleRateAndFrequency(int index, uint32_t log2Decim); void webapiReverseSendSettings(const QList& channelSettingsKeys, const InterferometerSettings& settings, bool force); void sendChannelSettings( const QList& pipes, diff --git a/plugins/channelmimo/interferometer/interferometerbaseband.cpp b/plugins/channelmimo/interferometer/interferometerbaseband.cpp index b70368bf4..e4cc3618f 100644 --- a/plugins/channelmimo/interferometer/interferometerbaseband.cpp +++ b/plugins/channelmimo/interferometer/interferometerbaseband.cpp @@ -24,6 +24,7 @@ #include "dsp/downchannelizer.h" #include "dsp/basebandsamplesink.h" #include "dsp/scopevis.h" +#include "dsp/devicesamplesource.h" #include "interferometerbaseband.h" @@ -31,11 +32,14 @@ MESSAGE_CLASS_DEFINITION(InterferometerBaseband::MsgConfigureChannelizer, Message) MESSAGE_CLASS_DEFINITION(InterferometerBaseband::MsgSignalNotification, Message) MESSAGE_CLASS_DEFINITION(InterferometerBaseband::MsgConfigureCorrelation, Message) +MESSAGE_CLASS_DEFINITION(InterferometerBaseband::MsgConfigureLocalDeviceSampleSource, Message) InterferometerBaseband::InterferometerBaseband(int fftSize) : m_correlator(fftSize), m_spectrumSink(nullptr), - m_scopeSink(nullptr) + m_scopeSink(nullptr), + m_localSampleSource(nullptr), + m_play(false) { m_sampleMIFifo.init(2, 96000 * 8); m_vbegin.resize(2); @@ -164,6 +168,21 @@ void InterferometerBaseband::run() m_spectrumSink->feed(m_correlator.m_tcorr.begin(), m_correlator.m_tcorr.begin() + m_correlator.m_processed, false); } } + + if (m_localSampleSource && m_play) + { + if ((m_correlator.getCorrType() == InterferometerSettings::CorrelationFFT) + || (m_correlator.getCorrType() == InterferometerSettings::CorrelationIFFT) + || (m_correlator.getCorrType() == InterferometerSettings::CorrelationIFFT2) + || (m_correlator.getCorrType() == InterferometerSettings::CorrelationIFFTStar)) + { + m_localSampleSource->getSampleFifo()->write(m_correlator.m_scorr.begin(), m_correlator.m_scorr.begin() + m_correlator.m_processed); + } + else + { + m_localSampleSource->getSampleFifo()->write(m_correlator.m_tcorr.begin(), m_correlator.m_tcorr.begin() + m_correlator.m_processed); + } + } } for (int i = 0; i < 2; i++) @@ -180,12 +199,13 @@ void InterferometerBaseband::run() void InterferometerBaseband::handleInputMessages() { - qDebug("InterferometerBaseband::handleInputMessage"); Message* message; while ((message = m_inputMessageQueue.pop()) != 0) { - if (handleMessage(*message)) { + qDebug("InterferometerBaseband::handleInputMessage: %s", message->getIdentifier()); + + if (handleMessage(*message)) { delete message; } } @@ -246,6 +266,16 @@ bool InterferometerBaseband::handleMessage(const Message& cmd) return true; } + else if (MsgConfigureLocalDeviceSampleSource::match(cmd)) + { + QMutexLocker mutexLocker(&m_mutex); + MsgConfigureLocalDeviceSampleSource& notif = (MsgConfigureLocalDeviceSampleSource&) cmd; + qDebug() << "InterferometerBaseband::handleMessage: MsgConfigureLocalDeviceSampleSource: " << notif.getDeviceSampleSource(); + m_localSampleSource = notif.getDeviceSampleSource(); + + return true; + } + else { qDebug("InterferometerBaseband::handleMessage: unhandled: %s", cmd.getIdentifier()); diff --git a/plugins/channelmimo/interferometer/interferometerbaseband.h b/plugins/channelmimo/interferometer/interferometerbaseband.h index 86d2ef770..674b1d3d0 100644 --- a/plugins/channelmimo/interferometer/interferometerbaseband.h +++ b/plugins/channelmimo/interferometer/interferometerbaseband.h @@ -33,6 +33,7 @@ class DownChannelizer; class BasebandSampleSink; class ScopeVis; +class DeviceSampleSource; class InterferometerBaseband : public QObject { @@ -103,6 +104,26 @@ public: { } }; + class MsgConfigureLocalDeviceSampleSource : public Message { + MESSAGE_CLASS_DECLARATION + + public: + static MsgConfigureLocalDeviceSampleSource* create(DeviceSampleSource *deviceSampleSource) { + return new MsgConfigureLocalDeviceSampleSource(deviceSampleSource); + } + + DeviceSampleSource *getDeviceSampleSource() const { return m_deviceSampleSource; } + + private: + + MsgConfigureLocalDeviceSampleSource(DeviceSampleSource *deviceSampleSource) : + Message(), + m_deviceSampleSource(deviceSampleSource) + { } + + DeviceSampleSource *m_deviceSampleSource; + }; + InterferometerBaseband(int fftSize); ~InterferometerBaseband(); void reset(); @@ -116,6 +137,7 @@ public: void feed(const SampleVector::const_iterator& begin, const SampleVector::const_iterator& end, unsigned int streamIndex); void setBasebandSampleRate(unsigned int sampleRate); + void play(bool play) { m_play = play; } private: void processFifo(const std::vector& data, unsigned int ibegin, unsigned int iend); @@ -133,6 +155,8 @@ private: MessageQueue m_inputMessageQueue; //!< Queue for asynchronous inbound communication QRecursiveMutex m_mutex; unsigned int m_lastStream; + DeviceSampleSource *m_localSampleSource; + bool m_play; private slots: void handleInputMessages(); diff --git a/plugins/channelmimo/interferometer/interferometergui.cpp b/plugins/channelmimo/interferometer/interferometergui.cpp index ec467d1e7..a4830d32c 100644 --- a/plugins/channelmimo/interferometer/interferometergui.cpp +++ b/plugins/channelmimo/interferometer/interferometergui.cpp @@ -225,6 +225,11 @@ void InterferometerGUI::displaySettings() setTitle(m_channelMarker.getTitle()); blockApplySettings(true); + int index = getLocalDeviceIndexInCombo(m_settings.m_localDeviceIndex); + if (index >= 0) { + ui->localDevice->setCurrentIndex(index); + } + ui->localDevicePlay->setChecked(m_settings.m_play); ui->decimationFactor->setCurrentIndex(m_settings.m_log2Decim); applyDecimation(); ui->phaseCorrection->setValue(m_settings.m_phase); @@ -338,6 +343,20 @@ void InterferometerGUI::updateDeviceSetList(const QList& deviceSetIndexes) ui->localDevice->blockSignals(false); } +int InterferometerGUI::getLocalDeviceIndexInCombo(int localDeviceIndex) +{ + int index = 0; + + for (; index < ui->localDevice->count(); index++) + { + if (localDeviceIndex == ui->localDevice->itemData(index).toInt()) { + return index; + } + } + + return -1; +} + void InterferometerGUI::on_decimationFactor_currentIndexChanged(int index) { m_settings.m_log2Decim = index; @@ -387,6 +406,23 @@ void InterferometerGUI::on_correlationType_currentIndexChanged(int index) applySettings(); } +void InterferometerGUI::on_localDevice_currentIndexChanged(int index) +{ + if (index >= 0) + { + m_settings.m_localDeviceIndex = ui->localDevice->currentData().toInt(); + m_settingsKeys.append("localDeviceIndex"); + applySettings(); + } +} + +void InterferometerGUI::on_localDevicePlay_toggled(bool checked) +{ + m_settings.m_play = checked; + m_settingsKeys.append("play"); + applySettings(); +} + void InterferometerGUI::applyDecimation() { uint32_t maxHash = 1; @@ -430,6 +466,8 @@ void InterferometerGUI::makeUIConnections() QObject::connect(ui->phaseCorrectionLabel, &ClickableLabel::clicked, this, &InterferometerGUI::on_phaseCorrectionLabel_clicked); QObject::connect(ui->gainLabel, &ClickableLabel::clicked, this, &InterferometerGUI::on_gainLabel_clicked); QObject::connect(ui->correlationType, QOverload::of(&QComboBox::currentIndexChanged), this, &InterferometerGUI::on_correlationType_currentIndexChanged); + QObject::connect(ui->localDevice, QOverload::of(&QComboBox::currentIndexChanged), this, &InterferometerGUI::on_localDevice_currentIndexChanged); + QObject::connect(ui->localDevicePlay, &ButtonSwitch::toggled, this, &InterferometerGUI::on_localDevicePlay_toggled); } void InterferometerGUI::updateAbsoluteCenterFrequency() diff --git a/plugins/channelmimo/interferometer/interferometergui.h b/plugins/channelmimo/interferometer/interferometergui.h index d95072148..a0d19f59d 100644 --- a/plugins/channelmimo/interferometer/interferometergui.h +++ b/plugins/channelmimo/interferometer/interferometergui.h @@ -95,6 +95,7 @@ private: void makeUIConnections(); void updateAbsoluteCenterFrequency(); void updateDeviceSetList(const QList& deviceSetIndexes); + int getLocalDeviceIndexInCombo(int localDeviceIndex); void leaveEvent(QEvent*); void enterEvent(EnterEventType*); @@ -108,6 +109,8 @@ private slots: void on_phaseCorrectionLabel_clicked(); void on_gainLabel_clicked(); void on_correlationType_currentIndexChanged(int index); + void on_localDevice_currentIndexChanged(int index); + void on_localDevicePlay_toggled(bool checked); void onWidgetRolled(QWidget* widget, bool rollDown); void onMenuDialogCalled(const QPoint& p); void tick(); diff --git a/plugins/channelmimo/interferometer/interferometersettings.cpp b/plugins/channelmimo/interferometer/interferometersettings.cpp index 68bd6e9de..78d66daab 100644 --- a/plugins/channelmimo/interferometer/interferometersettings.cpp +++ b/plugins/channelmimo/interferometer/interferometersettings.cpp @@ -42,6 +42,7 @@ void InterferometerSettings::resetToDefaults() m_phase = 0; m_gain = 0; m_localDeviceIndex = -1; + m_play = false; m_reverseAPIAddress = "127.0.0.1"; m_reverseAPIPort = 8888; m_reverseAPIDeviceIndex = 0; @@ -191,6 +192,9 @@ void InterferometerSettings::applySettings(const QStringList& settingsKeys, cons if (settingsKeys.contains("localDeviceIndex")) { m_localDeviceIndex = settings.m_localDeviceIndex; } + if (settingsKeys.contains("play")) { + m_play = settings.m_play; + } if (settingsKeys.contains("reverseAPIAddress")) { m_reverseAPIAddress = settings.m_reverseAPIAddress; } @@ -239,6 +243,9 @@ QString InterferometerSettings::getDebugString(const QStringList& settingsKeys, if (settingsKeys.contains("localDeviceIndex")) { ostr << " m_localDeviceIndex: " << m_localDeviceIndex; } + if (settingsKeys.contains("play") || force) { + ostr << " m_play: " << m_play; + } if (settingsKeys.contains("reverseAPIAddress")) { ostr << " m_reverseAPIAddress: " << m_reverseAPIAddress.toStdString(); } diff --git a/plugins/channelmimo/interferometer/interferometersettings.h b/plugins/channelmimo/interferometer/interferometersettings.h index 68b8789de..e977c79fe 100644 --- a/plugins/channelmimo/interferometer/interferometersettings.h +++ b/plugins/channelmimo/interferometer/interferometersettings.h @@ -47,7 +47,8 @@ struct InterferometerSettings uint32_t m_filterChainHash; int m_phase; int m_gain; - int m_localDeviceIndex; + int m_localDeviceIndex; //!< Local device set index (-1 if unset) + bool m_play; //!< Play/Stop correlation IQ in local device bool m_useReverseAPI; QString m_reverseAPIAddress; uint16_t m_reverseAPIPort;