1
0
mirror of https://github.com/f4exb/sdrangel.git synced 2025-05-23 18:52:28 -04:00

Deep redesign: phase #2

This commit is contained in:
f4exb 2015-08-14 05:00:28 +02:00
parent 1799cd816f
commit f5c5e19571
27 changed files with 592 additions and 550 deletions

View File

@ -111,6 +111,7 @@ set(sdrbase_SOURCES
sdrbase/util/message.cpp sdrbase/util/message.cpp
sdrbase/util/messagequeue.cpp sdrbase/util/messagequeue.cpp
sdrbase/util/syncmessenger.cpp
#sdrbase/util/miniz.cpp #sdrbase/util/miniz.cpp
sdrbase/util/simpleserializer.cpp sdrbase/util/simpleserializer.cpp
sdrbase/util/spinlock.cpp sdrbase/util/spinlock.cpp
@ -185,6 +186,7 @@ set(sdrbase_HEADERS
include/util/export.h include/util/export.h
include/util/message.h include/util/message.h
include/util/messagequeue.h include/util/messagequeue.h
include/util/syncmessenger.h
#include/util/miniz.h #include/util/miniz.h
include/util/simpleserializer.h include/util/simpleserializer.h
include/util/spinlock.h include/util/spinlock.h

View File

@ -131,6 +131,7 @@ Done since the fork
- File sample source plugin (recording reader) not working - File sample source plugin (recording reader) not working
- Make the DSP engine global static - Make the DSP engine global static
- Fixed startup initialization sequence. New initialization phase in DSP engine and new ready state - Fixed startup initialization sequence. New initialization phase in DSP engine and new ready state
- Message queuing and handling redesign
===== =====
To Do To Do

View File

@ -12,15 +12,16 @@ class SDRANGELOVE_API Channelizer : public SampleSink {
Q_OBJECT Q_OBJECT
public: public:
Channelizer(SampleSink* sampleSink); Channelizer(SampleSink* sampleSink);
~Channelizer(); virtual ~Channelizer();
void configure(MessageQueue* messageQueue, int sampleRate, int centerFrequency); void configure(MessageQueue* messageQueue, int sampleRate, int centerFrequency);
int getInputSampleRate() const { return m_inputSampleRate; } int getInputSampleRate() const { return m_inputSampleRate; }
void feed(SampleVector::const_iterator begin, SampleVector::const_iterator end, bool positiveOnly); virtual bool init(const Message& cmd);
void start(); virtual void feed(SampleVector::const_iterator begin, SampleVector::const_iterator end, bool positiveOnly);
void stop(); virtual void start();
bool handleMessage(Message* cmd); virtual void stop();
virtual bool handleMessage(const Message& cmd);
protected: protected:
struct FilterStage { struct FilterStage {

View File

@ -133,144 +133,115 @@ class SDRANGELOVE_API DSPConfigureSpectrumVis : public Message {
MESSAGE_CLASS_DECLARATION MESSAGE_CLASS_DECLARATION
public: public:
int getFFTSize() const { return m_fftSize; }
int getOverlapPercent() const { return m_overlapPercent; }
FFTWindow::Function getWindow() const { return m_window; }
static DSPConfigureSpectrumVis* create(int fftSize, int overlapPercent, FFTWindow::Function window)
{
return new DSPConfigureSpectrumVis(fftSize, overlapPercent, window);
}
private:
int m_fftSize;
int m_overlapPercent;
FFTWindow::Function m_window;
DSPConfigureSpectrumVis(int fftSize, int overlapPercent, FFTWindow::Function window) : DSPConfigureSpectrumVis(int fftSize, int overlapPercent, FFTWindow::Function window) :
Message(), Message(),
m_fftSize(fftSize), m_fftSize(fftSize),
m_overlapPercent(overlapPercent), m_overlapPercent(overlapPercent),
m_window(window) m_window(window)
{ } { }
int getFFTSize() const { return m_fftSize; }
int getOverlapPercent() const { return m_overlapPercent; }
FFTWindow::Function getWindow() const { return m_window; }
private:
int m_fftSize;
int m_overlapPercent;
FFTWindow::Function m_window;
}; };
class SDRANGELOVE_API DSPConfigureCorrection : public Message { class SDRANGELOVE_API DSPConfigureCorrection : public Message {
MESSAGE_CLASS_DECLARATION MESSAGE_CLASS_DECLARATION
public: public:
bool getDCOffsetCorrection() const { return m_dcOffsetCorrection; }
bool getIQImbalanceCorrection() const { return m_iqImbalanceCorrection; }
static DSPConfigureCorrection* create(bool dcOffsetCorrection, bool iqImbalanceCorrection)
{
return new DSPConfigureCorrection(dcOffsetCorrection, iqImbalanceCorrection);
}
private:
bool m_dcOffsetCorrection;
bool m_iqImbalanceCorrection;
DSPConfigureCorrection(bool dcOffsetCorrection, bool iqImbalanceCorrection) : DSPConfigureCorrection(bool dcOffsetCorrection, bool iqImbalanceCorrection) :
Message(), Message(),
m_dcOffsetCorrection(dcOffsetCorrection), m_dcOffsetCorrection(dcOffsetCorrection),
m_iqImbalanceCorrection(iqImbalanceCorrection) m_iqImbalanceCorrection(iqImbalanceCorrection)
{ } { }
bool getDCOffsetCorrection() const { return m_dcOffsetCorrection; }
bool getIQImbalanceCorrection() const { return m_iqImbalanceCorrection; }
private:
bool m_dcOffsetCorrection;
bool m_iqImbalanceCorrection;
}; };
class SDRANGELOVE_API DSPEngineReport : public Message { class SDRANGELOVE_API DSPEngineReport : public Message {
MESSAGE_CLASS_DECLARATION MESSAGE_CLASS_DECLARATION
public: public:
int getSampleRate() const { return m_sampleRate; }
quint64 getCenterFrequency() const { return m_centerFrequency; }
static DSPEngineReport* create(int sampleRate, quint64 centerFrequency)
{
return new DSPEngineReport(sampleRate, centerFrequency);
}
private:
int m_sampleRate;
quint64 m_centerFrequency;
DSPEngineReport(int sampleRate, quint64 centerFrequency) : DSPEngineReport(int sampleRate, quint64 centerFrequency) :
Message(), Message(),
m_sampleRate(sampleRate), m_sampleRate(sampleRate),
m_centerFrequency(centerFrequency) m_centerFrequency(centerFrequency)
{ } { }
int getSampleRate() const { return m_sampleRate; }
quint64 getCenterFrequency() const { return m_centerFrequency; }
private:
int m_sampleRate;
quint64 m_centerFrequency;
}; };
class SDRANGELOVE_API DSPConfigureScopeVis : public Message { class SDRANGELOVE_API DSPConfigureScopeVis : public Message {
MESSAGE_CLASS_DECLARATION MESSAGE_CLASS_DECLARATION
public: public:
int getTriggerChannel() const { return m_triggerChannel; }
Real getTriggerLevelHigh() const { return m_triggerLevelHigh; }
Real getTriggerLevelLow() const { return m_triggerLevelLow; }
static DSPConfigureScopeVis* create(int triggerChannel, Real triggerLevelHigh, Real triggerLevelLow)
{
return new DSPConfigureScopeVis(triggerChannel, triggerLevelHigh, triggerLevelLow);
}
private:
int m_triggerChannel;
Real m_triggerLevelHigh;
Real m_triggerLevelLow;
DSPConfigureScopeVis(int triggerChannel, Real triggerLevelHigh, Real triggerLevelLow) : DSPConfigureScopeVis(int triggerChannel, Real triggerLevelHigh, Real triggerLevelLow) :
Message(), Message(),
m_triggerChannel(triggerChannel), m_triggerChannel(triggerChannel),
m_triggerLevelHigh(triggerLevelHigh), m_triggerLevelHigh(triggerLevelHigh),
m_triggerLevelLow(triggerLevelLow) m_triggerLevelLow(triggerLevelLow)
{ } { }
int getTriggerChannel() const { return m_triggerChannel; }
Real getTriggerLevelHigh() const { return m_triggerLevelHigh; }
Real getTriggerLevelLow() const { return m_triggerLevelLow; }
private:
int m_triggerChannel;
Real m_triggerLevelHigh;
Real m_triggerLevelLow;
}; };
class SDRANGELOVE_API DSPSignalNotification : public Message { class SDRANGELOVE_API DSPSignalNotification : public Message {
MESSAGE_CLASS_DECLARATION MESSAGE_CLASS_DECLARATION
public: public:
int getSampleRate() const { return m_sampleRate; }
qint64 getFrequencyOffset() const { return m_frequencyOffset; }
static DSPSignalNotification* create(int sampleRate, quint64 frequencyOffset)
{
return new DSPSignalNotification(sampleRate, frequencyOffset);
}
private:
int m_sampleRate;
qint64 m_frequencyOffset;
DSPSignalNotification(int samplerate, qint64 frequencyOffset) : DSPSignalNotification(int samplerate, qint64 frequencyOffset) :
Message(), Message(),
m_sampleRate(samplerate), m_sampleRate(samplerate),
m_frequencyOffset(frequencyOffset) m_frequencyOffset(frequencyOffset)
{ } { }
int getSampleRate() const { return m_sampleRate; }
qint64 getFrequencyOffset() const { return m_frequencyOffset; }
private:
int m_sampleRate;
qint64 m_frequencyOffset;
}; };
class SDRANGELOVE_API DSPConfigureChannelizer : public Message { class SDRANGELOVE_API DSPConfigureChannelizer : public Message {
MESSAGE_CLASS_DECLARATION MESSAGE_CLASS_DECLARATION
public: public:
int getSampleRate() const { return m_sampleRate; }
int getCenterFrequency() const { return m_centerFrequency; }
static DSPConfigureChannelizer* create(int sampleRate, int centerFrequency)
{
return new DSPConfigureChannelizer(sampleRate, centerFrequency);
}
private:
int m_sampleRate;
int m_centerFrequency;
DSPConfigureChannelizer(int sampleRate, int centerFrequency) : DSPConfigureChannelizer(int sampleRate, int centerFrequency) :
Message(), Message(),
m_sampleRate(sampleRate), m_sampleRate(sampleRate),
m_centerFrequency(centerFrequency) m_centerFrequency(centerFrequency)
{ } { }
int getSampleRate() const { return m_sampleRate; }
int getCenterFrequency() const { return m_centerFrequency; }
private:
int m_sampleRate;
int m_centerFrequency;
}; };
#endif // INCLUDE_DSPCOMMANDS_H #endif // INCLUDE_DSPCOMMANDS_H

View File

@ -27,6 +27,7 @@
#include "dsp/samplefifo.h" #include "dsp/samplefifo.h"
#include "audio/audiooutput.h" #include "audio/audiooutput.h"
#include "util/messagequeue.h" #include "util/messagequeue.h"
#include "util/syncmessenger.h"
#include "util/export.h" #include "util/export.h"
class SampleSource; class SampleSource;
@ -78,6 +79,7 @@ public:
private: private:
MessageQueue m_inputMessageQueue; //<! Input message queue. Post here. MessageQueue m_inputMessageQueue; //<! Input message queue. Post here.
MessageQueue m_outputMessageQueue; //<! Output message queue. Listen here. MessageQueue m_outputMessageQueue; //<! Output message queue. Listen here.
SyncMessenger m_syncMessenger; //!< Used to process messages synchronously with the thread
State m_state; State m_state;
@ -113,11 +115,11 @@ private:
State gotoError(const QString& errorMsg); //!< Go to an error state State gotoError(const QString& errorMsg); //!< Go to an error state
void handleSetSource(SampleSource* source); //!< Manage source setting void handleSetSource(SampleSource* source); //!< Manage source setting
bool distributeMessage(Message* message); // FIXME: remove ?
private slots: private slots:
void handleData(); //!< Handle data when samples from source FIFO are ready to be processed void handleData(); //!< Handle data when samples from source FIFO are ready to be processed
void handleInputMessages(); //!< Handle input message queue void handleInputMessages(); //!< Handle input message queue
void handleSynchronousMessages(Message *message); //!< Handle synchronous messages with the thread
}; };
#endif // INCLUDE_DSPENGINE_H #endif // INCLUDE_DSPENGINE_H

View File

@ -26,19 +26,17 @@ public:
quint64 getByteCount() const { return m_byteCount; } quint64 getByteCount() const { return m_byteCount; }
void configure(MessageQueue* msgQueue, const std::string& filename, int sampleRate, quint64 centerFrequency); void configure(MessageQueue* msgQueue, const std::string& filename);
virtual bool init(Message* cmd); virtual bool init(const Message& cmd);
virtual void feed(SampleVector::const_iterator begin, SampleVector::const_iterator end, bool positiveOnly); virtual void feed(SampleVector::const_iterator begin, SampleVector::const_iterator end, bool positiveOnly);
virtual void start(); virtual void start();
virtual void stop(); virtual void stop();
virtual bool handleMessage(Message* message); virtual bool handleMessage(const Message& message);
void startRecording(); void startRecording();
void stopRecording(); void stopRecording();
static void readHeader(std::ifstream& samplefile, Header& header); static void readHeader(std::ifstream& samplefile, Header& header);
MessageQueue *getMessageQueue() { return m_messageQueue; }
private: private:
class MsgConfigureFileSink : public Message { class MsgConfigureFileSink : public Message {
MESSAGE_CLASS_DECLARATION MESSAGE_CLASS_DECLARATION
@ -67,9 +65,8 @@ private:
bool m_recordStart; bool m_recordStart;
std::ofstream m_sampleFile; std::ofstream m_sampleFile;
quint64 m_byteCount; quint64 m_byteCount;
MessageQueue m_messageQueue;
void handleConfigure(const std::string& fileName, int sampleRate, quint64 centerFrequency); void handleConfigure(const std::string& fileName);
void writeHeader(); void writeHeader();
}; };

View File

@ -4,17 +4,19 @@
#include "dsp/samplesink.h" #include "dsp/samplesink.h"
#include "util/export.h" #include "util/export.h"
class MessageQueue; class Message;
class SDRANGELOVE_API NullSink : public SampleSink { class SDRANGELOVE_API NullSink : public SampleSink {
public: public:
NullSink(); NullSink();
virtual ~NullSink();
void feed(SampleVector::const_iterator begin, SampleVector::const_iterator end, bool positiveOnly); virtual bool init(const Message& cmd);
void start(); virtual void feed(SampleVector::const_iterator begin, SampleVector::const_iterator end, bool positiveOnly);
void stop(); virtual void start();
bool handleMessage(Message* message); virtual void stop();
virtual bool handleMessage(const Message& message);
}; };
#endif // INCLUDE_NULLSINK_H #endif // INCLUDE_NULLSINK_H

View File

@ -23,6 +23,7 @@ public:
static const uint m_traceChunkSize; static const uint m_traceChunkSize;
ScopeVis(GLScope* glScope = NULL); ScopeVis(GLScope* glScope = NULL);
virtual ~ScopeVis();
void configure(MessageQueue* msgQueue, void configure(MessageQueue* msgQueue,
TriggerChannel triggerChannel, TriggerChannel triggerChannel,
@ -34,11 +35,11 @@ public:
uint traceSize); uint traceSize);
void setOneShot(bool oneShot); void setOneShot(bool oneShot);
void feed(SampleVector::const_iterator begin, SampleVector::const_iterator end, bool positiveOnly); virtual bool init(const Message& cmd);
void start(); virtual void feed(SampleVector::const_iterator begin, SampleVector::const_iterator end, bool positiveOnly);
void stop(); virtual void start();
bool handleMessageKeep(Message* message); virtual void stop();
bool handleMessage(Message* message); virtual bool handleMessage(const Message& message);
void setSampleRate(int sampleRate); void setSampleRate(int sampleRate);
int getSampleRate() const { return m_sampleRate; } int getSampleRate() const { return m_sampleRate; }

View File

@ -6,17 +6,19 @@
#include "dsp/scopevis.h" #include "dsp/scopevis.h"
#include "util/export.h" #include "util/export.h"
class MessageQueue; class Message;
class SDRANGELOVE_API SpectrumScopeComboVis : public SampleSink { class SDRANGELOVE_API SpectrumScopeComboVis : public SampleSink {
public: public:
SpectrumScopeComboVis(SpectrumVis* spectrumVis, ScopeVis* scopeVis); SpectrumScopeComboVis(SpectrumVis* spectrumVis, ScopeVis* scopeVis);
virtual ~SpectrumScopeComboVis();
void feed(SampleVector::const_iterator begin, SampleVector::const_iterator end, bool positiveOnly); virtual bool init(const Message& cmd);
void start(); virtual void feed(SampleVector::const_iterator begin, SampleVector::const_iterator end, bool positiveOnly);
void stop(); virtual void start();
bool handleMessage(Message* message); virtual void stop();
virtual bool handleMessage(const Message& message);
private: private:
SpectrumVis* m_spectrumVis; SpectrumVis* m_spectrumVis;

View File

@ -12,16 +12,16 @@ class MessageQueue;
class SDRANGELOVE_API SpectrumVis : public SampleSink { class SDRANGELOVE_API SpectrumVis : public SampleSink {
public: public:
SpectrumVis(GLSpectrum* glSpectrum = NULL); SpectrumVis(GLSpectrum* glSpectrum = NULL);
~SpectrumVis(); virtual ~SpectrumVis();
void configure(MessageQueue* msgQueue, int fftSize, int overlapPercent, FFTWindow::Function window); void configure(MessageQueue* msgQueue, int fftSize, int overlapPercent, FFTWindow::Function window);
void feed(SampleVector::const_iterator begin, SampleVector::const_iterator end, bool positiveOnly); virtual bool init(const Message& cmd);
virtual void feed(SampleVector::const_iterator begin, SampleVector::const_iterator end, bool positiveOnly);
void feedTriggered(SampleVector::const_iterator triggerPoint, SampleVector::const_iterator begin, SampleVector::const_iterator end, bool positiveOnly); void feedTriggered(SampleVector::const_iterator triggerPoint, SampleVector::const_iterator begin, SampleVector::const_iterator end, bool positiveOnly);
void start(); virtual void start();
void stop(); virtual void stop();
bool handleMessageKeep(Message* message); virtual bool handleMessage(const Message& message);
bool handleMessage(Message* message);
private: private:
FFTEngine* m_fft; FFTEngine* m_fft;
@ -30,11 +30,11 @@ private:
std::vector<Complex> m_fftBuffer; std::vector<Complex> m_fftBuffer;
std::vector<Real> m_logPowerSpectrum; std::vector<Real> m_logPowerSpectrum;
size_t m_fftSize; std::size_t m_fftSize;
size_t m_overlapPercent; std::size_t m_overlapPercent;
size_t m_overlapSize; std::size_t m_overlapSize;
size_t m_refillSize; std::size_t m_refillSize;
size_t m_fftBufferFill; std::size_t m_fftBufferFill;
bool m_needMoreSamples; bool m_needMoreSamples;
GLSpectrum* m_glSpectrum; GLSpectrum* m_glSpectrum;

View File

@ -4,6 +4,7 @@
#include <QObject> #include <QObject>
#include "dsptypes.h" #include "dsptypes.h"
#include "util/export.h" #include "util/export.h"
#include "util/messagequeue.h"
class Message; class Message;
@ -12,11 +13,18 @@ public:
SampleSink(); SampleSink();
virtual ~SampleSink(); virtual ~SampleSink();
virtual bool init(Message* cmd) = 0; virtual bool init(const Message& cmd) = 0;
virtual void feed(SampleVector::const_iterator begin, SampleVector::const_iterator end, bool positiveOnly) = 0; virtual void feed(SampleVector::const_iterator begin, SampleVector::const_iterator end, bool positiveOnly) = 0;
virtual void start() = 0; virtual void start() = 0;
virtual void stop() = 0; virtual void stop() = 0;
virtual bool handleMessage(Message* cmd) = 0; //!< Handle message immediately or submit it to a queue virtual bool handleMessage(const Message& cmd) = 0; //!< Processing of a message. Returns true if message has actually been processed
MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; }
MessageQueue *getOutputMessageQueue() { return &m_outputMessageQueue; }
protected:
MessageQueue m_inputMessageQueue;
MessageQueue m_outputMessageQueue;
}; };
#endif // INCLUDE_SAMPLESINK_H #endif // INCLUDE_SAMPLESINK_H

View File

@ -1,6 +1,6 @@
/////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2012 maintech GmbH, Otto-Hahn-Str. 15, 97204 Hoechberg, Germany // // Copyright (C) 2015 F4EXB //
// written by Christian Daniel // // written by Edouard Griffiths //
// // // //
// This program is free software; you can redistribute it and/or modify // // 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 // // it under the terms of the GNU General Public License as published by //
@ -21,42 +21,32 @@
#include <QtGlobal> #include <QtGlobal>
#include "dsp/samplefifo.h" #include "dsp/samplefifo.h"
#include "util/message.h" #include "util/message.h"
#include "util/messagequeue.h"
#include "util/export.h" #include "util/export.h"
class PluginGUI;
class MessageQueue;
class SDRANGELOVE_API SampleSource { class SDRANGELOVE_API SampleSource {
public: public:
struct SDRANGELOVE_API GeneralSettings { SampleSource();
quint64 m_centerFrequency;
GeneralSettings();
void resetToDefaults();
QByteArray serialize() const;
bool deserialize(const QByteArray& data);
};
SampleSource(MessageQueue* guiMessageQueue);
virtual ~SampleSource(); virtual ~SampleSource();
virtual void init(Message* cmd) = 0; virtual void init(const Message& cmd) = 0;
virtual bool startInput(int device) = 0; virtual bool start(int device) = 0;
virtual void stopInput() = 0; virtual void stop() = 0;
virtual const QString& getDeviceDescription() const = 0; virtual const QString& getDeviceDescription() const = 0;
virtual int getSampleRate() const = 0; virtual int getSampleRate() const = 0;
virtual quint64 getCenterFrequency() const = 0; virtual quint64 getCenterFrequency() const = 0;
virtual bool handleMessage(Message* message) = 0; virtual bool handleMessage(const Message& message) = 0;
SampleFifo* getSampleFifo() { return &m_sampleFifo; } MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; }
MessageQueue *getOutputMessageQueue() { return &m_outputMessageQueue; }
SampleFifo* getSampleFifo() { return &m_sampleFifo; }
protected: protected:
SampleFifo m_sampleFifo; SampleFifo m_sampleFifo;
MessageQueue* m_guiMessageQueue; MessageQueue m_inputMessageQueue;
MessageQueue m_outputMessageQueue;
GeneralSettings m_generalSettings;
}; };
#endif // INCLUDE_SAMPLESOURCE_H #endif // INCLUDE_SAMPLESOURCE_H

View File

@ -1,14 +1,26 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2015 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 INCLUDE_MESSAGE_H #ifndef INCLUDE_MESSAGE_H
#define INCLUDE_MESSAGE_H #define INCLUDE_MESSAGE_H
#include <stdlib.h> #include <stdlib.h>
#include <QAtomicInt>
#include "util/export.h" #include "util/export.h"
class MessageQueue;
class QWaitCondition;
class QMutex;
class SDRANGELOVE_API Message { class SDRANGELOVE_API Message {
public: public:
Message(); Message();
@ -16,33 +28,22 @@ public:
virtual const char* getIdentifier() const; virtual const char* getIdentifier() const;
virtual bool matchIdentifier(const char* identifier) const; virtual bool matchIdentifier(const char* identifier) const;
static bool match(Message* message); static bool match(const Message* message);
void* getDestination() const { return m_destination; } void* getDestination() const { return m_destination; }
void setDestination(void *destination) { m_destination = destination; }
void submit(MessageQueue* queue, void* destination = NULL);
int execute(MessageQueue* queue, void* destination = NULL);
void completed(int result = 0);
protected: protected:
// addressing // addressing
static const char* m_identifier; static const char* m_identifier;
void* m_destination; void* m_destination;
// stuff for synchronous messages
bool m_synchronous;
QWaitCondition* m_waitCondition;
QMutex* m_mutex;
QAtomicInt m_complete;
int m_result;
}; };
#define MESSAGE_CLASS_DECLARATION \ #define MESSAGE_CLASS_DECLARATION \
public: \ public: \
const char* getIdentifier() const; \ const char* getIdentifier() const; \
bool matchIdentifier(const char* identifier) const; \ bool matchIdentifier(const char* identifier) const; \
static bool match(Message* message); \ static bool match(const Message* message); \
protected: \ protected: \
static const char* m_identifier; \ static const char* m_identifier; \
private: private:
@ -53,6 +54,6 @@ protected:
bool Name::matchIdentifier(const char* identifier) const {\ bool Name::matchIdentifier(const char* identifier) const {\
return (m_identifier == identifier) ? true : BaseClass::matchIdentifier(identifier); \ return (m_identifier == identifier) ? true : BaseClass::matchIdentifier(identifier); \
} \ } \
bool Name::match(Message* message) { return message->matchIdentifier(m_identifier); } bool Name::match(const Message* message) { return message->matchIdentifier(m_identifier); }
#endif // INCLUDE_MESSAGE_H #endif // INCLUDE_MESSAGE_H

View File

@ -1,3 +1,20 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2015 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 INCLUDE_MESSAGEQUEUE_H #ifndef INCLUDE_MESSAGEQUEUE_H
#define INCLUDE_MESSAGEQUEUE_H #define INCLUDE_MESSAGEQUEUE_H
@ -15,11 +32,11 @@ public:
MessageQueue(QObject* parent = NULL); MessageQueue(QObject* parent = NULL);
~MessageQueue(); ~MessageQueue();
void submit(Message* message); void push(Message* message, bool emitSignal = true); //!< Push message onto queue
Message* accept(); Message* pop(); //!< Pop message from queue
int countPending(); int size(); //!< Returns queue size
void clear(); void clear(); //!< Empty queue
signals: signals:
void messageEnqueued(); void messageEnqueued();

View File

@ -0,0 +1,54 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2015 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 INCLUDE_UTIL_SYNCMESSENGER_H_
#define INCLUDE_UTIL_SYNCMESSENGER_H_
#include <QObject>
#include <QWaitCondition>
#include <QMutex>
#include <QAtomicInt>
#include "util/export.h"
class Message;
/**
* This class is responsible of managing the synchronous processing of a message across threads
*/
class SDRANGELOVE_API SyncMessenger : public QObject {
Q_OBJECT
public:
SyncMessenger();
~SyncMessenger();
int sendWait(Message *message, unsigned long msPollTime = 100); //!< Send message and waits for its process completion
void done(int result = 0); //!< Processing of the message is complete
signals:
void messageSent(Message *message);
protected:
QWaitCondition m_waitCondition;
QMutex m_mutex;
QAtomicInt m_complete;
int m_result;
};
#endif /* INCLUDE_UTIL_SYNCMESSENGER_H_ */

View File

@ -20,10 +20,26 @@ Channelizer::~Channelizer()
freeFilterChain(); freeFilterChain();
} }
bool Channelizer::init(const Message& cmd)
{
if (DSPSignalNotification::match(&cmd))
{
DSPSignalNotification* notif = (DSPSignalNotification*) &cmd;
m_inputSampleRate = notif->getSampleRate();
qDebug() << "FileSink::init: DSPSignalNotification: m_inputSampleRate: " << m_inputSampleRate;
emit inputSampleRateChanged();
return true;
}
else
{
return false;
}
}
void Channelizer::configure(MessageQueue* messageQueue, int sampleRate, int centerFrequency) void Channelizer::configure(MessageQueue* messageQueue, int sampleRate, int centerFrequency)
{ {
Message* cmd = DSPConfigureChannelizer::create(sampleRate, centerFrequency); Message* cmd = new DSPConfigureChannelizer(sampleRate, centerFrequency);
cmd->submit(messageQueue, this); messageQueue->push(cmd);
} }
void Channelizer::feed(SampleVector::const_iterator begin, SampleVector::const_iterator end, bool positiveOnly) void Channelizer::feed(SampleVector::const_iterator begin, SampleVector::const_iterator end, bool positiveOnly)
@ -64,52 +80,58 @@ void Channelizer::stop()
m_sampleSink->stop(); m_sampleSink->stop();
} }
bool Channelizer::handleMessage(Message* cmd) bool Channelizer::handleMessage(const Message& cmd)
{ {
qDebug() << "Channelizer::handleMessage: " << cmd->getIdentifier(); qDebug() << "Channelizer::handleMessage: " << cmd.getIdentifier();
if (DSPSignalNotification::match(cmd)) /*
if (DSPSignalNotification::match(&cmd))
{ {
DSPSignalNotification* signal = (DSPSignalNotification*)cmd; DSPSignalNotification* notif = (DSPSignalNotification*) &cmd;
m_inputSampleRate = signal->getSampleRate(); m_inputSampleRate = notif->getSampleRate();
qDebug() << "Channelizer::handleMessage: DSPSignalNotification: m_inputSampleRate: " << m_inputSampleRate; qDebug() << "Channelizer::handleMessage: DSPSignalNotification: m_inputSampleRate: " << m_inputSampleRate;
applyConfiguration(); applyConfiguration();
cmd->completed();
if(m_sampleSink != NULL) delete cmd;
if (m_sampleSink != NULL)
{ {
signal = DSPSignalNotification::create(m_currentOutputSampleRate, m_currentCenterFrequency); DSPSignalNotification notif(m_currentOutputSampleRate, m_currentCenterFrequency);
if(!m_sampleSink->handleMessage(signal)) { m_sampleSink->handleMessage(notif))
signal->completed();
}
} }
emit inputSampleRateChanged(); emit inputSampleRateChanged();
return true; return true;
} }
else if (DSPConfigureChannelizer::match(cmd)) else*/
if (DSPConfigureChannelizer::match(&cmd))
{ {
DSPConfigureChannelizer* chan = (DSPConfigureChannelizer*)cmd; DSPConfigureChannelizer* chan = (DSPConfigureChannelizer*) &cmd;
m_requestedOutputSampleRate = chan->getSampleRate(); m_requestedOutputSampleRate = chan->getSampleRate();
m_requestedCenterFrequency = chan->getCenterFrequency(); m_requestedCenterFrequency = chan->getCenterFrequency();
qDebug() << "Channelizer::handleMessage: DSPConfigureChannelizer:" qDebug() << "Channelizer::handleMessage: DSPConfigureChannelizer:"
<< " m_requestedOutputSampleRate: " << m_requestedOutputSampleRate << " m_requestedOutputSampleRate: " << m_requestedOutputSampleRate
<< " m_requestedCenterFrequency: " << m_requestedCenterFrequency; << " m_requestedCenterFrequency: " << m_requestedCenterFrequency;
applyConfiguration(); applyConfiguration();
cmd->completed();
if(m_sampleSink != NULL) if (m_sampleSink != NULL)
{ {
DSPSignalNotification* signal = DSPSignalNotification::create(m_currentOutputSampleRate, m_currentCenterFrequency); DSPSignalNotification notif(m_currentOutputSampleRate, m_currentCenterFrequency);
if(!m_sampleSink->handleMessage(signal)) { m_sampleSink->handleMessage(notif);
signal->completed();
}
} }
return true; return true;
} }
else else
{ {
if(m_sampleSink != NULL) { if (m_sampleSink != NULL)
{
return m_sampleSink->handleMessage(cmd); return m_sampleSink->handleMessage(cmd);
} else { }
else
{
return false; return false;
} }
} }

View File

@ -58,6 +58,7 @@ void DSPEngine::run()
qDebug() << "DSPEngine::run"; qDebug() << "DSPEngine::run";
connect(&m_inputMessageQueue, SIGNAL(messageEnqueued()), this, SLOT(handleInputMessages()), Qt::QueuedConnection); connect(&m_inputMessageQueue, SIGNAL(messageEnqueued()), this, SLOT(handleInputMessages()), Qt::QueuedConnection);
connect(&m_syncMessenger, SIGNAL(messageSent(Message*)), this, SLOT(handleSynchronousMessages(Message*)), Qt::QueuedConnection);
m_state = StIdle; m_state = StIdle;
@ -70,34 +71,34 @@ void DSPEngine::start()
qDebug() << "DSPEngine::start"; qDebug() << "DSPEngine::start";
DSPPing cmd; DSPPing cmd;
QThread::start(); QThread::start();
cmd.execute(&m_inputMessageQueue); m_syncMessenger.sendWait(&cmd);
} }
void DSPEngine::stop() void DSPEngine::stop()
{ {
qDebug() << "DSPEngine::stop"; qDebug() << "DSPEngine::stop";
DSPExit cmd; DSPExit cmd;
cmd.execute(&m_inputMessageQueue); m_syncMessenger.sendWait(&cmd);
} }
bool DSPEngine::initAcquisition() bool DSPEngine::initAcquisition()
{ {
DSPAcquisitionInit cmd; DSPAcquisitionInit cmd;
return cmd.execute(&m_inputMessageQueue) == StReady; return m_syncMessenger.sendWait(&cmd) == StReady;
} }
bool DSPEngine::startAcquisition() bool DSPEngine::startAcquisition()
{ {
DSPAcquisitionStart cmd; DSPAcquisitionStart cmd;
return cmd.execute(&m_inputMessageQueue) == StRunning; return m_syncMessenger.sendWait(&cmd) == StRunning;
} }
void DSPEngine::stopAcquistion() void DSPEngine::stopAcquistion()
{ {
DSPAcquisitionStop cmd; DSPAcquisitionStop cmd;
cmd.execute(&m_inputMessageQueue); m_syncMessenger.sendWait(&cmd);
if(m_dcOffsetCorrection) if(m_dcOffsetCorrection)
{ {
@ -108,51 +109,51 @@ void DSPEngine::stopAcquistion()
void DSPEngine::setSource(SampleSource* source) void DSPEngine::setSource(SampleSource* source)
{ {
DSPSetSource cmd(source); DSPSetSource cmd(source);
cmd.execute(&m_inputMessageQueue); m_syncMessenger.sendWait(&cmd);
} }
void DSPEngine::addSink(SampleSink* sink) void DSPEngine::addSink(SampleSink* sink)
{ {
qDebug() << "DSPEngine::addSink: " << sink->objectName().toStdString().c_str(); qDebug() << "DSPEngine::addSink: " << sink->objectName().toStdString().c_str();
DSPAddSink cmd(sink); DSPAddSink cmd(sink);
cmd.execute(&m_inputMessageQueue); m_syncMessenger.sendWait(&cmd);
} }
void DSPEngine::removeSink(SampleSink* sink) void DSPEngine::removeSink(SampleSink* sink)
{ {
DSPRemoveSink cmd(sink); DSPRemoveSink cmd(sink);
cmd.execute(&m_inputMessageQueue); m_syncMessenger.sendWait(&cmd);
} }
void DSPEngine::addAudioSink(AudioFifo* audioFifo) void DSPEngine::addAudioSink(AudioFifo* audioFifo)
{ {
DSPAddAudioSink cmd(audioFifo); DSPAddAudioSink cmd(audioFifo);
cmd.execute(&m_inputMessageQueue); m_syncMessenger.sendWait(&cmd);
} }
void DSPEngine::removeAudioSink(AudioFifo* audioFifo) void DSPEngine::removeAudioSink(AudioFifo* audioFifo)
{ {
DSPRemoveAudioSink cmd(audioFifo); DSPRemoveAudioSink cmd(audioFifo);
cmd.execute(&m_inputMessageQueue); m_syncMessenger.sendWait(&cmd);
} }
void DSPEngine::configureCorrections(bool dcOffsetCorrection, bool iqImbalanceCorrection) void DSPEngine::configureCorrections(bool dcOffsetCorrection, bool iqImbalanceCorrection)
{ {
Message* cmd = DSPConfigureCorrection::create(dcOffsetCorrection, iqImbalanceCorrection); DSPConfigureCorrection* cmd = new DSPConfigureCorrection(dcOffsetCorrection, iqImbalanceCorrection);
cmd->submit(&m_inputMessageQueue); m_inputMessageQueue.push(cmd);
} }
QString DSPEngine::errorMessage() QString DSPEngine::errorMessage()
{ {
DSPGetErrorMessage cmd; DSPGetErrorMessage cmd;
cmd.execute(&m_inputMessageQueue); m_syncMessenger.sendWait(&cmd);
return cmd.getErrorMessage(); return cmd.getErrorMessage();
} }
QString DSPEngine::sourceDeviceDescription() QString DSPEngine::sourceDeviceDescription()
{ {
DSPGetSourceDeviceDescription cmd; DSPGetSourceDeviceDescription cmd;
cmd.execute(&m_inputMessageQueue); m_syncMessenger.sendWait(&cmd);
return cmd.getDeviceDescription(); return cmd.getDeviceDescription();
} }
@ -229,17 +230,17 @@ void DSPEngine::imbalance(SampleVector::iterator begin, SampleVector::iterator e
void DSPEngine::work() void DSPEngine::work()
{ {
SampleFifo* sampleFifo = m_sampleSource->getSampleFifo(); SampleFifo* sampleFifo = m_sampleSource->getSampleFifo();
size_t samplesDone = 0; std::size_t samplesDone = 0;
bool positiveOnly = false; bool positiveOnly = false;
while ((sampleFifo->fill() > 0) && (m_inputMessageQueue.countPending() == 0) && (samplesDone < m_sampleRate)) while ((sampleFifo->fill() > 0) && (m_inputMessageQueue.size() == 0) && (samplesDone < m_sampleRate))
{ {
SampleVector::iterator part1begin; SampleVector::iterator part1begin;
SampleVector::iterator part1end; SampleVector::iterator part1end;
SampleVector::iterator part2begin; SampleVector::iterator part2begin;
SampleVector::iterator part2end; SampleVector::iterator part2end;
size_t count = sampleFifo->readBegin(sampleFifo->fill(), &part1begin, &part1end, &part2begin, &part2end); std::size_t count = sampleFifo->readBegin(sampleFifo->fill(), &part1begin, &part1end, &part2begin, &part2end);
// first part of FIFO data // first part of FIFO data
if (part1begin != part1end) if (part1begin != part1end)
@ -278,7 +279,7 @@ void DSPEngine::work()
} }
// adjust FIFO pointers // adjust FIFO pointers
sampleFifo->readCommit(count); sampleFifo->readCommit((unsigned int) count);
samplesDone += count; samplesDone += count;
} }
} }
@ -314,7 +315,7 @@ DSPEngine::State DSPEngine::gotoIdle()
(*it)->stop(); (*it)->stop();
} }
m_sampleSource->stopInput(); m_sampleSource->stop();
m_deviceDescription.clear(); m_deviceDescription.clear();
m_audioSink.stop(); m_audioSink.stop();
m_sampleRate = 0; m_sampleRate = 0;
@ -362,14 +363,14 @@ DSPEngine::State DSPEngine::gotoInit()
for(SampleSinks::const_iterator it = m_sampleSinks.begin(); it != m_sampleSinks.end(); it++) for(SampleSinks::const_iterator it = m_sampleSinks.begin(); it != m_sampleSinks.end(); it++)
{ {
qDebug() << " - initializing " << (*it)->objectName().toStdString().c_str(); qDebug() << " - initializing " << (*it)->objectName().toStdString().c_str();
DSPSignalNotification* notif = DSPSignalNotification::create(m_sampleRate, m_centerFrequency); DSPSignalNotification notif(m_sampleRate, m_centerFrequency);
(*it)->init(notif); (*it)->init(notif);
} }
// pass sample rate to main window // pass sample rate to main window
Message* rep = DSPEngineReport::create(m_sampleRate, m_centerFrequency); DSPEngineReport* rep = new DSPEngineReport(m_sampleRate, m_centerFrequency);
rep->submit(&m_outputMessageQueue); m_outputMessageQueue.push(rep);
return StReady; return StReady;
} }
@ -402,7 +403,7 @@ DSPEngine::State DSPEngine::gotoRunning()
// Start everything // Start everything
if(!m_sampleSource->startInput(0)) if(!m_sampleSource->start(0))
{ {
return gotoError("Could not start sample source"); return gotoError("Could not start sample source");
} }
@ -415,7 +416,7 @@ DSPEngine::State DSPEngine::gotoRunning()
(*it)->start(); (*it)->start();
} }
qDebug() << " - input message queue pending: " << m_inputMessageQueue.countPending(); qDebug() << " - input message queue pending: " << m_inputMessageQueue.size();
return StRunning; return StRunning;
} }
@ -448,33 +449,6 @@ void DSPEngine::handleSetSource(SampleSource* source)
} }
} }
bool DSPEngine::distributeMessage(Message* message)
{
if (m_sampleSource != 0)
{
if ((message->getDestination() == 0) || (message->getDestination() == m_sampleSource))
{
if (m_sampleSource->handleMessage(message))
{
return true;
}
}
}
for (SampleSinks::const_iterator it = m_sampleSinks.begin(); it != m_sampleSinks.end(); it++)
{
if ((message->getDestination() == NULL) || (message->getDestination() == *it))
{
if ((*it)->handleMessage(message))
{
return true;
}
}
}
return false;
}
void DSPEngine::handleData() void DSPEngine::handleData()
{ {
if(m_state == StRunning) if(m_state == StRunning)
@ -483,90 +457,92 @@ void DSPEngine::handleData()
} }
} }
void DSPEngine::handleSynchronousMessages(Message *message)
{
if (DSPExit::match(message))
{
gotoIdle();
m_state = StNotStarted;
exit();
m_syncMessenger.done(m_state);
}
else if (DSPAcquisitionInit::match(message))
{
m_state = gotoIdle();
if(m_state == StIdle) {
m_state = gotoInit(); // State goes ready if init is performed
}
m_syncMessenger.done(m_state);
}
else if (DSPAcquisitionStart::match(message))
{
if(m_state == StReady) {
m_state = gotoRunning();
}
m_syncMessenger.done(m_state);
}
else if (DSPAcquisitionStop::match(message))
{
m_state = gotoIdle();
m_syncMessenger.done(m_state);
}
else if (DSPGetSourceDeviceDescription::match(message))
{
((DSPGetSourceDeviceDescription*)message)->setDeviceDescription(m_deviceDescription);
m_syncMessenger.done(m_state);
}
else if (DSPGetErrorMessage::match(message))
{
((DSPGetErrorMessage*)message)->setErrorMessage(m_errorMessage);
m_syncMessenger.done(m_state);
}
else if (DSPSetSource::match(message)) {
handleSetSource(((DSPSetSource*)message)->getSampleSource());
m_syncMessenger.done(m_state);
}
else if (DSPAddSink::match(message))
{
SampleSink* sink = ((DSPAddSink*)message)->getSampleSink();
m_sampleSinks.push_back(sink);
m_syncMessenger.done(m_state);
}
else if (DSPRemoveSink::match(message))
{
SampleSink* sink = ((DSPRemoveSink*)message)->getSampleSink();
if(m_state == StRunning) {
sink->stop();
}
m_sampleSinks.remove(sink);
m_syncMessenger.done(m_state);
}
else if (DSPAddAudioSink::match(message))
{
m_audioSink.addFifo(((DSPAddAudioSink*)message)->getAudioFifo());
m_syncMessenger.done(m_state);
}
else if (DSPRemoveAudioSink::match(message))
{
m_audioSink.removeFifo(((DSPRemoveAudioSink*)message)->getAudioFifo());
m_syncMessenger.done(m_state);
}
m_syncMessenger.done(m_state);
}
void DSPEngine::handleInputMessages() void DSPEngine::handleInputMessages()
{ {
Message* message; Message* message;
while ((message = m_inputMessageQueue.accept()) != NULL) while ((message = m_inputMessageQueue.pop()) != 0)
{ {
qDebug("DSPEngine::handleInputMessages: Message: %s", message->getIdentifier()); qDebug("DSPEngine::handleInputMessages: Message: %s", message->getIdentifier());
if (DSPPing::match(message)) if (DSPConfigureCorrection::match(message))
{
message->completed(m_state);
}
else if (DSPExit::match(message))
{
gotoIdle();
m_state = StNotStarted;
exit();
message->completed(m_state);
}
else if (DSPAcquisitionInit::match(message))
{
m_state = gotoIdle();
if(m_state == StIdle) {
m_state = gotoInit(); // State goes ready if init is performed
}
message->completed(m_state);
}
else if (DSPAcquisitionStart::match(message))
{
if(m_state == StReady) {
m_state = gotoRunning();
}
message->completed(m_state);
}
else if (DSPAcquisitionStop::match(message))
{
m_state = gotoIdle();
message->completed(m_state);
}
else if (DSPGetSourceDeviceDescription::match(message))
{
((DSPGetSourceDeviceDescription*)message)->setDeviceDescription(m_deviceDescription);
message->completed();
}
else if (DSPGetErrorMessage::match(message))
{
((DSPGetErrorMessage*)message)->setErrorMessage(m_errorMessage);
message->completed();
}
else if (DSPSetSource::match(message)) {
handleSetSource(((DSPSetSource*)message)->getSampleSource());
message->completed();
}
else if (DSPAddSink::match(message))
{
SampleSink* sink = ((DSPAddSink*)message)->getSampleSink();
m_sampleSinks.push_back(sink);
message->completed();
}
else if (DSPRemoveSink::match(message))
{
SampleSink* sink = ((DSPAddSink*)message)->getSampleSink();
if(m_state == StRunning) {
sink->stop();
}
m_sampleSinks.remove(sink);
message->completed();
}
else if (DSPAddAudioSink::match(message))
{
m_audioSink.addFifo(((DSPAddAudioSink*)message)->getAudioFifo());
message->completed();
}
else if (DSPRemoveAudioSink::match(message))
{
m_audioSink.removeFifo(((DSPAddAudioSink*)message)->getAudioFifo());
message->completed();
}
else if (DSPConfigureCorrection::match(message))
{ {
DSPConfigureCorrection* conf = (DSPConfigureCorrection*)message; DSPConfigureCorrection* conf = (DSPConfigureCorrection*)message;
m_iqImbalanceCorrection = conf->getIQImbalanceCorrection(); m_iqImbalanceCorrection = conf->getIQImbalanceCorrection();
@ -585,20 +561,8 @@ void DSPEngine::handleInputMessages()
m_qRange = 1 << 16; m_qRange = 1 << 16;
m_imbalance = 65536; m_imbalance = 65536;
} }
}
message->completed(); delete message;
}
else
{
if (DSPSignalNotification::match(message))
{
DSPSignalNotification *conf = (DSPSignalNotification*)message;
qDebug() << " (" << conf->getSampleRate() << "," << conf->getFrequencyOffset() << ")";
}
if (!distributeMessage(message))
{
message->completed();
}
}
} }
} }

View File

@ -1,4 +1,5 @@
#include "dsp/filesink.h" #include "dsp/filesink.h"
#include "dsp/dspcommands.h"
#include "util/simpleserializer.h" #include "util/simpleserializer.h"
#include "util/messagequeue.h" #include "util/messagequeue.h"
@ -23,23 +24,26 @@ FileSink::~FileSink()
stopRecording(); stopRecording();
} }
void FileSink::configure(MessageQueue* msgQueue, const std::string& filename, int sampleRate, quint64 centerFrequency) void FileSink::configure(MessageQueue* msgQueue, const std::string& filename)
{ {
Message* cmd = MsgConfigureFileSink::create(filename, sampleRate, centerFrequency); Message* cmd = MsgConfigureFileSink::create(filename);
cmd->submit(msgQueue, this); msgQueue->push(cmd);
} }
bool FileSink::init(Message* cmd) bool FileSink::init(const Message& cmd)
{ {
if (DSPSignalNotification::match(cmd)) if (DSPSignalNotification::match(&cmd))
{ {
DSPSignalNotification* notif = (DSPSignalNotification*) cmd; DSPSignalNotification* notif = (DSPSignalNotification*) &cmd;
m_sampleRate = notif->getSampleRate(); m_sampleRate = notif->getSampleRate();
m_centerFrequency = notif->getFrequencyOffset(); m_centerFrequency = notif->getFrequencyOffset();
qDebug() << "FileSink::init: DSPSignalNotification: m_inputSampleRate: " << m_sampleRate; qDebug() << "FileSink::init: DSPSignalNotification: m_inputSampleRate: " << m_sampleRate;
cmd->completed();
return true; return true;
} }
else
{
return false;
}
} }
void FileSink::feed(SampleVector::const_iterator begin, SampleVector::const_iterator end, bool positiveOnly) void FileSink::feed(SampleVector::const_iterator begin, SampleVector::const_iterator end, bool positiveOnly)
@ -93,17 +97,14 @@ void FileSink::stopRecording()
} }
} }
bool FileSink::handleMessage(Message* message) bool FileSink::handleMessage(const Message& message)
{ {
if (MsgConfigureFileSink::match(message)) if (MsgConfigureFileSink::match(&message))
{ {
MsgConfigureFileSink* conf = (MsgConfigureFileSink*) message; MsgConfigureFileSink* conf = (MsgConfigureFileSink*) &message;
handleConfigure(conf->getFileName(), conf->getSampleRate(), conf->getCenterFrequency()); handleConfigure(conf->getFileName());
qDebug() << "FileSink::handleMessage:" qDebug() << "FileSink::handleMessage:"
<< " fileName: " << m_fileName.c_str() << " fileName: " << m_fileName.c_str();
<< " sampleRate: " << m_sampleRate
<< " centerFrequency: " << m_centerFrequency;
message->completed();
return true; return true;
} }
else else
@ -112,16 +113,14 @@ bool FileSink::handleMessage(Message* message)
} }
} }
void FileSink::handleConfigure(const std::string& fileName, int sampleRate, quint64 centerFrequency) void FileSink::handleConfigure(const std::string& fileName)
{ {
if ((fileName != m_fileName) || (m_sampleRate != sampleRate) || (m_centerFrequency != centerFrequency)) if (fileName != m_fileName)
{ {
stopRecording(); stopRecording();
} }
m_fileName = fileName; m_fileName = fileName;
m_sampleRate = sampleRate;
m_centerFrequency = centerFrequency;
} }
void FileSink::writeHeader() void FileSink::writeHeader()

View File

@ -7,6 +7,15 @@ NullSink::NullSink()
setObjectName("NullSink"); setObjectName("NullSink");
} }
NullSink::~NullSink()
{
}
bool NullSink::init(const Message& message)
{
return false;
}
void NullSink::feed(SampleVector::const_iterator begin, SampleVector::const_iterator end, bool positiveOnly) void NullSink::feed(SampleVector::const_iterator begin, SampleVector::const_iterator end, bool positiveOnly)
{ {
} }
@ -19,8 +28,7 @@ void NullSink::stop()
{ {
} }
bool NullSink::handleMessage(Message* message) bool NullSink::handleMessage(const Message& message)
{ {
message->completed(); return false;
return true;
} }

View File

@ -7,65 +7,3 @@ SampleSink::SampleSink()
SampleSink::~SampleSink() SampleSink::~SampleSink()
{ {
} }
bool SampleSink::executeMessage(Message *cmd)
{
return handleMessage(cmd);
}
#if 0
#include "samplesink.h"
SampleSink::SampleSink() :
m_sinkBuffer(),
m_sinkBufferFill(0)
{
}
void SampleSink::feed(SampleVector::const_iterator begin, SampleVector::const_iterator end)
{
size_t wus = workUnitSize();
// make sure our buffer is big enough for at least one work unit
if(m_sinkBuffer.size() < wus)
m_sinkBuffer.resize(wus);
while(begin < end) {
// if the buffer contains something, keep filling it until it contains one complete work unit
if((m_sinkBufferFill > 0) && (m_sinkBufferFill < wus)) {
// check number if missing samples, but don't copy more than we have
size_t len = wus - m_sinkBufferFill;
if(len > (size_t)(end - begin))
len = end - begin;
// copy
std::copy(begin, begin + len, m_sinkBuffer.begin() + m_sinkBufferFill);
// adjust pointers
m_sinkBufferFill += len;
begin += len;
}
// if one complete work unit is in the buffer, feed it to the worker
if(m_sinkBufferFill >= wus) {
size_t done = 0;
while(m_sinkBufferFill - done >= wus)
done += work(m_sinkBuffer.begin() + done, m_sinkBuffer.begin() + done + wus);
// now copy the remaining data to the front of the buffer (should be zero)
if(m_sinkBufferFill - done > 0) {
qDebug("error in SampleSink buffer management");
std::copy(m_sinkBuffer.begin() + done, m_sinkBuffer.begin() + m_sinkBufferFill, m_sinkBuffer.begin());
}
m_sinkBufferFill -= done;
}
// if no remainder from last run is buffered and we have at least one work unit left, feed the data to the worker
if(m_sinkBufferFill == 0) {
while((size_t)(end - begin) > wus)
begin += work(begin, begin + wus);
// copy any remaining data to the buffer
std::copy(begin, end, m_sinkBuffer.begin());
m_sinkBufferFill = end - begin;
begin += m_sinkBufferFill;
}
}
}
#endif

View File

@ -32,6 +32,10 @@ ScopeVis::ScopeVis(GLScope* glScope) :
m_traceback.resize(20*m_traceChunkSize); m_traceback.resize(20*m_traceChunkSize);
} }
ScopeVis::~ScopeVis()
{
}
void ScopeVis::configure(MessageQueue* msgQueue, void ScopeVis::configure(MessageQueue* msgQueue,
TriggerChannel triggerChannel, TriggerChannel triggerChannel,
Real triggerLevel, Real triggerLevel,
@ -48,7 +52,21 @@ void ScopeVis::configure(MessageQueue* msgQueue,
triggerPre, triggerPre,
triggerDelay, triggerDelay,
traceSize); traceSize);
cmd->submit(msgQueue, this); msgQueue->push(cmd);
}
bool ScopeVis::init(const Message& cmd)
{
if (DSPSignalNotification::match(&cmd))
{
DSPSignalNotification* signal = (DSPSignalNotification*) &cmd;
m_sampleRate = signal->getSampleRate();
return true;
}
else
{
return false;
}
} }
void ScopeVis::feed(SampleVector::const_iterator begin, SampleVector::const_iterator end, bool positiveOnly) void ScopeVis::feed(SampleVector::const_iterator begin, SampleVector::const_iterator end, bool positiveOnly)
@ -200,18 +218,11 @@ void ScopeVis::stop()
{ {
} }
bool ScopeVis::handleMessageKeep(Message* message) bool ScopeVis::handleMessage(const Message& message)
{ {
if(DSPSignalNotification::match(message)) { if (MsgConfigureScopeVis::match(&message))
DSPSignalNotification* signal = (DSPSignalNotification*)message; {
m_sampleRate = signal->getSampleRate(); MsgConfigureScopeVis* conf = (MsgConfigureScopeVis*) &message;
/*fprintf(stderr, "ScopeVis::handleMessage : %d samples/sec, %lld Hz offset, traceSize: \n",
m_sampleRate,
signal->getFrequencyOffset(),
m_trace.size());*/
return true;
} else if(MsgConfigureScopeVis::match(message)) {
MsgConfigureScopeVis* conf = (MsgConfigureScopeVis*)message;
m_tracebackCount = 0; m_tracebackCount = 0;
m_triggerState = Config; m_triggerState = Config;
m_triggerChannel = (TriggerChannel) conf->getTriggerChannel(); m_triggerChannel = (TriggerChannel) conf->getTriggerChannel();
@ -230,7 +241,7 @@ bool ScopeVis::handleMessageKeep(Message* message)
if (newSize > m_traceback.size()) { // fitting the exact required space is not a requirement for the back trace if (newSize > m_traceback.size()) { // fitting the exact required space is not a requirement for the back trace
m_traceback.resize(newSize); m_traceback.resize(newSize);
} }
qDebug() << "ScopeVis::handleMessageKeep:" qDebug() << "ScopeVis::handleMessage:"
<< " m_triggerChannel: " << m_triggerChannel << " m_triggerChannel: " << m_triggerChannel
<< " m_triggerLevel: " << m_triggerLevel << " m_triggerLevel: " << m_triggerLevel
<< " m_triggerPositiveEdge: " << (m_triggerPositiveEdge ? "edge+" : "edge-") << " m_triggerPositiveEdge: " << (m_triggerPositiveEdge ? "edge+" : "edge-")
@ -239,31 +250,13 @@ bool ScopeVis::handleMessageKeep(Message* message)
<< " m_triggerDelay: " << m_triggerDelay << " m_triggerDelay: " << m_triggerDelay
<< " m_traceSize: " << m_trace.size(); << " m_traceSize: " << m_trace.size();
return true; return true;
/* }
} else if(DSPConfigureScopeVis::match(message)) { else
DSPConfigureScopeVis* conf = (DSPConfigureScopeVis*)message; {
m_triggerState = Untriggered;
m_triggerChannel = (TriggerChannel)conf->getTriggerChannel();
m_triggerLevelHigh = conf->getTriggerLevelHigh() * 32767;
m_triggerLevelLow = conf->getTriggerLevelLow() * 32767;
return true;*/
} else {
return false; return false;
} }
} }
bool ScopeVis::handleMessage(Message* message)
{
bool done = handleMessageKeep(message);
if (done)
{
message->completed();
}
return done;
}
void ScopeVis::setSampleRate(int sampleRate) void ScopeVis::setSampleRate(int sampleRate)
{ {
m_sampleRate = sampleRate; m_sampleRate = sampleRate;

View File

@ -9,6 +9,18 @@ SpectrumScopeComboVis::SpectrumScopeComboVis(SpectrumVis* spectrumVis, ScopeVis*
setObjectName("SpectrumScopeComboVis"); setObjectName("SpectrumScopeComboVis");
} }
SpectrumScopeComboVis::~SpectrumScopeComboVis()
{
}
bool SpectrumScopeComboVis::init(const Message& cmd)
{
bool spectDone = m_spectrumVis->init(cmd);
bool scopeDone = m_scopeVis->init(cmd);
return (spectDone || scopeDone);
}
void SpectrumScopeComboVis::feed(SampleVector::const_iterator begin, SampleVector::const_iterator end, bool positiveOnly) void SpectrumScopeComboVis::feed(SampleVector::const_iterator begin, SampleVector::const_iterator end, bool positiveOnly)
{ {
m_scopeVis->feed(begin, end, false); m_scopeVis->feed(begin, end, false);
@ -28,15 +40,10 @@ void SpectrumScopeComboVis::stop()
m_scopeVis->stop(); m_scopeVis->stop();
} }
bool SpectrumScopeComboVis::handleMessage(Message* message) bool SpectrumScopeComboVis::handleMessage(const Message& message)
{ {
bool spectDone = m_spectrumVis->handleMessageKeep(message); bool spectDone = m_spectrumVis->handleMessage(message);
bool scopeDone = m_scopeVis->handleMessageKeep(message); bool scopeDone = m_scopeVis->handleMessage(message);
if (spectDone || scopeDone)
{
message->completed();
}
return (spectDone || scopeDone); return (spectDone || scopeDone);
} }

View File

@ -30,10 +30,15 @@ SpectrumVis::~SpectrumVis()
delete m_fft; delete m_fft;
} }
bool SpectrumVis::init(const Message& cmd)
{
return false;
}
void SpectrumVis::configure(MessageQueue* msgQueue, int fftSize, int overlapPercent, FFTWindow::Function window) void SpectrumVis::configure(MessageQueue* msgQueue, int fftSize, int overlapPercent, FFTWindow::Function window)
{ {
Message* cmd = DSPConfigureSpectrumVis::create(fftSize, overlapPercent, window); DSPConfigureSpectrumVis* cmd = new DSPConfigureSpectrumVis(fftSize, overlapPercent, window);
cmd->submit(msgQueue, this); msgQueue->push(cmd);
} }
void SpectrumVis::feedTriggered(SampleVector::const_iterator triggerPoint, SampleVector::const_iterator begin, SampleVector::const_iterator end, bool positiveOnly) void SpectrumVis::feedTriggered(SampleVector::const_iterator triggerPoint, SampleVector::const_iterator begin, SampleVector::const_iterator end, bool positiveOnly)
@ -136,39 +141,39 @@ void SpectrumVis::stop()
{ {
} }
bool SpectrumVis::handleMessageKeep(Message* message) bool SpectrumVis::handleMessage(const Message& message)
{ {
if(DSPConfigureSpectrumVis::match(message)) { if(DSPConfigureSpectrumVis::match(&message))
DSPConfigureSpectrumVis* conf = (DSPConfigureSpectrumVis*)message; {
DSPConfigureSpectrumVis* conf = (DSPConfigureSpectrumVis*) &message;
handleConfigure(conf->getFFTSize(), conf->getOverlapPercent(), conf->getWindow()); handleConfigure(conf->getFFTSize(), conf->getOverlapPercent(), conf->getWindow());
return true; return true;
} else { }
else
{
return false; return false;
} }
} }
bool SpectrumVis::handleMessage(Message* message)
{
bool done = handleMessageKeep(message);
if (done)
{
message->completed();
}
return done;
}
void SpectrumVis::handleConfigure(int fftSize, int overlapPercent, FFTWindow::Function window) void SpectrumVis::handleConfigure(int fftSize, int overlapPercent, FFTWindow::Function window)
{ {
if(fftSize > MAX_FFT_SIZE) if (fftSize > MAX_FFT_SIZE)
{
fftSize = MAX_FFT_SIZE; fftSize = MAX_FFT_SIZE;
else if(fftSize < 64) }
else if (fftSize < 64)
{
fftSize = 64; fftSize = 64;
if(overlapPercent > 100) }
if (overlapPercent > 100)
{
m_overlapPercent = 100; m_overlapPercent = 100;
else if(overlapPercent < 0) }
else if (overlapPercent < 0)
{
m_overlapPercent = 0; m_overlapPercent = 0;
}
m_fftSize = fftSize; m_fftSize = fftSize;
m_overlapPercent = overlapPercent; m_overlapPercent = overlapPercent;

View File

@ -319,7 +319,7 @@ void MainWindow::handleDSPMessages()
{ {
Message* message; Message* message;
while ((message = m_dspEngine->getOutputMessageQueue()->accept()) != 0) while ((message = m_dspEngine->getOutputMessageQueue()->pop()) != 0)
{ {
qDebug("Message: %s", message->getIdentifier()); qDebug("Message: %s", message->getIdentifier());
@ -333,10 +333,11 @@ void MainWindow::handleDSPMessages()
qDebug("SampleRate:%d, CenterFrequency:%llu", rep->getSampleRate(), rep->getCenterFrequency()); qDebug("SampleRate:%d, CenterFrequency:%llu", rep->getSampleRate(), rep->getCenterFrequency());
updateCenterFreqDisplay(); updateCenterFreqDisplay();
updateSampleRate(); updateSampleRate();
message->completed();
qDebug() << "MainWindow::handleMessages: m_fileSink->configure"; qDebug() << "MainWindow::handleMessages: m_fileSink->configure";
m_fileSink->configure(m_fileSink->getMessageQueue(), m_sampleFileName, m_sampleRate, m_centerFrequency); m_fileSink->configure(m_fileSink->getInputMessageQueue(), m_sampleFileName);
} }
delete message;
} }
} }
@ -344,14 +345,14 @@ void MainWindow::handleMessages()
{ {
Message* message; Message* message;
while ((message = m_messageQueue->accept()) != 0) while ((message = m_messageQueue->pop()) != 0)
{ {
qDebug("Message: %s", message->getIdentifier()); qDebug("Message: %s", message->getIdentifier());
std::cerr << "MainWindow::handleMessages: " << message->getIdentifier() << std::endl; std::cerr << "MainWindow::handleMessages: " << message->getIdentifier() << std::endl;
if (!m_pluginManager->handleMessage(message)) { if (!m_pluginManager->handleMessage(message))
message->completed(); {
delete message;
} }
} }
} }

View File

@ -1,3 +1,20 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2015 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 <QWaitCondition> #include <QWaitCondition>
#include <QMutex> #include <QMutex>
#include "util/message.h" #include "util/message.h"
@ -6,20 +23,12 @@
const char* Message::m_identifier = "Message"; const char* Message::m_identifier = "Message";
Message::Message() : Message::Message() :
m_destination(NULL), m_destination(0)
m_synchronous(false),
m_waitCondition(NULL),
m_mutex(NULL),
m_complete(0)
{ {
} }
Message::~Message() Message::~Message()
{ {
if(m_waitCondition != NULL)
delete m_waitCondition;
if(m_mutex != NULL)
delete m_mutex;
} }
const char* Message::getIdentifier() const const char* Message::getIdentifier() const
@ -32,48 +41,7 @@ bool Message::matchIdentifier(const char* identifier) const
return m_identifier == identifier; return m_identifier == identifier;
} }
bool Message::match(Message* message) bool Message::match(const Message* message)
{ {
return message->matchIdentifier(m_identifier); return message->matchIdentifier(m_identifier);
} }
void Message::submit(MessageQueue* queue, void* destination)
{
m_destination = destination;
m_synchronous = false;
queue->submit(this);
}
int Message::execute(MessageQueue* queue, void* destination)
{
m_destination = destination;
m_synchronous = true;
if(m_waitCondition == NULL)
m_waitCondition = new QWaitCondition;
if(m_mutex == NULL)
m_mutex = new QMutex;
m_mutex->lock();
m_complete.testAndSetAcquire(0, 1);
queue->submit(this);
while(!m_complete.testAndSetAcquire(0, 1))
((QWaitCondition*)m_waitCondition)->wait(m_mutex, 100);
m_complete = 0;
int result = m_result;
m_mutex->unlock();
return result;
}
void Message::completed(int result)
{
if(m_synchronous) {
m_result = result;
m_complete = 0;
if(m_waitCondition == NULL)
qFatal("wait condition is NULL");
m_waitCondition->wakeAll();
} else {
delete this;
}
}

View File

@ -1,3 +1,20 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2015 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 "util/messagequeue.h" #include "util/messagequeue.h"
#include "util/message.h" #include "util/message.h"
@ -10,29 +27,44 @@ MessageQueue::MessageQueue(QObject* parent) :
MessageQueue::~MessageQueue() MessageQueue::~MessageQueue()
{ {
Message* cmd; Message* message;
while((cmd = accept()) != NULL)
cmd->completed(); while ((message = pop()) != 0)
{
delete message;
}
} }
void MessageQueue::submit(Message* message) void MessageQueue::push(Message* message, bool emitSignal)
{ {
m_lock.lock(); if (message)
m_queue.append(message); {
m_lock.unlock(); m_lock.lock();
emit messageEnqueued(); m_queue.append(message);
m_lock.unlock();
}
if (emitSignal)
{
emit messageEnqueued();
}
} }
Message* MessageQueue::accept() Message* MessageQueue::pop()
{ {
SpinlockHolder spinlockHolder(&m_lock); SpinlockHolder spinlockHolder(&m_lock);
if(m_queue.isEmpty()) if (m_queue.isEmpty())
return NULL; {
else return m_queue.takeFirst(); return 0;
}
else
{
return m_queue.takeFirst();
}
} }
int MessageQueue::countPending() int MessageQueue::size()
{ {
SpinlockHolder spinlockHolder(&m_lock); SpinlockHolder spinlockHolder(&m_lock);

View File

@ -0,0 +1,56 @@
///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2015 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 "util/syncmessenger.h"
#include "util/message.h"
SyncMessenger::SyncMessenger() :
m_complete(0),
m_result(0)
{}
SyncMessenger::~SyncMessenger()
{}
int SyncMessenger::sendWait(Message *message, unsigned long msPollTime)
{
m_mutex.lock();
m_complete.testAndSetAcquire(0, 1);
emit messageSent(message);
while (!m_complete.testAndSetAcquire(0, 1))
{
m_waitCondition.wait(&m_mutex, msPollTime);
}
m_complete = 0;
int result = m_result;
m_mutex.unlock();
return result;
}
void SyncMessenger::done(int result)
{
m_result = result;
m_complete = 0;
m_waitCondition.wakeAll();
}