diff --git a/sdrbase/dsp/devicesamplemimo.cpp b/sdrbase/dsp/devicesamplemimo.cpp
new file mode 100644
index 000000000..b1b351686
--- /dev/null
+++ b/sdrbase/dsp/devicesamplemimo.cpp
@@ -0,0 +1,62 @@
+///////////////////////////////////////////////////////////////////////////////////
+// Copyright (C) 2019 F4EXB //
+// written by Edouard Griffiths //
+// //
+// This program is free software; you can redistribute it and/or modify //
+// it under the terms of the GNU General Public License as published by //
+// the Free Software Foundation as version 3 of the License, or //
+// (at your option) any later version. //
+// //
+// This program is distributed in the hope that it will be useful, //
+// but WITHOUT ANY WARRANTY; without even the implied warranty of //
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
+// GNU General Public License V3 for more details. //
+// //
+// You should have received a copy of the GNU General Public License //
+// along with this program. If not, see . //
+///////////////////////////////////////////////////////////////////////////////////
+
+#include
+
+#include "devicesamplemimo.h"
+
+DeviceSampleMIMO::DeviceSampleMIMO() :
+ m_guiMessageQueue(0)
+{
+ connect(&m_inputMessageQueue, SIGNAL(messageEnqueued()), this, SLOT(handleInputMessages()));
+}
+
+DeviceSampleMIMO::~DeviceSampleMIMO()
+{
+}
+
+void DeviceSampleMIMO::handleInputMessages()
+{
+ Message* message;
+
+ while ((message = m_inputMessageQueue.pop()) != 0)
+ {
+ if (handleMessage(*message))
+ {
+ delete message;
+ }
+ }
+}
+
+SampleSourceFifo* DeviceSampleMIMO::getSampleSourceFifo(int index)
+{
+ if ((index < 0) || (index >= m_sampleSourceFifos.size())) {
+ return nullptr;
+ } else {
+ return &m_sampleSourceFifos[index];
+ }
+}
+
+SampleSinkFifo* DeviceSampleMIMO::getSampleSinkFifo(int index)
+{
+ if ((index < 0) || (index >= m_sampleSinkFifos.size())) {
+ return nullptr;
+ } else {
+ return &m_sampleSinkFifos[index];
+ }
+}
diff --git a/sdrbase/dsp/devicesamplemimo.h b/sdrbase/dsp/devicesamplemimo.h
new file mode 100644
index 000000000..cd435c4b1
--- /dev/null
+++ b/sdrbase/dsp/devicesamplemimo.h
@@ -0,0 +1,140 @@
+///////////////////////////////////////////////////////////////////////////////////
+// Copyright (C) 2019 F4EXB //
+// written by Edouard Griffiths //
+// //
+// This program is free software; you can redistribute it and/or modify //
+// it under the terms of the GNU General Public License as published by //
+// the Free Software Foundation as version 3 of the License, or //
+// (at your option) any later version. //
+// //
+// This program is distributed in the hope that it will be useful, //
+// but WITHOUT ANY WARRANTY; without even the implied warranty of //
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
+// GNU General Public License V3 for more details. //
+// //
+// You should have received a copy of the GNU General Public License //
+// along with this program. If not, see . //
+///////////////////////////////////////////////////////////////////////////////////
+
+#ifndef SDRBASE_DSP_DEVICESAMPLEMIMO_H_
+#define SDRBASE_DSP_DEVICESAMPLEMIMO_H_
+
+#include
+
+#include "samplesourcefifo.h"
+#include "samplesinkfifo.h"
+#include "util/message.h"
+#include "util/messagequeue.h"
+#include "export.h"
+
+namespace SWGSDRangel
+{
+ class SWGDeviceSettings;
+ class SWGDeviceState;
+ class SWGDeviceReport;
+}
+
+class SDRBASE_API DeviceSampleMIMO : public QObject {
+ Q_OBJECT
+public:
+ typedef enum {
+ FC_POS_INFRA = 0,
+ FC_POS_SUPRA,
+ FC_POS_CENTER
+ } fcPos_t;
+
+ DeviceSampleMIMO();
+ virtual ~DeviceSampleMIMO();
+ virtual void destroy() = 0;
+
+ virtual void init() = 0; //!< initializations to be done when all collaborating objects are created and possibly connected
+ virtual bool start() = 0;
+ virtual void stop() = 0;
+
+ virtual QByteArray serialize() const = 0;
+ virtual bool deserialize(const QByteArray& data) = 0;
+
+ virtual const QString& getDeviceDescription() const = 0;
+
+ virtual int getSinkSampleRate(int index) const = 0; //!< Sample rate exposed by the sink at index
+ virtual void setSinkSampleRate(int sampleRate, int index) = 0; //!< For when the sink sample rate is set externally
+ virtual quint64 getSinkCenterFrequency(int index) const = 0; //!< Center frequency exposed by the sink at index
+ virtual void setSinkCenterFrequency(qint64 centerFrequency, int index) = 0;
+
+ virtual int getSourceSampleRate(int index) const = 0; //!< Sample rate exposed by the source at index
+ virtual void setSourceSampleRate(int sampleRate, int index) = 0; //!< For when the source sample rate is set externally
+ virtual quint64 getSourceCenterFrequency(int index) const = 0; //!< Center frequency exposed by the source at index
+ virtual void setSourceCenterFrequency(qint64 centerFrequency, int index) = 0;
+
+ virtual bool handleMessage(const Message& message) = 0;
+
+ virtual int webapiSettingsGet(
+ SWGSDRangel::SWGDeviceSettings& response,
+ QString& errorMessage)
+ {
+ (void) response;
+ errorMessage = "Not implemented";
+ return 501;
+ }
+
+ virtual int webapiSettingsPutPatch(
+ bool force, //!< true to force settings = put
+ const QStringList& deviceSettingsKeys,
+ SWGSDRangel::SWGDeviceSettings& response,
+ QString& errorMessage)
+ {
+ (void) force;
+ (void) deviceSettingsKeys;
+ (void) response;
+ errorMessage = "Not implemented";
+ return 501;
+ }
+
+ virtual int webapiRunGet(
+ SWGSDRangel::SWGDeviceState& response,
+ QString& errorMessage)
+ {
+ (void) response;
+ errorMessage = "Not implemented";
+ return 501;
+ }
+
+ virtual int webapiRun(bool run,
+ SWGSDRangel::SWGDeviceState& response,
+ QString& errorMessage)
+ {
+ (void) run;
+ (void) response;
+ errorMessage = "Not implemented";
+ return 501;
+ }
+
+ virtual int webapiReportGet(
+ SWGSDRangel::SWGDeviceReport& response,
+ QString& errorMessage)
+ {
+ (void) response;
+ errorMessage = "Not implemented";
+ return 501;
+ }
+
+ MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; }
+ virtual void setMessageQueueToGUI(MessageQueue *queue) = 0; // pure virtual so that child classes must have to deal with this
+ MessageQueue *getMessageQueueToGUI() { return m_guiMessageQueue; }
+
+ unsigned int getNbSourceFifos() const { return m_sampleSourceFifos.size(); }
+ unsigned int getNbSinkFifos() const { return m_sampleSinkFifos.size(); }
+ SampleSourceFifo* getSampleSourceFifo(int index);
+ SampleSinkFifo* getSampleSinkFifo(int index);
+
+protected slots:
+ void handleInputMessages();
+
+protected:
+ std::vector m_sampleSourceFifos; //!< Tx FIFOs
+ std::vector m_sampleSinkFifos; //!< Rx FIFOs
+ MessageQueue m_inputMessageQueue; //!< Input queue to the sink
+ MessageQueue *m_guiMessageQueue; //!< Input message queue to the GUI
+};
+
+#endif // SDRBASE_DSP_DEVICESAMPLEMIMO_H_
\ No newline at end of file
diff --git a/sdrbase/dsp/dspdevicemimoengine.cpp b/sdrbase/dsp/dspdevicemimoengine.cpp
new file mode 100644
index 000000000..810b1bc6b
--- /dev/null
+++ b/sdrbase/dsp/dspdevicemimoengine.cpp
@@ -0,0 +1,271 @@
+///////////////////////////////////////////////////////////////////////////////////
+// Copyright (C) 2019 F4EXB //
+// written by Edouard Griffiths //
+// //
+// This program is free software; you can redistribute it and/or modify //
+// it under the terms of the GNU General Public License as published by //
+// the Free Software Foundation as version 3 of the License, or //
+// (at your option) any later version. //
+// //
+// This program is distributed in the hope that it will be useful, //
+// but WITHOUT ANY WARRANTY; without even the implied warranty of //
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
+// GNU General Public License V3 for more details. //
+// //
+// You should have received a copy of the GNU General Public License //
+// along with this program. If not, see . //
+///////////////////////////////////////////////////////////////////////////////////
+
+#include
+
+#include "dsp/dspcommands.h"
+#include "threadedbasebandsamplesource.h"
+#include "threadedbasebandsamplesink.h"
+#include "devicesamplemimo.h"
+
+#include "dspdevicemimoengine.h"
+
+DSPDeviceMIMOEngine::DSPDeviceMIMOEngine(uint32_t uid, QObject* parent) :
+ QThread(parent),
+ m_uid(uid),
+ m_state(StNotStarted)
+{
+ connect(&m_inputMessageQueue, SIGNAL(messageEnqueued()), this, SLOT(handleInputMessages()), Qt::QueuedConnection);
+ connect(&m_syncMessenger, SIGNAL(messageSent()), this, SLOT(handleSynchronousMessages()), Qt::QueuedConnection);
+
+ moveToThread(this);
+}
+
+DSPDeviceMIMOEngine::~DSPDeviceMIMOEngine()
+{
+ stop();
+ wait();
+}
+
+void DSPDeviceMIMOEngine::run()
+{
+ qDebug() << "DSPDeviceMIMOEngine::run";
+ m_state = StIdle;
+ exec();
+}
+
+void DSPDeviceMIMOEngine::start()
+{
+ qDebug() << "DSPDeviceMIMOEngine::start";
+ QThread::start();
+}
+
+void DSPDeviceMIMOEngine::stop()
+{
+ qDebug() << "DSPDeviceMIMOEngine::stop";
+ gotoIdle();
+ m_state = StNotStarted;
+ QThread::exit();
+}
+
+bool DSPDeviceMIMOEngine::initProcess()
+{
+ qDebug() << "DSPDeviceMIMOEngine::initGeneration";
+ DSPGenerationInit cmd;
+
+ return m_syncMessenger.sendWait(cmd) == StReady;
+}
+
+bool DSPDeviceMIMOEngine::startProcess()
+{
+ qDebug() << "DSPDeviceMIMOEngine::startGeneration";
+ DSPGenerationStart cmd;
+
+ return m_syncMessenger.sendWait(cmd) == StRunning;
+}
+
+void DSPDeviceMIMOEngine::stopProcess()
+{
+ qDebug() << "DSPDeviceMIMOEngine::stopGeneration";
+ DSPGenerationStop cmd;
+ m_syncMessenger.storeMessage(cmd);
+ handleSynchronousMessages();
+}
+
+void DSPDeviceMIMOEngine::setMIMO(DeviceSampleMIMO* mimo)
+{
+ qDebug() << "DSPDeviceMIMOEngine::setSink";
+ SetSampleMIMO cmd(mimo);
+ m_syncMessenger.sendWait(cmd);
+}
+
+void DSPDeviceMIMOEngine::setMIMOSequence(int sequence)
+{
+ qDebug("DSPDeviceMIMOEngine::setSinkSequence: seq: %d", sequence);
+ m_sampleMIMOSequence = sequence;
+}
+
+void DSPDeviceMIMOEngine::addChannelSource(ThreadedBasebandSampleSource* source, int index)
+{
+ qDebug() << "DSPDeviceMIMOEngine::addThreadedSource: "
+ << source->objectName().toStdString().c_str()
+ << " at: "
+ << index;
+ AddThreadedBasebandSampleSource cmd(source, index);
+ m_syncMessenger.sendWait(cmd);
+}
+
+void DSPDeviceMIMOEngine::removeChannelSource(ThreadedBasebandSampleSource* source, int index)
+{
+ qDebug() << "DSPDeviceMIMOEngine::removeThreadedSource: "
+ << source->objectName().toStdString().c_str()
+ << " at: "
+ << index;
+ RemoveThreadedBasebandSampleSource cmd(source, index);
+ m_syncMessenger.sendWait(cmd);
+}
+
+void DSPDeviceMIMOEngine::addChannelSink(ThreadedBasebandSampleSink* sink, int index)
+{
+ qDebug() << "DSPDeviceMIMOEngine::addThreadedSink: "
+ << sink->objectName().toStdString().c_str()
+ << " at: "
+ << index;
+ AddThreadedBasebandSampleSink cmd(sink, index);
+ m_syncMessenger.sendWait(cmd);
+}
+
+void DSPDeviceMIMOEngine::removeChannelSink(ThreadedBasebandSampleSink* sink, int index)
+{
+ qDebug() << "DSPDeviceMIMOEngine::removeThreadedSink: "
+ << sink->objectName().toStdString().c_str()
+ << " at: "
+ << index;
+ RemoveThreadedBasebandSampleSink cmd(sink, index);
+ m_syncMessenger.sendWait(cmd);
+}
+
+void DSPDeviceMIMOEngine::addAncillarySink(BasebandSampleSink* sink, int index)
+{
+ qDebug() << "DSPDeviceMIMOEngine::addSink: "
+ << sink->objectName().toStdString().c_str()
+ << " at: "
+ << index;
+ AddBasebandSampleSink cmd(sink, index);
+ m_syncMessenger.sendWait(cmd);
+}
+
+void DSPDeviceMIMOEngine::removeAncillarySink(BasebandSampleSink* sink, int index)
+{
+ qDebug() << "DSPDeviceMIMOEngine::removeSink: "
+ << sink->objectName().toStdString().c_str()
+ << " at: "
+ << index;
+ RemoveBasebandSampleSink cmd(sink, index);
+ m_syncMessenger.sendWait(cmd);
+}
+
+void DSPDeviceMIMOEngine::addSpectrumSink(BasebandSampleSink* spectrumSink)
+{
+ qDebug() << "DSPDeviceMIMOEngine::addSpectrumSink: " << spectrumSink->objectName().toStdString().c_str();
+ AddSpectrumSink cmd(spectrumSink);
+ m_syncMessenger.sendWait(cmd);
+}
+
+void DSPDeviceMIMOEngine::removeSpectrumSink(BasebandSampleSink* spectrumSink)
+{
+ qDebug() << "DSPDeviceSinkEngine::removeSpectrumSink: " << spectrumSink->objectName().toStdString().c_str();
+ DSPRemoveSpectrumSink cmd(spectrumSink);
+ m_syncMessenger.sendWait(cmd);
+}
+
+QString DSPDeviceMIMOEngine::errorMessage()
+{
+ qDebug() << "DSPDeviceMIMOEngine::errorMessage";
+ GetErrorMessage cmd;
+ m_syncMessenger.sendWait(cmd);
+ return cmd.getErrorMessage();
+}
+
+QString DSPDeviceMIMOEngine::deviceDescription()
+{
+ qDebug() << "DSPDeviceMIMOEngine::deviceDescription";
+ GetSinkDeviceDescription cmd;
+ m_syncMessenger.sendWait(cmd);
+ return cmd.getDeviceDescription();
+}
+
+/**
+ * Routes samples from device source FIFO to sink channels that are registered for the FIFO
+ * Routes samples from source channels registered for the FIFO to the device sink FIFO
+ */
+void DSPDeviceMIMOEngine::work(int nbWriteSamples, int nbReadSamples)
+{
+ // Sources
+ for (unsigned int isource = 0; isource < m_deviceSampleMIMO->getNbSourceFifos(); isource++)
+ {
+ if (isource >= m_sourceStreamSampleRates.size()) {
+ continue;
+ }
+
+ SampleSinkFifo* sampleFifo = m_deviceSampleMIMO->getSampleSinkFifo(isource); // sink FIFO is for Rx
+ std::size_t samplesDone = 0;
+ bool positiveOnly = false;
+
+ while ((sampleFifo->fill() > 0) && (m_inputMessageQueue.size() == 0) && (samplesDone < m_sourceStreamSampleRates[isource]))
+ {
+ 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 (isource < m_basebandSampleSinks.size())
+ {
+ for (BasebandSampleSinks::const_iterator it = m_basebandSampleSinks[isource].begin(); it != m_basebandSampleSinks[isource].end(); ++it) {
+ (*it)->feed(part1begin, part1end, positiveOnly);
+ }
+ }
+
+ // feed data to threaded sinks
+ if (isource < m_threadedBasebandSampleSinks.size())
+ {
+ for (ThreadedBasebandSampleSinks::const_iterator it = m_threadedBasebandSampleSinks[isource].begin(); it != m_threadedBasebandSampleSinks[isource].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 (isource < m_basebandSampleSinks.size())
+ {
+ for (BasebandSampleSinks::const_iterator it = m_basebandSampleSinks[isource].begin(); it != m_basebandSampleSinks[isource].end(); ++it) {
+ (*it)->feed(part2begin, part2end, positiveOnly);
+ }
+ }
+
+ // feed data to threaded sinks
+ if (isource < m_threadedBasebandSampleSinks.size())
+ {
+ for (ThreadedBasebandSampleSinks::const_iterator it = m_threadedBasebandSampleSinks[isource].begin(); it != m_threadedBasebandSampleSinks[isource].end(); ++it) {
+ (*it)->feed(part2begin, part2end, positiveOnly);
+ }
+ }
+ }
+
+
+ // adjust FIFO pointers
+ sampleFifo->readCommit((unsigned int) count);
+ samplesDone += count;
+ } // while stream FIFO
+ } // for stream source
+
+ // TODO: sinks
+}
\ No newline at end of file
diff --git a/sdrbase/dsp/dspdevicemimoengine.h b/sdrbase/dsp/dspdevicemimoengine.h
new file mode 100644
index 000000000..153fb1cdd
--- /dev/null
+++ b/sdrbase/dsp/dspdevicemimoengine.h
@@ -0,0 +1,255 @@
+///////////////////////////////////////////////////////////////////////////////////
+// Copyright (C) 2019 F4EXB //
+// written by Edouard Griffiths //
+// //
+// This program is free software; you can redistribute it and/or modify //
+// it under the terms of the GNU General Public License as published by //
+// the Free Software Foundation as version 3 of the License, or //
+// (at your option) any later version. //
+// //
+// This program is distributed in the hope that it will be useful, //
+// but WITHOUT ANY WARRANTY; without even the implied warranty of //
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
+// GNU General Public License V3 for more details. //
+// //
+// You should have received a copy of the GNU General Public License //
+// along with this program. If not, see . //
+///////////////////////////////////////////////////////////////////////////////////
+
+#ifndef SDRBASE_DSP_DSPDEVICEMIMOENGINE_H_
+#define SDRBASE_DSP_DSPDEVICEMIMOENGINE_H_
+
+#include
+
+#include "util/messagequeue.h"
+#include "util/syncmessenger.h"
+#include "export.h"
+
+class DeviceSampleMIMO;
+class ThreadedBasebandSampleSource;
+class ThreadedBasebandSampleSink;
+class BasebandSampleSink;
+
+class SDRBASE_API DSPDeviceMIMOEngine : public QThread {
+ Q_OBJECT
+
+public:
+ class SetSampleMIMO : public Message {
+ MESSAGE_CLASS_DECLARATION
+ public:
+ SetSampleMIMO(DeviceSampleMIMO* sampleMIMO) : Message(), m_sampleMIMO(sampleMIMO) { }
+ DeviceSampleMIMO* getSampleMIMO() const { return m_sampleMIMO; }
+ private:
+ DeviceSampleMIMO* m_sampleMIMO;
+ };
+
+ class AddThreadedBasebandSampleSource : public Message {
+ MESSAGE_CLASS_DECLARATION
+ public:
+ AddThreadedBasebandSampleSource(ThreadedBasebandSampleSource* threadedSampleSource, int index) :
+ Message(),
+ m_threadedSampleSource(threadedSampleSource),
+ m_index(index)
+ { }
+ ThreadedBasebandSampleSource* getThreadedSampleSource() const { return m_threadedSampleSource; }
+ int getIndex() const { return m_index; }
+ private:
+ ThreadedBasebandSampleSource* m_threadedSampleSource;
+ int m_index;
+ };
+
+ class RemoveThreadedBasebandSampleSource : public Message {
+ MESSAGE_CLASS_DECLARATION
+
+ public:
+ RemoveThreadedBasebandSampleSource(ThreadedBasebandSampleSource* threadedSampleSource, int index) :
+ Message(),
+ m_threadedSampleSource(threadedSampleSource),
+ m_index(index)
+ { }
+ ThreadedBasebandSampleSource* getThreadedSampleSource() const { return m_threadedSampleSource; }
+ int getIndex() const { return m_index; }
+ private:
+ ThreadedBasebandSampleSource* m_threadedSampleSource;
+ int m_index;
+ };
+
+ class AddThreadedBasebandSampleSink : public Message {
+ MESSAGE_CLASS_DECLARATION
+ public:
+ AddThreadedBasebandSampleSink(ThreadedBasebandSampleSink* threadedSampleSink, int index) :
+ Message(),
+ m_threadedSampleSink(threadedSampleSink),
+ m_index(index)
+ { }
+ ThreadedBasebandSampleSink* getThreadedSampleSink() const { return m_threadedSampleSink; }
+ int getIndex() const { return m_index; }
+ private:
+ ThreadedBasebandSampleSink* m_threadedSampleSink;
+ int m_index;
+ };
+
+ class RemoveThreadedBasebandSampleSink : public Message {
+ MESSAGE_CLASS_DECLARATION
+ public:
+ RemoveThreadedBasebandSampleSink(ThreadedBasebandSampleSink* threadedSampleSink, int index) :
+ Message(),
+ m_threadedSampleSink(threadedSampleSink),
+ m_index(index)
+ { }
+ ThreadedBasebandSampleSink* getThreadedSampleSink() const { return m_threadedSampleSink; }
+ int getIndex() const { return m_index; }
+ private:
+ ThreadedBasebandSampleSink* m_threadedSampleSink;
+ int m_index;
+ };
+
+ class AddBasebandSampleSink : public Message {
+ MESSAGE_CLASS_DECLARATION
+ public:
+ AddBasebandSampleSink(BasebandSampleSink* sampleSink, int index) :
+ Message(),
+ m_sampleSink(sampleSink),
+ m_index(index)
+ { }
+ BasebandSampleSink* getSampleSink() const { return m_sampleSink; }
+ int getIndex() const { return m_index; }
+ private:
+ BasebandSampleSink* m_sampleSink;
+ int m_index;
+ };
+
+ class RemoveBasebandSampleSink : public Message {
+ MESSAGE_CLASS_DECLARATION
+ public:
+ RemoveBasebandSampleSink(BasebandSampleSink* sampleSink, int index) :
+ Message(),
+ m_sampleSink(sampleSink),
+ m_index(index)
+ { }
+ BasebandSampleSink* getSampleSink() const { return m_sampleSink; }
+ int getIndex() const { return m_index; }
+ private:
+ BasebandSampleSink* m_sampleSink;
+ int m_index;
+ };
+
+ class AddSpectrumSink : public Message {
+ MESSAGE_CLASS_DECLARATION
+ public:
+ AddSpectrumSink(BasebandSampleSink* sampleSink) : Message(), m_sampleSink(sampleSink) { }
+ BasebandSampleSink* getSampleSink() const { return m_sampleSink; }
+ private:
+ BasebandSampleSink* m_sampleSink;
+ };
+
+ class RemoveSpectrumSink : public Message {
+ MESSAGE_CLASS_DECLARATION
+ public:
+ RemoveSpectrumSink(BasebandSampleSink* sampleSink) : Message(), m_sampleSink(sampleSink) { }
+ BasebandSampleSink* getSampleSink() const { return m_sampleSink; }
+ private:
+ BasebandSampleSink* m_sampleSink;
+ };
+
+ class GetErrorMessage : public Message {
+ MESSAGE_CLASS_DECLARATION
+ public:
+ void setErrorMessage(const QString& text) { m_errorMessage = text; }
+ const QString& getErrorMessage() const { return m_errorMessage; }
+ private:
+ QString m_errorMessage;
+ };
+
+ class GetSinkDeviceDescription : public Message {
+ MESSAGE_CLASS_DECLARATION
+ public:
+ void setDeviceDescription(const QString& text) { m_deviceDescription = text; }
+ const QString& getDeviceDescription() const { return m_deviceDescription; }
+ private:
+ QString m_deviceDescription;
+ };
+
+ enum State {
+ StNotStarted, //!< engine is before initialization
+ StIdle, //!< engine is idle
+ StReady, //!< engine is ready to run
+ StRunning, //!< engine is running
+ StError //!< engine is in error
+ };
+
+ DSPDeviceMIMOEngine(uint32_t uid, QObject* parent = nullptr);
+ ~DSPDeviceMIMOEngine();
+
+ MessageQueue* getInputMessageQueue() { return &m_inputMessageQueue; }
+
+ void start(); //!< This thread start
+ void stop(); //!< This thread stop
+
+ bool initProcess(); //!< Initialize process sequence
+ bool startProcess(); //!< Start process sequence
+ void stopProcess(); //!< Stop process sequence
+
+ void setMIMO(DeviceSampleMIMO* mimo); //!< Set the sample MIMO type
+ DeviceSampleMIMO *getMIMO() { return m_deviceSampleMIMO; }
+ void setMIMOSequence(int sequence); //!< Set the sample MIMO sequence in type
+
+ void addChannelSource(ThreadedBasebandSampleSource* source, int index = 0); //!< Add a channel source that will run on its own thread
+ void removeChannelSource(ThreadedBasebandSampleSource* source, int index = 0); //!< Remove a channel source that runs on its own thread
+ void addChannelSink(ThreadedBasebandSampleSink* sink, int index = 0); //!< Add a channel sink that will run on its own thread
+ void removeChannelSink(ThreadedBasebandSampleSink* sink, int index = 0); //!< Remove a channel sink that runs on its own thread
+
+ void addAncillarySink(BasebandSampleSink* sink, int index = 0); //!< Add an ancillary sink like a I/Q recorder
+ void removeAncillarySink(BasebandSampleSink* sink, int index = 0); //!< Remove an ancillary sample sink
+
+ void addSpectrumSink(BasebandSampleSink* spectrumSink); //!< Add a spectrum vis baseband sample sink
+ void removeSpectrumSink(BasebandSampleSink* spectrumSink); //!< Add a spectrum vis baseband sample sink
+
+ State state() const { return m_state; } //!< Return DSP engine current state
+
+ QString errorMessage(); //!< Return the current error message
+ QString deviceDescription(); //!< Return the device description
+
+private:
+ uint32_t m_uid; //!< unique ID
+ State m_state;
+
+ QString m_errorMessage;
+ QString m_deviceDescription;
+
+ DeviceSampleMIMO* m_deviceSampleMIMO;
+ int m_sampleMIMOSequence;
+
+ MessageQueue m_inputMessageQueue; // BasebandSampleSinks;
+ std::vector m_basebandSampleSinks; //!< ancillary sample sinks on main thread (per input stream)
+
+ typedef std::list ThreadedBasebandSampleSinks;
+ std::vector m_threadedBasebandSampleSinks; //!< channel sample sinks on their own thread (per input stream)
+
+ typedef std::list ThreadedBasebandSampleSources;
+ std::vector m_threadedBasebandSampleSources; //!< channel sample sources on their own threads (per output stream)
+
+ std::vector m_sourceStreamSampleRates; //!< device sources streams (Rx) sample rates
+ std::vector m_sinkStreamSampleRates; //!< device sink streams (Tx) sample rates
+
+ BasebandSampleSink *m_spectrumSink; //!< The spectrum sink
+
+ void run();
+ void work(int nbWriteSamples, int nbReadSamples); //!< transfer samples if in running state
+
+ State gotoIdle(); //!< Go to the idle state
+ State gotoInit(); //!< Go to the acquisition init state from idle
+ State gotoRunning(); //!< Go to the running state from ready state
+ State gotoError(const QString& errorMsg); //!< Go to an error state
+
+private slots:
+ void handleData(int nbSamples); //!< Handle data when samples have to be written to the sample FIFO
+ void handleInputMessages(); //!< Handle input message queue
+ void handleSynchronousMessages(); //!< Handle synchronous messages with the thread
+ void handleForwardToSpectrumSink(int nbSamples);
+};
+
+#endif // SDRBASE_DSP_DSPDEVICEMIMOENGINE_H_
\ No newline at end of file