Deep redesign: phase #4. Compiles

This commit is contained in:
f4exb 2015-08-17 08:29:34 +02:00
parent b5f2475fbf
commit a6a7145f3d
77 changed files with 1816 additions and 1429 deletions

View File

@ -129,9 +129,12 @@ Done since the fork
- Coarse and fine trigger level sliders
- Minimalist recording (no file choice)
- File sample source plugin (recording reader) not working
- Make the DSP engine global static
- Fixed startup initialization sequence. New initialization phase in DSP engine and new ready state
- Message queuing and handling redesign
- Redesign:
- Make the DSP engine global static
- Fixed startup initialization sequence. New initialization phase in DSP engine and new ready state
- Synchronous messaging class to push message to thread and wait for completion
- Message queuing and handling redesign
- Many other little things...
=====
To Do

View File

@ -17,10 +17,9 @@ public:
void configure(MessageQueue* messageQueue, int sampleRate, int centerFrequency);
int getInputSampleRate() const { return m_inputSampleRate; }
virtual bool init(const Message& cmd);
virtual void feed(SampleVector::const_iterator begin, SampleVector::const_iterator end, bool positiveOnly);
virtual void start();
virtual void stop();
virtual void feed(SampleVector::const_iterator begin, SampleVector::const_iterator end, bool positiveOnly);
virtual bool handleMessage(const Message& cmd);
protected:

View File

@ -105,6 +105,30 @@ private:
SampleSink* m_sampleSink;
};
class SDRANGELOVE_API DSPAddThreadedSink : public Message {
MESSAGE_CLASS_DECLARATION
public:
DSPAddThreadedSink(SampleSink* sampleSink) : Message(), m_sampleSink(sampleSink) { }
SampleSink* getSampleSink() const { return m_sampleSink; }
private:
SampleSink* m_sampleSink;
};
class SDRANGELOVE_API DSPRemoveThreadedSink : public Message {
MESSAGE_CLASS_DECLARATION
public:
DSPRemoveThreadedSink(SampleSink* sampleSink) : Message(), m_sampleSink(sampleSink) { }
SampleSink* getSampleSink() const { return m_sampleSink; }
private:
SampleSink* m_sampleSink;
};
class SDRANGELOVE_API DSPAddAudioSink : public Message {
MESSAGE_CLASS_DECLARATION

View File

@ -32,6 +32,7 @@
class SampleSource;
class SampleSink;
class ThreadedSampleSink;
class AudioFifo;
class SDRANGELOVE_API DSPEngine : public QThread {
@ -66,6 +67,9 @@ public:
void addSink(SampleSink* sink); //!< Add a sample sink
void removeSink(SampleSink* sink); //!< Remove a sample sink
void addThreadedSink(SampleSink* sink); //!< Add a sample sink that will run on its own thread
void removeThreadedSink(SampleSink* sink); //!< Remove a sample sink that runs on its own thread
void addAudioSink(AudioFifo* audioFifo); //!< Add the audio sink
void removeAudioSink(AudioFifo* audioFifo); //!< Remove the audio sink
@ -89,7 +93,10 @@ private:
SampleSource* m_sampleSource;
typedef std::list<SampleSink*> SampleSinks;
SampleSinks m_sampleSinks;
SampleSinks m_sampleSinks; //!< sample sinks within main thread (usually spectrum, file output)
typedef std::list<ThreadedSampleSink*> ThreadedSampleSinks;
ThreadedSampleSinks m_threadedSampleSinks; //!< sample sinks on their own threads (usually channels)
AudioOutput m_audioSink;
@ -120,7 +127,7 @@ private slots:
void handleData(); //!< Handle data when samples from source FIFO are ready to be processed
void handleSourceMessages(); //!< Handle source message output
void handleInputMessages(); //!< Handle input message queue
void handleSynchronousMessages(Message *message); //!< Handle synchronous messages with the thread
void handleSynchronousMessages(const Message& message); //!< Handle synchronous messages with the thread
};
#endif // INCLUDE_DSPENGINE_H

View File

@ -28,7 +28,6 @@ public:
void configure(MessageQueue* msgQueue, const std::string& filename);
virtual bool init(const Message& cmd);
virtual void feed(SampleVector::const_iterator begin, SampleVector::const_iterator end, bool positiveOnly);
virtual void start();
virtual void stop();

View File

@ -35,7 +35,6 @@ public:
uint traceSize);
void setOneShot(bool oneShot);
virtual bool init(const Message& cmd);
virtual void feed(SampleVector::const_iterator begin, SampleVector::const_iterator end, bool positiveOnly);
virtual void start();
virtual void stop();

View File

@ -14,7 +14,6 @@ public:
SpectrumScopeComboVis(SpectrumVis* spectrumVis, ScopeVis* scopeVis);
virtual ~SpectrumScopeComboVis();
virtual bool init(const Message& cmd);
virtual void feed(SampleVector::const_iterator begin, SampleVector::const_iterator end, bool positiveOnly);
virtual void start();
virtual void stop();

View File

@ -16,7 +16,6 @@ public:
void configure(MessageQueue* msgQueue, int fftSize, int overlapPercent, FFTWindow::Function window);
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);
virtual void start();

View File

@ -52,7 +52,7 @@ public:
void freeAll();
bool handleMessage(Message* message);
bool handleMessage(const Message& message);
void updateSampleSourceDevices();
void fillSampleSourceSelector(QComboBox* comboBox);

View File

@ -13,18 +13,18 @@ public:
SampleSink();
virtual ~SampleSink();
virtual bool init(const Message& cmd) = 0;
virtual void feed(SampleVector::const_iterator begin, SampleVector::const_iterator end, bool positiveOnly) = 0;
virtual void start() = 0;
virtual void stop() = 0;
virtual void feed(SampleVector::const_iterator begin, SampleVector::const_iterator end, bool positiveOnly) = 0;
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; }
MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; } //!< Get the queue for asynchronous inbound communication
MessageQueue *getOutputMessageQueue() { return &m_outputMessageQueue; } //!< Get the queue for asynchronous outbound communication
protected:
MessageQueue m_inputMessageQueue;
MessageQueue m_outputMessageQueue;
void handleInputMessages();
MessageQueue m_inputMessageQueue; //!< Queue for asynchronous inbound communication
MessageQueue m_outputMessageQueue; //!< Queue for asynchronous outbound communication
};
#endif // INCLUDE_SAMPLESINK_H

View File

@ -29,13 +29,13 @@ public:
SampleSource();
virtual ~SampleSource();
virtual void init(const Message& cmd) = 0;
virtual bool init(const Message& cmd) = 0;
virtual bool start(int device) = 0;
virtual void stop() = 0;
virtual const QString& getDeviceDescription() const = 0;
virtual int getSampleRate() const { return m_sampleRate; };
virtual quint64 getCenterFrequency() const { return m_centerFrequency; };
virtual int getSampleRate() const = 0; //!< Sample rate exposed by the source
virtual quint64 getCenterFrequency() const = 0; //!< Center frequency exposed by the source
virtual bool handleMessage(const Message& message) = 0;
@ -44,15 +44,9 @@ public:
SampleFifo* getSampleFifo() { return &m_sampleFifo; }
protected:
void setSampleRate(int sampleRate);
void setCenterFrequency(quint64 centerFrequency);
void sendNewData();
SampleFifo m_sampleFifo;
MessageQueue m_inputMessageQueue;
MessageQueue m_outputMessageQueue;
int m_sampleRate;
quint64 m_centerFrequency;
};
#endif // INCLUDE_SAMPLESOURCE_H

View File

@ -1,41 +1,62 @@
///////////////////////////////////////////////////////////////////////////////////
// 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_THREADEDSAMPLESINK_H
#define INCLUDE_THREADEDSAMPLESINK_H
#include <QMutex>
#include <QThread>
#include "samplesink.h"
#include "dsp/samplefifo.h"
#include "util/messagequeue.h"
#include "util/export.h"
#include "util/syncmessenger.h"
class QThread;
class SampleSink;
class SDRANGELOVE_API ThreadedSampleSink : public SampleSink {
/**
* This class is a wrapper for SampleSink that runs the SampleSink object in its own thread
*/
class SDRANGELOVE_API ThreadedSampleSink : public QThread {
Q_OBJECT
public:
ThreadedSampleSink(SampleSink* sampleSink);
virtual ~ThreadedSampleSink();
~ThreadedSampleSink();
MessageQueue* getMessageQueue() { return &m_messageQueue; }
const SampleSink *getSink() const { return m_sampleSink; }
MessageQueue* getInputMessageQueue() { return m_sampleSink->getInputMessageQueue(); } //!< Return pointer to sample sink's input message queue
MessageQueue* getOutputMessageQueue() { return m_sampleSink->getOutputMessageQueue(); } //!< Return pointer to sample sink's output message queue
void feed(SampleVector::const_iterator begin, SampleVector::const_iterator end, bool positiveOnly);
void start();
void stop();
bool handleMessage(Message* cmd);
void start(); //!< this thread start()
void stop(); //!< this thread exit() and wait()
bool sendWaitSink(const Message& cmd); //!< Send message to sink synchronously
void feed(SampleVector::const_iterator& begin, SampleVector::const_iterator& end, bool positiveOnly); //!< Feed sink with samples
QString getSampleSinkObjectName() const;
protected:
QMutex m_mutex;
QThread* m_thread;
MessageQueue m_messageQueue;
SampleFifo m_sampleFifo;
SyncMessenger m_syncMessenger; //!< Used to process messages synchronously with the thread
SampleSink* m_sampleSink;
protected slots:
void handleData();
void handleMessages();
void threadStarted();
void threadFinished();
private:
void run(); //!< this thread run() method
void handleSynchronousMessages(const Message& message); //!< Handle synchronous messages with the thread
};
#endif // INCLUDE_THREADEDSAMPLESINK_H

View File

@ -37,12 +37,14 @@ public:
void removeChannelMarker(ChannelMarker* channelMarker);
// DSPEngine access
/* Direct access with DSP engine singleton
void setSampleSource(SampleSource* sampleSource);
void addSampleSink(SampleSink* sampleSink);
void removeSampleSink(SampleSink* sampleSink);
MessageQueue* getDSPEngineMessageQueue();
void addAudioSource(AudioFifo* audioFifo);
void removeAudioSource(AudioFifo* audioFifo);
*/
// Sample Source stuff
void registerSampleSource(const QString& sourceName, PluginInterface* plugin);

View File

@ -9,6 +9,8 @@ class Message;
class SDRANGELOVE_API PluginGUI {
public:
PluginGUI() { };
virtual ~PluginGUI() { };
virtual void destroy() = 0;
virtual void setName(const QString& name) = 0;
@ -23,7 +25,7 @@ public:
virtual QByteArray serialize() const = 0;
virtual bool deserialize(const QByteArray& data) = 0;
virtual bool handleMessage(Message* message) = 0;
virtual bool handleMessage(const Message& message) = 0;
};
#endif // INCLUDE_PLUGINGUI_H

View File

@ -43,7 +43,7 @@ protected:
public: \
const char* getIdentifier() const; \
bool matchIdentifier(const char* identifier) const; \
static bool match(const Message* message); \
static bool match(const Message& message); \
protected: \
static const char* m_identifier; \
private:
@ -54,6 +54,6 @@ protected:
bool Name::matchIdentifier(const char* identifier) const {\
return (m_identifier == identifier) ? true : BaseClass::matchIdentifier(identifier); \
} \
bool Name::match(const Message* message) { return message->matchIdentifier(m_identifier); }
bool Name::match(const Message& message) { return message.matchIdentifier(m_identifier); }
#endif // INCLUDE_MESSAGE_H

View File

@ -36,11 +36,11 @@ public:
SyncMessenger();
~SyncMessenger();
int sendWait(Message *message, unsigned long msPollTime = 100); //!< Send message and waits for its process completion
int sendWait(const 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);
void messageSent(const Message& message);
protected:
QWaitCondition m_waitCondition;

View File

@ -17,6 +17,7 @@
#include "amdemod.h"
#include <QTime>
#include <QDebug>
#include <stdio.h>
#include <complex.h>
#include "audio/audiooutput.h"
@ -55,93 +56,53 @@ AMDemod::~AMDemod()
void AMDemod::configure(MessageQueue* messageQueue, Real rfBandwidth, Real afBandwidth, Real volume, Real squelch)
{
Message* cmd = MsgConfigureAMDemod::create(rfBandwidth, afBandwidth, volume, squelch);
cmd->submit(messageQueue, this);
messageQueue->push(cmd);
}
/*
float arctan2(Real y, Real x)
{
Real coeff_1 = M_PI / 4;
Real coeff_2 = 3 * coeff_1;
Real abs_y = fabs(y) + 1e-10; // kludge to prevent 0/0 condition
Real angle;
if( x>= 0) {
Real r = (x - abs_y) / (x + abs_y);
angle = coeff_1 - coeff_1 * r;
} else {
Real r = (x + abs_y) / (abs_y - x);
angle = coeff_2 - coeff_1 * r;
}
if(y < 0)
return(-angle);
else return(angle);
}
Real angleDist(Real a, Real b)
{
Real dist = b - a;
while(dist <= M_PI)
dist += 2 * M_PI;
while(dist >= M_PI)
dist -= 2 * M_PI;
return dist;
}
*/
void AMDemod::feed(SampleVector::const_iterator begin, SampleVector::const_iterator end, bool firstOfBurst)
{
Complex ci;
if(m_audioFifo->size() <= 0)
if (m_audioFifo->size() <= 0)
{
return;
}
for(SampleVector::const_iterator it = begin; it != end; ++it) {
for (SampleVector::const_iterator it = begin; it != end; ++it)
{
Complex c(it->real() / 32768.0, it->imag() / 32768.0);
c *= m_nco.nextIQ();
{
if(m_interpolator.interpolate(&m_interpolatorDistanceRemain, c, &ci)) {
if (m_interpolator.interpolate(&m_interpolatorDistanceRemain, c, &ci))
{
m_sampleBuffer.push_back(Sample(ci.real() * 32767.0, ci.imag() * 32767.0));
Real magsq = ci.real() * ci.real() + ci.imag() * ci.imag();
m_movingAverage.feed(magsq);
if(m_movingAverage.average() >= m_squelchLevel)
if (m_movingAverage.average() >= m_squelchLevel)
{
m_squelchState = m_running.m_audioSampleRate/ 20;
}
qint16 sample;
if(m_squelchState > 0) {
if (m_squelchState > 0)
{
m_squelchState--;
/*
Real argument = arg(ci);
Real demod = argument - m_lastArgument;
m_lastArgument = argument;
*/
/* NFM demod:
Complex d = conj(m_lastSample) * ci;
m_lastSample = ci;
Real demod = atan2(d.imag(), d.real());
//Real demod = arctan2(d.imag(), d.real());
*/
/*
Real argument1 = arg(ci);//atan2(ci.imag(), ci.real());
Real argument2 = m_lastSample.real();
Real demod = angleDist(argument2, argument1);
m_lastSample = Complex(argument1, 0);
*/
Real demod = sqrt(magsq);
//demod /= M_PI;
demod = m_lowpass.filter(demod);
if(demod < -1)
if (demod < -1)
{
demod = -1;
else if(demod > 1)
}
else if (demod > 1)
{
demod = 1;
}
m_volumeAGC.feed(demod);
@ -149,7 +110,9 @@ void AMDemod::feed(SampleVector::const_iterator begin, SampleVector::const_itera
demod *= m_running.m_volume;
sample = demod * 32700 * 16;
} else {
}
else
{
m_volumeAGC.close();
sample = 0;
}
@ -157,10 +120,16 @@ void AMDemod::feed(SampleVector::const_iterator begin, SampleVector::const_itera
m_audioBuffer[m_audioBufferFill].l = sample;
m_audioBuffer[m_audioBufferFill].r = sample;
++m_audioBufferFill;
if(m_audioBufferFill >= m_audioBuffer.size()) {
if (m_audioBufferFill >= m_audioBuffer.size())
{
uint res = m_audioFifo->write((const quint8*)&m_audioBuffer[0], m_audioBufferFill, 1);
if(res != m_audioBufferFill)
if (res != m_audioBufferFill)
{
qDebug("lost %u audio samples", m_audioBufferFill - res);
}
m_audioBufferFill = 0;
}
@ -168,15 +137,24 @@ void AMDemod::feed(SampleVector::const_iterator begin, SampleVector::const_itera
}
}
}
if(m_audioBufferFill > 0) {
if (m_audioBufferFill > 0)
{
uint res = m_audioFifo->write((const quint8*)&m_audioBuffer[0], m_audioBufferFill, 1);
if(res != m_audioBufferFill)
if (res != m_audioBufferFill)
{
qDebug("lost %u samples", m_audioBufferFill - res);
}
m_audioBufferFill = 0;
}
if(m_sampleSink != NULL)
if(m_sampleSink != 0)
{
m_sampleSink->feed(m_sampleBuffer.begin(), m_sampleBuffer.end(), false);
}
m_sampleBuffer.clear();
}
@ -194,28 +172,54 @@ void AMDemod::stop()
{
}
bool AMDemod::handleMessage(Message* cmd)
bool AMDemod::handleMessage(const Message& cmd)
{
if(DSPSignalNotification::match(cmd)) {
DSPSignalNotification* signal = (DSPSignalNotification*)cmd;
qDebug() << "AMDemod::handleMessage";
if (DSPSignalNotification::match(cmd))
{
DSPSignalNotification& notif = (DSPSignalNotification&) cmd;
m_config.m_inputSampleRate = notif.getSampleRate();
m_config.m_inputFrequencyOffset = notif.getFrequencyOffset();
m_config.m_inputSampleRate = signal->getSampleRate();
m_config.m_inputFrequencyOffset = signal->getFrequencyOffset();
apply();
cmd->completed();
qDebug() << " - DSPSignalNotification:"
<< " m_inputSampleRate: " << m_config.m_inputSampleRate
<< " m_inputFrequencyOffset: " << m_config.m_inputFrequencyOffset;
return true;
} else if(MsgConfigureAMDemod::match(cmd)) {
MsgConfigureAMDemod* cfg = (MsgConfigureAMDemod*)cmd;
m_config.m_rfBandwidth = cfg->getRFBandwidth();
m_config.m_afBandwidth = cfg->getAFBandwidth();
m_config.m_volume = cfg->getVolume();
m_config.m_squelch = cfg->getSquelch();
}
else if (MsgConfigureAMDemod::match(cmd))
{
MsgConfigureAMDemod& cfg = (MsgConfigureAMDemod&) cmd;
m_config.m_rfBandwidth = cfg.getRFBandwidth();
m_config.m_afBandwidth = cfg.getAFBandwidth();
m_config.m_volume = cfg.getVolume();
m_config.m_squelch = cfg.getSquelch();
apply();
qDebug() << " - MsgConfigureAMDemod:"
<< " m_rfBandwidth: " << m_config.m_rfBandwidth
<< " m_afBandwidth: " << m_config.m_afBandwidth
<< " m_volume: " << m_config.m_volume
<< " m_squelch: " << m_config.m_squelch;
return true;
} else {
if(m_sampleSink != NULL)
}
else
{
if(m_sampleSink != 0)
{
return m_sampleSink->handleMessage(cmd);
else return false;
}
else
{
return false;
}
}
}
@ -223,23 +227,27 @@ void AMDemod::apply()
{
if((m_config.m_inputFrequencyOffset != m_running.m_inputFrequencyOffset) ||
(m_config.m_inputSampleRate != m_running.m_inputSampleRate)) {
(m_config.m_inputSampleRate != m_running.m_inputSampleRate))
{
m_nco.setFreq(-m_config.m_inputFrequencyOffset, m_config.m_inputSampleRate);
}
if((m_config.m_inputSampleRate != m_running.m_inputSampleRate) ||
(m_config.m_rfBandwidth != m_running.m_rfBandwidth)) {
(m_config.m_rfBandwidth != m_running.m_rfBandwidth))
{
m_interpolator.create(16, m_config.m_inputSampleRate, m_config.m_rfBandwidth / 2.2);
m_interpolatorDistanceRemain = 0;
m_interpolatorDistance = (Real) m_config.m_inputSampleRate / (Real) m_config.m_audioSampleRate;
}
if((m_config.m_afBandwidth != m_running.m_afBandwidth) ||
(m_config.m_audioSampleRate != m_running.m_audioSampleRate)) {
(m_config.m_audioSampleRate != m_running.m_audioSampleRate))
{
m_lowpass.create(21, m_config.m_audioSampleRate, m_config.m_afBandwidth);
}
if(m_config.m_squelch != m_running.m_squelch) {
if(m_config.m_squelch != m_running.m_squelch)
{
m_squelchLevel = pow(10.0, m_config.m_squelch / 20.0);
m_squelchLevel *= m_squelchLevel;
}

View File

@ -36,10 +36,10 @@ public:
void configure(MessageQueue* messageQueue, Real rfBandwidth, Real afBandwidth, Real volume, Real squelch);
void feed(SampleVector::const_iterator begin, SampleVector::const_iterator end, bool po);
void start();
void stop();
bool handleMessage(Message* cmd);
virtual void feed(SampleVector::const_iterator begin, SampleVector::const_iterator end, bool po);
virtual void start();
virtual void stop();
virtual bool handleMessage(const Message& cmd);
private:
class MsgConfigureAMDemod : public Message {

View File

@ -5,11 +5,11 @@
#include "ui_amdemodgui.h"
#include "dsp/threadedsamplesink.h"
#include "dsp/channelizer.h"
#include "dsp/nullsink.h"
#include "gui/glspectrum.h"
#include "plugin/pluginapi.h"
#include "util/simpleserializer.h"
#include "gui/basicchannelsettingswidget.h"
#include "dsp/dspengine.h"
#include "amdemod.h"
@ -100,7 +100,7 @@ bool AMDemodGUI::deserialize(const QByteArray& data)
}
}
bool AMDemodGUI::handleMessage(Message* message)
bool AMDemodGUI::handleMessage(const Message& message)
{
return false;
}
@ -185,12 +185,10 @@ AMDemodGUI::AMDemodGUI(PluginAPI* pluginAPI, QWidget* parent) :
connect(this, SIGNAL(menuDoubleClickEvent()), this, SLOT(onMenuDoubleClicked()));
m_audioFifo = new AudioFifo(4, 48000);
m_nullSink = new NullSink();
m_amDemod = new AMDemod(m_audioFifo, m_nullSink);
m_amDemod = new AMDemod(m_audioFifo, 0);
m_channelizer = new Channelizer(m_amDemod);
m_threadedSampleSink = new ThreadedSampleSink(m_channelizer);
m_pluginAPI->addAudioSource(m_audioFifo);
m_pluginAPI->addSampleSink(m_threadedSampleSink);
DSPEngine::instance()->addAudioSink(m_audioFifo);
DSPEngine::instance()->addThreadedSink(m_channelizer);
m_channelMarker = new ChannelMarker(this);
m_channelMarker->setColor(Qt::yellow);
@ -206,12 +204,10 @@ AMDemodGUI::AMDemodGUI(PluginAPI* pluginAPI, QWidget* parent) :
AMDemodGUI::~AMDemodGUI()
{
m_pluginAPI->removeChannelInstance(this);
m_pluginAPI->removeAudioSource(m_audioFifo);
m_pluginAPI->removeSampleSink(m_threadedSampleSink);
delete m_threadedSampleSink;
DSPEngine::instance()->removeAudioSink(m_audioFifo);
DSPEngine::instance()->removeThreadedSink(m_channelizer);
delete m_channelizer;
delete m_amDemod;
delete m_nullSink;
delete m_audioFifo;
delete m_channelMarker;
delete ui;
@ -220,12 +216,15 @@ AMDemodGUI::~AMDemodGUI()
void AMDemodGUI::applySettings()
{
setTitleColor(m_channelMarker->getColor());
m_channelizer->configure(m_threadedSampleSink->getMessageQueue(),
m_channelizer->configure(m_channelizer->getInputMessageQueue(),
48000,
m_channelMarker->getCenterFrequency());
ui->deltaFrequency->setValue(abs(m_channelMarker->getCenterFrequency()));
ui->deltaMinus->setChecked(m_channelMarker->getCenterFrequency() < 0);
m_amDemod->configure(m_threadedSampleSink->getMessageQueue(),
m_amDemod->configure(m_amDemod->getInputMessageQueue(),
m_rfBW[ui->rfBW->value()],
ui->afBW->value() * 1000.0,
ui->volume->value() / 10.0,

View File

@ -8,10 +8,8 @@ class PluginAPI;
class ChannelMarker;
class AudioFifo;
class ThreadedSampleSink;
class Channelizer;
class AMDemod;
class NullSink;
namespace Ui {
class AMDemodGUI;
@ -32,7 +30,7 @@ public:
QByteArray serialize() const;
bool deserialize(const QByteArray& data);
bool handleMessage(Message* message);
virtual bool handleMessage(const Message& message);
private slots:
void viewChanged();
@ -52,10 +50,8 @@ private:
bool m_basicSettingsShown;
AudioFifo* m_audioFifo;
ThreadedSampleSink* m_threadedSampleSink;
Channelizer* m_channelizer;
AMDemod* m_amDemod;
NullSink *m_nullSink;
static const int m_rfBW[];

View File

@ -17,6 +17,7 @@
///////////////////////////////////////////////////////////////////////////////////
#include <QTime>
#include <QDebug>
#include <stdio.h>
#include "audio/audiooutput.h"
#include "dsp/dspcommands.h"
@ -55,7 +56,7 @@ void ChannelAnalyzer::configure(MessageQueue* messageQueue,
bool ssb)
{
Message* cmd = MsgConfigureChannelAnalyzer::create(Bandwidth, LowCutoff, spanLog2, ssb);
cmd->submit(messageQueue, this);
messageQueue->push(cmd);
}
void ChannelAnalyzer::feed(SampleVector::const_iterator begin, SampleVector::const_iterator end, bool positiveOnly)
@ -65,13 +66,17 @@ void ChannelAnalyzer::feed(SampleVector::const_iterator begin, SampleVector::con
int decim = 1<<m_spanLog2;
unsigned char decim_mask = decim - 1; // counter LSB bit mask for decimation by 2^(m_scaleLog2 - 1)
for(SampleVector::const_iterator it = begin; it < end; ++it) {
for(SampleVector::const_iterator it = begin; it < end; ++it)
{
Complex c(it->real() / 32768.0, it->imag() / 32768.0);
c *= m_nco.nextIQ();
if (m_ssb) {
if (m_ssb)
{
n_out = SSBFilter->runSSB(c, &sideband, m_usb);
} else {
}
else
{
n_out = DSBFilter->runDSB(c, &sideband);
}
@ -116,29 +121,41 @@ void ChannelAnalyzer::stop()
{
}
bool ChannelAnalyzer::handleMessage(Message* cmd)
bool ChannelAnalyzer::handleMessage(const Message& cmd)
{
float band, lowCutoff;
if(DSPSignalNotification::match(cmd)) {
DSPSignalNotification* signal = (DSPSignalNotification*)cmd;
fprintf(stderr, "ChannelAnalyzer::handleMessage: %d samples/sec, %lld Hz offset\n", signal->getSampleRate(), signal->getFrequencyOffset());
m_sampleRate = signal->getSampleRate();
m_nco.setFreq(-signal->getFrequencyOffset(), m_sampleRate);
cmd->completed();
qDebug() << "ChannelAnalyzer::handleMessage";
if (DSPSignalNotification::match(cmd))
{
DSPSignalNotification& notif = (DSPSignalNotification&) cmd;
m_sampleRate = notif.getSampleRate();
m_nco.setFreq(-notif.getFrequencyOffset(), m_sampleRate);
qDebug() << " - DSPSignalNotification: m_sampleRate: " << m_sampleRate
<< " frequencyOffset: " << notif.getFrequencyOffset();
return true;
} else if(MsgConfigureChannelAnalyzer::match(cmd)) {
MsgConfigureChannelAnalyzer* cfg = (MsgConfigureChannelAnalyzer*)cmd;
}
else if (MsgConfigureChannelAnalyzer::match(cmd))
{
MsgConfigureChannelAnalyzer& cfg = (MsgConfigureChannelAnalyzer&) cmd;
band = cfg->getBandwidth();
lowCutoff = cfg->getLoCutoff();
band = cfg.getBandwidth();
lowCutoff = cfg.getLoCutoff();
if (band < 0) {
if (band < 0)
{
band = -band;
lowCutoff = -lowCutoff;
m_usb = false;
} else
}
else
{
m_usb = true;
}
if (band < 100.0f)
{
@ -153,14 +170,25 @@ bool ChannelAnalyzer::handleMessage(Message* cmd)
SSBFilter->create_filter(m_LowCutoff / m_sampleRate, m_Bandwidth / m_sampleRate);
DSBFilter->create_dsb_filter(m_Bandwidth / m_sampleRate);
m_spanLog2 = cfg->getSpanLog2();
m_ssb = cfg->getSSB();
m_spanLog2 = cfg.getSpanLog2();
m_ssb = cfg.getSSB();
qDebug() << " - MsgConfigureChannelAnalyzer: m_Bandwidth: " << m_Bandwidth
<< " m_LowCutoff: " << m_LowCutoff
<< " m_spanLog2: " << m_spanLog2
<< " m_ssb: " << m_ssb;
cmd->completed();
return true;
} else {
if(m_sampleSink != NULL)
}
else
{
if (m_sampleSink != 0)
{
return m_sampleSink->handleMessage(cmd);
else return false;
}
else
{
return false;
}
}
}

View File

@ -33,7 +33,7 @@
class ChannelAnalyzer : public SampleSink {
public:
ChannelAnalyzer(SampleSink* m_sampleSink);
~ChannelAnalyzer();
virtual ~ChannelAnalyzer();
void configure(MessageQueue* messageQueue,
Real Bandwidth,
@ -45,10 +45,10 @@ public:
return m_sampleRate;
}
void feed(SampleVector::const_iterator begin, SampleVector::const_iterator end, bool positiveOnly);
void start();
void stop();
bool handleMessage(Message* cmd);
virtual void feed(SampleVector::const_iterator begin, SampleVector::const_iterator end, bool positiveOnly);
virtual void start();
virtual void stop();
virtual bool handleMessage(const Message& cmd);
private:
class MsgConfigureChannelAnalyzer : public Message {

View File

@ -1,7 +1,6 @@
#include <QDockWidget>
#include <QMainWindow>
#include "ui_chanalyzergui.h"
#include "dsp/threadedsamplesink.h"
#include "dsp/channelizer.h"
#include "dsp/spectrumscopecombovis.h"
#include "dsp/spectrumvis.h"
@ -11,6 +10,7 @@
#include "plugin/pluginapi.h"
#include "util/simpleserializer.h"
#include "gui/basicchannelsettingswidget.h"
#include "dsp/dspengine.h"
#include "mainwindow.h"
#include "chanalyzer.h"
@ -103,7 +103,7 @@ bool ChannelAnalyzerGUI::deserialize(const QByteArray& data)
}
}
bool ChannelAnalyzerGUI::handleMessage(Message* message)
bool ChannelAnalyzerGUI::handleMessage(const Message& message)
{
return false;
}
@ -267,8 +267,7 @@ ChannelAnalyzerGUI::ChannelAnalyzerGUI(PluginAPI* pluginAPI, QWidget* parent) :
m_channelAnalyzer = new ChannelAnalyzer(m_spectrumScopeComboVis);
m_channelizer = new Channelizer(m_channelAnalyzer);
connect(m_channelizer, SIGNAL(inputSampleRateChanged()), this, SLOT(channelSampleRateChanged()));
m_threadedSampleSink = new ThreadedSampleSink(m_channelizer);
m_pluginAPI->addSampleSink(m_threadedSampleSink);
DSPEngine::instance()->addThreadedSink(m_channelizer);
ui->deltaFrequency->setColorMapper(ColorMapper(ColorMapper::ReverseGold));
@ -290,8 +289,8 @@ ChannelAnalyzerGUI::ChannelAnalyzerGUI(PluginAPI* pluginAPI, QWidget* parent) :
connect(m_channelMarker, SIGNAL(changed()), this, SLOT(viewChanged()));
m_pluginAPI->addChannelMarker(m_channelMarker);
ui->spectrumGUI->setBuddies(m_threadedSampleSink->getMessageQueue(), m_spectrumVis, ui->glSpectrum);
ui->scopeGUI->setBuddies(m_threadedSampleSink->getMessageQueue(), m_scopeVis, ui->glScope);
ui->spectrumGUI->setBuddies(m_spectrumVis->getInputMessageQueue(), m_spectrumVis, ui->glSpectrum);
ui->scopeGUI->setBuddies(m_scopeVis->getInputMessageQueue(), m_scopeVis, ui->glScope);
applySettings();
}
@ -299,8 +298,7 @@ ChannelAnalyzerGUI::ChannelAnalyzerGUI(PluginAPI* pluginAPI, QWidget* parent) :
ChannelAnalyzerGUI::~ChannelAnalyzerGUI()
{
m_pluginAPI->removeChannelInstance(this);
m_pluginAPI->removeSampleSink(m_threadedSampleSink);
delete m_threadedSampleSink;
DSPEngine::instance()->removeThreadedSink(m_channelizer);
delete m_channelizer;
delete m_channelAnalyzer;
delete m_spectrumVis;
@ -376,10 +374,12 @@ void ChannelAnalyzerGUI::applySettings()
setTitleColor(m_channelMarker->getColor());
ui->deltaFrequency->setValue(abs(m_channelMarker->getCenterFrequency()));
ui->deltaMinus->setChecked(m_channelMarker->getCenterFrequency() < 0);
m_channelizer->configure(m_threadedSampleSink->getMessageQueue(),
m_channelizer->configure(m_channelizer->getInputMessageQueue(),
m_channelizer->getInputSampleRate(),
m_channelMarker->getCenterFrequency());
m_channelAnalyzer->configure(m_threadedSampleSink->getMessageQueue(),
m_channelAnalyzer->configure(m_channelAnalyzer->getInputMessageQueue(),
ui->BW->value() * 100.0,
ui->lowCut->value() * 100.0,
m_spanLog2,

View File

@ -8,7 +8,6 @@ class PluginAPI;
class ChannelMarker;
//class AudioFifo;
class ThreadedSampleSink;
class Channelizer;
class ChannelAnalyzer;
class SpectrumScopeComboVis;
@ -34,7 +33,7 @@ public:
QByteArray serialize() const;
bool deserialize(const QByteArray& data);
bool handleMessage(Message* message);
virtual bool handleMessage(const Message& message);
private slots:
void viewChanged();
@ -56,7 +55,6 @@ private:
int m_rate;
int m_spanLog2;
ThreadedSampleSink* m_threadedSampleSink;
Channelizer* m_channelizer;
ChannelAnalyzer* m_channelAnalyzer;
SpectrumScopeComboVis* m_spectrumScopeComboVis;

View File

@ -17,6 +17,7 @@
///////////////////////////////////////////////////////////////////////////////////
#include <QTime>
#include <QDebug>
#include <stdio.h>
#include "lorademod.h"
#include "dsp/dspcommands.h"
@ -44,6 +45,7 @@ LoRaDemod::LoRaDemod(SampleSink* sampleSink) :
m_count = 0;
m_header = 0;
m_time = 0;
m_tune = 0;
loraFilter = new sfft(LORA_SFFT_LEN);
negaFilter = new sfft(LORA_SFFT_LEN);
@ -70,7 +72,7 @@ LoRaDemod::~LoRaDemod()
void LoRaDemod::configure(MessageQueue* messageQueue, Real Bandwidth)
{
Message* cmd = MsgConfigureLoRaDemod::create(Bandwidth);
cmd->submit(messageQueue, this);
messageQueue->push(cmd);
}
void LoRaDemod::dumpRaw()
@ -79,13 +81,18 @@ void LoRaDemod::dumpRaw()
char text[256];
max = m_time / 4 - 3;
if (max > 140)
max = 140; // about 2 symbols to each char
for ( j=0; j < max; j++) {
if (max > 140)
{
max = 140; // about 2 symbols to each char
}
for ( j=0; j < max; j++)
{
bin = (history[(j + 1) * 4] + m_tune ) & (LORA_SFFT_LEN - 1);
text[j] = toGray(bin >> 1);
}
prng6(text, max);
// First block is always 8 symbols
interleave6(text, 6);
@ -93,46 +100,75 @@ void LoRaDemod::dumpRaw()
hamming6(text, 6);
hamming6(&text[8], max);
for ( j=0; j < max / 2; j++) {
for ( j=0; j < max / 2; j++)
{
text[j] = (text[j * 2 + 1] << 4) | (0xf & text[j * 2 + 0]);
if ((text[j] < 32 )||( text[j] > 126))
{
text[j] = 0x5f;
}
}
text[3] = text[2];
text[2] = text[1];
text[1] = text[0];
text[j] = 0;
printf("%s\n", &text[1]);
}
short LoRaDemod::synch(short bin)
{
short i, j;
if (bin < 0) {
if (bin < 0)
{
if (m_time > 70)
{
dumpRaw();
}
m_time = 0;
return -1;
}
history[m_time] = bin;
if (m_time > 12)
{
if (bin == history[m_time - 6])
if (bin == history[m_time - 12]) {
{
if (bin == history[m_time - 12])
{
m_tune = LORA_SFFT_LEN - bin;
j = 0;
for (i=0; i<12; i++)
{
j += finetune[15 & (m_time - i)];
}
if (j < 0)
{
m_tune += 1;
}
m_tune &= (LORA_SFFT_LEN - 1);
m_time = 0;
return -1;
}
}
}
m_time++;
m_time &= 1023;
if (m_time & 3)
{
return -1;
}
return (bin + m_tune) & (LORA_SFFT_LEN - 1);
}
@ -149,24 +185,34 @@ int LoRaDemod::detect(Complex c, Complex a)
// process spectrum twice in FFTLEN
if (++m_count & ((1 << DATA_BITS) - 1))
{
return m_result;
}
movpoint = 3 & (m_count >> DATA_BITS);
loraFilter->fetch(mag);
negaFilter->fetch(rev);
peak = negpeak = 0.0f;
result = negresult = 0;
for (i = 0; i < LORA_SFFT_LEN; i++) {
if (rev[i] > negpeak) {
for (i = 0; i < LORA_SFFT_LEN; i++)
{
if (rev[i] > negpeak)
{
negpeak = rev[i];
negresult = i;
}
tfloat = mov[i] + mov[LORA_SFFT_LEN + i] +mov[2 * LORA_SFFT_LEN + i]
+ mov[3 * LORA_SFFT_LEN + i] + mag[i];
if (tfloat > peak) {
if (tfloat > peak)
{
peak = tfloat;
result = i;
}
mov[movpoint * LORA_SFFT_LEN + i] = mag[i];
}
@ -175,10 +221,17 @@ int LoRaDemod::detect(Complex c, Complex a)
finetune[15 & m_time] = (mag[p] > mag[q]) ? -1 : 1;
if (peak < negpeak * LORA_SQUELCH)
{
result = -1;
}
result = synch(result);
if (result >= 0)
{
m_result = result;
}
return m_result;
}
@ -188,11 +241,14 @@ void LoRaDemod::feed(SampleVector::const_iterator begin, SampleVector::const_ite
Complex ci;
m_sampleBuffer.clear();
for(SampleVector::const_iterator it = begin; it < end; ++it) {
for(SampleVector::const_iterator it = begin; it < end; ++it)
{
Complex c(it->real() / 32768.0, it->imag() / 32768.0);
c *= m_nco.nextIQ();
if(m_interpolator.interpolate(&m_sampleDistanceRemain, c, &ci)) {
if(m_interpolator.interpolate(&m_sampleDistanceRemain, c, &ci))
{
m_chirp = (m_chirp + 1) & (SPREADFACTOR - 1);
m_angle = (m_angle + m_chirp) & (SPREADFACTOR - 1);
Complex cangle(cos(M_PI*2*m_angle/SPREADFACTOR),-sin(M_PI*2*m_angle/SPREADFACTOR));
@ -204,8 +260,11 @@ void LoRaDemod::feed(SampleVector::const_iterator begin, SampleVector::const_ite
m_sampleDistanceRemain += (Real)m_sampleRate / m_Bandwidth;
}
}
if(m_sampleSink != NULL)
if(m_sampleSink != 0)
{
m_sampleSink->feed(m_sampleBuffer.begin(), m_sampleBuffer.end(), false);
}
}
void LoRaDemod::start()
@ -216,26 +275,43 @@ void LoRaDemod::stop()
{
}
bool LoRaDemod::handleMessage(Message* cmd)
bool LoRaDemod::handleMessage(const Message& cmd)
{
if(DSPSignalNotification::match(cmd)) {
DSPSignalNotification* signal = (DSPSignalNotification*)cmd;
m_sampleRate = signal->getSampleRate();
m_nco.setFreq(-signal->getFrequencyOffset(), m_sampleRate);
qDebug() << "LoRaDemod::handleMessage";
if (DSPSignalNotification::match(cmd))
{
DSPSignalNotification& notif = (DSPSignalNotification&) cmd;
m_sampleRate = notif.getSampleRate();
m_nco.setFreq(-notif.getFrequencyOffset(), m_sampleRate);
m_interpolator.create(16, m_sampleRate, m_Bandwidth/1.9);
m_sampleDistanceRemain = m_sampleRate / m_Bandwidth;
cmd->completed();
qDebug() << " DSPSignalNotification: m_sampleRate: " << m_sampleRate;
return true;
} else if(MsgConfigureLoRaDemod::match(cmd)) {
MsgConfigureLoRaDemod* cfg = (MsgConfigureLoRaDemod*)cmd;
m_Bandwidth = cfg->getBandwidth();
}
else if (MsgConfigureLoRaDemod::match(cmd))
{
MsgConfigureLoRaDemod& cfg = (MsgConfigureLoRaDemod&) cmd;
m_Bandwidth = cfg.getBandwidth();
m_interpolator.create(16, m_sampleRate, m_Bandwidth/1.9);
cmd->completed();
qDebug() << " MsgConfigureLoRaDemod: m_Bandwidth: " << m_Bandwidth;
return true;
} else {
if(m_sampleSink != NULL)
}
else
{
if(m_sampleSink != 0)
{
return m_sampleSink->handleMessage(cmd);
}
else
{
return false;
}
}
}

View File

@ -34,14 +34,14 @@
class LoRaDemod : public SampleSink {
public:
LoRaDemod(SampleSink* sampleSink);
~LoRaDemod();
virtual ~LoRaDemod();
void configure(MessageQueue* messageQueue, Real Bandwidth);
void feed(SampleVector::const_iterator begin, SampleVector::const_iterator end, bool pO);
void start();
void stop();
bool handleMessage(Message* cmd);
virtual void feed(SampleVector::const_iterator begin, SampleVector::const_iterator end, bool pO);
virtual void start();
virtual void stop();
virtual bool handleMessage(const Message& cmd);
private:
int detect(Complex sample, Complex angle);

View File

@ -12,6 +12,7 @@
#include "plugin/pluginapi.h"
#include "util/simpleserializer.h"
#include "gui/basicchannelsettingswidget.h"
#include "dsp/dspengine.h"
LoRaDemodGUI* LoRaDemodGUI::create(PluginAPI* pluginAPI)
{
@ -83,7 +84,7 @@ bool LoRaDemodGUI::deserialize(const QByteArray& data)
}
}
bool LoRaDemodGUI::handleMessage(Message* message)
bool LoRaDemodGUI::handleMessage(const Message& message)
{
return false;
}
@ -137,8 +138,7 @@ LoRaDemodGUI::LoRaDemodGUI(PluginAPI* pluginAPI, QWidget* parent) :
m_spectrumVis = new SpectrumVis(ui->glSpectrum);
m_LoRaDemod = new LoRaDemod(m_spectrumVis);
m_channelizer = new Channelizer(m_LoRaDemod);
m_threadedSampleSink = new ThreadedSampleSink(m_channelizer);
m_pluginAPI->addSampleSink(m_threadedSampleSink);
DSPEngine::instance()->addThreadedSink(m_channelizer);
ui->glSpectrum->setCenterFrequency(16000);
ui->glSpectrum->setSampleRate(32000);
@ -155,7 +155,7 @@ LoRaDemodGUI::LoRaDemodGUI(PluginAPI* pluginAPI, QWidget* parent) :
connect(m_channelMarker, SIGNAL(changed()), this, SLOT(viewChanged()));
m_pluginAPI->addChannelMarker(m_channelMarker);
ui->spectrumGUI->setBuddies(m_threadedSampleSink->getMessageQueue(), m_spectrumVis, ui->glSpectrum);
ui->spectrumGUI->setBuddies(m_channelizer->getInputMessageQueue(), m_spectrumVis, ui->glSpectrum);
applySettings();
}
@ -163,8 +163,7 @@ LoRaDemodGUI::LoRaDemodGUI(PluginAPI* pluginAPI, QWidget* parent) :
LoRaDemodGUI::~LoRaDemodGUI()
{
m_pluginAPI->removeChannelInstance(this);
m_pluginAPI->removeSampleSink(m_threadedSampleSink);
delete m_threadedSampleSink;
DSPEngine::instance()->removeThreadedSink(m_channelizer);
delete m_channelizer;
delete m_LoRaDemod;
delete m_spectrumVis;
@ -176,8 +175,10 @@ void LoRaDemodGUI::applySettings()
{
const int loraBW[] = BANDWIDTHSTRING;
int thisBW = loraBW[ui->BW->value()];
m_channelizer->configure(m_threadedSampleSink->getMessageQueue(),
m_channelizer->configure(m_channelizer->getInputMessageQueue(),
thisBW,
m_channelMarker->getCenterFrequency());
m_LoRaDemod->configure(m_threadedSampleSink->getMessageQueue(), thisBW);
m_LoRaDemod->configure(m_LoRaDemod->getInputMessageQueue(), thisBW);
}

View File

@ -8,7 +8,6 @@
class PluginAPI;
class ChannelMarker;
class ThreadedSampleSink;
class Channelizer;
class LoRaDemod;
class SpectrumVis;
@ -32,7 +31,7 @@ public:
QByteArray serialize() const;
bool deserialize(const QByteArray& data);
bool handleMessage(Message* message);
virtual bool handleMessage(const Message& message);
private slots:
void viewChanged();
@ -47,7 +46,6 @@ private:
ChannelMarker* m_channelMarker;
bool m_basicSettingsShown;
ThreadedSampleSink* m_threadedSampleSink;
Channelizer* m_channelizer;
LoRaDemod* m_LoRaDemod;
SpectrumVis* m_spectrumVis;

View File

@ -16,6 +16,7 @@
///////////////////////////////////////////////////////////////////////////////////
#include <QTime>
#include <QDebug>
#include <stdio.h>
#include <complex.h>
#include "nfmdemod.h"
@ -23,6 +24,7 @@
#include "audio/audiooutput.h"
#include "dsp/dspcommands.h"
#include "dsp/pidcontroller.h"
#include "dsp/dspengine.h"
static const Real afSqTones[2] = {1200.0, 8000.0};
@ -68,7 +70,7 @@ NFMDemod::~NFMDemod()
void NFMDemod::configure(MessageQueue* messageQueue, Real rfBandwidth, Real afBandwidth, Real volume, Real squelch)
{
Message* cmd = MsgConfigureNFMDemod::create(rfBandwidth, afBandwidth, volume, squelch);
cmd->submit(messageQueue, this);
messageQueue->push(cmd);
}
float arctan2(Real y, Real x)
@ -250,52 +252,80 @@ void NFMDemod::stop()
{
}
bool NFMDemod::handleMessage(Message* cmd)
bool NFMDemod::handleMessage(const Message& cmd)
{
if(DSPSignalNotification::match(cmd)) {
DSPSignalNotification* signal = (DSPSignalNotification*)cmd;
qDebug() << "NFMDemod::handleMessage";
if (DSPSignalNotification::match(cmd))
{
DSPSignalNotification& notif = (DSPSignalNotification&) cmd;
m_config.m_inputSampleRate = notif.getSampleRate();
m_config.m_inputFrequencyOffset = notif.getFrequencyOffset();
m_config.m_inputSampleRate = signal->getSampleRate();
m_config.m_inputFrequencyOffset = signal->getFrequencyOffset();
apply();
cmd->completed();
qDebug() << " - DSPSignalNotification: m_inputSampleRate: " << m_config.m_inputSampleRate
<< " m_inputFrequencyOffset: " << m_config.m_inputFrequencyOffset;
return true;
} else if(MsgConfigureNFMDemod::match(cmd)) {
MsgConfigureNFMDemod* cfg = (MsgConfigureNFMDemod*)cmd;
m_config.m_rfBandwidth = cfg->getRFBandwidth();
m_config.m_afBandwidth = cfg->getAFBandwidth();
m_config.m_volume = cfg->getVolume();
m_config.m_squelch = cfg->getSquelch();
}
else if (MsgConfigureNFMDemod::match(cmd))
{
MsgConfigureNFMDemod& cfg = (MsgConfigureNFMDemod&) cmd;
m_config.m_rfBandwidth = cfg.getRFBandwidth();
m_config.m_afBandwidth = cfg.getAFBandwidth();
m_config.m_volume = cfg.getVolume();
m_config.m_squelch = cfg.getSquelch();
apply();
qDebug() << " - MsgConfigureNFMDemod: m_rfBandwidth: " << m_config.m_rfBandwidth
<< " m_afBandwidth: " << m_config.m_afBandwidth
<< " m_volume: " << m_config.m_volume
<< " m_squelch: " << m_config.m_squelch;
return true;
} else {
if(m_sampleSink != NULL)
}
else
{
if (m_sampleSink != 0)
{
return m_sampleSink->handleMessage(cmd);
else return false;
}
else
{
return false;
}
}
}
void NFMDemod::apply()
{
if((m_config.m_inputFrequencyOffset != m_running.m_inputFrequencyOffset) ||
(m_config.m_inputSampleRate != m_running.m_inputSampleRate)) {
(m_config.m_inputSampleRate != m_running.m_inputSampleRate))
{
m_nco.setFreq(-m_config.m_inputFrequencyOffset, m_config.m_inputSampleRate);
}
if((m_config.m_inputSampleRate != m_running.m_inputSampleRate) ||
(m_config.m_rfBandwidth != m_running.m_rfBandwidth)) {
(m_config.m_rfBandwidth != m_running.m_rfBandwidth))
{
m_interpolator.create(16, m_config.m_inputSampleRate, m_config.m_rfBandwidth / 2.2);
m_interpolatorDistanceRemain = 0;
m_interpolatorDistance = (Real) m_config.m_inputSampleRate / (Real) m_config.m_audioSampleRate;
}
if((m_config.m_afBandwidth != m_running.m_afBandwidth) ||
(m_config.m_audioSampleRate != m_running.m_audioSampleRate)) {
(m_config.m_audioSampleRate != m_running.m_audioSampleRate))
{
m_lowpass.create(301, m_config.m_audioSampleRate, 250.0);
m_bandpass.create(301, m_config.m_audioSampleRate, 300.0, m_config.m_afBandwidth);
}
if(m_config.m_squelch != m_running.m_squelch) {
if(m_config.m_squelch != m_running.m_squelch)
{
m_squelchLevel = pow(10.0, m_config.m_squelch / 10.0);
m_squelchLevel *= m_squelchLevel;
m_afSquelch.setThreshold(m_squelchLevel);

View File

@ -41,10 +41,10 @@ public:
void configure(MessageQueue* messageQueue, Real rfBandwidth, Real afBandwidth, Real volume, Real squelch);
void feed(SampleVector::const_iterator begin, SampleVector::const_iterator end, bool po);
void start();
void stop();
bool handleMessage(Message* cmd);
virtual void feed(SampleVector::const_iterator begin, SampleVector::const_iterator end, bool po);
virtual void start();
virtual void stop();
virtual bool handleMessage(const Message& cmd);
void registerGUI(NFMDemodGUI *nfmDemodGUI) {
m_nfmDemodGUI = nfmDemodGUI;

View File

@ -10,6 +10,7 @@
#include "plugin/pluginapi.h"
#include "util/simpleserializer.h"
#include "gui/basicchannelsettingswidget.h"
#include "dsp/dspengine.h"
const int NFMDemodGUI::m_rfBW[] = {
5000, 6250, 8330, 10000, 12500, 15000, 20000, 25000, 40000
@ -69,12 +70,14 @@ bool NFMDemodGUI::deserialize(const QByteArray& data)
{
SimpleDeserializer d(data);
if(!d.isValid()) {
if (!d.isValid())
{
resetToDefaults();
return false;
}
if(d.getVersion() == 1) {
if (d.getVersion() == 1)
{
QByteArray bytetmp;
quint32 u32tmp;
qint32 tmp;
@ -96,13 +99,15 @@ bool NFMDemodGUI::deserialize(const QByteArray& data)
ui->ctcss->setCurrentIndex(tmp);
applySettings();
return true;
} else {
}
else
{
resetToDefaults();
return false;
}
}
bool NFMDemodGUI::handleMessage(Message* message)
bool NFMDemodGUI::handleMessage(const Message& message)
{
return false;
}
@ -125,9 +130,12 @@ void NFMDemodGUI::on_deltaMinus_clicked(bool minus)
void NFMDemodGUI::on_deltaFrequency_changed(quint64 value)
{
if (ui->deltaMinus->isChecked()) {
if (ui->deltaMinus->isChecked())
{
m_channelMarker->setCenterFrequency(-value);
} else {
}
else
{
m_channelMarker->setCenterFrequency(value);
}
}
@ -159,7 +167,8 @@ void NFMDemodGUI::on_squelch_valueChanged(int value)
void NFMDemodGUI::on_ctcss_currentIndexChanged(int index)
{
if (m_nfmDemod != NULL) {
if (m_nfmDemod != 0)
{
m_nfmDemod->setSelectedCtcssIndex(index);
}
}
@ -174,7 +183,8 @@ void NFMDemodGUI::onWidgetRolled(QWidget* widget, bool rollDown)
void NFMDemodGUI::onMenuDoubleClicked()
{
if(!m_basicSettingsShown) {
if (!m_basicSettingsShown)
{
m_basicSettingsShown = true;
BasicChannelSettingsWidget* bcsw = new BasicChannelSettingsWidget(m_channelMarker, this);
bcsw->show();
@ -193,9 +203,8 @@ NFMDemodGUI::NFMDemodGUI(PluginAPI* pluginAPI, QWidget* parent) :
connect(this, SIGNAL(menuDoubleClickEvent()), this, SLOT(onMenuDoubleClicked()));
m_audioFifo = new AudioFifo(4, 48000);
m_nullSink = new NullSink();
m_nfmDemod = new NFMDemod(m_audioFifo, m_nullSink);
m_nfmDemod = new NFMDemod(m_audioFifo, 0);
m_nfmDemod->registerGUI(this);
int ctcss_nbTones;
@ -203,7 +212,8 @@ NFMDemodGUI::NFMDemodGUI(PluginAPI* pluginAPI, QWidget* parent) :
ui->ctcss->addItem("--");
for (int i=0; i<ctcss_nbTones; i++) {
for (int i=0; i<ctcss_nbTones; i++)
{
ui->ctcss->addItem(QString("%1").arg(ctcss_tones[i]));
}
@ -211,9 +221,8 @@ NFMDemodGUI::NFMDemodGUI(PluginAPI* pluginAPI, QWidget* parent) :
//ui->deltaFrequency->setBold(true);
m_channelizer = new Channelizer(m_nfmDemod);
m_threadedSampleSink = new ThreadedSampleSink(m_channelizer);
m_pluginAPI->addAudioSource(m_audioFifo);
m_pluginAPI->addSampleSink(m_threadedSampleSink);
DSPEngine::instance()->addAudioSink(m_audioFifo);
DSPEngine::instance()->addThreadedSink(m_channelizer);
m_channelMarker = new ChannelMarker(this);
m_channelMarker->setColor(Qt::red);
@ -229,12 +238,10 @@ NFMDemodGUI::NFMDemodGUI(PluginAPI* pluginAPI, QWidget* parent) :
NFMDemodGUI::~NFMDemodGUI()
{
m_pluginAPI->removeChannelInstance(this);
m_pluginAPI->removeAudioSource(m_audioFifo);
m_pluginAPI->removeSampleSink(m_threadedSampleSink);
delete m_threadedSampleSink;
DSPEngine::instance()->removeAudioSink(m_audioFifo);
DSPEngine::instance()->removeThreadedSink(m_channelizer);
delete m_channelizer;
delete m_nfmDemod;
delete m_nullSink;
delete m_audioFifo;
delete m_channelMarker;
delete ui;
@ -243,12 +250,15 @@ NFMDemodGUI::~NFMDemodGUI()
void NFMDemodGUI::applySettings()
{
setTitleColor(m_channelMarker->getColor());
m_channelizer->configure(m_threadedSampleSink->getMessageQueue(),
m_channelizer->configure(m_channelizer->getInputMessageQueue(),
48000,
m_channelMarker->getCenterFrequency());
ui->deltaFrequency->setValue(abs(m_channelMarker->getCenterFrequency()));
ui->deltaMinus->setChecked(m_channelMarker->getCenterFrequency() < 0);
m_nfmDemod->configure(m_threadedSampleSink->getMessageQueue(),
m_nfmDemod->configure(m_nfmDemod->getInputMessageQueue(),
m_rfBW[ui->rfBW->value()],
ui->afBW->value() * 1000.0,
ui->volume->value() / 10.0,

View File

@ -9,10 +9,8 @@ class PluginAPI;
class ChannelMarker;
class AudioFifo;
class ThreadedSampleSink;
class Channelizer;
class NFMDemod;
class NullSink;
namespace Ui {
class NFMDemodGUI;
@ -33,7 +31,7 @@ public:
QByteArray serialize() const;
bool deserialize(const QByteArray& data);
bool handleMessage(Message* message);
virtual bool handleMessage(const Message& message);
void setCtcssFreq(Real ctcssFreq);
private slots:
@ -55,10 +53,8 @@ private:
bool m_basicSettingsShown;
AudioFifo* m_audioFifo;
ThreadedSampleSink* m_threadedSampleSink;
Channelizer* m_channelizer;
NFMDemod* m_nfmDemod;
NullSink *m_nullSink;
static const int m_rfBW[];

View File

@ -17,6 +17,7 @@
///////////////////////////////////////////////////////////////////////////////////
#include <QTime>
#include <QDebug>
#include <stdio.h>
#include "ssbdemod.h"
#include "audio/audiooutput.h"
@ -57,7 +58,7 @@ SSBDemod::~SSBDemod()
void SSBDemod::configure(MessageQueue* messageQueue, Real Bandwidth, Real LowCutoff, Real volume, int spanLog2)
{
Message* cmd = MsgConfigureSSBDemod::create(Bandwidth, LowCutoff, volume, spanLog2);
cmd->submit(messageQueue, this);
messageQueue->push(cmd);
}
void SSBDemod::feed(SampleVector::const_iterator begin, SampleVector::const_iterator end, bool positiveOnly)
@ -69,17 +70,23 @@ void SSBDemod::feed(SampleVector::const_iterator begin, SampleVector::const_iter
int decim = 1<<(m_spanLog2 - 1);
unsigned char decim_mask = decim - 1; // counter LSB bit mask for decimation by 2^(m_scaleLog2 - 1)
for(SampleVector::const_iterator it = begin; it < end; ++it) {
for(SampleVector::const_iterator it = begin; it < end; ++it)
{
Complex c(it->real() / 32768.0, it->imag() / 32768.0);
c *= m_nco.nextIQ();
if(m_interpolator.interpolate(&m_sampleDistanceRemain, c, &ci)) {
if(m_interpolator.interpolate(&m_sampleDistanceRemain, c, &ci))
{
n_out = SSBFilter->runSSB(ci, &sideband, m_usb);
m_sampleDistanceRemain += (Real)m_sampleRate / 48000.0;
} else
}
else
{
n_out = 0;
}
for (int i = 0; i < n_out; i++) {
for (int i = 0; i < n_out; i++)
{
Real demod = (sideband[i].real() + sideband[i].imag()) * 0.7 * 32768.0;
// Downsample by 2^(m_scaleLog2 - 1) for SSB band spectrum display
@ -87,7 +94,8 @@ void SSBDemod::feed(SampleVector::const_iterator begin, SampleVector::const_iter
sum += sideband[i];
if (!(m_undersampleCount++ & decim_mask)) {
if (!(m_undersampleCount++ & decim_mask))
{
avg = (sum.real() + sum.imag()) * 0.7 * 32768.0 / decim;
m_sampleBuffer.push_back(Sample(avg, 0.0));
sum.real() = 0.0;
@ -98,20 +106,32 @@ void SSBDemod::feed(SampleVector::const_iterator begin, SampleVector::const_iter
m_audioBuffer[m_audioBufferFill].l = sample;
m_audioBuffer[m_audioBufferFill].r = sample;
++m_audioBufferFill;
if(m_audioBufferFill >= m_audioBuffer.size()) {
if (m_audioBufferFill >= m_audioBuffer.size())
{
uint res = m_audioFifo->write((const quint8*)&m_audioBuffer[0], m_audioBufferFill, 1);
if (res != m_audioBufferFill)
{
qDebug("lost %u samples", m_audioBufferFill - res);
}
m_audioBufferFill = 0;
}
}
}
if(m_audioFifo->write((const quint8*)&m_audioBuffer[0], m_audioBufferFill, 0) != m_audioBufferFill)
;//qDebug("lost samples");
if (m_audioFifo->write((const quint8*)&m_audioBuffer[0], m_audioBufferFill, 0) != m_audioBufferFill)
{
qDebug("SSBDemod::feed: lost samples");
}
m_audioBufferFill = 0;
if(m_sampleSink != NULL)
if(m_sampleSink != 0)
{
m_sampleSink->feed(m_sampleBuffer.begin(), m_sampleBuffer.end(), true);
}
m_sampleBuffer.clear();
}
@ -123,24 +143,32 @@ void SSBDemod::stop()
{
}
bool SSBDemod::handleMessage(Message* cmd)
bool SSBDemod::handleMessage(const Message& cmd)
{
float band, lowCutoff;
if(DSPSignalNotification::match(cmd)) {
DSPSignalNotification* signal = (DSPSignalNotification*)cmd;
//fprintf(stderr, "%d samples/sec, %lld Hz offset", signal->getSampleRate(), signal->getFrequencyOffset());
m_sampleRate = signal->getSampleRate();
m_nco.setFreq(-signal->getFrequencyOffset(), m_sampleRate);
qDebug() << "SSBDemod::handleMessage";
if (DSPSignalNotification::match(cmd))
{
DSPSignalNotification& notif = (DSPSignalNotification&) cmd;
m_sampleRate = notif.getSampleRate();
m_nco.setFreq(-notif.getFrequencyOffset(), m_sampleRate);
m_interpolator.create(16, m_sampleRate, m_Bandwidth);
m_sampleDistanceRemain = m_sampleRate / 48000.0;
cmd->completed();
return true;
} else if(MsgConfigureSSBDemod::match(cmd)) {
MsgConfigureSSBDemod* cfg = (MsgConfigureSSBDemod*)cmd;
band = cfg->getBandwidth();
lowCutoff = cfg->getLoCutoff();
qDebug() << " - DSPSignalNotification: m_sampleRate: " << m_sampleRate
<< " frequencyOffset" << notif.getFrequencyOffset();
return true;
}
else if (MsgConfigureSSBDemod::match(cmd))
{
MsgConfigureSSBDemod& cfg = (MsgConfigureSSBDemod&) cmd;
band = cfg.getBandwidth();
lowCutoff = cfg.getLoCutoff();
if (band < 0) {
band = -band;
@ -161,16 +189,27 @@ bool SSBDemod::handleMessage(Message* cmd)
m_interpolator.create(16, m_sampleRate, band * 2.0f);
SSBFilter->create_filter(m_LowCutoff / 48000.0f, m_Bandwidth / 48000.0f);
m_volume = cfg->getVolume();
m_volume = cfg.getVolume();
m_volume *= m_volume * 0.1;
m_spanLog2 = cfg->getSpanLog2();
m_spanLog2 = cfg.getSpanLog2();
qDebug() << " - MsgConfigureSSBDemod: m_Bandwidth: " << m_Bandwidth
<< " m_LowCutoff: " << m_LowCutoff
<< " m_volume: " << m_volume
<< " m_spanLog2: " << m_spanLog2;
cmd->completed();
return true;
} else {
if(m_sampleSink != NULL)
}
else
{
if(m_sampleSink != 0)
{
return m_sampleSink->handleMessage(cmd);
else return false;
}
else
{
return false;
}
}
}

View File

@ -33,14 +33,14 @@ class AudioFifo;
class SSBDemod : public SampleSink {
public:
SSBDemod(AudioFifo* audioFifo, SampleSink* sampleSink);
~SSBDemod();
virtual ~SSBDemod();
void configure(MessageQueue* messageQueue, Real Bandwidth, Real LowCutoff, Real volume, int spanLog2);
void feed(SampleVector::const_iterator begin, SampleVector::const_iterator end, bool positiveOnly);
void start();
void stop();
bool handleMessage(Message* cmd);
virtual void feed(SampleVector::const_iterator begin, SampleVector::const_iterator end, bool positiveOnly);
virtual void start();
virtual void stop();
virtual bool handleMessage(const Message& cmd);
private:
class MsgConfigureSSBDemod : public Message {

View File

@ -12,6 +12,7 @@
#include "plugin/pluginapi.h"
#include "util/simpleserializer.h"
#include "gui/basicchannelsettingswidget.h"
#include "dsp/dspengine.h"
#include "mainwindow.h"
SSBDemodGUI* SSBDemodGUI::create(PluginAPI* pluginAPI)
@ -66,12 +67,14 @@ bool SSBDemodGUI::deserialize(const QByteArray& data)
{
SimpleDeserializer d(data);
if(!d.isValid()) {
if (!d.isValid())
{
resetToDefaults();
return false;
}
if(d.getVersion() == 1) {
if (d.getVersion() == 1)
{
QByteArray bytetmp;
quint32 u32tmp;
qint32 tmp;
@ -92,13 +95,15 @@ bool SSBDemodGUI::deserialize(const QByteArray& data)
setNewRate(tmp);
applySettings();
return true;
} else {
}
else
{
resetToDefaults();
return false;
}
}
bool SSBDemodGUI::handleMessage(Message* message)
bool SSBDemodGUI::handleMessage(const Message& message)
{
return false;
}
@ -121,9 +126,12 @@ void SSBDemodGUI::on_deltaMinus_clicked(bool minus)
void SSBDemodGUI::on_deltaFrequency_changed(quint64 value)
{
if (ui->deltaMinus->isChecked()) {
if (ui->deltaMinus->isChecked())
{
m_channelMarker->setCenterFrequency(-value);
} else {
}
else
{
m_channelMarker->setCenterFrequency(value);
}
}
@ -134,9 +142,12 @@ void SSBDemodGUI::on_BW_valueChanged(int value)
ui->BWText->setText(tr("%1k").arg(s));
m_channelMarker->setBandwidth(value * 100 * 2);
if (value < 0) {
if (value < 0)
{
m_channelMarker->setSidebands(ChannelMarker::lsb);
} else {
}
else
{
m_channelMarker->setSidebands(ChannelMarker::usb);
}
@ -149,18 +160,25 @@ int SSBDemodGUI::getEffectiveLowCutoff(int lowCutoff)
int effectiveLowCutoff = lowCutoff;
const int guard = 100;
if (ssbBW < 0) {
if (effectiveLowCutoff < ssbBW + guard) {
if (ssbBW < 0)
{
if (effectiveLowCutoff < ssbBW + guard)
{
effectiveLowCutoff = ssbBW + guard;
}
if (effectiveLowCutoff > 0) {
if (effectiveLowCutoff > 0)
{
effectiveLowCutoff = 0;
}
} else {
if (effectiveLowCutoff > ssbBW - guard) {
}
else
{
if (effectiveLowCutoff > ssbBW - guard)
{
effectiveLowCutoff = ssbBW - guard;
}
if (effectiveLowCutoff < 0) {
if (effectiveLowCutoff < 0)
{
effectiveLowCutoff = 0;
}
}
@ -186,7 +204,8 @@ void SSBDemodGUI::on_volume_valueChanged(int value)
void SSBDemodGUI::on_spanLog2_valueChanged(int value)
{
if (setNewRate(value)) {
if (setNewRate(value))
{
applySettings();
}
@ -202,7 +221,8 @@ void SSBDemodGUI::onWidgetRolled(QWidget* widget, bool rollDown)
void SSBDemodGUI::onMenuDoubleClicked()
{
if(!m_basicSettingsShown) {
if(!m_basicSettingsShown)
{
m_basicSettingsShown = true;
BasicChannelSettingsWidget* bcsw = new BasicChannelSettingsWidget(m_channelMarker, this);
bcsw->show();
@ -226,9 +246,8 @@ SSBDemodGUI::SSBDemodGUI(PluginAPI* pluginAPI, QWidget* parent) :
m_spectrumVis = new SpectrumVis(ui->glSpectrum);
m_ssbDemod = new SSBDemod(m_audioFifo, m_spectrumVis);
m_channelizer = new Channelizer(m_ssbDemod);
m_threadedSampleSink = new ThreadedSampleSink(m_channelizer);
m_pluginAPI->addAudioSource(m_audioFifo);
m_pluginAPI->addSampleSink(m_threadedSampleSink);
DSPEngine::instance()->addAudioSink(m_audioFifo);
DSPEngine::instance()->addThreadedSink(m_channelizer);
ui->deltaFrequency->setColorMapper(ColorMapper(ColorMapper::ReverseGold));
@ -248,7 +267,7 @@ SSBDemodGUI::SSBDemodGUI(PluginAPI* pluginAPI, QWidget* parent) :
connect(m_channelMarker, SIGNAL(changed()), this, SLOT(viewChanged()));
m_pluginAPI->addChannelMarker(m_channelMarker);
ui->spectrumGUI->setBuddies(m_threadedSampleSink->getMessageQueue(), m_spectrumVis, ui->glSpectrum);
ui->spectrumGUI->setBuddies(m_spectrumVis->getInputMessageQueue(), m_spectrumVis, ui->glSpectrum);
applySettings();
}
@ -256,9 +275,8 @@ SSBDemodGUI::SSBDemodGUI(PluginAPI* pluginAPI, QWidget* parent) :
SSBDemodGUI::~SSBDemodGUI()
{
m_pluginAPI->removeChannelInstance(this);
m_pluginAPI->removeAudioSource(m_audioFifo);
m_pluginAPI->removeSampleSink(m_threadedSampleSink);
delete m_threadedSampleSink;
DSPEngine::instance()->removeAudioSink(m_audioFifo);
DSPEngine::instance()->removeThreadedSink(m_channelizer);
delete m_channelizer;
delete m_ssbDemod;
delete m_spectrumVis;
@ -269,25 +287,32 @@ SSBDemodGUI::~SSBDemodGUI()
bool SSBDemodGUI::setNewRate(int spanLog2)
{
if ((spanLog2 < 1) || (spanLog2 > 5)) {
if ((spanLog2 < 1) || (spanLog2 > 5))
{
return false;
}
m_spanLog2 = spanLog2;
m_rate = 48000 / (1<<spanLog2);
if (ui->BW->value() < -m_rate/100) {
if (ui->BW->value() < -m_rate/100)
{
ui->BW->setValue(-m_rate/100);
m_channelMarker->setBandwidth(-m_rate*2);
} else if (ui->BW->value() > m_rate/100) {
}
else if (ui->BW->value() > m_rate/100)
{
ui->BW->setValue(m_rate/100);
m_channelMarker->setBandwidth(m_rate*2);
}
if (ui->lowCut->value() < -m_rate/100) {
if (ui->lowCut->value() < -m_rate/100)
{
ui->lowCut->setValue(-m_rate/100);
m_channelMarker->setLowCutoff(-m_rate);
} else if (ui->lowCut->value() > m_rate/100) {
}
else if (ui->lowCut->value() > m_rate/100)
{
ui->lowCut->setValue(m_rate/100);
m_channelMarker->setLowCutoff(m_rate);
}
@ -311,10 +336,12 @@ void SSBDemodGUI::applySettings()
setTitleColor(m_channelMarker->getColor());
ui->deltaFrequency->setValue(abs(m_channelMarker->getCenterFrequency()));
ui->deltaMinus->setChecked(m_channelMarker->getCenterFrequency() < 0);
m_channelizer->configure(m_threadedSampleSink->getMessageQueue(),
m_channelizer->configure(m_channelizer->getInputMessageQueue(),
48000,
m_channelMarker->getCenterFrequency());
m_ssbDemod->configure(m_threadedSampleSink->getMessageQueue(),
m_ssbDemod->configure(m_ssbDemod->getInputMessageQueue(),
ui->BW->value() * 100.0,
ui->lowCut->value() * 100.0,
ui->volume->value() / 10.0,

View File

@ -8,7 +8,6 @@ class PluginAPI;
class ChannelMarker;
class AudioFifo;
class ThreadedSampleSink;
class Channelizer;
class SSBDemod;
class SpectrumVis;
@ -32,7 +31,7 @@ public:
QByteArray serialize() const;
bool deserialize(const QByteArray& data);
bool handleMessage(Message* message);
virtual bool handleMessage(const Message& message);
private slots:
void viewChanged();
@ -54,7 +53,6 @@ private:
int m_spanLog2;
AudioFifo* m_audioFifo;
ThreadedSampleSink* m_threadedSampleSink;
Channelizer* m_channelizer;
SSBDemod* m_ssbDemod;
SpectrumVis* m_spectrumVis;

View File

@ -47,6 +47,7 @@ TCPSrc::TCPSrc(MessageQueue* uiMessageQueue, TCPSrcGUI* tcpSrcGUI, SampleSink* s
m_last = 0;
m_this = 0;
m_scale = 0;
m_boost = 0;
m_sampleBufferSSB.resize(tcpFftLen);
TCPFilter = new fftfilt(0.3 / 48.0, 16.0 / 48.0, tcpFftLen);
// if (!TCPFilter) segfault;
@ -60,13 +61,13 @@ TCPSrc::~TCPSrc()
void TCPSrc::configure(MessageQueue* messageQueue, SampleFormat sampleFormat, Real outputSampleRate, Real rfBandwidth, int tcpPort, int boost)
{
Message* cmd = MsgTCPSrcConfigure::create(sampleFormat, outputSampleRate, rfBandwidth, tcpPort, boost);
cmd->submit(messageQueue, this);
messageQueue->push(cmd);
}
void TCPSrc::setSpectrum(MessageQueue* messageQueue, bool enabled)
{
Message* cmd = MsgTCPSrcSpectrum::create(enabled);
cmd->submit(messageQueue, this);
messageQueue->push(cmd);
}
void TCPSrc::feed(SampleVector::const_iterator begin, SampleVector::const_iterator end, bool positiveOnly)
@ -157,61 +158,101 @@ void TCPSrc::stop()
delete m_tcpServer;
}
bool TCPSrc::handleMessage(Message* cmd)
bool TCPSrc::handleMessage(const Message& cmd)
{
if(DSPSignalNotification::match(cmd)) {
DSPSignalNotification* signal = (DSPSignalNotification*)cmd;
qDebug("%d samples/sec, %lld Hz offset", signal->getSampleRate(), signal->getFrequencyOffset());
m_inputSampleRate = signal->getSampleRate();
m_nco.setFreq(-signal->getFrequencyOffset(), m_inputSampleRate);
qDebug() << "TCPSrc::handleMessage";
if (DSPSignalNotification::match(cmd))
{
DSPSignalNotification& notif = (DSPSignalNotification&) cmd;
m_inputSampleRate = notif.getSampleRate();
m_nco.setFreq(-notif.getFrequencyOffset(), m_inputSampleRate);
m_interpolator.create(16, m_inputSampleRate, m_rfBandwidth / 2.0);
m_sampleDistanceRemain = m_inputSampleRate / m_outputSampleRate;
cmd->completed();
qDebug() << " - DSPSignalNotification: m_inputSampleRate: " << m_inputSampleRate
<< " frequencyOffset: " << notif.getFrequencyOffset();
return true;
} else if(MsgTCPSrcConfigure::match(cmd)) {
MsgTCPSrcConfigure* cfg = (MsgTCPSrcConfigure*)cmd;
m_sampleFormat = cfg->getSampleFormat();
m_outputSampleRate = cfg->getOutputSampleRate();
m_rfBandwidth = cfg->getRFBandwidth();
if(cfg->getTCPPort() != m_tcpPort) {
m_tcpPort = cfg->getTCPPort();
}
else if (MsgTCPSrcConfigure::match(cmd))
{
MsgTCPSrcConfigure& cfg = (MsgTCPSrcConfigure&) cmd;
m_sampleFormat = cfg.getSampleFormat();
m_outputSampleRate = cfg.getOutputSampleRate();
m_rfBandwidth = cfg.getRFBandwidth();
if (cfg.getTCPPort() != m_tcpPort)
{
m_tcpPort = cfg.getTCPPort();
if(m_tcpServer->isListening())
{
m_tcpServer->close();
}
m_tcpServer->listen(QHostAddress::Any, m_tcpPort);
}
m_boost = cfg->getBoost();
m_boost = cfg.getBoost();
m_interpolator.create(16, m_inputSampleRate, m_rfBandwidth / 2.0);
m_sampleDistanceRemain = m_inputSampleRate / m_outputSampleRate;
if (m_sampleFormat == FormatSSB)
{
TCPFilter->create_filter(0.3 / 48.0, m_rfBandwidth / 2.0 / m_outputSampleRate);
}
else
{
TCPFilter->create_filter(0.0, m_rfBandwidth / 2.0 / m_outputSampleRate);
cmd->completed();
}
qDebug() << " - MsgTCPSrcConfigure: m_sampleFormat: " << m_sampleFormat
<< " m_outputSampleRate: " << m_outputSampleRate
<< " m_rfBandwidth: " << m_rfBandwidth
<< " m_boost: " << m_boost;
return true;
} else if(MsgTCPSrcSpectrum::match(cmd)) {
MsgTCPSrcSpectrum* spc = (MsgTCPSrcSpectrum*)cmd;
m_spectrumEnabled = spc->getEnabled();
cmd->completed();
}
else if (MsgTCPSrcSpectrum::match(cmd))
{
MsgTCPSrcSpectrum& spc = (MsgTCPSrcSpectrum&) cmd;
m_spectrumEnabled = spc.getEnabled();
qDebug() << " - MsgTCPSrcSpectrum: m_spectrumEnabled: " << m_spectrumEnabled;
return true;
} else {
if(m_spectrum != NULL)
}
else
{
if(m_spectrum != 0)
{
return m_spectrum->handleMessage(cmd);
else return false;
}
else
{
return false;
}
}
}
void TCPSrc::closeAllSockets(Sockets* sockets)
{
for(int i = 0; i < sockets->count(); ++i) {
for(int i = 0; i < sockets->count(); ++i)
{
MsgTCPSrcConnection* msg = MsgTCPSrcConnection::create(false, sockets->at(i).id, QHostAddress(), 0);
msg->submit(m_uiMessageQueue, (PluginGUI*)m_tcpSrcGUI);
m_uiMessageQueue->push(msg);
sockets->at(i).socket->close();
}
}
void TCPSrc::onNewConnection()
{
while(m_tcpServer->hasPendingConnections()) {
while(m_tcpServer->hasPendingConnections())
{
QTcpSocket* connection = m_tcpServer->nextPendingConnection();
connect(connection, SIGNAL(disconnected()), this, SLOT(onDisconnected()));
@ -223,7 +264,7 @@ void TCPSrc::onNewConnection()
MsgTCPSrcConnection* msg = MsgTCPSrcConnection::create(true, id, connection->peerAddress(), connection->peerPort());
m_nextSSBId = (m_nextSSBId + 1) & 0xffffff;
m_ssbSockets.push_back(Socket(id, connection));
msg->submit(m_uiMessageQueue, (PluginGUI*)m_tcpSrcGUI);
m_uiMessageQueue->push(msg);
break;
}
@ -232,7 +273,7 @@ void TCPSrc::onNewConnection()
MsgTCPSrcConnection* msg = MsgTCPSrcConnection::create(true, id, connection->peerAddress(), connection->peerPort());
m_nextS16leId = (m_nextS16leId + 1) & 0xffffff;
m_s16leSockets.push_back(Socket(id, connection));
msg->submit(m_uiMessageQueue, (PluginGUI*)m_tcpSrcGUI);
m_uiMessageQueue->push(msg);
break;
}
@ -246,19 +287,25 @@ void TCPSrc::onNewConnection()
void TCPSrc::onDisconnected()
{
quint32 id;
QTcpSocket* socket = NULL;
QTcpSocket* socket = 0;
for(int i = 0; i < m_ssbSockets.count(); i++) {
if(m_ssbSockets[i].socket == sender()) {
for(int i = 0; i < m_ssbSockets.count(); i++)
{
if(m_ssbSockets[i].socket == sender())
{
id = m_ssbSockets[i].id;
socket = m_ssbSockets[i].socket;
m_ssbSockets.removeAt(i);
break;
}
}
if(socket == NULL) {
for(int i = 0; i < m_s16leSockets.count(); i++) {
if(m_s16leSockets[i].socket == sender()) {
if(socket == 0)
{
for(int i = 0; i < m_s16leSockets.count(); i++)
{
if(m_s16leSockets[i].socket == sender())
{
id = m_s16leSockets[i].id;
socket = m_s16leSockets[i].socket;
m_s16leSockets.removeAt(i);
@ -266,9 +313,11 @@ void TCPSrc::onDisconnected()
}
}
}
if(socket != NULL) {
if(socket != 0)
{
MsgTCPSrcConnection* msg = MsgTCPSrcConnection::create(false, id, QHostAddress(), 0);
msg->submit(m_uiMessageQueue, (PluginGUI*)m_tcpSrcGUI);
m_uiMessageQueue->push(msg);
socket->deleteLater();
}
}

View File

@ -26,15 +26,15 @@ public:
};
TCPSrc(MessageQueue* uiMessageQueue, TCPSrcGUI* tcpSrcGUI, SampleSink* spectrum);
~TCPSrc();
virtual ~TCPSrc();
void configure(MessageQueue* messageQueue, SampleFormat sampleFormat, Real outputSampleRate, Real rfBandwidth, int tcpPort, int boost);
void setSpectrum(MessageQueue* messageQueue, bool enabled);
void feed(SampleVector::const_iterator begin, SampleVector::const_iterator end, bool positiveOnly);
void start();
void stop();
bool handleMessage(Message* cmd);
virtual void feed(SampleVector::const_iterator begin, SampleVector::const_iterator end, bool positiveOnly);
virtual void start();
virtual void stop();
virtual bool handleMessage(const Message& cmd);
class MsgTCPSrcConnection : public Message {
MESSAGE_CLASS_DECLARATION

View File

@ -3,7 +3,7 @@
#include "tcpsrc.h"
#include "dsp/channelizer.h"
#include "dsp/spectrumvis.h"
#include "dsp/threadedsamplesink.h"
#include "dsp/dspengine.h"
#include "util/simpleserializer.h"
#include "gui/basicchannelsettingswidget.h"
#include "ui_tcpsrcgui.h"
@ -64,12 +64,14 @@ bool TCPSrcGUI::deserialize(const QByteArray& data)
{
SimpleDeserializer d(data);
if(!d.isValid()) {
if (!d.isValid())
{
resetToDefaults();
return false;
}
if(d.getVersion() == 1) {
if (d.getVersion() == 1)
{
QByteArray bytetmp;
qint32 s32tmp;
Real realtmp;
@ -104,22 +106,39 @@ bool TCPSrcGUI::deserialize(const QByteArray& data)
ui->boost->setValue(s32tmp);
applySettings();
return true;
} else {
}
else
{
resetToDefaults();
return false;
}
}
bool TCPSrcGUI::handleMessage(Message* message)
bool TCPSrcGUI::handleMessage(const Message& message)
{
if(TCPSrc::MsgTCPSrcConnection::match(message)) {
TCPSrc::MsgTCPSrcConnection* con = (TCPSrc::MsgTCPSrcConnection*)message;
if(con->getConnect())
addConnection(con->getID(), con->getPeerAddress(), con->getPeerPort());
else delConnection(con->getID());
message->completed();
qDebug() << "TCPSrcGUI::handleMessage";
if (TCPSrc::MsgTCPSrcConnection::match(message))
{
TCPSrc::MsgTCPSrcConnection& con = (TCPSrc::MsgTCPSrcConnection&) message;
if(con.getConnect())
{
addConnection(con.getID(), con.getPeerAddress(), con.getPeerPort());
}
else
{
delConnection(con.getID());
}
qDebug() << " - TCPSrc::MsgTCPSrcConnection: ID: " << con.getID()
<< " peerAddress: " << con.getPeerAddress()
<< " peerPort: " << con.getPeerPort();
return true;
} else {
}
else
{
return false;
}
}
@ -145,14 +164,13 @@ TCPSrcGUI::TCPSrcGUI(PluginAPI* pluginAPI, QWidget* parent) :
m_spectrumVis = new SpectrumVis(ui->glSpectrum);
m_tcpSrc = new TCPSrc(m_pluginAPI->getMainWindowMessageQueue(), this, m_spectrumVis);
m_channelizer = new Channelizer(m_tcpSrc);
m_threadedSampleSink = new ThreadedSampleSink(m_channelizer);
m_pluginAPI->addSampleSink(m_threadedSampleSink);
DSPEngine::instance()->addThreadedSink(m_channelizer);
ui->glSpectrum->setCenterFrequency(0);
ui->glSpectrum->setSampleRate(ui->sampleRate->text().toInt());
ui->glSpectrum->setDisplayWaterfall(true);
ui->glSpectrum->setDisplayMaxHold(true);
m_spectrumVis->configure(m_threadedSampleSink->getMessageQueue(), 64, 10, FFTWindow::BlackmanHarris);
m_spectrumVis->configure(m_spectrumVis->getInputMessageQueue(), 64, 10, FFTWindow::BlackmanHarris);
m_channelMarker = new ChannelMarker(this);
m_channelMarker->setBandwidth(16000);
@ -162,7 +180,7 @@ TCPSrcGUI::TCPSrcGUI(PluginAPI* pluginAPI, QWidget* parent) :
connect(m_channelMarker, SIGNAL(changed()), this, SLOT(channelMarkerChanged()));
m_pluginAPI->addChannelMarker(m_channelMarker);
ui->spectrumGUI->setBuddies(m_threadedSampleSink->getMessageQueue(), m_spectrumVis, ui->glSpectrum);
ui->spectrumGUI->setBuddies(m_spectrumVis->getInputMessageQueue(), m_spectrumVis, ui->glSpectrum);
applySettings();
}
@ -170,8 +188,7 @@ TCPSrcGUI::TCPSrcGUI(PluginAPI* pluginAPI, QWidget* parent) :
TCPSrcGUI::~TCPSrcGUI()
{
m_pluginAPI->removeChannelInstance(this);
m_pluginAPI->removeSampleSink(m_threadedSampleSink);
delete m_threadedSampleSink;
DSPEngine::instance()->removeThreadedSink(m_channelizer);
delete m_channelizer;
delete m_tcpSrc;
delete m_spectrumVis;
@ -184,14 +201,26 @@ void TCPSrcGUI::applySettings()
bool ok;
Real outputSampleRate = ui->sampleRate->text().toDouble(&ok);
if((!ok) || (outputSampleRate < 1000))
{
outputSampleRate = 48000;
}
Real rfBandwidth = ui->rfBandwidth->text().toDouble(&ok);
if((!ok) || (rfBandwidth > outputSampleRate))
{
rfBandwidth = outputSampleRate;
}
int tcpPort = ui->tcpPort->text().toInt(&ok);
if((!ok) || (tcpPort < 1) || (tcpPort > 65535))
{
tcpPort = 9999;
}
int boost = ui->boost->value();
setTitleColor(m_channelMarker->getColor());
@ -204,12 +233,14 @@ void TCPSrcGUI::applySettings()
connect(m_channelMarker, SIGNAL(changed()), this, SLOT(channelMarkerChanged()));
ui->glSpectrum->setSampleRate(outputSampleRate);
m_channelizer->configure(m_threadedSampleSink->getMessageQueue(),
m_channelizer->configure(m_channelizer->getInputMessageQueue(),
outputSampleRate,
m_channelMarker->getCenterFrequency());
TCPSrc::SampleFormat sampleFormat;
switch(ui->sampleFormat->currentIndex()) {
switch(ui->sampleFormat->currentIndex())
{
case 0:
sampleFormat = TCPSrc::FormatSSB;
break;
@ -230,7 +261,7 @@ void TCPSrcGUI::applySettings()
m_tcpPort = tcpPort;
m_boost = boost;
m_tcpSrc->configure(m_threadedSampleSink->getMessageQueue(),
m_tcpSrc->configure(m_tcpSrc->getInputMessageQueue(),
sampleFormat,
outputSampleRate,
rfBandwidth,
@ -273,13 +304,16 @@ void TCPSrcGUI::on_boost_valueChanged(int value)
void TCPSrcGUI::onWidgetRolled(QWidget* widget, bool rollDown)
{
if((widget == ui->spectrumBox) && (m_tcpSrc != NULL))
m_tcpSrc->setSpectrum(m_threadedSampleSink->getMessageQueue(), rollDown);
if ((widget == ui->spectrumBox) && (m_tcpSrc != 0))
{
m_tcpSrc->setSpectrum(m_tcpSrc->getInputMessageQueue(), rollDown);
}
}
void TCPSrcGUI::onMenuDoubleClicked()
{
if(!m_basicSettingsShown) {
if (!m_basicSettingsShown)
{
m_basicSettingsShown = true;
BasicChannelSettingsWidget* bcsw = new BasicChannelSettingsWidget(m_channelMarker, this);
bcsw->show();
@ -296,8 +330,10 @@ void TCPSrcGUI::addConnection(quint32 id, const QHostAddress& peerAddress, int p
void TCPSrcGUI::delConnection(quint32 id)
{
for(int i = 0; i < ui->connections->topLevelItemCount(); i++) {
if(ui->connections->topLevelItem(i)->type() == (int)id) {
for(int i = 0; i < ui->connections->topLevelItemCount(); i++)
{
if(ui->connections->topLevelItem(i)->type() == (int)id)
{
delete ui->connections->topLevelItem(i);
ui->connectedClientsBox->setWindowTitle(tr("Connected Clients (%1)").arg(ui->connections->topLevelItemCount()));
return;

View File

@ -8,7 +8,6 @@
class PluginAPI;
class ChannelMarker;
class ThreadedSampleSink;
class Channelizer;
class TCPSrc;
class SpectrumVis;
@ -32,7 +31,7 @@ public:
QByteArray serialize() const;
bool deserialize(const QByteArray& data);
bool handleMessage(Message* message);
virtual bool handleMessage(const Message& message);
private slots:
void channelMarkerChanged();
@ -59,12 +58,11 @@ private:
bool m_basicSettingsShown;
// RF path
ThreadedSampleSink* m_threadedSampleSink;
Channelizer* m_channelizer;
SpectrumVis* m_spectrumVis;
explicit TCPSrcGUI(PluginAPI* pluginAPI, QWidget* parent = NULL);
~TCPSrcGUI();
virtual ~TCPSrcGUI();
void applySettings();

View File

@ -16,6 +16,7 @@
///////////////////////////////////////////////////////////////////////////////////
#include <QTime>
#include <QDebug>
#include <stdio.h>
#include <complex.h>
#include "audio/audiooutput.h"
@ -51,13 +52,15 @@ WFMDemod::WFMDemod(AudioFifo* audioFifo, SampleSink* sampleSink) :
WFMDemod::~WFMDemod()
{
if (m_rfFilter)
{
delete m_rfFilter;
}
}
void WFMDemod::configure(MessageQueue* messageQueue, Real rfBandwidth, Real afBandwidth, Real volume, Real squelch)
{
Message* cmd = MsgConfigureWFMDemod::create(rfBandwidth, afBandwidth, volume, squelch);
cmd->submit(messageQueue, this);
messageQueue->push(cmd);
}
void WFMDemod::feed(SampleVector::const_iterator begin, SampleVector::const_iterator end, bool firstOfBurst)
@ -79,13 +82,6 @@ void WFMDemod::feed(SampleVector::const_iterator begin, SampleVector::const_iter
for (int i =0 ; i <rf_out; i++)
{
/*
// atan2 version
Real x = rf[i].real() * m_lastSample.real() + rf[i].imag() * m_lastSample.imag();
Real y = rf[i].real() * m_m1Sample.imag() - rf[i].imag() * m_m1Sample.real();
Real demod = atan2(x,y) / M_PI;
*/
msq = rf[i].real()*rf[i].real() + rf[i].imag()*rf[i].imag();
m_movingAverage.feed(msq);
@ -135,89 +131,6 @@ void WFMDemod::feed(SampleVector::const_iterator begin, SampleVector::const_iter
m_interpolatorDistanceRemain += m_interpolatorDistance;
}
}
#if 0
{
if(m_interpolator.interpolate(&m_interpolatorDistanceRemain, e, &ci))
{
m_sampleBuffer.push_back(Sample(ci.real() * 32767.0, ci.imag() * 32767.0));
m_movingAverage.feed(ci.real() * ci.real() + ci.imag() * ci.imag());
if(m_movingAverage.average() >= m_squelchLevel)
m_squelchState = m_running.m_audioSampleRate/ 20;
qint16 sample;
if(m_squelchState > 0) {
m_squelchState--;
/*
Real argument = arg(ci);
argument /= M_PI;
Real demod = argument - m_lastArgument;
m_lastArgument = argument;
*/
//ci *= 32768.0;
/*
Complex d = conj(m_lastSample) * ci;
m_lastSample = ci;
Real demod = atan2(d.imag(), d.real());
*/
//m_lastSample = ci;
/*
Real argument = atan2(ci.real()*m_lastSample.imag() - m_lastSample.real()*ci.imag(),
ci.real()*m_lastSample.real() + ci.imag()*m_lastSample.imag());
argument /= M_PI;
Real demod = argument - m_lastArgument;
m_lastArgument = argument;
m_lastSample = ci;
*/
//Real demod = arctan2(d.imag(), d.real());
/*
Real argument1 = arg(ci);//atan2(ci.imag(), ci.real());
Real argument2 = m_lastSample.real();
Real demod = angleDist(argument2, argument1);
m_lastSample = Complex(argument1, 0);
*/
//demod /= M_PI;
demod = m_lowpass.filter(demod);
/*
if(demod < -1)
demod = -1;
else if(demod > 1)
demod = 1;
*/
demod *= m_running.m_volume;
sample = demod * 64;
} else {
sample = 0;
}
m_audioBuffer[m_audioBufferFill].l = sample;
m_audioBuffer[m_audioBufferFill].r = sample;
++m_audioBufferFill;
if(m_audioBufferFill >= m_audioBuffer.size()) {
uint res = m_audioFifo->write((const quint8*)&m_audioBuffer[0], m_audioBufferFill, 1);
if(res != m_audioBufferFill)
qDebug("lost %u audio samples", m_audioBufferFill - res);
m_audioBufferFill = 0;
}
m_interpolatorDistanceRemain += m_interpolatorDistance;
}
}
#endif
}
if(m_audioBufferFill > 0) {
@ -246,28 +159,50 @@ void WFMDemod::stop()
{
}
bool WFMDemod::handleMessage(Message* cmd)
bool WFMDemod::handleMessage(const Message& cmd)
{
if(DSPSignalNotification::match(cmd)) {
DSPSignalNotification* signal = (DSPSignalNotification*)cmd;
qDebug() << "WFMDemod::handleMessage";
m_config.m_inputSampleRate = signal->getSampleRate();
m_config.m_inputFrequencyOffset = signal->getFrequencyOffset();
if (DSPSignalNotification::match(cmd))
{
DSPSignalNotification& notif = (DSPSignalNotification&) cmd;
m_config.m_inputSampleRate = notif.getSampleRate();
m_config.m_inputFrequencyOffset = notif.getFrequencyOffset();
apply();
cmd->completed();
qDebug() << " - DSPSignalNotification: m_inputSampleRate: " << m_config.m_inputSampleRate
<< " m_inputFrequencyOffset: " << m_config.m_inputFrequencyOffset;
return true;
} else if(MsgConfigureWFMDemod::match(cmd)) {
MsgConfigureWFMDemod* cfg = (MsgConfigureWFMDemod*)cmd;
m_config.m_rfBandwidth = cfg->getRFBandwidth();
m_config.m_afBandwidth = cfg->getAFBandwidth();
m_config.m_volume = cfg->getVolume();
m_config.m_squelch = cfg->getSquelch();
}
else if (MsgConfigureWFMDemod::match(cmd))
{
MsgConfigureWFMDemod& cfg = (MsgConfigureWFMDemod&) cmd;
m_config.m_rfBandwidth = cfg.getRFBandwidth();
m_config.m_afBandwidth = cfg.getAFBandwidth();
m_config.m_volume = cfg.getVolume();
m_config.m_squelch = cfg.getSquelch();
apply();
qDebug() << " - MsgConfigureWFMDemod: m_rfBandwidth: " << m_config.m_rfBandwidth
<< " m_afBandwidth: " << m_config.m_afBandwidth
<< " m_volume: " << m_config.m_volume
<< " m_squelch: " << m_config.m_squelch;
return true;
} else {
if(m_sampleSink != NULL)
}
else
{
if (m_sampleSink != 0)
{
return m_sampleSink->handleMessage(cmd);
else return false;
}
else
{
return false;
}
}
}

View File

@ -35,14 +35,14 @@ class AudioFifo;
class WFMDemod : public SampleSink {
public:
WFMDemod(AudioFifo* audioFifo, SampleSink* sampleSink);
~WFMDemod();
virtual ~WFMDemod();
void configure(MessageQueue* messageQueue, Real rfBandwidth, Real afBandwidth, Real volume, Real squelch);
void feed(SampleVector::const_iterator begin, SampleVector::const_iterator end, bool po);
void start();
void stop();
bool handleMessage(Message* cmd);
virtual void feed(SampleVector::const_iterator begin, SampleVector::const_iterator end, bool po);
virtual void start();
virtual void stop();
virtual bool handleMessage(const Message& cmd);
private:
class MsgConfigureWFMDemod : public Message {

View File

@ -1,9 +1,10 @@
#include <QDockWidget>
#include <QMainWindow>
#include <QDebug>
#include "ui_wfmdemodgui.h"
#include "dsp/threadedsamplesink.h"
#include "dsp/channelizer.h"
#include "dsp/nullsink.h"
#include "dsp/dspengine.h"
#include "gui/glspectrum.h"
#include "plugin/pluginapi.h"
#include "util/simpleserializer.h"
@ -79,12 +80,14 @@ bool WFMDemodGUI::deserialize(const QByteArray& data)
{
SimpleDeserializer d(data);
if(!d.isValid()) {
if (!d.isValid())
{
resetToDefaults();
return false;
}
if(d.getVersion() == 1) {
if (d.getVersion() == 1)
{
QByteArray bytetmp;
quint32 u32tmp;
qint32 tmp;
@ -104,13 +107,15 @@ bool WFMDemodGUI::deserialize(const QByteArray& data)
m_channelMarker->setColor(u32tmp);
applySettings();
return true;
} else {
}
else
{
resetToDefaults();
return false;
}
}
bool WFMDemodGUI::handleMessage(Message* message)
bool WFMDemodGUI::handleMessage(const Message& message)
{
return false;
}
@ -133,9 +138,12 @@ void WFMDemodGUI::on_deltaMinus_clicked(bool minus)
void WFMDemodGUI::on_deltaFrequency_changed(quint64 value)
{
if (ui->deltaMinus->isChecked()) {
if (ui->deltaMinus->isChecked())
{
m_channelMarker->setCenterFrequency(-value);
} else {
}
else
{
m_channelMarker->setCenterFrequency(value);
}
}
@ -172,7 +180,8 @@ void WFMDemodGUI::onWidgetRolled(QWidget* widget, bool rollDown)
void WFMDemodGUI::onMenuDoubleClicked()
{
if(!m_basicSettingsShown) {
if(!m_basicSettingsShown)
{
m_basicSettingsShown = true;
BasicChannelSettingsWidget* bcsw = new BasicChannelSettingsWidget(m_channelMarker, this);
bcsw->show();
@ -191,12 +200,10 @@ WFMDemodGUI::WFMDemodGUI(PluginAPI* pluginAPI, QWidget* parent) :
connect(this, SIGNAL(menuDoubleClickEvent()), this, SLOT(onMenuDoubleClicked()));
m_audioFifo = new AudioFifo(4, 250000); // TODO: check. Room for 1s FIFO at max rate
m_nullSink = new NullSink();
m_wfmDemod = new WFMDemod(m_audioFifo, m_nullSink);
m_wfmDemod = new WFMDemod(m_audioFifo, 0);
m_channelizer = new Channelizer(m_wfmDemod);
m_threadedSampleSink = new ThreadedSampleSink(m_channelizer);
m_pluginAPI->addAudioSource(m_audioFifo);
m_pluginAPI->addSampleSink(m_threadedSampleSink);
DSPEngine::instance()->addAudioSink(m_audioFifo);
DSPEngine::instance()->addThreadedSink(m_channelizer);
m_channelMarker = new ChannelMarker(this);
m_channelMarker->setColor(Qt::blue);
@ -212,12 +219,10 @@ WFMDemodGUI::WFMDemodGUI(PluginAPI* pluginAPI, QWidget* parent) :
WFMDemodGUI::~WFMDemodGUI()
{
m_pluginAPI->removeChannelInstance(this);
m_pluginAPI->removeAudioSource(m_audioFifo);
m_pluginAPI->removeSampleSink(m_threadedSampleSink);
delete m_threadedSampleSink;
DSPEngine::instance()->removeAudioSink(m_audioFifo);
DSPEngine::instance()->removeThreadedSink(m_channelizer);
delete m_channelizer;
delete m_wfmDemod;
delete m_nullSink;
delete m_audioFifo;
delete m_channelMarker;
delete ui;
@ -226,12 +231,15 @@ WFMDemodGUI::~WFMDemodGUI()
void WFMDemodGUI::applySettings()
{
setTitleColor(m_channelMarker->getColor());
m_channelizer->configure(m_threadedSampleSink->getMessageQueue(),
m_channelizer->configure(m_channelizer->getInputMessageQueue(),
requiredBW(m_rfBW[ui->rfBW->value()]), // TODO: this is where requested sample rate is specified
m_channelMarker->getCenterFrequency());
ui->deltaFrequency->setValue(abs(m_channelMarker->getCenterFrequency()));
ui->deltaMinus->setChecked(m_channelMarker->getCenterFrequency() < 0);
m_wfmDemod->configure(m_threadedSampleSink->getMessageQueue(),
m_wfmDemod->configure(m_wfmDemod->getInputMessageQueue(),
m_rfBW[ui->rfBW->value()],
ui->afBW->value() * 1000.0,
ui->volume->value() / 10.0,

View File

@ -8,10 +8,8 @@ class PluginAPI;
class ChannelMarker;
class AudioFifo;
class ThreadedSampleSink;
class Channelizer;
class WFMDemod;
class NullSink;
namespace Ui {
class WFMDemodGUI;
@ -32,7 +30,7 @@ public:
QByteArray serialize() const;
bool deserialize(const QByteArray& data);
bool handleMessage(Message* message);
virtual bool handleMessage(const Message& message);
private slots:
void viewChanged();
@ -52,15 +50,13 @@ private:
bool m_basicSettingsShown;
AudioFifo* m_audioFifo;
ThreadedSampleSink* m_threadedSampleSink;
Channelizer* m_channelizer;
WFMDemod* m_wfmDemod;
NullSink *m_nullSink;
static const int m_rfBW[];
explicit WFMDemodGUI(PluginAPI* pluginAPI, QWidget* parent = NULL);
~WFMDemodGUI();
virtual ~WFMDemodGUI();
void applySettings();

View File

@ -20,6 +20,7 @@
#include "ui_bladerfgui.h"
#include "plugin/pluginapi.h"
#include "gui/colormapper.h"
#include "dsp/dspengine.h"
#include "bladerfgui.h"
BladerfGui::BladerfGui(PluginAPI* pluginAPI, QWidget* parent) :
@ -35,8 +36,8 @@ BladerfGui::BladerfGui(PluginAPI* pluginAPI, QWidget* parent) :
connect(&m_updateTimer, SIGNAL(timeout()), this, SLOT(updateHardware()));
displaySettings();
m_sampleSource = new BladerfInput(m_pluginAPI->getMainWindowMessageQueue());
m_pluginAPI->setSampleSource(m_sampleSource);
m_sampleSource = new BladerfInput();
DSPEngine::instance()->setSource(m_sampleSource);
}
BladerfGui::~BladerfGui()
@ -61,32 +62,14 @@ QString BladerfGui::getName() const
void BladerfGui::resetToDefaults()
{
m_generalSettings.resetToDefaults();
m_settings.resetToDefaults();
displaySettings();
sendSettings();
}
QByteArray BladerfGui::serializeGeneral() const
{
return m_generalSettings.serialize();
}
bool BladerfGui::deserializeGeneral(const QByteArray&data)
{
if(m_generalSettings.deserialize(data)) {
displaySettings();
sendSettings();
return true;
} else {
resetToDefaults();
return false;
}
}
qint64 BladerfGui::getCenterFrequency() const
{
return m_generalSettings.m_centerFrequency;
return m_settings.m_centerFrequency;
}
QByteArray BladerfGui::serialize() const
@ -106,23 +89,25 @@ bool BladerfGui::deserialize(const QByteArray& data)
}
}
bool BladerfGui::handleMessage(Message* message)
bool BladerfGui::handleMessage(const Message& message)
{
if(BladerfInput::MsgReportBladerf::match(message)) {
if (BladerfInput::MsgReportBladerf::match(message))
{
displaySettings();
message->completed();
return true;
} else {
}
else
{
return false;
}
}
void BladerfGui::displaySettings()
{
ui->centerFrequency->setValue(m_generalSettings.m_centerFrequency / 1000);
ui->centerFrequency->setValue(m_settings.m_centerFrequency / 1000);
ui->samplerateText->setText(tr("%1k").arg(m_settings.m_samplerate / 1000));
unsigned int sampleRateIndex = BladerfSampleRates::getRateIndex(m_settings.m_samplerate);
ui->samplerateText->setText(tr("%1k").arg(m_settings.m_devSampleRate / 1000));
unsigned int sampleRateIndex = BladerfSampleRates::getRateIndex(m_settings.m_devSampleRate);
ui->samplerate->setValue(sampleRateIndex);
ui->bandwidthText->setText(tr("%1k").arg(m_settings.m_bandwidth / 1000));
@ -154,7 +139,7 @@ void BladerfGui::sendSettings()
void BladerfGui::on_centerFrequency_changed(quint64 value)
{
m_generalSettings.m_centerFrequency = value * 1000;
m_settings.m_centerFrequency = value * 1000;
sendSettings();
}
@ -162,7 +147,7 @@ void BladerfGui::on_samplerate_valueChanged(int value)
{
int newrate = BladerfSampleRates::getRate(value);
ui->samplerateText->setText(tr("%1k").arg(newrate));
m_settings.m_samplerate = newrate * 1000;
m_settings.m_devSampleRate = newrate * 1000;
sendSettings();
}
@ -291,8 +276,8 @@ void BladerfGui::on_xb200_currentIndexChanged(int index)
void BladerfGui::updateHardware()
{
BladerfInput::MsgConfigureBladerf* message = BladerfInput::MsgConfigureBladerf::create(m_generalSettings, m_settings);
message->submit(m_pluginAPI->getDSPEngineMessageQueue());
BladerfInput::MsgConfigureBladerf* message = BladerfInput::MsgConfigureBladerf::create( m_settings);
m_sampleSource->getInputMessageQueue()->push(message);
m_updateTimer.stop();
}

View File

@ -34,25 +34,22 @@ class BladerfGui : public QWidget, public PluginGUI {
public:
explicit BladerfGui(PluginAPI* pluginAPI, QWidget* parent = NULL);
~BladerfGui();
virtual ~BladerfGui();
void destroy();
void setName(const QString& name);
QString getName() const;
void resetToDefaults();
QByteArray serializeGeneral() const;
bool deserializeGeneral(const QByteArray&data);
qint64 getCenterFrequency() const;
QByteArray serialize() const;
bool deserialize(const QByteArray& data);
bool handleMessage(Message* message);
virtual bool handleMessage(const Message& message);
private:
Ui::BladerfGui* ui;
PluginAPI* m_pluginAPI;
SampleSource::GeneralSettings m_generalSettings;
BladerfInput::Settings m_settings;
QTimer m_updateTimer;
std::vector<int> m_gains;

View File

@ -29,10 +29,11 @@ MESSAGE_CLASS_DEFINITION(BladerfInput::MsgConfigureBladerf, Message)
MESSAGE_CLASS_DEFINITION(BladerfInput::MsgReportBladerf, Message)
BladerfInput::Settings::Settings() :
m_centerFrequency(435000*1000),
m_devSampleRate(3072000),
m_lnaGain(0),
m_vga1(20),
m_vga2(9),
m_samplerate(3072000),
m_bandwidth(1500000),
m_log2Decim(0),
m_fcPos(FC_POS_INFRA),
@ -44,10 +45,11 @@ BladerfInput::Settings::Settings() :
void BladerfInput::Settings::resetToDefaults()
{
m_centerFrequency = 435000*1000;
m_devSampleRate = 3072000;
m_lnaGain = 0;
m_vga1 = 20;
m_vga2 = 9;
m_samplerate = 3072000;
m_bandwidth = 1500000;
m_log2Decim = 0;
m_fcPos = FC_POS_INFRA;
@ -59,16 +61,17 @@ void BladerfInput::Settings::resetToDefaults()
QByteArray BladerfInput::Settings::serialize() const
{
SimpleSerializer s(1);
s.writeS32(1, m_lnaGain);
s.writeS32(2, m_vga1);
s.writeS32(3, m_vga2);
s.writeS32(4, m_samplerate);
s.writeU32(5, m_log2Decim);
s.writeBool(6, m_xb200);
s.writeS32(7, (int) m_xb200Path);
s.writeS32(8, (int) m_xb200Filter);
s.writeS32(9, m_bandwidth);
s.writeS32(10, (int) m_fcPos);
s.writeU64(1, m_centerFrequency);
s.writeS32(2, m_devSampleRate);
s.writeS32(3, m_lnaGain);
s.writeS32(4, m_vga1);
s.writeS32(5, m_vga2);
s.writeU32(6, m_log2Decim);
s.writeBool(7, m_xb200);
s.writeS32(8, (int) m_xb200Path);
s.writeS32(9, (int) m_xb200Filter);
s.writeS32(10, m_bandwidth);
s.writeS32(11, (int) m_fcPos);
return s.final();
}
@ -76,63 +79,75 @@ bool BladerfInput::Settings::deserialize(const QByteArray& data)
{
SimpleDeserializer d(data);
if(!d.isValid()) {
if (!d.isValid())
{
resetToDefaults();
return false;
}
if(d.getVersion() == 1) {
if (d.getVersion() == 1)
{
int intval;
d.readS32(1, &m_lnaGain, 0);
d.readS32(2, &m_vga1, 20);
d.readS32(3, &m_vga2, 9);
d.readS32(4, &m_samplerate, 0);
d.readU32(5, &m_log2Decim, 0);
d.readBool(6, &m_xb200);
d.readS32(7, &intval);
m_xb200Path = (bladerf_xb200_path) intval;
d.readU64(1, &m_centerFrequency, 435000*1000);
d.readS32(2, &m_devSampleRate, 3072000);
d.readS32(3, &m_lnaGain, 0);
d.readS32(4, &m_vga1, 20);
d.readS32(5, &m_vga2, 9);
d.readU32(6, &m_log2Decim, 0);
d.readBool(7, &m_xb200);
d.readS32(8, &intval);
m_xb200Path = (bladerf_xb200_path) intval;
d.readS32(9, &intval);
m_xb200Filter = (bladerf_xb200_filter) intval;
d.readS32(9, &m_bandwidth, 0);
d.readS32(10, &intval, 0);
d.readS32(10, &m_bandwidth, 0);
d.readS32(11, &intval, 0);
m_fcPos = (fcPos_t) intval;
return true;
} else {
}
else
{
resetToDefaults();
return false;
}
}
BladerfInput::BladerfInput(MessageQueue* msgQueueToGUI) :
SampleSource(msgQueueToGUI),
BladerfInput::BladerfInput() :
m_settings(),
m_dev(NULL),
m_bladerfThread(NULL),
m_dev(0),
m_bladerfThread(0),
m_deviceDescription("BladeRF")
{
}
BladerfInput::~BladerfInput()
{
stopInput();
stop();
}
bool BladerfInput::startInput(int device)
bool BladerfInput::init(const Message& cmd)
{
return false;
}
bool BladerfInput::start(int device)
{
QMutexLocker mutexLocker(&m_mutex);
if(m_dev != NULL)
stopInput();
if (m_dev != 0)
{
stop();
}
int res;
int fpga_loaded;
if(!m_sampleFifo.setSize(96000 * 4)) {
if (!m_sampleFifo.setSize(96000 * 4))
{
qCritical("Could not allocate SampleFifo");
return false;
}
if ((m_dev = open_bladerf_from_serial(0)) == NULL) // TODO: fix; Open first available device as there is no proper handling for multiple devices
if ((m_dev = open_bladerf_from_serial(0)) == 0) // TODO: fix; Open first available device as there is no proper handling for multiple devices
{
qCritical("could not open BladeRF");
return false;
@ -140,11 +155,14 @@ bool BladerfInput::startInput(int device)
fpga_loaded = bladerf_is_fpga_configured(m_dev);
if (fpga_loaded < 0) {
if (fpga_loaded < 0)
{
qCritical("Failed to check FPGA state: %s",
bladerf_strerror(fpga_loaded));
return false;
} else if (fpga_loaded == 0) {
}
else if (fpga_loaded == 0)
{
qCritical("The device's FPGA is not loaded.");
return false;
}
@ -170,31 +188,34 @@ bool BladerfInput::startInput(int device)
m_bladerfThread->startWork();
mutexLocker.unlock();
applySettings(m_generalSettings, m_settings, true);
applySettings(m_settings, true);
qDebug("BladerfInput::startInput: started");
//MsgReportBladerf::create(m_gains)->submit(m_guiMessageQueue); Pass anything here
return true;
failed:
stopInput();
stop();
return false;
}
void BladerfInput::stopInput()
void BladerfInput::stop()
{
QMutexLocker mutexLocker(&m_mutex);
if(m_bladerfThread != NULL) {
if(m_bladerfThread != 0)
{
m_bladerfThread->stopWork();
delete m_bladerfThread;
m_bladerfThread = NULL;
m_bladerfThread = 0;
}
if(m_dev != NULL) {
if(m_dev != 0)
{
bladerf_close(m_dev);
m_dev = NULL;
m_dev = 0;
}
m_deviceDescription.clear();
}
@ -205,28 +226,28 @@ const QString& BladerfInput::getDeviceDescription() const
int BladerfInput::getSampleRate() const
{
int rate = m_settings.m_samplerate;
int rate = m_settings.m_devSampleRate;
return (rate / (1<<m_settings.m_log2Decim));
}
quint64 BladerfInput::getCenterFrequency() const
{
return m_generalSettings.m_centerFrequency;
return m_settings.m_centerFrequency;
}
bool BladerfInput::handleMessage(Message* message)
bool BladerfInput::handleMessage(const Message& message)
{
if (MsgConfigureBladerf::match(message))
{
qDebug() << "BladerfInput::handleMessage: MsgConfigureBladerf";
MsgConfigureBladerf* conf = (MsgConfigureBladerf*) message;
MsgConfigureBladerf& conf = (MsgConfigureBladerf&) message;
if(!applySettings(conf->getGeneralSettings(), conf->getSettings(), false)) {
if (!applySettings(conf.getSettings(), false))
{
qDebug("BladeRF config error");
}
message->completed();
return true;
}
else
@ -235,7 +256,7 @@ bool BladerfInput::handleMessage(Message* message)
}
}
bool BladerfInput::applySettings(const GeneralSettings& generalSettings, const Settings& settings, bool force)
bool BladerfInput::applySettings(const Settings& settings, bool force)
{
QMutexLocker mutexLocker(&m_mutex);
@ -245,11 +266,14 @@ bool BladerfInput::applySettings(const GeneralSettings& generalSettings, const S
{
m_settings.m_lnaGain = settings.m_lnaGain;
if (m_dev != NULL)
if (m_dev != 0)
{
if(bladerf_set_lna_gain(m_dev, getLnaGain(m_settings.m_lnaGain)) != 0) {
if(bladerf_set_lna_gain(m_dev, getLnaGain(m_settings.m_lnaGain)) != 0)
{
qDebug("bladerf_set_lna_gain() failed");
} else {
}
else
{
qDebug() << "BladerfInput: LNA gain set to " << getLnaGain(m_settings.m_lnaGain);
}
}
@ -259,11 +283,14 @@ bool BladerfInput::applySettings(const GeneralSettings& generalSettings, const S
{
m_settings.m_vga1 = settings.m_vga1;
if (m_dev != NULL)
if (m_dev != 0)
{
if(bladerf_set_rxvga1(m_dev, m_settings.m_vga1) != 0) {
if(bladerf_set_rxvga1(m_dev, m_settings.m_vga1) != 0)
{
qDebug("bladerf_set_rxvga1() failed");
} else {
}
else
{
qDebug() << "BladerfInput: VGA1 gain set to " << m_settings.m_vga1;
}
}
@ -273,11 +300,14 @@ bool BladerfInput::applySettings(const GeneralSettings& generalSettings, const S
{
m_settings.m_vga2 = settings.m_vga2;
if(m_dev != NULL)
if(m_dev != 0)
{
if(bladerf_set_rxvga2(m_dev, m_settings.m_vga2) != 0) {
if(bladerf_set_rxvga2(m_dev, m_settings.m_vga2) != 0)
{
qDebug("bladerf_set_rxvga2() failed");
} else {
}
else
{
qDebug() << "BladerfInput: VGA2 gain set to " << m_settings.m_vga2;
}
}
@ -287,21 +317,27 @@ bool BladerfInput::applySettings(const GeneralSettings& generalSettings, const S
{
m_settings.m_xb200 = settings.m_xb200;
if (m_dev != NULL)
if (m_dev != 0)
{
if (m_settings.m_xb200)
{
if (bladerf_expansion_attach(m_dev, BLADERF_XB_200) != 0) {
if (bladerf_expansion_attach(m_dev, BLADERF_XB_200) != 0)
{
qDebug("bladerf_expansion_attach(xb200) failed");
} else {
}
else
{
qDebug() << "BladerfInput: Attach XB200";
}
}
else
{
if (bladerf_expansion_attach(m_dev, BLADERF_XB_NONE) != 0) {
if (bladerf_expansion_attach(m_dev, BLADERF_XB_NONE) != 0)
{
qDebug("bladerf_expansion_attach(none) failed");
} else {
}
else
{
qDebug() << "BladerfInput: Detach XB200";
}
}
@ -311,11 +347,15 @@ bool BladerfInput::applySettings(const GeneralSettings& generalSettings, const S
if ((m_settings.m_xb200Path != settings.m_xb200Path) || force)
{
m_settings.m_xb200Path = settings.m_xb200Path;
if (m_dev != NULL)
if (m_dev != 0)
{
if(bladerf_xb200_set_path(m_dev, BLADERF_MODULE_RX, m_settings.m_xb200Path) != 0) {
if(bladerf_xb200_set_path(m_dev, BLADERF_MODULE_RX, m_settings.m_xb200Path) != 0)
{
qDebug("bladerf_xb200_set_path(BLADERF_MODULE_RX) failed");
} else {
}
else
{
qDebug() << "BladerfInput: set xb200 path to " << m_settings.m_xb200Path;
}
}
@ -325,32 +365,35 @@ bool BladerfInput::applySettings(const GeneralSettings& generalSettings, const S
{
m_settings.m_xb200Filter = settings.m_xb200Filter;
if(m_dev != NULL)
if (m_dev != 0)
{
if(bladerf_xb200_set_filterbank(m_dev, BLADERF_MODULE_RX, m_settings.m_xb200Filter) != 0) {
if(bladerf_xb200_set_filterbank(m_dev, BLADERF_MODULE_RX, m_settings.m_xb200Filter) != 0)
{
qDebug("bladerf_xb200_set_filterbank(BLADERF_MODULE_RX) failed");
} else {
}
else
{
qDebug() << "BladerfInput: set xb200 filter to " << m_settings.m_xb200Filter;
}
}
}
if ((m_settings.m_samplerate != settings.m_samplerate) || force)
if ((m_settings.m_devSampleRate != settings.m_devSampleRate) || force)
{
m_settings.m_samplerate = settings.m_samplerate;
m_settings.m_devSampleRate = settings.m_devSampleRate;
if (m_dev != NULL)
if (m_dev != 0)
{
unsigned int actualSamplerate;
if (bladerf_set_sample_rate(m_dev, BLADERF_MODULE_RX, m_settings.m_samplerate, &actualSamplerate) < 0)
if (bladerf_set_sample_rate(m_dev, BLADERF_MODULE_RX, m_settings.m_devSampleRate, &actualSamplerate) < 0)
{
qCritical("could not set sample rate: %d", m_settings.m_samplerate);
qCritical("could not set sample rate: %d", m_settings.m_devSampleRate);
}
else
{
qDebug() << "bladerf_set_sample_rate(BLADERF_MODULE_RX) actual sample rate is " << actualSamplerate;
m_bladerfThread->setSamplerate(m_settings.m_samplerate);
m_bladerfThread->setSamplerate(m_settings.m_devSampleRate);
}
}
}
@ -359,13 +402,16 @@ bool BladerfInput::applySettings(const GeneralSettings& generalSettings, const S
{
m_settings.m_bandwidth = settings.m_bandwidth;
if(m_dev != NULL)
if(m_dev != 0)
{
unsigned int actualBandwidth;
if( bladerf_set_bandwidth(m_dev, BLADERF_MODULE_RX, m_settings.m_bandwidth, &actualBandwidth) < 0)
qCritical("could not set sample rate: %d", m_settings.m_samplerate);
else {
{
qCritical("could not set bandwidth: %d", m_settings.m_bandwidth);
}
else
{
qDebug() << "bladerf_set_bandwidth(BLADERF_MODULE_RX) actual bandwidth is " << actualBandwidth;
}
}
@ -375,7 +421,7 @@ bool BladerfInput::applySettings(const GeneralSettings& generalSettings, const S
{
m_settings.m_log2Decim = settings.m_log2Decim;
if(m_dev != NULL)
if(m_dev != 0)
{
m_bladerfThread->setLog2Decimation(m_settings.m_log2Decim);
qDebug() << "BladerfInput: set decimation to " << (1<<m_settings.m_log2Decim);
@ -386,22 +432,22 @@ bool BladerfInput::applySettings(const GeneralSettings& generalSettings, const S
{
m_settings.m_fcPos = settings.m_fcPos;
if(m_dev != NULL)
if(m_dev != 0)
{
m_bladerfThread->setFcPos((int) m_settings.m_fcPos);
qDebug() << "BladerfInput: set fc pos (enum) to " << (int) m_settings.m_fcPos;
}
}
m_generalSettings.m_centerFrequency = generalSettings.m_centerFrequency;
m_settings.m_centerFrequency = settings.m_centerFrequency;
qint64 centerFrequency = m_generalSettings.m_centerFrequency;
qint64 centerFrequency = m_settings.m_centerFrequency;
qint64 f_img = centerFrequency;
qint64 f_cut = centerFrequency + m_settings.m_bandwidth/2;
if ((m_settings.m_log2Decim == 0) || (m_settings.m_fcPos == FC_POS_CENTER))
{
centerFrequency = m_generalSettings.m_centerFrequency;
centerFrequency = m_settings.m_centerFrequency;
f_img = centerFrequency;
f_cut = centerFrequency + m_settings.m_bandwidth/2;
}
@ -409,29 +455,30 @@ bool BladerfInput::applySettings(const GeneralSettings& generalSettings, const S
{
if (m_settings.m_fcPos == FC_POS_INFRA)
{
centerFrequency = m_generalSettings.m_centerFrequency + (m_settings.m_samplerate / 4);
f_img = centerFrequency + m_settings.m_samplerate/2;
centerFrequency = m_settings.m_centerFrequency + (m_settings.m_devSampleRate / 4);
f_img = centerFrequency + m_settings.m_devSampleRate/2;
f_cut = centerFrequency + m_settings.m_bandwidth/2;
}
else if (m_settings.m_fcPos == FC_POS_SUPRA)
{
centerFrequency = m_generalSettings.m_centerFrequency - (m_settings.m_samplerate / 4);
f_img = centerFrequency - m_settings.m_samplerate/2;
centerFrequency = m_settings.m_centerFrequency - (m_settings.m_devSampleRate / 4);
f_img = centerFrequency - m_settings.m_devSampleRate/2;
f_cut = centerFrequency - m_settings.m_bandwidth/2;
}
}
if (m_dev != NULL)
{
if (bladerf_set_frequency( m_dev, BLADERF_MODULE_RX, centerFrequency ) != 0) {
qDebug("bladerf_set_frequency(%lld) failed", m_generalSettings.m_centerFrequency);
if (bladerf_set_frequency( m_dev, BLADERF_MODULE_RX, centerFrequency ) != 0)
{
qDebug("bladerf_set_frequency(%lld) failed", m_settings.m_centerFrequency);
}
}
qDebug() << " - center freq: " << m_generalSettings.m_centerFrequency << " Hz"
qDebug() << " - center freq: " << m_settings.m_centerFrequency << " Hz"
<< " RF center freq: " << centerFrequency << " Hz"
<< " RF sample rate: " << m_settings.m_samplerate << "Hz"
<< " Actual sample rate: " << m_settings.m_samplerate/(1<<m_settings.m_log2Decim) << "Hz"
<< " RF sample rate: " << m_settings.m_devSampleRate << "Hz"
<< " Actual sample rate: " << m_settings.m_devSampleRate/(1<<m_settings.m_log2Decim) << "Hz"
<< " BW: " << m_settings.m_bandwidth << "Hz"
<< " img: " << f_img << "Hz"
<< " cut: " << f_cut << "Hz"
@ -442,11 +489,16 @@ bool BladerfInput::applySettings(const GeneralSettings& generalSettings, const S
bladerf_lna_gain BladerfInput::getLnaGain(int lnaGain)
{
if (lnaGain == 2) {
if (lnaGain == 2)
{
return BLADERF_LNA_GAIN_MAX;
} else if (lnaGain == 1) {
}
else if (lnaGain == 1)
{
return BLADERF_LNA_GAIN_MID;
} else {
}
else
{
return BLADERF_LNA_GAIN_BYPASS;
}
}
@ -465,21 +517,27 @@ struct bladerf *BladerfInput::open_bladerf_from_serial(const char *serial)
/* Specify the desired device's serial number, while leaving all other
* fields in the info structure wildcard values */
if (serial != NULL) {
if (serial != NULL)
{
strncpy(info.serial, serial, BLADERF_SERIAL_LENGTH - 1);
info.serial[BLADERF_SERIAL_LENGTH - 1] = '\0';
}
status = bladerf_open_with_devinfo(&dev, &info);
if (status == BLADERF_ERR_NODEV) {
if (status == BLADERF_ERR_NODEV)
{
fprintf(stderr, "No devices available with serial=%s\n", serial);
return NULL;
} else if (status != 0) {
}
else if (status != 0)
{
fprintf(stderr, "Failed to open device with serial=%s (%s)\n",
serial, bladerf_strerror(status));
return NULL;
} else {
}
else
{
return dev;
}
}

View File

@ -32,10 +32,11 @@ public:
} fcPos_t;
struct Settings {
quint64 m_centerFrequency;
qint32 m_devSampleRate;
qint32 m_lnaGain;
qint32 m_vga1;
qint32 m_vga2;
qint32 m_samplerate;
qint32 m_bandwidth;
quint32 m_log2Decim;
fcPos_t m_fcPos;
@ -53,21 +54,18 @@ public:
MESSAGE_CLASS_DECLARATION
public:
const GeneralSettings& getGeneralSettings() const { return m_generalSettings; }
const Settings& getSettings() const { return m_settings; }
static MsgConfigureBladerf* create(const GeneralSettings& generalSettings, const Settings& settings)
static MsgConfigureBladerf* create(const Settings& settings)
{
return new MsgConfigureBladerf(generalSettings, settings);
return new MsgConfigureBladerf(settings);
}
private:
GeneralSettings m_generalSettings;
Settings m_settings;
MsgConfigureBladerf(const GeneralSettings& generalSettings, const Settings& settings) :
MsgConfigureBladerf(const Settings& settings) :
Message(),
m_generalSettings(generalSettings),
m_settings(settings)
{ }
};
@ -89,28 +87,29 @@ public:
{ }
};
BladerfInput(MessageQueue* msgQueueToGUI);
~BladerfInput();
BladerfInput();
virtual ~BladerfInput();
bool startInput(int device);
void stopInput();
virtual bool init(const Message& message);
virtual bool start(int device);
virtual void stop();
const QString& getDeviceDescription() const;
int getSampleRate() const;
quint64 getCenterFrequency() const;
virtual const QString& getDeviceDescription() const;
virtual int getSampleRate() const;
virtual quint64 getCenterFrequency() const;
bool handleMessage(Message* message);
virtual bool handleMessage(const Message& message);
private:
bool applySettings(const Settings& settings, bool force);
bladerf_lna_gain getLnaGain(int lnaGain);
struct bladerf *open_bladerf_from_serial(const char *serial);
QMutex m_mutex;
Settings m_settings;
struct bladerf* m_dev;
BladerfThread* m_bladerfThread;
QString m_deviceDescription;
bool applySettings(const GeneralSettings& generalSettings, const Settings& settings, bool force);
bladerf_lna_gain getLnaGain(int lnaGain);
struct bladerf *open_bladerf_from_serial(const char *serial);
};
#endif // INCLUDE_BLADERFINPUT_H

View File

@ -5,7 +5,6 @@ set(fcd_SOURCES
fcdinput.cpp
fcdplugin.cpp
fcdthread.cpp
fcdsource.cpp
hid-libusb.c
)

View File

@ -1,6 +1,7 @@
#include "fcdgui.h"
#include "ui_fcdgui.h"
#include "plugin/pluginapi.h"
#include "dsp/dspengine.h"
FCDGui::FCDGui(PluginAPI* pluginAPI, QWidget* parent) :
QWidget(parent),
@ -14,8 +15,8 @@ FCDGui::FCDGui(PluginAPI* pluginAPI, QWidget* parent) :
connect(&m_updateTimer, SIGNAL(timeout()), this, SLOT(updateHardware()));
displaySettings();
m_sampleSource = new FCDInput(m_pluginAPI->getMainWindowMessageQueue());
m_pluginAPI->setSampleSource(m_sampleSource);
m_sampleSource = new FCDInput();
DSPEngine::instance()->setSource(m_sampleSource);
}
FCDGui::~FCDGui()
@ -40,34 +41,11 @@ QString FCDGui::getName() const
void FCDGui::resetToDefaults()
{
m_generalSettings.resetToDefaults();
m_settings.resetToDefaults();
displaySettings();
sendSettings();
}
QByteArray FCDGui::serializeGeneral() const
{
return m_generalSettings.serialize();
}
bool FCDGui::deserializeGeneral(const QByteArray&data)
{
if(m_generalSettings.deserialize(data)) {
displaySettings();
sendSettings();
return true;
} else {
resetToDefaults();
return false;
}
}
qint64 FCDGui::getCenterFrequency() const
{
return m_generalSettings.m_centerFrequency;
}
QByteArray FCDGui::serialize() const
{
return m_settings.serialize();
@ -75,24 +53,27 @@ QByteArray FCDGui::serialize() const
bool FCDGui::deserialize(const QByteArray& data)
{
if(m_settings.deserialize(data)) {
if(m_settings.deserialize(data))
{
displaySettings();
sendSettings();
return true;
} else {
}
else
{
resetToDefaults();
return false;
}
}
bool FCDGui::handleMessage(Message* message)
bool FCDGui::handleMessage(const Message& message)
{
return true;
return false;
}
void FCDGui::displaySettings()
{
ui->centerFrequency->setValue(m_generalSettings.m_centerFrequency / 1000);
ui->centerFrequency->setValue(m_settings.centerFrequency / 1000);
ui->checkBoxR->setChecked(m_settings.range);
ui->checkBoxG->setChecked(m_settings.gain);
ui->checkBoxB->setChecked(m_settings.bias);
@ -106,49 +87,61 @@ void FCDGui::sendSettings()
void FCDGui::on_centerFrequency_changed(quint64 value)
{
m_generalSettings.m_centerFrequency = value * 1000;
m_settings.centerFrequency = value * 1000;
sendSettings();
}
void FCDGui::updateHardware()
{
FCDInput::MsgConfigureFCD* message = FCDInput::MsgConfigureFCD::create(m_generalSettings, m_settings);
message->submit(m_pluginAPI->getDSPEngineMessageQueue());
FCDInput::MsgConfigureFCD* message = FCDInput::MsgConfigureFCD::create(m_settings);
m_sampleSource->getInputMessageQueue()->push(message);
m_updateTimer.stop();
}
void FCDGui::on_checkBoxR_stateChanged(int state)
{
if (state == Qt::Checked) {
if (state == Qt::Checked)
{
ui->centerFrequency->setValueRange(7, 150U, 240000U);
ui->centerFrequency->setValue(7000);
m_generalSettings.m_centerFrequency = 7000 * 1000;
m_settings.centerFrequency = 7000 * 1000;
m_settings.range = 1;
}
else {
else
{
ui->centerFrequency->setValueRange(7, 420000U, 1900000U);
ui->centerFrequency->setValue(434450);
m_generalSettings.m_centerFrequency = 434450 * 1000;
ui->centerFrequency->setValue(435000);
m_settings.centerFrequency = 435000 * 1000;
m_settings.range = 0;
}
sendSettings();
}
void FCDGui::on_checkBoxG_stateChanged(int state)
{
if (state == Qt::Checked) {
if (state == Qt::Checked)
{
m_settings.gain = 1;
} else {
}
else
{
m_settings.gain = 0;
}
sendSettings();
}
void FCDGui::on_checkBoxB_stateChanged(int state)
{
if (state == Qt::Checked) {
if (state == Qt::Checked)
{
m_settings.bias = 1;
} else {
}
else
{
m_settings.bias = 0;
}
sendSettings();
}

View File

@ -16,25 +16,22 @@ class FCDGui : public QWidget, public PluginGUI {
public:
explicit FCDGui(PluginAPI* pluginAPI, QWidget* parent = NULL);
~FCDGui();
virtual ~FCDGui();
void destroy();
void setName(const QString& name);
QString getName() const;
void resetToDefaults();
QByteArray serializeGeneral() const;
bool deserializeGeneral(const QByteArray&data);
qint64 getCenterFrequency() const;
QByteArray serialize() const;
bool deserialize(const QByteArray& data);
bool handleMessage(Message* message);
virtual bool handleMessage(const Message& message);
private:
Ui::FCDGui* ui;
PluginAPI* m_pluginAPI;
SampleSource::GeneralSettings m_generalSettings;
FCDInput::Settings m_settings;
QTimer m_updateTimer;
std::vector<int> m_gains;

View File

@ -20,12 +20,14 @@
#include "fcdinput.h"
#include "fcdthread.h"
#include "fcdgui.h"
#include "qthid.h"
#include "util/simpleserializer.h"
MESSAGE_CLASS_DEFINITION(FCDInput::MsgConfigureFCD, Message)
//MESSAGE_CLASS_DEFINITION(FCDInput::MsgReportFCD, Message)
FCDInput::Settings::Settings() :
centerFrequency(435000000),
range(0),
gain(0),
bias(0)
@ -34,6 +36,7 @@ FCDInput::Settings::Settings() :
void FCDInput::Settings::resetToDefaults()
{
centerFrequency = 435000000;
range = 0;
gain = 0;
bias = 0;
@ -42,75 +45,92 @@ void FCDInput::Settings::resetToDefaults()
QByteArray FCDInput::Settings::serialize() const
{
SimpleSerializer s(1);
s.writeS32(1, range);
s.writeS32(2, gain);
s.writeS32(3, bias);
s.writeU64(1, centerFrequency);
s.writeS32(2, range);
s.writeS32(3, gain);
s.writeS32(4, bias);
return s.final();
}
bool FCDInput::Settings::deserialize(const QByteArray& data)
{
SimpleDeserializer d(data);
if(d.isValid() && d.getVersion() == 1) {
d.readS32(1, &range, 0);
d.readS32(2, &gain, 0);
d.readS32(3, &bias, 0);
if (d.isValid() && d.getVersion() == 1)
{
d.readU64(1, &centerFrequency, 435000000);
d.readS32(2, &range, 0);
d.readS32(3, &gain, 0);
d.readS32(4, &bias, 0);
return true;
}
resetToDefaults();
return true;
}
FCDInput::FCDInput(MessageQueue* msgQueueToGUI) :
SampleSource(msgQueueToGUI),
FCDInput::FCDInput() :
m_settings(),
m_FCDThread(NULL),
m_FCDThread(0),
m_deviceDescription()
{
}
FCDInput::~FCDInput()
{
stopInput();
stop();
}
bool FCDInput::startInput(int device)
bool FCDInput::init(const Message& cmd)
{
return false;
}
bool FCDInput::start(int device)
{
QMutexLocker mutexLocker(&m_mutex);
if(m_FCDThread)
if (m_FCDThread)
{
return false;
}
/* Apply settings before streaming to avoid bus contention;
* there is very little spare bandwidth on a full speed USB device.
* Failure is harmless if no device is found */
applySettings(m_generalSettings, m_settings, true);
if(!m_sampleFifo.setSize(4096*16)) {
applySettings(m_settings, true);
if(!m_sampleFifo.setSize(4096*16))
{
qCritical("Could not allocate SampleFifo");
return false;
}
if((m_FCDThread = new FCDThread(&m_sampleFifo)) == NULL) {
if ((m_FCDThread = new FCDThread(&m_sampleFifo)) == NULL)
{
qFatal("out of memory");
return false;
}
m_deviceDescription = QString("Funcube Dongle");
qDebug("FCDInput: start");
qDebug("FCDInput::start");
return true;
}
void FCDInput::stopInput()
void FCDInput::stop()
{
QMutexLocker mutexLocker(&m_mutex);
if(m_FCDThread) {
if (m_FCDThread)
{
m_FCDThread->stopWork();
// wait for thread to quit ?
delete m_FCDThread;
m_FCDThread = NULL;
m_FCDThread = 0;
}
m_deviceDescription.clear();
}
@ -121,45 +141,66 @@ const QString& FCDInput::getDeviceDescription() const
int FCDInput::getSampleRate() const
{
return 192000;
return 96000;
}
quint64 FCDInput::getCenterFrequency() const
{
return m_generalSettings.m_centerFrequency;
return m_settings.centerFrequency;
}
bool FCDInput::handleMessage(Message* message)
bool FCDInput::handleMessage(const Message& message)
{
if(MsgConfigureFCD::match(message)) {
MsgConfigureFCD* conf = (MsgConfigureFCD*)message;
applySettings(conf->getGeneralSettings(), conf->getSettings(), false);
message->completed();
if(MsgConfigureFCD::match(message))
{
MsgConfigureFCD& conf = (MsgConfigureFCD&) message;
applySettings(conf.getSettings(), false);
return true;
} else {
}
else
{
return false;
}
}
void FCDInput::applySettings(const GeneralSettings& generalSettings, const Settings& settings, bool force)
void FCDInput::applySettings(const Settings& settings, bool force)
{
bool freqChange;
bool sampleSourcChange = false;
if((m_generalSettings.m_centerFrequency != generalSettings.m_centerFrequency))
freqChange = true;
else
freqChange = false;
if(freqChange || force) {
m_generalSettings.m_centerFrequency = generalSettings.m_centerFrequency;
set_center_freq( (double)(generalSettings.m_centerFrequency) );
if ((m_settings.centerFrequency != settings.centerFrequency))
{
m_settings.centerFrequency = settings.centerFrequency;
set_center_freq((double) m_settings.centerFrequency);
sampleSourcChange = true;
}
if(!freqChange || force) {
set_lna_gain(settings.gain);
set_bias_t(settings.bias);
if (!sampleSourcChange || force)
{
set_lna_gain(settings.gain > 0);
set_bias_t(settings.bias > 0);
}
}
void FCDInput::set_center_freq(double freq)
{
if (fcdAppSetFreq(freq) == FCD_MODE_NONE)
{
qDebug("No FCD HID found for frquency change");
}
}
void FCDInput::set_bias_t(bool on)
{
quint8 cmd = on ? 1 : 0;
fcdAppSetParam(FCD_CMD_APP_SET_BIAS_TEE, &cmd, 1);
}
void FCDInput::set_lna_gain(bool on)
{
quint8 cmd = on ? 1 : 0;
fcdAppSetParam(FCD_CMD_APP_SET_LNA_GAIN, &cmd, 1);
}

View File

@ -23,7 +23,7 @@
struct fcd_buffer {
void *start;
size_t length;
std::size_t length;
};
class FCDThread;
@ -32,6 +32,7 @@ class FCDInput : public SampleSource {
public:
struct Settings {
Settings();
quint64 centerFrequency;
qint32 range;
qint32 gain;
qint32 bias;
@ -44,46 +45,46 @@ public:
MESSAGE_CLASS_DECLARATION
public:
const GeneralSettings& getGeneralSettings() const { return m_generalSettings; }
const Settings& getSettings() const { return m_settings; }
static MsgConfigureFCD* create(const GeneralSettings& generalSettings, const Settings& settings)
static MsgConfigureFCD* create(const Settings& settings)
{
return new MsgConfigureFCD(generalSettings, settings);
return new MsgConfigureFCD(settings);
}
private:
GeneralSettings m_generalSettings;
Settings m_settings;
MsgConfigureFCD(const GeneralSettings& generalSettings, const Settings& settings) :
MsgConfigureFCD(const Settings& settings) :
Message(),
m_generalSettings(generalSettings),
m_settings(settings)
{ }
};
FCDInput();
virtual ~FCDInput();
FCDInput(MessageQueue* msgQueueToGUI);
~FCDInput();
virtual bool init(const Message& cmd);
virtual bool start(int device);
virtual void stop();
bool startInput(int device);
void stopInput();
virtual const QString& getDeviceDescription() const;
virtual int getSampleRate() const;
virtual quint64 getCenterFrequency() const;
virtual bool handleMessage(const Message& message);
const QString& getDeviceDescription() const;
int getSampleRate() const;
void set_center_freq(double freq);
void set_bias_t(bool on);
void set_lna_gain(bool on);
quint64 getCenterFrequency() const;
bool handleMessage(Message* message);
private:
void applySettings(const Settings& settings, bool force);
QMutex m_mutex;
Settings m_settings;
FCDThread* m_FCDThread;
QString m_deviceDescription;
void applySettings(const GeneralSettings& generalSettings, const Settings& settings, bool force);
};
#endif // INCLUDE_FCD_H

View File

@ -1,95 +0,0 @@
/* (C)2015 John Greb
*
* Funcube Dongle command line interface
* Copyright 2011 David Pello EA1IDZ
* Copyright 2011 Pieter-Tjerk de Boer PA3FWM
* Copyright 2012-2014 Alexandru Csete OZ9AEC
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public Licence version 3.
*/
#include "fcdinput.h"
#include "fcdthread.h"
#include "qthid.h"
bool FCDThread::OpenSource(const char* cardname)
{
bool fail = false;
snd_pcm_hw_params_t* params;
//fcd_rate = FCDPP_RATE;
//fcd_channels =2;
//fcd_format = SND_PCM_SFMT_U16_LE;
snd_pcm_stream_t fcd_stream = SND_PCM_STREAM_CAPTURE;
if (fcd_handle)
return false;
if ( snd_pcm_open( &fcd_handle, cardname, fcd_stream, 0 ) < 0 )
return false;
snd_pcm_hw_params_alloca(&params);
if ( snd_pcm_hw_params_any(fcd_handle, params) < 0 )
fail = true;
else if ( snd_pcm_hw_params(fcd_handle, params) < 0 ) {
fail = true;
// TODO: check actual samplerate, may be crippled firmware
} else {
if ( snd_pcm_start(fcd_handle) < 0 )
fail = true;
}
if (fail) {
qCritical("Funcube Dongle stream start failed");
snd_pcm_close( fcd_handle );
return false;
} else {
qDebug("Funcube stream started");
}
return true;
}
void FCDThread::CloseSource()
{
if (fcd_handle)
snd_pcm_close( fcd_handle );
fcd_handle = NULL;
}
void FCDInput::set_center_freq(double freq)
{
if (fcdAppSetFreq(freq) == FCD_MODE_NONE)
qDebug("No FCD HID found for frquency change");
}
void FCDInput::set_bias_t(bool on)
{
quint8 cmd = on ? 1 : 0;
fcdAppSetParam(FCD_CMD_APP_SET_BIAS_TEE, &cmd, 1);
}
void FCDInput::set_lna_gain(bool on)
{
quint8 cmd = on ? 1 : 0;
fcdAppSetParam(FCD_CMD_APP_SET_LNA_GAIN, &cmd, 1);
}
int FCDThread::work(int n_items)
{
int l;
SampleVector::iterator it;
void *out;
it = m_convertBuffer.begin();
out = (void *)&it[0];
l = snd_pcm_mmap_readi(fcd_handle, out, (snd_pcm_uframes_t)n_items);
if (l > 0)
m_sampleFifo->write(it, it + l);
if (l == -EPIPE) {
qDebug("FCD: Overrun detected");
return 0;
}
return l;
}

View File

@ -54,3 +54,84 @@ void FCDThread::run()
CloseSource();
}
bool FCDThread::OpenSource(const char* cardname)
{
bool fail = false;
snd_pcm_hw_params_t* params;
//fcd_rate = FCDPP_RATE;
//fcd_channels =2;
//fcd_format = SND_PCM_SFMT_U16_LE;
snd_pcm_stream_t fcd_stream = SND_PCM_STREAM_CAPTURE;
if (fcd_handle)
{
return false;
}
if (snd_pcm_open(&fcd_handle, cardname, fcd_stream, 0) < 0)
{
return false;
}
snd_pcm_hw_params_alloca(&params);
if (snd_pcm_hw_params_any(fcd_handle, params) < 0)
{
fail = true;
}
else if (snd_pcm_hw_params(fcd_handle, params) < 0)
{
fail = true;
// TODO: check actual samplerate, may be crippled firmware
}
else
{
if (snd_pcm_start(fcd_handle) < 0)
{
fail = true;
}
}
if (fail)
{
qCritical("Funcube Dongle stream start failed");
snd_pcm_close( fcd_handle );
return false;
}
else
{
qDebug("Funcube stream started");
}
return true;
}
void FCDThread::CloseSource()
{
if (fcd_handle)
{
snd_pcm_close( fcd_handle );
}
fcd_handle = NULL;
}
int FCDThread::work(int n_items)
{
int l;
SampleVector::iterator it;
void *out;
it = m_convertBuffer.begin();
out = (void *)&it[0];
l = snd_pcm_mmap_readi(fcd_handle, out, (snd_pcm_uframes_t)n_items);
if (l > 0)
m_sampleFifo->write(it, it + l);
if (l == -EPIPE) {
qDebug("FCD: Overrun detected");
return 0;
}
return l;
}

View File

@ -23,6 +23,7 @@
#include "ui_filesourcegui.h"
#include "plugin/pluginapi.h"
#include "gui/colormapper.h"
#include "dsp/dspengine.h"
#include "mainwindow.h"
#include "filesourcegui.h"
@ -49,8 +50,8 @@ FileSourceGui::FileSourceGui(PluginAPI* pluginAPI, QWidget* parent) :
connect(&(m_pluginAPI->getMainWindow()->getMasterTimer()), SIGNAL(timeout()), this, SLOT(tick()));
displaySettings();
m_sampleSource = new FileSourceInput(m_pluginAPI->getMainWindowMessageQueue(), m_pluginAPI->getMainWindow()->getMasterTimer());
m_pluginAPI->setSampleSource(m_sampleSource);
m_sampleSource = new FileSourceInput(m_pluginAPI->getMainWindow()->getMasterTimer());
DSPEngine::instance()->setSource(m_sampleSource);
}
FileSourceGui::~FileSourceGui()
@ -75,32 +76,14 @@ QString FileSourceGui::getName() const
void FileSourceGui::resetToDefaults()
{
m_generalSettings.resetToDefaults();
m_settings.resetToDefaults();
displaySettings();
sendSettings();
}
QByteArray FileSourceGui::serializeGeneral() const
{
return m_generalSettings.serialize();
}
bool FileSourceGui::deserializeGeneral(const QByteArray&data)
{
if(m_generalSettings.deserialize(data)) {
displaySettings();
sendSettings();
return true;
} else {
resetToDefaults();
return false;
}
}
qint64 FileSourceGui::getCenterFrequency() const
{
return m_generalSettings.m_centerFrequency;
return m_centerFrequency;
}
QByteArray FileSourceGui::serialize() const
@ -120,28 +103,25 @@ bool FileSourceGui::deserialize(const QByteArray& data)
}
}
bool FileSourceGui::handleMessage(Message* message)
bool FileSourceGui::handleMessage(const Message& message)
{
if(FileSourceInput::MsgReportFileSourceAcquisition::match(message))
{
m_acquisition = ((FileSourceInput::MsgReportFileSourceAcquisition*)message)->getAcquisition();
m_acquisition = ((FileSourceInput::MsgReportFileSourceAcquisition&)message).getAcquisition();
updateWithAcquisition();
message->completed();
return true;
}
else if(FileSourceInput::MsgReportFileSourceStreamData::match(message))
{
m_sampleRate = ((FileSourceInput::MsgReportFileSourceStreamData*)message)->getSampleRate();
m_centerFrequency = ((FileSourceInput::MsgReportFileSourceStreamData*)message)->getCenterFrequency();
m_startingTimeStamp = ((FileSourceInput::MsgReportFileSourceStreamData*)message)->getStartingTimeStamp();
message->completed();
m_sampleRate = ((FileSourceInput::MsgReportFileSourceStreamData&)message).getSampleRate();
m_centerFrequency = ((FileSourceInput::MsgReportFileSourceStreamData&)message).getCenterFrequency();
m_startingTimeStamp = ((FileSourceInput::MsgReportFileSourceStreamData&)message).getStartingTimeStamp();
updateWithStreamData();
return true;
}
else if(FileSourceInput::MsgReportFileSourceStreamTiming::match(message))
{
m_samplesCount = ((FileSourceInput::MsgReportFileSourceStreamTiming*)message)->getSamplesCount();
message->completed();
m_samplesCount = ((FileSourceInput::MsgReportFileSourceStreamTiming&)message).getSamplesCount();
updateWithStreamTime();
return true;
}
@ -157,31 +137,25 @@ void FileSourceGui::displaySettings()
void FileSourceGui::sendSettings()
{
/*
if(!m_updateTimer.isActive())
m_updateTimer.start(100);
*/
}
void FileSourceGui::updateHardware()
{
/*
FileSourceInput::MsgConfigureFileSource* message = FileSourceInput::MsgConfigureFileSource::create(m_generalSettings, m_settings);
message->submit(m_pluginAPI->getDSPEngineMessageQueue());
m_updateTimer.stop();*/
}
void FileSourceGui::on_play_toggled(bool checked)
{
FileSourceInput::MsgConfigureFileSourceWork* message = FileSourceInput::MsgConfigureFileSourceWork::create(checked);
message->submit(m_pluginAPI->getDSPEngineMessageQueue());
m_sampleSource->getInputMessageQueue()->push(message);
}
void FileSourceGui::on_showFileDialog_clicked(bool checked)
{
QString fileName = QFileDialog::getOpenFileName(this,
tr("Open I/Q record file"), ".", tr("SDR I/Q Files (*.sdriq)"));
if (fileName != "") {
if (fileName != "")
{
m_fileName = fileName;
ui->fileNameText->setText(m_fileName);
configureFileName();
@ -192,7 +166,7 @@ void FileSourceGui::configureFileName()
{
qDebug() << "FileSourceGui::configureFileName: " << m_fileName.toStdString().c_str();
FileSourceInput::MsgConfigureFileSourceName* message = FileSourceInput::MsgConfigureFileSourceName::create(m_fileName);
message->submit(m_pluginAPI->getDSPEngineMessageQueue());
m_sampleSource->getInputMessageQueue()->push(message);
}
void FileSourceGui::updateWithAcquisition()
@ -239,6 +213,6 @@ void FileSourceGui::tick()
{
if ((++m_tickCount & 0xf) == 0) {
FileSourceInput::MsgConfigureFileSourceStreamTiming* message = FileSourceInput::MsgConfigureFileSourceStreamTiming::create();
message->submit(m_pluginAPI->getDSPEngineMessageQueue());
m_sampleSource->getInputMessageQueue()->push(message);
}
}

View File

@ -33,25 +33,22 @@ class FileSourceGui : public QWidget, public PluginGUI {
public:
explicit FileSourceGui(PluginAPI* pluginAPI, QWidget* parent = NULL);
~FileSourceGui();
virtual ~FileSourceGui();
void destroy();
void setName(const QString& name);
QString getName() const;
void resetToDefaults();
QByteArray serializeGeneral() const;
bool deserializeGeneral(const QByteArray&data);
qint64 getCenterFrequency() const;
QByteArray serialize() const;
bool deserialize(const QByteArray& data);
bool handleMessage(Message* message);
virtual bool handleMessage(const Message& message);
private:
Ui::FileSourceGui* ui;
PluginAPI* m_pluginAPI;
SampleSource::GeneralSettings m_generalSettings;
FileSourceInput::Settings m_settings;
QTimer m_updateTimer;
std::vector<int> m_gains;

View File

@ -69,8 +69,7 @@ bool FileSourceInput::Settings::deserialize(const QByteArray& data)
}
}
FileSourceInput::FileSourceInput(MessageQueue* msgQueueToGUI, const QTimer& masterTimer) :
SampleSource(msgQueueToGUI),
FileSourceInput::FileSourceInput(const QTimer& masterTimer) :
m_settings(),
m_fileSourceThread(NULL),
m_deviceDescription(),
@ -84,7 +83,7 @@ FileSourceInput::FileSourceInput(MessageQueue* msgQueueToGUI, const QTimer& mast
FileSourceInput::~FileSourceInput()
{
stopInput();
stop();
}
void FileSourceInput::openFileStream()
@ -105,19 +104,15 @@ void FileSourceInput::openFileStream()
m_centerFrequency = header.centerFrequency;
m_startingTimeStamp = header.startTimeStamp;
MsgReportFileSourceStreamData::create(m_sampleRate, m_centerFrequency, m_startingTimeStamp)->submit(m_guiMessageQueue); // file stream data
MsgReportFileSourceStreamData *report = MsgReportFileSourceStreamData::create(m_sampleRate, m_centerFrequency, m_startingTimeStamp); // file stream data
getOutputMessageQueue()->push(report);
}
bool FileSourceInput::startInput(int device)
bool FileSourceInput::start(int device)
{
QMutexLocker mutexLocker(&m_mutex);
qDebug() << "FileSourceInput::startInput";
/*
if (!m_ifstream.is_open()) {
openFileStream();
}*/
if (m_ifstream.tellg() != 0) {
m_ifstream.clear();
m_ifstream.seekg(0, std::ios::beg);
@ -132,7 +127,8 @@ bool FileSourceInput::startInput(int device)
if((m_fileSourceThread = new FileSourceThread(&m_ifstream, &m_sampleFifo)) == NULL) {
qFatal("out of memory");
goto failed;
stop();
return false;
}
m_fileSourceThread->setSamplerate(m_sampleRate);
@ -144,29 +140,28 @@ bool FileSourceInput::startInput(int device)
//applySettings(m_generalSettings, m_settings, true);
qDebug("FileSourceInput::startInput: started");
MsgReportFileSourceAcquisition::create(true)->submit(m_guiMessageQueue); // acquisition on
MsgReportFileSourceAcquisition *report = MsgReportFileSourceAcquisition::create(true); // acquisition on
getOutputMessageQueue()->push(report);
return true;
failed:
stopInput();
return false;
}
void FileSourceInput::stopInput()
void FileSourceInput::stop()
{
qDebug() << "FileSourceInput::stopInput";
qDebug() << "FileSourceInput::stop";
QMutexLocker mutexLocker(&m_mutex);
if(m_fileSourceThread != NULL) {
if(m_fileSourceThread != 0)
{
m_fileSourceThread->stopWork();
delete m_fileSourceThread;
m_fileSourceThread = NULL;
m_fileSourceThread = 0;
}
m_deviceDescription.clear();
MsgReportFileSourceAcquisition::create(false)->submit(m_guiMessageQueue); // acquisition off
MsgReportFileSourceAcquisition *report = MsgReportFileSourceAcquisition::create(false); // acquisition off
getOutputMessageQueue()->push(report);
}
const QString& FileSourceInput::getDeviceDescription() const
@ -189,40 +184,52 @@ std::time_t FileSourceInput::getStartingTimeStamp() const
return m_startingTimeStamp;
}
bool FileSourceInput::handleMessage(Message* message)
bool FileSourceInput::handleMessage(const Message& message)
{
if (MsgConfigureFileSourceName::match(message))
{
MsgConfigureFileSourceName* conf = (MsgConfigureFileSourceName*) message;
m_fileName = conf->getFileName();
MsgConfigureFileSourceName& conf = (MsgConfigureFileSourceName&) message;
m_fileName = conf.getFileName();
openFileStream();
message->completed();
return true;
}
else if (MsgConfigureFileSourceWork::match(message))
{
MsgConfigureFileSourceWork* conf = (MsgConfigureFileSourceWork*) message;
bool working = conf->isWorking();
MsgConfigureFileSourceWork& conf = (MsgConfigureFileSourceWork&) message;
bool working = conf.isWorking();
if (m_fileSourceThread != 0)
{
if (working) {
if (working)
{
m_fileSourceThread->startWork();
} else {
}
else
{
m_fileSourceThread->stopWork();
}
MsgReportFileSourceStreamTiming::create(m_fileSourceThread->getSamplesCount())->submit(m_guiMessageQueue);
MsgReportFileSourceStreamTiming *report =
MsgReportFileSourceStreamTiming::create(m_fileSourceThread->getSamplesCount());
getOutputMessageQueue()->push(report);
}
message->completed();
return true;
}
else if (MsgConfigureFileSourceStreamTiming::match(message))
{
if (m_fileSourceThread != 0) {
MsgReportFileSourceStreamTiming::create(m_fileSourceThread->getSamplesCount())->submit(m_guiMessageQueue);
}else {
MsgReportFileSourceStreamTiming::create(0)->submit(m_guiMessageQueue);
MsgReportFileSourceStreamTiming *report;
if (m_fileSourceThread != 0)
{
report = MsgReportFileSourceStreamTiming::create(m_fileSourceThread->getSamplesCount());
}
else
{
report = MsgReportFileSourceStreamTiming::create(0);
}
getOutputMessageQueue()->push(report);
}
else
{
@ -230,30 +237,38 @@ bool FileSourceInput::handleMessage(Message* message)
}
}
bool FileSourceInput::applySettings(const GeneralSettings& generalSettings, const Settings& settings, bool force)
bool FileSourceInput::applySettings(const Settings& settings, bool force)
{
QMutexLocker mutexLocker(&m_mutex);
bool wasRunning = false;
if((m_settings.m_fileName != settings.m_fileName) || force) {
if((m_settings.m_fileName != settings.m_fileName) || force)
{
m_settings.m_fileName = settings.m_fileName;
if (m_fileSourceThread != 0) {
if (m_fileSourceThread != 0)
{
wasRunning = m_fileSourceThread->isRunning();
if (wasRunning) {
if (wasRunning)
{
m_fileSourceThread->stopWork();
}
}
if (m_ifstream.is_open()) {
if (m_ifstream.is_open())
{
m_ifstream.close();
}
openFileStream();
if (m_fileSourceThread != 0) {
if (m_fileSourceThread != 0)
{
m_fileSourceThread->setSamplerate(m_sampleRate);
if (wasRunning) {
if (wasRunning)
{
m_fileSourceThread->startWork();
}
}

View File

@ -41,21 +41,18 @@ public:
MESSAGE_CLASS_DECLARATION
public:
const GeneralSettings& getGeneralSettings() const { return m_generalSettings; }
const Settings& getSettings() const { return m_settings; }
static MsgConfigureFileSource* create(const GeneralSettings& generalSettings, const Settings& settings)
static MsgConfigureFileSource* create(const Settings& settings)
{
return new MsgConfigureFileSource(generalSettings, settings);
return new MsgConfigureFileSource(settings);
}
private:
GeneralSettings m_generalSettings;
Settings m_settings;
MsgConfigureFileSource(const GeneralSettings& generalSettings, const Settings& settings) :
MsgConfigureFileSource(const Settings& settings) :
Message(),
m_generalSettings(generalSettings),
m_settings(settings)
{ }
};
@ -183,18 +180,19 @@ public:
{ }
};
FileSourceInput(MessageQueue* msgQueueToGUI, const QTimer& masterTimer);
~FileSourceInput();
FileSourceInput(const QTimer& masterTimer);
virtual ~FileSourceInput();
bool startInput(int device);
void stopInput();
virtual bool init(const Message& message);
virtual bool start(int device);
virtual void stop();
const QString& getDeviceDescription() const;
int getSampleRate() const;
quint64 getCenterFrequency() const;
virtual const QString& getDeviceDescription() const;
virtual int getSampleRate() const;
virtual quint64 getCenterFrequency() const;
std::time_t getStartingTimeStamp() const;
bool handleMessage(Message* message);
virtual bool handleMessage(const Message& message);
private:
QMutex m_mutex;
@ -208,7 +206,7 @@ private:
std::time_t m_startingTimeStamp;
const QTimer& m_masterTimer;
bool applySettings(const GeneralSettings& generalSettings, const Settings& settings, bool force);
bool applySettings(const Settings& settings, bool force);
void openFileStream();
};

View File

@ -2,13 +2,14 @@
#include "ui_rtlsdrgui.h"
#include "plugin/pluginapi.h"
#include "gui/colormapper.h"
#include "dsp/dspengine.h"
RTLSDRGui::RTLSDRGui(PluginAPI* pluginAPI, QWidget* parent) :
QWidget(parent),
ui(new Ui::RTLSDRGui),
m_pluginAPI(pluginAPI),
m_settings(),
m_sampleSource(NULL)
m_sampleSource(0)
{
ui->setupUi(this);
ui->centerFrequency->setColorMapper(ColorMapper(ColorMapper::ReverseGold));
@ -16,8 +17,8 @@ RTLSDRGui::RTLSDRGui(PluginAPI* pluginAPI, QWidget* parent) :
connect(&m_updateTimer, SIGNAL(timeout()), this, SLOT(updateHardware()));
displaySettings();
m_sampleSource = new RTLSDRInput(m_pluginAPI->getMainWindowMessageQueue());
m_pluginAPI->setSampleSource(m_sampleSource);
m_sampleSource = new RTLSDRInput();
DSPEngine::instance()->setSource(m_sampleSource);
}
RTLSDRGui::~RTLSDRGui()
@ -42,32 +43,14 @@ QString RTLSDRGui::getName() const
void RTLSDRGui::resetToDefaults()
{
m_generalSettings.resetToDefaults();
m_settings.resetToDefaults();
displaySettings();
sendSettings();
}
QByteArray RTLSDRGui::serializeGeneral() const
{
return m_generalSettings.serialize();
}
bool RTLSDRGui::deserializeGeneral(const QByteArray&data)
{
if(m_generalSettings.deserialize(data)) {
displaySettings();
sendSettings();
return true;
} else {
resetToDefaults();
return false;
}
}
qint64 RTLSDRGui::getCenterFrequency() const
{
return m_generalSettings.m_centerFrequency;
return m_settings.m_centerFrequency;
}
QByteArray RTLSDRGui::serialize() const
@ -77,53 +60,65 @@ QByteArray RTLSDRGui::serialize() const
bool RTLSDRGui::deserialize(const QByteArray& data)
{
if(m_settings.deserialize(data)) {
if (m_settings.deserialize(data))
{
displaySettings();
sendSettings();
return true;
} else {
}
else
{
resetToDefaults();
return false;
}
}
bool RTLSDRGui::handleMessage(Message* message)
bool RTLSDRGui::handleMessage(const Message& message)
{
if(RTLSDRInput::MsgReportRTLSDR::match(message)) {
m_gains = ((RTLSDRInput::MsgReportRTLSDR*)message)->getGains();
if (RTLSDRInput::MsgReportRTLSDR::match(message))
{
m_gains = ((RTLSDRInput::MsgReportRTLSDR&) message).getGains();
displaySettings();
message->completed();
return true;
} else {
}
else
{
return false;
}
}
void RTLSDRGui::displaySettings()
{
ui->centerFrequency->setValue(m_generalSettings.m_centerFrequency / 1000);
ui->samplerateText->setText(tr("%1k").arg(m_settings.m_samplerate / 1000));
unsigned int sampleRateIndex = RTLSDRSampleRates::getRateIndex(m_settings.m_samplerate);
ui->centerFrequency->setValue(m_settings.m_centerFrequency / 1000);
ui->samplerateText->setText(tr("%1k").arg(m_settings.m_devSampleRate / 1000));
unsigned int sampleRateIndex = RTLSDRSampleRates::getRateIndex(m_settings.m_devSampleRate);
ui->samplerate->setValue(sampleRateIndex);
ui->ppm->setValue(m_settings.m_loPpmCorrection);
ui->ppmText->setText(tr("%1").arg(m_settings.m_loPpmCorrection));
ui->decimText->setText(tr("%1").arg(1<<m_settings.m_log2Decim));
ui->decim->setValue(m_settings.m_log2Decim);
if(m_gains.size() > 0) {
if (m_gains.size() > 0)
{
int dist = abs(m_settings.m_gain - m_gains[0]);
int pos = 0;
for(uint i = 1; i < m_gains.size(); i++) {
if(abs(m_settings.m_gain - m_gains[i]) < dist) {
for (uint i = 1; i < m_gains.size(); i++)
{
if (abs(m_settings.m_gain - m_gains[i]) < dist)
{
dist = abs(m_settings.m_gain - m_gains[i]);
pos = i;
}
}
ui->gainText->setText(tr("%1.%2").arg(m_gains[pos] / 10).arg(abs(m_gains[pos] % 10)));
ui->gain->setMaximum(m_gains.size() - 1);
ui->gain->setEnabled(true);
ui->gain->setValue(pos);
} else {
}
else
{
ui->gain->setMaximum(0);
ui->gain->setEnabled(false);
ui->gain->setValue(0);
@ -133,40 +128,54 @@ void RTLSDRGui::displaySettings()
void RTLSDRGui::sendSettings()
{
if(!m_updateTimer.isActive())
{
m_updateTimer.start(100);
}
}
void RTLSDRGui::on_centerFrequency_changed(quint64 value)
{
m_generalSettings.m_centerFrequency = value * 1000;
m_settings.m_centerFrequency = value * 1000;
sendSettings();
}
void RTLSDRGui::on_decim_valueChanged(int value)
{
if ((value <0) || (value > 4))
{
return;
}
ui->decimText->setText(tr("%1").arg(1<<value));
m_settings.m_log2Decim = value;
sendSettings();
}
void RTLSDRGui::on_ppm_valueChanged(int value)
{
if((value > 99) || (value < -99))
if ((value > 99) || (value < -99))
{
return;
}
ui->ppmText->setText(tr("%1").arg(value));
m_settings.m_loPpmCorrection = value;
sendSettings();
}
void RTLSDRGui::on_gain_valueChanged(int value)
{
if(value > (int)m_gains.size())
if (value > (int)m_gains.size())
{
return;
}
int gain = m_gains[value];
ui->gainText->setText(tr("%1.%2").arg(gain / 10).arg(abs(gain % 10)));
m_settings.m_gain = gain;
sendSettings();
}
@ -174,34 +183,39 @@ void RTLSDRGui::on_samplerate_valueChanged(int value)
{
int newrate = RTLSDRSampleRates::getRate(value);
ui->samplerateText->setText(tr("%1k").arg(newrate));
m_settings.m_samplerate = newrate * 1000;
m_settings.m_devSampleRate = newrate * 1000;
sendSettings();
}
void RTLSDRGui::updateHardware()
{
RTLSDRInput::MsgConfigureRTLSDR* message = RTLSDRInput::MsgConfigureRTLSDR::create(m_generalSettings, m_settings);
message->submit(m_pluginAPI->getDSPEngineMessageQueue());
RTLSDRInput::MsgConfigureRTLSDR* message = RTLSDRInput::MsgConfigureRTLSDR::create(m_settings);
m_sampleSource->getInputMessageQueue()->push(message);
m_updateTimer.stop();
}
void RTLSDRGui::on_checkBox_stateChanged(int state) {
if (state == Qt::Checked){
void RTLSDRGui::on_checkBox_stateChanged(int state)
{
if (state == Qt::Checked)
{
// Direct Modes: 0: off, 1: I, 2: Q, 3: NoMod.
((RTLSDRInput*)m_sampleSource)->set_ds_mode(3);
ui->gain->setEnabled(false);
ui->centerFrequency->setValueRange(7, 1000U, 275000U);
ui->centerFrequency->setValue(7000);
m_generalSettings.m_centerFrequency = 7000 * 1000;
m_settings.m_centerFrequency = 7000 * 1000;
}
else {
else
{
((RTLSDRInput*)m_sampleSource)->set_ds_mode(0);
ui->gain->setEnabled(true);
ui->centerFrequency->setValueRange(7, 28500U, 1700000U);
ui->centerFrequency->setValue(434000);
ui->gain->setValue(0);
m_generalSettings.m_centerFrequency = 434000 * 1000;
m_settings.m_centerFrequency = 435000 * 1000;
}
sendSettings();
}

View File

@ -17,25 +17,22 @@ class RTLSDRGui : public QWidget, public PluginGUI {
public:
explicit RTLSDRGui(PluginAPI* pluginAPI, QWidget* parent = NULL);
~RTLSDRGui();
virtual ~RTLSDRGui();
void destroy();
void setName(const QString& name);
QString getName() const;
void resetToDefaults();
QByteArray serializeGeneral() const;
bool deserializeGeneral(const QByteArray&data);
qint64 getCenterFrequency() const;
QByteArray serialize() const;
bool deserialize(const QByteArray& data);
bool handleMessage(Message* message);
virtual bool handleMessage(const Message& message);
private:
Ui::RTLSDRGui* ui;
PluginAPI* m_pluginAPI;
SampleSource::GeneralSettings m_generalSettings;
RTLSDRInput::Settings m_settings;
QTimer m_updateTimer;
std::vector<int> m_gains;

View File

@ -26,8 +26,9 @@ MESSAGE_CLASS_DEFINITION(RTLSDRInput::MsgConfigureRTLSDR, Message)
MESSAGE_CLASS_DEFINITION(RTLSDRInput::MsgReportRTLSDR, Message)
RTLSDRInput::Settings::Settings() :
m_devSampleRate(1024*1000),
m_centerFrequency(435000*1000),
m_gain(0),
m_samplerate(1024000),
m_loPpmCorrection(0),
m_log2Decim(4)
{
@ -35,8 +36,9 @@ RTLSDRInput::Settings::Settings() :
void RTLSDRInput::Settings::resetToDefaults()
{
m_devSampleRate = 1024*1000;
m_centerFrequency = 435000*1000;
m_gain = 0;
m_samplerate = 1024000;
m_loPpmCorrection = 0;
m_log2Decim = 4;
}
@ -44,10 +46,11 @@ void RTLSDRInput::Settings::resetToDefaults()
QByteArray RTLSDRInput::Settings::serialize() const
{
SimpleSerializer s(1);
s.writeS32(1, m_gain);
s.writeS32(2, m_samplerate);
s.writeS32(3, m_loPpmCorrection);
s.writeU32(4, m_log2Decim);
s.writeS32(1, m_devSampleRate);
s.writeU64(2, m_centerFrequency);
s.writeS32(3, m_gain);
s.writeS32(4, m_loPpmCorrection);
s.writeU32(5, m_log2Decim);
return s.final();
}
@ -55,43 +58,49 @@ bool RTLSDRInput::Settings::deserialize(const QByteArray& data)
{
SimpleDeserializer d(data);
if(!d.isValid()) {
if (!d.isValid())
{
resetToDefaults();
return false;
}
if(d.getVersion() == 1) {
d.readS32(1, &m_gain, 0);
d.readS32(2, &m_samplerate, 0);
d.readS32(3, &m_loPpmCorrection, 0);
d.readU32(4, &m_log2Decim, 4);
if(d.getVersion() == 1)
{
d.readS32(1, &m_devSampleRate, 1024*1000);
d.readU64(2, &m_centerFrequency, 435000*1000);
d.readS32(3, &m_gain, 0);
d.readS32(4, &m_loPpmCorrection, 0);
d.readU32(5, &m_log2Decim, 4);
return true;
} else {
}
else
{
resetToDefaults();
return false;
}
}
RTLSDRInput::RTLSDRInput(MessageQueue* msgQueueToGUI) :
SampleSource(msgQueueToGUI),
RTLSDRInput::RTLSDRInput() :
m_settings(),
m_dev(NULL),
m_rtlSDRThread(NULL),
m_dev(0),
m_rtlSDRThread(0),
m_deviceDescription()
{
}
RTLSDRInput::~RTLSDRInput()
{
stopInput();
stop();
}
bool RTLSDRInput::startInput(int device)
bool RTLSDRInput::start(int device)
{
QMutexLocker mutexLocker(&m_mutex);
if(m_dev != NULL)
stopInput();
if (m_dev != 0)
{
stop();
}
char vendor[256];
char product[256];
@ -99,12 +108,14 @@ bool RTLSDRInput::startInput(int device)
int res;
int numberOfGains;
if(!m_sampleFifo.setSize(96000 * 4)) {
if (!m_sampleFifo.setSize(96000 * 4))
{
qCritical("Could not allocate SampleFifo");
return false;
}
if((res = rtlsdr_open(&m_dev, device)) < 0) {
if ((res = rtlsdr_open(&m_dev, device)) < 0)
{
qCritical("could not open RTLSDR #%d: %s", device, strerror(errno));
return false;
}
@ -112,74 +123,101 @@ bool RTLSDRInput::startInput(int device)
vendor[0] = '\0';
product[0] = '\0';
serial[0] = '\0';
if((res = rtlsdr_get_usb_strings(m_dev, vendor, product, serial)) < 0) {
if ((res = rtlsdr_get_usb_strings(m_dev, vendor, product, serial)) < 0)
{
qCritical("error accessing USB device");
goto failed;
stop();
return false;
}
qWarning("RTLSDRInput open: %s %s, SN: %s", vendor, product, serial);
m_deviceDescription = QString("%1 (SN %2)").arg(product).arg(serial);
if((res = rtlsdr_set_sample_rate(m_dev, 1024000)) < 0) {
if ((res = rtlsdr_set_sample_rate(m_dev, 1024000)) < 0)
{
qCritical("could not set sample rate: 1024k S/s");
goto failed;
stop();
return false;
}
if((res = rtlsdr_set_tuner_gain_mode(m_dev, 1)) < 0) {
if ((res = rtlsdr_set_tuner_gain_mode(m_dev, 1)) < 0)
{
qCritical("error setting tuner gain mode");
goto failed;
stop();
return false;
}
if((res = rtlsdr_set_agc_mode(m_dev, 0)) < 0) {
if ((res = rtlsdr_set_agc_mode(m_dev, 0)) < 0)
{
qCritical("error setting agc mode");
goto failed;
stop();
return false;
}
numberOfGains = rtlsdr_get_tuner_gains(m_dev, NULL);
if(numberOfGains < 0) {
if (numberOfGains < 0)
{
qCritical("error getting number of gain values supported");
goto failed;
}
m_gains.resize(numberOfGains);
if(rtlsdr_get_tuner_gains(m_dev, &m_gains[0]) < 0) {
qCritical("error getting gain values");
goto failed;
}
if((res = rtlsdr_reset_buffer(m_dev)) < 0) {
qCritical("could not reset USB EP buffers: %s", strerror(errno));
goto failed;
stop();
return false;
}
if((m_rtlSDRThread = new RTLSDRThread(m_dev, &m_sampleFifo)) == NULL) {
qFatal("out of memory");
goto failed;
m_gains.resize(numberOfGains);
if (rtlsdr_get_tuner_gains(m_dev, &m_gains[0]) < 0)
{
qCritical("error getting gain values");
stop();
return false;
}
if ((res = rtlsdr_reset_buffer(m_dev)) < 0)
{
qCritical("could not reset USB EP buffers: %s", strerror(errno));
stop();
return false;
}
if ((m_rtlSDRThread = new RTLSDRThread(m_dev, &m_sampleFifo)) == NULL)
{
qFatal("out of memory");
stop();
return false;
}
m_rtlSDRThread->startWork();
mutexLocker.unlock();
applySettings(m_generalSettings, m_settings, true);
qDebug("RTLSDRInput: start");
MsgReportRTLSDR::create(m_gains)->submit(m_guiMessageQueue);
applySettings(m_settings, true);
qDebug("RTLSDRInput::start");
MsgReportRTLSDR *message = MsgReportRTLSDR::create(m_gains);
getOutputMessageQueue()->push(message);
return true;
failed:
stopInput();
return false;
}
void RTLSDRInput::stopInput()
void RTLSDRInput::stop()
{
QMutexLocker mutexLocker(&m_mutex);
if(m_rtlSDRThread != NULL) {
if (m_rtlSDRThread != 0)
{
m_rtlSDRThread->stopWork();
delete m_rtlSDRThread;
m_rtlSDRThread = NULL;
m_rtlSDRThread = 0;
}
if(m_dev != NULL) {
if (m_dev != 0)
{
rtlsdr_close(m_dev);
m_dev = NULL;
m_dev = 0;
}
m_deviceDescription.clear();
}
@ -190,88 +228,110 @@ const QString& RTLSDRInput::getDeviceDescription() const
int RTLSDRInput::getSampleRate() const
{
int rate = m_settings.m_samplerate;
int rate = m_settings.m_devSampleRate;
return (rate / (1<<m_settings.m_log2Decim));
/*
if (rate < 800000)
return (rate / 4);
if ((rate == 1152000) || (rate == 2048000))
return (rate / 8);
return (rate / 16);
*/
}
quint64 RTLSDRInput::getCenterFrequency() const
{
return m_generalSettings.m_centerFrequency;
return m_settings.m_centerFrequency;
}
bool RTLSDRInput::handleMessage(Message* message)
bool RTLSDRInput::handleMessage(const Message& message)
{
if(MsgConfigureRTLSDR::match(message)) {
MsgConfigureRTLSDR* conf = (MsgConfigureRTLSDR*)message;
if(!applySettings(conf->getGeneralSettings(), conf->getSettings(), false))
if (MsgConfigureRTLSDR::match(message))
{
MsgConfigureRTLSDR& conf = (MsgConfigureRTLSDR&) message;
if (!applySettings(conf.getSettings(), false))
{
qDebug("RTLSDR config error");
message->completed();
}
return true;
} else {
}
else
{
return false;
}
}
bool RTLSDRInput::applySettings(const GeneralSettings& generalSettings, const Settings& settings, bool force)
bool RTLSDRInput::applySettings(const Settings& settings, bool force)
{
QMutexLocker mutexLocker(&m_mutex);
if((m_settings.m_gain != settings.m_gain) || force) {
if ((m_settings.m_gain != settings.m_gain) || force)
{
m_settings.m_gain = settings.m_gain;
if(m_dev != NULL) {
if(m_dev != 0)
{
if(rtlsdr_set_tuner_gain(m_dev, m_settings.m_gain) != 0)
{
qDebug("rtlsdr_set_tuner_gain() failed");
}
}
if((m_settings.m_samplerate != settings.m_samplerate) || force) {
if(m_dev != NULL) {
if( rtlsdr_set_sample_rate(m_dev, settings.m_samplerate) < 0)
qCritical("could not set sample rate: %d", settings.m_samplerate);
else {
m_settings.m_samplerate = settings.m_samplerate;
m_rtlSDRThread->setSamplerate(settings.m_samplerate);
}
}
}
if((m_settings.m_loPpmCorrection != settings.m_loPpmCorrection) || force) {
if(m_dev != NULL) {
if( rtlsdr_set_freq_correction(m_dev, settings.m_loPpmCorrection) < 0)
if ((m_settings.m_devSampleRate != settings.m_devSampleRate) || force)
{
if(m_dev != 0)
{
if( rtlsdr_set_sample_rate(m_dev, settings.m_devSampleRate) < 0)
{
qCritical("could not set sample rate: %d", settings.m_devSampleRate);
}
else
{
m_settings.m_devSampleRate = settings.m_devSampleRate;
m_rtlSDRThread->setSamplerate(settings.m_devSampleRate);
}
}
}
if ((m_settings.m_loPpmCorrection != settings.m_loPpmCorrection) || force)
{
if (m_dev != 0)
{
if (rtlsdr_set_freq_correction(m_dev, settings.m_loPpmCorrection) < 0)
{
qCritical("could not set LO ppm correction: %d", settings.m_loPpmCorrection);
else {
}
else
{
m_settings.m_loPpmCorrection = settings.m_loPpmCorrection;
//m_rtlSDRThread->setSamplerate(settings.m_samplerate);
}
}
}
if((m_settings.m_log2Decim != settings.m_log2Decim) || force) {
if(m_dev != NULL) {
if ((m_settings.m_log2Decim != settings.m_log2Decim) || force)
{
if(m_dev != 0)
{
m_settings.m_log2Decim = settings.m_log2Decim;
m_rtlSDRThread->setLog2Decimation(settings.m_log2Decim);
}
}
m_generalSettings.m_centerFrequency = generalSettings.m_centerFrequency;
if(m_dev != NULL) {
qint64 centerFrequency = m_generalSettings.m_centerFrequency + (m_settings.m_samplerate / 4);
m_settings.m_centerFrequency = settings.m_centerFrequency;
if (m_settings.m_log2Decim == 0) { // Little wooby-doop if no decimation
centerFrequency = m_generalSettings.m_centerFrequency;
} else {
centerFrequency = m_generalSettings.m_centerFrequency + (m_settings.m_samplerate / 4);
if(m_dev != 0)
{
qint64 centerFrequency = m_settings.m_centerFrequency + (m_settings.m_devSampleRate / 4);
if (m_settings.m_log2Decim == 0)
{ // Little wooby-doop if no decimation
centerFrequency = m_settings.m_centerFrequency;
}
else
{
centerFrequency = m_settings.m_centerFrequency + (m_settings.m_devSampleRate / 4);
}
if(rtlsdr_set_center_freq( m_dev, centerFrequency ) != 0)
qDebug("osmosdr_set_center_freq(%lld) failed", m_generalSettings.m_centerFrequency);
if (rtlsdr_set_center_freq( m_dev, centerFrequency ) != 0)
{
qDebug("rtlsdr_set_center_freq(%lld) failed", m_settings.m_centerFrequency);
}
}
return true;

View File

@ -27,8 +27,9 @@ class RTLSDRThread;
class RTLSDRInput : public SampleSource {
public:
struct Settings {
int m_devSampleRate;
quint64 m_centerFrequency;
qint32 m_gain;
qint32 m_samplerate;
qint32 m_loPpmCorrection;
quint32 m_log2Decim;
@ -42,21 +43,18 @@ public:
MESSAGE_CLASS_DECLARATION
public:
const GeneralSettings& getGeneralSettings() const { return m_generalSettings; }
const Settings& getSettings() const { return m_settings; }
static MsgConfigureRTLSDR* create(const GeneralSettings& generalSettings, const Settings& settings)
static MsgConfigureRTLSDR* create(const Settings& settings)
{
return new MsgConfigureRTLSDR(generalSettings, settings);
return new MsgConfigureRTLSDR(settings);
}
private:
GeneralSettings m_generalSettings;
Settings m_settings;
MsgConfigureRTLSDR(const GeneralSettings& generalSettings, const Settings& settings) :
MsgConfigureRTLSDR(const Settings& settings) :
Message(),
m_generalSettings(generalSettings),
m_settings(settings)
{ }
};
@ -81,18 +79,18 @@ public:
{ }
};
RTLSDRInput(MessageQueue* msgQueueToGUI);
~RTLSDRInput();
RTLSDRInput();
virtual ~RTLSDRInput();
bool startInput(int device);
void stopInput();
virtual bool init(const Message& message);
virtual bool start(int device);
virtual void stop();
const QString& getDeviceDescription() const;
int getSampleRate() const;
quint64 getCenterFrequency() const;
bool handleMessage(Message* message);
virtual const QString& getDeviceDescription() const;
virtual int getSampleRate() const;
virtual quint64 getCenterFrequency() const;
virtual bool handleMessage(const Message& message);
void set_ds_mode(int on);
@ -104,7 +102,7 @@ private:
QString m_deviceDescription;
std::vector<int> m_gains;
bool applySettings(const GeneralSettings& generalSettings, const Settings& settings, bool force);
bool applySettings(const Settings& settings, bool force);
};
#endif // INCLUDE_RTLSDRINPUT_H

View File

@ -20,22 +20,6 @@ Channelizer::~Channelizer()
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)
{
Message* cmd = new DSPConfigureChannelizer(sampleRate, centerFrequency);
@ -84,31 +68,27 @@ bool Channelizer::handleMessage(const Message& cmd)
{
qDebug() << "Channelizer::handleMessage: " << cmd.getIdentifier();
/*
if (DSPSignalNotification::match(&cmd))
if (DSPSignalNotification::match(cmd))
{
DSPSignalNotification* notif = (DSPSignalNotification*) &cmd;
m_inputSampleRate = notif->getSampleRate();
DSPSignalNotification& notif = (DSPSignalNotification&) cmd;
m_inputSampleRate = notif.getSampleRate();
qDebug() << "Channelizer::handleMessage: DSPSignalNotification: m_inputSampleRate: " << m_inputSampleRate;
applyConfiguration();
delete cmd;
if (m_sampleSink != NULL)
{
DSPSignalNotification notif(m_currentOutputSampleRate, m_currentCenterFrequency);
m_sampleSink->handleMessage(notif))
m_sampleSink->handleMessage(notif);
}
emit inputSampleRateChanged();
return true;
}
else*/
if (DSPConfigureChannelizer::match(&cmd))
else
if (DSPConfigureChannelizer::match(cmd))
{
DSPConfigureChannelizer* chan = (DSPConfigureChannelizer*) &cmd;
m_requestedOutputSampleRate = chan->getSampleRate();
m_requestedCenterFrequency = chan->getCenterFrequency();
DSPConfigureChannelizer& chan = (DSPConfigureChannelizer&) cmd;
m_requestedOutputSampleRate = chan.getSampleRate();
m_requestedCenterFrequency = chan.getCenterFrequency();
qDebug() << "Channelizer::handleMessage: DSPConfigureChannelizer:"
<< " m_requestedOutputSampleRate: " << m_requestedOutputSampleRate

View File

@ -27,6 +27,8 @@ MESSAGE_CLASS_DEFINITION(DSPGetErrorMessage, Message)
MESSAGE_CLASS_DEFINITION(DSPSetSource, Message)
MESSAGE_CLASS_DEFINITION(DSPAddSink, Message)
MESSAGE_CLASS_DEFINITION(DSPRemoveSink, Message)
MESSAGE_CLASS_DEFINITION(DSPAddThreadedSink, Message)
MESSAGE_CLASS_DEFINITION(DSPRemoveThreadedSink, Message)
MESSAGE_CLASS_DEFINITION(DSPAddAudioSink, Message)
MESSAGE_CLASS_DEFINITION(DSPRemoveAudioSink, Message)
MESSAGE_CLASS_DEFINITION(DSPConfigureSpectrumVis, Message)

View File

@ -21,13 +21,14 @@
#include "dsp/channelizer.h"
#include "dsp/samplefifo.h"
#include "dsp/samplesink.h"
#include "dsp/threadedsamplesink.h"
#include "dsp/dspcommands.h"
#include "dsp/samplesource/samplesource.h"
DSPEngine::DSPEngine(QObject* parent) :
QThread(parent),
m_state(StNotStarted),
m_sampleSource(NULL),
m_sampleSource(0),
m_sampleSinks(),
m_sampleRate(0),
m_centerFrequency(0),
@ -71,34 +72,34 @@ void DSPEngine::start()
qDebug() << "DSPEngine::start";
DSPPing cmd;
QThread::start();
m_syncMessenger.sendWait(&cmd);
m_syncMessenger.sendWait(cmd);
}
void DSPEngine::stop()
{
qDebug() << "DSPEngine::stop";
DSPExit cmd;
m_syncMessenger.sendWait(&cmd);
m_syncMessenger.sendWait(cmd);
}
bool DSPEngine::initAcquisition()
{
DSPAcquisitionInit cmd;
return m_syncMessenger.sendWait(&cmd) == StReady;
return m_syncMessenger.sendWait(cmd) == StReady;
}
bool DSPEngine::startAcquisition()
{
DSPAcquisitionStart cmd;
return m_syncMessenger.sendWait(&cmd) == StRunning;
return m_syncMessenger.sendWait(cmd) == StRunning;
}
void DSPEngine::stopAcquistion()
{
DSPAcquisitionStop cmd;
m_syncMessenger.sendWait(&cmd);
m_syncMessenger.sendWait(cmd);
if(m_dcOffsetCorrection)
{
@ -109,32 +110,45 @@ void DSPEngine::stopAcquistion()
void DSPEngine::setSource(SampleSource* source)
{
DSPSetSource cmd(source);
m_syncMessenger.sendWait(&cmd);
m_syncMessenger.sendWait(cmd);
}
void DSPEngine::addSink(SampleSink* sink)
{
qDebug() << "DSPEngine::addSink: " << sink->objectName().toStdString().c_str();
DSPAddSink cmd(sink);
m_syncMessenger.sendWait(&cmd);
m_syncMessenger.sendWait(cmd);
}
void DSPEngine::removeSink(SampleSink* sink)
{
DSPRemoveSink cmd(sink);
m_syncMessenger.sendWait(&cmd);
m_syncMessenger.sendWait(cmd);
}
void DSPEngine::addThreadedSink(SampleSink* sink)
{
qDebug() << "DSPEngine::addThreadedSink: " << sink->objectName().toStdString().c_str();
DSPAddThreadedSink cmd(sink);
m_syncMessenger.sendWait(cmd);
}
void DSPEngine::removeThreadedSink(SampleSink* sink)
{
DSPRemoveThreadedSink cmd(sink);
m_syncMessenger.sendWait(cmd);
}
void DSPEngine::addAudioSink(AudioFifo* audioFifo)
{
DSPAddAudioSink cmd(audioFifo);
m_syncMessenger.sendWait(&cmd);
m_syncMessenger.sendWait(cmd);
}
void DSPEngine::removeAudioSink(AudioFifo* audioFifo)
{
DSPRemoveAudioSink cmd(audioFifo);
m_syncMessenger.sendWait(&cmd);
m_syncMessenger.sendWait(cmd);
}
void DSPEngine::configureCorrections(bool dcOffsetCorrection, bool iqImbalanceCorrection)
@ -146,14 +160,14 @@ void DSPEngine::configureCorrections(bool dcOffsetCorrection, bool iqImbalanceCo
QString DSPEngine::errorMessage()
{
DSPGetErrorMessage cmd;
m_syncMessenger.sendWait(&cmd);
m_syncMessenger.sendWait(cmd);
return cmd.getErrorMessage();
}
QString DSPEngine::sourceDeviceDescription()
{
DSPGetSourceDeviceDescription cmd;
m_syncMessenger.sendWait(&cmd);
m_syncMessenger.sendWait(cmd);
return cmd.getDeviceDescription();
}
@ -360,11 +374,18 @@ DSPEngine::State DSPEngine::gotoInit()
<< " sampleRate: " << m_sampleRate
<< " centerFrequency: " << m_centerFrequency;
for(SampleSinks::const_iterator it = m_sampleSinks.begin(); it != m_sampleSinks.end(); it++)
DSPSignalNotification notif(m_sampleRate, m_centerFrequency);
for (SampleSinks::const_iterator it = m_sampleSinks.begin(); it != m_sampleSinks.end(); ++it)
{
qDebug() << " - initializing " << (*it)->objectName().toStdString().c_str();
DSPSignalNotification notif(m_sampleRate, m_centerFrequency);
(*it)->init(notif);
(*it)->handleMessage(notif);
}
for (ThreadedSampleSinks::const_iterator it = m_threadedSampleSinks.begin(); it != m_threadedSampleSinks.end(); ++it)
{
qDebug() << " - initializing ThreadedSampleSink(" << (*it)->getSampleSinkObjectName().toStdString().c_str() << ")";
(*it)->sendWaitSink(notif);
}
// pass sample rate to main window
@ -416,6 +437,12 @@ DSPEngine::State DSPEngine::gotoRunning()
(*it)->start();
}
for (ThreadedSampleSinks::const_iterator it = m_threadedSampleSinks.begin(); it != m_threadedSampleSinks.end(); ++it)
{
qDebug() << " - starting ThreadedSampleSink(" << (*it)->getSampleSinkObjectName().toStdString().c_str() << ")";
(*it)->start();
}
qDebug() << " - input message queue pending: " << m_inputMessageQueue.size();
return StRunning;
@ -459,7 +486,7 @@ void DSPEngine::handleData()
}
}
void DSPEngine::handleSynchronousMessages(Message *message)
void DSPEngine::handleSynchronousMessages(const Message& message)
{
if (DSPExit::match(message))
{
@ -493,27 +520,27 @@ void DSPEngine::handleSynchronousMessages(Message *message)
}
else if (DSPGetSourceDeviceDescription::match(message))
{
((DSPGetSourceDeviceDescription*)message)->setDeviceDescription(m_deviceDescription);
((DSPGetSourceDeviceDescription&) message).setDeviceDescription(m_deviceDescription);
m_syncMessenger.done(m_state);
}
else if (DSPGetErrorMessage::match(message))
{
((DSPGetErrorMessage*)message)->setErrorMessage(m_errorMessage);
((DSPGetErrorMessage&) message).setErrorMessage(m_errorMessage);
m_syncMessenger.done(m_state);
}
else if (DSPSetSource::match(message)) {
handleSetSource(((DSPSetSource*)message)->getSampleSource());
handleSetSource(((DSPSetSource&) message).getSampleSource());
m_syncMessenger.done(m_state);
}
else if (DSPAddSink::match(message))
{
SampleSink* sink = ((DSPAddSink*)message)->getSampleSink();
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();
SampleSink* sink = ((DSPRemoveSink&)message).getSampleSink();
if(m_state == StRunning) {
sink->stop();
@ -522,14 +549,46 @@ void DSPEngine::handleSynchronousMessages(Message *message)
m_sampleSinks.remove(sink);
m_syncMessenger.done(m_state);
}
else if (DSPAddThreadedSink::match(message))
{
SampleSink* sink = ((DSPAddThreadedSink&) message).getSampleSink();
ThreadedSampleSink *threadedSink = new ThreadedSampleSink(sink);
m_threadedSampleSinks.push_back(threadedSink);
threadedSink->start();
m_syncMessenger.done(m_state);
}
else if (DSPRemoveThreadedSink::match(message))
{
SampleSink* sink = ((DSPRemoveThreadedSink&) message).getSampleSink();
ThreadedSampleSinks::iterator threadedSinkIt = m_threadedSampleSinks.begin();
for (; threadedSinkIt != m_threadedSampleSinks.end(); ++threadedSinkIt)
{
if ((*threadedSinkIt)->getSink() == sink)
{
break;
}
}
if (threadedSinkIt != m_threadedSampleSinks.end())
{
if (m_state == StRunning)
{
(*threadedSinkIt)->stop();
}
m_threadedSampleSinks.remove(*threadedSinkIt);
delete (*threadedSinkIt);
}
}
else if (DSPAddAudioSink::match(message))
{
m_audioSink.addFifo(((DSPAddAudioSink*)message)->getAudioFifo());
m_audioSink.addFifo(((DSPAddAudioSink&) message).getAudioFifo());
m_syncMessenger.done(m_state);
}
else if (DSPRemoveAudioSink::match(message))
{
m_audioSink.removeFifo(((DSPRemoveAudioSink*)message)->getAudioFifo());
m_audioSink.removeFifo(((DSPRemoveAudioSink&) message).getAudioFifo());
m_syncMessenger.done(m_state);
}
@ -544,9 +603,9 @@ void DSPEngine::handleInputMessages()
{
qDebug("DSPEngine::handleInputMessages: Message: %s", message->getIdentifier());
if (DSPConfigureCorrection::match(message))
if (DSPConfigureCorrection::match(*message))
{
DSPConfigureCorrection* conf = (DSPConfigureCorrection*)message;
DSPConfigureCorrection* conf = (DSPConfigureCorrection*) message;
m_iqImbalanceCorrection = conf->getIQImbalanceCorrection();
if(m_dcOffsetCorrection != conf->getDCOffsetCorrection())
@ -577,21 +636,29 @@ void DSPEngine::handleSourceMessages()
while ((message = m_sampleSource->getOutputMessageQueue()->pop()) != 0)
{
if (DSPSignalNotification::match(message))
if (DSPSignalNotification::match(*message))
{
DSPSignalNotification *notif = (DSPSignalNotification *) &message;
DSPSignalNotification *notif = (DSPSignalNotification *) message;
// update DSP values
m_sampleRate = notif->getSampleRate();
m_centerFrequency = notif->getFrequencyOffset();
qDebug() << " - DSPSignalNotification(" << m_sampleRate << "," << m_centerFrequency << ")";
// forward source changes to sinks
for(SampleSinks::const_iterator it = m_sampleSinks.begin(); it != m_sampleSinks.end(); it++)
{
qDebug() << " - initializing " << (*it)->objectName().toStdString().c_str();
(*it)->init(*message);
qDebug() << " - forward message to " << (*it)->objectName().toStdString().c_str();
(*it)->handleMessage(*message);
}
for (ThreadedSampleSinks::const_iterator it = m_threadedSampleSinks.begin(); it != m_threadedSampleSinks.end(); ++it)
{
qDebug() << " - forward message to ThreadedSampleSink(" << (*it)->getSampleSinkObjectName().toStdString().c_str() << ")";
(*it)->sendWaitSink(*message);
}
// forward changes to listeners

View File

@ -30,22 +30,6 @@ void FileSink::configure(MessageQueue* msgQueue, const std::string& filename)
msgQueue->push(cmd);
}
bool FileSink::init(const Message& cmd)
{
if (DSPSignalNotification::match(&cmd))
{
DSPSignalNotification* notif = (DSPSignalNotification*) &cmd;
m_sampleRate = notif->getSampleRate();
m_centerFrequency = notif->getFrequencyOffset();
qDebug() << "FileSink::init: DSPSignalNotification: m_inputSampleRate: " << m_sampleRate;
return true;
}
else
{
return false;
}
}
void FileSink::feed(SampleVector::const_iterator begin, SampleVector::const_iterator end, bool positiveOnly)
{
// if no recording is active, send the samples to /dev/null
@ -99,12 +83,22 @@ void FileSink::stopRecording()
bool FileSink::handleMessage(const Message& message)
{
if (MsgConfigureFileSink::match(&message))
qDebug() << "FileSink::handleMessage";
if (DSPSignalNotification::match(message))
{
DSPSignalNotification& notif = (DSPSignalNotification&) message;
m_sampleRate = notif.getSampleRate();
m_centerFrequency = notif.getFrequencyOffset();
qDebug() << " - DSPSignalNotification: m_inputSampleRate: " << m_sampleRate
<< " m_centerFrequency: " << m_centerFrequency;
return true;
}
else if (MsgConfigureFileSink::match(message))
{
MsgConfigureFileSink* conf = (MsgConfigureFileSink*) &message;
handleConfigure(conf->getFileName());
qDebug() << "FileSink::handleMessage:"
<< " fileName: " << m_fileName.c_str();
MsgConfigureFileSink& conf = (MsgConfigureFileSink&) message;
handleConfigure(conf.getFileName());
qDebug() << " - MsgConfigureFileSink: fileName: " << m_fileName.c_str();
return true;
}
else

View File

@ -1,9 +1,25 @@
#include "dsp/samplesink.h"
#include "util/message.h"
SampleSink::SampleSink()
{
connect(&m_inputMessageQueue, SIGNAL(messageEnqueued()), this, SLOT(handleInputMessage()));
}
SampleSink::~SampleSink()
{
}
void SampleSink::handleInputMessages()
{
Message* message;
while ((message = m_inputMessageQueue.pop()) != 0)
{
if (handleMessage(*message))
{
delete message;
}
}
}

View File

@ -16,41 +16,11 @@
///////////////////////////////////////////////////////////////////////////////////
#include "dsp/samplesource/samplesource.h"
#include "dsp/dspcommands.h"
#include <QDebug>
SampleSource::SampleSource() :
m_sampleRate(0),
m_centerFrequency(0)
SampleSource::SampleSource()
{
}
SampleSource::~SampleSource()
{
}
void SampleSource::setSampleRate(int sampleRate)
{
if (sampleRate != m_sampleRate)
{
// TODO: adjust FIFO size
m_sampleRate = sampleRate;
sendNewData();
}
}
void SampleSource::setCenterFrequency(quint64 centerFrequency)
{
if (centerFrequency != m_centerFrequency)
{
m_centerFrequency = centerFrequency;
sendNewData();
}
}
void SampleSource::sendNewData()
{
DSPSignalNotification *notif = new DSPSignalNotification(m_sampleRate, m_centerFrequency);
m_outputMessageQueue.push(notif);
}

View File

@ -55,20 +55,6 @@ void ScopeVis::configure(MessageQueue* msgQueue,
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)
{
if (m_triggerChannel == TriggerFreeRun) {
@ -220,28 +206,47 @@ void ScopeVis::stop()
bool ScopeVis::handleMessage(const Message& message)
{
if (MsgConfigureScopeVis::match(&message))
qDebug() << "ScopeVis::handleMessage";
if (DSPSignalNotification::match(message))
{
MsgConfigureScopeVis* conf = (MsgConfigureScopeVis*) &message;
m_tracebackCount = 0;
DSPSignalNotification& notif = (DSPSignalNotification&) message;
m_sampleRate = notif.getSampleRate();
qDebug() << " - DSPSignalNotification: m_sampleRate: " << m_sampleRate;
return true;
}
else if (MsgConfigureScopeVis::match(message))
{
MsgConfigureScopeVis& conf = (MsgConfigureScopeVis&) message;
m_tracebackCount = 0;
m_triggerState = Config;
m_triggerChannel = (TriggerChannel) conf->getTriggerChannel();
m_triggerLevel = conf->getTriggerLevel();
m_triggerPositiveEdge = conf->getTriggerPositiveEdge();
m_triggerBothEdges = conf->getTriggerBothEdges();
m_triggerPre = conf->getTriggerPre();
if (m_triggerPre >= m_traceback.size()) {
m_triggerChannel = (TriggerChannel) conf.getTriggerChannel();
m_triggerLevel = conf.getTriggerLevel();
m_triggerPositiveEdge = conf.getTriggerPositiveEdge();
m_triggerBothEdges = conf.getTriggerBothEdges();
m_triggerPre = conf.getTriggerPre();
if (m_triggerPre >= m_traceback.size())
{
m_triggerPre = m_traceback.size() - 1; // top sample in FIFO is always the triggering one (pre-trigger delay = 0)
}
m_triggerDelay = conf->getTriggerDelay();
uint newSize = conf->getTraceSize();
if (newSize != m_trace.size()) {
m_triggerDelay = conf.getTriggerDelay();
uint newSize = conf.getTraceSize();
if (newSize != m_trace.size())
{
m_trace.resize(newSize);
}
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);
}
qDebug() << "ScopeVis::handleMessage:"
qDebug() << " - MsgConfigureScopeVis:"
<< " m_triggerChannel: " << m_triggerChannel
<< " m_triggerLevel: " << m_triggerLevel
<< " m_triggerPositiveEdge: " << (m_triggerPositiveEdge ? "edge+" : "edge-")
@ -249,6 +254,7 @@ bool ScopeVis::handleMessage(const Message& message)
<< " m_preTrigger: " << m_triggerPre
<< " m_triggerDelay: " << m_triggerDelay
<< " m_traceSize: " << m_trace.size();
return true;
}
else

View File

@ -13,14 +13,6 @@ 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)
{
m_scopeVis->feed(begin, end, false);

View File

@ -30,11 +30,6 @@ SpectrumVis::~SpectrumVis()
delete m_fft;
}
bool SpectrumVis::init(const Message& cmd)
{
return false;
}
void SpectrumVis::configure(MessageQueue* msgQueue, int fftSize, int overlapPercent, FFTWindow::Function window)
{
DSPConfigureSpectrumVis* cmd = new DSPConfigureSpectrumVis(fftSize, overlapPercent, window);
@ -69,13 +64,13 @@ void SpectrumVis::feed(SampleVector::const_iterator begin, SampleVector::const_i
return;
while(begin < end) {
size_t todo = end - begin;
size_t samplesNeeded = m_refillSize - m_fftBufferFill;
std::size_t todo = end - begin;
std::size_t samplesNeeded = m_refillSize - m_fftBufferFill;
if(todo >= samplesNeeded) {
// fill up the buffer
std::vector<Complex>::iterator it = m_fftBuffer.begin() + m_fftBufferFill;
for(size_t i = 0; i < samplesNeeded; ++i, ++begin)
for(std::size_t i = 0; i < samplesNeeded; ++i, ++begin)
*it++ = Complex(begin->real() / 32768.0, begin->imag() / 32768.0);
// apply fft window (and copy from m_fftBuffer to m_fftIn)
@ -90,10 +85,10 @@ void SpectrumVis::feed(SampleVector::const_iterator begin, SampleVector::const_i
const Complex* fftOut = m_fft->out();
Complex c;
Real v;
size_t halfSize = m_fftSize / 2;
std::size_t halfSize = m_fftSize / 2;
if ( positiveOnly ) {
for(size_t i = 0; i < halfSize; i++) {
for(std::size_t i = 0; i < halfSize; i++) {
c = fftOut[i];
v = c.real() * c.real() + c.imag() * c.imag();
v = mult * log2f(v) + ofs;
@ -101,7 +96,7 @@ void SpectrumVis::feed(SampleVector::const_iterator begin, SampleVector::const_i
m_logPowerSpectrum[i * 2 + 1] = v;
}
} else {
for(size_t i = 0; i < halfSize; i++) {
for(std::size_t i = 0; i < halfSize; i++) {
c = fftOut[i + halfSize];
v = c.real() * c.real() + c.imag() * c.imag();
v = mult * log2f(v) + ofs;
@ -143,10 +138,10 @@ void SpectrumVis::stop()
bool SpectrumVis::handleMessage(const Message& message)
{
if(DSPConfigureSpectrumVis::match(&message))
if (DSPConfigureSpectrumVis::match(message))
{
DSPConfigureSpectrumVis* conf = (DSPConfigureSpectrumVis*) &message;
handleConfigure(conf->getFFTSize(), conf->getOverlapPercent(), conf->getWindow());
DSPConfigureSpectrumVis& conf = (DSPConfigureSpectrumVis&) message;
handleConfigure(conf.getFFTSize(), conf.getOverlapPercent(), conf.getWindow());
return true;
}
else

View File

@ -4,59 +4,56 @@
#include "util/message.h"
ThreadedSampleSink::ThreadedSampleSink(SampleSink* sampleSink) :
m_thread(new QThread),
m_sampleSink(sampleSink)
{
setObjectName("ThreadedSampleSink");
moveToThread(m_thread);
connect(m_thread, SIGNAL(started()), this, SLOT(threadStarted()));
connect(m_thread, SIGNAL(finished()), this, SLOT(threadFinished()));
m_messageQueue.moveToThread(m_thread);
connect(&m_messageQueue, SIGNAL(messageEnqueued()), this, SLOT(handleMessages()));
m_sampleFifo.moveToThread(m_thread);
connect(&m_sampleFifo, SIGNAL(dataReady()), this, SLOT(handleData()));
m_sampleFifo.setSize(262144);
sampleSink->moveToThread(m_thread);
moveToThread(this);
}
ThreadedSampleSink::~ThreadedSampleSink()
{
m_thread->exit();
m_thread->wait();
delete m_thread;
}
void ThreadedSampleSink::feed(SampleVector::const_iterator begin, SampleVector::const_iterator end, bool positiveOnly)
{
Q_UNUSED(positiveOnly);
m_sampleFifo.write(begin, end);
wait();
}
void ThreadedSampleSink::start()
{
m_thread->start();
QThread::start();
}
void ThreadedSampleSink::stop()
{
m_thread->exit();
m_thread->wait();
m_sampleFifo.readCommit(m_sampleFifo.fill());
exit();
wait();
}
bool ThreadedSampleSink::handleMessage(Message* cmd)
void ThreadedSampleSink::run()
{
qDebug() << "ThreadedSampleSink::handleMessage: "
<< m_sampleSink->objectName().toStdString().c_str()
<< ": " << cmd->getIdentifier();
// called from other thread
m_messageQueue.submit(cmd);
return true;
connect(&m_syncMessenger, SIGNAL(messageSent(const Message&)), this, SLOT(handleSynchronousMessages(const Message&)), Qt::QueuedConnection);
exec();
}
void ThreadedSampleSink::feed(SampleVector::const_iterator& begin, SampleVector::const_iterator& end, bool positiveOnly)
{
m_sampleSink->feed(begin, end, positiveOnly);
}
bool ThreadedSampleSink::sendWaitSink(const Message& cmd)
{
m_syncMessenger.sendWait(cmd);
}
void ThreadedSampleSink::handleSynchronousMessages(const Message& message)
{
m_sampleSink->handleMessage(message); // just delegate to the sink
m_syncMessenger.done();
}
QString ThreadedSampleSink::getSampleSinkObjectName() const
{
return m_sampleSink->objectName();
}
/*
void ThreadedSampleSink::handleData()
{
bool positiveOnly = false;
@ -84,30 +81,5 @@ void ThreadedSampleSink::handleData()
m_sampleFifo.readCommit(part2end - part2begin);
}
}
}
}*/
void ThreadedSampleSink::handleMessages()
{
Message* message;
while((message = m_messageQueue.accept()) != NULL) {
qDebug("ThreadedSampleSink::handleMessages: %s", message->getIdentifier());
if(m_sampleSink != NULL) {
if(!m_sampleSink->handleMessage(message))
message->completed();
} else {
message->completed();
}
}
}
void ThreadedSampleSink::threadStarted()
{
if(m_sampleSink != NULL)
m_sampleSink->start();
}
void ThreadedSampleSink::threadFinished()
{
if(m_sampleSink != NULL)
m_sampleSink->stop();
}

View File

@ -325,9 +325,9 @@ void MainWindow::handleDSPMessages()
std::cerr << "MainWindow::handleDSPMessages: " << message->getIdentifier() << std::endl;
if (DSPEngineReport::match(message))
if (DSPEngineReport::match(*message))
{
DSPEngineReport* rep = (DSPEngineReport*)message;
DSPEngineReport* rep = (DSPEngineReport*) message;
m_sampleRate = rep->getSampleRate();
m_centerFrequency = rep->getCenterFrequency();
qDebug("SampleRate:%d, CenterFrequency:%llu", rep->getSampleRate(), rep->getCenterFrequency());
@ -350,7 +350,7 @@ void MainWindow::handleMessages()
qDebug("Message: %s", message->getIdentifier());
std::cerr << "MainWindow::handleMessages: " << message->getIdentifier() << std::endl;
if (!m_pluginManager->handleMessage(message))
if (!m_pluginManager->handleMessage(*message))
{
delete message;
}

View File

@ -54,6 +54,7 @@ void PluginAPI::removeChannelMarker(ChannelMarker* channelMarker)
m_mainWindow->removeChannelMarker(channelMarker);
}
/*
void PluginAPI::setSampleSource(SampleSource* sampleSource)
{
m_dspEngine->stopAcquistion();
@ -83,7 +84,7 @@ void PluginAPI::addAudioSource(AudioFifo* audioFifo)
void PluginAPI::removeAudioSource(AudioFifo* audioFifo)
{
m_dspEngine->removeAudioSink(audioFifo);
}
}*/
void PluginAPI::registerSampleSource(const QString& sourceName, PluginInterface* plugin)
{

View File

@ -177,21 +177,30 @@ void PluginManager::freeAll()
}
}
bool PluginManager::handleMessage(Message* message)
bool PluginManager::handleMessage(const Message& message)
{
if(m_sampleSourceInstance != NULL) {
if((message->getDestination() == NULL) || (message->getDestination() == m_sampleSourceInstance)) {
if(m_sampleSourceInstance->handleMessage(message))
if (m_sampleSourceInstance != 0)
{
if ((message.getDestination() == 0) || (message.getDestination() == m_sampleSourceInstance))
{
if (m_sampleSourceInstance->handleMessage(message))
{
return true;
}
}
}
for(ChannelInstanceRegistrations::iterator it = m_channelInstanceRegistrations.begin(); it != m_channelInstanceRegistrations.end(); ++it) {
if((message->getDestination() == NULL) || (message->getDestination() == it->m_gui)) {
if(it->m_gui->handleMessage(message))
for (ChannelInstanceRegistrations::iterator it = m_channelInstanceRegistrations.begin(); it != m_channelInstanceRegistrations.end(); ++it)
{
if ((message.getDestination() == 0) || (message.getDestination() == it->m_gui))
{
if (it->m_gui->handleMessage(message))
{
return true;
}
}
}
return false;
}

View File

@ -26,7 +26,7 @@ SyncMessenger::SyncMessenger() :
SyncMessenger::~SyncMessenger()
{}
int SyncMessenger::sendWait(Message *message, unsigned long msPollTime)
int SyncMessenger::sendWait(const Message& message, unsigned long msPollTime)
{
m_mutex.lock();
m_complete.testAndSetAcquire(0, 1);