1
0
mirror of https://github.com/f4exb/sdrangel.git synced 2025-03-07 11:59:04 -05:00

Tx ph.1: Added the DSPDeviceSinkEngine class

This commit is contained in:
f4exb 2016-10-17 18:15:08 +02:00
parent 9cf62833ba
commit 0f7ac00a71
12 changed files with 973 additions and 365 deletions

View File

@ -102,6 +102,7 @@ set(sdrbase_SOURCES
sdrbase/dsp/dspcommands.cpp
sdrbase/dsp/dspengine.cpp
sdrbase/dsp/dspdevicesourceengine.cpp
sdrbase/dsp/dspdevicesinkengine.cpp
sdrbase/dsp/fftengine.cpp
sdrbase/dsp/fftfilt.cxx
sdrbase/dsp/fftwindow.cpp
@ -191,6 +192,7 @@ set(sdrbase_HEADERS
sdrbase/dsp/dspcommands.h
sdrbase/dsp/dspengine.h
sdrbase/dsp/dspdevicesourceengine.h
sdrbase/dsp/dspdevicesinkengine.h
sdrbase/dsp/dsptypes.h
sdrbase/dsp/fftengine.h
sdrbase/dsp/fftfilt.h

View File

@ -1,129 +1,129 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2016 Edouard Griffiths, F4EXB //
// //
// 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 //
// //
// 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 <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#ifndef SDRBASE_DEVICE_DEVICESINKAPI_H_
#define SDRBASE_DEVICE_DEVICESINKAPI_H_
#include <QObject>
#include <QString>
#include "util/export.h"
class MainWindow;
class DSPDeviceSinkEngine; // TODO: TBD
class GLSpectrum;
class ChannelWindow;
class BasebandSampleSource; // TODO: TBD
class ThreadedBasebandSampleSource; // TODO: TBD
class DeviceSampleSink; // TODO: TBD
class MessageQueue;
class ChannelMarker;
class QWidget;
class PluginGUI;
class PluginAPI;
class Preset;
class SDRANGEL_API DeviceSinkAPI : public QObject {
Q_OBJECT
public:
// Device engine stuff
void addSource(BasebandSampleSource* source); //!< Add a baseband sample source to device engine
void removeSource(BasebandSampleSource* sink); //!< Remove a baseband sample source from device engine
void addThreadedSource(ThreadedBasebandSampleSource* sink); //!< Add a baseband sample source that will run on its own thread to device engine
void removeThreadedSource(ThreadedBasebandSampleSource* sink); //!< Remove a baseband sample source that runs on its own thread from device engine
void setSink(DeviceSampleSink* sink); //!< Set device engine sample sink type
bool initGeneration(); //!< Initialize device engine generation sequence
bool startGeneration(); //!< Start device engine generation sequence
void stopGeneration(); //!< Stop device engine generation sequence
//TODO: DSPDeviceSourceEngine::State state() const; //!< device engine state
QString errorMessage(); //!< Return the current device engine error message
uint getDeviceUID() const; //!< Return the current device engine unique ID
MessageQueue *getDeviceInputMessageQueue();
MessageQueue *getDeviceOutputMessageQueue();
// device related stuff
GLSpectrum *getSpectrum(); //!< Direct spectrum getter
void addChannelMarker(ChannelMarker* channelMarker); //!< Add channel marker to spectrum
ChannelWindow *getChannelWindow(); //!< Direct channel window getter
void addRollupWidget(QWidget *widget); //!< Add rollup widget to channel window
void setOutputGUI(QWidget* outputGUI, const QString& sinkDisplayName);
void setSampleSinkId(const QString& id);
void setSampleSinkSerial(const QString& serial);
void setSampleSinkSequence(int sequence);
void setSampleSinkPluginGUI(PluginGUI *gui);
void registerChannelInstance(const QString& channelName, PluginGUI* pluginGUI);
void removeChannelInstance(PluginGUI* pluginGUI);
void freeAll();
void loadSinkSettings(const Preset* preset);
void saveSinkSettings(Preset* preset);
void loadChannelSettings(const Preset* preset, PluginAPI *pluginAPI);
void saveChannelSettings(Preset* preset);
MainWindow *getMainWindow() { return m_mainWindow; }
protected:
struct ChannelInstanceRegistration
{
QString m_channelName;
PluginGUI* m_gui;
ChannelInstanceRegistration() :
m_channelName(),
m_gui(0)
{ }
ChannelInstanceRegistration(const QString& channelName, PluginGUI* pluginGUI) :
m_channelName(channelName),
m_gui(pluginGUI)
{ }
bool operator<(const ChannelInstanceRegistration& other) const;
};
typedef QList<ChannelInstanceRegistration> ChannelInstanceRegistrations;
DeviceSinkAPI(MainWindow *mainWindow,
int deviceTabIndex,
DSPDeviceSourceEngine *deviceEngine,
GLSpectrum *glSpectrum,
ChannelWindow *channelWindow);
~DeviceSinkAPI();
void renameChannelInstances();
MainWindow *m_mainWindow;
int m_deviceTabIndex;
DSPDeviceSinkEngine *m_deviceEngine;
GLSpectrum *m_spectrum;
ChannelWindow *m_channelWindow;
QString m_sampleSinkId;
QString m_sampleSinkSerial;
int m_sampleSinkSequence;
PluginGUI* m_sampleSinkPluginGUI;
ChannelInstanceRegistrations m_channelInstanceRegistrations;
friend class MainWindow;
};
#endif /* SDRBASE_DEVICE_DEVICESINKAPI_H_ */
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2016 Edouard Griffiths, F4EXB //
// //
// 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 //
// //
// 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 <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#ifndef SDRBASE_DEVICE_DEVICESINKAPI_H_
#define SDRBASE_DEVICE_DEVICESINKAPI_H_
#include <QObject>
#include <QString>
#include "dsp/dspdevicesinkengine.h" // TODO: TBD
#include "util/export.h"
class MainWindow;
class GLSpectrum;
class ChannelWindow;
class BasebandSampleSource;
class ThreadedBasebandSampleSource;
class DeviceSampleSink;
class MessageQueue;
class ChannelMarker;
class QWidget;
class PluginGUI;
class PluginAPI;
class Preset;
class SDRANGEL_API DeviceSinkAPI : public QObject {
Q_OBJECT
public:
// Device engine stuff
void addSource(BasebandSampleSource* source); //!< Add a baseband sample source to device engine
void removeSource(BasebandSampleSource* sink); //!< Remove a baseband sample source from device engine
void addThreadedSource(ThreadedBasebandSampleSource* sink); //!< Add a baseband sample source that will run on its own thread to device engine
void removeThreadedSource(ThreadedBasebandSampleSource* sink); //!< Remove a baseband sample source that runs on its own thread from device engine
void setSink(DeviceSampleSink* sink); //!< Set device engine sample sink type
bool initGeneration(); //!< Initialize device engine generation sequence
bool startGeneration(); //!< Start device engine generation sequence
void stopGeneration(); //!< Stop device engine generation sequence
DSPDeviceSinkEngine::State state() const; //!< device engine state
QString errorMessage(); //!< Return the current device engine error message
uint getDeviceUID() const; //!< Return the current device engine unique ID
MessageQueue *getDeviceInputMessageQueue();
MessageQueue *getDeviceOutputMessageQueue();
// device related stuff
GLSpectrum *getSpectrum(); //!< Direct spectrum getter
void addChannelMarker(ChannelMarker* channelMarker); //!< Add channel marker to spectrum
ChannelWindow *getChannelWindow(); //!< Direct channel window getter
void addRollupWidget(QWidget *widget); //!< Add rollup widget to channel window
void setOutputGUI(QWidget* outputGUI, const QString& sinkDisplayName);
void setSampleSinkId(const QString& id);
void setSampleSinkSerial(const QString& serial);
void setSampleSinkSequence(int sequence);
void setSampleSinkPluginGUI(PluginGUI *gui);
void registerChannelInstance(const QString& channelName, PluginGUI* pluginGUI);
void removeChannelInstance(PluginGUI* pluginGUI);
void freeAll();
void loadSinkSettings(const Preset* preset);
void saveSinkSettings(Preset* preset);
void loadChannelSettings(const Preset* preset, PluginAPI *pluginAPI);
void saveChannelSettings(Preset* preset);
MainWindow *getMainWindow() { return m_mainWindow; }
protected:
struct ChannelInstanceRegistration
{
QString m_channelName;
PluginGUI* m_gui;
ChannelInstanceRegistration() :
m_channelName(),
m_gui(0)
{ }
ChannelInstanceRegistration(const QString& channelName, PluginGUI* pluginGUI) :
m_channelName(channelName),
m_gui(pluginGUI)
{ }
bool operator<(const ChannelInstanceRegistration& other) const;
};
typedef QList<ChannelInstanceRegistration> ChannelInstanceRegistrations;
DeviceSinkAPI(MainWindow *mainWindow,
int deviceTabIndex,
DSPDeviceSourceEngine *deviceEngine,
GLSpectrum *glSpectrum,
ChannelWindow *channelWindow);
~DeviceSinkAPI();
void renameChannelInstances();
MainWindow *m_mainWindow;
int m_deviceTabIndex;
DSPDeviceSinkEngine *m_deviceEngine;
GLSpectrum *m_spectrum;
ChannelWindow *m_channelWindow;
QString m_sampleSinkId;
QString m_sampleSinkSerial;
int m_sampleSinkSequence;
PluginGUI* m_sampleSinkPluginGUI;
ChannelInstanceRegistrations m_channelInstanceRegistrations;
friend class MainWindow;
};
#endif /* SDRBASE_DEVICE_DEVICESINKAPI_H_ */

View File

@ -25,7 +25,6 @@
#include "util/export.h"
class MainWindow;
class DSPDeviceSourceEngine;
class GLSpectrum;
class ChannelWindow;
class BasebandSampleSink;

View File

@ -21,13 +21,22 @@ MESSAGE_CLASS_DEFINITION(DSPExit, Message)
MESSAGE_CLASS_DEFINITION(DSPAcquisitionInit, Message)
MESSAGE_CLASS_DEFINITION(DSPAcquisitionStart, Message)
MESSAGE_CLASS_DEFINITION(DSPAcquisitionStop, Message)
MESSAGE_CLASS_DEFINITION(DSPGenerationInit, Message)
MESSAGE_CLASS_DEFINITION(DSPGenerationStart, Message)
MESSAGE_CLASS_DEFINITION(DSPGenerationStop, Message)
MESSAGE_CLASS_DEFINITION(DSPGetSourceDeviceDescription, Message)
MESSAGE_CLASS_DEFINITION(DSPGetSinkDeviceDescription, Message)
MESSAGE_CLASS_DEFINITION(DSPGetErrorMessage, Message)
MESSAGE_CLASS_DEFINITION(DSPSetSource, Message)
MESSAGE_CLASS_DEFINITION(DSPSetSink, Message)
MESSAGE_CLASS_DEFINITION(DSPAddSink, Message)
MESSAGE_CLASS_DEFINITION(DSPAddSource, Message)
MESSAGE_CLASS_DEFINITION(DSPRemoveSink, Message)
MESSAGE_CLASS_DEFINITION(DSPRemoveSource, Message)
MESSAGE_CLASS_DEFINITION(DSPAddThreadedSampleSink, Message)
MESSAGE_CLASS_DEFINITION(DSPAddThreadedSampleSource, Message)
MESSAGE_CLASS_DEFINITION(DSPRemoveThreadedSampleSink, Message)
MESSAGE_CLASS_DEFINITION(DSPRemoveThreadedSampleSource, Message)
MESSAGE_CLASS_DEFINITION(DSPAddAudioSink, Message)
MESSAGE_CLASS_DEFINITION(DSPRemoveAudioSink, Message)
//MESSAGE_CLASS_DEFINITION(DSPConfigureSpectrumVis, Message)

View File

@ -26,6 +26,9 @@
class DeviceSampleSource;
class BasebandSampleSink;
class ThreadedBasebandSampleSink;
class DeviceSampleSink;
class BasebandSampleSource;
class ThreadedBasebandSampleSource;
class AudioFifo;
class SDRANGEL_API DSPExit : public Message {
@ -44,6 +47,18 @@ class SDRANGEL_API DSPAcquisitionStop : public Message {
MESSAGE_CLASS_DECLARATION
};
class SDRANGEL_API DSPGenerationInit : public Message {
MESSAGE_CLASS_DECLARATION
};
class SDRANGEL_API DSPGenerationStart : public Message {
MESSAGE_CLASS_DECLARATION
};
class SDRANGEL_API DSPGenerationStop : public Message {
MESSAGE_CLASS_DECLARATION
};
class SDRANGEL_API DSPGetSourceDeviceDescription : public Message {
MESSAGE_CLASS_DECLARATION
@ -55,6 +70,17 @@ private:
QString m_deviceDescription;
};
class SDRANGEL_API DSPGetSinkDeviceDescription : 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;
};
class SDRANGEL_API DSPGetErrorMessage : public Message {
MESSAGE_CLASS_DECLARATION
@ -78,6 +104,18 @@ private:
DeviceSampleSource* m_sampleSource;
};
class SDRANGEL_API DSPSetSink : public Message {
MESSAGE_CLASS_DECLARATION
public:
DSPSetSink(DeviceSampleSink* sampleSink) : Message(), m_sampleSink(sampleSink) { }
DeviceSampleSink* getSampleSink() const { return m_sampleSink; }
private:
DeviceSampleSink* m_sampleSink;
};
class SDRANGEL_API DSPAddSink : public Message {
MESSAGE_CLASS_DECLARATION
@ -90,6 +128,18 @@ private:
BasebandSampleSink* m_sampleSink;
};
class SDRANGEL_API DSPAddSource : public Message {
MESSAGE_CLASS_DECLARATION
public:
DSPAddSource(BasebandSampleSource* sampleSource) : Message(), m_sampleSource(sampleSource) { }
BasebandSampleSource* getSampleSource() const { return m_sampleSource; }
private:
BasebandSampleSource* m_sampleSource;
};
class SDRANGEL_API DSPRemoveSink : public Message {
MESSAGE_CLASS_DECLARATION
@ -102,6 +152,18 @@ private:
BasebandSampleSink* m_sampleSink;
};
class SDRANGEL_API DSPRemoveSource : public Message {
MESSAGE_CLASS_DECLARATION
public:
DSPRemoveSource(BasebandSampleSource* sampleSource) : Message(), m_sampleSource(sampleSource) { }
BasebandSampleSource* getSampleSource() const { return m_sampleSource; }
private:
BasebandSampleSource* m_sampleSource;
};
class SDRANGEL_API DSPAddThreadedSampleSink : public Message {
MESSAGE_CLASS_DECLARATION
@ -114,6 +176,18 @@ private:
ThreadedBasebandSampleSink* m_threadedSampleSink;
};
class SDRANGEL_API DSPAddThreadedSampleSource : public Message {
MESSAGE_CLASS_DECLARATION
public:
DSPAddThreadedSampleSource(ThreadedBasebandSampleSource* threadedSampleSource) : Message(), m_threadedSampleSource(threadedSampleSource) { }
ThreadedBasebandSampleSource* getThreadedSampleSource() const { return m_threadedSampleSource; }
private:
ThreadedBasebandSampleSource* m_threadedSampleSource;
};
class SDRANGEL_API DSPRemoveThreadedSampleSink : public Message {
MESSAGE_CLASS_DECLARATION
@ -126,6 +200,18 @@ private:
ThreadedBasebandSampleSink* m_threadedSampleSink;
};
class SDRANGEL_API DSPRemoveThreadedSampleSource : public Message {
MESSAGE_CLASS_DECLARATION
public:
DSPRemoveThreadedSampleSource(ThreadedBasebandSampleSource* threadedSampleSource) : Message(), m_threadedSampleSource(threadedSampleSource) { }
ThreadedBasebandSampleSource* getThreadedSampleSource() const { return m_threadedSampleSource; }
private:
ThreadedBasebandSampleSource* m_threadedSampleSource;
};
class SDRANGEL_API DSPAddAudioSink : public Message {
MESSAGE_CLASS_DECLARATION

View File

@ -0,0 +1,554 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2016 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 //
// //
// 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 <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#include <stdio.h>
#include <QDebug>
#include <QThread>
#include "dspdevicesinkengine.h"
#include "dsp/basebandsamplesource.h"
#include "dsp/basebandsamplesink.h"
#include "dsp/devicesamplesink.h"
#include "dsp/dspcommands.h"
#include "samplesourcefifo.h"
#include "threadedbasebandsamplesource.h"
DSPDeviceSinkEngine::DSPDeviceSinkEngine(uint uid, QObject* parent) :
m_uid(uid),
QThread(parent),
m_state(StNotStarted),
m_deviceSampleSink(0),
m_sampleSinkSequence(0),
m_basebandSampleSources(),
m_sampleRate(0),
m_centerFrequency(0)
{
connect(&m_inputMessageQueue, SIGNAL(messageEnqueued()), this, SLOT(handleInputMessages()), Qt::QueuedConnection);
connect(&m_syncMessenger, SIGNAL(messageSent()), this, SLOT(handleSynchronousMessages()), Qt::QueuedConnection);
moveToThread(this);
}
DSPDeviceSinkEngine::~DSPDeviceSinkEngine()
{
wait();
}
void DSPDeviceSinkEngine::run()
{
qDebug() << "DSPDeviceSinkEngine::run";
m_state = StIdle;
m_syncMessenger.done(); // Release start() that is waiting in main thread
exec();
}
void DSPDeviceSinkEngine::start()
{
qDebug() << "DSPDeviceSinkEngine::start";
QThread::start();
}
void DSPDeviceSinkEngine::stop()
{
qDebug() << "DSPDeviceSinkEngine::stop";
DSPExit cmd;
m_syncMessenger.sendWait(cmd);
}
bool DSPDeviceSinkEngine::initGeneration()
{
qDebug() << "DSPDeviceSinkEngine::initGeneration";
DSPGenerationInit cmd;
return m_syncMessenger.sendWait(cmd) == StReady;
}
bool DSPDeviceSinkEngine::startGeneration()
{
qDebug() << "DSPDeviceSinkEngine::startGeneration";
DSPGenerationStart cmd;
return m_syncMessenger.sendWait(cmd) == StRunning;
}
void DSPDeviceSinkEngine::stopGeneration()
{
qDebug() << "DSPDeviceSinkEngine::stopGeneration";
DSPGenerationStop cmd;
m_syncMessenger.storeMessage(cmd);
handleSynchronousMessages();
}
void DSPDeviceSinkEngine::setSink(DeviceSampleSink* sink)
{
qDebug() << "DSPDeviceSinkEngine::setSink";
DSPSetSink cmd(sink);
m_syncMessenger.sendWait(cmd);
}
void DSPDeviceSinkEngine::setSinkSequence(int sequence)
{
qDebug("DSPDeviceSinkEngine::setSinkSequence: seq: %d", sequence);
m_sampleSinkSequence = sequence;
}
void DSPDeviceSinkEngine::addSource(BasebandSampleSource* source)
{
qDebug() << "DSPDeviceSinkEngine::addSource: " << source->objectName().toStdString().c_str();
DSPAddSource cmd(source);
m_syncMessenger.sendWait(cmd);
}
void DSPDeviceSinkEngine::removeSource(BasebandSampleSource* source)
{
qDebug() << "DSPDeviceSinkEngine::removeSource: " << source->objectName().toStdString().c_str();
DSPRemoveSource cmd(source);
m_syncMessenger.sendWait(cmd);
}
void DSPDeviceSinkEngine::addThreadedSource(ThreadedBasebandSampleSource* source)
{
qDebug() << "DSPDeviceSinkEngine::addThreadedSource: " << source->objectName().toStdString().c_str();
DSPAddThreadedSampleSource cmd(source);
m_syncMessenger.sendWait(cmd);
}
void DSPDeviceSinkEngine::removeThreadedSource(ThreadedBasebandSampleSource* source)
{
qDebug() << "DSPDeviceSinkEngine::removeThreadedSource: " << source->objectName().toStdString().c_str();
DSPRemoveThreadedSampleSource cmd(source);
m_syncMessenger.sendWait(cmd);
}
void DSPDeviceSinkEngine::addSink(BasebandSampleSink* sink)
{
qDebug() << "DSPDeviceSinkEngine::addSink: " << sink->objectName().toStdString().c_str();
DSPAddSink cmd(sink);
m_syncMessenger.sendWait(cmd);
}
void DSPDeviceSinkEngine::removeSink(BasebandSampleSink* sink)
{
qDebug() << "DSPDeviceSinkEngine::removeSink: " << sink->objectName().toStdString().c_str();
DSPRemoveSink cmd(sink);
m_syncMessenger.sendWait(cmd);
}
QString DSPDeviceSinkEngine::errorMessage()
{
qDebug() << "DSPDeviceSinkEngine::errorMessage";
DSPGetErrorMessage cmd;
m_syncMessenger.sendWait(cmd);
return cmd.getErrorMessage();
}
QString DSPDeviceSinkEngine::sinkDeviceDescription()
{
qDebug() << "DSPDeviceSinkEngine::sinkDeviceDescription";
DSPGetSinkDeviceDescription cmd;
m_syncMessenger.sendWait(cmd);
return cmd.getDeviceDescription();
}
void DSPDeviceSinkEngine::work()
{
SampleSourceFifo* sampleFifo = m_deviceSampleSink->getSampleFifo();
unsigned int nbWriteSamples = sampleFifo->getChunkSize();
SampleVector::iterator writeBegin;
sampleFifo->getWriteIterator(writeBegin);
SampleVector::iterator writeAt = writeBegin;
Sample s;
if ((m_threadedBasebandSampleSources.size() + m_basebandSampleSources.size()) > 0)
{
for (int is = 0; is < nbWriteSamples; is++, ++writeAt)
{
// pull data from threaded sources and merge them in the device sample FIFO
for (ThreadedBasebandSampleSources::iterator it = m_threadedBasebandSampleSources.begin(); it != m_threadedBasebandSampleSources.end(); ++it)
{
(*it)->pull(s);
s /= (m_threadedBasebandSampleSources.size() + m_basebandSampleSources.size());
*writeAt += s;
}
// pull data from direct sources and merge them in the device sample FIFO
for (BasebandSampleSources::iterator it = m_basebandSampleSources.begin(); it != m_basebandSampleSources.end(); ++it)
{
(*it)->pull(s);
s /= (m_threadedBasebandSampleSources.size() + m_basebandSampleSources.size());
*writeAt += s;
}
}
// feed the mix to the sinks normally just the main spectrum vis
for (BasebandSampleSinks::iterator it = m_basebandSampleSinks.begin(); it != m_basebandSampleSinks.end(); ++it)
{
(*it)->feed(writeBegin, writeBegin + nbWriteSamples, false);
}
}
}
// notStarted -> idle -> init -> running -+
// ^ |
// +-----------------------+
DSPDeviceSinkEngine::State DSPDeviceSinkEngine::gotoIdle()
{
qDebug() << "DSPDeviceSinkEngine::gotoIdle";
switch(m_state) {
case StNotStarted:
return StNotStarted;
case StIdle:
case StError:
return StIdle;
case StReady:
case StRunning:
break;
}
if(m_deviceSampleSink == 0)
{
return StIdle;
}
// stop everything
for(BasebandSampleSources::const_iterator it = m_basebandSampleSources.begin(); it != m_basebandSampleSources.end(); it++)
{
(*it)->stop();
}
for(ThreadedBasebandSampleSources::const_iterator it = m_threadedBasebandSampleSources.begin(); it != m_threadedBasebandSampleSources.end(); it++)
{
(*it)->stop();
}
for(BasebandSampleSinks::const_iterator it = m_basebandSampleSinks.begin(); it != m_basebandSampleSinks.end(); it++)
{
(*it)->stop();
}
m_deviceSampleSink->stop();
m_deviceDescription.clear();
m_sampleRate = 0;
return StIdle;
}
DSPDeviceSinkEngine::State DSPDeviceSinkEngine::gotoInit()
{
qDebug() << "DSPDeviceSinkEngine::gotoInit";
switch(m_state) {
case StNotStarted:
return StNotStarted;
case StRunning: // FIXME: assumes it goes first through idle state. Could we get back to init from running directly?
return StRunning;
case StReady:
return StReady;
case StIdle:
case StError:
break;
}
if (m_deviceSampleSink == 0)
{
return gotoError("DSPDeviceSinkEngine::gotoInit: No sample source configured");
}
// init: pass sample rate and center frequency to all sample rate and/or center frequency dependent sinks and wait for completion
m_deviceDescription = m_deviceSampleSink->getDeviceDescription();
m_centerFrequency = m_deviceSampleSink->getCenterFrequency();
m_sampleRate = m_deviceSampleSink->getSampleRate();
qDebug() << "DSPDeviceSinkEngine::gotoInit: " << m_deviceDescription.toStdString().c_str() << ": "
<< " sampleRate: " << m_sampleRate
<< " centerFrequency: " << m_centerFrequency;
DSPSignalNotification notif(m_sampleRate, m_centerFrequency);
for (BasebandSampleSources::const_iterator it = m_basebandSampleSources.begin(); it != m_basebandSampleSources.end(); ++it)
{
qDebug() << "DSPDeviceSinkEngine::gotoInit: initializing " << (*it)->objectName().toStdString().c_str();
(*it)->handleMessage(notif);
}
for (ThreadedBasebandSampleSources::const_iterator it = m_threadedBasebandSampleSources.begin(); it != m_threadedBasebandSampleSources.end(); ++it)
{
qDebug() << "DSPDeviceSinkEngine::gotoInit: initializing ThreadedSampleSource(" << (*it)->getSampleSourceObjectName().toStdString().c_str() << ")";
(*it)->handleSourceMessage(notif);
}
for (BasebandSampleSinks::const_iterator it = m_basebandSampleSinks.begin(); it != m_basebandSampleSinks.end(); ++it)
{
qDebug() << "DSPDeviceSinkEngine::gotoInit: initializing " << (*it)->objectName().toStdString().c_str();
(*it)->handleMessage(notif);
}
// pass data to listeners
DSPSignalNotification* rep = new DSPSignalNotification(notif); // make a copy for the output queue
m_outputMessageQueue.push(rep);
return StReady;
}
DSPDeviceSinkEngine::State DSPDeviceSinkEngine::gotoRunning()
{
qDebug() << "DSPDeviceSinkEngine::gotoRunning";
switch(m_state)
{
case StNotStarted:
return StNotStarted;
case StIdle:
return StIdle;
case StRunning:
return StRunning;
case StReady:
case StError:
break;
}
if(m_deviceSampleSink == NULL) {
return gotoError("DSPDeviceSinkEngine::gotoRunning: No sample source configured");
}
qDebug() << "DSPDeviceSinkEngine::gotoRunning: " << m_deviceDescription.toStdString().c_str() << " started";
// Start everything
if(!m_deviceSampleSink->start(m_sampleSinkSequence))
{
return gotoError("DSPDeviceSinkEngine::gotoRunning: Could not start sample source");
}
for(BasebandSampleSources::const_iterator it = m_basebandSampleSources.begin(); it != m_basebandSampleSources.end(); it++)
{
qDebug() << "DSPDeviceSinkEngine::gotoRunning: starting " << (*it)->objectName().toStdString().c_str();
(*it)->start();
}
for (ThreadedBasebandSampleSources::const_iterator it = m_threadedBasebandSampleSources.begin(); it != m_threadedBasebandSampleSources.end(); ++it)
{
qDebug() << "DSPDeviceSinkEngine::gotoRunning: starting ThreadedSampleSource(" << (*it)->getSampleSourceObjectName().toStdString().c_str() << ")";
(*it)->start();
}
for(BasebandSampleSinks::const_iterator it = m_basebandSampleSinks.begin(); it != m_basebandSampleSinks.end(); it++)
{
qDebug() << "DSPDeviceSinkEngine::gotoRunning: starting " << (*it)->objectName().toStdString().c_str();
(*it)->start();
}
qDebug() << "DSPDeviceSinkEngine::gotoRunning: input message queue pending: " << m_inputMessageQueue.size();
return StRunning;
}
DSPDeviceSinkEngine::State DSPDeviceSinkEngine::gotoError(const QString& errorMessage)
{
qDebug() << "DSPDeviceSinkEngine::gotoError";
m_errorMessage = errorMessage;
m_deviceDescription.clear();
m_state = StError;
return StError;
}
void DSPDeviceSinkEngine::handleSetSink(DeviceSampleSink* sink)
{
gotoIdle();
// if(m_sampleSource != 0)
// {
// disconnect(m_sampleSource->getSampleFifo(), SIGNAL(dataReady()), this, SLOT(handleData()));
// }
m_deviceSampleSink = sink;
if(m_deviceSampleSink != 0)
{
qDebug("DSPDeviceSinkEngine::handleSetSink: set %s", qPrintable(sink->getDeviceDescription()));
connect(m_deviceSampleSink->getSampleFifo(), SIGNAL(dataWrite()), this, SLOT(handleData()), Qt::QueuedConnection);
}
else
{
qDebug("DSPDeviceSinkEngine::handleSetSource: set none");
}
}
void DSPDeviceSinkEngine::handleData()
{
if(m_state == StRunning)
{
work();
}
}
void DSPDeviceSinkEngine::handleSynchronousMessages()
{
Message *message = m_syncMessenger.getMessage();
qDebug() << "DSPDeviceSourceEngine::handleSynchronousMessages: " << message->getIdentifier();
if (DSPExit::match(*message))
{
gotoIdle();
m_state = StNotStarted;
exit();
}
else if (DSPGenerationInit::match(*message))
{
m_state = gotoIdle();
if(m_state == StIdle) {
m_state = gotoInit(); // State goes ready if init is performed
}
}
else if (DSPGenerationStart::match(*message))
{
if(m_state == StReady) {
m_state = gotoRunning();
}
}
else if (DSPGenerationStop::match(*message))
{
m_state = gotoIdle();
}
else if (DSPGetSinkDeviceDescription::match(*message))
{
((DSPGetSinkDeviceDescription*) message)->setDeviceDescription(m_deviceDescription);
}
else if (DSPGetErrorMessage::match(*message))
{
((DSPGetErrorMessage*) message)->setErrorMessage(m_errorMessage);
}
else if (DSPSetSink::match(*message)) {
handleSetSink(((DSPSetSink*) message)->getSampleSink());
}
else if (DSPAddSink::match(*message))
{
BasebandSampleSink* sink = ((DSPAddSink*) message)->getSampleSink();
m_basebandSampleSinks.push_back(sink);
}
else if (DSPRemoveSink::match(*message))
{
BasebandSampleSink* sink = ((DSPRemoveSink*) message)->getSampleSink();
if(m_state == StRunning) {
sink->stop();
}
m_basebandSampleSinks.remove(sink);
}
else if (DSPAddSource::match(*message))
{
BasebandSampleSource* source = ((DSPAddSource*) message)->getSampleSource();
m_basebandSampleSources.push_back(source);
}
else if (DSPRemoveSource::match(*message))
{
BasebandSampleSource* source = ((DSPRemoveSource*) message)->getSampleSource();
if(m_state == StRunning) {
source->stop();
}
m_basebandSampleSources.remove(source);
}
else if (DSPAddThreadedSampleSource::match(*message))
{
ThreadedBasebandSampleSource *threadedSource = ((DSPAddThreadedSampleSource*) message)->getThreadedSampleSource();
m_threadedBasebandSampleSources.push_back(threadedSource);
threadedSource->start();
}
else if (DSPRemoveThreadedSampleSource::match(*message))
{
ThreadedBasebandSampleSource* threadedSource = ((DSPRemoveThreadedSampleSource*) message)->getThreadedSampleSource();
threadedSource->stop();
m_threadedBasebandSampleSources.remove(threadedSource);
}
m_syncMessenger.done(m_state);
}
void DSPDeviceSinkEngine::handleInputMessages()
{
qDebug() << "DSPDeviceSinkEngine::handleInputMessages";
Message* message;
while ((message = m_inputMessageQueue.pop()) != 0)
{
qDebug("DSPDeviceSinkEngine::handleInputMessages: message: %s", message->getIdentifier());
if (DSPSignalNotification::match(*message))
{
DSPSignalNotification *notif = (DSPSignalNotification *) message;
// update DSP values
m_sampleRate = notif->getSampleRate();
m_centerFrequency = notif->getCenterFrequency();
qDebug() << "DSPDeviceSinkEngine::handleInputMessages: DSPSignalNotification(" << m_sampleRate << "," << m_centerFrequency << ")";
// forward source changes to sources with immediate execution
for(BasebandSampleSources::const_iterator it = m_basebandSampleSources.begin(); it != m_basebandSampleSources.end(); it++)
{
qDebug() << "DSPDeviceSinkEngine::handleInputMessages: forward message to " << (*it)->objectName().toStdString().c_str();
(*it)->handleMessage(*message);
}
for (ThreadedBasebandSampleSources::const_iterator it = m_threadedBasebandSampleSources.begin(); it != m_threadedBasebandSampleSources.end(); ++it)
{
qDebug() << "DSPDeviceSinkEngine::handleSourceMessages: forward message to ThreadedSampleSource(" << (*it)->getSampleSourceObjectName().toStdString().c_str() << ")";
(*it)->handleSourceMessage(*message);
}
// forward source changes to sinks with immediate execution
for(BasebandSampleSinks::const_iterator it = m_basebandSampleSinks.begin(); it != m_basebandSampleSinks.end(); it++)
{
qDebug() << "DSPDeviceSourceEngine::handleInputMessages: forward message to " << (*it)->objectName().toStdString().c_str();
(*it)->handleMessage(*message);
}
// forward changes to listeners on DSP output queue
DSPSignalNotification* rep = new DSPSignalNotification(*notif); // make a copy for the output queue
m_outputMessageQueue.push(rep);
delete message;
}
}
}

View File

@ -1,121 +1,128 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2016 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 //
// //
// 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 <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#ifndef SDRBASE_DSP_DSPDEVICESINKENGINE_H_
#define SDRBASE_DSP_DSPDEVICESINKENGINE_H_
#include <QThread>
#include <QTimer>
#include <QMutex>
#include <QWaitCondition>
#include <list>
#include "dsp/dsptypes.h"
#include "dsp/fftwindow.h"
#include "util/messagequeue.h"
#include "util/syncmessenger.h"
#include "util/export.h"
class DeviceSampleSink;
class BasebandSampleSource;
class ThreadedBasebandSampleSource; // TODO: TBD
class SDRANGEL_API DSPDeviceSinkEngine : public QThread {
Q_OBJECT
public:
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
};
DSPDeviceSinkEngine(uint uid, QObject* parent = NULL);
~DSPDeviceSinkEngine();
uint getUID() const { return m_uid; }
MessageQueue* getInputMessageQueue() { return &m_inputMessageQueue; }
MessageQueue* getOutputMessageQueue() { return &m_outputMessageQueue; }
void start(); //!< This thread start
void stop(); //!< This thread stop
bool initGeneration(); //!< Initialize generation sequence
bool startGeneration(); //!< Start generation sequence
void stopGeneration(); //!< Stop generation sequence
void setSink(DeviceSampleSink* sink); //!< Set the sample sink type
void setSinkSequence(int sequence); //!< Set the sample sink sequence in type
void addSource(BasebandSampleSource* source); //!< Add a baseband sample source
void removeSink(BasebandSampleSource* source); //!< Remove a baseband sample source
void addThreadedSource(ThreadedBasebandSampleSource* source); //!< Add a baseband sample source that will run on its own thread
void removeThreadedSource(ThreadedBasebandSampleSource* source); //!< Remove a baseband sample source that runs on its own thread
State state() const { return m_state; } //!< Return DSP engine current state
QString errorMessage(); //!< Return the current error message
QString sinkDeviceDescription(); //!< Return the sink device description
private:
uint m_uid; //!< unique ID
MessageQueue m_inputMessageQueue; //<! Input message queue. Post here.
MessageQueue m_outputMessageQueue; //<! Output message queue. Listen here.
SyncMessenger m_syncMessenger; //!< Used to process messages synchronously with the thread
State m_state;
QString m_errorMessage;
QString m_deviceDescription;
DeviceSampleSink* m_deviceSampleSink;
int m_sampleSinkSequence;
typedef std::list<BasebandSampleSource*> BasebandSampleSources;
BasebandSampleSources m_basebandSampleSources; //!< baseband sample sources within main thread (usually file input)
typedef std::list<ThreadedBasebandSampleSource*> ThreadedBasebandSampleSources;
ThreadedBasebandSampleSources m_threadedBasebandSampleSources; //!< baseband sample sources on their own threads (usually channels)
uint m_sampleRate;
quint64 m_centerFrequency;
void run();
void work(); //!< transfer samples from beseband sources to sink 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
void handleSetSink(DeviceSampleSink* sink); //!< Manage sink setting
private slots:
void handleData(); //!< Handle data when samples from source FIFO are ready to be processed
void handleInputMessages(); //!< Handle input message queue
void handleSynchronousMessages(); //!< Handle synchronous messages with the thread
};
#endif /* SDRBASE_DSP_DSPDEVICESINKENGINE_H_ */
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2016 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 //
// //
// 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 <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#ifndef SDRBASE_DSP_DSPDEVICESINKENGINE_H_
#define SDRBASE_DSP_DSPDEVICESINKENGINE_H_
#include <QThread>
#include <QTimer>
#include <QMutex>
#include <QWaitCondition>
#include <list>
#include "dsp/dsptypes.h"
#include "dsp/fftwindow.h"
#include "util/messagequeue.h"
#include "util/syncmessenger.h"
#include "util/export.h"
class DeviceSampleSink;
class BasebandSampleSource;
class ThreadedBasebandSampleSource;
class BasebandSampleSink;
class SDRANGEL_API DSPDeviceSinkEngine : public QThread {
Q_OBJECT
public:
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
};
DSPDeviceSinkEngine(uint uid, QObject* parent = NULL);
~DSPDeviceSinkEngine();
uint getUID() const { return m_uid; }
MessageQueue* getInputMessageQueue() { return &m_inputMessageQueue; }
MessageQueue* getOutputMessageQueue() { return &m_outputMessageQueue; }
void start(); //!< This thread start
void stop(); //!< This thread stop
bool initGeneration(); //!< Initialize generation sequence
bool startGeneration(); //!< Start generation sequence
void stopGeneration(); //!< Stop generation sequence
void setSink(DeviceSampleSink* sink); //!< Set the sample sink type
void setSinkSequence(int sequence); //!< Set the sample sink sequence in type
void addSource(BasebandSampleSource* source); //!< Add a baseband sample source
void removeSource(BasebandSampleSource* source); //!< Remove a baseband sample source
void addThreadedSource(ThreadedBasebandSampleSource* source); //!< Add a baseband sample source that will run on its own thread
void removeThreadedSource(ThreadedBasebandSampleSource* source); //!< Remove a baseband sample source that runs on its own thread
void addSink(BasebandSampleSink* sink); //!< Add a baseband sample sink
void removeSink(BasebandSampleSink* sink); //!< Remove a baseband sample sink
State state() const { return m_state; } //!< Return DSP engine current state
QString errorMessage(); //!< Return the current error message
QString sinkDeviceDescription(); //!< Return the sink device description
private:
uint m_uid; //!< unique ID
MessageQueue m_inputMessageQueue; //<! Input message queue. Post here.
MessageQueue m_outputMessageQueue; //<! Output message queue. Listen here.
SyncMessenger m_syncMessenger; //!< Used to process messages synchronously with the thread
State m_state;
QString m_errorMessage;
QString m_deviceDescription;
DeviceSampleSink* m_deviceSampleSink;
int m_sampleSinkSequence;
typedef std::list<BasebandSampleSource*> BasebandSampleSources;
BasebandSampleSources m_basebandSampleSources; //!< baseband sample sources within main thread (usually file input)
typedef std::list<ThreadedBasebandSampleSource*> ThreadedBasebandSampleSources;
ThreadedBasebandSampleSources m_threadedBasebandSampleSources; //!< baseband sample sources on their own threads (usually channels)
typedef std::list<BasebandSampleSink*> BasebandSampleSinks;
BasebandSampleSinks m_basebandSampleSinks; //!< baseband sample sinks within main thread (this is only the spectrum vis normally)
uint m_sampleRate;
quint64 m_centerFrequency;
void run();
void work(); //!< transfer samples from beseband sources to sink 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
void handleSetSink(DeviceSampleSink* sink); //!< Manage sink setting
private slots:
void handleData(); //!< Handle data when samples from source FIFO are ready to be processed
void handleInputMessages(); //!< Handle input message queue
void handleSynchronousMessages(); //!< Handle synchronous messages with the thread
};
#endif /* SDRBASE_DSP_DSPDEVICESINKENGINE_H_ */

View File

@ -348,6 +348,8 @@ DSPDeviceSourceEngine::State DSPDeviceSourceEngine::gotoIdle()
(*it)->stop();
}
// TODO: why not stopping the threaded baseband sample sinks?
m_deviceSampleSource->stop();
m_deviceDescription.clear();
m_sampleRate = 0;

View File

@ -40,6 +40,7 @@ struct Sample
inline Sample& operator+=(const Sample& other) { m_real += other.m_real; m_imag += other.m_imag; return *this; }
inline Sample& operator-=(const Sample& other) { m_real -= other.m_real; m_imag -= other.m_imag; return *this; }
inline Sample& operator/=(const unsigned int& divisor) { m_real /= divisor; m_imag /= divisor; return *this; }
inline void setReal(FixReal v) { m_real = v; }
inline void setImag(FixReal v) { m_imag = v; }

View File

@ -20,34 +20,6 @@
#include "dsp/threadedbasebandsamplesource.h"
ThreadedBasebandSampleSourceFifo::ThreadedBasebandSampleSourceFifo(BasebandSampleSource* sampleSource) :
m_sampleSource(sampleSource),
m_sampleSourceFifo(1<<19, 1<<17)
{
m_samplesChunkSize = m_sampleSourceFifo.getChunkSize();
connect(&m_sampleSourceFifo, SIGNAL(dataWrite()), this, SLOT(handleFifoData()));
}
ThreadedBasebandSampleSourceFifo::~ThreadedBasebandSampleSourceFifo()
{
}
void ThreadedBasebandSampleSourceFifo::readFromFifo(SampleVector::iterator& beginRead, unsigned int nbSamples)
{
m_sampleSourceFifo.read(beginRead, nbSamples);
}
void ThreadedBasebandSampleSourceFifo::handleFifoData()
{
for (int i = 0; i < m_samplesChunkSize; i++)
{
SampleVector::iterator sampleIt;
m_sampleSourceFifo.getWriteIterator(sampleIt);
m_sampleSource->pull(*sampleIt);
m_sampleSourceFifo.bumpIndex();
}
}
ThreadedBasebandSampleSource::ThreadedBasebandSampleSource(BasebandSampleSource* sampleSource, QObject *parent) :
m_basebandSampleSource(sampleSource)
{
@ -57,16 +29,13 @@ ThreadedBasebandSampleSource::ThreadedBasebandSampleSource(BasebandSampleSource*
qDebug() << "ThreadedBasebandSampleSource::ThreadedBasebandSampleSource: " << name;
m_thread = new QThread(parent);
m_threadedBasebandSampleSourceFifo = new ThreadedBasebandSampleSourceFifo(m_basebandSampleSource);
m_basebandSampleSource->moveToThread(m_thread);
m_threadedBasebandSampleSourceFifo->moveToThread(m_thread);
qDebug() << "ThreadedBasebandSampleSource::ThreadedBasebandSampleSource: thread: " << thread() << " m_thread: " << m_thread;
}
ThreadedBasebandSampleSource::~ThreadedBasebandSampleSource()
{
delete m_threadedBasebandSampleSourceFifo;
delete m_thread;
}
@ -85,9 +54,9 @@ void ThreadedBasebandSampleSource::stop()
m_thread->wait();
}
void ThreadedBasebandSampleSource::pull(SampleVector::iterator& beginRead, unsigned int nbSamples)
void ThreadedBasebandSampleSource::pull(Sample& sample)
{
m_threadedBasebandSampleSourceFifo->readFromFifo(beginRead, nbSamples);
m_basebandSampleSource->pull(sample);
}
bool ThreadedBasebandSampleSource::handleSourceMessage(const Message& cmd)

View File

@ -1,81 +1,58 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2016 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 //
// //
// 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 <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#ifndef SDRBASE_DSP_THREADEDBASEBANDSAMPLESOURCE_H_
#define SDRBASE_DSP_THREADEDBASEBANDSAMPLESOURCE_H_
#include <dsp/basebandsamplesource.h>
#include <QMutex>
#include "samplesourcefifo.h"
#include "util/messagequeue.h"
#include "util/export.h"
class BasebandSampleSource;
class QThread;
/**
* Because Qt is a piece of shit this class cannot be a nested protected class of ThreadedSampleSource
* So let's make everything public
*/
class ThreadedBasebandSampleSourceFifo : public QObject {
Q_OBJECT
public:
ThreadedBasebandSampleSourceFifo(BasebandSampleSource* sampleSource);
~ThreadedBasebandSampleSourceFifo();
void readFromFifo(SampleVector::iterator& beginRead, unsigned int nbSamples);
BasebandSampleSource* m_sampleSource;
SampleSourceFifo m_sampleSourceFifo;
public slots:
void handleFifoData();
private:
unsigned int m_samplesChunkSize;
};
/**
* This class is a wrapper for BasebandSampleSource that runs the BasebandSampleSource object in its own thread
*/
class SDRANGEL_API ThreadedBasebandSampleSource : public QObject {
Q_OBJECT
public:
ThreadedBasebandSampleSource(BasebandSampleSource* sampleSource, QObject *parent = 0);
~ThreadedBasebandSampleSource();
const BasebandSampleSource *getSource() const { return m_basebandSampleSource; }
MessageQueue* getInputMessageQueue() { return m_basebandSampleSource->getInputMessageQueue(); } //!< Return pointer to sample source's input message queue
MessageQueue* getOutputMessageQueue() { return m_basebandSampleSource->getOutputMessageQueue(); } //!< Return pointer to sample source's output message queue
void start(); //!< this thread start()
void stop(); //!< this thread exit() and wait()
bool handleSourceMessage(const Message& cmd); //!< Send message to source synchronously
void pull(SampleVector::iterator& beginRead, unsigned int nbSamples); //!< Pull samples from source
QString getSampleSourceObjectName() const;
protected:
QThread *m_thread; //!< The thead object
ThreadedBasebandSampleSourceFifo *m_threadedBasebandSampleSourceFifo;
BasebandSampleSource* m_basebandSampleSource;
};
#endif /* SDRBASE_DSP_THREADEDBASEBANDSAMPLESOURCE_H_ */
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2016 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 //
// //
// 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 <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#ifndef SDRBASE_DSP_THREADEDBASEBANDSAMPLESOURCE_H_
#define SDRBASE_DSP_THREADEDBASEBANDSAMPLESOURCE_H_
#include <dsp/basebandsamplesource.h>
#include <QMutex>
#include "samplesourcefifo.h"
#include "util/messagequeue.h"
#include "util/export.h"
class BasebandSampleSource;
class QThread;
/**
* This class is a wrapper for BasebandSampleSource that runs the BasebandSampleSource object in its own thread
*/
class SDRANGEL_API ThreadedBasebandSampleSource : public QObject {
Q_OBJECT
public:
ThreadedBasebandSampleSource(BasebandSampleSource* sampleSource, QObject *parent = 0);
~ThreadedBasebandSampleSource();
const BasebandSampleSource *getSource() const { return m_basebandSampleSource; }
MessageQueue* getInputMessageQueue() { return m_basebandSampleSource->getInputMessageQueue(); } //!< Return pointer to sample source's input message queue
MessageQueue* getOutputMessageQueue() { return m_basebandSampleSource->getOutputMessageQueue(); } //!< Return pointer to sample source's output message queue
void start(); //!< this thread start()
void stop(); //!< this thread exit() and wait()
bool handleSourceMessage(const Message& cmd); //!< Send message to source synchronously
void pull(Sample& sample); //!< Pull one sample from source
QString getSampleSourceObjectName() const;
protected:
QThread *m_thread; //!< The thead object
BasebandSampleSource* m_basebandSampleSource;
};
#endif /* SDRBASE_DSP_THREADEDBASEBANDSAMPLESOURCE_H_ */

View File

@ -40,6 +40,7 @@ SOURCES += mainwindow.cpp\
dsp/dspcommands.cpp\
dsp/dspengine.cpp\
dsp/dspdevicesourceengine.cpp\
dsp/dspdevicesinkengine.cpp\
dsp/dvserialengine.cpp\
dsp/dvserialworker.cpp\
dsp/fftengine.cpp\
@ -120,6 +121,7 @@ HEADERS += mainwindow.h\
dsp/dspcommands.h\
dsp/dspengine.h\
dsp/dspdevicesourceengine.h\
dsp/dspdevicesinkengine.h\
dsp/dvserialengine.h\
dsp/dvserialworker.h\
dsp/dsptypes.h\