From 8c8c05653d7854fcdb23ba51b340abc9400fae1b Mon Sep 17 00:00:00 2001 From: f4exb Date: Thu, 12 Sep 2019 18:20:25 +0200 Subject: [PATCH] Interferometer (4) --- .../interferometer/interferometer.cpp | 118 ++++++++++---- .../interferometer/interferometer.h | 43 ++---- .../interferometer/interferometercorr.cpp | 76 ++++++--- .../interferometer/interferometercorr.h | 24 ++- .../interferometer/interferometergui.cpp | 75 ++++++--- .../interferometer/interferometergui.h | 9 +- .../interferometer/interferometergui.ui | 117 +++++--------- .../interferometer/interferometerplugin.cpp | 6 +- .../interferometer/interferometerplugin.h | 6 +- .../interferometer/interferometersettings.h | 2 +- .../interferometer/interferometersink.cpp | 146 ++++++++++++++---- .../interferometer/interferometersink.h | 56 ++++++- .../interferometerstreamsink.cpp | 6 +- .../interferometer/interferometerstreamsink.h | 1 + sdrgui/mainwindow.cpp | 22 ++- 15 files changed, 472 insertions(+), 235 deletions(-) diff --git a/plugins/channelmimo/interferometer/interferometer.cpp b/plugins/channelmimo/interferometer/interferometer.cpp index 7e0bcab75..19b21664e 100644 --- a/plugins/channelmimo/interferometer/interferometer.cpp +++ b/plugins/channelmimo/interferometer/interferometer.cpp @@ -33,35 +33,41 @@ #include "interferometer.h" MESSAGE_CLASS_DEFINITION(Interferometer::MsgConfigureInterferometer, Message) -MESSAGE_CLASS_DEFINITION(Interferometer::MsgConfigureChannelizer, Message) -MESSAGE_CLASS_DEFINITION(Interferometer::MsgSampleRateNotification, Message) +MESSAGE_CLASS_DEFINITION(Interferometer::MsgBasebandNotification, Message) const QString Interferometer::m_channelIdURI = "sdrangel.channel.interferometer"; const QString Interferometer::m_channelId = "Interferometer"; +const int Interferometer::m_fftSize = 4096; Interferometer::Interferometer(DeviceAPI *deviceAPI) : - ChannelAPI(m_channelIdURI, ChannelAPI::StreamSingleSink), + ChannelAPI(m_channelIdURI, ChannelAPI::StreamMIMO), m_deviceAPI(deviceAPI), m_spectrumSink(nullptr), m_scopeSink(nullptr), + m_guiMessageQueue(nullptr), m_frequencyOffset(0), m_deviceSampleRate(48000) { - m_deviceAPI->addChannelSinkAPI(this); + setObjectName(m_channelId); + m_thread = new QThread(this); - m_sink = new InterferometerSink(); + m_sink = new InterferometerSink(m_fftSize); m_sink->moveToThread(m_thread); - start(); + m_deviceAPI->addMIMOChannel(this); + m_deviceAPI->addMIMOChannelAPI(this); + connect(&m_inputMessageQueue, SIGNAL(messageEnqueued()), this, SLOT(handleInputMessages())); + + m_networkManager = new QNetworkAccessManager(); + connect(m_networkManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(networkManagerFinished(QNetworkReply*))); } Interferometer::~Interferometer() { + disconnect(m_networkManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(networkManagerFinished(QNetworkReply*))); + delete m_networkManager; + m_deviceAPI->removeChannelSinkAPI(this); - - if (m_thread->isRunning()) { - stop(); - } - + m_deviceAPI->removeMIMOChannel(this); delete m_sink; delete m_thread; } @@ -94,8 +100,26 @@ void Interferometer::feed(const SampleVector::const_iterator& begin, const Sampl m_sink->feed(begin, end, sinkIndex); } +void Interferometer::pull(Sample& sample, unsigned int sourceIndex) +{ + (void) sample; + (void) sourceIndex; +} + void Interferometer::applySettings(const InterferometerSettings& settings, bool force) { + qDebug() << "Interferometer::applySettings: " + << "m_correlationType: " << settings.m_correlationType + << "m_filterChainHash: " << settings.m_filterChainHash + << "m_log2Decim: " << settings.m_log2Decim + << "m_correlationType: " << settings.m_correlationType + << "m_useReverseAPI: " << settings.m_useReverseAPI + << "m_reverseAPIAddress: " << settings.m_reverseAPIAddress + << "m_reverseAPIPort: " << settings.m_reverseAPIPort + << "m_reverseAPIDeviceIndex: " << settings.m_reverseAPIDeviceIndex + << "m_reverseAPIChannelIndex: " << settings.m_reverseAPIChannelIndex + << "m_title: " << settings.m_title; + if ((m_settings.m_log2Decim != settings.m_log2Decim) || (m_settings.m_filterChainHash != settings.m_filterChainHash) || force) { @@ -103,6 +127,28 @@ void Interferometer::applySettings(const InterferometerSettings& settings, bool settings.m_log2Decim, settings.m_filterChainHash); m_sink->getInputMessageQueue()->push(msg); } + + if ((m_settings.m_correlationType != settings.m_correlationType) || force) + { + InterferometerSink::MsgConfigureCorrelation *msg = InterferometerSink::MsgConfigureCorrelation::create( + settings.m_correlationType); + m_sink->getInputMessageQueue()->push(msg); + } + + m_settings = settings; +} + +void Interferometer::handleInputMessages() +{ + Message* message; + + while ((message = m_inputMessageQueue.pop()) != 0) + { + if (handleMessage(*message)) + { + delete message; + } + } } bool Interferometer::handleMessage(const Message& cmd) @@ -114,27 +160,39 @@ bool Interferometer::handleMessage(const Message& cmd) applySettings(cfg.getSettings(), cfg.getForce()); return true; } - else if (DSPSignalNotification::match(cmd)) + else if (DSPMIMOSignalNotification::match(cmd)) { - DSPSignalNotification& notif = (DSPSignalNotification&) cmd; + DSPMIMOSignalNotification& notif = (DSPMIMOSignalNotification&) cmd; - qDebug() << "Interferometer::handleMessage: DSPSignalNotification:" + qDebug() << "Interferometer::handleMessage: DSPMIMOSignalNotification:" << " inputSampleRate: " << notif.getSampleRate() - << " centerFrequency: " << notif.getCenterFrequency(); + << " centerFrequency: " << notif.getCenterFrequency() + << " sourceElseSink: " << notif.getSourceOrSink() + << " streamIndex: " << notif.getIndex(); - m_deviceSampleRate = notif.getSampleRate(); - calculateFrequencyOffset(); // This is when device sample rate changes - - // Redo the channelizer stuff with the new sample rate to re-synchronize everything - InterferometerSink::MsgConfigureChannelizer *msg = InterferometerSink::MsgConfigureChannelizer::create( - m_settings.m_log2Decim, - m_settings.m_filterChainHash); - m_sink->getInputMessageQueue()->push(msg); - - if (m_guiMessageQueue) + if (notif.getSourceOrSink()) // deals with source messages only { - MsgSampleRateNotification *msg = MsgSampleRateNotification::create(notif.getSampleRate()); - m_guiMessageQueue->push(msg); + m_deviceSampleRate = notif.getSampleRate(); + calculateFrequencyOffset(); // This is when device sample rate changes + + // Notify sink of input sample rate change + InterferometerSink::MsgSignalNotification *sig = InterferometerSink::MsgSignalNotification::create( + m_deviceSampleRate, notif.getCenterFrequency(), notif.getIndex() + ); + m_sink->getInputMessageQueue()->push(sig); + + // Redo the channelizer stuff with the new sample rate to re-synchronize everything + InterferometerSink::MsgConfigureChannelizer *msg = InterferometerSink::MsgConfigureChannelizer::create( + m_settings.m_log2Decim, + m_settings.m_filterChainHash); + m_sink->getInputMessageQueue()->push(msg); + + if (m_guiMessageQueue) + { + MsgBasebandNotification *msg = MsgBasebandNotification::create( + notif.getSampleRate(), notif.getCenterFrequency()); + m_guiMessageQueue->push(msg); + } } return true; @@ -185,6 +243,12 @@ void Interferometer::calculateFrequencyOffset() m_frequencyOffset = m_deviceSampleRate * shiftFactor; } +void Interferometer::applyChannelSettings(uint32_t log2Decim, uint32_t filterChainHash) +{ + InterferometerSink::MsgConfigureChannelizer *msg = InterferometerSink::MsgConfigureChannelizer::create(log2Decim, filterChainHash); + m_sink->getInputMessageQueue()->push(msg); +} + int Interferometer::webapiSettingsGet( SWGSDRangel::SWGChannelSettings& response, QString& errorMessage) diff --git a/plugins/channelmimo/interferometer/interferometer.h b/plugins/channelmimo/interferometer/interferometer.h index 4998fbfd0..26005a663 100644 --- a/plugins/channelmimo/interferometer/interferometer.h +++ b/plugins/channelmimo/interferometer/interferometer.h @@ -21,7 +21,7 @@ #include #include -#include "dsp/mimosamplesink.h" +#include "dsp/mimochannel.h" #include "channel/channelapi.h" #include "util/messagequeue.h" #include "util/message.h" @@ -35,7 +35,7 @@ class QNetworkReply; class QNetworkAccessManager; class BasebandSampleSink; -class Interferometer: public MIMOSampleSink, public ChannelAPI +class Interferometer: public MIMOChannel, public ChannelAPI { Q_OBJECT public: @@ -62,46 +62,27 @@ public: { } }; - class MsgConfigureChannelizer : public Message { + class MsgBasebandNotification : public Message { MESSAGE_CLASS_DECLARATION public: - int getLog2Decim() const { return m_log2Decim; } - int getFilterChainHash() const { return m_filterChainHash; } - - static MsgConfigureChannelizer* create(unsigned int log2Decim, unsigned int filterChainHash) { - return new MsgConfigureChannelizer(log2Decim, filterChainHash); - } - - private: - unsigned int m_log2Decim; - unsigned int m_filterChainHash; - - MsgConfigureChannelizer(unsigned int log2Decim, unsigned int filterChainHash) : - Message(), - m_log2Decim(log2Decim), - m_filterChainHash(filterChainHash) - { } - }; - - class MsgSampleRateNotification : public Message { - MESSAGE_CLASS_DECLARATION - - public: - static MsgSampleRateNotification* create(int sampleRate) { - return new MsgSampleRateNotification(sampleRate); + static MsgBasebandNotification* create(int sampleRate, qint64 centerFrequency) { + return new MsgBasebandNotification(sampleRate, centerFrequency); } int getSampleRate() const { return m_sampleRate; } + qint64 getCenterFrequency() const { return m_centerFrequency; } private: - MsgSampleRateNotification(int sampleRate) : + MsgBasebandNotification(int sampleRate, qint64 centerFrequency) : Message(), - m_sampleRate(sampleRate) + m_sampleRate(sampleRate), + m_centerFrequency(centerFrequency) { } int m_sampleRate; + qint64 m_centerFrequency; }; Interferometer(DeviceAPI *deviceAPI); @@ -111,6 +92,7 @@ public: virtual void start(); //!< thread start() virtual void stop(); //!< thread exit() and wait() virtual void feed(const SampleVector::const_iterator& begin, const SampleVector::const_iterator& end, unsigned int sinkIndex); + virtual void pull(Sample& sample, unsigned int sourceIndex); virtual bool handleMessage(const Message& cmd); //!< Processing of a message. Returns true if message has actually been processed virtual void getIdentifier(QString& id) { id = objectName(); } @@ -136,6 +118,7 @@ public: void setSpectrumSink(BasebandSampleSink *spectrumSink); void setScopeSink(BasebandSampleSink *scopeSink); + void applyChannelSettings(uint32_t log2Decim, uint32_t filterChainHash); virtual int webapiSettingsGet( SWGSDRangel::SWGChannelSettings& response, @@ -158,6 +141,7 @@ public: static const QString m_channelIdURI; static const QString m_channelId; + static const int m_fftSize; private: DeviceAPI *m_deviceAPI; @@ -181,6 +165,7 @@ private: void webapiReverseSendSettings(QList& channelSettingsKeys, const InterferometerSettings& settings, bool force); private slots: + void handleInputMessages(); void networkManagerFinished(QNetworkReply *reply); void handleData(int start, int stop); }; diff --git a/plugins/channelmimo/interferometer/interferometercorr.cpp b/plugins/channelmimo/interferometer/interferometercorr.cpp index 3f7bfa755..c7ed3e75d 100644 --- a/plugins/channelmimo/interferometer/interferometercorr.cpp +++ b/plugins/channelmimo/interferometer/interferometercorr.cpp @@ -25,7 +25,10 @@ Sample sAdd(const Sample& a, const Sample& b) { //!< Sample addition } Sample sMulConj(const Sample& a, const Sample& b) { //!< Sample multiply with conjugate - return Sample{a.real()*b.real() + a.imag()*b.imag(), a.imag()*b.real() - a.real()*b.imag()}; + Sample s; + s.setReal((a.real()*b.real() + a.imag()*b.imag()) / (1<<(SDR_RX_SAMP_SZ - 16 + 1))); + s.setImag((a.imag()*b.real() - a.real()*b.imag()) / (1<<(SDR_RX_SAMP_SZ - 16 + 1))); + return s; } Sample cf2s(const std::complex& a) { //!< Complex float to Sample @@ -35,6 +38,13 @@ Sample cf2s(const std::complex& a) { //!< Complex float to Sample return s; } +Sample invfft2s(const std::complex& a) { //!< Complex float to Sample + Sample s; + s.setReal(a.real()); + s.setImag(a.imag()); + return s; +} + InterferometerCorrelator::InterferometerCorrelator(int fftSize) : m_corrType(InterferometerSettings::CorrelationAdd), m_fftSize(fftSize) @@ -55,35 +65,50 @@ InterferometerCorrelator::InterferometerCorrelator(int fftSize) : InterferometerCorrelator::~InterferometerCorrelator() { - for (int i = 0; i < 2; i++) - { - delete[] m_fft[i]; - } - delete[] m_dataj; + delete m_invFFT; + + for (int i = 0; i < 2; i++) { + delete m_fft[i]; + } } -void InterferometerCorrelator::performCorr(const SampleVector& data0, const SampleVector& data1) +bool InterferometerCorrelator::performCorr( + const SampleVector& data0, + int size0, + const SampleVector& data1, + int size1 +) { + bool results = false; + switch (m_corrType) { case InterferometerSettings::CorrelationAdd: - performOpCorr(data0, data1, sAdd); + results = performOpCorr(data0, size0, data1, size1, sAdd); break; case InterferometerSettings::CorrelationMultiply: - performOpCorr(data0, data1, sMulConj); + results = performOpCorr(data0, size0, data1, size1, sMulConj); break; - case InterferometerSettings::CorrelationCorrelation: - performFFTCorr(data0, data1); + case InterferometerSettings::CorrelationFFT: + results = performFFTCorr(data0, size0, data1, size1); break; default: break; } + + return results; } -void InterferometerCorrelator::performOpCorr(const SampleVector& data0, const SampleVector& data1, Sample sampleOp(const Sample& a, const Sample& b)) +bool InterferometerCorrelator::performOpCorr( + const SampleVector& data0, + int size0, + const SampleVector& data1, + int size1, + Sample sampleOp(const Sample& a, const Sample& b) +) { - unsigned int size = std::min(data0.size(), data1.size()); + unsigned int size = std::min(size0, size1); adjustTCorrSize(size); std::transform( @@ -95,12 +120,20 @@ void InterferometerCorrelator::performOpCorr(const SampleVector& data0, const Sa ); m_processed = size; - m_remaining = 0; + m_remaining[0] = size0 - size; + m_remaining[1] = size1 - size; + return true; } -void InterferometerCorrelator::performFFTCorr(const SampleVector& data0, const SampleVector& data1) +bool InterferometerCorrelator::performFFTCorr( + const SampleVector& data0, + int size0, + const SampleVector& data1, + int size1 +) { - unsigned int size = std::min(data0.size(), data1.size()); + unsigned int size = std::min(size0, size1); + int nfft = 0; SampleVector::const_iterator begin0 = data0.begin(); SampleVector::const_iterator begin1 = data1.begin(); adjustSCorrSize(size); @@ -167,18 +200,21 @@ void InterferometerCorrelator::performFFTCorr(const SampleVector& data0, const S m_invFFT->out(), m_invFFT->out() + 2*m_fftSize, m_tcorr.begin(), - cf2s + invfft2s ); - // TODO: do something with the result size -= m_fftSize; begin0 += m_fftSize; begin1 += m_fftSize; + nfft++; } // update the samples counters - m_processed = begin0 - data0.begin(); - m_remaining = size - m_fftSize; + m_processed = nfft*m_fftSize; + m_remaining[0] = size0 - nfft*m_fftSize; + m_remaining[1] = size1 - nfft*m_fftSize; + + return nfft > 0; } void InterferometerCorrelator::adjustSCorrSize(int size) diff --git a/plugins/channelmimo/interferometer/interferometercorr.h b/plugins/channelmimo/interferometer/interferometercorr.h index ebfec4ffd..735a2d8d1 100644 --- a/plugins/channelmimo/interferometer/interferometercorr.h +++ b/plugins/channelmimo/interferometer/interferometercorr.h @@ -37,20 +37,36 @@ public: void setCorrType(InterferometerSettings::CorrelationType corrType) { m_corrType = corrType; } InterferometerSettings::CorrelationType getCorrType() const { return m_corrType; } - void performCorr(const SampleVector& data0, const SampleVector& data1); + bool performCorr( //!< Returns true if results were produced + const SampleVector& data0, + int size0, + const SampleVector& data1, + int size1 + ); int getFullFFTSize() const { return 2*m_fftSize; } SampleVector m_scorr; //!< raw correlation result (spectrum) - Sample vector expected SampleVector m_tcorr; //!< correlation result (time or spectrum inverse FFT) - Sample vector expected int m_processed; //!< number of samples processed at the end of correlation - int m_remaining; //!< number of samples remaining at the end of correlation + int m_remaining[2]; //!< number of samples remaining per member at the end of correlation signals: void dataReady(int start, int stop); private: - void performOpCorr(const SampleVector& data0, const SampleVector& data1, Sample sampleOp(const Sample& a, const Sample& b)); - void performFFTCorr(const SampleVector& data0, const SampleVector& data1); + bool performOpCorr( //!< Returns true if results were produced + const SampleVector& data0, + int size0, + const SampleVector& data1, + int size1, + Sample sampleOp(const Sample& a, const Sample& b) + ); + bool performFFTCorr( //!< Returns true if results were produced + const SampleVector& data0, + int size0, + const SampleVector& data1, + int size1 + ); void adjustSCorrSize(int size); void adjustTCorrSize(int size); diff --git a/plugins/channelmimo/interferometer/interferometergui.cpp b/plugins/channelmimo/interferometer/interferometergui.cpp index dc2730d44..a1387c0f0 100644 --- a/plugins/channelmimo/interferometer/interferometergui.cpp +++ b/plugins/channelmimo/interferometer/interferometergui.cpp @@ -20,12 +20,15 @@ #include "device/deviceuiset.h" #include "gui/basicchannelsettingsdialog.h" #include "dsp/hbfilterchainconverter.h" +#include "dsp/scopevis.h" +#include "dsp/spectrumvis.h" +#include "mainwindow.h" #include "interferometergui.h" #include "interferometer.h" #include "ui_interferometergui.h" -InterferometerGUI* InterferometerGUI::create(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, MIMOSampleSink *channelMIMO) +InterferometerGUI* InterferometerGUI::create(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, MIMOChannel *channelMIMO) { InterferometerGUI* gui = new InterferometerGUI(pluginAPI, deviceUISet, channelMIMO); return gui; @@ -47,7 +50,7 @@ QString InterferometerGUI::getName() const } qint64 InterferometerGUI::getCenterFrequency() const { - return 0; + return m_centerFrequency; } void InterferometerGUI::setCenterFrequency(qint64 centerFrequency) @@ -79,13 +82,18 @@ bool InterferometerGUI::deserialize(const QByteArray& data) } } +MessageQueue* InterferometerGUI::getInputMessageQueue() +{ + return &m_inputMessageQueue; +} + bool InterferometerGUI::handleMessage(const Message& message) { - if (Interferometer::MsgSampleRateNotification::match(message)) + if (Interferometer::MsgBasebandNotification::match(message)) { - Interferometer::MsgSampleRateNotification& notif = (Interferometer::MsgSampleRateNotification&) message; - m_channelMarker.setBandwidth(notif.getSampleRate()); + Interferometer::MsgBasebandNotification& notif = (Interferometer::MsgBasebandNotification&) message; m_sampleRate = notif.getSampleRate(); + m_centerFrequency = notif.getCenterFrequency(); displayRateAndShift(); return true; } @@ -95,23 +103,42 @@ bool InterferometerGUI::handleMessage(const Message& message) } } -InterferometerGUI::InterferometerGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, MIMOSampleSink *channelMIMO, QWidget* parent) : +InterferometerGUI::InterferometerGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, MIMOChannel *channelMIMO, QWidget* parent) : RollupWidget(parent), ui(new Ui::InterferometerGUI), m_pluginAPI(pluginAPI), m_deviceUISet(deviceUISet), - m_sampleRate(0), + m_sampleRate(48000), + m_centerFrequency(435000000), m_tickCount(0) { ui->setupUi(this); setAttribute(Qt::WA_DeleteOnClose, true); + setStreamIndicator("M"); + connect(this, SIGNAL(widgetRolled(QWidget*,bool)), this, SLOT(onWidgetRolled(QWidget*,bool))); connect(this, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(onMenuDialogCalled(const QPoint &))); + m_spectrumVis = new SpectrumVis(SDR_RX_SCALEF, ui->glSpectrum); + m_scopeVis = new ScopeVis(ui->glScope); + m_interferometer = (Interferometer*) channelMIMO; + m_interferometer->setScopeSink(m_scopeVis); + m_interferometer->setSpectrumSink(m_spectrumVis); m_interferometer->setMessageQueueToGUI(getInputMessageQueue()); + ui->glSpectrum->setDisplayWaterfall(true); + ui->glSpectrum->setDisplayMaxHold(true); + ui->glSpectrum->setCenterFrequency(0); + ui->glSpectrum->setSsbSpectrum(false); + ui->glSpectrum->setLsbDisplay(false); + + ui->glSpectrum->connectTimer(MainWindow::getInstance()->getMasterTimer()); + ui->glScope->connectTimer(MainWindow::getInstance()->getMasterTimer()); + connect(&MainWindow::getInstance()->getMasterTimer(), SIGNAL(timeout()), this, SLOT(tick())); + m_channelMarker.blockSignals(true); + m_channelMarker.addStreamIndex(1); m_channelMarker.setColor(m_settings.m_rgbColor); m_channelMarker.setCenterFrequency(0); m_channelMarker.setTitle("Interferometer"); @@ -120,21 +147,30 @@ InterferometerGUI::InterferometerGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUI m_settings.setChannelMarker(&m_channelMarker); - // m_deviceUISet->registerRxChannelInstance(LocalSink::m_channelIdURI, this); + m_deviceUISet->registerChannelInstance(Interferometer::m_channelIdURI, this); m_deviceUISet->addChannelMarker(&m_channelMarker); m_deviceUISet->addRollupWidget(this); + ui->spectrumGUI->setBuddies(m_spectrumVis->getInputMessageQueue(), m_spectrumVis, ui->glSpectrum); + ui->scopeGUI->setBuddies(m_scopeVis->getInputMessageQueue(), m_scopeVis, ui->glScope); + + m_scopeVis->setTraceChunkSize(Interferometer::m_fftSize); // Set scope trace length unit to FFT size + ui->scopeGUI->traceLengthChange(); + connect(getInputMessageQueue(), SIGNAL(messageEnqueued()), this, SLOT(handleSourceMessages())); //connect(&(m_deviceUISet->m_deviceSourceAPI->getMasterTimer()), SIGNAL(timeout()), this, SLOT(tick())); displaySettings(); + displayRateAndShift(); applySettings(true); } InterferometerGUI::~InterferometerGUI() { - //m_deviceUISet->removeRxChannelInstance(this); + m_deviceUISet->removeChannelInstance(this); delete m_interferometer; // TODO: check this: when the GUI closes it has to delete the demodulator + delete m_spectrumVis; + delete m_scopeVis; delete ui; } @@ -154,17 +190,6 @@ void InterferometerGUI::applySettings(bool force) } } -void InterferometerGUI::applyChannelSettings() -{ - if (m_doApplySettings) - { - Interferometer::MsgConfigureChannelizer *msgChan = Interferometer::MsgConfigureChannelizer::create( - m_settings.m_log2Decim, - m_settings.m_filterChainHash); - m_interferometer->getInputMessageQueue()->push(msgChan); - } -} - void InterferometerGUI::displaySettings() { m_channelMarker.blockSignals(true); @@ -193,6 +218,8 @@ void InterferometerGUI::displayRateAndShift() ui->channelRateText->setText(tr("%1k").arg(QString::number(channelSampleRate / 1000.0, 'g', 5))); m_channelMarker.setCenterFrequency(shift); m_channelMarker.setBandwidth(channelSampleRate); + ui->glSpectrum->setSampleRate(channelSampleRate); + m_scopeVis->setLiveRate(channelSampleRate); } void InterferometerGUI::leaveEvent(QEvent*) @@ -267,6 +294,12 @@ void InterferometerGUI::on_position_valueChanged(int value) applyPosition(); } +void InterferometerGUI::on_correlationType_currentIndexChanged(int index) +{ + m_settings.m_correlationType = (InterferometerSettings::CorrelationType) index; + applySettings(); +} + void InterferometerGUI::applyDecimation() { uint32_t maxHash = 1; @@ -289,7 +322,7 @@ void InterferometerGUI::applyPosition() ui->filterChainText->setText(s); displayRateAndShift(); - applyChannelSettings(); + applySettings(); } void InterferometerGUI::tick() diff --git a/plugins/channelmimo/interferometer/interferometergui.h b/plugins/channelmimo/interferometer/interferometergui.h index db932138d..4f4e470b8 100644 --- a/plugins/channelmimo/interferometer/interferometergui.h +++ b/plugins/channelmimo/interferometer/interferometergui.h @@ -28,7 +28,7 @@ class PluginAPI; class DeviceUISet; -class MIMOSampleSink; +class MIMOChannel; class Interferometer; class SpectrumVis; class ScopeVis; @@ -40,7 +40,7 @@ namespace Ui { class InterferometerGUI : public RollupWidget, public PluginInstanceGUI { Q_OBJECT public: - static InterferometerGUI* create(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, MIMOSampleSink *mimoChannel); + static InterferometerGUI* create(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, MIMOChannel *mimoChannel); virtual void destroy(); virtual void setName(const QString& name); @@ -64,6 +64,7 @@ private: ChannelMarker m_channelMarker; InterferometerSettings m_settings; int m_sampleRate; + qint64 m_centerFrequency; double m_shiftFrequencyFactor; //!< Channel frequency shift factor bool m_doApplySettings; MovingAverageUtil m_channelPowerAvg; @@ -73,12 +74,11 @@ private: MessageQueue m_inputMessageQueue; uint32_t m_tickCount; - explicit InterferometerGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, MIMOSampleSink *rxChannel, QWidget* parent = nullptr); + explicit InterferometerGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, MIMOChannel *rxChannel, QWidget* parent = nullptr); virtual ~InterferometerGUI(); void blockApplySettings(bool block); void applySettings(bool force = false); - void applyChannelSettings(); void applyDecimation(); void applyPosition(); void displaySettings(); @@ -91,6 +91,7 @@ private slots: void handleSourceMessages(); void on_decimationFactor_currentIndexChanged(int index); void on_position_valueChanged(int value); + void on_correlationType_currentIndexChanged(int index); void onWidgetRolled(QWidget* widget, bool rollDown); void onMenuDialogCalled(const QPoint& p); void handleInputMessages(); diff --git a/plugins/channelmimo/interferometer/interferometergui.ui b/plugins/channelmimo/interferometer/interferometergui.ui index 6b96cabc0..70bb4c4b6 100644 --- a/plugins/channelmimo/interferometer/interferometergui.ui +++ b/plugins/channelmimo/interferometer/interferometergui.ui @@ -150,6 +150,42 @@ + + + + Qt::Vertical + + + + + + + Corr + + + + + + + Correlation type + + + + Add + + + + + Mul + + + + + FFT + + + + @@ -182,28 +218,6 @@ - - - - - 52 - 0 - - - - Channel power - - - Qt::LeftToRight - - - -100.0 dB - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - @@ -257,61 +271,6 @@ - - - - - - - 15 - 0 - - - - BP - - - - - - - Lowpass filter cutoff frequency - - - -60 - - - 60 - - - 1 - - - 30 - - - Qt::Horizontal - - - - - - - - 50 - 0 - - - - 3.0k - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - @@ -330,7 +289,7 @@ - Channel Spectrum + Frequency domain @@ -385,7 +344,7 @@ - Channel Scope + Time domain diff --git a/plugins/channelmimo/interferometer/interferometerplugin.cpp b/plugins/channelmimo/interferometer/interferometerplugin.cpp index 9ee31d514..6d74df8a1 100644 --- a/plugins/channelmimo/interferometer/interferometerplugin.cpp +++ b/plugins/channelmimo/interferometer/interferometerplugin.cpp @@ -58,18 +58,18 @@ void InterferometerPlugin::initPlugin(PluginAPI* pluginAPI) #ifdef SERVER_MODE PluginInstanceGUI* InterferometerPlugin::createRxChannelGUI( DeviceUISet *deviceUISet, - MIMOSampleSink *mimoChannel) const + MIMOChannel *mimoChannel) const { return 0; } #else -PluginInstanceGUI* InterferometerPlugin::createMIMOChannelGUI(DeviceUISet *deviceUISet, MIMOSampleSink *mimoChannel) const +PluginInstanceGUI* InterferometerPlugin::createMIMOChannelGUI(DeviceUISet *deviceUISet, MIMOChannel *mimoChannel) const { return InterferometerGUI::create(m_pluginAPI, deviceUISet, mimoChannel); } #endif -MIMOSampleSink* InterferometerPlugin::createMIMOChannelBS(DeviceAPI *deviceAPI) const +MIMOChannel* InterferometerPlugin::createMIMOChannelBS(DeviceAPI *deviceAPI) const { return new Interferometer(deviceAPI); } diff --git a/plugins/channelmimo/interferometer/interferometerplugin.h b/plugins/channelmimo/interferometer/interferometerplugin.h index 0a39fceca..d3b560a7d 100644 --- a/plugins/channelmimo/interferometer/interferometerplugin.h +++ b/plugins/channelmimo/interferometer/interferometerplugin.h @@ -23,7 +23,7 @@ #include "plugin/plugininterface.h" class DeviceUISet; -class MIMOSampleSink; +class MIMOChannel; class InterferometerPlugin : public QObject, PluginInterface { Q_OBJECT @@ -36,8 +36,8 @@ public: const PluginDescriptor& getPluginDescriptor() const; void initPlugin(PluginAPI* pluginAPI); - virtual PluginInstanceGUI* createMIMOChannelGUI(DeviceUISet *deviceUISet, MIMOSampleSink *mimoChannel) const; - virtual MIMOSampleSink* createMIMOChannelBS(DeviceAPI *deviceAPI) const; + virtual PluginInstanceGUI* createMIMOChannelGUI(DeviceUISet *deviceUISet, MIMOChannel *mimoChannel) const; + virtual MIMOChannel* createMIMOChannelBS(DeviceAPI *deviceAPI) const; virtual ChannelAPI* createMIMOChannelCS(DeviceAPI *deviceAPI) const; virtual ChannelWebAPIAdapter* createChannelWebAPIAdapter() const; diff --git a/plugins/channelmimo/interferometer/interferometersettings.h b/plugins/channelmimo/interferometer/interferometersettings.h index 860d5ced4..652e0610d 100644 --- a/plugins/channelmimo/interferometer/interferometersettings.h +++ b/plugins/channelmimo/interferometer/interferometersettings.h @@ -29,7 +29,7 @@ struct InterferometerSettings { CorrelationAdd, CorrelationMultiply, - CorrelationCorrelation + CorrelationFFT }; CorrelationType m_correlationType; diff --git a/plugins/channelmimo/interferometer/interferometersink.cpp b/plugins/channelmimo/interferometer/interferometersink.cpp index 569a6fd91..2aa164a87 100644 --- a/plugins/channelmimo/interferometer/interferometersink.cpp +++ b/plugins/channelmimo/interferometer/interferometersink.cpp @@ -18,25 +18,37 @@ #include #include "dsp/downchannelizer.h" +#include "dsp/dspcommands.h" + #include "interferometersink.h" MESSAGE_CLASS_DEFINITION(InterferometerSink::MsgConfigureChannelizer, Message) +MESSAGE_CLASS_DEFINITION(InterferometerSink::MsgSignalNotification, Message) +MESSAGE_CLASS_DEFINITION(InterferometerSink::MsgConfigureCorrelation, Message) -InterferometerSink::InterferometerSink() : - m_correlator(4096), +InterferometerSink::InterferometerSink(int fftSize) : + m_correlator(fftSize), m_spectrumSink(nullptr), m_scopeSink(nullptr) { for (int i = 0; i < 2; i++) { + m_sinkFifos[i].setSize(96000 * 4); m_sinks[i].setStreamIndex(i); m_channelizers[i] = new DownChannelizer(&m_sinks[i]); + // QObject::connect( + // &m_sinkBuffers[i], + // &SampleSinkVector::dataReady, + // this, + // [=](){ this->handleSinkBuffer(i); }, + // Qt::QueuedConnection + // ); QObject::connect( - &m_sinkBuffers[i], - &SampleSinkVector::dataReady, + &m_sinkFifos[i], + &SampleSinkFifo::dataReady, this, - [=](){ this->handleSinkBuffer(i); }, + [=](){ this->handleSinkFifo(i); }, Qt::QueuedConnection ); } @@ -58,14 +70,55 @@ void InterferometerSink::feed(const SampleVector::const_iterator& begin, const S return; } - m_sinkBuffers[streamIndex].write(begin, end); + m_sinkFifos[streamIndex].write(begin, end); + //m_sinkBuffers[streamIndex].write(begin, end); } -void InterferometerSink::handleSinkBuffer(unsigned int sinkIndex) +// void InterferometerSink::handleSinkBuffer(unsigned int sinkIndex) +// { +// SampleVector::iterator vbegin; +// SampleVector::iterator vend; +// m_sinkBuffers[sinkIndex].read(vbegin, vend); +// m_channelizers[sinkIndex]->feed(vbegin, vend, false); +// //qDebug("InterferometerSink::handleSinkBuffer: stream: %u samples: %ld", sinkIndex, vend - vbegin); + +// if (sinkIndex == 1) { +// run(); +// } +// } + +void InterferometerSink::handleSinkFifo(unsigned int sinkIndex) +{ + int samplesDone = 0; + + while ((m_sinkFifos[sinkIndex].fill() > 0) && (m_inputMessageQueue.size() == 0) && (samplesDone < m_channelizers[sinkIndex]->getInputSampleRate())) + { + SampleVector::iterator part1begin; + SampleVector::iterator part1end; + SampleVector::iterator part2begin; + SampleVector::iterator part2end; + + unsigned int count = m_sinkFifos[sinkIndex].readBegin(m_sinkFifos[sinkIndex].fill(), &part1begin, &part1end, &part2begin, &part2end); + + if (part1begin != part1end) { // first part of FIFO data + //qDebug("InterferometerSink::handleSinkFifo: part1-stream: %u count: %u", sinkIndex, count); + processFifo(part1begin, part1end, sinkIndex); + } + + if (part2begin != part2end) { // second part of FIFO data (used when block wraps around) + //qDebug("InterferometerSink::handleSinkFifo: part2-stream: %u count: %u", sinkIndex, count); + processFifo(part2begin, part2end, sinkIndex); + } + + m_sinkFifos[sinkIndex].readCommit((unsigned int) count); // adjust FIFO pointers + samplesDone += count; + } + + //qDebug("InterferometerSink::handleSinkFifo: done"); +} + +void InterferometerSink::processFifo(const SampleVector::iterator& vbegin, const SampleVector::iterator& vend, unsigned int sinkIndex) { - SampleVector::iterator vbegin; - SampleVector::iterator vend; - m_sinkBuffers[sinkIndex].read(vbegin, vend); m_channelizers[sinkIndex]->feed(vbegin, vend, false); if (sinkIndex == 1) { @@ -75,35 +128,32 @@ void InterferometerSink::handleSinkBuffer(unsigned int sinkIndex) void InterferometerSink::run() { - m_correlator.performCorr(m_sinks[0].getData(), m_sinks[1].getData()); - - if (m_scopeSink) { - m_scopeSink->feed(m_correlator.m_tcorr.begin(), m_correlator.m_tcorr.begin() + m_correlator.m_processed, false); - } - - if (m_spectrumSink) + if (m_correlator.performCorr(m_sinks[0].getData(), m_sinks[0].getSize(), m_sinks[1].getData(), m_sinks[1].getSize())) { - if (m_correlator.getCorrType() == InterferometerSettings::CorrelationCorrelation) { - m_spectrumSink->feed(m_correlator.m_scorr.begin(), m_correlator.m_scorr.begin() + m_correlator.m_processed, false); - } else { - m_spectrumSink->feed(m_correlator.m_tcorr.begin(), m_correlator.m_tcorr.begin() + m_correlator.m_processed, false); + if (m_scopeSink) { + m_scopeSink->feed(m_correlator.m_tcorr.begin(), m_correlator.m_tcorr.begin() + m_correlator.m_processed, false); } - } - if (m_correlator.m_remaining != 0) - { - for (int i = 0; i < 2; i++) + if (m_spectrumSink) { - std::copy( - m_sinks[i].getData().begin() + m_correlator.m_processed, - m_sinks[i].getData().begin() + m_correlator.m_processed + m_correlator.m_remaining, - m_sinks[i].getData().begin() - ); + if (m_correlator.getCorrType() == InterferometerSettings::CorrelationFFT) { + m_spectrumSink->feed(m_correlator.m_scorr.begin(), m_correlator.m_scorr.begin() + m_correlator.m_processed, false); + } else { + m_spectrumSink->feed(m_correlator.m_tcorr.begin(), m_correlator.m_tcorr.begin() + m_correlator.m_processed, false); + } } } - m_sinks[0].setDataStart(m_correlator.m_remaining); - m_sinks[1].setDataStart(m_correlator.m_remaining); + for (int i = 0; i < 2; i++) + { + std::copy( + m_sinks[i].getData().begin() + m_correlator.m_processed, + m_sinks[i].getData().begin() + m_correlator.m_processed + m_correlator.m_remaining[i], + m_sinks[i].getData().begin() + ); + + m_sinks[i].setDataStart(m_correlator.m_remaining[i]); + } } void InterferometerSink::handleInputMessages() @@ -140,6 +190,38 @@ bool InterferometerSink::handleMessage(const Message& cmd) return true; } + else if (MsgSignalNotification::match(cmd)) + { + MsgSignalNotification& cfg = (MsgSignalNotification&) cmd; + int inputSampleRate = cfg.getInputSampleRate(); + qint64 centerFrequency = cfg.getCenterFrequency(); + int streamIndex = cfg.getStreamIndex(); + + qDebug() << "InterferometerSink::handleMessage: MsgSignalNotification:" + << " inputSampleRate: " << inputSampleRate + << " centerFrequency: " << centerFrequency + << " streamIndex: " << streamIndex; + + if (streamIndex < 2) + { + DSPSignalNotification *notif = new DSPSignalNotification(inputSampleRate, centerFrequency); + m_channelizers[streamIndex]->getInputMessageQueue()->push(notif); + } + + return true; + } + else if (MsgConfigureCorrelation::match(cmd)) + { + MsgConfigureCorrelation& cfg = (MsgConfigureCorrelation&) cmd; + InterferometerSettings::CorrelationType correlationType = cfg.getCorrelationType(); + + qDebug() << "InterferometerSink::handleMessage: MsgConfigureCorrelation:" + << " correlationType: " << correlationType; + + m_correlator.setCorrType(correlationType); + + return true; + } else { return false; diff --git a/plugins/channelmimo/interferometer/interferometersink.h b/plugins/channelmimo/interferometer/interferometersink.h index 97745d86f..b38187171 100644 --- a/plugins/channelmimo/interferometer/interferometersink.h +++ b/plugins/channelmimo/interferometer/interferometersink.h @@ -20,8 +20,8 @@ #include -#include "dsp/mimosamplesink.h" -#include "dsp/samplesinkvector.h" +//#include "dsp/samplesinkvector.h" +#include "dsp/samplesinkfifo.h" #include "interferometerstreamsink.h" #include "interferometercorr.h" @@ -54,7 +54,50 @@ public: { } }; - InterferometerSink(); + class MsgConfigureCorrelation : public Message { + MESSAGE_CLASS_DECLARATION + + public: + InterferometerSettings::CorrelationType getCorrelationType() const { return m_correlationType; } + + static MsgConfigureCorrelation *create(InterferometerSettings::CorrelationType correlationType) { + return new MsgConfigureCorrelation(correlationType); + } + + private: + InterferometerSettings::CorrelationType m_correlationType; + + MsgConfigureCorrelation(InterferometerSettings::CorrelationType correlationType) : + Message(), + m_correlationType(correlationType) + {} + }; + + class MsgSignalNotification : public Message { + MESSAGE_CLASS_DECLARATION + + public: + int getInputSampleRate() const { return m_inputSampleRate; } + qint64 getCenterFrequency() const { return m_centerFrequency; } + int getStreamIndex() const { return m_streamIndex; } + + static MsgSignalNotification* create(int inputSampleRate, qint64 centerFrequency, int streamIndex) { + return new MsgSignalNotification(inputSampleRate, centerFrequency, streamIndex); + } + private: + int m_inputSampleRate; + qint64 m_centerFrequency; + int m_streamIndex; + + MsgSignalNotification(int inputSampleRate, qint64 centerFrequency, int streamIndex) : + Message(), + m_inputSampleRate(inputSampleRate), + m_centerFrequency(centerFrequency), + m_streamIndex(streamIndex) + { } + }; + + InterferometerSink(int fftSize); ~InterferometerSink(); MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; } //!< Get the queue for asynchronous inbound communication @@ -64,11 +107,13 @@ public: void feed(const SampleVector::const_iterator& begin, const SampleVector::const_iterator& end, unsigned int streamIndex); private: + void processFifo(const SampleVector::iterator& vbegin, const SampleVector::iterator& vend, unsigned int sinkIndex); void run(); bool handleMessage(const Message& cmd); InterferometerCorrelator m_correlator; - SampleSinkVector m_sinkBuffers[2]; + //SampleSinkVector m_sinkBuffers[2]; + SampleSinkFifo m_sinkFifos[2]; InterferometerStreamSink m_sinks[2]; DownChannelizer *m_channelizers[2]; BasebandSampleSink *m_spectrumSink; @@ -76,7 +121,8 @@ private: MessageQueue m_inputMessageQueue; //!< Queue for asynchronous inbound communication private slots: - void handleSinkBuffer(unsigned int sinkIndex); //!< Handle data when samples have to be processed + //void handleSinkBuffer(unsigned int sinkIndex); //!< Handle data when samples have to be processed + void handleSinkFifo(unsigned int sinkIndex); //!< Handle data when samples have to be processed void handleInputMessages(); }; diff --git a/plugins/channelmimo/interferometer/interferometerstreamsink.cpp b/plugins/channelmimo/interferometer/interferometerstreamsink.cpp index 7e9a12e26..f9f8bcd91 100644 --- a/plugins/channelmimo/interferometer/interferometerstreamsink.cpp +++ b/plugins/channelmimo/interferometer/interferometerstreamsink.cpp @@ -24,6 +24,7 @@ InterferometerStreamSink::InterferometerStreamSink() : m_streamIndex(0), m_dataSize(0), m_bufferSize(0), + m_dataStart(0), m_sampleRate(48000), m_settingsMutex(QMutex::Recursive) {} @@ -42,8 +43,10 @@ void InterferometerStreamSink::feed(const SampleVector::const_iterator& begin, c m_settingsMutex.lock(); m_dataSize = (end - begin) + m_dataStart; - if (m_dataSize > m_bufferSize) { + if (m_dataSize > m_bufferSize) + { m_data.resize(m_dataSize); + m_bufferSize = m_dataSize; } std::copy(begin, end, m_data.begin() + m_dataStart); @@ -57,6 +60,7 @@ bool InterferometerStreamSink::handleMessage(const Message& cmd) DownChannelizer::MsgChannelizerNotification& notif = (DownChannelizer::MsgChannelizerNotification&) cmd; qDebug() << "InterferometerStreamSink::handleMessage: MsgChannelizerNotification:" + << " streamIndex: " << m_streamIndex << " inputSampleRate: " << notif.getSampleRate() << " inputFrequencyOffset: " << notif.getFrequencyOffset(); m_sampleRate = notif.getSampleRate(); diff --git a/plugins/channelmimo/interferometer/interferometerstreamsink.h b/plugins/channelmimo/interferometer/interferometerstreamsink.h index a3a7031a7..68b567eb8 100644 --- a/plugins/channelmimo/interferometer/interferometerstreamsink.h +++ b/plugins/channelmimo/interferometer/interferometerstreamsink.h @@ -39,6 +39,7 @@ public: unsigned int getStreamIndex() const { return m_streamIndex; } void setStreamIndex(unsigned int streamIndex) { m_streamIndex = streamIndex; } SampleVector& getData() { return m_data; } + int getSize() const { return m_dataSize; } void setDataStart(int dataStart) { m_dataStart = dataStart; } private: diff --git a/sdrgui/mainwindow.cpp b/sdrgui/mainwindow.cpp index 0548e1461..b69e59097 100644 --- a/sdrgui/mainwindow.cpp +++ b/sdrgui/mainwindow.cpp @@ -454,6 +454,12 @@ void MainWindow::addMIMODevice() m_deviceUIs.back()->m_deviceAPI = deviceAPI; m_deviceUIs.back()->m_samplingDeviceControl->setPluginManager(m_pluginManager); QComboBox *channelSelector = m_deviceUIs.back()->m_samplingDeviceControl->getChannelSelector(); + // add MIMO channels + QList mimoChannelNames; + m_pluginManager->listMIMOChannels(mimoChannelNames); + QStringList mimoChannelNamesList(mimoChannelNames); + channelSelector->addItems(mimoChannelNamesList); + m_deviceUIs.back()->setNumberOfAvailableMIMOChannels(mimoChannelNamesList.size()); // Add Rx channels QList rxChannelNames; m_pluginManager->listRxChannels(rxChannelNames); @@ -1952,18 +1958,22 @@ void MainWindow::channelAddClicked(bool checked) } else if (deviceUI->m_deviceMIMOEngine) // MIMO device => all possible channels. Depends on index range { + int nbMIMOChannels = deviceUI->getNumberOfAvailableMIMOChannels(); int nbRxChannels = deviceUI->getNumberOfAvailableRxChannels(); int nbTxChannels = deviceUI->getNumberOfAvailableTxChannels(); int selectedIndex = deviceUI->m_samplingDeviceControl->getChannelSelector()->currentIndex(); - qDebug("MainWindow::channelAddClicked: MIMO: tab: %d nbRx: %d nbTx: %d selected: %d", - currentSourceTabIndex, nbRxChannels, nbTxChannels, selectedIndex); + qDebug("MainWindow::channelAddClicked: MIMO: tab: %d nbMIMO: %d nbRx: %d nbTx: %d selected: %d", + currentSourceTabIndex, nbMIMOChannels, nbRxChannels, nbTxChannels, selectedIndex); - if (selectedIndex < nbRxChannels) { - m_pluginManager->createRxChannelInstance( + if (selectedIndex < nbMIMOChannels) { + m_pluginManager->createMIMOChannelInstance( selectedIndex, deviceUI, deviceUI->m_deviceAPI); - } else if (selectedIndex < nbRxChannels + nbTxChannels) { + } else if (selectedIndex < nbMIMOChannels + nbRxChannels) { + m_pluginManager->createRxChannelInstance( + selectedIndex - nbMIMOChannels, deviceUI, deviceUI->m_deviceAPI); + } else if (selectedIndex < nbMIMOChannels + nbRxChannels + nbTxChannels) { m_pluginManager->createTxChannelInstance( - selectedIndex - nbRxChannels, deviceUI, deviceUI->m_deviceAPI); + selectedIndex - nbMIMOChannels - nbRxChannels, deviceUI, deviceUI->m_deviceAPI); } } }