From b72ff29c27332d7ec2456ee14a09caccfbd740e7 Mon Sep 17 00:00:00 2001 From: f4exb Date: Mon, 13 May 2019 01:55:12 +0200 Subject: [PATCH] MIMO support: added DSP Engine and Device for MIMO (1) --- sdrbase/dsp/devicesamplemimo.cpp | 62 +++++++ sdrbase/dsp/devicesamplemimo.h | 140 ++++++++++++++ sdrbase/dsp/dspdevicemimoengine.cpp | 271 ++++++++++++++++++++++++++++ sdrbase/dsp/dspdevicemimoengine.h | 255 ++++++++++++++++++++++++++ 4 files changed, 728 insertions(+) create mode 100644 sdrbase/dsp/devicesamplemimo.cpp create mode 100644 sdrbase/dsp/devicesamplemimo.h create mode 100644 sdrbase/dsp/dspdevicemimoengine.cpp create mode 100644 sdrbase/dsp/dspdevicemimoengine.h 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