mirror of https://github.com/f4exb/sdrangel.git
Created demod constructor method in all Rx channel plugins
This commit is contained in:
parent
cef9d5d7bc
commit
4ad038ed9d
|
@ -1,236 +1,237 @@
|
||||||
///////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////
|
||||||
// Copyright (C) 2015 Edouard Griffiths, F4EXB //
|
// Copyright (C) 2015 Edouard Griffiths, F4EXB //
|
||||||
// //
|
// //
|
||||||
// This program is free software; you can redistribute it and/or modify //
|
// This program is free software; you can redistribute it and/or modify //
|
||||||
// it under the terms of the GNU General Public License as published by //
|
// it under the terms of the GNU General Public License as published by //
|
||||||
// the Free Software Foundation as version 3 of the License, or //
|
// the Free Software Foundation as version 3 of the License, or //
|
||||||
// //
|
// //
|
||||||
// This program is distributed in the hope that it will be useful, //
|
// This program is distributed in the hope that it will be useful, //
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
|
||||||
// GNU General Public License V3 for more details. //
|
// GNU General Public License V3 for more details. //
|
||||||
// //
|
// //
|
||||||
// You should have received a copy of the GNU General Public License //
|
// You should have received a copy of the GNU General Public License //
|
||||||
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
|
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
|
||||||
///////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
#include "chanalyzer.h"
|
#include "chanalyzer.h"
|
||||||
|
|
||||||
#include <QTime>
|
#include <QTime>
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
#include <dsp/downchannelizer.h>
|
#include <dsp/downchannelizer.h>
|
||||||
#include "dsp/threadedbasebandsamplesink.h"
|
#include "dsp/threadedbasebandsamplesink.h"
|
||||||
#include "device/devicesourceapi.h"
|
#include "device/devicesourceapi.h"
|
||||||
#include "audio/audiooutput.h"
|
#include "audio/audiooutput.h"
|
||||||
|
|
||||||
|
MESSAGE_CLASS_DEFINITION(ChannelAnalyzer::MsgConfigureChannelAnalyzer, Message)
|
||||||
MESSAGE_CLASS_DEFINITION(ChannelAnalyzer::MsgConfigureChannelAnalyzer, Message)
|
MESSAGE_CLASS_DEFINITION(ChannelAnalyzer::MsgConfigureChannelizer, Message)
|
||||||
MESSAGE_CLASS_DEFINITION(ChannelAnalyzer::MsgConfigureChannelizer, Message)
|
MESSAGE_CLASS_DEFINITION(ChannelAnalyzer::MsgReportChannelSampleRateChanged, Message)
|
||||||
MESSAGE_CLASS_DEFINITION(ChannelAnalyzer::MsgReportChannelSampleRateChanged, Message)
|
|
||||||
|
const QString ChannelAnalyzer::m_channelID = "org.f4exb.sdrangelove.channel.chanalyzer";
|
||||||
ChannelAnalyzer::ChannelAnalyzer(DeviceSourceAPI *deviceAPI) :
|
|
||||||
m_deviceAPI(deviceAPI),
|
ChannelAnalyzer::ChannelAnalyzer(DeviceSourceAPI *deviceAPI) :
|
||||||
m_sampleSink(0),
|
m_deviceAPI(deviceAPI),
|
||||||
m_settingsMutex(QMutex::Recursive)
|
m_sampleSink(0),
|
||||||
{
|
m_settingsMutex(QMutex::Recursive)
|
||||||
m_Bandwidth = 5000;
|
{
|
||||||
m_LowCutoff = 300;
|
m_Bandwidth = 5000;
|
||||||
m_spanLog2 = 3;
|
m_LowCutoff = 300;
|
||||||
m_sampleRate = 96000;
|
m_spanLog2 = 3;
|
||||||
m_frequency = 0;
|
m_sampleRate = 96000;
|
||||||
m_nco.setFreq(m_frequency, m_sampleRate);
|
m_frequency = 0;
|
||||||
m_undersampleCount = 0;
|
m_nco.setFreq(m_frequency, m_sampleRate);
|
||||||
m_sum = 0;
|
m_undersampleCount = 0;
|
||||||
m_usb = true;
|
m_sum = 0;
|
||||||
m_ssb = true;
|
m_usb = true;
|
||||||
m_magsq = 0;
|
m_ssb = true;
|
||||||
SSBFilter = new fftfilt(m_LowCutoff / m_sampleRate, m_Bandwidth / m_sampleRate, ssbFftLen);
|
m_magsq = 0;
|
||||||
DSBFilter = new fftfilt(m_Bandwidth / m_sampleRate, 2*ssbFftLen);
|
SSBFilter = new fftfilt(m_LowCutoff / m_sampleRate, m_Bandwidth / m_sampleRate, ssbFftLen);
|
||||||
|
DSBFilter = new fftfilt(m_Bandwidth / m_sampleRate, 2*ssbFftLen);
|
||||||
m_channelizer = new DownChannelizer(this);
|
|
||||||
m_threadedChannelizer = new ThreadedBasebandSampleSink(m_channelizer, this);
|
m_channelizer = new DownChannelizer(this);
|
||||||
connect(m_channelizer, SIGNAL(inputSampleRateChanged()), this, SLOT(channelSampleRateChanged()));
|
m_threadedChannelizer = new ThreadedBasebandSampleSink(m_channelizer, this);
|
||||||
m_deviceAPI->addThreadedSink(m_threadedChannelizer);
|
connect(m_channelizer, SIGNAL(inputSampleRateChanged()), this, SLOT(channelSampleRateChanged()));
|
||||||
}
|
m_deviceAPI->addThreadedSink(m_threadedChannelizer);
|
||||||
|
}
|
||||||
ChannelAnalyzer::~ChannelAnalyzer()
|
|
||||||
{
|
ChannelAnalyzer::~ChannelAnalyzer()
|
||||||
if (SSBFilter) delete SSBFilter;
|
{
|
||||||
if (DSBFilter) delete DSBFilter;
|
if (SSBFilter) delete SSBFilter;
|
||||||
m_deviceAPI->removeThreadedSink(m_threadedChannelizer);
|
if (DSBFilter) delete DSBFilter;
|
||||||
delete m_threadedChannelizer;
|
m_deviceAPI->removeThreadedSink(m_threadedChannelizer);
|
||||||
delete m_channelizer;
|
delete m_threadedChannelizer;
|
||||||
}
|
delete m_channelizer;
|
||||||
|
}
|
||||||
void ChannelAnalyzer::configure(MessageQueue* messageQueue,
|
|
||||||
Real Bandwidth,
|
void ChannelAnalyzer::configure(MessageQueue* messageQueue,
|
||||||
Real LowCutoff,
|
Real Bandwidth,
|
||||||
int spanLog2,
|
Real LowCutoff,
|
||||||
bool ssb)
|
int spanLog2,
|
||||||
{
|
bool ssb)
|
||||||
Message* cmd = MsgConfigureChannelAnalyzer::create(Bandwidth, LowCutoff, spanLog2, ssb);
|
{
|
||||||
messageQueue->push(cmd);
|
Message* cmd = MsgConfigureChannelAnalyzer::create(Bandwidth, LowCutoff, spanLog2, ssb);
|
||||||
}
|
messageQueue->push(cmd);
|
||||||
|
}
|
||||||
void ChannelAnalyzer::feed(const SampleVector::const_iterator& begin, const SampleVector::const_iterator& end, bool positiveOnly __attribute__((unused)))
|
|
||||||
{
|
void ChannelAnalyzer::feed(const SampleVector::const_iterator& begin, const SampleVector::const_iterator& end, bool positiveOnly __attribute__((unused)))
|
||||||
fftfilt::cmplx *sideband;
|
{
|
||||||
int n_out;
|
fftfilt::cmplx *sideband;
|
||||||
int decim = 1<<m_spanLog2;
|
int n_out;
|
||||||
unsigned char decim_mask = decim - 1; // counter LSB bit mask for decimation by 2^(m_scaleLog2 - 1)
|
int decim = 1<<m_spanLog2;
|
||||||
|
unsigned char decim_mask = decim - 1; // counter LSB bit mask for decimation by 2^(m_scaleLog2 - 1)
|
||||||
m_settingsMutex.lock();
|
|
||||||
|
m_settingsMutex.lock();
|
||||||
for(SampleVector::const_iterator it = begin; it < end; ++it)
|
|
||||||
{
|
for(SampleVector::const_iterator it = begin; it < end; ++it)
|
||||||
//Complex c(it->real() / 32768.0f, it->imag() / 32768.0f);
|
{
|
||||||
Complex c(it->real(), it->imag());
|
//Complex c(it->real() / 32768.0f, it->imag() / 32768.0f);
|
||||||
c *= m_nco.nextIQ();
|
Complex c(it->real(), it->imag());
|
||||||
|
c *= m_nco.nextIQ();
|
||||||
if (m_ssb)
|
|
||||||
{
|
if (m_ssb)
|
||||||
n_out = SSBFilter->runSSB(c, &sideband, m_usb);
|
{
|
||||||
}
|
n_out = SSBFilter->runSSB(c, &sideband, m_usb);
|
||||||
else
|
}
|
||||||
{
|
else
|
||||||
n_out = DSBFilter->runDSB(c, &sideband);
|
{
|
||||||
}
|
n_out = DSBFilter->runDSB(c, &sideband);
|
||||||
|
}
|
||||||
for (int i = 0; i < n_out; i++)
|
|
||||||
{
|
for (int i = 0; i < n_out; i++)
|
||||||
// Downsample by 2^(m_scaleLog2 - 1) for SSB band spectrum display
|
{
|
||||||
// smart decimation with bit gain using float arithmetic (23 bits significand)
|
// Downsample by 2^(m_scaleLog2 - 1) for SSB band spectrum display
|
||||||
|
// smart decimation with bit gain using float arithmetic (23 bits significand)
|
||||||
m_sum += sideband[i];
|
|
||||||
|
m_sum += sideband[i];
|
||||||
if (!(m_undersampleCount++ & decim_mask))
|
|
||||||
{
|
if (!(m_undersampleCount++ & decim_mask))
|
||||||
m_sum /= decim;
|
{
|
||||||
m_magsq = (m_sum.real() * m_sum.real() + m_sum.imag() * m_sum.imag())/ (1<<30);
|
m_sum /= decim;
|
||||||
|
m_magsq = (m_sum.real() * m_sum.real() + m_sum.imag() * m_sum.imag())/ (1<<30);
|
||||||
if (m_ssb & !m_usb)
|
|
||||||
{ // invert spectrum for LSB
|
if (m_ssb & !m_usb)
|
||||||
//m_sampleBuffer.push_back(Sample(m_sum.imag() * 32768.0, m_sum.real() * 32768.0));
|
{ // invert spectrum for LSB
|
||||||
m_sampleBuffer.push_back(Sample(m_sum.imag(), m_sum.real()));
|
//m_sampleBuffer.push_back(Sample(m_sum.imag() * 32768.0, m_sum.real() * 32768.0));
|
||||||
}
|
m_sampleBuffer.push_back(Sample(m_sum.imag(), m_sum.real()));
|
||||||
else
|
}
|
||||||
{
|
else
|
||||||
//m_sampleBuffer.push_back(Sample(m_sum.real() * 32768.0, m_sum.imag() * 32768.0));
|
{
|
||||||
m_sampleBuffer.push_back(Sample(m_sum.real(), m_sum.imag()));
|
//m_sampleBuffer.push_back(Sample(m_sum.real() * 32768.0, m_sum.imag() * 32768.0));
|
||||||
}
|
m_sampleBuffer.push_back(Sample(m_sum.real(), m_sum.imag()));
|
||||||
|
}
|
||||||
m_sum = 0;
|
|
||||||
}
|
m_sum = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if(m_sampleSink != NULL)
|
|
||||||
{
|
if(m_sampleSink != NULL)
|
||||||
m_sampleSink->feed(m_sampleBuffer.begin(), m_sampleBuffer.end(), m_ssb); // m_ssb = positive only
|
{
|
||||||
}
|
m_sampleSink->feed(m_sampleBuffer.begin(), m_sampleBuffer.end(), m_ssb); // m_ssb = positive only
|
||||||
|
}
|
||||||
m_sampleBuffer.clear();
|
|
||||||
|
m_sampleBuffer.clear();
|
||||||
m_settingsMutex.unlock();
|
|
||||||
}
|
m_settingsMutex.unlock();
|
||||||
|
}
|
||||||
void ChannelAnalyzer::start()
|
|
||||||
{
|
void ChannelAnalyzer::start()
|
||||||
}
|
{
|
||||||
|
}
|
||||||
void ChannelAnalyzer::stop()
|
|
||||||
{
|
void ChannelAnalyzer::stop()
|
||||||
}
|
{
|
||||||
|
}
|
||||||
void ChannelAnalyzer::channelSampleRateChanged()
|
|
||||||
{
|
void ChannelAnalyzer::channelSampleRateChanged()
|
||||||
MsgReportChannelSampleRateChanged *msg = MsgReportChannelSampleRateChanged::create();
|
{
|
||||||
getMessageQueueToGUI()->push(msg);
|
MsgReportChannelSampleRateChanged *msg = MsgReportChannelSampleRateChanged::create();
|
||||||
}
|
getMessageQueueToGUI()->push(msg);
|
||||||
|
}
|
||||||
bool ChannelAnalyzer::handleMessage(const Message& cmd)
|
|
||||||
{
|
bool ChannelAnalyzer::handleMessage(const Message& cmd)
|
||||||
float band, lowCutoff;
|
{
|
||||||
|
float band, lowCutoff;
|
||||||
qDebug() << "ChannelAnalyzer::handleMessage";
|
|
||||||
|
qDebug() << "ChannelAnalyzer::handleMessage";
|
||||||
if (DownChannelizer::MsgChannelizerNotification::match(cmd))
|
|
||||||
{
|
if (DownChannelizer::MsgChannelizerNotification::match(cmd))
|
||||||
DownChannelizer::MsgChannelizerNotification& notif = (DownChannelizer::MsgChannelizerNotification&) cmd;
|
{
|
||||||
|
DownChannelizer::MsgChannelizerNotification& notif = (DownChannelizer::MsgChannelizerNotification&) cmd;
|
||||||
m_sampleRate = notif.getSampleRate();
|
|
||||||
m_nco.setFreq(-notif.getFrequencyOffset(), m_sampleRate);
|
m_sampleRate = notif.getSampleRate();
|
||||||
|
m_nco.setFreq(-notif.getFrequencyOffset(), m_sampleRate);
|
||||||
qDebug() << "ChannelAnalyzer::handleMessage: MsgChannelizerNotification: m_sampleRate: " << m_sampleRate
|
|
||||||
<< " frequencyOffset: " << notif.getFrequencyOffset();
|
qDebug() << "ChannelAnalyzer::handleMessage: MsgChannelizerNotification: m_sampleRate: " << m_sampleRate
|
||||||
|
<< " frequencyOffset: " << notif.getFrequencyOffset();
|
||||||
return true;
|
|
||||||
}
|
return true;
|
||||||
else if (MsgConfigureChannelizer::match(cmd))
|
}
|
||||||
{
|
else if (MsgConfigureChannelizer::match(cmd))
|
||||||
MsgConfigureChannelizer& cfg = (MsgConfigureChannelizer&) cmd;
|
{
|
||||||
|
MsgConfigureChannelizer& cfg = (MsgConfigureChannelizer&) cmd;
|
||||||
m_channelizer->configure(m_channelizer->getInputMessageQueue(),
|
|
||||||
m_channelizer->getInputSampleRate(),
|
m_channelizer->configure(m_channelizer->getInputMessageQueue(),
|
||||||
cfg.getCenterFrequency());
|
m_channelizer->getInputSampleRate(),
|
||||||
|
cfg.getCenterFrequency());
|
||||||
return true;
|
|
||||||
}
|
return true;
|
||||||
else if (MsgConfigureChannelAnalyzer::match(cmd))
|
}
|
||||||
{
|
else if (MsgConfigureChannelAnalyzer::match(cmd))
|
||||||
MsgConfigureChannelAnalyzer& cfg = (MsgConfigureChannelAnalyzer&) 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;
|
band = -band;
|
||||||
m_usb = false;
|
lowCutoff = -lowCutoff;
|
||||||
}
|
m_usb = false;
|
||||||
else
|
}
|
||||||
{
|
else
|
||||||
m_usb = true;
|
{
|
||||||
}
|
m_usb = true;
|
||||||
|
}
|
||||||
if (band < 100.0f)
|
|
||||||
{
|
if (band < 100.0f)
|
||||||
band = 100.0f;
|
{
|
||||||
lowCutoff = 0;
|
band = 100.0f;
|
||||||
}
|
lowCutoff = 0;
|
||||||
|
}
|
||||||
m_settingsMutex.lock();
|
|
||||||
|
m_settingsMutex.lock();
|
||||||
m_Bandwidth = band;
|
|
||||||
m_LowCutoff = lowCutoff;
|
m_Bandwidth = band;
|
||||||
|
m_LowCutoff = lowCutoff;
|
||||||
SSBFilter->create_filter(m_LowCutoff / m_sampleRate, m_Bandwidth / m_sampleRate);
|
|
||||||
DSBFilter->create_dsb_filter(m_Bandwidth / m_sampleRate);
|
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();
|
||||||
m_settingsMutex.unlock();
|
|
||||||
|
m_settingsMutex.unlock();
|
||||||
qDebug() << " - MsgConfigureChannelAnalyzer: m_Bandwidth: " << m_Bandwidth
|
|
||||||
<< " m_LowCutoff: " << m_LowCutoff
|
qDebug() << " - MsgConfigureChannelAnalyzer: m_Bandwidth: " << m_Bandwidth
|
||||||
<< " m_spanLog2: " << m_spanLog2
|
<< " m_LowCutoff: " << m_LowCutoff
|
||||||
<< " m_ssb: " << m_ssb;
|
<< " m_spanLog2: " << m_spanLog2
|
||||||
|
<< " m_ssb: " << m_ssb;
|
||||||
return true;
|
|
||||||
}
|
return true;
|
||||||
else
|
}
|
||||||
{
|
else
|
||||||
if (m_sampleSink != 0)
|
{
|
||||||
{
|
if (m_sampleSink != 0)
|
||||||
return m_sampleSink->handleMessage(cmd);
|
{
|
||||||
}
|
return m_sampleSink->handleMessage(cmd);
|
||||||
else
|
}
|
||||||
{
|
else
|
||||||
return false;
|
{
|
||||||
}
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,154 +1,156 @@
|
||||||
///////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////
|
||||||
// Copyright (C) 2015 Edouard Griffiths, F4EXB //
|
// Copyright (C) 2015 Edouard Griffiths, F4EXB //
|
||||||
// //
|
// //
|
||||||
// This program is free software; you can redistribute it and/or modify //
|
// This program is free software; you can redistribute it and/or modify //
|
||||||
// it under the terms of the GNU General Public License as published by //
|
// it under the terms of the GNU General Public License as published by //
|
||||||
// the Free Software Foundation as version 3 of the License, or //
|
// the Free Software Foundation as version 3 of the License, or //
|
||||||
// //
|
// //
|
||||||
// This program is distributed in the hope that it will be useful, //
|
// This program is distributed in the hope that it will be useful, //
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
|
||||||
// GNU General Public License V3 for more details. //
|
// GNU General Public License V3 for more details. //
|
||||||
// //
|
// //
|
||||||
// You should have received a copy of the GNU General Public License //
|
// You should have received a copy of the GNU General Public License //
|
||||||
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
|
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
|
||||||
///////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
#ifndef INCLUDE_CHANALYZER_H
|
#ifndef INCLUDE_CHANALYZER_H
|
||||||
#define INCLUDE_CHANALYZER_H
|
#define INCLUDE_CHANALYZER_H
|
||||||
|
|
||||||
#include <dsp/basebandsamplesink.h>
|
#include <dsp/basebandsamplesink.h>
|
||||||
#include <QMutex>
|
#include <QMutex>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include "dsp/ncof.h"
|
#include "dsp/ncof.h"
|
||||||
#include "dsp/fftfilt.h"
|
#include "dsp/fftfilt.h"
|
||||||
#include "audio/audiofifo.h"
|
#include "audio/audiofifo.h"
|
||||||
#include "util/message.h"
|
#include "util/message.h"
|
||||||
|
|
||||||
#define ssbFftLen 1024
|
#define ssbFftLen 1024
|
||||||
|
|
||||||
class DeviceSourceAPI;
|
class DeviceSourceAPI;
|
||||||
class ThreadedBasebandSampleSink;
|
class ThreadedBasebandSampleSink;
|
||||||
class DownChannelizer;
|
class DownChannelizer;
|
||||||
|
|
||||||
class ChannelAnalyzer : public BasebandSampleSink {
|
class ChannelAnalyzer : public BasebandSampleSink {
|
||||||
public:
|
public:
|
||||||
class MsgConfigureChannelAnalyzer : public Message {
|
class MsgConfigureChannelAnalyzer : public Message {
|
||||||
MESSAGE_CLASS_DECLARATION
|
MESSAGE_CLASS_DECLARATION
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Real getBandwidth() const { return m_Bandwidth; }
|
Real getBandwidth() const { return m_Bandwidth; }
|
||||||
Real getLoCutoff() const { return m_LowCutoff; }
|
Real getLoCutoff() const { return m_LowCutoff; }
|
||||||
int getSpanLog2() const { return m_spanLog2; }
|
int getSpanLog2() const { return m_spanLog2; }
|
||||||
bool getSSB() const { return m_ssb; }
|
bool getSSB() const { return m_ssb; }
|
||||||
|
|
||||||
static MsgConfigureChannelAnalyzer* create(Real Bandwidth,
|
static MsgConfigureChannelAnalyzer* create(Real Bandwidth,
|
||||||
Real LowCutoff,
|
Real LowCutoff,
|
||||||
int spanLog2,
|
int spanLog2,
|
||||||
bool ssb)
|
bool ssb)
|
||||||
{
|
{
|
||||||
return new MsgConfigureChannelAnalyzer(Bandwidth, LowCutoff, spanLog2, ssb);
|
return new MsgConfigureChannelAnalyzer(Bandwidth, LowCutoff, spanLog2, ssb);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Real m_Bandwidth;
|
Real m_Bandwidth;
|
||||||
Real m_LowCutoff;
|
Real m_LowCutoff;
|
||||||
int m_spanLog2;
|
int m_spanLog2;
|
||||||
bool m_ssb;
|
bool m_ssb;
|
||||||
|
|
||||||
MsgConfigureChannelAnalyzer(Real Bandwidth,
|
MsgConfigureChannelAnalyzer(Real Bandwidth,
|
||||||
Real LowCutoff,
|
Real LowCutoff,
|
||||||
int spanLog2,
|
int spanLog2,
|
||||||
bool ssb) :
|
bool ssb) :
|
||||||
Message(),
|
Message(),
|
||||||
m_Bandwidth(Bandwidth),
|
m_Bandwidth(Bandwidth),
|
||||||
m_LowCutoff(LowCutoff),
|
m_LowCutoff(LowCutoff),
|
||||||
m_spanLog2(spanLog2),
|
m_spanLog2(spanLog2),
|
||||||
m_ssb(ssb)
|
m_ssb(ssb)
|
||||||
{ }
|
{ }
|
||||||
};
|
};
|
||||||
|
|
||||||
class MsgConfigureChannelizer : public Message {
|
class MsgConfigureChannelizer : public Message {
|
||||||
MESSAGE_CLASS_DECLARATION
|
MESSAGE_CLASS_DECLARATION
|
||||||
|
|
||||||
public:
|
public:
|
||||||
int getCenterFrequency() const { return m_centerFrequency; }
|
int getCenterFrequency() const { return m_centerFrequency; }
|
||||||
|
|
||||||
static MsgConfigureChannelizer* create(int centerFrequency)
|
static MsgConfigureChannelizer* create(int centerFrequency)
|
||||||
{
|
{
|
||||||
return new MsgConfigureChannelizer(centerFrequency);
|
return new MsgConfigureChannelizer(centerFrequency);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int m_centerFrequency;
|
int m_centerFrequency;
|
||||||
|
|
||||||
MsgConfigureChannelizer(int centerFrequency) :
|
MsgConfigureChannelizer(int centerFrequency) :
|
||||||
Message(),
|
Message(),
|
||||||
m_centerFrequency(centerFrequency)
|
m_centerFrequency(centerFrequency)
|
||||||
{ }
|
{ }
|
||||||
};
|
};
|
||||||
|
|
||||||
class MsgReportChannelSampleRateChanged : public Message {
|
class MsgReportChannelSampleRateChanged : public Message {
|
||||||
MESSAGE_CLASS_DECLARATION
|
MESSAGE_CLASS_DECLARATION
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
static MsgReportChannelSampleRateChanged* create()
|
static MsgReportChannelSampleRateChanged* create()
|
||||||
{
|
{
|
||||||
return new MsgReportChannelSampleRateChanged();
|
return new MsgReportChannelSampleRateChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
MsgReportChannelSampleRateChanged() :
|
MsgReportChannelSampleRateChanged() :
|
||||||
Message()
|
Message()
|
||||||
{ }
|
{ }
|
||||||
};
|
};
|
||||||
|
|
||||||
ChannelAnalyzer(DeviceSourceAPI *deviceAPI);
|
ChannelAnalyzer(DeviceSourceAPI *deviceAPI);
|
||||||
virtual ~ChannelAnalyzer();
|
virtual ~ChannelAnalyzer();
|
||||||
void setSampleSink(BasebandSampleSink* sampleSink) { m_sampleSink = sampleSink; }
|
void setSampleSink(BasebandSampleSink* sampleSink) { m_sampleSink = sampleSink; }
|
||||||
|
|
||||||
void configure(MessageQueue* messageQueue,
|
void configure(MessageQueue* messageQueue,
|
||||||
Real Bandwidth,
|
Real Bandwidth,
|
||||||
Real LowCutoff,
|
Real LowCutoff,
|
||||||
int spanLog2,
|
int spanLog2,
|
||||||
bool ssb);
|
bool ssb);
|
||||||
|
|
||||||
int getSampleRate() const { return m_sampleRate; }
|
int getSampleRate() const { return m_sampleRate; }
|
||||||
Real getMagSq() const { return m_magsq; }
|
Real getMagSq() const { return m_magsq; }
|
||||||
|
|
||||||
virtual void feed(const SampleVector::const_iterator& begin, const SampleVector::const_iterator& end, bool positiveOnly);
|
virtual void feed(const SampleVector::const_iterator& begin, const SampleVector::const_iterator& end, bool positiveOnly);
|
||||||
virtual void start();
|
virtual void start();
|
||||||
virtual void stop();
|
virtual void stop();
|
||||||
virtual bool handleMessage(const Message& cmd);
|
virtual bool handleMessage(const Message& cmd);
|
||||||
|
|
||||||
private slots:
|
static const QString m_channelID;
|
||||||
void channelSampleRateChanged();
|
|
||||||
|
private slots:
|
||||||
private:
|
void channelSampleRateChanged();
|
||||||
DeviceSourceAPI *m_deviceAPI;
|
|
||||||
ThreadedBasebandSampleSink* m_threadedChannelizer;
|
private:
|
||||||
DownChannelizer* m_channelizer;
|
DeviceSourceAPI *m_deviceAPI;
|
||||||
|
ThreadedBasebandSampleSink* m_threadedChannelizer;
|
||||||
Real m_Bandwidth;
|
DownChannelizer* m_channelizer;
|
||||||
Real m_LowCutoff;
|
|
||||||
int m_spanLog2;
|
Real m_Bandwidth;
|
||||||
int m_undersampleCount;
|
Real m_LowCutoff;
|
||||||
fftfilt::cmplx m_sum;
|
int m_spanLog2;
|
||||||
int m_sampleRate;
|
int m_undersampleCount;
|
||||||
int m_frequency;
|
fftfilt::cmplx m_sum;
|
||||||
bool m_usb;
|
int m_sampleRate;
|
||||||
bool m_ssb;
|
int m_frequency;
|
||||||
Real m_magsq;
|
bool m_usb;
|
||||||
|
bool m_ssb;
|
||||||
NCOF m_nco;
|
Real m_magsq;
|
||||||
fftfilt* SSBFilter;
|
|
||||||
fftfilt* DSBFilter;
|
NCOF m_nco;
|
||||||
|
fftfilt* SSBFilter;
|
||||||
BasebandSampleSink* m_sampleSink;
|
fftfilt* DSBFilter;
|
||||||
SampleVector m_sampleBuffer;
|
|
||||||
QMutex m_settingsMutex;
|
BasebandSampleSink* m_sampleSink;
|
||||||
};
|
SampleVector m_sampleBuffer;
|
||||||
|
QMutex m_settingsMutex;
|
||||||
#endif // INCLUDE_CHANALYZER_H
|
};
|
||||||
|
|
||||||
|
#endif // INCLUDE_CHANALYZER_H
|
||||||
|
|
|
@ -38,8 +38,6 @@
|
||||||
|
|
||||||
#include "chanalyzer.h"
|
#include "chanalyzer.h"
|
||||||
|
|
||||||
const QString ChannelAnalyzerGUI::m_channelID = "org.f4exb.sdrangelove.channel.chanalyzer";
|
|
||||||
|
|
||||||
ChannelAnalyzerGUI* ChannelAnalyzerGUI::create(PluginAPI* pluginAPI, DeviceUISet *deviceUISet)
|
ChannelAnalyzerGUI* ChannelAnalyzerGUI::create(PluginAPI* pluginAPI, DeviceUISet *deviceUISet)
|
||||||
{
|
{
|
||||||
ChannelAnalyzerGUI* gui = new ChannelAnalyzerGUI(pluginAPI, deviceUISet);
|
ChannelAnalyzerGUI* gui = new ChannelAnalyzerGUI(pluginAPI, deviceUISet);
|
||||||
|
@ -370,7 +368,7 @@ ChannelAnalyzerGUI::ChannelAnalyzerGUI(PluginAPI* pluginAPI, DeviceUISet *device
|
||||||
|
|
||||||
connect(&m_channelMarker, SIGNAL(changed()), this, SLOT(viewChanged()));
|
connect(&m_channelMarker, SIGNAL(changed()), this, SLOT(viewChanged()));
|
||||||
|
|
||||||
m_deviceUISet->registerRxChannelInstance(m_channelID, this);
|
m_deviceUISet->registerRxChannelInstance(ChannelAnalyzer::m_channelID, this);
|
||||||
m_deviceUISet->addChannelMarker(&m_channelMarker);
|
m_deviceUISet->addChannelMarker(&m_channelMarker);
|
||||||
m_deviceUISet->addRollupWidget(this);
|
m_deviceUISet->addRollupWidget(this);
|
||||||
|
|
||||||
|
|
|
@ -55,8 +55,6 @@ public:
|
||||||
virtual MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; }
|
virtual MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; }
|
||||||
virtual bool handleMessage(const Message& message);
|
virtual bool handleMessage(const Message& message);
|
||||||
|
|
||||||
static const QString m_channelID;
|
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void viewChanged();
|
void viewChanged();
|
||||||
void on_deltaFrequency_changed(quint64 value);
|
void on_deltaFrequency_changed(quint64 value);
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
#include "plugin/pluginapi.h"
|
#include "plugin/pluginapi.h"
|
||||||
|
|
||||||
#include "chanalyzergui.h"
|
#include "chanalyzergui.h"
|
||||||
|
#include "chanalyzer.h"
|
||||||
|
|
||||||
const PluginDescriptor ChannelAnalyzerPlugin::m_pluginDescriptor = {
|
const PluginDescriptor ChannelAnalyzerPlugin::m_pluginDescriptor = {
|
||||||
QString("Channel Analyzer"),
|
QString("Channel Analyzer"),
|
||||||
|
@ -30,12 +31,12 @@ void ChannelAnalyzerPlugin::initPlugin(PluginAPI* pluginAPI)
|
||||||
m_pluginAPI = pluginAPI;
|
m_pluginAPI = pluginAPI;
|
||||||
|
|
||||||
// register demodulator
|
// register demodulator
|
||||||
m_pluginAPI->registerRxChannel(ChannelAnalyzerGUI::m_channelID, this);
|
m_pluginAPI->registerRxChannel(ChannelAnalyzer::m_channelID, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
PluginInstanceGUI* ChannelAnalyzerPlugin::createRxChannelGUI(const QString& channelName, DeviceUISet *deviceUISet)
|
PluginInstanceGUI* ChannelAnalyzerPlugin::createRxChannelGUI(const QString& channelName, DeviceUISet *deviceUISet)
|
||||||
{
|
{
|
||||||
if(channelName == ChannelAnalyzerGUI::m_channelID)
|
if(channelName == ChannelAnalyzer::m_channelID)
|
||||||
{
|
{
|
||||||
ChannelAnalyzerGUI* gui = ChannelAnalyzerGUI::create(m_pluginAPI, deviceUISet);
|
ChannelAnalyzerGUI* gui = ChannelAnalyzerGUI::create(m_pluginAPI, deviceUISet);
|
||||||
return gui;
|
return gui;
|
||||||
|
@ -43,3 +44,15 @@ PluginInstanceGUI* ChannelAnalyzerPlugin::createRxChannelGUI(const QString& chan
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
BasebandSampleSink* ChannelAnalyzerPlugin::createRxChannel(const QString& channelName, DeviceSourceAPI *deviceAPI)
|
||||||
|
{
|
||||||
|
if(channelName == ChannelAnalyzer::m_channelID)
|
||||||
|
{
|
||||||
|
ChannelAnalyzer* sink = new ChannelAnalyzer(deviceAPI);
|
||||||
|
return sink;
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
#include "plugin/plugininterface.h"
|
#include "plugin/plugininterface.h"
|
||||||
|
|
||||||
class DeviceUISet;
|
class DeviceUISet;
|
||||||
|
class BasebandSampleSink;
|
||||||
|
|
||||||
class ChannelAnalyzerPlugin : public QObject, PluginInterface {
|
class ChannelAnalyzerPlugin : public QObject, PluginInterface {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
@ -18,6 +19,7 @@ public:
|
||||||
void initPlugin(PluginAPI* pluginAPI);
|
void initPlugin(PluginAPI* pluginAPI);
|
||||||
|
|
||||||
PluginInstanceGUI* createRxChannelGUI(const QString& channelName, DeviceUISet *deviceUISet);
|
PluginInstanceGUI* createRxChannelGUI(const QString& channelName, DeviceUISet *deviceUISet);
|
||||||
|
BasebandSampleSink* createRxChannel(const QString& channelName, DeviceSourceAPI *deviceAPI);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static const PluginDescriptor m_pluginDescriptor;
|
static const PluginDescriptor m_pluginDescriptor;
|
||||||
|
|
|
@ -1,251 +1,252 @@
|
||||||
///////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////
|
||||||
// Copyright (C) 2017 Edouard Griffiths, F4EXB //
|
// Copyright (C) 2017 Edouard Griffiths, F4EXB //
|
||||||
// //
|
// //
|
||||||
// This program is free software; you can redistribute it and/or modify //
|
// This program is free software; you can redistribute it and/or modify //
|
||||||
// it under the terms of the GNU General Public License as published by //
|
// it under the terms of the GNU General Public License as published by //
|
||||||
// the Free Software Foundation as version 3 of the License, or //
|
// the Free Software Foundation as version 3 of the License, or //
|
||||||
// //
|
// //
|
||||||
// This program is distributed in the hope that it will be useful, //
|
// This program is distributed in the hope that it will be useful, //
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
|
||||||
// GNU General Public License V3 for more details. //
|
// GNU General Public License V3 for more details. //
|
||||||
// //
|
// //
|
||||||
// You should have received a copy of the GNU General Public License //
|
// You should have received a copy of the GNU General Public License //
|
||||||
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
|
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
|
||||||
///////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
#include "chanalyzerng.h"
|
#include "chanalyzerng.h"
|
||||||
|
|
||||||
#include <QTime>
|
#include <QTime>
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
#include "device/devicesourceapi.h"
|
#include "device/devicesourceapi.h"
|
||||||
#include "audio/audiooutput.h"
|
#include "audio/audiooutput.h"
|
||||||
#include "dsp/threadedbasebandsamplesink.h"
|
#include "dsp/threadedbasebandsamplesink.h"
|
||||||
#include "dsp/downchannelizer.h"
|
#include "dsp/downchannelizer.h"
|
||||||
|
|
||||||
|
MESSAGE_CLASS_DEFINITION(ChannelAnalyzerNG::MsgConfigureChannelAnalyzer, Message)
|
||||||
MESSAGE_CLASS_DEFINITION(ChannelAnalyzerNG::MsgConfigureChannelAnalyzer, Message)
|
MESSAGE_CLASS_DEFINITION(ChannelAnalyzerNG::MsgConfigureChannelizer, Message)
|
||||||
MESSAGE_CLASS_DEFINITION(ChannelAnalyzerNG::MsgConfigureChannelizer, Message)
|
MESSAGE_CLASS_DEFINITION(ChannelAnalyzerNG::MsgReportChannelSampleRateChanged, Message)
|
||||||
MESSAGE_CLASS_DEFINITION(ChannelAnalyzerNG::MsgReportChannelSampleRateChanged, Message)
|
|
||||||
|
const QString ChannelAnalyzerNG::m_channelID = "sdrangel.channel.chanalyzerng";
|
||||||
ChannelAnalyzerNG::ChannelAnalyzerNG(DeviceSourceAPI *deviceAPI) :
|
|
||||||
m_deviceAPI(deviceAPI),
|
ChannelAnalyzerNG::ChannelAnalyzerNG(DeviceSourceAPI *deviceAPI) :
|
||||||
m_sampleSink(0),
|
m_deviceAPI(deviceAPI),
|
||||||
m_settingsMutex(QMutex::Recursive)
|
m_sampleSink(0),
|
||||||
{
|
m_settingsMutex(QMutex::Recursive)
|
||||||
m_undersampleCount = 0;
|
{
|
||||||
m_sum = 0;
|
m_undersampleCount = 0;
|
||||||
m_usb = true;
|
m_sum = 0;
|
||||||
m_magsq = 0;
|
m_usb = true;
|
||||||
m_useInterpolator = false;
|
m_magsq = 0;
|
||||||
m_interpolatorDistance = 1.0f;
|
m_useInterpolator = false;
|
||||||
m_interpolatorDistanceRemain = 0.0f;
|
m_interpolatorDistance = 1.0f;
|
||||||
SSBFilter = new fftfilt(m_config.m_LowCutoff / m_config.m_inputSampleRate, m_config.m_Bandwidth / m_config.m_inputSampleRate, ssbFftLen);
|
m_interpolatorDistanceRemain = 0.0f;
|
||||||
DSBFilter = new fftfilt(m_config.m_Bandwidth / m_config.m_inputSampleRate, 2*ssbFftLen);
|
SSBFilter = new fftfilt(m_config.m_LowCutoff / m_config.m_inputSampleRate, m_config.m_Bandwidth / m_config.m_inputSampleRate, ssbFftLen);
|
||||||
|
DSBFilter = new fftfilt(m_config.m_Bandwidth / m_config.m_inputSampleRate, 2*ssbFftLen);
|
||||||
m_channelizer = new DownChannelizer(this);
|
|
||||||
m_threadedChannelizer = new ThreadedBasebandSampleSink(m_channelizer, this);
|
m_channelizer = new DownChannelizer(this);
|
||||||
connect(m_channelizer, SIGNAL(inputSampleRateChanged()), this, SLOT(channelizerInputSampleRateChanged()));
|
m_threadedChannelizer = new ThreadedBasebandSampleSink(m_channelizer, this);
|
||||||
m_deviceAPI->addThreadedSink(m_threadedChannelizer);
|
connect(m_channelizer, SIGNAL(inputSampleRateChanged()), this, SLOT(channelizerInputSampleRateChanged()));
|
||||||
|
m_deviceAPI->addThreadedSink(m_threadedChannelizer);
|
||||||
apply(true);
|
|
||||||
}
|
apply(true);
|
||||||
|
}
|
||||||
ChannelAnalyzerNG::~ChannelAnalyzerNG()
|
|
||||||
{
|
ChannelAnalyzerNG::~ChannelAnalyzerNG()
|
||||||
if (SSBFilter) delete SSBFilter;
|
{
|
||||||
if (DSBFilter) delete DSBFilter;
|
if (SSBFilter) delete SSBFilter;
|
||||||
m_deviceAPI->removeThreadedSink(m_threadedChannelizer);
|
if (DSBFilter) delete DSBFilter;
|
||||||
delete m_threadedChannelizer;
|
m_deviceAPI->removeThreadedSink(m_threadedChannelizer);
|
||||||
delete m_channelizer;
|
delete m_threadedChannelizer;
|
||||||
}
|
delete m_channelizer;
|
||||||
|
}
|
||||||
void ChannelAnalyzerNG::configure(MessageQueue* messageQueue,
|
|
||||||
int channelSampleRate,
|
void ChannelAnalyzerNG::configure(MessageQueue* messageQueue,
|
||||||
Real Bandwidth,
|
int channelSampleRate,
|
||||||
Real LowCutoff,
|
Real Bandwidth,
|
||||||
int spanLog2,
|
Real LowCutoff,
|
||||||
bool ssb)
|
int spanLog2,
|
||||||
{
|
bool ssb)
|
||||||
Message* cmd = MsgConfigureChannelAnalyzer::create(channelSampleRate, Bandwidth, LowCutoff, spanLog2, ssb);
|
{
|
||||||
messageQueue->push(cmd);
|
Message* cmd = MsgConfigureChannelAnalyzer::create(channelSampleRate, Bandwidth, LowCutoff, spanLog2, ssb);
|
||||||
}
|
messageQueue->push(cmd);
|
||||||
|
}
|
||||||
void ChannelAnalyzerNG::feed(const SampleVector::const_iterator& begin, const SampleVector::const_iterator& end, bool positiveOnly __attribute__((unused)))
|
|
||||||
{
|
void ChannelAnalyzerNG::feed(const SampleVector::const_iterator& begin, const SampleVector::const_iterator& end, bool positiveOnly __attribute__((unused)))
|
||||||
fftfilt::cmplx *sideband = 0;
|
{
|
||||||
Complex ci;
|
fftfilt::cmplx *sideband = 0;
|
||||||
|
Complex ci;
|
||||||
m_settingsMutex.lock();
|
|
||||||
|
m_settingsMutex.lock();
|
||||||
for(SampleVector::const_iterator it = begin; it < end; ++it)
|
|
||||||
{
|
for(SampleVector::const_iterator it = begin; it < end; ++it)
|
||||||
Complex c(it->real(), it->imag());
|
{
|
||||||
c *= m_nco.nextIQ();
|
Complex c(it->real(), it->imag());
|
||||||
|
c *= m_nco.nextIQ();
|
||||||
if (m_useInterpolator)
|
|
||||||
{
|
if (m_useInterpolator)
|
||||||
if (m_interpolator.decimate(&m_interpolatorDistanceRemain, c, &ci))
|
{
|
||||||
{
|
if (m_interpolator.decimate(&m_interpolatorDistanceRemain, c, &ci))
|
||||||
processOneSample(ci, sideband);
|
{
|
||||||
m_interpolatorDistanceRemain += m_interpolatorDistance;
|
processOneSample(ci, sideband);
|
||||||
}
|
m_interpolatorDistanceRemain += m_interpolatorDistance;
|
||||||
}
|
}
|
||||||
else
|
}
|
||||||
{
|
else
|
||||||
processOneSample(c, sideband);
|
{
|
||||||
}
|
processOneSample(c, sideband);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if(m_sampleSink != 0)
|
|
||||||
{
|
if(m_sampleSink != 0)
|
||||||
m_sampleSink->feed(m_sampleBuffer.begin(), m_sampleBuffer.end(), m_running.m_ssb); // m_ssb = positive only
|
{
|
||||||
}
|
m_sampleSink->feed(m_sampleBuffer.begin(), m_sampleBuffer.end(), m_running.m_ssb); // m_ssb = positive only
|
||||||
|
}
|
||||||
m_sampleBuffer.clear();
|
|
||||||
|
m_sampleBuffer.clear();
|
||||||
m_settingsMutex.unlock();
|
|
||||||
}
|
m_settingsMutex.unlock();
|
||||||
|
}
|
||||||
void ChannelAnalyzerNG::start()
|
|
||||||
{
|
void ChannelAnalyzerNG::start()
|
||||||
}
|
{
|
||||||
|
}
|
||||||
void ChannelAnalyzerNG::stop()
|
|
||||||
{
|
void ChannelAnalyzerNG::stop()
|
||||||
}
|
{
|
||||||
|
}
|
||||||
void ChannelAnalyzerNG::channelizerInputSampleRateChanged()
|
|
||||||
{
|
void ChannelAnalyzerNG::channelizerInputSampleRateChanged()
|
||||||
MsgReportChannelSampleRateChanged *msg = MsgReportChannelSampleRateChanged::create();
|
{
|
||||||
getMessageQueueToGUI()->push(msg);
|
MsgReportChannelSampleRateChanged *msg = MsgReportChannelSampleRateChanged::create();
|
||||||
}
|
getMessageQueueToGUI()->push(msg);
|
||||||
|
}
|
||||||
bool ChannelAnalyzerNG::handleMessage(const Message& cmd)
|
|
||||||
{
|
bool ChannelAnalyzerNG::handleMessage(const Message& cmd)
|
||||||
qDebug() << "ChannelAnalyzerNG::handleMessage: " << cmd.getIdentifier();
|
{
|
||||||
|
qDebug() << "ChannelAnalyzerNG::handleMessage: " << cmd.getIdentifier();
|
||||||
if (DownChannelizer::MsgChannelizerNotification::match(cmd))
|
|
||||||
{
|
if (DownChannelizer::MsgChannelizerNotification::match(cmd))
|
||||||
DownChannelizer::MsgChannelizerNotification& notif = (DownChannelizer::MsgChannelizerNotification&) cmd;
|
{
|
||||||
|
DownChannelizer::MsgChannelizerNotification& notif = (DownChannelizer::MsgChannelizerNotification&) cmd;
|
||||||
m_config.m_inputSampleRate = notif.getSampleRate();
|
|
||||||
m_config.m_frequency = notif.getFrequencyOffset();
|
m_config.m_inputSampleRate = notif.getSampleRate();
|
||||||
|
m_config.m_frequency = notif.getFrequencyOffset();
|
||||||
qDebug() << "ChannelAnalyzerNG::handleMessage: MsgChannelizerNotification:"
|
|
||||||
<< " m_sampleRate: " << m_config.m_inputSampleRate
|
qDebug() << "ChannelAnalyzerNG::handleMessage: MsgChannelizerNotification:"
|
||||||
<< " frequencyOffset: " << m_config.m_frequency;
|
<< " m_sampleRate: " << m_config.m_inputSampleRate
|
||||||
|
<< " frequencyOffset: " << m_config.m_frequency;
|
||||||
apply();
|
|
||||||
return true;
|
apply();
|
||||||
}
|
return true;
|
||||||
else if (MsgConfigureChannelizer::match(cmd))
|
}
|
||||||
{
|
else if (MsgConfigureChannelizer::match(cmd))
|
||||||
MsgConfigureChannelizer& cfg = (MsgConfigureChannelizer&) cmd;
|
{
|
||||||
m_channelizer->configure(m_channelizer->getInputMessageQueue(),
|
MsgConfigureChannelizer& cfg = (MsgConfigureChannelizer&) cmd;
|
||||||
cfg.getSampleRate(),
|
m_channelizer->configure(m_channelizer->getInputMessageQueue(),
|
||||||
cfg.getCenterFrequency());
|
cfg.getSampleRate(),
|
||||||
return true;
|
cfg.getCenterFrequency());
|
||||||
}
|
return true;
|
||||||
else if (MsgConfigureChannelAnalyzer::match(cmd))
|
}
|
||||||
{
|
else if (MsgConfigureChannelAnalyzer::match(cmd))
|
||||||
MsgConfigureChannelAnalyzer& cfg = (MsgConfigureChannelAnalyzer&) cmd;
|
{
|
||||||
|
MsgConfigureChannelAnalyzer& cfg = (MsgConfigureChannelAnalyzer&) cmd;
|
||||||
m_config.m_channelSampleRate = cfg.getChannelSampleRate();
|
|
||||||
m_config.m_Bandwidth = cfg.getBandwidth();
|
m_config.m_channelSampleRate = cfg.getChannelSampleRate();
|
||||||
m_config.m_LowCutoff = cfg.getLoCutoff();
|
m_config.m_Bandwidth = cfg.getBandwidth();
|
||||||
m_config.m_spanLog2 = cfg.getSpanLog2();
|
m_config.m_LowCutoff = cfg.getLoCutoff();
|
||||||
m_config.m_ssb = cfg.getSSB();
|
m_config.m_spanLog2 = cfg.getSpanLog2();
|
||||||
|
m_config.m_ssb = cfg.getSSB();
|
||||||
qDebug() << "ChannelAnalyzerNG::handleMessage: MsgConfigureChannelAnalyzer:"
|
|
||||||
<< " m_channelSampleRate: " << m_config.m_channelSampleRate
|
qDebug() << "ChannelAnalyzerNG::handleMessage: MsgConfigureChannelAnalyzer:"
|
||||||
<< " m_Bandwidth: " << m_config.m_Bandwidth
|
<< " m_channelSampleRate: " << m_config.m_channelSampleRate
|
||||||
<< " m_LowCutoff: " << m_config.m_LowCutoff
|
<< " m_Bandwidth: " << m_config.m_Bandwidth
|
||||||
<< " m_spanLog2: " << m_config.m_spanLog2
|
<< " m_LowCutoff: " << m_config.m_LowCutoff
|
||||||
<< " m_ssb: " << m_config.m_ssb;
|
<< " m_spanLog2: " << m_config.m_spanLog2
|
||||||
|
<< " m_ssb: " << m_config.m_ssb;
|
||||||
apply();
|
|
||||||
return true;
|
apply();
|
||||||
}
|
return true;
|
||||||
else
|
}
|
||||||
{
|
else
|
||||||
if (m_sampleSink != 0)
|
{
|
||||||
{
|
if (m_sampleSink != 0)
|
||||||
return m_sampleSink->handleMessage(cmd);
|
{
|
||||||
}
|
return m_sampleSink->handleMessage(cmd);
|
||||||
else
|
}
|
||||||
{
|
else
|
||||||
return false;
|
{
|
||||||
}
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void ChannelAnalyzerNG::apply(bool force)
|
|
||||||
{
|
void ChannelAnalyzerNG::apply(bool force)
|
||||||
if ((m_running.m_frequency != m_config.m_frequency) ||
|
{
|
||||||
(m_running.m_inputSampleRate != m_config.m_inputSampleRate) ||
|
if ((m_running.m_frequency != m_config.m_frequency) ||
|
||||||
force)
|
(m_running.m_inputSampleRate != m_config.m_inputSampleRate) ||
|
||||||
{
|
force)
|
||||||
m_nco.setFreq(-m_config.m_frequency, m_config.m_inputSampleRate);
|
{
|
||||||
}
|
m_nco.setFreq(-m_config.m_frequency, m_config.m_inputSampleRate);
|
||||||
|
}
|
||||||
if ((m_running.m_inputSampleRate != m_config.m_inputSampleRate) ||
|
|
||||||
(m_running.m_channelSampleRate != m_config.m_channelSampleRate) ||
|
if ((m_running.m_inputSampleRate != m_config.m_inputSampleRate) ||
|
||||||
force)
|
(m_running.m_channelSampleRate != m_config.m_channelSampleRate) ||
|
||||||
{
|
force)
|
||||||
m_settingsMutex.lock();
|
{
|
||||||
m_interpolator.create(16, m_config.m_inputSampleRate, m_config.m_inputSampleRate / 2.2);
|
m_settingsMutex.lock();
|
||||||
m_interpolatorDistanceRemain = 0.0f;
|
m_interpolator.create(16, m_config.m_inputSampleRate, m_config.m_inputSampleRate / 2.2);
|
||||||
m_interpolatorDistance = (Real) m_config.m_inputSampleRate / (Real) m_config.m_channelSampleRate;
|
m_interpolatorDistanceRemain = 0.0f;
|
||||||
m_useInterpolator = (m_config.m_inputSampleRate != m_config.m_channelSampleRate); // optim
|
m_interpolatorDistance = (Real) m_config.m_inputSampleRate / (Real) m_config.m_channelSampleRate;
|
||||||
m_settingsMutex.unlock();
|
m_useInterpolator = (m_config.m_inputSampleRate != m_config.m_channelSampleRate); // optim
|
||||||
}
|
m_settingsMutex.unlock();
|
||||||
|
}
|
||||||
if ((m_running.m_channelSampleRate != m_config.m_channelSampleRate) ||
|
|
||||||
(m_running.m_Bandwidth != m_config.m_Bandwidth) ||
|
if ((m_running.m_channelSampleRate != m_config.m_channelSampleRate) ||
|
||||||
(m_running.m_LowCutoff != m_config.m_LowCutoff) ||
|
(m_running.m_Bandwidth != m_config.m_Bandwidth) ||
|
||||||
force)
|
(m_running.m_LowCutoff != m_config.m_LowCutoff) ||
|
||||||
{
|
force)
|
||||||
float bandwidth = m_config.m_Bandwidth;
|
{
|
||||||
float lowCutoff = m_config.m_LowCutoff;
|
float bandwidth = m_config.m_Bandwidth;
|
||||||
|
float lowCutoff = m_config.m_LowCutoff;
|
||||||
if (bandwidth < 0)
|
|
||||||
{
|
if (bandwidth < 0)
|
||||||
bandwidth = -bandwidth;
|
{
|
||||||
lowCutoff = -lowCutoff;
|
bandwidth = -bandwidth;
|
||||||
m_usb = false;
|
lowCutoff = -lowCutoff;
|
||||||
}
|
m_usb = false;
|
||||||
else
|
}
|
||||||
{
|
else
|
||||||
m_usb = true;
|
{
|
||||||
}
|
m_usb = true;
|
||||||
|
}
|
||||||
if (bandwidth < 100.0f)
|
|
||||||
{
|
if (bandwidth < 100.0f)
|
||||||
bandwidth = 100.0f;
|
{
|
||||||
lowCutoff = 0;
|
bandwidth = 100.0f;
|
||||||
}
|
lowCutoff = 0;
|
||||||
|
}
|
||||||
m_settingsMutex.lock();
|
|
||||||
|
m_settingsMutex.lock();
|
||||||
SSBFilter->create_filter(lowCutoff / m_config.m_channelSampleRate, bandwidth / m_config.m_channelSampleRate);
|
|
||||||
DSBFilter->create_dsb_filter(bandwidth / m_config.m_channelSampleRate);
|
SSBFilter->create_filter(lowCutoff / m_config.m_channelSampleRate, bandwidth / m_config.m_channelSampleRate);
|
||||||
|
DSBFilter->create_dsb_filter(bandwidth / m_config.m_channelSampleRate);
|
||||||
m_settingsMutex.unlock();
|
|
||||||
}
|
m_settingsMutex.unlock();
|
||||||
|
}
|
||||||
m_running.m_frequency = m_config.m_frequency;
|
|
||||||
m_running.m_channelSampleRate = m_config.m_channelSampleRate;
|
m_running.m_frequency = m_config.m_frequency;
|
||||||
m_running.m_inputSampleRate = m_config.m_inputSampleRate;
|
m_running.m_channelSampleRate = m_config.m_channelSampleRate;
|
||||||
m_running.m_Bandwidth = m_config.m_Bandwidth;
|
m_running.m_inputSampleRate = m_config.m_inputSampleRate;
|
||||||
m_running.m_LowCutoff = m_config.m_LowCutoff;
|
m_running.m_Bandwidth = m_config.m_Bandwidth;
|
||||||
|
m_running.m_LowCutoff = m_config.m_LowCutoff;
|
||||||
//m_settingsMutex.lock();
|
|
||||||
m_running.m_spanLog2 = m_config.m_spanLog2;
|
//m_settingsMutex.lock();
|
||||||
m_running.m_ssb = m_config.m_ssb;
|
m_running.m_spanLog2 = m_config.m_spanLog2;
|
||||||
//m_settingsMutex.unlock();
|
m_running.m_ssb = m_config.m_ssb;
|
||||||
}
|
//m_settingsMutex.unlock();
|
||||||
|
}
|
||||||
|
|
|
@ -1,242 +1,244 @@
|
||||||
///////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////
|
||||||
// Copyright (C) 2017 Edouard Griffiths, F4EXB //
|
// Copyright (C) 2017 Edouard Griffiths, F4EXB //
|
||||||
// //
|
// //
|
||||||
// This program is free software; you can redistribute it and/or modify //
|
// This program is free software; you can redistribute it and/or modify //
|
||||||
// it under the terms of the GNU General Public License as published by //
|
// it under the terms of the GNU General Public License as published by //
|
||||||
// the Free Software Foundation as version 3 of the License, or //
|
// the Free Software Foundation as version 3 of the License, or //
|
||||||
// //
|
// //
|
||||||
// This program is distributed in the hope that it will be useful, //
|
// This program is distributed in the hope that it will be useful, //
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
|
||||||
// GNU General Public License V3 for more details. //
|
// GNU General Public License V3 for more details. //
|
||||||
// //
|
// //
|
||||||
// You should have received a copy of the GNU General Public License //
|
// You should have received a copy of the GNU General Public License //
|
||||||
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
|
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
|
||||||
///////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
#ifndef INCLUDE_CHANALYZERNG_H
|
#ifndef INCLUDE_CHANALYZERNG_H
|
||||||
#define INCLUDE_CHANALYZERNG_H
|
#define INCLUDE_CHANALYZERNG_H
|
||||||
|
|
||||||
#include <dsp/basebandsamplesink.h>
|
#include <dsp/basebandsamplesink.h>
|
||||||
#include <QMutex>
|
#include <QMutex>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "dsp/interpolator.h"
|
#include "dsp/interpolator.h"
|
||||||
#include "dsp/ncof.h"
|
#include "dsp/ncof.h"
|
||||||
#include "dsp/fftfilt.h"
|
#include "dsp/fftfilt.h"
|
||||||
#include "audio/audiofifo.h"
|
#include "audio/audiofifo.h"
|
||||||
#include "util/message.h"
|
#include "util/message.h"
|
||||||
|
|
||||||
#define ssbFftLen 1024
|
#define ssbFftLen 1024
|
||||||
|
|
||||||
class DeviceSourceAPI;
|
class DeviceSourceAPI;
|
||||||
class ThreadedBasebandSampleSink;
|
class ThreadedBasebandSampleSink;
|
||||||
class DownChannelizer;
|
class DownChannelizer;
|
||||||
|
|
||||||
class ChannelAnalyzerNG : public BasebandSampleSink {
|
class ChannelAnalyzerNG : public BasebandSampleSink {
|
||||||
public:
|
public:
|
||||||
class MsgConfigureChannelAnalyzer : public Message {
|
class MsgConfigureChannelAnalyzer : public Message {
|
||||||
MESSAGE_CLASS_DECLARATION
|
MESSAGE_CLASS_DECLARATION
|
||||||
|
|
||||||
public:
|
public:
|
||||||
int getChannelSampleRate() const { return m_channelSampleRate; }
|
int getChannelSampleRate() const { return m_channelSampleRate; }
|
||||||
Real getBandwidth() const { return m_Bandwidth; }
|
Real getBandwidth() const { return m_Bandwidth; }
|
||||||
Real getLoCutoff() const { return m_LowCutoff; }
|
Real getLoCutoff() const { return m_LowCutoff; }
|
||||||
int getSpanLog2() const { return m_spanLog2; }
|
int getSpanLog2() const { return m_spanLog2; }
|
||||||
bool getSSB() const { return m_ssb; }
|
bool getSSB() const { return m_ssb; }
|
||||||
|
|
||||||
static MsgConfigureChannelAnalyzer* create(
|
static MsgConfigureChannelAnalyzer* create(
|
||||||
int channelSampleRate,
|
int channelSampleRate,
|
||||||
Real Bandwidth,
|
Real Bandwidth,
|
||||||
Real LowCutoff,
|
Real LowCutoff,
|
||||||
int spanLog2,
|
int spanLog2,
|
||||||
bool ssb)
|
bool ssb)
|
||||||
{
|
{
|
||||||
return new MsgConfigureChannelAnalyzer(
|
return new MsgConfigureChannelAnalyzer(
|
||||||
channelSampleRate,
|
channelSampleRate,
|
||||||
Bandwidth,
|
Bandwidth,
|
||||||
LowCutoff,
|
LowCutoff,
|
||||||
spanLog2,
|
spanLog2,
|
||||||
ssb);
|
ssb);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int m_channelSampleRate;
|
int m_channelSampleRate;
|
||||||
Real m_Bandwidth;
|
Real m_Bandwidth;
|
||||||
Real m_LowCutoff;
|
Real m_LowCutoff;
|
||||||
int m_spanLog2;
|
int m_spanLog2;
|
||||||
bool m_ssb;
|
bool m_ssb;
|
||||||
|
|
||||||
MsgConfigureChannelAnalyzer(
|
MsgConfigureChannelAnalyzer(
|
||||||
int channelSampleRate,
|
int channelSampleRate,
|
||||||
Real Bandwidth,
|
Real Bandwidth,
|
||||||
Real LowCutoff,
|
Real LowCutoff,
|
||||||
int spanLog2,
|
int spanLog2,
|
||||||
bool ssb) :
|
bool ssb) :
|
||||||
Message(),
|
Message(),
|
||||||
m_channelSampleRate(channelSampleRate),
|
m_channelSampleRate(channelSampleRate),
|
||||||
m_Bandwidth(Bandwidth),
|
m_Bandwidth(Bandwidth),
|
||||||
m_LowCutoff(LowCutoff),
|
m_LowCutoff(LowCutoff),
|
||||||
m_spanLog2(spanLog2),
|
m_spanLog2(spanLog2),
|
||||||
m_ssb(ssb)
|
m_ssb(ssb)
|
||||||
{ }
|
{ }
|
||||||
};
|
};
|
||||||
|
|
||||||
class MsgConfigureChannelizer : public Message {
|
class MsgConfigureChannelizer : public Message {
|
||||||
MESSAGE_CLASS_DECLARATION
|
MESSAGE_CLASS_DECLARATION
|
||||||
|
|
||||||
public:
|
public:
|
||||||
int getSampleRate() const { return m_sampleRate; }
|
int getSampleRate() const { return m_sampleRate; }
|
||||||
int getCenterFrequency() const { return m_centerFrequency; }
|
int getCenterFrequency() const { return m_centerFrequency; }
|
||||||
|
|
||||||
static MsgConfigureChannelizer* create(int sampleRate, int centerFrequency)
|
static MsgConfigureChannelizer* create(int sampleRate, int centerFrequency)
|
||||||
{
|
{
|
||||||
return new MsgConfigureChannelizer(sampleRate, centerFrequency);
|
return new MsgConfigureChannelizer(sampleRate, centerFrequency);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int m_sampleRate;
|
int m_sampleRate;
|
||||||
int m_centerFrequency;
|
int m_centerFrequency;
|
||||||
|
|
||||||
MsgConfigureChannelizer(int sampleRate, int centerFrequency) :
|
MsgConfigureChannelizer(int sampleRate, int centerFrequency) :
|
||||||
Message(),
|
Message(),
|
||||||
m_sampleRate(sampleRate),
|
m_sampleRate(sampleRate),
|
||||||
m_centerFrequency(centerFrequency)
|
m_centerFrequency(centerFrequency)
|
||||||
{ }
|
{ }
|
||||||
};
|
};
|
||||||
|
|
||||||
class MsgReportChannelSampleRateChanged : public Message {
|
class MsgReportChannelSampleRateChanged : public Message {
|
||||||
MESSAGE_CLASS_DECLARATION
|
MESSAGE_CLASS_DECLARATION
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
static MsgReportChannelSampleRateChanged* create()
|
static MsgReportChannelSampleRateChanged* create()
|
||||||
{
|
{
|
||||||
return new MsgReportChannelSampleRateChanged();
|
return new MsgReportChannelSampleRateChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
MsgReportChannelSampleRateChanged() :
|
MsgReportChannelSampleRateChanged() :
|
||||||
Message()
|
Message()
|
||||||
{ }
|
{ }
|
||||||
};
|
};
|
||||||
|
|
||||||
ChannelAnalyzerNG(DeviceSourceAPI *deviceAPI);
|
ChannelAnalyzerNG(DeviceSourceAPI *deviceAPI);
|
||||||
virtual ~ChannelAnalyzerNG();
|
virtual ~ChannelAnalyzerNG();
|
||||||
void setSampleSink(BasebandSampleSink* sampleSink) { m_sampleSink = sampleSink; }
|
void setSampleSink(BasebandSampleSink* sampleSink) { m_sampleSink = sampleSink; }
|
||||||
|
|
||||||
void configure(MessageQueue* messageQueue,
|
void configure(MessageQueue* messageQueue,
|
||||||
int channelSampleRate,
|
int channelSampleRate,
|
||||||
Real Bandwidth,
|
Real Bandwidth,
|
||||||
Real LowCutoff,
|
Real LowCutoff,
|
||||||
int spanLog2,
|
int spanLog2,
|
||||||
bool ssb);
|
bool ssb);
|
||||||
|
|
||||||
DownChannelizer *getChannelizer() { return m_channelizer; }
|
DownChannelizer *getChannelizer() { return m_channelizer; }
|
||||||
int getInputSampleRate() const { return m_running.m_inputSampleRate; }
|
int getInputSampleRate() const { return m_running.m_inputSampleRate; }
|
||||||
int getChannelSampleRate() const { return m_running.m_channelSampleRate; }
|
int getChannelSampleRate() const { return m_running.m_channelSampleRate; }
|
||||||
double getMagSq() const { return m_magsq; }
|
double getMagSq() const { return m_magsq; }
|
||||||
|
|
||||||
virtual void feed(const SampleVector::const_iterator& begin, const SampleVector::const_iterator& end, bool positiveOnly);
|
virtual void feed(const SampleVector::const_iterator& begin, const SampleVector::const_iterator& end, bool positiveOnly);
|
||||||
virtual void start();
|
virtual void start();
|
||||||
virtual void stop();
|
virtual void stop();
|
||||||
virtual bool handleMessage(const Message& cmd);
|
virtual bool handleMessage(const Message& cmd);
|
||||||
|
|
||||||
private slots:
|
static const QString m_channelID;
|
||||||
void channelizerInputSampleRateChanged();
|
|
||||||
|
private slots:
|
||||||
private:
|
void channelizerInputSampleRateChanged();
|
||||||
|
|
||||||
struct Config
|
private:
|
||||||
{
|
|
||||||
int m_frequency;
|
struct Config
|
||||||
int m_inputSampleRate;
|
{
|
||||||
int m_channelSampleRate;
|
int m_frequency;
|
||||||
Real m_Bandwidth;
|
int m_inputSampleRate;
|
||||||
Real m_LowCutoff;
|
int m_channelSampleRate;
|
||||||
int m_spanLog2;
|
Real m_Bandwidth;
|
||||||
bool m_ssb;
|
Real m_LowCutoff;
|
||||||
|
int m_spanLog2;
|
||||||
Config() :
|
bool m_ssb;
|
||||||
m_frequency(0),
|
|
||||||
m_inputSampleRate(96000),
|
Config() :
|
||||||
m_channelSampleRate(96000),
|
m_frequency(0),
|
||||||
m_Bandwidth(5000),
|
m_inputSampleRate(96000),
|
||||||
m_LowCutoff(300),
|
m_channelSampleRate(96000),
|
||||||
m_spanLog2(3),
|
m_Bandwidth(5000),
|
||||||
m_ssb(false)
|
m_LowCutoff(300),
|
||||||
{}
|
m_spanLog2(3),
|
||||||
};
|
m_ssb(false)
|
||||||
|
{}
|
||||||
Config m_config;
|
};
|
||||||
Config m_running;
|
|
||||||
|
Config m_config;
|
||||||
DeviceSourceAPI *m_deviceAPI;
|
Config m_running;
|
||||||
ThreadedBasebandSampleSink* m_threadedChannelizer;
|
|
||||||
DownChannelizer* m_channelizer;
|
DeviceSourceAPI *m_deviceAPI;
|
||||||
|
ThreadedBasebandSampleSink* m_threadedChannelizer;
|
||||||
int m_undersampleCount;
|
DownChannelizer* m_channelizer;
|
||||||
fftfilt::cmplx m_sum;
|
|
||||||
bool m_usb;
|
int m_undersampleCount;
|
||||||
double m_magsq;
|
fftfilt::cmplx m_sum;
|
||||||
bool m_useInterpolator;
|
bool m_usb;
|
||||||
|
double m_magsq;
|
||||||
NCOF m_nco;
|
bool m_useInterpolator;
|
||||||
Interpolator m_interpolator;
|
|
||||||
Real m_interpolatorDistance;
|
NCOF m_nco;
|
||||||
Real m_interpolatorDistanceRemain;
|
Interpolator m_interpolator;
|
||||||
|
Real m_interpolatorDistance;
|
||||||
fftfilt* SSBFilter;
|
Real m_interpolatorDistanceRemain;
|
||||||
fftfilt* DSBFilter;
|
|
||||||
|
fftfilt* SSBFilter;
|
||||||
BasebandSampleSink* m_sampleSink;
|
fftfilt* DSBFilter;
|
||||||
SampleVector m_sampleBuffer;
|
|
||||||
QMutex m_settingsMutex;
|
BasebandSampleSink* m_sampleSink;
|
||||||
|
SampleVector m_sampleBuffer;
|
||||||
void apply(bool force = false);
|
QMutex m_settingsMutex;
|
||||||
|
|
||||||
void processOneSample(Complex& c, fftfilt::cmplx *sideband)
|
void apply(bool force = false);
|
||||||
{
|
|
||||||
int n_out;
|
void processOneSample(Complex& c, fftfilt::cmplx *sideband)
|
||||||
int decim = 1<<m_running.m_spanLog2;
|
{
|
||||||
|
int n_out;
|
||||||
if (m_running.m_ssb)
|
int decim = 1<<m_running.m_spanLog2;
|
||||||
{
|
|
||||||
n_out = SSBFilter->runSSB(c, &sideband, m_usb);
|
if (m_running.m_ssb)
|
||||||
}
|
{
|
||||||
else
|
n_out = SSBFilter->runSSB(c, &sideband, m_usb);
|
||||||
{
|
}
|
||||||
n_out = DSBFilter->runDSB(c, &sideband);
|
else
|
||||||
}
|
{
|
||||||
|
n_out = DSBFilter->runDSB(c, &sideband);
|
||||||
for (int i = 0; i < n_out; i++)
|
}
|
||||||
{
|
|
||||||
// Downsample by 2^(m_scaleLog2 - 1) for SSB band spectrum display
|
for (int i = 0; i < n_out; i++)
|
||||||
// smart decimation with bit gain using float arithmetic (23 bits significand)
|
{
|
||||||
|
// Downsample by 2^(m_scaleLog2 - 1) for SSB band spectrum display
|
||||||
m_sum += sideband[i];
|
// smart decimation with bit gain using float arithmetic (23 bits significand)
|
||||||
|
|
||||||
if (!(m_undersampleCount++ & (decim - 1))) // counter LSB bit mask for decimation by 2^(m_scaleLog2 - 1)
|
m_sum += sideband[i];
|
||||||
{
|
|
||||||
m_sum /= decim;
|
if (!(m_undersampleCount++ & (decim - 1))) // counter LSB bit mask for decimation by 2^(m_scaleLog2 - 1)
|
||||||
m_magsq = (m_sum.real() * m_sum.real() + m_sum.imag() * m_sum.imag())/ (1<<30);
|
{
|
||||||
|
m_sum /= decim;
|
||||||
if (m_running.m_ssb & !m_usb)
|
m_magsq = (m_sum.real() * m_sum.real() + m_sum.imag() * m_sum.imag())/ (1<<30);
|
||||||
{ // invert spectrum for LSB
|
|
||||||
//m_sampleBuffer.push_back(Sample(m_sum.imag() * 32768.0, m_sum.real() * 32768.0));
|
if (m_running.m_ssb & !m_usb)
|
||||||
m_sampleBuffer.push_back(Sample(m_sum.imag(), m_sum.real()));
|
{ // invert spectrum for LSB
|
||||||
}
|
//m_sampleBuffer.push_back(Sample(m_sum.imag() * 32768.0, m_sum.real() * 32768.0));
|
||||||
else
|
m_sampleBuffer.push_back(Sample(m_sum.imag(), m_sum.real()));
|
||||||
{
|
}
|
||||||
//m_sampleBuffer.push_back(Sample(m_sum.real() * 32768.0, m_sum.imag() * 32768.0));
|
else
|
||||||
m_sampleBuffer.push_back(Sample(m_sum.real(), m_sum.imag()));
|
{
|
||||||
}
|
//m_sampleBuffer.push_back(Sample(m_sum.real() * 32768.0, m_sum.imag() * 32768.0));
|
||||||
|
m_sampleBuffer.push_back(Sample(m_sum.real(), m_sum.imag()));
|
||||||
m_sum = 0;
|
}
|
||||||
}
|
|
||||||
}
|
m_sum = 0;
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
}
|
||||||
#endif // INCLUDE_CHANALYZERNG_H
|
};
|
||||||
|
|
||||||
|
#endif // INCLUDE_CHANALYZERNG_H
|
||||||
|
|
|
@ -38,8 +38,6 @@
|
||||||
|
|
||||||
#include "chanalyzerng.h"
|
#include "chanalyzerng.h"
|
||||||
|
|
||||||
const QString ChannelAnalyzerNGGUI::m_channelID = "sdrangel.channel.chanalyzerng";
|
|
||||||
|
|
||||||
ChannelAnalyzerNGGUI* ChannelAnalyzerNGGUI::create(PluginAPI* pluginAPI, DeviceUISet *deviceUISet)
|
ChannelAnalyzerNGGUI* ChannelAnalyzerNGGUI::create(PluginAPI* pluginAPI, DeviceUISet *deviceUISet)
|
||||||
{
|
{
|
||||||
ChannelAnalyzerNGGUI* gui = new ChannelAnalyzerNGGUI(pluginAPI, deviceUISet);
|
ChannelAnalyzerNGGUI* gui = new ChannelAnalyzerNGGUI(pluginAPI, deviceUISet);
|
||||||
|
@ -407,7 +405,7 @@ ChannelAnalyzerNGGUI::ChannelAnalyzerNGGUI(PluginAPI* pluginAPI, DeviceUISet *de
|
||||||
|
|
||||||
connect(&m_channelMarker, SIGNAL(changed()), this, SLOT(viewChanged()));
|
connect(&m_channelMarker, SIGNAL(changed()), this, SLOT(viewChanged()));
|
||||||
|
|
||||||
m_deviceUISet->registerRxChannelInstance(m_channelID, this);
|
m_deviceUISet->registerRxChannelInstance(ChannelAnalyzerNG::m_channelID, this);
|
||||||
m_deviceUISet->addChannelMarker(&m_channelMarker);
|
m_deviceUISet->addChannelMarker(&m_channelMarker);
|
||||||
m_deviceUISet->addRollupWidget(this);
|
m_deviceUISet->addRollupWidget(this);
|
||||||
|
|
||||||
|
|
|
@ -55,8 +55,6 @@ public:
|
||||||
virtual MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; }
|
virtual MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; }
|
||||||
virtual bool handleMessage(const Message& message);
|
virtual bool handleMessage(const Message& message);
|
||||||
|
|
||||||
static const QString m_channelID;
|
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void viewChanged();
|
void viewChanged();
|
||||||
// void channelizerInputSampleRateChanged();
|
// void channelizerInputSampleRateChanged();
|
||||||
|
|
|
@ -19,10 +19,11 @@
|
||||||
#include "plugin/pluginapi.h"
|
#include "plugin/pluginapi.h"
|
||||||
#include "chanalyzerngplugin.h"
|
#include "chanalyzerngplugin.h"
|
||||||
#include "chanalyzernggui.h"
|
#include "chanalyzernggui.h"
|
||||||
|
#include "chanalyzerng.h"
|
||||||
|
|
||||||
const PluginDescriptor ChannelAnalyzerNGPlugin::m_pluginDescriptor = {
|
const PluginDescriptor ChannelAnalyzerNGPlugin::m_pluginDescriptor = {
|
||||||
QString("Channel Analyzer NG"),
|
QString("Channel Analyzer NG"),
|
||||||
QString("3.8.0"),
|
QString("3.8.2"),
|
||||||
QString("(c) Edouard Griffiths, F4EXB"),
|
QString("(c) Edouard Griffiths, F4EXB"),
|
||||||
QString("https://github.com/f4exb/sdrangel"),
|
QString("https://github.com/f4exb/sdrangel"),
|
||||||
true,
|
true,
|
||||||
|
@ -45,16 +46,28 @@ void ChannelAnalyzerNGPlugin::initPlugin(PluginAPI* pluginAPI)
|
||||||
m_pluginAPI = pluginAPI;
|
m_pluginAPI = pluginAPI;
|
||||||
|
|
||||||
// register demodulator
|
// register demodulator
|
||||||
m_pluginAPI->registerRxChannel(ChannelAnalyzerNGGUI::m_channelID, this);
|
m_pluginAPI->registerRxChannel(ChannelAnalyzerNG::m_channelID, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
PluginInstanceGUI* ChannelAnalyzerNGPlugin::createRxChannelGUI(const QString& channelName, DeviceUISet *deviceUISet)
|
PluginInstanceGUI* ChannelAnalyzerNGPlugin::createRxChannelGUI(const QString& channelName, DeviceUISet *deviceUISet)
|
||||||
{
|
{
|
||||||
if(channelName == ChannelAnalyzerNGGUI::m_channelID)
|
if(channelName == ChannelAnalyzerNG::m_channelID)
|
||||||
{
|
{
|
||||||
ChannelAnalyzerNGGUI* gui = ChannelAnalyzerNGGUI::create(m_pluginAPI, deviceUISet);
|
ChannelAnalyzerNGGUI* gui = ChannelAnalyzerNGGUI::create(m_pluginAPI, deviceUISet);
|
||||||
return gui;
|
return gui;
|
||||||
} else {
|
} else {
|
||||||
return NULL;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BasebandSampleSink* ChannelAnalyzerNGPlugin::createRxChannel(const QString& channelName, DeviceSourceAPI *deviceAPI)
|
||||||
|
{
|
||||||
|
if(channelName == ChannelAnalyzerNG::m_channelID)
|
||||||
|
{
|
||||||
|
ChannelAnalyzerNG* sink = new ChannelAnalyzerNG(deviceAPI);
|
||||||
|
return sink;
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -22,6 +22,7 @@
|
||||||
#include "plugin/plugininterface.h"
|
#include "plugin/plugininterface.h"
|
||||||
|
|
||||||
class DeviceUISet;
|
class DeviceUISet;
|
||||||
|
class BasebandSampleSink;
|
||||||
|
|
||||||
class ChannelAnalyzerNGPlugin : public QObject, PluginInterface {
|
class ChannelAnalyzerNGPlugin : public QObject, PluginInterface {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
@ -35,6 +36,7 @@ public:
|
||||||
void initPlugin(PluginAPI* pluginAPI);
|
void initPlugin(PluginAPI* pluginAPI);
|
||||||
|
|
||||||
PluginInstanceGUI* createRxChannelGUI(const QString& channelName, DeviceUISet *deviceUISet);
|
PluginInstanceGUI* createRxChannelGUI(const QString& channelName, DeviceUISet *deviceUISet);
|
||||||
|
BasebandSampleSink* createRxChannel(const QString& channelName, DeviceSourceAPI *deviceAPI);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static const PluginDescriptor m_pluginDescriptor;
|
static const PluginDescriptor m_pluginDescriptor;
|
||||||
|
|
|
@ -32,6 +32,7 @@
|
||||||
MESSAGE_CLASS_DEFINITION(AMDemod::MsgConfigureAMDemod, Message)
|
MESSAGE_CLASS_DEFINITION(AMDemod::MsgConfigureAMDemod, Message)
|
||||||
MESSAGE_CLASS_DEFINITION(AMDemod::MsgConfigureChannelizer, Message)
|
MESSAGE_CLASS_DEFINITION(AMDemod::MsgConfigureChannelizer, Message)
|
||||||
|
|
||||||
|
const QString AMDemod::m_channelID = "de.maintech.sdrangelove.channel.am";
|
||||||
const int AMDemod::m_udpBlockSize = 512;
|
const int AMDemod::m_udpBlockSize = 512;
|
||||||
|
|
||||||
AMDemod::AMDemod(DeviceSourceAPI *deviceAPI) :
|
AMDemod::AMDemod(DeviceSourceAPI *deviceAPI) :
|
||||||
|
|
|
@ -1,227 +1,229 @@
|
||||||
///////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////
|
||||||
// Copyright (C) 2015 Edouard Griffiths, F4EXB. //
|
// Copyright (C) 2015 Edouard Griffiths, F4EXB. //
|
||||||
// //
|
// //
|
||||||
// This program is free software; you can redistribute it and/or modify //
|
// This program is free software; you can redistribute it and/or modify //
|
||||||
// it under the terms of the GNU General Public License as published by //
|
// it under the terms of the GNU General Public License as published by //
|
||||||
// the Free Software Foundation as version 3 of the License, or //
|
// the Free Software Foundation as version 3 of the License, or //
|
||||||
// //
|
// //
|
||||||
// This program is distributed in the hope that it will be useful, //
|
// This program is distributed in the hope that it will be useful, //
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
|
||||||
// GNU General Public License V3 for more details. //
|
// GNU General Public License V3 for more details. //
|
||||||
// //
|
// //
|
||||||
// You should have received a copy of the GNU General Public License //
|
// You should have received a copy of the GNU General Public License //
|
||||||
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
|
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
|
||||||
///////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
#ifndef INCLUDE_AMDEMOD_H
|
#ifndef INCLUDE_AMDEMOD_H
|
||||||
#define INCLUDE_AMDEMOD_H
|
#define INCLUDE_AMDEMOD_H
|
||||||
|
|
||||||
#include <dsp/basebandsamplesink.h>
|
#include <dsp/basebandsamplesink.h>
|
||||||
#include <QMutex>
|
#include <QMutex>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include "dsp/nco.h"
|
#include "dsp/nco.h"
|
||||||
#include "dsp/interpolator.h"
|
#include "dsp/interpolator.h"
|
||||||
#include "dsp/movingaverage.h"
|
#include "dsp/movingaverage.h"
|
||||||
#include "dsp/agc.h"
|
#include "dsp/agc.h"
|
||||||
#include "dsp/bandpass.h"
|
#include "dsp/bandpass.h"
|
||||||
#include "audio/audiofifo.h"
|
#include "audio/audiofifo.h"
|
||||||
#include "util/message.h"
|
#include "util/message.h"
|
||||||
#include "amdemodsettings.h"
|
#include "amdemodsettings.h"
|
||||||
|
|
||||||
class DeviceSourceAPI;
|
class DeviceSourceAPI;
|
||||||
class DownChannelizer;
|
class DownChannelizer;
|
||||||
class ThreadedBasebandSampleSink;
|
class ThreadedBasebandSampleSink;
|
||||||
|
|
||||||
class AMDemod : public BasebandSampleSink {
|
class AMDemod : public BasebandSampleSink {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
class MsgConfigureAMDemod : public Message {
|
class MsgConfigureAMDemod : public Message {
|
||||||
MESSAGE_CLASS_DECLARATION
|
MESSAGE_CLASS_DECLARATION
|
||||||
|
|
||||||
public:
|
public:
|
||||||
const AMDemodSettings& getSettings() const { return m_settings; }
|
const AMDemodSettings& getSettings() const { return m_settings; }
|
||||||
bool getForce() const { return m_force; }
|
bool getForce() const { return m_force; }
|
||||||
|
|
||||||
static MsgConfigureAMDemod* create(const AMDemodSettings& settings, bool force)
|
static MsgConfigureAMDemod* create(const AMDemodSettings& settings, bool force)
|
||||||
{
|
{
|
||||||
return new MsgConfigureAMDemod(settings, force);
|
return new MsgConfigureAMDemod(settings, force);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
AMDemodSettings m_settings;
|
AMDemodSettings m_settings;
|
||||||
bool m_force;
|
bool m_force;
|
||||||
|
|
||||||
MsgConfigureAMDemod(const AMDemodSettings& settings, bool force) :
|
MsgConfigureAMDemod(const AMDemodSettings& settings, bool force) :
|
||||||
Message(),
|
Message(),
|
||||||
m_settings(settings),
|
m_settings(settings),
|
||||||
m_force(force)
|
m_force(force)
|
||||||
{ }
|
{ }
|
||||||
};
|
};
|
||||||
|
|
||||||
class MsgConfigureChannelizer : public Message {
|
class MsgConfigureChannelizer : public Message {
|
||||||
MESSAGE_CLASS_DECLARATION
|
MESSAGE_CLASS_DECLARATION
|
||||||
|
|
||||||
public:
|
public:
|
||||||
int getSampleRate() const { return m_sampleRate; }
|
int getSampleRate() const { return m_sampleRate; }
|
||||||
int getCenterFrequency() const { return m_centerFrequency; }
|
int getCenterFrequency() const { return m_centerFrequency; }
|
||||||
|
|
||||||
static MsgConfigureChannelizer* create(int sampleRate, int centerFrequency)
|
static MsgConfigureChannelizer* create(int sampleRate, int centerFrequency)
|
||||||
{
|
{
|
||||||
return new MsgConfigureChannelizer(sampleRate, centerFrequency);
|
return new MsgConfigureChannelizer(sampleRate, centerFrequency);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int m_sampleRate;
|
int m_sampleRate;
|
||||||
int m_centerFrequency;
|
int m_centerFrequency;
|
||||||
|
|
||||||
MsgConfigureChannelizer(int sampleRate, int centerFrequency) :
|
MsgConfigureChannelizer(int sampleRate, int centerFrequency) :
|
||||||
Message(),
|
Message(),
|
||||||
m_sampleRate(sampleRate),
|
m_sampleRate(sampleRate),
|
||||||
m_centerFrequency(centerFrequency)
|
m_centerFrequency(centerFrequency)
|
||||||
{ }
|
{ }
|
||||||
};
|
};
|
||||||
|
|
||||||
AMDemod(DeviceSourceAPI *deviceAPI);
|
AMDemod(DeviceSourceAPI *deviceAPI);
|
||||||
~AMDemod();
|
~AMDemod();
|
||||||
|
|
||||||
virtual void feed(const SampleVector::const_iterator& begin, const SampleVector::const_iterator& end, bool po);
|
virtual void feed(const SampleVector::const_iterator& begin, const SampleVector::const_iterator& end, bool po);
|
||||||
virtual void start();
|
virtual void start();
|
||||||
virtual void stop();
|
virtual void stop();
|
||||||
virtual bool handleMessage(const Message& cmd);
|
virtual bool handleMessage(const Message& cmd);
|
||||||
|
|
||||||
double getMagSq() const { return m_magsq; }
|
double getMagSq() const { return m_magsq; }
|
||||||
bool getSquelchOpen() const { return m_squelchOpen; }
|
bool getSquelchOpen() const { return m_squelchOpen; }
|
||||||
|
|
||||||
void getMagSqLevels(double& avg, double& peak, int& nbSamples)
|
void getMagSqLevels(double& avg, double& peak, int& nbSamples)
|
||||||
{
|
{
|
||||||
avg = m_magsqCount == 0 ? 1e-10 : m_magsqSum / m_magsqCount;
|
avg = m_magsqCount == 0 ? 1e-10 : m_magsqSum / m_magsqCount;
|
||||||
peak = m_magsqPeak == 0.0 ? 1e-10 : m_magsqPeak;
|
peak = m_magsqPeak == 0.0 ? 1e-10 : m_magsqPeak;
|
||||||
nbSamples = m_magsqCount == 0 ? 1 : m_magsqCount;
|
nbSamples = m_magsqCount == 0 ? 1 : m_magsqCount;
|
||||||
m_magsqSum = 0.0f;
|
m_magsqSum = 0.0f;
|
||||||
m_magsqPeak = 0.0f;
|
m_magsqPeak = 0.0f;
|
||||||
m_magsqCount = 0;
|
m_magsqCount = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
static const QString m_channelID;
|
||||||
enum RateState {
|
|
||||||
RSInitialFill,
|
private:
|
||||||
RSRunning
|
enum RateState {
|
||||||
};
|
RSInitialFill,
|
||||||
|
RSRunning
|
||||||
DeviceSourceAPI *m_deviceAPI;
|
};
|
||||||
ThreadedBasebandSampleSink* m_threadedChannelizer;
|
|
||||||
DownChannelizer* m_channelizer;
|
DeviceSourceAPI *m_deviceAPI;
|
||||||
|
ThreadedBasebandSampleSink* m_threadedChannelizer;
|
||||||
AMDemodSettings m_settings;
|
DownChannelizer* m_channelizer;
|
||||||
|
|
||||||
NCO m_nco;
|
AMDemodSettings m_settings;
|
||||||
Interpolator m_interpolator;
|
|
||||||
Real m_interpolatorDistance;
|
NCO m_nco;
|
||||||
Real m_interpolatorDistanceRemain;
|
Interpolator m_interpolator;
|
||||||
|
Real m_interpolatorDistance;
|
||||||
Real m_squelchLevel;
|
Real m_interpolatorDistanceRemain;
|
||||||
uint32_t m_squelchCount;
|
|
||||||
bool m_squelchOpen;
|
Real m_squelchLevel;
|
||||||
double m_magsq;
|
uint32_t m_squelchCount;
|
||||||
double m_magsqSum;
|
bool m_squelchOpen;
|
||||||
double m_magsqPeak;
|
double m_magsq;
|
||||||
int m_magsqCount;
|
double m_magsqSum;
|
||||||
|
double m_magsqPeak;
|
||||||
MovingAverage<double> m_movingAverage;
|
int m_magsqCount;
|
||||||
SimpleAGC m_volumeAGC;
|
|
||||||
Bandpass<Real> m_bandpass;
|
MovingAverage<double> m_movingAverage;
|
||||||
|
SimpleAGC m_volumeAGC;
|
||||||
AudioVector m_audioBuffer;
|
Bandpass<Real> m_bandpass;
|
||||||
uint32_t m_audioBufferFill;
|
|
||||||
AudioFifo m_audioFifo;
|
AudioVector m_audioBuffer;
|
||||||
UDPSink<qint16> *m_udpBufferAudio;
|
uint32_t m_audioBufferFill;
|
||||||
|
AudioFifo m_audioFifo;
|
||||||
static const int m_udpBlockSize;
|
UDPSink<qint16> *m_udpBufferAudio;
|
||||||
|
|
||||||
QMutex m_settingsMutex;
|
static const int m_udpBlockSize;
|
||||||
|
|
||||||
// void apply(bool force = false);
|
QMutex m_settingsMutex;
|
||||||
void applySettings(const AMDemodSettings& settings, bool force = false);
|
|
||||||
|
// void apply(bool force = false);
|
||||||
void processOneSample(Complex &ci)
|
void applySettings(const AMDemodSettings& settings, bool force = false);
|
||||||
{
|
|
||||||
Real magsq = ci.real() * ci.real() + ci.imag() * ci.imag();
|
void processOneSample(Complex &ci)
|
||||||
magsq /= (1<<30);
|
{
|
||||||
m_movingAverage.feed(magsq);
|
Real magsq = ci.real() * ci.real() + ci.imag() * ci.imag();
|
||||||
m_magsq = m_movingAverage.average();
|
magsq /= (1<<30);
|
||||||
m_magsqSum += magsq;
|
m_movingAverage.feed(magsq);
|
||||||
|
m_magsq = m_movingAverage.average();
|
||||||
if (magsq > m_magsqPeak)
|
m_magsqSum += magsq;
|
||||||
{
|
|
||||||
m_magsqPeak = magsq;
|
if (magsq > m_magsqPeak)
|
||||||
}
|
{
|
||||||
|
m_magsqPeak = magsq;
|
||||||
m_magsqCount++;
|
}
|
||||||
|
|
||||||
if (m_magsq >= m_squelchLevel)
|
m_magsqCount++;
|
||||||
{
|
|
||||||
if (m_squelchCount <= m_settings.m_audioSampleRate / 10)
|
if (m_magsq >= m_squelchLevel)
|
||||||
{
|
{
|
||||||
if (m_squelchCount == m_settings.m_audioSampleRate / 20) {
|
if (m_squelchCount <= m_settings.m_audioSampleRate / 10)
|
||||||
m_volumeAGC.fill(1.0);
|
{
|
||||||
}
|
if (m_squelchCount == m_settings.m_audioSampleRate / 20) {
|
||||||
|
m_volumeAGC.fill(1.0);
|
||||||
m_squelchCount++;
|
}
|
||||||
}
|
|
||||||
}
|
m_squelchCount++;
|
||||||
else
|
}
|
||||||
{
|
}
|
||||||
if (m_squelchCount > 1)
|
else
|
||||||
{
|
{
|
||||||
m_squelchCount -= 2;
|
if (m_squelchCount > 1)
|
||||||
}
|
{
|
||||||
}
|
m_squelchCount -= 2;
|
||||||
|
}
|
||||||
qint16 sample;
|
}
|
||||||
|
|
||||||
if ((m_squelchCount >= m_settings.m_audioSampleRate / 20) && !m_settings.m_audioMute)
|
qint16 sample;
|
||||||
{
|
|
||||||
Real demod = sqrt(magsq);
|
if ((m_squelchCount >= m_settings.m_audioSampleRate / 20) && !m_settings.m_audioMute)
|
||||||
m_volumeAGC.feed(demod);
|
{
|
||||||
demod = (demod - m_volumeAGC.getValue()) / m_volumeAGC.getValue();
|
Real demod = sqrt(magsq);
|
||||||
|
m_volumeAGC.feed(demod);
|
||||||
if (m_settings.m_bandpassEnable)
|
demod = (demod - m_volumeAGC.getValue()) / m_volumeAGC.getValue();
|
||||||
{
|
|
||||||
demod = m_bandpass.filter(demod);
|
if (m_settings.m_bandpassEnable)
|
||||||
demod /= 301.0f;
|
{
|
||||||
}
|
demod = m_bandpass.filter(demod);
|
||||||
|
demod /= 301.0f;
|
||||||
Real attack = (m_squelchCount - 0.05f * m_settings.m_audioSampleRate) / (0.05f * m_settings.m_audioSampleRate);
|
}
|
||||||
sample = demod * attack * 2048 * m_settings.m_volume;
|
|
||||||
if (m_settings.m_copyAudioToUDP) m_udpBufferAudio->write(demod * attack * 32768);
|
Real attack = (m_squelchCount - 0.05f * m_settings.m_audioSampleRate) / (0.05f * m_settings.m_audioSampleRate);
|
||||||
|
sample = demod * attack * 2048 * m_settings.m_volume;
|
||||||
m_squelchOpen = true;
|
if (m_settings.m_copyAudioToUDP) m_udpBufferAudio->write(demod * attack * 32768);
|
||||||
}
|
|
||||||
else
|
m_squelchOpen = true;
|
||||||
{
|
}
|
||||||
sample = 0;
|
else
|
||||||
if (m_settings.m_copyAudioToUDP) m_udpBufferAudio->write(0);
|
{
|
||||||
m_squelchOpen = false;
|
sample = 0;
|
||||||
}
|
if (m_settings.m_copyAudioToUDP) m_udpBufferAudio->write(0);
|
||||||
|
m_squelchOpen = false;
|
||||||
m_audioBuffer[m_audioBufferFill].l = sample;
|
}
|
||||||
m_audioBuffer[m_audioBufferFill].r = sample;
|
|
||||||
++m_audioBufferFill;
|
m_audioBuffer[m_audioBufferFill].l = sample;
|
||||||
|
m_audioBuffer[m_audioBufferFill].r = sample;
|
||||||
if (m_audioBufferFill >= m_audioBuffer.size())
|
++m_audioBufferFill;
|
||||||
{
|
|
||||||
uint res = m_audioFifo.write((const quint8*)&m_audioBuffer[0], m_audioBufferFill, 10);
|
if (m_audioBufferFill >= m_audioBuffer.size())
|
||||||
|
{
|
||||||
if (res != m_audioBufferFill)
|
uint res = m_audioFifo.write((const quint8*)&m_audioBuffer[0], m_audioBufferFill, 10);
|
||||||
{
|
|
||||||
qDebug("AMDemod::feed: %u/%u audio samples written", res, m_audioBufferFill);
|
if (res != m_audioBufferFill)
|
||||||
}
|
{
|
||||||
|
qDebug("AMDemod::feed: %u/%u audio samples written", res, m_audioBufferFill);
|
||||||
m_audioBufferFill = 0;
|
}
|
||||||
}
|
|
||||||
}
|
m_audioBufferFill = 0;
|
||||||
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
#endif // INCLUDE_AMDEMOD_H
|
};
|
||||||
|
|
||||||
|
#endif // INCLUDE_AMDEMOD_H
|
||||||
|
|
|
@ -34,8 +34,6 @@
|
||||||
|
|
||||||
#include "amdemod.h"
|
#include "amdemod.h"
|
||||||
|
|
||||||
const QString AMDemodGUI::m_channelID = "de.maintech.sdrangelove.channel.am";
|
|
||||||
|
|
||||||
AMDemodGUI* AMDemodGUI::create(PluginAPI* pluginAPI, DeviceUISet *deviceUISet)
|
AMDemodGUI* AMDemodGUI::create(PluginAPI* pluginAPI, DeviceUISet *deviceUISet)
|
||||||
{
|
{
|
||||||
AMDemodGUI* gui = new AMDemodGUI(pluginAPI, deviceUISet);
|
AMDemodGUI* gui = new AMDemodGUI(pluginAPI, deviceUISet);
|
||||||
|
@ -206,7 +204,7 @@ AMDemodGUI::AMDemodGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, QWidget*
|
||||||
|
|
||||||
connect(&m_channelMarker, SIGNAL(changed()), this, SLOT(channelMarkerChanged()));
|
connect(&m_channelMarker, SIGNAL(changed()), this, SLOT(channelMarkerChanged()));
|
||||||
|
|
||||||
m_deviceUISet->registerRxChannelInstance(m_channelID, this);
|
m_deviceUISet->registerRxChannelInstance(AMDemod::m_channelID, this);
|
||||||
m_deviceUISet->addChannelMarker(&m_channelMarker);
|
m_deviceUISet->addChannelMarker(&m_channelMarker);
|
||||||
m_deviceUISet->addRollupWidget(this);
|
m_deviceUISet->addRollupWidget(this);
|
||||||
|
|
||||||
|
|
|
@ -37,8 +37,6 @@ public:
|
||||||
virtual MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; }
|
virtual MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; }
|
||||||
virtual bool handleMessage(const Message& message);
|
virtual bool handleMessage(const Message& message);
|
||||||
|
|
||||||
static const QString m_channelID;
|
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void channelMarkerChanged();
|
void channelMarkerChanged();
|
||||||
void on_deltaFrequency_changed(qint64 value);
|
void on_deltaFrequency_changed(qint64 value);
|
||||||
|
|
|
@ -31,12 +31,12 @@ void AMDemodPlugin::initPlugin(PluginAPI* pluginAPI)
|
||||||
m_pluginAPI = pluginAPI;
|
m_pluginAPI = pluginAPI;
|
||||||
|
|
||||||
// register AM demodulator
|
// register AM demodulator
|
||||||
m_pluginAPI->registerRxChannel(AMDemodGUI::m_channelID, this);
|
m_pluginAPI->registerRxChannel(AMDemod::m_channelID, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
PluginInstanceGUI* AMDemodPlugin::createRxChannelGUI(const QString& channelName, DeviceUISet *deviceUISet)
|
PluginInstanceGUI* AMDemodPlugin::createRxChannelGUI(const QString& channelName, DeviceUISet *deviceUISet)
|
||||||
{
|
{
|
||||||
if(channelName == AMDemodGUI::m_channelID)
|
if(channelName == AMDemod::m_channelID)
|
||||||
{
|
{
|
||||||
AMDemodGUI* gui = AMDemodGUI::create(m_pluginAPI, deviceUISet);
|
AMDemodGUI* gui = AMDemodGUI::create(m_pluginAPI, deviceUISet);
|
||||||
return gui;
|
return gui;
|
||||||
|
@ -47,7 +47,7 @@ PluginInstanceGUI* AMDemodPlugin::createRxChannelGUI(const QString& channelName,
|
||||||
|
|
||||||
BasebandSampleSink* AMDemodPlugin::createRxChannel(const QString& channelName, DeviceSourceAPI *deviceAPI)
|
BasebandSampleSink* AMDemodPlugin::createRxChannel(const QString& channelName, DeviceSourceAPI *deviceAPI)
|
||||||
{
|
{
|
||||||
if(channelName == AMDemodGUI::m_channelID)
|
if(channelName == AMDemod::m_channelID)
|
||||||
{
|
{
|
||||||
AMDemod* sink = new AMDemod(deviceAPI);
|
AMDemod* sink = new AMDemod(deviceAPI);
|
||||||
return sink;
|
return sink;
|
||||||
|
|
|
@ -35,6 +35,7 @@ MESSAGE_CLASS_DEFINITION(ATVDemod::MsgReportEffectiveSampleRate, Message)
|
||||||
MESSAGE_CLASS_DEFINITION(ATVDemod::MsgConfigureChannelizer, Message)
|
MESSAGE_CLASS_DEFINITION(ATVDemod::MsgConfigureChannelizer, Message)
|
||||||
MESSAGE_CLASS_DEFINITION(ATVDemod::MsgReportChannelSampleRateChanged, Message)
|
MESSAGE_CLASS_DEFINITION(ATVDemod::MsgReportChannelSampleRateChanged, Message)
|
||||||
|
|
||||||
|
const QString ATVDemod::m_channelID = "sdrangel.channel.demodatv";
|
||||||
const int ATVDemod::m_ssbFftLen = 1024;
|
const int ATVDemod::m_ssbFftLen = 1024;
|
||||||
|
|
||||||
ATVDemod::ATVDemod(DeviceSourceAPI *deviceAPI) :
|
ATVDemod::ATVDemod(DeviceSourceAPI *deviceAPI) :
|
||||||
|
|
|
@ -227,6 +227,8 @@ public:
|
||||||
double getMagSq() const { return m_objMagSqAverage.average(); } //!< Beware this is scaled to 2^30
|
double getMagSq() const { return m_objMagSqAverage.average(); } //!< Beware this is scaled to 2^30
|
||||||
bool getBFOLocked();
|
bool getBFOLocked();
|
||||||
|
|
||||||
|
static const QString m_channelID;
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void channelSampleRateChanged();
|
void channelSampleRateChanged();
|
||||||
|
|
||||||
|
|
|
@ -36,8 +36,6 @@
|
||||||
|
|
||||||
#include "atvdemod.h"
|
#include "atvdemod.h"
|
||||||
|
|
||||||
const QString ATVDemodGUI::m_strChannelID = "sdrangel.channel.demodatv";
|
|
||||||
|
|
||||||
ATVDemodGUI* ATVDemodGUI::create(PluginAPI* objPluginAPI,
|
ATVDemodGUI* ATVDemodGUI::create(PluginAPI* objPluginAPI,
|
||||||
DeviceUISet *deviceUISet)
|
DeviceUISet *deviceUISet)
|
||||||
{
|
{
|
||||||
|
@ -312,7 +310,7 @@ ATVDemodGUI::ATVDemodGUI(PluginAPI* objPluginAPI, DeviceUISet *deviceUISet,
|
||||||
|
|
||||||
connect(&m_channelMarker, SIGNAL(changed()), this, SLOT(viewChanged()));
|
connect(&m_channelMarker, SIGNAL(changed()), this, SLOT(viewChanged()));
|
||||||
|
|
||||||
m_deviceUISet->registerRxChannelInstance(m_strChannelID, this);
|
m_deviceUISet->registerRxChannelInstance(ATVDemod::m_channelID, this);
|
||||||
m_deviceUISet->addChannelMarker(&m_channelMarker);
|
m_deviceUISet->addChannelMarker(&m_channelMarker);
|
||||||
m_deviceUISet->addRollupWidget(this);
|
m_deviceUISet->addRollupWidget(this);
|
||||||
|
|
||||||
|
|
|
@ -54,8 +54,6 @@ public:
|
||||||
virtual MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; }
|
virtual MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; }
|
||||||
virtual bool handleMessage(const Message& objMessage);
|
virtual bool handleMessage(const Message& objMessage);
|
||||||
|
|
||||||
static const QString m_strChannelID;
|
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void viewChanged();
|
void viewChanged();
|
||||||
void handleSourceMessages();
|
void handleSourceMessages();
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
#include "plugin/pluginapi.h"
|
#include "plugin/pluginapi.h"
|
||||||
|
|
||||||
#include "atvdemodgui.h"
|
#include "atvdemodgui.h"
|
||||||
|
#include "atvdemod.h"
|
||||||
#include "atvdemodplugin.h"
|
#include "atvdemodplugin.h"
|
||||||
|
|
||||||
const PluginDescriptor ATVDemodPlugin::m_ptrPluginDescriptor =
|
const PluginDescriptor ATVDemodPlugin::m_ptrPluginDescriptor =
|
||||||
|
@ -50,18 +51,30 @@ void ATVDemodPlugin::initPlugin(PluginAPI* ptrPluginAPI)
|
||||||
m_ptrPluginAPI = ptrPluginAPI;
|
m_ptrPluginAPI = ptrPluginAPI;
|
||||||
|
|
||||||
// register ATV demodulator
|
// register ATV demodulator
|
||||||
m_ptrPluginAPI->registerRxChannel(ATVDemodGUI::m_strChannelID, this);
|
m_ptrPluginAPI->registerRxChannel(ATVDemod::m_channelID, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
PluginInstanceGUI* ATVDemodPlugin::createRxChannelGUI(const QString& strChannelName, DeviceUISet *deviceUISet)
|
PluginInstanceGUI* ATVDemodPlugin::createRxChannelGUI(const QString& strChannelName, DeviceUISet *deviceUISet)
|
||||||
{
|
{
|
||||||
if(strChannelName == ATVDemodGUI::m_strChannelID)
|
if(strChannelName == ATVDemod::m_channelID)
|
||||||
{
|
{
|
||||||
ATVDemodGUI* ptrGui = ATVDemodGUI::create(m_ptrPluginAPI, deviceUISet);
|
ATVDemodGUI* ptrGui = ATVDemodGUI::create(m_ptrPluginAPI, deviceUISet);
|
||||||
return ptrGui;
|
return ptrGui;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return NULL;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BasebandSampleSink* ATVDemodPlugin::createRxChannel(const QString& channelName, DeviceSourceAPI *deviceAPI)
|
||||||
|
{
|
||||||
|
if(channelName == ATVDemod::m_channelID)
|
||||||
|
{
|
||||||
|
ATVDemod* sink = new ATVDemod(deviceAPI);
|
||||||
|
return sink;
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -22,6 +22,7 @@
|
||||||
#include "plugin/plugininterface.h"
|
#include "plugin/plugininterface.h"
|
||||||
|
|
||||||
class DeviceUISet;
|
class DeviceUISet;
|
||||||
|
class BasebandSampleSink;
|
||||||
|
|
||||||
class ATVDemodPlugin : public QObject, PluginInterface
|
class ATVDemodPlugin : public QObject, PluginInterface
|
||||||
{
|
{
|
||||||
|
@ -36,6 +37,7 @@ public:
|
||||||
void initPlugin(PluginAPI* ptrPluginAPI);
|
void initPlugin(PluginAPI* ptrPluginAPI);
|
||||||
|
|
||||||
PluginInstanceGUI* createRxChannelGUI(const QString& strChannelName, DeviceUISet *deviceUISet);
|
PluginInstanceGUI* createRxChannelGUI(const QString& strChannelName, DeviceUISet *deviceUISet);
|
||||||
|
BasebandSampleSink* createRxChannel(const QString& channelName, DeviceSourceAPI *deviceAPI);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static const PluginDescriptor m_ptrPluginDescriptor;
|
static const PluginDescriptor m_ptrPluginDescriptor;
|
||||||
|
|
|
@ -34,6 +34,7 @@ MESSAGE_CLASS_DEFINITION(BFMDemod::MsgConfigureChannelizer, Message)
|
||||||
MESSAGE_CLASS_DEFINITION(BFMDemod::MsgReportChannelSampleRateChanged, Message)
|
MESSAGE_CLASS_DEFINITION(BFMDemod::MsgReportChannelSampleRateChanged, Message)
|
||||||
MESSAGE_CLASS_DEFINITION(BFMDemod::MsgConfigureBFMDemod, Message)
|
MESSAGE_CLASS_DEFINITION(BFMDemod::MsgConfigureBFMDemod, Message)
|
||||||
|
|
||||||
|
const QString BFMDemod::m_channelID = "sdrangel.channel.bfm";
|
||||||
const Real BFMDemod::default_deemphasis = 50.0; // 50 us
|
const Real BFMDemod::default_deemphasis = 50.0; // 50 us
|
||||||
const int BFMDemod::m_udpBlockSize = 512;
|
const int BFMDemod::m_udpBlockSize = 512;
|
||||||
|
|
||||||
|
|
|
@ -1,219 +1,221 @@
|
||||||
///////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////
|
||||||
// Copyright (C) 2015 F4EXB //
|
// Copyright (C) 2015 F4EXB //
|
||||||
// written by Edouard Griffiths //
|
// written by Edouard Griffiths //
|
||||||
// //
|
// //
|
||||||
// This program is free software; you can redistribute it and/or modify //
|
// This program is free software; you can redistribute it and/or modify //
|
||||||
// it under the terms of the GNU General Public License as published by //
|
// it under the terms of the GNU General Public License as published by //
|
||||||
// the Free Software Foundation as version 3 of the License, or //
|
// the Free Software Foundation as version 3 of the License, or //
|
||||||
// //
|
// //
|
||||||
// This program is distributed in the hope that it will be useful, //
|
// This program is distributed in the hope that it will be useful, //
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
|
||||||
// GNU General Public License V3 for more details. //
|
// GNU General Public License V3 for more details. //
|
||||||
// //
|
// //
|
||||||
// You should have received a copy of the GNU General Public License //
|
// You should have received a copy of the GNU General Public License //
|
||||||
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
|
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
|
||||||
///////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
#ifndef INCLUDE_BFMDEMOD_H
|
#ifndef INCLUDE_BFMDEMOD_H
|
||||||
#define INCLUDE_BFMDEMOD_H
|
#define INCLUDE_BFMDEMOD_H
|
||||||
|
|
||||||
#include <dsp/basebandsamplesink.h>
|
#include <dsp/basebandsamplesink.h>
|
||||||
#include <QMutex>
|
#include <QMutex>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include "dsp/nco.h"
|
#include "dsp/nco.h"
|
||||||
#include "dsp/interpolator.h"
|
#include "dsp/interpolator.h"
|
||||||
#include "dsp/lowpass.h"
|
#include "dsp/lowpass.h"
|
||||||
#include "dsp/movingaverage.h"
|
#include "dsp/movingaverage.h"
|
||||||
#include "dsp/fftfilt.h"
|
#include "dsp/fftfilt.h"
|
||||||
#include "dsp/phaselock.h"
|
#include "dsp/phaselock.h"
|
||||||
#include "dsp/filterrc.h"
|
#include "dsp/filterrc.h"
|
||||||
#include "dsp/phasediscri.h"
|
#include "dsp/phasediscri.h"
|
||||||
#include "audio/audiofifo.h"
|
#include "audio/audiofifo.h"
|
||||||
#include "util/message.h"
|
#include "util/message.h"
|
||||||
#include "util/udpsink.h"
|
#include "util/udpsink.h"
|
||||||
|
|
||||||
#include "rdsparser.h"
|
#include "rdsparser.h"
|
||||||
#include "rdsdecoder.h"
|
#include "rdsdecoder.h"
|
||||||
#include "rdsdemod.h"
|
#include "rdsdemod.h"
|
||||||
#include "bfmdemodsettings.h"
|
#include "bfmdemodsettings.h"
|
||||||
|
|
||||||
class DeviceSourceAPI;
|
class DeviceSourceAPI;
|
||||||
class ThreadedBasebandSampleSink;
|
class ThreadedBasebandSampleSink;
|
||||||
class DownChannelizer;
|
class DownChannelizer;
|
||||||
|
|
||||||
class BFMDemod : public BasebandSampleSink {
|
class BFMDemod : public BasebandSampleSink {
|
||||||
public:
|
public:
|
||||||
class MsgConfigureBFMDemod : public Message {
|
class MsgConfigureBFMDemod : public Message {
|
||||||
MESSAGE_CLASS_DECLARATION
|
MESSAGE_CLASS_DECLARATION
|
||||||
|
|
||||||
public:
|
public:
|
||||||
const BFMDemodSettings& getSettings() const { return m_settings; }
|
const BFMDemodSettings& getSettings() const { return m_settings; }
|
||||||
bool getForce() const { return m_force; }
|
bool getForce() const { return m_force; }
|
||||||
|
|
||||||
static MsgConfigureBFMDemod* create(const BFMDemodSettings& settings, bool force)
|
static MsgConfigureBFMDemod* create(const BFMDemodSettings& settings, bool force)
|
||||||
{
|
{
|
||||||
return new MsgConfigureBFMDemod(settings, force);
|
return new MsgConfigureBFMDemod(settings, force);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
BFMDemodSettings m_settings;
|
BFMDemodSettings m_settings;
|
||||||
bool m_force;
|
bool m_force;
|
||||||
|
|
||||||
MsgConfigureBFMDemod(const BFMDemodSettings& settings, bool force) :
|
MsgConfigureBFMDemod(const BFMDemodSettings& settings, bool force) :
|
||||||
Message(),
|
Message(),
|
||||||
m_settings(settings),
|
m_settings(settings),
|
||||||
m_force(force)
|
m_force(force)
|
||||||
{ }
|
{ }
|
||||||
};
|
};
|
||||||
|
|
||||||
class MsgConfigureChannelizer : public Message {
|
class MsgConfigureChannelizer : public Message {
|
||||||
MESSAGE_CLASS_DECLARATION
|
MESSAGE_CLASS_DECLARATION
|
||||||
|
|
||||||
public:
|
public:
|
||||||
int getSampleRate() const { return m_sampleRate; }
|
int getSampleRate() const { return m_sampleRate; }
|
||||||
int getCenterFrequency() const { return m_centerFrequency; }
|
int getCenterFrequency() const { return m_centerFrequency; }
|
||||||
|
|
||||||
static MsgConfigureChannelizer* create(int sampleRate, int centerFrequency)
|
static MsgConfigureChannelizer* create(int sampleRate, int centerFrequency)
|
||||||
{
|
{
|
||||||
return new MsgConfigureChannelizer(sampleRate, centerFrequency);
|
return new MsgConfigureChannelizer(sampleRate, centerFrequency);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int m_sampleRate;
|
int m_sampleRate;
|
||||||
int m_centerFrequency;
|
int m_centerFrequency;
|
||||||
|
|
||||||
MsgConfigureChannelizer(int sampleRate, int centerFrequency) :
|
MsgConfigureChannelizer(int sampleRate, int centerFrequency) :
|
||||||
Message(),
|
Message(),
|
||||||
m_sampleRate(sampleRate),
|
m_sampleRate(sampleRate),
|
||||||
m_centerFrequency(centerFrequency)
|
m_centerFrequency(centerFrequency)
|
||||||
{ }
|
{ }
|
||||||
};
|
};
|
||||||
|
|
||||||
class MsgReportChannelSampleRateChanged : public Message {
|
class MsgReportChannelSampleRateChanged : public Message {
|
||||||
MESSAGE_CLASS_DECLARATION
|
MESSAGE_CLASS_DECLARATION
|
||||||
|
|
||||||
public:
|
public:
|
||||||
int getSampleRate() const { return m_sampleRate; }
|
int getSampleRate() const { return m_sampleRate; }
|
||||||
|
|
||||||
static MsgReportChannelSampleRateChanged* create(int sampleRate)
|
static MsgReportChannelSampleRateChanged* create(int sampleRate)
|
||||||
{
|
{
|
||||||
return new MsgReportChannelSampleRateChanged(sampleRate);
|
return new MsgReportChannelSampleRateChanged(sampleRate);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int m_sampleRate;
|
int m_sampleRate;
|
||||||
|
|
||||||
MsgReportChannelSampleRateChanged(int sampleRate) :
|
MsgReportChannelSampleRateChanged(int sampleRate) :
|
||||||
Message(),
|
Message(),
|
||||||
m_sampleRate(sampleRate)
|
m_sampleRate(sampleRate)
|
||||||
{ }
|
{ }
|
||||||
};
|
};
|
||||||
|
|
||||||
BFMDemod(DeviceSourceAPI *deviceAPI);
|
BFMDemod(DeviceSourceAPI *deviceAPI);
|
||||||
virtual ~BFMDemod();
|
virtual ~BFMDemod();
|
||||||
void setSampleSink(BasebandSampleSink* sampleSink) { m_sampleSink = sampleSink; }
|
void setSampleSink(BasebandSampleSink* sampleSink) { m_sampleSink = sampleSink; }
|
||||||
|
|
||||||
int getSampleRate() const { return m_settings.m_inputSampleRate; }
|
int getSampleRate() const { return m_settings.m_inputSampleRate; }
|
||||||
virtual void feed(const SampleVector::const_iterator& begin, const SampleVector::const_iterator& end, bool po);
|
virtual void feed(const SampleVector::const_iterator& begin, const SampleVector::const_iterator& end, bool po);
|
||||||
virtual void start();
|
virtual void start();
|
||||||
virtual void stop();
|
virtual void stop();
|
||||||
virtual bool handleMessage(const Message& cmd);
|
virtual bool handleMessage(const Message& cmd);
|
||||||
|
|
||||||
double getMagSq() const { return m_magsq; }
|
double getMagSq() const { return m_magsq; }
|
||||||
|
|
||||||
bool getPilotLock() const { return m_pilotPLL.locked(); }
|
bool getPilotLock() const { return m_pilotPLL.locked(); }
|
||||||
Real getPilotLevel() const { return m_pilotPLL.get_pilot_level(); }
|
Real getPilotLevel() const { return m_pilotPLL.get_pilot_level(); }
|
||||||
|
|
||||||
Real getDecoderQua() const { return m_rdsDecoder.m_qua; }
|
Real getDecoderQua() const { return m_rdsDecoder.m_qua; }
|
||||||
bool getDecoderSynced() const { return m_rdsDecoder.synced(); }
|
bool getDecoderSynced() const { return m_rdsDecoder.synced(); }
|
||||||
Real getDemodAcc() const { return m_rdsDemod.m_report.acc; }
|
Real getDemodAcc() const { return m_rdsDemod.m_report.acc; }
|
||||||
Real getDemodQua() const { return m_rdsDemod.m_report.qua; }
|
Real getDemodQua() const { return m_rdsDemod.m_report.qua; }
|
||||||
Real getDemodFclk() const { return m_rdsDemod.m_report.fclk; }
|
Real getDemodFclk() const { return m_rdsDemod.m_report.fclk; }
|
||||||
|
|
||||||
void getMagSqLevels(double& avg, double& peak, int& nbSamples)
|
void getMagSqLevels(double& avg, double& peak, int& nbSamples)
|
||||||
{
|
{
|
||||||
avg = m_magsqCount == 0 ? 1e-10 : m_magsqSum / m_magsqCount;
|
avg = m_magsqCount == 0 ? 1e-10 : m_magsqSum / m_magsqCount;
|
||||||
m_magsq = avg;
|
m_magsq = avg;
|
||||||
peak = m_magsqPeak == 0.0 ? 1e-10 : m_magsqPeak;
|
peak = m_magsqPeak == 0.0 ? 1e-10 : m_magsqPeak;
|
||||||
nbSamples = m_magsqCount == 0 ? 1 : m_magsqCount;
|
nbSamples = m_magsqCount == 0 ? 1 : m_magsqCount;
|
||||||
m_magsqSum = 0.0f;
|
m_magsqSum = 0.0f;
|
||||||
m_magsqPeak = 0.0f;
|
m_magsqPeak = 0.0f;
|
||||||
m_magsqCount = 0;
|
m_magsqCount = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
RDSParser& getRDSParser() { return m_rdsParser; }
|
RDSParser& getRDSParser() { return m_rdsParser; }
|
||||||
|
|
||||||
private slots:
|
static const QString m_channelID;
|
||||||
void channelSampleRateChanged();
|
|
||||||
|
private slots:
|
||||||
private:
|
void channelSampleRateChanged();
|
||||||
enum RateState {
|
|
||||||
RSInitialFill,
|
private:
|
||||||
RSRunning
|
enum RateState {
|
||||||
};
|
RSInitialFill,
|
||||||
|
RSRunning
|
||||||
DeviceSourceAPI *m_deviceAPI;
|
};
|
||||||
ThreadedBasebandSampleSink* m_threadedChannelizer;
|
|
||||||
DownChannelizer* m_channelizer;
|
DeviceSourceAPI *m_deviceAPI;
|
||||||
|
ThreadedBasebandSampleSink* m_threadedChannelizer;
|
||||||
BFMDemodSettings m_settings;
|
DownChannelizer* m_channelizer;
|
||||||
|
|
||||||
NCO m_nco;
|
BFMDemodSettings m_settings;
|
||||||
Interpolator m_interpolator; //!< Interpolator between fixed demod bandwidth and audio bandwidth (rational)
|
|
||||||
Real m_interpolatorDistance;
|
NCO m_nco;
|
||||||
Real m_interpolatorDistanceRemain;
|
Interpolator m_interpolator; //!< Interpolator between fixed demod bandwidth and audio bandwidth (rational)
|
||||||
|
Real m_interpolatorDistance;
|
||||||
Interpolator m_interpolatorStereo; //!< Twin Interpolator for stereo subcarrier
|
Real m_interpolatorDistanceRemain;
|
||||||
Real m_interpolatorStereoDistance;
|
|
||||||
Real m_interpolatorStereoDistanceRemain;
|
Interpolator m_interpolatorStereo; //!< Twin Interpolator for stereo subcarrier
|
||||||
|
Real m_interpolatorStereoDistance;
|
||||||
Interpolator m_interpolatorRDS; //!< Twin Interpolator for stereo subcarrier
|
Real m_interpolatorStereoDistanceRemain;
|
||||||
Real m_interpolatorRDSDistance;
|
|
||||||
Real m_interpolatorRDSDistanceRemain;
|
Interpolator m_interpolatorRDS; //!< Twin Interpolator for stereo subcarrier
|
||||||
|
Real m_interpolatorRDSDistance;
|
||||||
Lowpass<Real> m_lowpass;
|
Real m_interpolatorRDSDistanceRemain;
|
||||||
fftfilt* m_rfFilter;
|
|
||||||
static const int filtFftLen = 1024;
|
Lowpass<Real> m_lowpass;
|
||||||
|
fftfilt* m_rfFilter;
|
||||||
Real m_squelchLevel;
|
static const int filtFftLen = 1024;
|
||||||
int m_squelchState;
|
|
||||||
|
Real m_squelchLevel;
|
||||||
Real m_m1Arg; //!> x^-1 real sample
|
int m_squelchState;
|
||||||
|
|
||||||
double m_magsq;
|
Real m_m1Arg; //!> x^-1 real sample
|
||||||
double m_magsqSum;
|
|
||||||
double m_magsqPeak;
|
double m_magsq;
|
||||||
int m_magsqCount;
|
double m_magsqSum;
|
||||||
|
double m_magsqPeak;
|
||||||
AudioVector m_audioBuffer;
|
int m_magsqCount;
|
||||||
uint m_audioBufferFill;
|
|
||||||
|
AudioVector m_audioBuffer;
|
||||||
BasebandSampleSink* m_sampleSink;
|
uint m_audioBufferFill;
|
||||||
AudioFifo m_audioFifo;
|
|
||||||
SampleVector m_sampleBuffer;
|
BasebandSampleSink* m_sampleSink;
|
||||||
QMutex m_settingsMutex;
|
AudioFifo m_audioFifo;
|
||||||
|
SampleVector m_sampleBuffer;
|
||||||
RDSPhaseLock m_pilotPLL;
|
QMutex m_settingsMutex;
|
||||||
Real m_pilotPLLSamples[4];
|
|
||||||
|
RDSPhaseLock m_pilotPLL;
|
||||||
RDSDemod m_rdsDemod;
|
Real m_pilotPLLSamples[4];
|
||||||
RDSDecoder m_rdsDecoder;
|
|
||||||
RDSParser m_rdsParser;
|
RDSDemod m_rdsDemod;
|
||||||
|
RDSDecoder m_rdsDecoder;
|
||||||
LowPassFilterRC m_deemphasisFilterX;
|
RDSParser m_rdsParser;
|
||||||
LowPassFilterRC m_deemphasisFilterY;
|
|
||||||
static const Real default_deemphasis;
|
LowPassFilterRC m_deemphasisFilterX;
|
||||||
|
LowPassFilterRC m_deemphasisFilterY;
|
||||||
Real m_fmExcursion;
|
static const Real default_deemphasis;
|
||||||
static const int default_excursion = 750000; // +/- 75 kHz
|
|
||||||
|
Real m_fmExcursion;
|
||||||
PhaseDiscriminators m_phaseDiscri;
|
static const int default_excursion = 750000; // +/- 75 kHz
|
||||||
UDPSink<AudioSample> *m_udpBufferAudio;
|
|
||||||
|
PhaseDiscriminators m_phaseDiscri;
|
||||||
static const int m_udpBlockSize;
|
UDPSink<AudioSample> *m_udpBufferAudio;
|
||||||
|
|
||||||
void applySettings(const BFMDemodSettings& settings, bool force = false);
|
static const int m_udpBlockSize;
|
||||||
};
|
|
||||||
|
void applySettings(const BFMDemodSettings& settings, bool force = false);
|
||||||
#endif // INCLUDE_BFMDEMOD_H
|
};
|
||||||
|
|
||||||
|
#endif // INCLUDE_BFMDEMOD_H
|
||||||
|
|
|
@ -43,8 +43,6 @@
|
||||||
#include "rdstmc.h"
|
#include "rdstmc.h"
|
||||||
#include "ui_bfmdemodgui.h"
|
#include "ui_bfmdemodgui.h"
|
||||||
|
|
||||||
const QString BFMDemodGUI::m_channelID = "sdrangel.channel.bfm";
|
|
||||||
|
|
||||||
BFMDemodGUI* BFMDemodGUI::create(PluginAPI* pluginAPI, DeviceUISet *deviceUIset)
|
BFMDemodGUI* BFMDemodGUI::create(PluginAPI* pluginAPI, DeviceUISet *deviceUIset)
|
||||||
{
|
{
|
||||||
BFMDemodGUI* gui = new BFMDemodGUI(pluginAPI, deviceUIset);
|
BFMDemodGUI* gui = new BFMDemodGUI(pluginAPI, deviceUIset);
|
||||||
|
@ -364,7 +362,7 @@ BFMDemodGUI::BFMDemodGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, QWidget
|
||||||
|
|
||||||
connect(&m_channelMarker, SIGNAL(changed()), this, SLOT(channelMarkerChanged()));
|
connect(&m_channelMarker, SIGNAL(changed()), this, SLOT(channelMarkerChanged()));
|
||||||
|
|
||||||
m_deviceUISet->registerRxChannelInstance(m_channelID, this);
|
m_deviceUISet->registerRxChannelInstance(BFMDemod::m_channelID, this);
|
||||||
m_deviceUISet->addChannelMarker(&m_channelMarker);
|
m_deviceUISet->addChannelMarker(&m_channelMarker);
|
||||||
m_deviceUISet->addRollupWidget(this);
|
m_deviceUISet->addRollupWidget(this);
|
||||||
|
|
||||||
|
|
|
@ -56,8 +56,6 @@ public:
|
||||||
virtual MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; }
|
virtual MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; }
|
||||||
virtual bool handleMessage(const Message& message);
|
virtual bool handleMessage(const Message& message);
|
||||||
|
|
||||||
static const QString m_channelID;
|
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void on_deltaFrequency_changed(qint64 value);
|
void on_deltaFrequency_changed(qint64 value);
|
||||||
void on_rfBW_valueChanged(int value);
|
void on_rfBW_valueChanged(int value);
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
#include "plugin/pluginapi.h"
|
#include "plugin/pluginapi.h"
|
||||||
|
|
||||||
#include "bfmdemodgui.h"
|
#include "bfmdemodgui.h"
|
||||||
|
#include "bfmdemod.h"
|
||||||
|
|
||||||
const PluginDescriptor BFMPlugin::m_pluginDescriptor = {
|
const PluginDescriptor BFMPlugin::m_pluginDescriptor = {
|
||||||
QString("Broadcast FM Demodulator"),
|
QString("Broadcast FM Demodulator"),
|
||||||
|
@ -47,12 +48,12 @@ void BFMPlugin::initPlugin(PluginAPI* pluginAPI)
|
||||||
m_pluginAPI = pluginAPI;
|
m_pluginAPI = pluginAPI;
|
||||||
|
|
||||||
// register BFM demodulator
|
// register BFM demodulator
|
||||||
m_pluginAPI->registerRxChannel(BFMDemodGUI::m_channelID, this);
|
m_pluginAPI->registerRxChannel(BFMDemod::m_channelID, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
PluginInstanceGUI* BFMPlugin::createRxChannelGUI(const QString& channelName, DeviceUISet *deviceUISet)
|
PluginInstanceGUI* BFMPlugin::createRxChannelGUI(const QString& channelName, DeviceUISet *deviceUISet)
|
||||||
{
|
{
|
||||||
if(channelName == BFMDemodGUI::m_channelID)
|
if(channelName == BFMDemod::m_channelID)
|
||||||
{
|
{
|
||||||
BFMDemodGUI* gui = BFMDemodGUI::create(m_pluginAPI, deviceUISet);
|
BFMDemodGUI* gui = BFMDemodGUI::create(m_pluginAPI, deviceUISet);
|
||||||
return gui;
|
return gui;
|
||||||
|
@ -60,3 +61,15 @@ PluginInstanceGUI* BFMPlugin::createRxChannelGUI(const QString& channelName, Dev
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
BasebandSampleSink* BFMPlugin::createRxChannel(const QString& channelName, DeviceSourceAPI *deviceAPI)
|
||||||
|
{
|
||||||
|
if(channelName == BFMDemod::m_channelID)
|
||||||
|
{
|
||||||
|
BFMDemod* sink = new BFMDemod(deviceAPI);
|
||||||
|
return sink;
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -35,6 +35,7 @@ public:
|
||||||
void initPlugin(PluginAPI* pluginAPI);
|
void initPlugin(PluginAPI* pluginAPI);
|
||||||
|
|
||||||
PluginInstanceGUI* createRxChannelGUI(const QString& channelName, DeviceUISet *deviceUISet);
|
PluginInstanceGUI* createRxChannelGUI(const QString& channelName, DeviceUISet *deviceUISet);
|
||||||
|
BasebandSampleSink* createRxChannel(const QString& channelName, DeviceSourceAPI *deviceAPI);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static const PluginDescriptor m_pluginDescriptor;
|
static const PluginDescriptor m_pluginDescriptor;
|
||||||
|
|
|
@ -35,6 +35,7 @@ MESSAGE_CLASS_DEFINITION(DSDDemod::MsgConfigureChannelizer, Message)
|
||||||
MESSAGE_CLASS_DEFINITION(DSDDemod::MsgConfigureDSDDemod, Message)
|
MESSAGE_CLASS_DEFINITION(DSDDemod::MsgConfigureDSDDemod, Message)
|
||||||
MESSAGE_CLASS_DEFINITION(DSDDemod::MsgConfigureMyPosition, Message)
|
MESSAGE_CLASS_DEFINITION(DSDDemod::MsgConfigureMyPosition, Message)
|
||||||
|
|
||||||
|
const QString DSDDemod::m_channelID = "sdrangel.channel.dsddemod";
|
||||||
const int DSDDemod::m_udpBlockSize = 512;
|
const int DSDDemod::m_udpBlockSize = 512;
|
||||||
|
|
||||||
DSDDemod::DSDDemod(DeviceSourceAPI *deviceAPI) :
|
DSDDemod::DSDDemod(DeviceSourceAPI *deviceAPI) :
|
||||||
|
|
|
@ -1,194 +1,195 @@
|
||||||
///////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////
|
||||||
// Copyright (C) 2016 F4EXB //
|
// Copyright (C) 2016 F4EXB //
|
||||||
// written by Edouard Griffiths //
|
// written by Edouard Griffiths //
|
||||||
// //
|
// //
|
||||||
// This program is free software; you can redistribute it and/or modify //
|
// This program is free software; you can redistribute it and/or modify //
|
||||||
// it under the terms of the GNU General Public License as published by //
|
// it under the terms of the GNU General Public License as published by //
|
||||||
// the Free Software Foundation as version 3 of the License, or //
|
// the Free Software Foundation as version 3 of the License, or //
|
||||||
// //
|
// //
|
||||||
// This program is distributed in the hope that it will be useful, //
|
// This program is distributed in the hope that it will be useful, //
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
|
||||||
// GNU General Public License V3 for more details. //
|
// GNU General Public License V3 for more details. //
|
||||||
// //
|
// //
|
||||||
// You should have received a copy of the GNU General Public License //
|
// You should have received a copy of the GNU General Public License //
|
||||||
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
|
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
|
||||||
///////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
#ifndef INCLUDE_DSDDEMOD_H
|
#ifndef INCLUDE_DSDDEMOD_H
|
||||||
#define INCLUDE_DSDDEMOD_H
|
#define INCLUDE_DSDDEMOD_H
|
||||||
|
|
||||||
#include <dsp/basebandsamplesink.h>
|
#include <dsp/basebandsamplesink.h>
|
||||||
#include <dsp/phasediscri.h>
|
#include <dsp/phasediscri.h>
|
||||||
#include <QMutex>
|
#include <QMutex>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include "dsp/nco.h"
|
#include "dsp/nco.h"
|
||||||
#include "dsp/interpolator.h"
|
#include "dsp/interpolator.h"
|
||||||
#include "dsp/lowpass.h"
|
#include "dsp/lowpass.h"
|
||||||
#include "dsp/bandpass.h"
|
#include "dsp/bandpass.h"
|
||||||
#include "dsp/afsquelch.h"
|
#include "dsp/afsquelch.h"
|
||||||
#include "dsp/movingaverage.h"
|
#include "dsp/movingaverage.h"
|
||||||
#include "dsp/afsquelch.h"
|
#include "dsp/afsquelch.h"
|
||||||
#include "audio/audiofifo.h"
|
#include "audio/audiofifo.h"
|
||||||
#include "util/message.h"
|
#include "util/message.h"
|
||||||
#include "util/udpsink.h"
|
#include "util/udpsink.h"
|
||||||
|
|
||||||
#include "dsddemodsettings.h"
|
#include "dsddemodsettings.h"
|
||||||
#include "dsddecoder.h"
|
#include "dsddecoder.h"
|
||||||
|
|
||||||
class DeviceSourceAPI;
|
class DeviceSourceAPI;
|
||||||
class ThreadedBasebandSampleSink;
|
class ThreadedBasebandSampleSink;
|
||||||
class DownChannelizer;
|
class DownChannelizer;
|
||||||
|
|
||||||
class DSDDemod : public BasebandSampleSink {
|
class DSDDemod : public BasebandSampleSink {
|
||||||
public:
|
public:
|
||||||
class MsgConfigureDSDDemod : public Message {
|
class MsgConfigureDSDDemod : public Message {
|
||||||
MESSAGE_CLASS_DECLARATION
|
MESSAGE_CLASS_DECLARATION
|
||||||
|
|
||||||
public:
|
public:
|
||||||
const DSDDemodSettings& getSettings() const { return m_settings; }
|
const DSDDemodSettings& getSettings() const { return m_settings; }
|
||||||
bool getForce() const { return m_force; }
|
bool getForce() const { return m_force; }
|
||||||
|
|
||||||
static MsgConfigureDSDDemod* create(const DSDDemodSettings& settings, bool force)
|
static MsgConfigureDSDDemod* create(const DSDDemodSettings& settings, bool force)
|
||||||
{
|
{
|
||||||
return new MsgConfigureDSDDemod(settings, force);
|
return new MsgConfigureDSDDemod(settings, force);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
DSDDemodSettings m_settings;
|
DSDDemodSettings m_settings;
|
||||||
bool m_force;
|
bool m_force;
|
||||||
|
|
||||||
MsgConfigureDSDDemod(const DSDDemodSettings& settings, bool force) :
|
MsgConfigureDSDDemod(const DSDDemodSettings& settings, bool force) :
|
||||||
Message(),
|
Message(),
|
||||||
m_settings(settings),
|
m_settings(settings),
|
||||||
m_force(force)
|
m_force(force)
|
||||||
{ }
|
{ }
|
||||||
};
|
};
|
||||||
|
|
||||||
class MsgConfigureChannelizer : public Message {
|
class MsgConfigureChannelizer : public Message {
|
||||||
MESSAGE_CLASS_DECLARATION
|
MESSAGE_CLASS_DECLARATION
|
||||||
|
|
||||||
public:
|
public:
|
||||||
int getSampleRate() const { return m_sampleRate; }
|
int getSampleRate() const { return m_sampleRate; }
|
||||||
int getCenterFrequency() const { return m_centerFrequency; }
|
int getCenterFrequency() const { return m_centerFrequency; }
|
||||||
|
|
||||||
static MsgConfigureChannelizer* create(int sampleRate, int centerFrequency)
|
static MsgConfigureChannelizer* create(int sampleRate, int centerFrequency)
|
||||||
{
|
{
|
||||||
return new MsgConfigureChannelizer(sampleRate, centerFrequency);
|
return new MsgConfigureChannelizer(sampleRate, centerFrequency);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int m_sampleRate;
|
int m_sampleRate;
|
||||||
int m_centerFrequency;
|
int m_centerFrequency;
|
||||||
|
|
||||||
MsgConfigureChannelizer(int sampleRate, int centerFrequency) :
|
MsgConfigureChannelizer(int sampleRate, int centerFrequency) :
|
||||||
Message(),
|
Message(),
|
||||||
m_sampleRate(sampleRate),
|
m_sampleRate(sampleRate),
|
||||||
m_centerFrequency(centerFrequency)
|
m_centerFrequency(centerFrequency)
|
||||||
{ }
|
{ }
|
||||||
};
|
};
|
||||||
|
|
||||||
DSDDemod(DeviceSourceAPI *deviceAPI);
|
DSDDemod(DeviceSourceAPI *deviceAPI);
|
||||||
~DSDDemod();
|
~DSDDemod();
|
||||||
void setScopeSink(BasebandSampleSink* sampleSink) { m_scope = sampleSink; }
|
void setScopeSink(BasebandSampleSink* sampleSink) { m_scope = sampleSink; }
|
||||||
|
|
||||||
void configureMyPosition(MessageQueue* messageQueue, float myLatitude, float myLongitude);
|
void configureMyPosition(MessageQueue* messageQueue, float myLatitude, float myLongitude);
|
||||||
|
|
||||||
virtual void feed(const SampleVector::const_iterator& begin, const SampleVector::const_iterator& end, bool po);
|
virtual void feed(const SampleVector::const_iterator& begin, const SampleVector::const_iterator& end, bool po);
|
||||||
virtual void start();
|
virtual void start();
|
||||||
virtual void stop();
|
virtual void stop();
|
||||||
virtual bool handleMessage(const Message& cmd);
|
virtual bool handleMessage(const Message& cmd);
|
||||||
|
|
||||||
double getMagSq() { return m_magsq; }
|
double getMagSq() { return m_magsq; }
|
||||||
bool getSquelchOpen() const { return m_squelchOpen; }
|
bool getSquelchOpen() const { return m_squelchOpen; }
|
||||||
|
|
||||||
const DSDDecoder& getDecoder() const { return m_dsdDecoder; }
|
const DSDDecoder& getDecoder() const { return m_dsdDecoder; }
|
||||||
|
|
||||||
void getMagSqLevels(double& avg, double& peak, int& nbSamples)
|
void getMagSqLevels(double& avg, double& peak, int& nbSamples)
|
||||||
{
|
{
|
||||||
avg = m_magsqCount == 0 ? 1e-10 : m_magsqSum / m_magsqCount;
|
avg = m_magsqCount == 0 ? 1e-10 : m_magsqSum / m_magsqCount;
|
||||||
m_magsq = avg;
|
m_magsq = avg;
|
||||||
peak = m_magsqPeak == 0.0 ? 1e-10 : m_magsqPeak;
|
peak = m_magsqPeak == 0.0 ? 1e-10 : m_magsqPeak;
|
||||||
nbSamples = m_magsqCount == 0 ? 1 : m_magsqCount;
|
nbSamples = m_magsqCount == 0 ? 1 : m_magsqCount;
|
||||||
m_magsqSum = 0.0f;
|
m_magsqSum = 0.0f;
|
||||||
m_magsqPeak = 0.0f;
|
m_magsqPeak = 0.0f;
|
||||||
m_magsqCount = 0;
|
m_magsqCount = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const QString m_channelID;
|
||||||
private:
|
|
||||||
class MsgConfigureMyPosition : public Message {
|
private:
|
||||||
MESSAGE_CLASS_DECLARATION
|
class MsgConfigureMyPosition : public Message {
|
||||||
|
MESSAGE_CLASS_DECLARATION
|
||||||
public:
|
|
||||||
float getMyLatitude() const { return m_myLatitude; }
|
public:
|
||||||
float getMyLongitude() const { return m_myLongitude; }
|
float getMyLatitude() const { return m_myLatitude; }
|
||||||
|
float getMyLongitude() const { return m_myLongitude; }
|
||||||
static MsgConfigureMyPosition* create(float myLatitude, float myLongitude)
|
|
||||||
{
|
static MsgConfigureMyPosition* create(float myLatitude, float myLongitude)
|
||||||
return new MsgConfigureMyPosition(myLatitude, myLongitude);
|
{
|
||||||
}
|
return new MsgConfigureMyPosition(myLatitude, myLongitude);
|
||||||
|
}
|
||||||
private:
|
|
||||||
float m_myLatitude;
|
private:
|
||||||
float m_myLongitude;
|
float m_myLatitude;
|
||||||
|
float m_myLongitude;
|
||||||
MsgConfigureMyPosition(float myLatitude, float myLongitude) :
|
|
||||||
m_myLatitude(myLatitude),
|
MsgConfigureMyPosition(float myLatitude, float myLongitude) :
|
||||||
m_myLongitude(myLongitude)
|
m_myLatitude(myLatitude),
|
||||||
{}
|
m_myLongitude(myLongitude)
|
||||||
};
|
{}
|
||||||
|
};
|
||||||
enum RateState {
|
|
||||||
RSInitialFill,
|
enum RateState {
|
||||||
RSRunning
|
RSInitialFill,
|
||||||
};
|
RSRunning
|
||||||
|
};
|
||||||
DSDDemodSettings m_settings;
|
|
||||||
|
DSDDemodSettings m_settings;
|
||||||
DeviceSourceAPI *m_deviceAPI;
|
|
||||||
ThreadedBasebandSampleSink* m_threadedChannelizer;
|
DeviceSourceAPI *m_deviceAPI;
|
||||||
DownChannelizer* m_channelizer;
|
ThreadedBasebandSampleSink* m_threadedChannelizer;
|
||||||
|
DownChannelizer* m_channelizer;
|
||||||
NCO m_nco;
|
|
||||||
Interpolator m_interpolator;
|
NCO m_nco;
|
||||||
Real m_interpolatorDistance;
|
Interpolator m_interpolator;
|
||||||
Real m_interpolatorDistanceRemain;
|
Real m_interpolatorDistance;
|
||||||
int m_sampleCount;
|
Real m_interpolatorDistanceRemain;
|
||||||
int m_squelchCount;
|
int m_sampleCount;
|
||||||
int m_squelchGate;
|
int m_squelchCount;
|
||||||
|
int m_squelchGate;
|
||||||
double m_squelchLevel;
|
|
||||||
bool m_squelchOpen;
|
double m_squelchLevel;
|
||||||
|
bool m_squelchOpen;
|
||||||
MovingAverage<double> m_movingAverage;
|
|
||||||
double m_magsq;
|
MovingAverage<double> m_movingAverage;
|
||||||
double m_magsqSum;
|
double m_magsq;
|
||||||
double m_magsqPeak;
|
double m_magsqSum;
|
||||||
int m_magsqCount;
|
double m_magsqPeak;
|
||||||
|
int m_magsqCount;
|
||||||
Real m_fmExcursion;
|
|
||||||
|
Real m_fmExcursion;
|
||||||
SampleVector m_scopeSampleBuffer;
|
|
||||||
AudioVector m_audioBuffer;
|
SampleVector m_scopeSampleBuffer;
|
||||||
uint m_audioBufferFill;
|
AudioVector m_audioBuffer;
|
||||||
qint16 *m_sampleBuffer; //!< samples ring buffer
|
uint m_audioBufferFill;
|
||||||
int m_sampleBufferIndex;
|
qint16 *m_sampleBuffer; //!< samples ring buffer
|
||||||
|
int m_sampleBufferIndex;
|
||||||
AudioFifo m_audioFifo1;
|
|
||||||
AudioFifo m_audioFifo2;
|
AudioFifo m_audioFifo1;
|
||||||
BasebandSampleSink* m_scope;
|
AudioFifo m_audioFifo2;
|
||||||
bool m_scopeEnabled;
|
BasebandSampleSink* m_scope;
|
||||||
|
bool m_scopeEnabled;
|
||||||
DSDDecoder m_dsdDecoder;
|
|
||||||
QMutex m_settingsMutex;
|
DSDDecoder m_dsdDecoder;
|
||||||
|
QMutex m_settingsMutex;
|
||||||
PhaseDiscriminators m_phaseDiscri;
|
|
||||||
UDPSink<AudioSample> *m_udpBufferAudio;
|
PhaseDiscriminators m_phaseDiscri;
|
||||||
|
UDPSink<AudioSample> *m_udpBufferAudio;
|
||||||
static const int m_udpBlockSize;
|
|
||||||
|
static const int m_udpBlockSize;
|
||||||
void applySettings(DSDDemodSettings& settings, bool force = false);
|
|
||||||
};
|
void applySettings(DSDDemodSettings& settings, bool force = false);
|
||||||
|
};
|
||||||
#endif // INCLUDE_DSDDEMOD_H
|
|
||||||
|
#endif // INCLUDE_DSDDEMOD_H
|
||||||
|
|
|
@ -38,8 +38,6 @@
|
||||||
#include "dsddemodbaudrates.h"
|
#include "dsddemodbaudrates.h"
|
||||||
#include "dsddemod.h"
|
#include "dsddemod.h"
|
||||||
|
|
||||||
const QString DSDDemodGUI::m_channelID = "sdrangel.channel.dsddemod";
|
|
||||||
|
|
||||||
DSDDemodGUI* DSDDemodGUI::create(PluginAPI* pluginAPI, DeviceUISet *deviceUISet)
|
DSDDemodGUI* DSDDemodGUI::create(PluginAPI* pluginAPI, DeviceUISet *deviceUISet)
|
||||||
{
|
{
|
||||||
DSDDemodGUI* gui = new DSDDemodGUI(pluginAPI, deviceUISet);
|
DSDDemodGUI* gui = new DSDDemodGUI(pluginAPI, deviceUISet);
|
||||||
|
@ -281,7 +279,7 @@ DSDDemodGUI::DSDDemodGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, QWidget
|
||||||
|
|
||||||
connect(&m_channelMarker, SIGNAL(changed()), this, SLOT(channelMarkerChanged()));
|
connect(&m_channelMarker, SIGNAL(changed()), this, SLOT(channelMarkerChanged()));
|
||||||
|
|
||||||
m_deviceUISet->registerRxChannelInstance(m_channelID, this);
|
m_deviceUISet->registerRxChannelInstance(DSDDemod::m_channelID, this);
|
||||||
m_deviceUISet->addChannelMarker(&m_channelMarker);
|
m_deviceUISet->addChannelMarker(&m_channelMarker);
|
||||||
m_deviceUISet->addRollupWidget(this);
|
m_deviceUISet->addRollupWidget(this);
|
||||||
|
|
||||||
|
|
|
@ -57,8 +57,6 @@ public:
|
||||||
virtual MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; }
|
virtual MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; }
|
||||||
virtual bool handleMessage(const Message& message);
|
virtual bool handleMessage(const Message& message);
|
||||||
|
|
||||||
static const QString m_channelID;
|
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void formatStatusText();
|
void formatStatusText();
|
||||||
void channelMarkerChanged();
|
void channelMarkerChanged();
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
#include <QtPlugin>
|
#include <QtPlugin>
|
||||||
#include "plugin/pluginapi.h"
|
#include "plugin/pluginapi.h"
|
||||||
#include "dsddemodgui.h"
|
#include "dsddemodgui.h"
|
||||||
|
#include "dsddemod.h"
|
||||||
|
|
||||||
const PluginDescriptor DSDDemodPlugin::m_pluginDescriptor = {
|
const PluginDescriptor DSDDemodPlugin::m_pluginDescriptor = {
|
||||||
QString("DSD Demodulator"),
|
QString("DSD Demodulator"),
|
||||||
|
@ -47,16 +48,27 @@ void DSDDemodPlugin::initPlugin(PluginAPI* pluginAPI)
|
||||||
m_pluginAPI = pluginAPI;
|
m_pluginAPI = pluginAPI;
|
||||||
|
|
||||||
// register DSD demodulator
|
// register DSD demodulator
|
||||||
m_pluginAPI->registerRxChannel(DSDDemodGUI::m_channelID, this);
|
m_pluginAPI->registerRxChannel(DSDDemod::m_channelID, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
PluginInstanceGUI* DSDDemodPlugin::createRxChannelGUI(const QString& channelName, DeviceUISet *deviceUISet)
|
PluginInstanceGUI* DSDDemodPlugin::createRxChannelGUI(const QString& channelName, DeviceUISet *deviceUISet)
|
||||||
{
|
{
|
||||||
if(channelName == DSDDemodGUI::m_channelID)
|
if(channelName == DSDDemod::m_channelID)
|
||||||
{
|
{
|
||||||
DSDDemodGUI* gui = DSDDemodGUI::create(m_pluginAPI, deviceUISet);
|
DSDDemodGUI* gui = DSDDemodGUI::create(m_pluginAPI, deviceUISet);
|
||||||
return gui;
|
return gui;
|
||||||
} else {
|
} else {
|
||||||
return NULL;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BasebandSampleSink* DSDDemodPlugin::createRxChannel(const QString& channelName, DeviceSourceAPI *deviceAPI)
|
||||||
|
{
|
||||||
|
if(channelName == DSDDemod::m_channelID)
|
||||||
|
{
|
||||||
|
DSDDemod* sink = new DSDDemod(deviceAPI);
|
||||||
|
return sink;
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -22,6 +22,7 @@
|
||||||
#include "plugin/plugininterface.h"
|
#include "plugin/plugininterface.h"
|
||||||
|
|
||||||
class DeviceUISet;
|
class DeviceUISet;
|
||||||
|
class BasebandSampleSink;
|
||||||
|
|
||||||
class DSDDemodPlugin : public QObject, PluginInterface {
|
class DSDDemodPlugin : public QObject, PluginInterface {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
@ -35,6 +36,7 @@ public:
|
||||||
void initPlugin(PluginAPI* pluginAPI);
|
void initPlugin(PluginAPI* pluginAPI);
|
||||||
|
|
||||||
PluginInstanceGUI* createRxChannelGUI(const QString& channelName, DeviceUISet *deviceUISet);
|
PluginInstanceGUI* createRxChannelGUI(const QString& channelName, DeviceUISet *deviceUISet);
|
||||||
|
BasebandSampleSink* createRxChannel(const QString& channelName, DeviceSourceAPI *deviceAPI);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static const PluginDescriptor m_pluginDescriptor;
|
static const PluginDescriptor m_pluginDescriptor;
|
||||||
|
|
|
@ -31,6 +31,8 @@
|
||||||
MESSAGE_CLASS_DEFINITION(LoRaDemod::MsgConfigureLoRaDemod, Message)
|
MESSAGE_CLASS_DEFINITION(LoRaDemod::MsgConfigureLoRaDemod, Message)
|
||||||
MESSAGE_CLASS_DEFINITION(LoRaDemod::MsgConfigureChannelizer, Message)
|
MESSAGE_CLASS_DEFINITION(LoRaDemod::MsgConfigureChannelizer, Message)
|
||||||
|
|
||||||
|
const QString LoRaDemod::m_channelID = "de.maintech.sdrangelove.channel.lora";
|
||||||
|
|
||||||
LoRaDemod::LoRaDemod(DeviceSourceAPI* deviceAPI) :
|
LoRaDemod::LoRaDemod(DeviceSourceAPI* deviceAPI) :
|
||||||
m_deviceAPI(deviceAPI),
|
m_deviceAPI(deviceAPI),
|
||||||
m_sampleSink(0),
|
m_sampleSink(0),
|
||||||
|
|
|
@ -96,6 +96,8 @@ public:
|
||||||
virtual void stop();
|
virtual void stop();
|
||||||
virtual bool handleMessage(const Message& cmd);
|
virtual bool handleMessage(const Message& cmd);
|
||||||
|
|
||||||
|
static const QString m_channelID;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int detect(Complex sample, Complex angle);
|
int detect(Complex sample, Complex angle);
|
||||||
void dumpRaw(void);
|
void dumpRaw(void);
|
||||||
|
|
|
@ -16,8 +16,6 @@
|
||||||
#include "lorademod.h"
|
#include "lorademod.h"
|
||||||
#include "lorademodgui.h"
|
#include "lorademodgui.h"
|
||||||
|
|
||||||
const QString LoRaDemodGUI::m_channelID = "de.maintech.sdrangelove.channel.lora";
|
|
||||||
|
|
||||||
LoRaDemodGUI* LoRaDemodGUI::create(PluginAPI* pluginAPI, DeviceUISet *deviceUISet)
|
LoRaDemodGUI* LoRaDemodGUI::create(PluginAPI* pluginAPI, DeviceUISet *deviceUISet)
|
||||||
{
|
{
|
||||||
LoRaDemodGUI* gui = new LoRaDemodGUI(pluginAPI, deviceUISet);
|
LoRaDemodGUI* gui = new LoRaDemodGUI(pluginAPI, deviceUISet);
|
||||||
|
@ -153,7 +151,7 @@ LoRaDemodGUI::LoRaDemodGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, QWidg
|
||||||
|
|
||||||
connect(&m_channelMarker, SIGNAL(changed()), this, SLOT(viewChanged()));
|
connect(&m_channelMarker, SIGNAL(changed()), this, SLOT(viewChanged()));
|
||||||
|
|
||||||
m_deviceUISet->registerRxChannelInstance(m_channelID, this);
|
m_deviceUISet->registerRxChannelInstance(LoRaDemod::m_channelID, this);
|
||||||
m_deviceUISet->addChannelMarker(&m_channelMarker);
|
m_deviceUISet->addChannelMarker(&m_channelMarker);
|
||||||
m_deviceUISet->addRollupWidget(this);
|
m_deviceUISet->addRollupWidget(this);
|
||||||
|
|
||||||
|
|
|
@ -35,8 +35,6 @@ public:
|
||||||
virtual MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; }
|
virtual MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; }
|
||||||
virtual bool handleMessage(const Message& message);
|
virtual bool handleMessage(const Message& message);
|
||||||
|
|
||||||
static const QString m_channelID;
|
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void viewChanged();
|
void viewChanged();
|
||||||
void on_BW_valueChanged(int value);
|
void on_BW_valueChanged(int value);
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
|
|
||||||
#include "loraplugin.h"
|
#include "loraplugin.h"
|
||||||
#include "lorademodgui.h"
|
#include "lorademodgui.h"
|
||||||
|
#include "lorademod.h"
|
||||||
|
|
||||||
const PluginDescriptor LoRaPlugin::m_pluginDescriptor = {
|
const PluginDescriptor LoRaPlugin::m_pluginDescriptor = {
|
||||||
QString("LoRa Demodulator"),
|
QString("LoRa Demodulator"),
|
||||||
|
@ -29,16 +30,27 @@ void LoRaPlugin::initPlugin(PluginAPI* pluginAPI)
|
||||||
m_pluginAPI = pluginAPI;
|
m_pluginAPI = pluginAPI;
|
||||||
|
|
||||||
// register demodulator
|
// register demodulator
|
||||||
m_pluginAPI->registerRxChannel(LoRaDemodGUI::m_channelID, this);
|
m_pluginAPI->registerRxChannel(LoRaDemod::m_channelID, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
PluginInstanceGUI* LoRaPlugin::createRxChannelGUI(const QString& channelName, DeviceUISet *deviceUISet)
|
PluginInstanceGUI* LoRaPlugin::createRxChannelGUI(const QString& channelName, DeviceUISet *deviceUISet)
|
||||||
{
|
{
|
||||||
if(channelName == LoRaDemodGUI::m_channelID)
|
if(channelName == LoRaDemod::m_channelID)
|
||||||
{
|
{
|
||||||
LoRaDemodGUI* gui = LoRaDemodGUI::create(m_pluginAPI, deviceUISet);
|
LoRaDemodGUI* gui = LoRaDemodGUI::create(m_pluginAPI, deviceUISet);
|
||||||
return gui;
|
return gui;
|
||||||
} else {
|
} else {
|
||||||
return NULL;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BasebandSampleSink* LoRaPlugin::createRxChannel(const QString& channelName, DeviceSourceAPI *deviceAPI)
|
||||||
|
{
|
||||||
|
if(channelName == LoRaDemod::m_channelID)
|
||||||
|
{
|
||||||
|
LoRaDemod* sink = new LoRaDemod(deviceAPI);
|
||||||
|
return sink;
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
#include "plugin/plugininterface.h"
|
#include "plugin/plugininterface.h"
|
||||||
|
|
||||||
class DeviceUISet;
|
class DeviceUISet;
|
||||||
|
class BasebandSampleSink;
|
||||||
|
|
||||||
class LoRaPlugin : public QObject, PluginInterface {
|
class LoRaPlugin : public QObject, PluginInterface {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
@ -18,6 +19,7 @@ public:
|
||||||
void initPlugin(PluginAPI* pluginAPI);
|
void initPlugin(PluginAPI* pluginAPI);
|
||||||
|
|
||||||
PluginInstanceGUI* createRxChannelGUI(const QString& channelName, DeviceUISet *deviceUISet);
|
PluginInstanceGUI* createRxChannelGUI(const QString& channelName, DeviceUISet *deviceUISet);
|
||||||
|
BasebandSampleSink* createRxChannel(const QString& channelName, DeviceSourceAPI *deviceAPI);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static const PluginDescriptor m_pluginDescriptor;
|
static const PluginDescriptor m_pluginDescriptor;
|
||||||
|
|
|
@ -35,6 +35,8 @@ MESSAGE_CLASS_DEFINITION(NFMDemod::MsgConfigureNFMDemod, Message)
|
||||||
MESSAGE_CLASS_DEFINITION(NFMDemod::MsgConfigureChannelizer, Message)
|
MESSAGE_CLASS_DEFINITION(NFMDemod::MsgConfigureChannelizer, Message)
|
||||||
MESSAGE_CLASS_DEFINITION(NFMDemod::MsgReportCTCSSFreq, Message)
|
MESSAGE_CLASS_DEFINITION(NFMDemod::MsgReportCTCSSFreq, Message)
|
||||||
|
|
||||||
|
const QString NFMDemod::m_channelID = "de.maintech.sdrangelove.channel.nfm";
|
||||||
|
|
||||||
static const double afSqTones[2] = {1000.0, 6000.0}; // {1200.0, 8000.0};
|
static const double afSqTones[2] = {1000.0, 6000.0}; // {1200.0, 8000.0};
|
||||||
const int NFMDemod::m_udpBlockSize = 512;
|
const int NFMDemod::m_udpBlockSize = 512;
|
||||||
|
|
||||||
|
|
|
@ -138,6 +138,8 @@ public:
|
||||||
m_magsqCount = 0;
|
m_magsqCount = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const QString m_channelID;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
enum RateState {
|
enum RateState {
|
||||||
RSInitialFill,
|
RSInitialFill,
|
||||||
|
|
|
@ -16,8 +16,6 @@
|
||||||
#include "mainwindow.h"
|
#include "mainwindow.h"
|
||||||
#include "nfmdemod.h"
|
#include "nfmdemod.h"
|
||||||
|
|
||||||
const QString NFMDemodGUI::m_channelID = "de.maintech.sdrangelove.channel.nfm";
|
|
||||||
|
|
||||||
NFMDemodGUI* NFMDemodGUI::create(PluginAPI* pluginAPI, DeviceUISet *deviceUISet)
|
NFMDemodGUI* NFMDemodGUI::create(PluginAPI* pluginAPI, DeviceUISet *deviceUISet)
|
||||||
{
|
{
|
||||||
NFMDemodGUI* gui = new NFMDemodGUI(pluginAPI, deviceUISet);
|
NFMDemodGUI* gui = new NFMDemodGUI(pluginAPI, deviceUISet);
|
||||||
|
@ -277,7 +275,7 @@ NFMDemodGUI::NFMDemodGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, QWidget
|
||||||
|
|
||||||
connect(&m_channelMarker, SIGNAL(changed()), this, SLOT(channelMarkerChanged()));
|
connect(&m_channelMarker, SIGNAL(changed()), this, SLOT(channelMarkerChanged()));
|
||||||
|
|
||||||
m_deviceUISet->registerRxChannelInstance(m_channelID, this);
|
m_deviceUISet->registerRxChannelInstance(NFMDemod::m_channelID, this);
|
||||||
m_deviceUISet->addChannelMarker(&m_channelMarker);
|
m_deviceUISet->addChannelMarker(&m_channelMarker);
|
||||||
m_deviceUISet->addRollupWidget(this);
|
m_deviceUISet->addRollupWidget(this);
|
||||||
|
|
||||||
|
|
|
@ -38,8 +38,6 @@ public:
|
||||||
virtual bool handleMessage(const Message& message);
|
virtual bool handleMessage(const Message& message);
|
||||||
void setCtcssFreq(Real ctcssFreq);
|
void setCtcssFreq(Real ctcssFreq);
|
||||||
|
|
||||||
static const QString m_channelID;
|
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void channelMarkerChanged();
|
void channelMarkerChanged();
|
||||||
void on_deltaFrequency_changed(qint64 value);
|
void on_deltaFrequency_changed(qint64 value);
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
|
|
||||||
#include "nfmplugin.h"
|
#include "nfmplugin.h"
|
||||||
#include "nfmdemodgui.h"
|
#include "nfmdemodgui.h"
|
||||||
|
#include "nfmdemod.h"
|
||||||
|
|
||||||
const PluginDescriptor NFMPlugin::m_pluginDescriptor = {
|
const PluginDescriptor NFMPlugin::m_pluginDescriptor = {
|
||||||
QString("NFM Demodulator"),
|
QString("NFM Demodulator"),
|
||||||
|
@ -29,15 +30,26 @@ void NFMPlugin::initPlugin(PluginAPI* pluginAPI)
|
||||||
m_pluginAPI = pluginAPI;
|
m_pluginAPI = pluginAPI;
|
||||||
|
|
||||||
// register NFM demodulator
|
// register NFM demodulator
|
||||||
m_pluginAPI->registerRxChannel(NFMDemodGUI::m_channelID, this);
|
m_pluginAPI->registerRxChannel(NFMDemod::m_channelID, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
PluginInstanceGUI* NFMPlugin::createRxChannelGUI(const QString& channelName, DeviceUISet *deviceUISet)
|
PluginInstanceGUI* NFMPlugin::createRxChannelGUI(const QString& channelName, DeviceUISet *deviceUISet)
|
||||||
{
|
{
|
||||||
if(channelName == NFMDemodGUI::m_channelID) {
|
if(channelName == NFMDemod::m_channelID) {
|
||||||
NFMDemodGUI* gui = NFMDemodGUI::create(m_pluginAPI, deviceUISet);
|
NFMDemodGUI* gui = NFMDemodGUI::create(m_pluginAPI, deviceUISet);
|
||||||
return gui;
|
return gui;
|
||||||
} else {
|
} else {
|
||||||
return NULL;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BasebandSampleSink* NFMPlugin::createRxChannel(const QString& channelName, DeviceSourceAPI *deviceAPI)
|
||||||
|
{
|
||||||
|
if(channelName == NFMDemod::m_channelID)
|
||||||
|
{
|
||||||
|
NFMDemod* sink = new NFMDemod(deviceAPI);
|
||||||
|
return sink;
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
#include "plugin/plugininterface.h"
|
#include "plugin/plugininterface.h"
|
||||||
|
|
||||||
class DeviceUISet;
|
class DeviceUISet;
|
||||||
|
class BasebandSampleSink;
|
||||||
|
|
||||||
class NFMPlugin : public QObject, PluginInterface {
|
class NFMPlugin : public QObject, PluginInterface {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
@ -18,6 +19,7 @@ public:
|
||||||
void initPlugin(PluginAPI* pluginAPI);
|
void initPlugin(PluginAPI* pluginAPI);
|
||||||
|
|
||||||
PluginInstanceGUI* createRxChannelGUI(const QString& channelName, DeviceUISet *deviceUISet);
|
PluginInstanceGUI* createRxChannelGUI(const QString& channelName, DeviceUISet *deviceUISet);
|
||||||
|
BasebandSampleSink* createRxChannel(const QString& channelName, DeviceSourceAPI *deviceAPI);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static const PluginDescriptor m_pluginDescriptor;
|
static const PluginDescriptor m_pluginDescriptor;
|
||||||
|
|
|
@ -34,6 +34,8 @@ MESSAGE_CLASS_DEFINITION(SSBDemod::MsgConfigureSSBDemod, Message)
|
||||||
MESSAGE_CLASS_DEFINITION(SSBDemod::MsgConfigureSSBDemodPrivate, Message)
|
MESSAGE_CLASS_DEFINITION(SSBDemod::MsgConfigureSSBDemodPrivate, Message)
|
||||||
MESSAGE_CLASS_DEFINITION(SSBDemod::MsgConfigureChannelizer, Message)
|
MESSAGE_CLASS_DEFINITION(SSBDemod::MsgConfigureChannelizer, Message)
|
||||||
|
|
||||||
|
const QString SSBDemod::m_channelID = "de.maintech.sdrangelove.channel.ssb";
|
||||||
|
|
||||||
SSBDemod::SSBDemod(DeviceSourceAPI *deviceAPI) :
|
SSBDemod::SSBDemod(DeviceSourceAPI *deviceAPI) :
|
||||||
m_deviceAPI(deviceAPI),
|
m_deviceAPI(deviceAPI),
|
||||||
m_audioBinaual(false),
|
m_audioBinaual(false),
|
||||||
|
|
|
@ -1,270 +1,272 @@
|
||||||
///////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////
|
||||||
// Copyright (C) 2012 maintech GmbH, Otto-Hahn-Str. 15, 97204 Hoechberg, Germany //
|
// Copyright (C) 2012 maintech GmbH, Otto-Hahn-Str. 15, 97204 Hoechberg, Germany //
|
||||||
// written by Christian Daniel //
|
// written by Christian Daniel //
|
||||||
// //
|
// //
|
||||||
// This program is free software; you can redistribute it and/or modify //
|
// This program is free software; you can redistribute it and/or modify //
|
||||||
// it under the terms of the GNU General Public License as published by //
|
// it under the terms of the GNU General Public License as published by //
|
||||||
// the Free Software Foundation as version 3 of the License, or //
|
// the Free Software Foundation as version 3 of the License, or //
|
||||||
// //
|
// //
|
||||||
// This program is distributed in the hope that it will be useful, //
|
// This program is distributed in the hope that it will be useful, //
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
|
||||||
// GNU General Public License V3 for more details. //
|
// GNU General Public License V3 for more details. //
|
||||||
// //
|
// //
|
||||||
// You should have received a copy of the GNU General Public License //
|
// You should have received a copy of the GNU General Public License //
|
||||||
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
|
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
|
||||||
///////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
#ifndef INCLUDE_SSBDEMOD_H
|
#ifndef INCLUDE_SSBDEMOD_H
|
||||||
#define INCLUDE_SSBDEMOD_H
|
#define INCLUDE_SSBDEMOD_H
|
||||||
|
|
||||||
#include <QMutex>
|
#include <QMutex>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include <dsp/basebandsamplesink.h>
|
#include <dsp/basebandsamplesink.h>
|
||||||
#include "dsp/ncof.h"
|
#include "dsp/ncof.h"
|
||||||
#include "dsp/interpolator.h"
|
#include "dsp/interpolator.h"
|
||||||
#include "dsp/fftfilt.h"
|
#include "dsp/fftfilt.h"
|
||||||
#include "dsp/agc.h"
|
#include "dsp/agc.h"
|
||||||
#include "audio/audiofifo.h"
|
#include "audio/audiofifo.h"
|
||||||
#include "util/message.h"
|
#include "util/message.h"
|
||||||
|
|
||||||
#include "ssbdemodsettings.h"
|
#include "ssbdemodsettings.h"
|
||||||
|
|
||||||
#define ssbFftLen 1024
|
#define ssbFftLen 1024
|
||||||
#define agcTarget 3276.8 // -10 dB amplitude => -20 dB power: center of normal signal
|
#define agcTarget 3276.8 // -10 dB amplitude => -20 dB power: center of normal signal
|
||||||
|
|
||||||
class DeviceSourceAPI;
|
class DeviceSourceAPI;
|
||||||
class ThreadedBasebandSampleSink;
|
class ThreadedBasebandSampleSink;
|
||||||
class DownChannelizer;
|
class DownChannelizer;
|
||||||
|
|
||||||
class SSBDemod : public BasebandSampleSink {
|
class SSBDemod : public BasebandSampleSink {
|
||||||
public:
|
public:
|
||||||
class MsgConfigureSSBDemod : public Message {
|
class MsgConfigureSSBDemod : public Message {
|
||||||
MESSAGE_CLASS_DECLARATION
|
MESSAGE_CLASS_DECLARATION
|
||||||
|
|
||||||
public:
|
public:
|
||||||
const SSBDemodSettings& getSettings() const { return m_settings; }
|
const SSBDemodSettings& getSettings() const { return m_settings; }
|
||||||
bool getForce() const { return m_force; }
|
bool getForce() const { return m_force; }
|
||||||
|
|
||||||
static MsgConfigureSSBDemod* create(const SSBDemodSettings& settings, bool force)
|
static MsgConfigureSSBDemod* create(const SSBDemodSettings& settings, bool force)
|
||||||
{
|
{
|
||||||
return new MsgConfigureSSBDemod(settings, force);
|
return new MsgConfigureSSBDemod(settings, force);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
SSBDemodSettings m_settings;
|
SSBDemodSettings m_settings;
|
||||||
bool m_force;
|
bool m_force;
|
||||||
|
|
||||||
MsgConfigureSSBDemod(const SSBDemodSettings& settings, bool force) :
|
MsgConfigureSSBDemod(const SSBDemodSettings& settings, bool force) :
|
||||||
Message(),
|
Message(),
|
||||||
m_settings(settings),
|
m_settings(settings),
|
||||||
m_force(force)
|
m_force(force)
|
||||||
{ }
|
{ }
|
||||||
};
|
};
|
||||||
|
|
||||||
class MsgConfigureChannelizer : public Message {
|
class MsgConfigureChannelizer : public Message {
|
||||||
MESSAGE_CLASS_DECLARATION
|
MESSAGE_CLASS_DECLARATION
|
||||||
|
|
||||||
public:
|
public:
|
||||||
int getSampleRate() const { return m_sampleRate; }
|
int getSampleRate() const { return m_sampleRate; }
|
||||||
int getCenterFrequency() const { return m_centerFrequency; }
|
int getCenterFrequency() const { return m_centerFrequency; }
|
||||||
|
|
||||||
static MsgConfigureChannelizer* create(int sampleRate, int centerFrequency)
|
static MsgConfigureChannelizer* create(int sampleRate, int centerFrequency)
|
||||||
{
|
{
|
||||||
return new MsgConfigureChannelizer(sampleRate, centerFrequency);
|
return new MsgConfigureChannelizer(sampleRate, centerFrequency);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int m_sampleRate;
|
int m_sampleRate;
|
||||||
int m_centerFrequency;
|
int m_centerFrequency;
|
||||||
|
|
||||||
MsgConfigureChannelizer(int sampleRate, int centerFrequency) :
|
MsgConfigureChannelizer(int sampleRate, int centerFrequency) :
|
||||||
Message(),
|
Message(),
|
||||||
m_sampleRate(sampleRate),
|
m_sampleRate(sampleRate),
|
||||||
m_centerFrequency(centerFrequency)
|
m_centerFrequency(centerFrequency)
|
||||||
{ }
|
{ }
|
||||||
};
|
};
|
||||||
|
|
||||||
SSBDemod(DeviceSourceAPI *deviceAPI);
|
SSBDemod(DeviceSourceAPI *deviceAPI);
|
||||||
virtual ~SSBDemod();
|
virtual ~SSBDemod();
|
||||||
void setSampleSink(BasebandSampleSink* sampleSink) { m_sampleSink = sampleSink; }
|
void setSampleSink(BasebandSampleSink* sampleSink) { m_sampleSink = sampleSink; }
|
||||||
|
|
||||||
void configure(MessageQueue* messageQueue,
|
void configure(MessageQueue* messageQueue,
|
||||||
Real Bandwidth,
|
Real Bandwidth,
|
||||||
Real LowCutoff,
|
Real LowCutoff,
|
||||||
Real volume,
|
Real volume,
|
||||||
int spanLog2,
|
int spanLog2,
|
||||||
bool audioBinaural,
|
bool audioBinaural,
|
||||||
bool audioFlipChannels,
|
bool audioFlipChannels,
|
||||||
bool dsb,
|
bool dsb,
|
||||||
bool audioMute,
|
bool audioMute,
|
||||||
bool agc,
|
bool agc,
|
||||||
bool agcClamping,
|
bool agcClamping,
|
||||||
int agcTimeLog2,
|
int agcTimeLog2,
|
||||||
int agcPowerThreshold,
|
int agcPowerThreshold,
|
||||||
int agcThresholdGate);
|
int agcThresholdGate);
|
||||||
|
|
||||||
virtual void feed(const SampleVector::const_iterator& begin, const SampleVector::const_iterator& end, bool positiveOnly);
|
virtual void feed(const SampleVector::const_iterator& begin, const SampleVector::const_iterator& end, bool positiveOnly);
|
||||||
virtual void start();
|
virtual void start();
|
||||||
virtual void stop();
|
virtual void stop();
|
||||||
virtual bool handleMessage(const Message& cmd);
|
virtual bool handleMessage(const Message& cmd);
|
||||||
|
|
||||||
double getMagSq() const { return m_magsq; }
|
double getMagSq() const { return m_magsq; }
|
||||||
bool getAudioActive() const { return m_audioActive; }
|
bool getAudioActive() const { return m_audioActive; }
|
||||||
|
|
||||||
void getMagSqLevels(double& avg, double& peak, int& nbSamples)
|
void getMagSqLevels(double& avg, double& peak, int& nbSamples)
|
||||||
{
|
{
|
||||||
avg = m_magsqCount == 0 ? 1e-10 : m_magsqSum / m_magsqCount;
|
avg = m_magsqCount == 0 ? 1e-10 : m_magsqSum / m_magsqCount;
|
||||||
m_magsq = avg;
|
m_magsq = avg;
|
||||||
peak = m_magsqPeak == 0.0 ? 1e-10 : m_magsqPeak;
|
peak = m_magsqPeak == 0.0 ? 1e-10 : m_magsqPeak;
|
||||||
nbSamples = m_magsqCount == 0 ? 1 : m_magsqCount;
|
nbSamples = m_magsqCount == 0 ? 1 : m_magsqCount;
|
||||||
m_magsqSum = 0.0f;
|
m_magsqSum = 0.0f;
|
||||||
m_magsqPeak = 0.0f;
|
m_magsqPeak = 0.0f;
|
||||||
m_magsqCount = 0;
|
m_magsqCount = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
static const QString m_channelID;
|
||||||
class MsgConfigureSSBDemodPrivate : public Message {
|
|
||||||
MESSAGE_CLASS_DECLARATION
|
private:
|
||||||
|
class MsgConfigureSSBDemodPrivate : public Message {
|
||||||
public:
|
MESSAGE_CLASS_DECLARATION
|
||||||
Real getBandwidth() const { return m_Bandwidth; }
|
|
||||||
Real getLoCutoff() const { return m_LowCutoff; }
|
public:
|
||||||
Real getVolume() const { return m_volume; }
|
Real getBandwidth() const { return m_Bandwidth; }
|
||||||
int getSpanLog2() const { return m_spanLog2; }
|
Real getLoCutoff() const { return m_LowCutoff; }
|
||||||
bool getAudioBinaural() const { return m_audioBinaural; }
|
Real getVolume() const { return m_volume; }
|
||||||
bool getAudioFlipChannels() const { return m_audioFlipChannels; }
|
int getSpanLog2() const { return m_spanLog2; }
|
||||||
bool getDSB() const { return m_dsb; }
|
bool getAudioBinaural() const { return m_audioBinaural; }
|
||||||
bool getAudioMute() const { return m_audioMute; }
|
bool getAudioFlipChannels() const { return m_audioFlipChannels; }
|
||||||
bool getAGC() const { return m_agc; }
|
bool getDSB() const { return m_dsb; }
|
||||||
bool getAGCClamping() const { return m_agcClamping; }
|
bool getAudioMute() const { return m_audioMute; }
|
||||||
int getAGCTimeLog2() const { return m_agcTimeLog2; }
|
bool getAGC() const { return m_agc; }
|
||||||
int getAGCPowerThershold() const { return m_agcPowerThreshold; }
|
bool getAGCClamping() const { return m_agcClamping; }
|
||||||
int getAGCThersholdGate() const { return m_agcThresholdGate; }
|
int getAGCTimeLog2() const { return m_agcTimeLog2; }
|
||||||
|
int getAGCPowerThershold() const { return m_agcPowerThreshold; }
|
||||||
static MsgConfigureSSBDemodPrivate* create(Real Bandwidth,
|
int getAGCThersholdGate() const { return m_agcThresholdGate; }
|
||||||
Real LowCutoff,
|
|
||||||
Real volume,
|
static MsgConfigureSSBDemodPrivate* create(Real Bandwidth,
|
||||||
int spanLog2,
|
Real LowCutoff,
|
||||||
bool audioBinaural,
|
Real volume,
|
||||||
bool audioFlipChannels,
|
int spanLog2,
|
||||||
bool dsb,
|
bool audioBinaural,
|
||||||
bool audioMute,
|
bool audioFlipChannels,
|
||||||
bool agc,
|
bool dsb,
|
||||||
bool agcClamping,
|
bool audioMute,
|
||||||
int agcTimeLog2,
|
bool agc,
|
||||||
int agcPowerThreshold,
|
bool agcClamping,
|
||||||
int agcThresholdGate)
|
int agcTimeLog2,
|
||||||
{
|
int agcPowerThreshold,
|
||||||
return new MsgConfigureSSBDemodPrivate(
|
int agcThresholdGate)
|
||||||
Bandwidth,
|
{
|
||||||
LowCutoff,
|
return new MsgConfigureSSBDemodPrivate(
|
||||||
volume,
|
Bandwidth,
|
||||||
spanLog2,
|
LowCutoff,
|
||||||
audioBinaural,
|
volume,
|
||||||
audioFlipChannels,
|
spanLog2,
|
||||||
dsb,
|
audioBinaural,
|
||||||
audioMute,
|
audioFlipChannels,
|
||||||
agc,
|
dsb,
|
||||||
agcClamping,
|
audioMute,
|
||||||
agcTimeLog2,
|
agc,
|
||||||
agcPowerThreshold,
|
agcClamping,
|
||||||
agcThresholdGate);
|
agcTimeLog2,
|
||||||
}
|
agcPowerThreshold,
|
||||||
|
agcThresholdGate);
|
||||||
private:
|
}
|
||||||
Real m_Bandwidth;
|
|
||||||
Real m_LowCutoff;
|
private:
|
||||||
Real m_volume;
|
Real m_Bandwidth;
|
||||||
int m_spanLog2;
|
Real m_LowCutoff;
|
||||||
bool m_audioBinaural;
|
Real m_volume;
|
||||||
bool m_audioFlipChannels;
|
int m_spanLog2;
|
||||||
bool m_dsb;
|
bool m_audioBinaural;
|
||||||
bool m_audioMute;
|
bool m_audioFlipChannels;
|
||||||
bool m_agc;
|
bool m_dsb;
|
||||||
bool m_agcClamping;
|
bool m_audioMute;
|
||||||
int m_agcTimeLog2;
|
bool m_agc;
|
||||||
int m_agcPowerThreshold;
|
bool m_agcClamping;
|
||||||
int m_agcThresholdGate;
|
int m_agcTimeLog2;
|
||||||
|
int m_agcPowerThreshold;
|
||||||
MsgConfigureSSBDemodPrivate(Real Bandwidth,
|
int m_agcThresholdGate;
|
||||||
Real LowCutoff,
|
|
||||||
Real volume,
|
MsgConfigureSSBDemodPrivate(Real Bandwidth,
|
||||||
int spanLog2,
|
Real LowCutoff,
|
||||||
bool audioBinaural,
|
Real volume,
|
||||||
bool audioFlipChannels,
|
int spanLog2,
|
||||||
bool dsb,
|
bool audioBinaural,
|
||||||
bool audioMute,
|
bool audioFlipChannels,
|
||||||
bool agc,
|
bool dsb,
|
||||||
bool agcClamping,
|
bool audioMute,
|
||||||
int agcTimeLog2,
|
bool agc,
|
||||||
int agcPowerThreshold,
|
bool agcClamping,
|
||||||
int agcThresholdGate) :
|
int agcTimeLog2,
|
||||||
Message(),
|
int agcPowerThreshold,
|
||||||
m_Bandwidth(Bandwidth),
|
int agcThresholdGate) :
|
||||||
m_LowCutoff(LowCutoff),
|
Message(),
|
||||||
m_volume(volume),
|
m_Bandwidth(Bandwidth),
|
||||||
m_spanLog2(spanLog2),
|
m_LowCutoff(LowCutoff),
|
||||||
m_audioBinaural(audioBinaural),
|
m_volume(volume),
|
||||||
m_audioFlipChannels(audioFlipChannels),
|
m_spanLog2(spanLog2),
|
||||||
m_dsb(dsb),
|
m_audioBinaural(audioBinaural),
|
||||||
m_audioMute(audioMute),
|
m_audioFlipChannels(audioFlipChannels),
|
||||||
m_agc(agc),
|
m_dsb(dsb),
|
||||||
m_agcClamping(agcClamping),
|
m_audioMute(audioMute),
|
||||||
m_agcTimeLog2(agcTimeLog2),
|
m_agc(agc),
|
||||||
m_agcPowerThreshold(agcPowerThreshold),
|
m_agcClamping(agcClamping),
|
||||||
m_agcThresholdGate(agcThresholdGate)
|
m_agcTimeLog2(agcTimeLog2),
|
||||||
{ }
|
m_agcPowerThreshold(agcPowerThreshold),
|
||||||
};
|
m_agcThresholdGate(agcThresholdGate)
|
||||||
|
{ }
|
||||||
DeviceSourceAPI *m_deviceAPI;
|
};
|
||||||
ThreadedBasebandSampleSink* m_threadedChannelizer;
|
|
||||||
DownChannelizer* m_channelizer;
|
DeviceSourceAPI *m_deviceAPI;
|
||||||
SSBDemodSettings m_settings;
|
ThreadedBasebandSampleSink* m_threadedChannelizer;
|
||||||
|
DownChannelizer* m_channelizer;
|
||||||
Real m_Bandwidth;
|
SSBDemodSettings m_settings;
|
||||||
Real m_LowCutoff;
|
|
||||||
Real m_volume;
|
Real m_Bandwidth;
|
||||||
int m_spanLog2;
|
Real m_LowCutoff;
|
||||||
fftfilt::cmplx m_sum;
|
Real m_volume;
|
||||||
int m_undersampleCount;
|
int m_spanLog2;
|
||||||
int m_sampleRate;
|
fftfilt::cmplx m_sum;
|
||||||
int m_frequency;
|
int m_undersampleCount;
|
||||||
bool m_audioBinaual;
|
int m_sampleRate;
|
||||||
bool m_audioFlipChannels;
|
int m_frequency;
|
||||||
bool m_usb;
|
bool m_audioBinaual;
|
||||||
bool m_dsb;
|
bool m_audioFlipChannels;
|
||||||
bool m_audioMute;
|
bool m_usb;
|
||||||
double m_magsq;
|
bool m_dsb;
|
||||||
double m_magsqSum;
|
bool m_audioMute;
|
||||||
double m_magsqPeak;
|
double m_magsq;
|
||||||
int m_magsqCount;
|
double m_magsqSum;
|
||||||
MagAGC m_agc;
|
double m_magsqPeak;
|
||||||
bool m_agcActive;
|
int m_magsqCount;
|
||||||
bool m_agcClamping;
|
MagAGC m_agc;
|
||||||
int m_agcNbSamples; //!< number of audio (48 kHz) samples for AGC averaging
|
bool m_agcActive;
|
||||||
double m_agcPowerThreshold; //!< AGC power threshold (linear)
|
bool m_agcClamping;
|
||||||
int m_agcThresholdGate; //!< Gate length in number of samples befor threshold triggers
|
int m_agcNbSamples; //!< number of audio (48 kHz) samples for AGC averaging
|
||||||
bool m_audioActive; //!< True if an audio signal is produced (no AGC or AGC and above threshold)
|
double m_agcPowerThreshold; //!< AGC power threshold (linear)
|
||||||
|
int m_agcThresholdGate; //!< Gate length in number of samples befor threshold triggers
|
||||||
NCOF m_nco;
|
bool m_audioActive; //!< True if an audio signal is produced (no AGC or AGC and above threshold)
|
||||||
Interpolator m_interpolator;
|
|
||||||
Real m_sampleDistanceRemain;
|
NCOF m_nco;
|
||||||
fftfilt* SSBFilter;
|
Interpolator m_interpolator;
|
||||||
fftfilt* DSBFilter;
|
Real m_sampleDistanceRemain;
|
||||||
|
fftfilt* SSBFilter;
|
||||||
BasebandSampleSink* m_sampleSink;
|
fftfilt* DSBFilter;
|
||||||
SampleVector m_sampleBuffer;
|
|
||||||
|
BasebandSampleSink* m_sampleSink;
|
||||||
AudioVector m_audioBuffer;
|
SampleVector m_sampleBuffer;
|
||||||
uint m_audioBufferFill;
|
|
||||||
AudioFifo m_audioFifo;
|
AudioVector m_audioBuffer;
|
||||||
quint32 m_audioSampleRate;
|
uint m_audioBufferFill;
|
||||||
|
AudioFifo m_audioFifo;
|
||||||
QMutex m_settingsMutex;
|
quint32 m_audioSampleRate;
|
||||||
|
|
||||||
void applySettings(const SSBDemodSettings& settings, bool force = false);
|
QMutex m_settingsMutex;
|
||||||
};
|
|
||||||
|
void applySettings(const SSBDemodSettings& settings, bool force = false);
|
||||||
#endif // INCLUDE_SSBDEMOD_H
|
};
|
||||||
|
|
||||||
|
#endif // INCLUDE_SSBDEMOD_H
|
||||||
|
|
|
@ -17,8 +17,6 @@
|
||||||
#include "mainwindow.h"
|
#include "mainwindow.h"
|
||||||
#include "ssbdemod.h"
|
#include "ssbdemod.h"
|
||||||
|
|
||||||
const QString SSBDemodGUI::m_channelID = "de.maintech.sdrangelove.channel.ssb";
|
|
||||||
|
|
||||||
SSBDemodGUI* SSBDemodGUI::create(PluginAPI* pluginAPI, DeviceUISet *deviceUISet)
|
SSBDemodGUI* SSBDemodGUI::create(PluginAPI* pluginAPI, DeviceUISet *deviceUISet)
|
||||||
{
|
{
|
||||||
SSBDemodGUI* gui = new SSBDemodGUI(pluginAPI, deviceUISet);
|
SSBDemodGUI* gui = new SSBDemodGUI(pluginAPI, deviceUISet);
|
||||||
|
@ -253,7 +251,7 @@ SSBDemodGUI::SSBDemodGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, QWidget
|
||||||
|
|
||||||
connect(&m_channelMarker, SIGNAL(changed()), this, SLOT(viewChanged()));
|
connect(&m_channelMarker, SIGNAL(changed()), this, SLOT(viewChanged()));
|
||||||
|
|
||||||
m_deviceUISet->registerRxChannelInstance(m_channelID, this);
|
m_deviceUISet->registerRxChannelInstance(SSBDemod::m_channelID, this);
|
||||||
m_deviceUISet->addChannelMarker(&m_channelMarker);
|
m_deviceUISet->addChannelMarker(&m_channelMarker);
|
||||||
m_deviceUISet->addRollupWidget(this);
|
m_deviceUISet->addRollupWidget(this);
|
||||||
|
|
||||||
|
|
|
@ -37,8 +37,6 @@ public:
|
||||||
virtual MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; }
|
virtual MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; }
|
||||||
virtual bool handleMessage(const Message& message);
|
virtual bool handleMessage(const Message& message);
|
||||||
|
|
||||||
static const QString m_channelID;
|
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void viewChanged();
|
void viewChanged();
|
||||||
void on_deltaFrequency_changed(qint64 value);
|
void on_deltaFrequency_changed(qint64 value);
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
#include <QtPlugin>
|
#include <QtPlugin>
|
||||||
#include "plugin/pluginapi.h"
|
#include "plugin/pluginapi.h"
|
||||||
#include "ssbdemodgui.h"
|
#include "ssbdemodgui.h"
|
||||||
|
#include "ssbdemod.h"
|
||||||
|
|
||||||
const PluginDescriptor SSBPlugin::m_pluginDescriptor = {
|
const PluginDescriptor SSBPlugin::m_pluginDescriptor = {
|
||||||
QString("SSB Demodulator"),
|
QString("SSB Demodulator"),
|
||||||
|
@ -30,16 +31,27 @@ void SSBPlugin::initPlugin(PluginAPI* pluginAPI)
|
||||||
m_pluginAPI = pluginAPI;
|
m_pluginAPI = pluginAPI;
|
||||||
|
|
||||||
// register demodulator
|
// register demodulator
|
||||||
m_pluginAPI->registerRxChannel(SSBDemodGUI::m_channelID, this);
|
m_pluginAPI->registerRxChannel(SSBDemod::m_channelID, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
PluginInstanceGUI* SSBPlugin::createRxChannelGUI(const QString& channelName, DeviceUISet *deviceUISet)
|
PluginInstanceGUI* SSBPlugin::createRxChannelGUI(const QString& channelName, DeviceUISet *deviceUISet)
|
||||||
{
|
{
|
||||||
if(channelName == SSBDemodGUI::m_channelID)
|
if(channelName == SSBDemod::m_channelID)
|
||||||
{
|
{
|
||||||
SSBDemodGUI* gui = SSBDemodGUI::create(m_pluginAPI, deviceUISet);
|
SSBDemodGUI* gui = SSBDemodGUI::create(m_pluginAPI, deviceUISet);
|
||||||
return gui;
|
return gui;
|
||||||
} else {
|
} else {
|
||||||
return NULL;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BasebandSampleSink* SSBPlugin::createRxChannel(const QString& channelName, DeviceSourceAPI *deviceAPI)
|
||||||
|
{
|
||||||
|
if(channelName == SSBDemod::m_channelID)
|
||||||
|
{
|
||||||
|
SSBDemod* sink = new SSBDemod(deviceAPI);
|
||||||
|
return sink;
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
#include "plugin/plugininterface.h"
|
#include "plugin/plugininterface.h"
|
||||||
|
|
||||||
class DeviceUISet;
|
class DeviceUISet;
|
||||||
|
class BasebandSampleSink;
|
||||||
|
|
||||||
class SSBPlugin : public QObject, PluginInterface {
|
class SSBPlugin : public QObject, PluginInterface {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
@ -18,6 +19,7 @@ public:
|
||||||
void initPlugin(PluginAPI* pluginAPI);
|
void initPlugin(PluginAPI* pluginAPI);
|
||||||
|
|
||||||
PluginInstanceGUI* createRxChannelGUI(const QString& channelName, DeviceUISet *deviceUISet);
|
PluginInstanceGUI* createRxChannelGUI(const QString& channelName, DeviceUISet *deviceUISet);
|
||||||
|
BasebandSampleSink* createRxChannel(const QString& channelName, DeviceSourceAPI *deviceAPI);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static const PluginDescriptor m_pluginDescriptor;
|
static const PluginDescriptor m_pluginDescriptor;
|
||||||
|
|
|
@ -33,6 +33,8 @@
|
||||||
MESSAGE_CLASS_DEFINITION(WFMDemod::MsgConfigureWFMDemod, Message)
|
MESSAGE_CLASS_DEFINITION(WFMDemod::MsgConfigureWFMDemod, Message)
|
||||||
MESSAGE_CLASS_DEFINITION(WFMDemod::MsgConfigureChannelizer, Message)
|
MESSAGE_CLASS_DEFINITION(WFMDemod::MsgConfigureChannelizer, Message)
|
||||||
|
|
||||||
|
const QString WFMDemod::m_channelID = "de.maintech.sdrangelove.channel.wfm";
|
||||||
|
|
||||||
WFMDemod::WFMDemod(DeviceSourceAPI* deviceAPI) :
|
WFMDemod::WFMDemod(DeviceSourceAPI* deviceAPI) :
|
||||||
m_deviceAPI(deviceAPI),
|
m_deviceAPI(deviceAPI),
|
||||||
m_squelchOpen(false),
|
m_squelchOpen(false),
|
||||||
|
|
|
@ -109,6 +109,8 @@ public:
|
||||||
m_magsqCount = 0;
|
m_magsqCount = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const QString m_channelID;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
enum RateState {
|
enum RateState {
|
||||||
RSInitialFill,
|
RSInitialFill,
|
||||||
|
|
|
@ -18,8 +18,6 @@
|
||||||
|
|
||||||
#include "wfmdemod.h"
|
#include "wfmdemod.h"
|
||||||
|
|
||||||
const QString WFMDemodGUI::m_channelID = "de.maintech.sdrangelove.channel.wfm";
|
|
||||||
|
|
||||||
WFMDemodGUI* WFMDemodGUI::create(PluginAPI* pluginAPI, DeviceUISet *deviceUISet)
|
WFMDemodGUI* WFMDemodGUI::create(PluginAPI* pluginAPI, DeviceUISet *deviceUISet)
|
||||||
{
|
{
|
||||||
WFMDemodGUI* gui = new WFMDemodGUI(pluginAPI, deviceUISet);
|
WFMDemodGUI* gui = new WFMDemodGUI(pluginAPI, deviceUISet);
|
||||||
|
@ -187,7 +185,7 @@ WFMDemodGUI::WFMDemodGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, QWidget
|
||||||
|
|
||||||
connect(&m_channelMarker, SIGNAL(changed()), this, SLOT(channelMarkerChanged()));
|
connect(&m_channelMarker, SIGNAL(changed()), this, SLOT(channelMarkerChanged()));
|
||||||
|
|
||||||
m_deviceUISet->registerRxChannelInstance(m_channelID, this);
|
m_deviceUISet->registerRxChannelInstance(WFMDemod::m_channelID, this);
|
||||||
m_deviceUISet->addChannelMarker(&m_channelMarker);
|
m_deviceUISet->addChannelMarker(&m_channelMarker);
|
||||||
m_deviceUISet->addRollupWidget(this);
|
m_deviceUISet->addRollupWidget(this);
|
||||||
|
|
||||||
|
|
|
@ -36,8 +36,6 @@ public:
|
||||||
virtual MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; }
|
virtual MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; }
|
||||||
virtual bool handleMessage(const Message& message);
|
virtual bool handleMessage(const Message& message);
|
||||||
|
|
||||||
static const QString m_channelID;
|
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void channelMarkerChanged();
|
void channelMarkerChanged();
|
||||||
void on_deltaFrequency_changed(qint64 value);
|
void on_deltaFrequency_changed(qint64 value);
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
#include "plugin/pluginapi.h"
|
#include "plugin/pluginapi.h"
|
||||||
|
|
||||||
#include "wfmdemodgui.h"
|
#include "wfmdemodgui.h"
|
||||||
|
#include "wfmdemod.h"
|
||||||
|
|
||||||
const PluginDescriptor WFMPlugin::m_pluginDescriptor = {
|
const PluginDescriptor WFMPlugin::m_pluginDescriptor = {
|
||||||
QString("WFM Demodulator"),
|
QString("WFM Demodulator"),
|
||||||
|
@ -30,16 +31,27 @@ void WFMPlugin::initPlugin(PluginAPI* pluginAPI)
|
||||||
m_pluginAPI = pluginAPI;
|
m_pluginAPI = pluginAPI;
|
||||||
|
|
||||||
// register WFM demodulator
|
// register WFM demodulator
|
||||||
m_pluginAPI->registerRxChannel(WFMDemodGUI::m_channelID, this);
|
m_pluginAPI->registerRxChannel(WFMDemod::m_channelID, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
PluginInstanceGUI* WFMPlugin::createRxChannelGUI(const QString& channelName, DeviceUISet *deviceUISet)
|
PluginInstanceGUI* WFMPlugin::createRxChannelGUI(const QString& channelName, DeviceUISet *deviceUISet)
|
||||||
{
|
{
|
||||||
if(channelName == WFMDemodGUI::m_channelID)
|
if(channelName == WFMDemod::m_channelID)
|
||||||
{
|
{
|
||||||
WFMDemodGUI* gui = WFMDemodGUI::create(m_pluginAPI, deviceUISet);
|
WFMDemodGUI* gui = WFMDemodGUI::create(m_pluginAPI, deviceUISet);
|
||||||
return gui;
|
return gui;
|
||||||
} else {
|
} else {
|
||||||
return NULL;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BasebandSampleSink* WFMPlugin::createRxChannel(const QString& channelName, DeviceSourceAPI *deviceAPI)
|
||||||
|
{
|
||||||
|
if(channelName == WFMDemod::m_channelID)
|
||||||
|
{
|
||||||
|
WFMDemod* sink = new WFMDemod(deviceAPI);
|
||||||
|
return sink;
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
#include "plugin/plugininterface.h"
|
#include "plugin/plugininterface.h"
|
||||||
|
|
||||||
class DeviceUISet;
|
class DeviceUISet;
|
||||||
|
class BasebandSampleSink;
|
||||||
|
|
||||||
class WFMPlugin : public QObject, PluginInterface {
|
class WFMPlugin : public QObject, PluginInterface {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
@ -18,6 +19,7 @@ public:
|
||||||
void initPlugin(PluginAPI* pluginAPI);
|
void initPlugin(PluginAPI* pluginAPI);
|
||||||
|
|
||||||
PluginInstanceGUI* createRxChannelGUI(const QString& channelName, DeviceUISet *deviceUISet);
|
PluginInstanceGUI* createRxChannelGUI(const QString& channelName, DeviceUISet *deviceUISet);
|
||||||
|
BasebandSampleSink* createRxChannel(const QString& channelName, DeviceSourceAPI *deviceAPI);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static const PluginDescriptor m_pluginDescriptor;
|
static const PluginDescriptor m_pluginDescriptor;
|
||||||
|
|
|
@ -30,6 +30,8 @@ MESSAGE_CLASS_DEFINITION(TCPSrc::MsgConfigureChannelizer, Message)
|
||||||
MESSAGE_CLASS_DEFINITION(TCPSrc::MsgTCPSrcConnection, Message)
|
MESSAGE_CLASS_DEFINITION(TCPSrc::MsgTCPSrcConnection, Message)
|
||||||
MESSAGE_CLASS_DEFINITION(TCPSrc::MsgTCPSrcSpectrum, Message)
|
MESSAGE_CLASS_DEFINITION(TCPSrc::MsgTCPSrcSpectrum, Message)
|
||||||
|
|
||||||
|
const QString TCPSrc::m_channelID = "sdrangel.channel.tcpsrc";
|
||||||
|
|
||||||
TCPSrc::TCPSrc(DeviceSourceAPI* deviceAPI) :
|
TCPSrc::TCPSrc(DeviceSourceAPI* deviceAPI) :
|
||||||
m_deviceAPI(deviceAPI),
|
m_deviceAPI(deviceAPI),
|
||||||
m_settingsMutex(QMutex::Recursive)
|
m_settingsMutex(QMutex::Recursive)
|
||||||
|
|
|
@ -113,6 +113,8 @@ public:
|
||||||
virtual void stop();
|
virtual void stop();
|
||||||
virtual bool handleMessage(const Message& cmd);
|
virtual bool handleMessage(const Message& cmd);
|
||||||
|
|
||||||
|
static const QString m_channelID;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
class MsgTCPSrcSpectrum : public Message {
|
class MsgTCPSrcSpectrum : public Message {
|
||||||
MESSAGE_CLASS_DECLARATION
|
MESSAGE_CLASS_DECLARATION
|
||||||
|
|
|
@ -12,8 +12,6 @@
|
||||||
#include "mainwindow.h"
|
#include "mainwindow.h"
|
||||||
#include "tcpsrc.h"
|
#include "tcpsrc.h"
|
||||||
|
|
||||||
const QString TCPSrcGUI::m_channelID = "sdrangel.channel.tcpsrc";
|
|
||||||
|
|
||||||
TCPSrcGUI* TCPSrcGUI::create(PluginAPI* pluginAPI, DeviceUISet *deviceUISet)
|
TCPSrcGUI* TCPSrcGUI::create(PluginAPI* pluginAPI, DeviceUISet *deviceUISet)
|
||||||
{
|
{
|
||||||
TCPSrcGUI* gui = new TCPSrcGUI(pluginAPI, deviceUISet);
|
TCPSrcGUI* gui = new TCPSrcGUI(pluginAPI, deviceUISet);
|
||||||
|
@ -165,7 +163,7 @@ TCPSrcGUI::TCPSrcGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, QWidget* pa
|
||||||
|
|
||||||
connect(&m_channelMarker, SIGNAL(changed()), this, SLOT(channelMarkerChanged()));
|
connect(&m_channelMarker, SIGNAL(changed()), this, SLOT(channelMarkerChanged()));
|
||||||
|
|
||||||
m_deviceUISet->registerRxChannelInstance(m_channelID, this);
|
m_deviceUISet->registerRxChannelInstance(TCPSrc::m_channelID, this);
|
||||||
m_deviceUISet->addChannelMarker(&m_channelMarker);
|
m_deviceUISet->addChannelMarker(&m_channelMarker);
|
||||||
m_deviceUISet->addRollupWidget(this);
|
m_deviceUISet->addRollupWidget(this);
|
||||||
|
|
||||||
|
|
|
@ -39,8 +39,6 @@ public:
|
||||||
virtual MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; }
|
virtual MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; }
|
||||||
virtual bool handleMessage(const Message& message);
|
virtual bool handleMessage(const Message& message);
|
||||||
|
|
||||||
static const QString m_channelID;
|
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void channelMarkerChanged();
|
void channelMarkerChanged();
|
||||||
void on_deltaFrequency_changed(qint64 value);
|
void on_deltaFrequency_changed(qint64 value);
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
#include "plugin/pluginapi.h"
|
#include "plugin/pluginapi.h"
|
||||||
|
|
||||||
#include "tcpsrcgui.h"
|
#include "tcpsrcgui.h"
|
||||||
|
#include "tcpsrc.h"
|
||||||
|
|
||||||
const PluginDescriptor TCPSrcPlugin::m_pluginDescriptor = {
|
const PluginDescriptor TCPSrcPlugin::m_pluginDescriptor = {
|
||||||
QString("TCP Channel Source"),
|
QString("TCP Channel Source"),
|
||||||
|
@ -30,18 +31,29 @@ void TCPSrcPlugin::initPlugin(PluginAPI* pluginAPI)
|
||||||
m_pluginAPI = pluginAPI;
|
m_pluginAPI = pluginAPI;
|
||||||
|
|
||||||
// register TCP Channel Source
|
// register TCP Channel Source
|
||||||
m_pluginAPI->registerRxChannel(TCPSrcGUI::m_channelID, this);
|
m_pluginAPI->registerRxChannel(TCPSrc::m_channelID, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
PluginInstanceGUI* TCPSrcPlugin::createRxChannelGUI(const QString& channelName, DeviceUISet *deviceUISet)
|
PluginInstanceGUI* TCPSrcPlugin::createRxChannelGUI(const QString& channelName, DeviceUISet *deviceUISet)
|
||||||
{
|
{
|
||||||
if(channelName == TCPSrcGUI::m_channelID)
|
if(channelName == TCPSrc::m_channelID)
|
||||||
{
|
{
|
||||||
TCPSrcGUI* gui = TCPSrcGUI::create(m_pluginAPI, deviceUISet);
|
TCPSrcGUI* gui = TCPSrcGUI::create(m_pluginAPI, deviceUISet);
|
||||||
// deviceAPI->registerChannelInstance("sdrangel.channel.tcpsrc", gui);
|
// deviceAPI->registerChannelInstance("sdrangel.channel.tcpsrc", gui);
|
||||||
// m_pluginAPI->addChannelRollup(gui);
|
// m_pluginAPI->addChannelRollup(gui);
|
||||||
return gui;
|
return gui;
|
||||||
} else {
|
} else {
|
||||||
return NULL;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BasebandSampleSink* TCPSrcPlugin::createRxChannel(const QString& channelName, DeviceSourceAPI *deviceAPI)
|
||||||
|
{
|
||||||
|
if(channelName == TCPSrc::m_channelID)
|
||||||
|
{
|
||||||
|
TCPSrc* sink = new TCPSrc(deviceAPI);
|
||||||
|
return sink;
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
#include "plugin/plugininterface.h"
|
#include "plugin/plugininterface.h"
|
||||||
|
|
||||||
class DeviceUISet;
|
class DeviceUISet;
|
||||||
|
class BasebandSampleSink;
|
||||||
|
|
||||||
class TCPSrcPlugin : public QObject, PluginInterface {
|
class TCPSrcPlugin : public QObject, PluginInterface {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
@ -18,6 +19,7 @@ public:
|
||||||
void initPlugin(PluginAPI* pluginAPI);
|
void initPlugin(PluginAPI* pluginAPI);
|
||||||
|
|
||||||
PluginInstanceGUI* createRxChannelGUI(const QString& channelName, DeviceUISet *deviceUISet);
|
PluginInstanceGUI* createRxChannelGUI(const QString& channelName, DeviceUISet *deviceUISet);
|
||||||
|
BasebandSampleSink* createRxChannel(const QString& channelName, DeviceSourceAPI *deviceAPI);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static const PluginDescriptor m_pluginDescriptor;
|
static const PluginDescriptor m_pluginDescriptor;
|
||||||
|
|
|
@ -33,6 +33,8 @@ MESSAGE_CLASS_DEFINITION(UDPSrc::MsgConfigureUDPSrc, Message)
|
||||||
MESSAGE_CLASS_DEFINITION(UDPSrc::MsgConfigureChannelizer, Message)
|
MESSAGE_CLASS_DEFINITION(UDPSrc::MsgConfigureChannelizer, Message)
|
||||||
MESSAGE_CLASS_DEFINITION(UDPSrc::MsgUDPSrcSpectrum, Message)
|
MESSAGE_CLASS_DEFINITION(UDPSrc::MsgUDPSrcSpectrum, Message)
|
||||||
|
|
||||||
|
const QString UDPSrc::m_channelID = "sdrangel.channel.udpsrc";
|
||||||
|
|
||||||
UDPSrc::UDPSrc(DeviceSourceAPI *deviceAPI) :
|
UDPSrc::UDPSrc(DeviceSourceAPI *deviceAPI) :
|
||||||
m_deviceAPI(deviceAPI),
|
m_deviceAPI(deviceAPI),
|
||||||
m_outMovingAverage(480, 1e-10),
|
m_outMovingAverage(480, 1e-10),
|
||||||
|
|
|
@ -104,6 +104,7 @@ public:
|
||||||
virtual void stop();
|
virtual void stop();
|
||||||
virtual bool handleMessage(const Message& cmd);
|
virtual bool handleMessage(const Message& cmd);
|
||||||
|
|
||||||
|
static const QString m_channelID;
|
||||||
static const int udpBlockSize = 512; // UDP block size in number of bytes
|
static const int udpBlockSize = 512; // UDP block size in number of bytes
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
|
|
|
@ -30,8 +30,6 @@
|
||||||
|
|
||||||
#include "udpsrc.h"
|
#include "udpsrc.h"
|
||||||
|
|
||||||
const QString UDPSrcGUI::m_channelID = "sdrangel.channel.udpsrc";
|
|
||||||
|
|
||||||
UDPSrcGUI* UDPSrcGUI::create(PluginAPI* pluginAPI, DeviceUISet *deviceUISet)
|
UDPSrcGUI* UDPSrcGUI::create(PluginAPI* pluginAPI, DeviceUISet *deviceUISet)
|
||||||
{
|
{
|
||||||
UDPSrcGUI* gui = new UDPSrcGUI(pluginAPI, deviceUISet);
|
UDPSrcGUI* gui = new UDPSrcGUI(pluginAPI, deviceUISet);
|
||||||
|
@ -185,7 +183,7 @@ UDPSrcGUI::UDPSrcGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, QWidget* pa
|
||||||
|
|
||||||
connect(&m_channelMarker, SIGNAL(changed()), this, SLOT(channelMarkerChanged()));
|
connect(&m_channelMarker, SIGNAL(changed()), this, SLOT(channelMarkerChanged()));
|
||||||
|
|
||||||
m_deviceUISet->registerRxChannelInstance(m_channelID, this);
|
m_deviceUISet->registerRxChannelInstance(UDPSrc::m_channelID, this);
|
||||||
m_deviceUISet->addChannelMarker(&m_channelMarker);
|
m_deviceUISet->addChannelMarker(&m_channelMarker);
|
||||||
m_deviceUISet->addRollupWidget(this);
|
m_deviceUISet->addRollupWidget(this);
|
||||||
|
|
||||||
|
|
|
@ -55,8 +55,6 @@ public:
|
||||||
virtual MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; }
|
virtual MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; }
|
||||||
virtual bool handleMessage(const Message& message);
|
virtual bool handleMessage(const Message& message);
|
||||||
|
|
||||||
static const QString m_channelID;
|
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void channelMarkerChanged();
|
void channelMarkerChanged();
|
||||||
void on_deltaFrequency_changed(qint64 value);
|
void on_deltaFrequency_changed(qint64 value);
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
#include "plugin/pluginapi.h"
|
#include "plugin/pluginapi.h"
|
||||||
|
|
||||||
#include "udpsrcgui.h"
|
#include "udpsrcgui.h"
|
||||||
|
#include "udpsrc.h"
|
||||||
|
|
||||||
const PluginDescriptor UDPSrcPlugin::m_pluginDescriptor = {
|
const PluginDescriptor UDPSrcPlugin::m_pluginDescriptor = {
|
||||||
QString("UDP Channel Source"),
|
QString("UDP Channel Source"),
|
||||||
|
@ -47,12 +48,12 @@ void UDPSrcPlugin::initPlugin(PluginAPI* pluginAPI)
|
||||||
m_pluginAPI = pluginAPI;
|
m_pluginAPI = pluginAPI;
|
||||||
|
|
||||||
// register TCP Channel Source
|
// register TCP Channel Source
|
||||||
m_pluginAPI->registerRxChannel(UDPSrcGUI::m_channelID, this);
|
m_pluginAPI->registerRxChannel(UDPSrc::m_channelID, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
PluginInstanceGUI* UDPSrcPlugin::createRxChannelGUI(const QString& channelName, DeviceUISet *deviceUISet)
|
PluginInstanceGUI* UDPSrcPlugin::createRxChannelGUI(const QString& channelName, DeviceUISet *deviceUISet)
|
||||||
{
|
{
|
||||||
if(channelName == UDPSrcGUI::m_channelID)
|
if(channelName == UDPSrc::m_channelID)
|
||||||
{
|
{
|
||||||
UDPSrcGUI* gui = UDPSrcGUI::create(m_pluginAPI, deviceUISet);
|
UDPSrcGUI* gui = UDPSrcGUI::create(m_pluginAPI, deviceUISet);
|
||||||
// deviceAPI->registerChannelInstance("sdrangel.channel.udpsrc", gui);
|
// deviceAPI->registerChannelInstance("sdrangel.channel.udpsrc", gui);
|
||||||
|
@ -62,3 +63,14 @@ PluginInstanceGUI* UDPSrcPlugin::createRxChannelGUI(const QString& channelName,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BasebandSampleSink* UDPSrcPlugin::createRxChannel(const QString& channelName, DeviceSourceAPI *deviceAPI)
|
||||||
|
{
|
||||||
|
if(channelName == UDPSrc::m_channelID)
|
||||||
|
{
|
||||||
|
UDPSrc* sink = new UDPSrc(deviceAPI);
|
||||||
|
return sink;
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -22,6 +22,7 @@
|
||||||
#include "plugin/plugininterface.h"
|
#include "plugin/plugininterface.h"
|
||||||
|
|
||||||
class DeviceUISet;
|
class DeviceUISet;
|
||||||
|
class BasebandSampleSink;
|
||||||
|
|
||||||
class UDPSrcPlugin : public QObject, PluginInterface {
|
class UDPSrcPlugin : public QObject, PluginInterface {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
@ -35,6 +36,7 @@ public:
|
||||||
void initPlugin(PluginAPI* pluginAPI);
|
void initPlugin(PluginAPI* pluginAPI);
|
||||||
|
|
||||||
PluginInstanceGUI* createRxChannelGUI(const QString& channelName, DeviceUISet *deviceUISet);
|
PluginInstanceGUI* createRxChannelGUI(const QString& channelName, DeviceUISet *deviceUISet);
|
||||||
|
BasebandSampleSink* createRxChannel(const QString& channelName, DeviceSourceAPI *deviceAPI);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static const PluginDescriptor m_pluginDescriptor;
|
static const PluginDescriptor m_pluginDescriptor;
|
||||||
|
|
Loading…
Reference in New Issue