diff --git a/plugins/channelrx/demodam/amdemod.cpp b/plugins/channelrx/demodam/amdemod.cpp index 99eeb328e..7e4149e26 100644 --- a/plugins/channelrx/demodam/amdemod.cpp +++ b/plugins/channelrx/demodam/amdemod.cpp @@ -36,6 +36,7 @@ #include "dsp/dspengine.h" #include "dsp/threadedbasebandsamplesink.h" #include "dsp/dspcommands.h" +#include "dsp/devicesamplemimo.h" #include "dsp/fftfilt.h" #include "device/deviceapi.h" #include "util/db.h" @@ -374,7 +375,7 @@ bool AMDemod::handleMessage(const Message& cmd) void AMDemod::applyAudioSampleRate(int sampleRate) { - qDebug("AMDemod::applyAudioSampleRate: %d", sampleRate); + qDebug("AMDemod::applyAudioSampleRate: sampleRate: %d m_inputSampleRate: %d", sampleRate, m_inputSampleRate); MsgConfigureChannelizer* channelConfigMsg = MsgConfigureChannelizer::create( sampleRate, m_settings.m_inputFrequencyOffset); @@ -408,7 +409,8 @@ void AMDemod::applyChannelSettings(int inputSampleRate, int inputFrequencyOffset { qDebug() << "AMDemod::applyChannelSettings:" << " inputSampleRate: " << inputSampleRate - << " inputFrequencyOffset: " << inputFrequencyOffset; + << " inputFrequencyOffset: " << inputFrequencyOffset + << " m_audioSampleRate: " << m_audioSampleRate; if ((m_inputFrequencyOffset != inputFrequencyOffset) || (m_inputSampleRate != inputSampleRate) || force) @@ -526,7 +528,18 @@ void AMDemod::applySettings(const AMDemodSettings& settings, bool force) reverseAPIKeys.append("volume"); } - if ((m_settings.m_streamIndex != settings.m_streamIndex) || 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"); } diff --git a/plugins/channelrx/demodam/amdemodgui.cpp b/plugins/channelrx/demodam/amdemodgui.cpp index 8a4aabfc6..756a0a608 100644 --- a/plugins/channelrx/demodam/amdemodgui.cpp +++ b/plugins/channelrx/demodam/amdemodgui.cpp @@ -240,6 +240,7 @@ void AMDemodGUI::onMenuDialogCalled(const QPoint &p) dialog.exec(); m_settings.m_streamIndex = dialog.getSelectedStreamIndex(); + displayStreamIndex(); applySettings(); } diff --git a/plugins/samplemimo/testmi/testmi.cpp b/plugins/samplemimo/testmi/testmi.cpp index 8780743b4..d34039475 100644 --- a/plugins/samplemimo/testmi/testmi.cpp +++ b/plugins/samplemimo/testmi/testmi.cpp @@ -51,9 +51,9 @@ TestMI::TestMI(DeviceAPI *deviceAPI) : { m_fileSink = new FileRecord(QString("test_%1.sdriq").arg(m_deviceAPI->getDeviceUID())); m_deviceAPI->setNbSourceStreams(2); - m_deviceAPI->addSourceStream(); // Add a new source stream data set in the engine - m_deviceAPI->addSourceStream(); // Add a new source stream data set in the engine - m_deviceAPI->addAncillarySink(m_fileSink); + m_deviceAPI->addSourceStream(true); // Add a new source stream data set in the engine - asynchronous handling of FIFOs + m_deviceAPI->addSourceStream(true); // Add a new source stream data set in the engine - asynchronous handling of FIFOs + //m_deviceAPI->addAncillarySink(m_fileSink); TODO: implement when active m_sampleSinkFifos.push_back(SampleSinkFifo(96000 * 4)); m_sampleSinkFifos.push_back(SampleSinkFifo(96000 * 4)); m_networkManager = new QNetworkAccessManager(); @@ -87,15 +87,18 @@ void TestMI::init() bool TestMI::start() { + qDebug("TestMI::start"); QMutexLocker mutexLocker(&m_mutex); - if (m_running) stop(); + if (m_running) { + stop(); + } - m_testSourceThreads.push_back(new TestMIThread(&m_sampleSinkFifos[0])); + m_testSourceThreads.push_back(new TestMIThread(&m_sampleSinkFifos[0], 0)); m_testSourceThreads.back()->setSamplerate(m_settings.m_streams[0].m_sampleRate); m_testSourceThreads.back()->startStop(true); - m_testSourceThreads.push_back(new TestMIThread(&m_sampleSinkFifos[1])); + m_testSourceThreads.push_back(new TestMIThread(&m_sampleSinkFifos[1], 1)); m_testSourceThreads.back()->setSamplerate(m_settings.m_streams[1].m_sampleRate); m_testSourceThreads.back()->startStop(true); @@ -109,6 +112,7 @@ bool TestMI::start() void TestMI::stop() { + qDebug("TestMI::stop"); QMutexLocker mutexLocker(&m_mutex); std::vector::iterator it = m_testSourceThreads.begin(); @@ -263,12 +267,10 @@ bool TestMI::applySettings(const TestMISettings& settings, bool force) { DeviceSettingsKeys deviceSettingsKeys; - QList> streamReverseAPIKeys; // FIXME: one set of keys per streams - for (unsigned int istream = 0; istream < m_settings.m_streams.size(); istream++) { deviceSettingsKeys.m_streamsSettingsKeys.push_back(QList()); - QList& reverseAPIKeys = streamReverseAPIKeys.back(); + QList& reverseAPIKeys = deviceSettingsKeys.m_streamsSettingsKeys.back(); if ((m_settings.m_streams[istream].m_autoCorrOptions != settings.m_streams[istream].m_autoCorrOptions) || force) { @@ -296,7 +298,8 @@ bool TestMI::applySettings(const TestMISettings& settings, bool force) if ((istream < m_testSourceThreads.size()) && (m_testSourceThreads[istream])) { m_testSourceThreads[istream]->setSamplerate(settings.m_streams[istream].m_sampleRate); - qDebug("TestMI::applySettings: sample rate set to %d", settings.m_streams[istream].m_sampleRate); + qDebug("TestMI::applySettings: thread on stream: %u sample rate set to %d", + istream, settings.m_streams[istream].m_sampleRate); } } @@ -307,7 +310,8 @@ bool TestMI::applySettings(const TestMISettings& settings, bool force) if ((istream < m_testSourceThreads.size()) && (m_testSourceThreads[istream])) { m_testSourceThreads[istream]->setLog2Decimation(settings.m_streams[istream].m_log2Decim); - qDebug() << "TestMI::applySettings: set decimation to " << (1<setFcPos((int) settings.m_streams[istream].m_fcPos); m_testSourceThreads[istream]->setFrequencyShift(frequencyShift); qDebug() << "TestMI::applySettings:" - << " istream: " << istream + << " thread on istream: " << istream << " center freq: " << settings.m_streams[istream].m_centerFrequency << " Hz" << " device center freq: " << deviceCenterFrequency << " Hz" << " device sample rate: " << devSampleRate << "Hz" diff --git a/plugins/samplemimo/testmi/testmithread.cpp b/plugins/samplemimo/testmi/testmithread.cpp index bb06a9085..53457a7b4 100644 --- a/plugins/samplemimo/testmi/testmithread.cpp +++ b/plugins/samplemimo/testmi/testmithread.cpp @@ -28,7 +28,7 @@ MESSAGE_CLASS_DEFINITION(TestMIThread::MsgStartStop, Message) -TestMIThread::TestMIThread(SampleSinkFifo* sampleFifo, QObject* parent) : +TestMIThread::TestMIThread(SampleSinkFifo* sampleFifo, int streamIndex, QObject* parent) : QThread(parent), m_running(false), m_buf(0), @@ -36,6 +36,7 @@ TestMIThread::TestMIThread(SampleSinkFifo* sampleFifo, QObject* parent) : m_chunksize(0), m_convertBuffer(TESTMI_BLOCKSIZE), m_sampleFifo(sampleFifo), + m_streamIndex(streamIndex), m_frequencyShift(0), m_toneFrequency(440), m_modulation(TestMIStreamSettings::ModulationNone), diff --git a/plugins/samplemimo/testmi/testmithread.h b/plugins/samplemimo/testmi/testmithread.h index 2df410ae1..72e8bad97 100644 --- a/plugins/samplemimo/testmi/testmithread.h +++ b/plugins/samplemimo/testmi/testmithread.h @@ -58,7 +58,7 @@ public: { } }; - TestMIThread(SampleSinkFifo* sampleFifo, QObject* parent = 0); + TestMIThread(SampleSinkFifo* sampleFifo, int streamIndex, QObject* parent = 0); ~TestMIThread(); void startStop(bool start); @@ -90,6 +90,7 @@ private: quint32 m_chunksize; SampleVector m_convertBuffer; SampleSinkFifo* m_sampleFifo; + int m_streamIndex; NCOF m_nco; NCOF m_toneNco; int m_frequencyShift; diff --git a/sdrbase/device/deviceapi.cpp b/sdrbase/device/deviceapi.cpp index 3cf7fb95b..9992ecc09 100644 --- a/sdrbase/device/deviceapi.cpp +++ b/sdrbase/device/deviceapi.cpp @@ -58,10 +58,10 @@ DeviceAPI::~DeviceAPI() { } -void DeviceAPI::addSourceStream() +void DeviceAPI::addSourceStream(bool connect) { if (m_deviceMIMOEngine) { - m_deviceMIMOEngine->addSourceStream(); + m_deviceMIMOEngine->addSourceStream(connect); } } @@ -72,10 +72,10 @@ void DeviceAPI::removeLastSourceStream() } } -void DeviceAPI::addSinkStream() +void DeviceAPI::addSinkStream(bool connect) { if (m_deviceMIMOEngine) { - m_deviceMIMOEngine->addSinkStream(); + m_deviceMIMOEngine->addSinkStream(connect); } } @@ -92,7 +92,7 @@ void DeviceAPI::addAncillarySink(BasebandSampleSink *sink) m_deviceSourceEngine->addSink(sink); } else if (m_deviceSinkEngine) { m_deviceSinkEngine->addSpectrumSink(sink); - } + } // TODO: MIMO } void DeviceAPI::removeAncillarySink(BasebandSampleSink* sink) @@ -101,7 +101,7 @@ void DeviceAPI::removeAncillarySink(BasebandSampleSink* sink) m_deviceSourceEngine->removeSink(sink); } else if (m_deviceSinkEngine) { m_deviceSinkEngine->removeSpectrumSink(sink); - } + } // TODO: MIMO } void DeviceAPI::setSpectrumSinkInput(bool sourceElseSink, unsigned int index) @@ -126,6 +126,8 @@ void DeviceAPI::removeChannelSink(ThreadedBasebandSampleSink* sink, int streamIn if (m_deviceSourceEngine) { m_deviceSourceEngine->removeThreadedSink(sink); + } else if (m_deviceMIMOEngine) { + m_deviceMIMOEngine->removeChannelSink(sink, streamIndex); } } diff --git a/sdrbase/device/deviceapi.h b/sdrbase/device/deviceapi.h index 6d3547c1d..3aa63a0c1 100644 --- a/sdrbase/device/deviceapi.h +++ b/sdrbase/device/deviceapi.h @@ -67,9 +67,9 @@ public: ~DeviceAPI(); // MIMO Engine baseband / channel lists management - void addSourceStream(); + void addSourceStream(bool connect); void removeLastSourceStream(); - void addSinkStream(); + void addSinkStream(bool connect); void removeLastSinkStream(); void addAncillarySink(BasebandSampleSink* sink); //!< Adds a sink to receive full baseband and that is not a channel (e.g. spectrum) diff --git a/sdrbase/dsp/dspdevicemimoengine.cpp b/sdrbase/dsp/dspdevicemimoengine.cpp index 3f6390d31..cd318e10b 100644 --- a/sdrbase/dsp/dspdevicemimoengine.cpp +++ b/sdrbase/dsp/dspdevicemimoengine.cpp @@ -122,10 +122,10 @@ void DSPDeviceMIMOEngine::setMIMOSequence(int sequence) m_sampleMIMOSequence = sequence; } -void DSPDeviceMIMOEngine::addSourceStream() +void DSPDeviceMIMOEngine::addSourceStream(bool connect) { qDebug("DSPDeviceMIMOEngine::addSourceStream"); - AddSourceStream cmd; + AddSourceStream cmd(connect); m_syncMessenger.sendWait(cmd); } @@ -136,10 +136,10 @@ void DSPDeviceMIMOEngine::removeLastSourceStream() m_syncMessenger.sendWait(cmd); } -void DSPDeviceMIMOEngine::addSinkStream() +void DSPDeviceMIMOEngine::addSinkStream(bool connect) { qDebug("DSPDeviceMIMOEngine::addSinkStream"); - AddSinkStream cmd; + AddSinkStream cmd(connect); m_syncMessenger.sendWait(cmd); } @@ -335,6 +335,81 @@ void DSPDeviceMIMOEngine::work(int nbWriteSamples) // TODO: sinks } +void DSPDeviceMIMOEngine::workSampleSink(unsigned int sinkIndex) +{ + if (m_state != StRunning) { + return; + } + + SampleSinkFifo* sampleFifo = m_deviceSampleMIMO->getSampleSinkFifo(sinkIndex); + int samplesDone = 0; + bool positiveOnly = false; + + while ((sampleFifo->fill() > 0) && (m_inputMessageQueue.size() == 0) && (samplesDone < m_deviceSampleMIMO->getSourceSampleRate(sinkIndex))) + { + SampleVector::iterator part1begin; + SampleVector::iterator part1end; + SampleVector::iterator part2begin; + SampleVector::iterator part2end; + + std::size_t count = sampleFifo->readBegin(sampleFifo->fill(), &part1begin, &part1end, &part2begin, &part2end); + + // first part of FIFO data + if (part1begin != part1end) + { + // TODO: DC and IQ corrections + + // feed data to direct sinks + if (sinkIndex < m_basebandSampleSinks.size()) + { + for (BasebandSampleSinks::const_iterator it = m_basebandSampleSinks[sinkIndex].begin(); it != m_basebandSampleSinks[sinkIndex].end(); ++it) { + (*it)->feed(part1begin, part1end, positiveOnly); + } + } + + // possibly feed data to spectrum sink + if ((m_spectrumSink) && (m_spectrumInputSourceElseSink) && (sinkIndex == m_spectrumInputIndex)) { + m_spectrumSink->feed(part1begin, part1end, positiveOnly); + } + + // feed data to threaded sinks + for (ThreadedBasebandSampleSinks::const_iterator it = m_threadedBasebandSampleSinks[sinkIndex].begin(); it != m_threadedBasebandSampleSinks[sinkIndex].end(); ++it) + { + (*it)->feed(part1begin, part1end, positiveOnly); + } + } + + // second part of FIFO data (used when block wraps around) + if(part2begin != part2end) + { + // TODO: DC and IQ corrections + + // feed data to direct sinks + if (sinkIndex < m_basebandSampleSinks.size()) + { + for (BasebandSampleSinks::const_iterator it = m_basebandSampleSinks[sinkIndex].begin(); it != m_basebandSampleSinks[sinkIndex].end(); ++it) { + (*it)->feed(part2begin, part2end, positiveOnly); + } + } + + // possibly feed data to spectrum sink + if ((m_spectrumSink) && (m_spectrumInputSourceElseSink) && (sinkIndex == m_spectrumInputIndex)) { + m_spectrumSink->feed(part2begin, part2end, positiveOnly); + } + + // feed data to threaded sinks + for (ThreadedBasebandSampleSinks::const_iterator it = m_threadedBasebandSampleSinks[sinkIndex].begin(); it != m_threadedBasebandSampleSinks[sinkIndex].end(); ++it) + { + (*it)->feed(part2begin, part2end, positiveOnly); + } + } + + // adjust FIFO pointers + sampleFifo->readCommit((unsigned int) count); + samplesDone += count; + } +} + // notStarted -> idle -> init -> running -+ // ^ | // +-----------------------+ @@ -544,7 +619,7 @@ DSPDeviceMIMOEngine::State DSPDeviceMIMOEngine::gotoError(const QString& errorMe void DSPDeviceMIMOEngine::handleData() { - if(m_state == StRunning) + if (m_state == StRunning) { work(0); // TODO: implement Tx side } @@ -554,14 +629,38 @@ void DSPDeviceMIMOEngine::handleSetMIMO(DeviceSampleMIMO* mimo) { m_deviceSampleMIMO = mimo; - if (mimo && (mimo->getNbSinkFifos() > 0)) + if (mimo) { - // if there is at least one Rx then the first Rx drives the FIFOs - qDebug("DSPDeviceMIMOEngine::handleSetMIMO: set %s", qPrintable(mimo->getDeviceDescription())); - connect(m_deviceSampleMIMO->getSampleSinkFifo(0), SIGNAL(dataReady()), this, SLOT(handleData()), Qt::QueuedConnection); + if ((m_sampleSinkConnectionIndexes.size() == 1) && (m_sampleSourceConnectionIndexes.size() == 0)) // true MIMO (synchronous FIFOs) + { + qDebug("DSPDeviceMIMOEngine::handleSetMIMO: synchronous set %s", qPrintable(mimo->getDeviceDescription())); + // connect(m_deviceSampleMIMO->getSampleSinkFifo(m_sampleSinkConnectionIndexes[0]), SIGNAL(dataReady()), this, SLOT(handleData()), Qt::QueuedConnection); + QObject::connect( + m_deviceSampleMIMO->getSampleSinkFifo(m_sampleSinkConnectionIndexes[0]), + &SampleSinkFifo::dataReady, + this, + [=](){ this->handleData(); }, // lambda function is not strictly needed here + Qt::QueuedConnection + ); + } + else if (m_sampleSinkConnectionIndexes.size() != 0) // asynchronous FIFOs + { + for (unsigned int isink = 0; isink < m_sampleSinkConnectionIndexes.size(); isink++) + { + qDebug("DSPDeviceMIMOEngine::handleSetMIMO: asynchronous sources set %s channel %u", + qPrintable(mimo->getDeviceDescription()), isink); + QObject::connect( + m_deviceSampleMIMO->getSampleSinkFifo(m_sampleSinkConnectionIndexes[isink]), + &SampleSinkFifo::dataReady, + this, + [=](){ this->workSampleSink(isink); }, + Qt::QueuedConnection + ); + } + } } - // TODO: only Tx + // TODO: Tx } void DSPDeviceMIMOEngine::handleSynchronousMessages() @@ -601,8 +700,13 @@ void DSPDeviceMIMOEngine::handleSynchronousMessages() else if (AddSourceStream::match(*message)) { m_basebandSampleSinks.push_back(BasebandSampleSinks()); + int currentIndex = m_threadedBasebandSampleSinks.size(); m_threadedBasebandSampleSinks.push_back(ThreadedBasebandSampleSinks()); m_sourcesCorrections.push_back(SourceCorrection()); + + if (((AddSourceStream *) message)->getConnect()) { + m_sampleSinkConnectionIndexes.push_back(currentIndex); + } } else if (RemoveLastSourceStream::match(*message)) { @@ -611,7 +715,12 @@ void DSPDeviceMIMOEngine::handleSynchronousMessages() } else if (AddSinkStream::match(*message)) { + int currentIndex = m_threadedBasebandSampleSources.size(); m_threadedBasebandSampleSources.push_back(ThreadedBasebandSampleSources()); + + if (((AddSinkStream *) message)->getConnect()) { + m_sampleSourceConnectionIndexes.push_back(currentIndex); + } } else if (RemoveLastSinkStream::match(*message)) { diff --git a/sdrbase/dsp/dspdevicemimoengine.h b/sdrbase/dsp/dspdevicemimoengine.h index fd7f3a299..4276ae015 100644 --- a/sdrbase/dsp/dspdevicemimoengine.h +++ b/sdrbase/dsp/dspdevicemimoengine.h @@ -62,6 +62,11 @@ public: class AddSourceStream : public Message { MESSAGE_CLASS_DECLARATION + public: + AddSourceStream(bool connect) : Message(), m_connect(connect) { } + bool getConnect() const { return m_connect; } + private: + bool m_connect; }; class RemoveLastSourceStream : public Message { @@ -70,6 +75,11 @@ public: class AddSinkStream : public Message { MESSAGE_CLASS_DECLARATION + public: + AddSinkStream(bool connect) : Message(), m_connect(connect) { } + bool getConnect() const { return m_connect; } + private: + bool m_connect; }; class RemoveLastSinkStream : public Message { @@ -266,9 +276,9 @@ public: void setMIMOSequence(int sequence); //!< Set the sample MIMO sequence in type uint getUID() const { return m_uid; } - void addSourceStream(); + void addSourceStream(bool connect); void removeLastSourceStream(); - void addSinkStream(); + void addSinkStream(bool connect); void removeLastSinkStream(); void addChannelSource(ThreadedBasebandSampleSource* source, int index = 0); //!< Add a channel source that will run on its own thread @@ -358,9 +368,11 @@ private: typedef std::list ThreadedBasebandSampleSinks; std::vector m_threadedBasebandSampleSinks; //!< channel sample sinks on their own thread (per input stream) + std::vector m_sampleSinkConnectionIndexes; typedef std::list ThreadedBasebandSampleSources; std::vector m_threadedBasebandSampleSources; //!< channel sample sources on their own threads (per output stream) + std::vector m_sampleSourceConnectionIndexes; std::vector m_sourcesCorrections; @@ -380,6 +392,7 @@ private: private slots: void handleData(); //!< Handle data when samples have to be processed + void workSampleSink(unsigned int sinkIndex); void handleSynchronousMessages(); //!< Handle synchronous messages with the thread void handleInputMessages(); //!< Handle input message queue void handleForwardToSpectrumSink(int nbSamples); diff --git a/sdrgui/mainwindow.cpp b/sdrgui/mainwindow.cpp index 5ea432d3e..b62ce1e17 100644 --- a/sdrgui/mainwindow.cpp +++ b/sdrgui/mainwindow.cpp @@ -1837,7 +1837,7 @@ void MainWindow::sampleMIMOChanged() deviceUI->m_deviceAPI->setSamplingDevicePluginInterface( DeviceEnumerator::instance()->getMIMOPluginInterface(deviceUI->m_samplingDeviceControl->getSelectedDeviceIndex())); - // constructs new GUI and output object + // constructs new GUI and MIMO object DeviceSampleMIMO *mimo = deviceUI->m_deviceAPI->getPluginInterface()->createSampleMIMOPluginInstance( deviceUI->m_deviceAPI->getSamplingDeviceId(), deviceUI->m_deviceAPI); deviceUI->m_deviceAPI->setSampleMIMO(mimo);