1
0
mirror of https://github.com/f4exb/sdrangel.git synced 2024-11-26 17:58:43 -05:00

DATV demod: fixed compilation warnings

This commit is contained in:
f4exb 2018-02-25 00:07:08 +01:00
parent 2e5cfcafee
commit 3354c774fc
11 changed files with 4361 additions and 3427 deletions

View File

@ -16,9 +16,9 @@ if(LIBDSDCC_FOUND AND LIBMBE_FOUND)
add_subdirectory(demoddsd)
endif(LIBDSDCC_FOUND AND LIBMBE_FOUND)
if (NOT RX_SAMPLE_24BIT)
#if (NOT RX_SAMPLE_24BIT)
add_subdirectory(demoddatv)
endif()
#endif()
if (BUILD_DEBIAN)
add_subdirectory(demoddsd)

View File

@ -24,8 +24,6 @@ set(datv_FORMS
datvdemodgui.ui
)
set (CMAKE_CXX_FLAGS "-Wno-unused-variable -Wno-deprecated-declarations")
include_directories(
.
${CMAKE_CURRENT_BINARY_DIR}

View File

@ -27,72 +27,82 @@
namespace leansdr
{
static const int DEFAULT_GUI_DECIMATION = 64;
static const int DEFAULT_GUI_DECIMATION = 64;
template<typename T> struct datvconstellation : runnable
template<typename T> struct datvconstellation: runnable
{
T xymin;
T xymax;
unsigned long decimation;
unsigned long pixels_per_frame;
cstln_lut<256> **cstln; // Optional ptr to optional constellation
pipereader<complex<T> > in;
unsigned long phase;
DATVScreen *m_objDATVScreen;
datvconstellation(
scheduler *sch,
pipebuf<complex<T> > &_in,
T _xymin,
T _xymax,
const char *_name = 0,
DATVScreen * objDATVScreen = 0) :
runnable(sch, _name ? _name : _in.name),
xymin(_xymin),
xymax(_xymax),
decimation(DEFAULT_GUI_DECIMATION),
pixels_per_frame(1024),
cstln(0),
in(_in),
phase(0),
m_objDATVScreen(objDATVScreen)
{
T xymin, xymax;
unsigned long decimation;
unsigned long pixels_per_frame;
cstln_lut<256> **cstln; // Optional ptr to optional constellation
DATVScreen *m_objDATVScreen;
}
datvconstellation(scheduler *sch, pipebuf< complex<T> > &_in, T _xymin, T _xymax, const char *_name=NULL, DATVScreen * objDATVScreen=NULL) :
runnable(sch, _name?_name:_in.name),
xymin(_xymin),
xymax(_xymax),
decimation(DEFAULT_GUI_DECIMATION),
pixels_per_frame(1024),
cstln(NULL),
in(_in),
phase(0),
m_objDATVScreen(objDATVScreen)
{
}
void run()
{
void run()
{
//Symbols
while ( in.readable() >= pixels_per_frame )
while (in.readable() >= pixels_per_frame)
{
if ( ! phase )
if (!phase)
{
m_objDATVScreen->resetImage();
complex<T> *p = in.rd(), *pend = p+pixels_per_frame;
complex<T> *p = in.rd(), *pend = p + pixels_per_frame;
for ( ; p<pend; ++p )
for (; p < pend; ++p)
{
if(m_objDATVScreen!=NULL)
if (m_objDATVScreen != NULL)
{
m_objDATVScreen->selectRow(256*(p->re-xymin)/(xymax-xymin));
m_objDATVScreen->setDataColor(256- 256*((p->im-xymin)/(xymax-xymin)),255,0,255);
m_objDATVScreen->selectRow(
256 * (p->re - xymin) / (xymax - xymin));
m_objDATVScreen->setDataColor(
256 - 256 * ((p->im - xymin) / (xymax - xymin)),
255, 0, 255);
}
}
if ( cstln && (*cstln) )
if (cstln && (*cstln))
{
// Plot constellation points
// Plot constellation points
for ( int i=0; i<(*cstln)->nsymbols; ++i )
{
complex<signed char> *p = &(*cstln)->symbols[i];
int x = 256*(p->re-xymin)/(xymax-xymin);
int y = 256 - 256*(p->im-xymin)/(xymax-xymin);
for ( int d=-4; d<=4; ++d )
for (int i = 0; i < (*cstln)->nsymbols; ++i)
{
m_objDATVScreen->selectRow(x+d);
m_objDATVScreen->setDataColor(y,5,250,250);
m_objDATVScreen->selectRow(x);
m_objDATVScreen->setDataColor(y+d,5,250,250);
complex<signed char> *p = &(*cstln)->symbols[i];
int x = 256 * (p->re - xymin) / (xymax - xymin);
int y = 256 - 256 * (p->im - xymin) / (xymax - xymin);
for (int d = -4; d <= 4; ++d)
{
m_objDATVScreen->selectRow(x + d);
m_objDATVScreen->setDataColor(y, 5, 250, 250);
m_objDATVScreen->selectRow(x);
m_objDATVScreen->setDataColor(y + d, 5, 250, 250);
}
}
}
}
m_objDATVScreen->renderImage(NULL);
@ -101,27 +111,25 @@ namespace leansdr
in.read(pixels_per_frame);
if ( ++phase >= decimation )
if (++phase >= decimation)
{
phase = 0;
}
}
}
}
}
//private:
pipereader< complex<T> > in;
unsigned long phase;
//gfx g;
//private:
//gfx g;
void draw_begin()
{
void draw_begin()
{
//g.clear();
//g.setfg(0, 255, 0);
//g.line(g.w/2,0, g.w/2, g.h);
//g.line(0,g.h/2, g.w,g.h/2);
}
}
};
};
}

View File

@ -38,21 +38,22 @@ MESSAGE_CLASS_DEFINITION(DATVDemod::MsgConfigureChannelizer, Message)
DATVDemod::DATVDemod(DeviceSourceAPI *deviceAPI) :
ChannelSinkAPI(m_channelIdURI),
m_deviceAPI(deviceAPI),
m_objSettingsMutex(QMutex::NonRecursive),
m_objRegisteredDATVScreen(NULL),
m_objVideoStream(NULL),
m_objRegisteredVideoRender(NULL),
m_objRenderThread(NULL),
m_enmModulation(BPSK /*DATV_FM1*/),
m_blnNeedConfigUpdate(false),
m_blnRenderingVideo(false)
m_deviceAPI(deviceAPI),
m_objRegisteredDATVScreen(NULL),
m_objRegisteredVideoRender(NULL),
m_objVideoStream(NULL),
m_objRenderThread(NULL),
m_blnRenderingVideo(false),
m_enmModulation(BPSK /*DATV_FM1*/),
m_objSettingsMutex(QMutex::NonRecursive)
{
setObjectName("DATVDemod");
qDebug("DATVDemod::DATVDemod: sizeof FixReal: %lu: SDR_RX_SAMP_SZ: %u", sizeof(FixReal), (unsigned int) SDR_RX_SAMP_SZ);
//*************** DATV PARAMETERS ***************
m_blnInitialized=false;
CleanUpDATVFramework(false);
CleanUpDATVFramework();
m_objVideoStream = new DATVideostream();
@ -102,6 +103,7 @@ DATVDemod::~DATVDemod()
bool DATVDemod::SetDATVScreen(DATVScreen *objScreen)
{
m_objRegisteredDATVScreen = objScreen;
return true;
}
DATVideostream * DATVDemod::SetVideoRender(DATVideoRender *objScreen)
@ -240,185 +242,185 @@ void DATVDemod::InitDATVParameters(int intMsps,
m_blnInitialized=true;
}
void DATVDemod::CleanUpDATVFramework(bool blnRelease)
void DATVDemod::CleanUpDATVFramework()
{
//if(blnRelease==true)
if(false)
{
if(m_objScheduler!=NULL)
{
m_objScheduler->shutdown();
delete m_objScheduler;
}
// if (false)
// {
// if(m_objScheduler!=NULL)
// {
// m_objScheduler->shutdown();
// delete m_objScheduler;
// }
//
// // INPUT
// if(p_rawiq!=NULL) delete p_rawiq;
// if(p_rawiq_writer!=NULL) delete p_rawiq_writer;
// if(p_preprocessed!=NULL) delete p_preprocessed;
//
// // NOTCH FILTER
// if(r_auto_notch!=NULL) delete r_auto_notch;
// if(p_autonotched!=NULL) delete p_autonotched;
//
// // FREQUENCY CORRECTION : DEROTATOR
// if(p_derot!=NULL) delete p_derot;
// if(r_derot!=NULL) delete r_derot;
//
// // CNR ESTIMATION
// if(p_cnr!=NULL) delete p_cnr;
// if(r_cnr!=NULL) delete r_cnr;
//
// //FILTERING
// if(r_resample!=NULL) delete r_resample;
// if(p_resampled!=NULL) delete p_resampled;
// if(coeffs!=NULL) delete coeffs;
//
// // OUTPUT PREPROCESSED DATA
// if(sampler!=NULL) delete sampler;
// if(coeffs_sampler!=NULL) delete coeffs_sampler;
// if(p_symbols!=NULL) delete p_symbols;
// if(p_freq!=NULL) delete p_freq;
// if(p_ss!=NULL) delete p_ss;
// if(p_mer!=NULL) delete p_mer;
// if(p_sampled!=NULL) delete p_sampled;
//
// //DECIMATION
// if(p_decimated!=NULL) delete p_decimated;
// if(p_decim!=NULL) delete p_decim;
// if(r_ppout!=NULL) delete r_ppout;
//
// //GENERIC CONSTELLATION RECEIVER
// if(m_objDemodulator!=NULL) delete m_objDemodulator;
//
// //DECONVOLUTION AND SYNCHRONIZATION
// if(p_bytes!=NULL) delete p_bytes;
// if(r_deconv!=NULL) delete r_deconv;
// if(r!=NULL) delete r;
// if(p_descrambled!=NULL) delete p_descrambled;
// if(p_frames!=NULL) delete p_frames;
// if(r_etr192_descrambler!=NULL) delete r_etr192_descrambler;
// if(r_sync!=NULL) delete r_sync;
// if(p_mpegbytes!=NULL) delete p_mpegbytes;
// if(p_lock!=NULL) delete p_lock;
// if(p_locktime!=NULL) delete p_locktime;
// if(r_sync_mpeg!=NULL) delete r_sync_mpeg;
//
//
// // DEINTERLEAVING
// if(p_rspackets!=NULL) delete p_rspackets;
// if(r_deinter!=NULL) delete r_deinter;
// if(p_vbitcount!=NULL) delete p_vbitcount;
// if(p_verrcount!=NULL) delete p_verrcount;
// if(p_rtspackets!=NULL) delete p_rtspackets;
// if(r_rsdec!=NULL) delete r_rsdec;
//
// //BER ESTIMATION
// if(p_vber!=NULL) delete p_vber;
// if(r_vber!=NULL) delete r_vber;
//
// // DERANDOMIZATION
// if(p_tspackets!=NULL) delete p_tspackets;
// if(r_derand!=NULL) delete r_derand;
//
//
// //OUTPUT : To remove
// if(r_stdout!=NULL) delete r_stdout;
// if(r_videoplayer!=NULL) delete r_videoplayer;
//
// //CONSTELLATION
// if(r_scope_symbols!=NULL) delete r_scope_symbols;
//
// }
// INPUT
if(p_rawiq!=NULL) delete p_rawiq;
if(p_rawiq_writer!=NULL) delete p_rawiq_writer;
if(p_preprocessed!=NULL) delete p_preprocessed;
// NOTCH FILTER
if(r_auto_notch!=NULL) delete r_auto_notch;
if(p_autonotched!=NULL) delete p_autonotched;
// FREQUENCY CORRECTION : DEROTATOR
if(p_derot!=NULL) delete p_derot;
if(r_derot!=NULL) delete r_derot;
// CNR ESTIMATION
if(p_cnr!=NULL) delete p_cnr;
if(r_cnr!=NULL) delete r_cnr;
//FILTERING
if(r_resample!=NULL) delete r_resample;
if(p_resampled!=NULL) delete p_resampled;
if(coeffs!=NULL) delete coeffs;
// OUTPUT PREPROCESSED DATA
if(sampler!=NULL) delete sampler;
if(coeffs_sampler!=NULL) delete coeffs_sampler;
if(p_symbols!=NULL) delete p_symbols;
if(p_freq!=NULL) delete p_freq;
if(p_ss!=NULL) delete p_ss;
if(p_mer!=NULL) delete p_mer;
if(p_sampled!=NULL) delete p_sampled;
//DECIMATION
if(p_decimated!=NULL) delete p_decimated;
if(p_decim!=NULL) delete p_decim;
if(r_ppout!=NULL) delete r_ppout;
//GENERIC CONSTELLATION RECEIVER
if(m_objDemodulator!=NULL) delete m_objDemodulator;
//DECONVOLUTION AND SYNCHRONIZATION
if(p_bytes!=NULL) delete p_bytes;
if(r_deconv!=NULL) delete r_deconv;
if(r!=NULL) delete r;
if(p_descrambled!=NULL) delete p_descrambled;
if(p_frames!=NULL) delete p_frames;
if(r_etr192_descrambler!=NULL) delete r_etr192_descrambler;
if(r_sync!=NULL) delete r_sync;
if(p_mpegbytes!=NULL) delete p_mpegbytes;
if(p_lock!=NULL) delete p_lock;
if(p_locktime!=NULL) delete p_locktime;
if(r_sync_mpeg!=NULL) delete r_sync_mpeg;
// DEINTERLEAVING
if(p_rspackets!=NULL) delete p_rspackets;
if(r_deinter!=NULL) delete r_deinter;
if(p_vbitcount!=NULL) delete p_vbitcount;
if(p_verrcount!=NULL) delete p_verrcount;
if(p_rtspackets!=NULL) delete p_rtspackets;
if(r_rsdec!=NULL) delete r_rsdec;
//BER ESTIMATION
if(p_vber!=NULL) delete p_vber;
if(r_vber!=NULL) delete r_vber;
// DERANDOMIZATION
if(p_tspackets!=NULL) delete p_tspackets;
if(r_derand!=NULL) delete r_derand;
//OUTPUT : To remove
if(r_stdout!=NULL) delete r_stdout;
if(r_videoplayer!=NULL) delete r_videoplayer;
//CONSTELLATION
if(r_scope_symbols!=NULL) delete r_scope_symbols;
}
m_objScheduler=NULL;
m_objScheduler = 0;
// INPUT
p_rawiq = NULL;
p_rawiq_writer = NULL;
p_rawiq = 0;
p_rawiq_writer = 0;
p_preprocessed = NULL;
p_preprocessed = 0;
// NOTCH FILTER
r_auto_notch = NULL;
p_autonotched = NULL;
r_auto_notch = 0;
p_autonotched = 0;
// FREQUENCY CORRECTION : DEROTATOR
p_derot = NULL;
r_derot=NULL;
p_derot = 0;
r_derot = 0;
// CNR ESTIMATION
p_cnr = NULL;
r_cnr = NULL;
p_cnr = 0;
r_cnr = 0;
//FILTERING
r_resample = NULL;
p_resampled = NULL;
coeffs = NULL;
ncoeffs=0;
r_resample = 0;
p_resampled = 0;
coeffs = 0;
ncoeffs = 0;
// OUTPUT PREPROCESSED DATA
sampler = NULL;
coeffs_sampler=NULL;
ncoeffs_sampler=0;
sampler = 0;
coeffs_sampler = 0;
ncoeffs_sampler = 0;
p_symbols = NULL;
p_freq = NULL;
p_ss = NULL;
p_mer = NULL;
p_sampled = NULL;
p_symbols = 0;
p_freq = 0;
p_ss = 0;
p_mer = 0;
p_sampled = 0;
//DECIMATION
p_decimated = NULL;
p_decim = NULL;
r_ppout = NULL;
p_decimated = 0;
p_decim = 0;
r_ppout = 0;
//GENERIC CONSTELLATION RECEIVER
m_objDemodulator = NULL;
m_objDemodulator = 0;
//DECONVOLUTION AND SYNCHRONIZATION
p_bytes=NULL;
r_deconv=NULL;
r = NULL;
p_bytes = 0;
r_deconv = 0;
r = 0;
p_descrambled = NULL;
p_frames = NULL;
r_etr192_descrambler = NULL;
r_sync = NULL;
p_descrambled = 0;
p_frames = 0;
r_etr192_descrambler = 0;
r_sync = 0;
p_mpegbytes = NULL;
p_lock = NULL;
p_locktime = NULL;
r_sync_mpeg = NULL;
p_mpegbytes = 0;
p_lock = 0;
p_locktime = 0;
r_sync_mpeg = 0;
// DEINTERLEAVING
p_rspackets = NULL;
r_deinter = NULL;
p_rspackets = 0;
r_deinter = 0;
p_vbitcount = NULL;
p_verrcount = NULL;
p_rtspackets = NULL;
r_rsdec = NULL;
p_vbitcount = 0;
p_verrcount = 0;
p_rtspackets = 0;
r_rsdec = 0;
//BER ESTIMATION
p_vber = NULL;
r_vber = NULL;
p_vber = 0;
r_vber = 0;
// DERANDOMIZATION
p_tspackets = NULL;
r_derand = NULL;
p_tspackets = 0;
r_derand = 0;
//OUTPUT : To remove
r_stdout = NULL;
r_videoplayer = NULL;
r_stdout = 0;
r_videoplayer = 0;
//CONSTELLATION
r_scope_symbols = NULL;
r_scope_symbols = 0;
}
void DATVDemod::InitDATVFramework()
@ -516,7 +518,7 @@ void DATVDemod::InitDATVFramework()
m_lngExpectedReadIQ = BUF_BASEBAND;
CleanUpDATVFramework(true);
CleanUpDATVFramework();
m_objScheduler = new scheduler();
@ -819,7 +821,7 @@ void DATVDemod::InitDATVFramework()
m_blnDVBInitialized=true;
}
void DATVDemod::feed(const SampleVector::const_iterator& begin, const SampleVector::const_iterator& end, bool firstOfBurst)
void DATVDemod::feed(const SampleVector::const_iterator& begin, const SampleVector::const_iterator& end, bool firstOfBurst __attribute__((unused)))
{
float fltI;
float fltQ;
@ -964,12 +966,12 @@ bool DATVDemod::handleMessage(const Message& cmd)
m_channelizer->configure(m_channelizer->getInputMessageQueue(),
m_channelizer->getInputSampleRate(),
m_objRunning.intCenterFrequency);
cfg.getCenterFrequency());
//m_objRunning.intCenterFrequency);
qDebug() << "ATVDemod::handleMessage: MsgConfigureChannelizer: sampleRate: " << m_channelizer->getInputSampleRate()
<< " centerFrequency: " << m_objRunning.intCenterFrequency;
qDebug() << "DATVDemod::handleMessage: MsgConfigureChannelizer: sampleRate: " << m_channelizer->getInputSampleRate()
<< " centerFrequency: " << cfg.getCenterFrequency();
//<< " centerFrequency: " << m_objRunning.intCenterFrequency;
return true;
}

View File

@ -43,8 +43,6 @@ class DownChannelizer;
#endif
#include "datvconstellation.h"
#include "datvvideoplayer.h"
@ -70,68 +68,81 @@ class DownChannelizer;
using namespace leansdr;
enum DATVModulation { BPSK, QPSK, PSK8, APSK16, APSK32, APSK64E, QAM16, QAM64, QAM256 };
enum dvb_version { DVB_S, DVB_S2 };
enum dvb_sampler { SAMP_NEAREST, SAMP_LINEAR, SAMP_RRC };
inline int decimation(float Fin, float Fout) { int d = Fin / Fout; return max(d, 1); }
struct config
{
dvb_version standard;
dvb_sampler sampler;
int buf_factor; // Buffer sizing
float Fs; // Sampling frequency (Hz)
float Fderot; // Shift the signal (Hz). Note: Ftune is faster
int anf; // Number of auto notch filters
bool cnr; // Measure CNR
unsigned int decim; // Decimation, 0=auto
float Fm; // QPSK symbol rate (Hz)
cstln_lut<256>::predef constellation;
code_rate fec;
float Ftune; // Bias frequency for the QPSK demodulator (Hz)
bool allow_drift;
bool fastlock;
bool viterbi;
bool hard_metric;
bool resample;
float resample_rej; // Approx. filter rejection in dB
int rrc_steps; // Discrete steps between symbols, 0=auto
float rrc_rej; // Approx. RRC filter rejection in dB
float rolloff; // Roll-off 0..1
bool hdlc; // Expect HDLC frames instead of MPEG packets
bool packetized; // Output frames with 16-bit BE length
float Finfo; // Desired refresh rate on fd_info (Hz)
config() : buf_factor(4),
Fs(2.4e6),
Fderot(0),
anf(1),
cnr(false),
decim(0),
Fm(2e6),
standard(DVB_S),
constellation(cstln_lut<256>::QPSK),
fec(FEC12),
Ftune(0),
allow_drift(false),
fastlock(true),
viterbi(false),
hard_metric(false),
resample(false),
resample_rej(10),
sampler(SAMP_LINEAR),
rrc_steps(0),
rrc_rej(10),
rolloff(0.35),
hdlc(false),
packetized(false),
Finfo(5)
{
}
enum DATVModulation
{
BPSK, QPSK, PSK8, APSK16, APSK32, APSK64E, QAM16, QAM64, QAM256
};
enum dvb_version
{
DVB_S, DVB_S2
};
enum dvb_sampler
{
SAMP_NEAREST, SAMP_LINEAR, SAMP_RRC
};
inline int decimation(float Fin, float Fout)
{
int d = Fin / Fout;
return max(d, 1);
}
struct config
{
dvb_version standard;
dvb_sampler sampler;
int buf_factor; // Buffer sizing
float Fs; // Sampling frequency (Hz)
float Fderot; // Shift the signal (Hz). Note: Ftune is faster
int anf; // Number of auto notch filters
bool cnr; // Measure CNR
unsigned int decim; // Decimation, 0=auto
float Fm; // QPSK symbol rate (Hz)
cstln_lut<256>::predef constellation;
code_rate fec;
float Ftune; // Bias frequency for the QPSK demodulator (Hz)
bool allow_drift;
bool fastlock;
bool viterbi;
bool hard_metric;
bool resample;
float resample_rej; // Approx. filter rejection in dB
int rrc_steps; // Discrete steps between symbols, 0=auto
float rrc_rej; // Approx. RRC filter rejection in dB
float rolloff; // Roll-off 0..1
bool hdlc; // Expect HDLC frames instead of MPEG packets
bool packetized; // Output frames with 16-bit BE length
float Finfo; // Desired refresh rate on fd_info (Hz)
config() :
standard(DVB_S),
sampler(SAMP_LINEAR),
buf_factor(4),
Fs(2.4e6),
Fderot(0),
anf(1),
cnr(false),
decim(0),
Fm(2e6),
constellation(cstln_lut<256>::QPSK),
fec(FEC12),
Ftune(0),
allow_drift(false),
fastlock(true),
viterbi(false),
hard_metric(false),
resample(false),
resample_rej(10),
rrc_steps(0),
rrc_rej(10),
rolloff(0.35),
hdlc(false),
packetized(false),
Finfo(5)
{
}
};
struct DATVConfig
{
@ -152,118 +163,205 @@ struct DATVConfig
bool blnViterbi;
DATVConfig() :
intMsps(1024000),
intRFBandwidth(1024000),
intCenterFrequency(0),
enmStandard(DVB_S),
enmModulation(BPSK),
enmFEC(FEC12),
intSampleRate(1024000),
intSymbolRate(250000),
intNotchFilters(1),
blnAllowDrift(false),
blnFastLock(false),
blnHDLC(false),
blnHardMetric(false),
blnResample(false),
blnViterbi(false)
intMsps(1024000),
intRFBandwidth(1024000),
intCenterFrequency(0),
enmStandard(DVB_S),
enmModulation(BPSK),
enmFEC(FEC12),
intSampleRate(1024000),
intSymbolRate(250000),
intNotchFilters(1),
blnAllowDrift(false),
blnFastLock(false),
blnHDLC(false),
blnHardMetric(false),
blnResample(false),
blnViterbi(false)
{
}
};
class DATVDemod : public BasebandSampleSink, public ChannelSinkAPI
class DATVDemod: public BasebandSampleSink, public ChannelSinkAPI
{
Q_OBJECT
Q_OBJECT
public:
class MsgConfigureChannelizer: public Message
{
MESSAGE_CLASS_DECLARATION
public:
int getCenterFrequency() const
{
return m_centerFrequency;
}
static MsgConfigureChannelizer* create(int centerFrequency)
{
return new MsgConfigureChannelizer(centerFrequency);
}
private:
int m_centerFrequency;
MsgConfigureChannelizer(int centerFrequency) :
Message(), m_centerFrequency(centerFrequency)
{
}
};
DATVDemod(DeviceSourceAPI *);
~DATVDemod();
virtual void destroy() { delete this; }
virtual void getIdentifier(QString& id) { id = objectName(); }
virtual void getTitle(QString& title) { title = objectName(); }
virtual qint64 getCenterFrequency() const { return m_objRunning.intCenterFrequency; }
virtual void destroy()
{
delete this;
}
virtual void getIdentifier(QString& id)
{
id = objectName();
}
virtual void getTitle(QString& title)
{
title = objectName();
}
virtual qint64 getCenterFrequency() const
{
return m_objRunning.intCenterFrequency;
}
virtual QByteArray serialize() const { return QByteArray(); }
virtual bool deserialize(const QByteArray& data __attribute__((unused))) { return false; }
virtual QByteArray serialize() const
{
return QByteArray();
}
virtual bool deserialize(const QByteArray& data __attribute__((unused)))
{
return false;
}
void configure(
MessageQueue* objMessageQueue,
int intRFBandwidth,
int intCenterFrequency,
dvb_version enmStandard,
DATVModulation enmModulation,
code_rate enmFEC,
int intSymbolRate,
int intNotchFilters,
bool blnAllowDrift,
bool blnFastLock,
bool blnHDLC,
bool blnHardMetric,
bool blnResample,
bool blnViterbi);
void configure(MessageQueue* objMessageQueue,
int intRFBandwidth,
int intCenterFrequency,
dvb_version enmStandard,
DATVModulation enmModulation,
code_rate enmFEC,
int intSymbolRate,
int intNotchFilters,
bool blnAllowDrift,
bool blnFastLock,
bool blnHDLC,
bool blnHardMetric,
bool blnResample,
bool blnViterbi);
virtual void feed(const SampleVector::const_iterator& begin, const SampleVector::const_iterator& end, bool po);
virtual void start();
virtual void stop();
virtual bool handleMessage(const Message& cmd);
virtual void feed(const SampleVector::const_iterator& begin,
const SampleVector::const_iterator& end, bool po);
virtual void start();
virtual void stop();
virtual bool handleMessage(const Message& cmd);
bool SetDATVScreen(DATVScreen *objScreen);
DATVideostream * SetVideoRender(DATVideoRender *objScreen);
bool PlayVideo(bool blnStartStop);
void InitDATVParameters(int intMsps,
int intRFBandwidth,
int intCenterFrequency,
dvb_version enmStandard,
DATVModulation enmModulation,
code_rate enmFEC,
int intSampleRate,
int intSymbolRate,
int intNotchFilters,
bool blnAllowDrift,
bool blnFastLock,
bool blnHDLC,
bool blnHardMetric,
bool blnResample,
bool blnViterbi);
void InitDATVParameters(
int intMsps,
int intRFBandwidth,
int intCenterFrequency,
dvb_version enmStandard,
DATVModulation enmModulation,
code_rate enmFEC,
int intSampleRate,
int intSymbolRate,
int intNotchFilters,
bool blnAllowDrift,
bool blnFastLock,
bool blnHDLC,
bool blnHardMetric,
bool blnResample,
bool blnViterbi);
void CleanUpDATVFramework(bool blnRelease);
void CleanUpDATVFramework();
int GetSampleRate();
void InitDATVFramework();
static const QString m_channelIdURI;
static const QString m_channelId;
class MsgConfigureChannelizer : public Message
{
MESSAGE_CLASS_DECLARATION
public:
int getCenterFrequency() const { return m_centerFrequency; }
static MsgConfigureChannelizer* create(int centerFrequency)
{
return new MsgConfigureChannelizer(centerFrequency);
}
private:
int m_centerFrequency;
MsgConfigureChannelizer(int centerFrequency) :
Message(),
m_centerFrequency(centerFrequency)
{ }
};
private:
class MsgConfigureDATVDemod: public Message
{
MESSAGE_CLASS_DECLARATION
public:
static MsgConfigureDATVDemod* create(
int intRFBandwidth,
int intCenterFrequency,
dvb_version enmStandard,
DATVModulation enmModulation,
code_rate enmFEC,
int intSymbolRate,
int intNotchFilters,
bool blnAllowDrift,
bool blnFastLock,
bool blnHDLC,
bool blnHardMetric,
bool blnResample,
bool blnViterbi)
{
return new MsgConfigureDATVDemod(
intRFBandwidth,
intCenterFrequency,
enmStandard,
enmModulation,
enmFEC,
intSymbolRate,
intNotchFilters,
blnAllowDrift,
blnFastLock,
blnHDLC,
blnHardMetric,
blnResample,
blnViterbi);
}
DATVConfig m_objMsgConfig;
private:
MsgConfigureDATVDemod(
int intRFBandwidth,
int intCenterFrequency,
dvb_version enmStandard,
DATVModulation enmModulation,
code_rate enmFEC,
int intSymbolRate,
int intNotchFilters,
bool blnAllowDrift,
bool blnFastLock,
bool blnHDLC,
bool blnHardMetric,
bool blnResample,
bool blnViterbi) :
Message()
{
m_objMsgConfig.intRFBandwidth = intRFBandwidth;
m_objMsgConfig.intCenterFrequency = intCenterFrequency;
m_objMsgConfig.enmStandard = enmStandard;
m_objMsgConfig.enmModulation = enmModulation;
m_objMsgConfig.enmFEC = enmFEC;
m_objMsgConfig.intSymbolRate = intSymbolRate;
m_objMsgConfig.intNotchFilters = intNotchFilters;
m_objMsgConfig.blnAllowDrift = blnAllowDrift;
m_objMsgConfig.blnFastLock = blnFastLock;
m_objMsgConfig.blnHDLC = blnHDLC;
m_objMsgConfig.blnHardMetric = blnHardMetric;
m_objMsgConfig.blnResample = blnResample;
m_objMsgConfig.blnViterbi = blnViterbi;
}
};
unsigned long m_lngExpectedReadIQ;
unsigned long m_lngReadIQ;
@ -305,7 +403,7 @@ private:
cnr_fft<f32> *r_cnr;
//FILTERING
fir_filter<cf32,float> *r_resample;
fir_filter<cf32, float> *r_resample;
pipebuf<cf32> *p_resampled;
float *coeffs;
int ncoeffs;
@ -344,18 +442,17 @@ private:
pipebuf<u8> *p_mpegbytes;
pipebuf<int> *p_lock;
pipebuf<u32> *p_locktime;
mpeg_sync<u8,0> *r_sync_mpeg;
mpeg_sync<u8, 0> *r_sync_mpeg;
// DEINTERLEAVING
pipebuf< rspacket<u8> > *p_rspackets;
pipebuf<rspacket<u8> > *p_rspackets;
deinterleaver<u8> *r_deinter;
// REED-SOLOMON
pipebuf<int> *p_vbitcount;
pipebuf<int> *p_verrcount;
pipebuf<tspacket> *p_rtspackets;
rs_decoder<u8,0> *r_rsdec;
rs_decoder<u8, 0> *r_rsdec;
// BER ESTIMATION
pipebuf<float> *p_vber;
@ -365,7 +462,6 @@ private:
pipebuf<tspacket> *p_tspackets;
derandomizer *r_derand;
//OUTPUT
file_writer<tspacket> *r_stdout;
datvvideoplayer<tspacket> *r_videoplayer;
@ -373,87 +469,26 @@ private:
//CONSTELLATION
datvconstellation<f32> *r_scope_symbols;
DeviceSourceAPI* m_deviceAPI;
private:
ThreadedBasebandSampleSink* m_threadedChannelizer;
DownChannelizer* m_channelizer;
DeviceSourceAPI* m_deviceAPI;
//*************** DATV PARAMETERS ***************
DATVScreen * m_objRegisteredDATVScreen;
DATVideoRender * m_objRegisteredVideoRender;
DATVideostream * m_objVideoStream;
DATVideoRenderThread * m_objRenderThread;
ThreadedBasebandSampleSink* m_threadedChannelizer;
DownChannelizer* m_channelizer;
fftfilt * m_objRFFilter;
NCO m_objNCO;
//*************** DATV PARAMETERS ***************
DATVScreen * m_objRegisteredDATVScreen;
DATVideoRender * m_objRegisteredVideoRender;
DATVideostream * m_objVideoStream;
DATVideoRenderThread * m_objRenderThread;
bool m_blnInitialized;
bool m_blnRenderingVideo;
fftfilt * m_objRFFilter;
NCO m_objNCO;
bool m_blnInitialized;
bool m_blnRenderingVideo;
DATVModulation m_enmModulation;
//QElapsedTimer m_objTimer;
private:
class MsgConfigureDATVDemod : public Message
{
MESSAGE_CLASS_DECLARATION
public:
static MsgConfigureDATVDemod* create(int intRFBandwidth,
int intCenterFrequency,
dvb_version enmStandard,
DATVModulation enmModulation,
code_rate enmFEC,
int intSymbolRate,
int intNotchFilters,
bool blnAllowDrift,
bool blnFastLock,
bool blnHDLC,
bool blnHardMetric,
bool blnResample,
bool blnViterbi)
{
return new MsgConfigureDATVDemod(intRFBandwidth,intCenterFrequency,enmStandard, enmModulation, enmFEC, intSymbolRate, intNotchFilters, blnAllowDrift,blnFastLock,blnHDLC,blnHardMetric,blnResample, blnViterbi);
}
DATVConfig m_objMsgConfig;
private:
MsgConfigureDATVDemod(int intRFBandwidth,
int intCenterFrequency,
dvb_version enmStandard,
DATVModulation enmModulation,
code_rate enmFEC,
int intSymbolRate,
int intNotchFilters,
bool blnAllowDrift,
bool blnFastLock,
bool blnHDLC,
bool blnHardMetric,
bool blnResample,
bool blnViterbi) :
Message()
{
m_objMsgConfig.intRFBandwidth = intRFBandwidth;
m_objMsgConfig.intCenterFrequency = intCenterFrequency;
m_objMsgConfig.enmStandard = enmStandard;
m_objMsgConfig.enmModulation = enmModulation;
m_objMsgConfig.enmFEC = enmFEC;
m_objMsgConfig.intSymbolRate = intSymbolRate;
m_objMsgConfig.intNotchFilters = intNotchFilters;
m_objMsgConfig.blnAllowDrift = blnAllowDrift;
m_objMsgConfig.blnFastLock = blnFastLock;
m_objMsgConfig.blnHDLC = blnHDLC;
m_objMsgConfig.blnHardMetric = blnHardMetric;
m_objMsgConfig.blnResample = blnResample;
m_objMsgConfig.blnViterbi = blnViterbi;
}
};
DATVModulation m_enmModulation;
//QElapsedTimer m_objTimer;
DATVConfig m_objRunning;

View File

@ -47,7 +47,7 @@ DATVDemodGUI* DATVDemodGUI::create(PluginAPI* objPluginAPI,
}
void DATVDemodGUI::destroy()
{
{
delete this;
}
@ -208,7 +208,7 @@ bool DATVDemodGUI::deserialize(const QByteArray& arrData)
}
}
bool DATVDemodGUI::handleMessage(const Message& objMessage)
bool DATVDemodGUI::handleMessage(const Message& objMessage __attribute__((unused)))
{
return false;
}
@ -233,7 +233,7 @@ void DATVDemodGUI::channelSampleRateChanged()
applySettings();
}
void DATVDemodGUI::onWidgetRolled(QWidget* widget, bool rollDown)
void DATVDemodGUI::onWidgetRolled(QWidget* widget __attribute__((unused)), bool rollDown __attribute__((unused)))
{
}
@ -258,7 +258,7 @@ DATVDemodGUI::DATVDemodGUI(PluginAPI* objPluginAPI, DeviceUISet *deviceUISet, Ba
m_objChannelMarker(this),
m_blnBasicSettingsShown(false),
m_blnDoApplySettings(true)
{
{
ui->setupUi(this);
setAttribute(Qt::WA_DeleteOnClose, true);
connect(this, SIGNAL(widgetRolled(QWidget*,bool)), this, SLOT(onWidgetRolled(QWidget*,bool)));
@ -491,9 +491,9 @@ void DATVDemodGUI::enterEvent(QEvent*)
}
void DATVDemodGUI::tick()
{
{
if((m_intLastDecodedData-m_intPreviousDecodedData)>=0)
{
{
m_intLastSpeed = 8*(m_intLastDecodedData-m_intPreviousDecodedData);
ui->lblRate->setText(QString("Speed: %1b/s").arg(formatBytes(m_intLastSpeed)));
}
@ -506,12 +506,12 @@ void DATVDemodGUI::tick()
return;
}
void DATVDemodGUI::on_cmbStandard_currentIndexChanged(const QString &arg1)
{
void DATVDemodGUI::on_cmbStandard_currentIndexChanged(const QString &arg1 __attribute__((unused)))
{
applySettings();
}
void DATVDemodGUI::on_cmbModulation_currentIndexChanged(const QString &arg1)
void DATVDemodGUI::on_cmbModulation_currentIndexChanged(const QString &arg1 __attribute__((unused)))
{
QString strModulation;
QString strFEC;
@ -563,8 +563,8 @@ void DATVDemodGUI::on_cmbModulation_currentIndexChanged(const QString &arg1)
}
void DATVDemodGUI::on_cmbFEC_currentIndexChanged(const QString &arg1)
{
void DATVDemodGUI::on_cmbFEC_currentIndexChanged(const QString &arg1 __attribute__((unused)))
{
QString strFEC;
strFEC = ui->cmbFEC->currentText();
@ -625,7 +625,7 @@ void DATVDemodGUI::on_chkHardMetric_clicked()
/*
void DATVDemodGUI::on_pushButton_clicked()
{
applySettings();
applySettings();
}
*/
@ -641,12 +641,12 @@ void DATVDemodGUI::on_spiSampleRate_valueChanged(int arg1)
}
*/
void DATVDemodGUI::on_spiSymbolRate_valueChanged(int arg1)
void DATVDemodGUI::on_spiSymbolRate_valueChanged(int arg1 __attribute__((unused)))
{
applySettings();
}
void DATVDemodGUI::on_spiNotchFilters_valueChanged(int arg1)
void DATVDemodGUI::on_spiNotchFilters_valueChanged(int arg1 __attribute__((unused)))
{
applySettings();
}
@ -701,8 +701,8 @@ void DATVDemodGUI::on_pushButton_4_clicked()
}
void DATVDemodGUI::on_mouseEvent(QMouseEvent* obj)
{
void DATVDemodGUI::on_mouseEvent(QMouseEvent* obj __attribute__((unused)))
{
}
QString DATVDemodGUI::formatBytes(qint64 intBytes)
@ -724,7 +724,7 @@ QString DATVDemodGUI::formatBytes(qint64 intBytes)
}
void DATVDemodGUI::on_StreamDataAvailable(int *intPackets, int *intBytes, int *intPercent, qint64 *intTotalReceived)
void DATVDemodGUI::on_StreamDataAvailable(int *intPackets __attribute__((unused)), int *intBytes, int *intPercent, qint64 *intTotalReceived)
{
ui->lblStatus->setText(QString("Decod: %1B").arg(formatBytes(*intTotalReceived)));
m_intLastDecodedData = *intTotalReceived;
@ -742,7 +742,7 @@ void DATVDemodGUI::on_StreamDataAvailable(int *intPackets, int *intBytes, int *i
}
void DATVDemodGUI::on_spiBandwidth_valueChanged(int arg1)
void DATVDemodGUI::on_spiBandwidth_valueChanged(int arg1 __attribute__((unused)))
{
applySettings();
}

View File

@ -5,347 +5,438 @@
#include "leansdr/framework.h"
#include "leansdr/math.h"
namespace leansdr {
namespace leansdr
{
//////////////////////////////////////////////////////////////////////
// DSP blocks
//////////////////////////////////////////////////////////////////////
// [cconverter] converts complex streams between numric types,
// with optional ofsetting and rational scaling.
template<typename Tin, int Zin, typename Tout, int Zout, int Gn, int Gd>
struct cconverter : runnable {
cconverter(scheduler *sch, pipebuf< complex<Tin> > &_in,
pipebuf< complex<Tout> > &_out)
: runnable(sch, "cconverter"),
in(_in), out(_out) {
//////////////////////////////////////////////////////////////////////
// DSP blocks
//////////////////////////////////////////////////////////////////////
// [cconverter] converts complex streams between numric types,
// with optional ofsetting and rational scaling.
template<typename Tin, int Zin, typename Tout, int Zout, int Gn, int Gd>
struct cconverter: runnable
{
cconverter(scheduler *sch, pipebuf<complex<Tin> > &_in,
pipebuf<complex<Tout> > &_out) :
runnable(sch, "cconverter"), in(_in), out(_out)
{
}
void run() {
unsigned long count = min(in.readable(), out.writable());
complex<Tin> *pin=in.rd(), *pend=pin+count;
complex<Tout> *pout = out.wr();
for ( ; pin<pend; ++pin,++pout ) {
pout->re = Zout + (pin->re-(Tin)Zin)*Gn/Gd;
pout->im = Zout + (pin->im-(Tin)Zin)*Gn/Gd;
}
in.read(count);
out.written(count);
void run()
{
unsigned long count = min(in.readable(), out.writable());
complex<Tin> *pin = in.rd(), *pend = pin + count;
complex<Tout> *pout = out.wr();
for (; pin < pend; ++pin, ++pout)
{
pout->re = Zout + (pin->re - (Tin) Zin) * Gn / Gd;
pout->im = Zout + (pin->im - (Tin) Zin) * Gn / Gd;
}
in.read(count);
out.written(count);
}
private:
pipereader< complex<Tin> > in;
pipewriter< complex<Tout> > out;
};
template<typename T>
struct cfft_engine {
const int n;
cfft_engine(int _n) : n(_n), invsqrtn(1.0/sqrt(n)) {
// Compute log2(n)
logn = 0;
for ( int t=n; t>1; t>>=1 ) ++logn;
// Bit reversal
bitrev = new int[n];
for ( int i=0; i<n; ++i ) {
bitrev[i] = 0;
for ( int b=0; b<logn; ++b ) bitrev[i] = (bitrev[i]<<1) | ((i>>b)&1);
}
// Float constants
omega = new complex<T>[n];
omega_rev = new complex<T>[n];
for ( int i=0; i<n; ++i ) {
float a = 2.0*M_PI * i / n;
omega_rev[i].re = (omega[i].re = cosf(a));
omega_rev[i].im = - (omega[i].im = sinf(a));
}
private:
pipereader<complex<Tin> > in;
pipewriter<complex<Tout> > out;
};
template<typename T>
struct cfft_engine
{
const unsigned int n;
cfft_engine(unsigned int _n) :
n(_n), invsqrtn(1.0 / sqrt(n))
{
// Compute log2(n)
logn = 0;
for (int t = n; t > 1; t >>= 1)
++logn;
// Bit reversal
bitrev = new int[n];
for (unsigned int i = 0; i < n; ++i)
{
bitrev[i] = 0;
for (int b = 0; b < logn; ++b)
bitrev[i] = (bitrev[i] << 1) | ((i >> b) & 1);
}
// Float constants
omega = new complex<T> [n];
omega_rev = new complex<T> [n];
for (unsigned int i = 0; i < n; ++i)
{
float a = 2.0 * M_PI * i / n;
omega_rev[i].re = (omega[i].re = cosf(a));
omega_rev[i].im = -(omega[i].im = sinf(a));
}
}
void inplace(complex<T> *data, bool reverse=false) {
// Bit-reversal permutation
for ( int i=0; i<n; ++i ) {
int r = bitrev[i];
if ( r < i ) { complex<T> tmp=data[i]; data[i]=data[r]; data[r]=tmp; }
}
complex<T> *om = reverse ? omega_rev : omega;
// Danielson-Lanczos
for ( int i=0; i<logn; ++i ) {
int hbs = 1 << i;
int dom = 1 << (logn-1-i);
for ( int j=0; j<dom; ++j ) {
int p = j*hbs*2, q = p+hbs;
for ( int k=0; k<hbs; ++k ) {
complex<T> &w = om[k*dom];
complex<T> &dqk = data[q+k];
complex<T> x(w.re*dqk.re - w.im*dqk.im,
w.re*dqk.im + w.im*dqk.re);
data[q+k].re = data[p+k].re - x.re;
data[q+k].im = data[p+k].im - x.im;
data[p+k].re = data[p+k].re + x.re;
data[p+k].im = data[p+k].im + x.im;
}
}
}
if ( reverse ) {
float invn = 1.0 / n;
for ( int i=0; i<n; ++i ) {
data[i].re *= invn;
data[i].im *= invn;
}
}
void inplace(complex<T> *data, bool reverse = false)
{
// Bit-reversal permutation
for (unsigned int i = 0; i < n; ++i)
{
unsigned int r = bitrev[i];
if (r < i)
{
complex<T> tmp = data[i];
data[i] = data[r];
data[r] = tmp;
}
}
complex<T> *om = reverse ? omega_rev : omega;
// Danielson-Lanczos
for (int i = 0; i < logn; ++i)
{
int hbs = 1 << i;
int dom = 1 << (logn - 1 - i);
for (int j = 0; j < dom; ++j)
{
int p = j * hbs * 2, q = p + hbs;
for (int k = 0; k < hbs; ++k)
{
complex<T> &w = om[k * dom];
complex<T> &dqk = data[q + k];
complex<T> x(w.re * dqk.re - w.im * dqk.im,
w.re * dqk.im + w.im * dqk.re);
data[q + k].re = data[p + k].re - x.re;
data[q + k].im = data[p + k].im - x.im;
data[p + k].re = data[p + k].re + x.re;
data[p + k].im = data[p + k].im + x.im;
}
}
}
if (reverse)
{
float invn = 1.0 / n;
for (unsigned int i = 0; i < n; ++i)
{
data[i].re *= invn;
data[i].im *= invn;
}
}
}
private:
private:
int logn;
int *bitrev;
complex<T> *omega, *omega_rev;
float invsqrtn;
};
template<typename T>
struct adder : runnable {
adder(scheduler *sch,
pipebuf<T> &_in1, pipebuf<T> &_in2, pipebuf<T> &_out)
: runnable(sch, "adder"),
in1(_in1), in2(_in2), out(_out) {
};
template<typename T>
struct adder: runnable
{
adder(scheduler *sch, pipebuf<T> &_in1, pipebuf<T> &_in2, pipebuf<T> &_out) :
runnable(sch, "adder"),
in1(_in1),
in2(_in2),
out(_out)
{
}
void run() {
int n = out.writable();
if ( in1.readable() < n ) n = in1.readable();
if ( in2.readable() < n ) n = in2.readable();
T *pin1=in1.rd(), *pin2=in2.rd(), *pout=out.wr(), *pend=pout+n;
while ( pout < pend ) *pout++ = *pin1++ + *pin2++;
in1.read(n);
in2.read(n);
out.written(n);
void run()
{
int n = out.writable();
if (in1.readable() < n)
n = in1.readable();
if (in2.readable() < n)
n = in2.readable();
T *pin1 = in1.rd(), *pin2 = in2.rd(), *pout = out.wr(), *pend = pout
+ n;
while (pout < pend)
*pout++ = *pin1++ + *pin2++;
in1.read(n);
in2.read(n);
out.written(n);
}
private:
private:
pipereader<T> in1, in2;
pipewriter<T> out;
};
template<typename Tscale, typename Tin, typename Tout>
struct scaler : runnable {
};
template<typename Tscale, typename Tin, typename Tout>
struct scaler: runnable
{
Tscale scale;
scaler(scheduler *sch, Tscale _scale,
pipebuf<Tin> &_in, pipebuf<Tout> &_out)
: runnable(sch, "scaler"),
scale(_scale),
in(_in), out(_out) {
scaler(scheduler *sch, Tscale _scale, pipebuf<Tin> &_in, pipebuf<Tout> &_out) :
runnable(sch, "scaler"),
scale(_scale),
in(_in),
out(_out)
{
}
void run() {
unsigned long count = min(in.readable(), out.writable());
Tin *pin=in.rd(), *pend=pin+count;
Tout *pout = out.wr();
for ( ; pin<pend; ++pin,++pout ) *pout = *pin * scale;
in.read(count);
out.written(count);
void run()
{
unsigned long count = min(in.readable(), out.writable());
Tin *pin = in.rd(), *pend = pin + count;
Tout *pout = out.wr();
for (; pin < pend; ++pin, ++pout)
*pout = *pin * scale;
in.read(count);
out.written(count);
}
private:
private:
pipereader<Tin> in;
pipewriter<Tout> out;
};
// [awgb_c] generates complex white gaussian noise.
template<typename T>
struct wgn_c : runnable {
wgn_c(scheduler *sch, pipebuf< complex<T> > &_out)
: runnable(sch, "awgn"), stddev(1.0), out(_out) {
};
// [awgb_c] generates complex white gaussian noise.
template<typename T>
struct wgn_c: runnable
{
wgn_c(scheduler *sch, pipebuf<complex<T> > &_out) :
runnable(sch, "awgn"),
stddev(1.0),
out(_out)
{
}
void run() {
int n = out.writable();
complex<T> *pout=out.wr(), *pend=pout+n;
while ( pout < pend ) {
// TAOCP
float x, y, r2;
do {
x = 2*drand48() - 1;
y = 2*drand48() - 1;
r2 = x*x + y*y;
} while ( r2==0 || r2>=1 );
float k = sqrtf(-logf(r2)/r2) * stddev;
pout->re = k*x;
pout->im = k*y;
++pout;
}
out.written(n);
void run()
{
int n = out.writable();
complex<T> *pout = out.wr(), *pend = pout + n;
while (pout < pend)
{
// TAOCP
float x, y, r2;
do
{
x = 2 * drand48() - 1;
y = 2 * drand48() - 1;
r2 = x * x + y * y;
} while (r2 == 0 || r2 >= 1);
float k = sqrtf(-logf(r2) / r2) * stddev;
pout->re = k * x;
pout->im = k * y;
++pout;
}
out.written(n);
}
float stddev;
private:
pipewriter< complex<T> > out;
};
template<typename T>
struct naive_lowpass : runnable {
naive_lowpass(scheduler *sch, pipebuf<T> &_in, pipebuf<T> &_out, int _w)
: runnable(sch, "lowpass"), in(_in), out(_out), w(_w) {
private:
pipewriter<complex<T> > out;
};
template<typename T>
struct naive_lowpass: runnable
{
naive_lowpass(scheduler *sch, pipebuf<T> &_in, pipebuf<T> &_out, int _w) :
runnable(sch, "lowpass"),
in(_in),
out(_out),
w(_w)
{
}
void run() {
if ( in.readable() < w ) return;
unsigned long count = min(in.readable()-w, out.writable());
T *pin=in.rd(), *pend=pin+count;
T *pout = out.wr();
float k = 1.0 / w;
for ( ; pin<pend; ++pin,++pout ) {
T x = 0.0;
for ( int i=0; i<w; ++i ) x = x + pin[i];
*pout = x * k;
}
in.read(count);
out.written(count);
void run()
{
if (in.readable() < w)
return;
unsigned long count = min(in.readable() - w, out.writable());
T *pin = in.rd(), *pend = pin + count;
T *pout = out.wr();
float k = 1.0 / w;
for (; pin < pend; ++pin, ++pout)
{
T x = 0.0;
for (int i = 0; i < w; ++i)
x = x + pin[i];
*pout = x * k;
}
in.read(count);
out.written(count);
}
private:
private:
pipereader<T> in;
pipewriter<T> out;
int w;
};
};
template<typename T, typename Tc>
struct fir_filter : runnable {
fir_filter(scheduler *sch, int _ncoeffs, Tc *_coeffs,
pipebuf<T> &_in, pipebuf<T> &_out,
unsigned int _decim=1)
: runnable(sch, "fir_filter"),
ncoeffs(_ncoeffs), coeffs(_coeffs),
in(_in), out(_out),
decim(_decim),
freq_tap(NULL), tap_multiplier(1), freq_tol(0.1) {
shifted_coeffs = new T[ncoeffs];
set_freq(0);
template<typename T, typename Tc>
struct fir_filter: runnable
{
fir_filter(scheduler *sch, int _ncoeffs, Tc *_coeffs, pipebuf<T> &_in, pipebuf<T> &_out, unsigned int _decim = 1) :
runnable(sch, "fir_filter"),
freq_tap(NULL),
tap_multiplier(1),
freq_tol(0.1),
ncoeffs(_ncoeffs),
coeffs(_coeffs),
in(_in),
out(_out),
decim(_decim)
{
shifted_coeffs = new T[ncoeffs];
set_freq(0);
}
void run() {
if ( in.readable() < ncoeffs ) return;
if ( freq_tap ) {
float new_freq = *freq_tap * tap_multiplier;
if ( fabs(current_freq-new_freq) > freq_tol ) {
if ( sch->verbose )
fprintf(stderr, "Shifting filter %f -> %f\n",
current_freq, new_freq);
set_freq(new_freq);
}
}
void run()
{
if (in.readable() < ncoeffs)
return;
unsigned long count = min((in.readable()-ncoeffs)/decim,
out.writable());
T *pin=in.rd()+ncoeffs, *pend=pin+count*decim, *pout=out.wr();
// TBD use coeffs when current_freq=0 (fewer mults if float)
for ( ; pin<pend; pin+=decim,++pout ) {
T *pc = shifted_coeffs;
T *pi = pin;
T x = 0;
for ( unsigned int i=ncoeffs; i--; ++pc,--pi )
x = x + (*pc)*(*pi);
*pout = x;
}
in.read(count*decim);
out.written(count);
if (freq_tap)
{
float new_freq = *freq_tap * tap_multiplier;
if (fabs(current_freq - new_freq) > freq_tol)
{
if (sch->verbose)
fprintf(stderr, "Shifting filter %f -> %f\n", current_freq,
new_freq);
set_freq(new_freq);
}
}
unsigned long count = min((in.readable() - ncoeffs) / decim,
out.writable());
T *pin = in.rd() + ncoeffs, *pend = pin + count * decim, *pout =
out.wr();
// TBD use coeffs when current_freq=0 (fewer mults if float)
for (; pin < pend; pin += decim, ++pout)
{
T *pc = shifted_coeffs;
T *pi = pin;
T x = 0;
for (unsigned int i = ncoeffs; i--; ++pc, --pi)
x = x + (*pc) * (*pi);
*pout = x;
}
in.read(count * decim);
out.written(count);
}
private:
public:
float *freq_tap;
float tap_multiplier;
float freq_tol;
private:
unsigned int ncoeffs;
Tc *coeffs;
pipereader<T> in;
pipewriter<T> out;
unsigned int decim;
T *shifted_coeffs;
T *shifted_coeffs;
float current_freq;
void set_freq(float f) {
for ( int i=0; i<ncoeffs; ++i ) {
float a = 2*M_PI * f * (i-ncoeffs/2);
float c=cosf(a), s=sinf(a);
// TBD Support T=complex
shifted_coeffs[i].re = coeffs[i] * c;
shifted_coeffs[i].im = coeffs[i] * s;
}
current_freq = f;
void set_freq(float f)
{
for (unsigned int i = 0; i < ncoeffs; ++i)
{
float a = 2 * M_PI * f * (i - ncoeffs / 2);
float c = cosf(a), s = sinf(a);
// TBD Support T=complex
shifted_coeffs[i].re = coeffs[i] * c;
shifted_coeffs[i].im = coeffs[i] * s;
}
current_freq = f;
}
public:
};
// fir_filter
// FIR FILTER WITH INTERPOLATION AND DECIMATION
template<typename T, typename Tc>
struct fir_resampler: runnable
{
fir_resampler(scheduler *sch, int _ncoeffs, Tc *_coeffs, pipebuf<T> &_in, pipebuf<T> &_out, int _interp = 1, int _decim = 1) :
runnable(sch, "fir_resampler"),
ncoeffs(_ncoeffs),
coeffs(_coeffs),
interp(_interp),
decim(_decim),
in(_in),
out(_out, interp),
freq_tap(NULL),
tap_multiplier(1),
freq_tol(0.1)
{
if (decim != 1)
fail("fir_resampler: decim not implemented"); // TBD
shifted_coeffs = new T[ncoeffs];
set_freq(0);
}
void run()
{
if (in.readable() < ncoeffs)
return;
if (freq_tap)
{
float new_freq = *freq_tap * tap_multiplier;
if (fabs(current_freq - new_freq) > freq_tol)
{
if (sch->verbose)
fprintf(stderr, "Shifting filter %f -> %f\n", current_freq,
new_freq);
set_freq(new_freq);
}
}
if (in.readable() * interp < ncoeffs)
return;
unsigned long count = min((in.readable() * interp - ncoeffs) / interp,
out.writable() / interp);
int latency = (ncoeffs + interp) / interp;
T *pin = in.rd() + latency, *pend = pin + count, *pout = out.wr();
// TBD use coeffs when current_freq=0 (fewer mults if float)
for (; pin < pend; ++pin)
{
for (int i = 0; i < interp; ++i, ++pout)
{
T *pi = pin;
T *pc = shifted_coeffs + i, *pcend = shifted_coeffs + ncoeffs;
T x = 0;
for (; pc < pcend; pc += interp, --pi)
x = x + (*pc) * (*pi);
*pout = x;
}
}
in.read(count);
out.written(count * interp);
}
public:
float *freq_tap;
float tap_multiplier;
float freq_tol;
}; // fir_filter
// FIR FILTER WITH INTERPOLATION AND DECIMATION
template<typename T, typename Tc>
struct fir_resampler : runnable {
fir_resampler(scheduler *sch, int _ncoeffs, Tc *_coeffs,
pipebuf<T> &_in, pipebuf<T> &_out,
int _interp=1, int _decim=1)
: runnable(sch, "fir_resampler"),
ncoeffs(_ncoeffs), coeffs(_coeffs),
interp(_interp), decim(_decim),
in(_in), out(_out,interp),
freq_tap(NULL), tap_multiplier(1), freq_tol(0.1)
{
if ( decim != 1 ) fail("fir_resampler: decim not implemented"); // TBD
shifted_coeffs = new T[ncoeffs];
set_freq(0);
}
void run() {
if ( in.readable() < ncoeffs ) return;
if ( freq_tap ) {
float new_freq = *freq_tap * tap_multiplier;
if ( fabs(current_freq-new_freq) > freq_tol ) {
if ( sch->verbose )
fprintf(stderr, "Shifting filter %f -> %f\n",
current_freq, new_freq);
set_freq(new_freq);
}
}
if ( in.readable()*interp < ncoeffs ) return;
unsigned long count = min((in.readable()*interp-ncoeffs)/interp,
out.writable()/interp);
int latency = (ncoeffs+interp) / interp;
T *pin=in.rd()+latency, *pend=pin+count, *pout=out.wr();
// TBD use coeffs when current_freq=0 (fewer mults if float)
for ( ; pin<pend; ++pin ) {
for ( int i=0; i<interp; ++i,++pout ) {
T *pi = pin;
T *pc = shifted_coeffs+i, *pcend=shifted_coeffs+ncoeffs;
T x = 0;
for ( ; pc<pcend; pc+=interp,--pi )
x = x + (*pc)*(*pi);
*pout = x;
}
}
in.read(count);
out.written(count*interp);
}
private:
private:
unsigned int ncoeffs;
Tc *coeffs;
int interp, decim;
pipereader<T> in;
pipewriter<T> out;
public:
float *freq_tap;
float tap_multiplier;
float freq_tol;
private:
T *shifted_coeffs;
T *shifted_coeffs;
float current_freq;
void set_freq(float f) {
for ( int i=0; i<ncoeffs; ++i ) {
float a = 2*M_PI * f * i;
float c=cosf(a), s=sinf(a);
// TBD Support T=complex
shifted_coeffs[i].re = coeffs[i] * c;
shifted_coeffs[i].im = coeffs[i] * s;
}
current_freq = f;
}
}; // fir_resampler
} // namespace
void set_freq(float f)
{
for (int i = 0; i < ncoeffs; ++i)
{
float a = 2 * M_PI * f * i;
float c = cosf(a), s = sinf(a);
// TBD Support T=complex
shifted_coeffs[i].re = coeffs[i] * c;
shifted_coeffs[i].im = coeffs[i] * s;
}
current_freq = f;
}
};
// fir_resampler
}// namespace
#endif // LEANSDR_DSP_H

File diff suppressed because it is too large Load Diff

View File

@ -1,54 +1,104 @@
#ifndef LEANSDR_FRAMEWORK_H
#define LEANSDR_FRAMEWORK_H
#include <cstddef>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
namespace leansdr {
inline void fatal(const char *s) { perror(s); exit(1); }
inline void fail(const char *s) { fprintf(stderr, "** %s\n", s); exit(1); }
//////////////////////////////////////////////////////////////////////
// DSP framework
//////////////////////////////////////////////////////////////////////
// [pipebuf] is a FIFO buffer with multiple readers.
// [pipewriter] is a client-side hook for writing into a [pipebuf].
// [pipereader] is a client-side hook reading from a [pipebuf].
// [runnable] is anything that moves data between [pipebufs].
// [scheduler] is a global context which invokes [runnables] until fixpoint.
static const int MAX_PIPES = 64;
static const int MAX_RUNNABLES = 64;
static const int MAX_READERS = 8;
struct pipebuf_common {
virtual int sizeofT() { return 0; }
virtual long long hash() { return 0; }
virtual void dump(size_t *total_bufs) { }
const char *name;
pipebuf_common(const char *_name) : name(_name) { }
};
namespace leansdr
{
inline void fatal(const char *s)
{
perror(s);
exit(1);
}
inline void fail(const char *s)
{
fprintf(stderr, "leansdr::fail: %s\n", s);
exit(1);
}
//////////////////////////////////////////////////////////////////////
// DSP framework
//////////////////////////////////////////////////////////////////////
// [pipebuf] is a FIFO buffer with multiple readers.
// [pipewriter] is a client-side hook for writing into a [pipebuf].
// [pipereader] is a client-side hook reading from a [pipebuf].
// [runnable] is anything that moves data between [pipebufs].
// [scheduler] is a global context which invokes [runnables] until fixpoint.
static const int MAX_PIPES = 64;
static const int MAX_RUNNABLES = 64;
static const int MAX_READERS = 8;
struct pipebuf_common
{
virtual int sizeofT()
{
return 0;
}
virtual long long hash()
{
return 0;
}
virtual void dump(std::size_t *total_bufs __attribute__((unused)))
{
}
pipebuf_common(const char *_name) :
name(_name)
{
}
virtual ~pipebuf_common()
{
}
struct runnable_common {
const char *name;
runnable_common(const char *_name) : name(_name) { }
virtual void run() { }
virtual void shutdown() { }
};
struct runnable_common
{
runnable_common(const char *_name) :
name(_name)
{
}
virtual ~runnable_common()
{
}
virtual void run()
{
}
virtual void shutdown()
{
}
#ifdef DEBUG
~runnable_common() { fprintf(stderr, "Deallocating %s !\n", name); }
~runnable_common()
{ fprintf(stderr, "Deallocating %s !\n", name);}
#endif
};
struct window_placement {
const char *name;
};
struct window_placement
{
const char *name; // NULL to terminate
int x, y, w, h;
};
};
struct scheduler {
struct scheduler
{
pipebuf_common *pipes[MAX_PIPES];
int npipes;
runnable_common *runnables[MAX_RUNNABLES];
@ -56,213 +106,362 @@ namespace leansdr {
window_placement *windows;
bool verbose, debug;
scheduler()
: npipes(0), nrunnables(0), windows(NULL),
verbose(false), debug(false) {
scheduler() :
npipes(0), nrunnables(0), windows(NULL), verbose(false), debug(
false)
{
}
void add_pipe(pipebuf_common *p) {
if ( npipes == MAX_PIPES ) fail("MAX_PIPES");
pipes[npipes++] = p;
void add_pipe(pipebuf_common *p)
{
if (npipes == MAX_PIPES) {
fail("MAX_PIPES");
}
pipes[npipes++] = p;
}
void add_runnable(runnable_common *r) {
if ( nrunnables == MAX_RUNNABLES ) fail("MAX_RUNNABLES");
runnables[nrunnables++] = r;
void add_runnable(runnable_common *r)
{
if (nrunnables == MAX_RUNNABLES) {
fail("MAX_RUNNABLES");
}
runnables[nrunnables++] = r;
}
void step() {
for ( int i=0; i<nrunnables; ++i )
runnables[i]->run();
void step()
{
for (int i = 0; i < nrunnables; ++i) {
runnables[i]->run();
}
}
void run() {
unsigned long long prev_hash = 0;
while ( 1 ) {
step();
unsigned long long h = hash();
if ( h == prev_hash ) break;
prev_hash = h;
}
void run()
{
unsigned long long prev_hash = 0;
while (1)
{
step();
unsigned long long h = hash();
if (h == prev_hash) {
break;
}
prev_hash = h;
}
}
void shutdown() {
for ( int i=0; i<nrunnables; ++i )
runnables[i]->shutdown();
void shutdown()
{
for (int i = 0; i < nrunnables; ++i) {
runnables[i]->shutdown();
}
}
unsigned long long hash() {
unsigned long long h = 0;
for ( int i=0; i<npipes; ++i ) h += (1+i)*pipes[i]->hash();
return h;
unsigned long long hash()
{
unsigned long long h = 0;
for (int i = 0; i < npipes; ++i) {
h += (1 + i) * pipes[i]->hash();
}
return h;
}
void dump() {
fprintf(stderr, "\n");
size_t total_bufs = 0;
for ( int i=0; i<npipes; ++i ) pipes[i]->dump(&total_bufs);
fprintf(stderr, "Total buffer memory: %ld KiB\n",
(unsigned long)total_bufs/1024);
void dump()
{
fprintf(stderr, "\n");
std::size_t total_bufs = 0;
for (int i = 0; i < npipes; ++i) {
pipes[i]->dump(&total_bufs);
}
fprintf(stderr, "leansdr::scheduler::dump Total buffer memory: %ld KiB\n", (unsigned long) total_bufs / 1024);
}
};
struct runnable : runnable_common {
runnable(scheduler *_sch, const char *name)
: runnable_common(name), sch(_sch) {
sch->add_runnable(this);
};
struct runnable: runnable_common
{
runnable(scheduler *_sch, const char *name) :
runnable_common(name), sch(_sch)
{
sch->add_runnable(this);
}
protected:
protected:
scheduler *sch;
};
template<typename T>
struct pipebuf : pipebuf_common {
};
template<typename T>
struct pipebuf: pipebuf_common
{
T *buf;
T *rds[MAX_READERS];
int nrd;
T *wr;
T *end;
int sizeofT() { return sizeof(T); }
pipebuf(scheduler *sch, const char *name, unsigned long size)
: pipebuf_common(name),
buf(new T[size]), nrd(0), wr(buf), end(buf+size),
min_write(1),
total_written(0), total_read(0) {
sch->add_pipe(this);
int sizeofT()
{
return sizeof(T);
}
int add_reader() {
if ( nrd == MAX_READERS ) fail("too many readers");
rds[nrd] = wr;
return nrd++;
pipebuf(scheduler *sch, const char *name, unsigned long size) :
pipebuf_common(name), buf(new T[size]), nrd(0), wr(buf), end(
buf + size), min_write(1), total_written(0), total_read(0)
{
sch->add_pipe(this);
}
void pack() {
T *rd = wr;
for ( int i=0; i<nrd; ++i ) if ( rds[i] < rd ) rd = rds[i];
memmove(buf, rd, (wr-rd)*sizeof(T));
wr -= rd - buf;
for ( int i=0; i<nrd; ++i ) rds[i] -= rd - buf;
int add_reader()
{
if (nrd == MAX_READERS) {
fail("too many readers");
}
rds[nrd] = wr;
return nrd++;
}
long long hash() {
return total_written + total_read;
void pack()
{
T *rd = wr;
for (int i = 0; i < nrd; ++i)
{
if (rds[i] < rd) {
rd = rds[i];
}
}
memmove(buf, rd, (wr - rd) * sizeof(T));
wr -= rd - buf;
for (int i = 0; i < nrd; ++i) {
rds[i] -= rd - buf;
}
}
void dump(size_t *total_bufs) {
if ( total_written < 10000 )
fprintf(stderr, ".%-16s : %4ld/%4ld", name,
total_read, total_written);
else if ( total_written < 1000000 )
fprintf(stderr, ".%-16s : %3ldk/%3ldk", name,
total_read/1000, total_written/1000);
else
fprintf(stderr, ".%-16s : %3ldM/%3ldM", name,
total_read/1000000, total_written/1000000);
*total_bufs += (end-buf) * sizeof(T);
unsigned long nw = end - wr;
fprintf(stderr, " %6ld writable %c,", nw, (nw<min_write)?'!':' ');
T *rd = wr;
for ( int j=0; j<nrd; ++j ) if ( rds[j] < rd ) rd = rds[j];
fprintf(stderr, " %6d unread (", (int)(wr-rd));
for ( int j=0; j<nrd; ++j )
fprintf(stderr, " %d", (int)(wr-rds[j]));
fprintf(stderr, " )\n");
long long hash()
{
return total_written + total_read;
}
void dump(std::size_t *total_bufs)
{
if (total_written < 10000) {
fprintf(stderr, "leansdr::pipebuf::dump: .%-16s : %4ld/%4ld", name, total_read, total_written);
} else if (total_written < 1000000) {
fprintf(stderr, "leansdr::pipebuf::dump: .%-16s : %3ldk/%3ldk", name, total_read / 1000, total_written / 1000);
} else {
fprintf(stderr, "leansdr::pipebuf::dump: .%-16s : %3ldM/%3ldM", name, total_read / 1000000, total_written / 1000000);
}
*total_bufs += (end - buf) * sizeof(T);
unsigned long nw = end - wr;
fprintf(stderr, "leansdr::pipebuf: %6ld writable %c,", nw, (nw < min_write) ? '!' : ' ');
T *rd = wr;
for (int j = 0; j < nrd; ++j)
{
if (rds[j] < rd) {
rd = rds[j];
}
}
fprintf(stderr, "leansdr::pipebuf::dump: %6d unread (", (int) (wr - rd));
for (int j = 0; j < nrd; ++j) {
fprintf(stderr, "leansdr::pipebuf: %d", (int) (wr - rds[j]));
}
fprintf(stderr, "leansdr::pipebuf::dump: )\n");
}
unsigned long min_write;
unsigned long total_written, total_read;
#ifdef DEBUG
~pipebuf() { fprintf(stderr, "Deallocating %s !\n", name); }
~pipebuf()
{ fprintf(stderr, "Deallocating %s !\n", name);}
#endif
};
template<typename T>
struct pipewriter {
};
template<typename T>
struct pipewriter
{
pipebuf<T> &buf;
pipewriter(pipebuf<T> &_buf, unsigned long min_write=1)
: buf(_buf) {
if ( min_write > buf.min_write ) buf.min_write = min_write;
}
// Return number of items writable at this->wr, 0 if full.
unsigned long writable() {
if ( buf.end-buf.wr < buf.min_write ) buf.pack();
return buf.end - buf.wr;
}
T *wr() { return buf.wr; }
void written(unsigned long n) {
if ( buf.wr+n > buf.end ) {
fprintf(stderr, "Bug: overflow to %s\n", buf.name);
exit(1);
}
buf.wr += n;
buf.total_written += n;
}
void write(const T &e) {
*wr() = e;
written(1);
}
};
// Convenience functions for working with optional pipes
pipewriter(pipebuf<T> &_buf, unsigned long min_write = 1) :
buf(_buf)
{
if (min_write > buf.min_write) {
buf.min_write = min_write;
}
}
template<typename T>
pipewriter<T> *opt_writer(pipebuf<T> *buf) {
/** Return number of items writable at this->wr, 0 if full. */
unsigned long writable()
{
if (buf.end < buf.wr)
{
fprintf(stderr, "leansdr::pipewriter::writable: Bug: overflow to %s\n", buf.name);
exit(1);
}
unsigned long delta = buf.end - buf.wr;
if (delta < buf.min_write) {
buf.pack();
}
return delta;
}
T *wr()
{
return buf.wr;
}
void written(unsigned long n)
{
if (buf.wr + n > buf.end)
{
fprintf(stderr, "leansdr::pipewriter::written: Bug: overflow to %s\n", buf.name);
exit(1);
}
buf.wr += n;
buf.total_written += n;
}
void write(const T &e)
{
*wr() = e;
written(1);
}
};
// Convenience functions for working with optional pipes
template<typename T>
pipewriter<T> *opt_writer(pipebuf<T> *buf)
{
return buf ? new pipewriter<T>(*buf) : NULL;
}
}
template<typename T>
bool opt_writable(pipewriter<T> *p, int n=1) {
return (p==NULL) || p->writable()>=n;
}
template<typename T>
bool opt_writable(pipewriter<T> *p, unsigned int n = 1)
{
return (p == NULL) || p->writable() >= n;
}
template<typename T>
void opt_write(pipewriter<T> *p, T val) {
if ( p ) p->write(val);
}
template<typename T>
void opt_write(pipewriter<T> *p, T val)
{
if (p) {
p->write(val);
}
}
template<typename T>
struct pipereader {
template<typename T>
struct pipereader
{
pipebuf<T> &buf;
int id;
pipereader(pipebuf<T> &_buf) : buf(_buf), id(_buf.add_reader()) { }
unsigned long readable() { return buf.wr - buf.rds[id]; }
T *rd() { return buf.rds[id]; }
void read(unsigned long n) {
if ( buf.rds[id]+n > buf.wr ) {
fprintf(stderr, "Bug: underflow from %s\n", buf.name);
exit(1);
}
buf.rds[id] += n;
buf.total_read += n;
pipereader(pipebuf<T> &_buf) :
buf(_buf), id(_buf.add_reader())
{
}
};
// Math functions for templates
template<typename T> T gen_sqrt(T x);
inline float gen_sqrt(float x) { return sqrtf(x); }
inline unsigned int gen_sqrt(unsigned int x) { return sqrtl(x); }
inline long double gen_sqrt(long double x) { return sqrtl(x); }
template<typename T> T gen_abs(T x);
inline float gen_abs(float x) { return fabsf(x); }
inline int gen_abs(int x) { return abs(x); }
inline long int gen_abs(long int x) { return labs(x); }
unsigned long readable()
{
return buf.wr - buf.rds[id];
}
template<typename T> T gen_hypot(T x, T y);
inline float gen_hypot(float x, float y) { return hypotf(x,y); }
inline long double gen_hypot(long double x, long double y)
{ return hypotl(x,y); }
T *rd()
{
return buf.rds[id];
}
template<typename T> T gen_atan2(T y, T x);
inline float gen_atan2(float y, float x) { return atan2f(y,x); }
inline long double gen_atan2(long double y, long double x)
{ return atan2l(y,x); }
void read(unsigned long n)
{
if (buf.rds[id] + n > buf.wr)
{
fprintf(stderr, "leansdr::pipereader::read: Bug: underflow from %s\n", buf.name);
exit(1);
}
buf.rds[id] += n;
buf.total_read += n;
}
};
template<typename T>
T min(const T &x, const T &y) { return (x<y) ? x : y; }
// Math functions for templates
template<typename T>
T max(const T &x, const T &y) { return (x<y) ? y : x; }
template<typename T> T gen_sqrt(T x);
inline float gen_sqrt(float x)
{
return sqrtf(x);
}
// Abreviations for integer types
inline unsigned int gen_sqrt(unsigned int x)
{
return sqrtl(x);
}
typedef unsigned char u8;
typedef unsigned short u16;
typedef unsigned long u32;
typedef signed char s8;
typedef signed short s16;
typedef signed long s32;
inline long double gen_sqrt(long double x)
{
return sqrtl(x);
}
template<typename T> T gen_abs(T x);
inline float gen_abs(float x)
{
return fabsf(x);
}
inline int gen_abs(int x)
{
return abs(x);
}
inline long int gen_abs(long int x)
{
return labs(x);
}
template<typename T> T gen_hypot(T x, T y);
inline float gen_hypot(float x, float y)
{
return hypotf(x, y);
}
inline long double gen_hypot(long double x, long double y)
{
return hypotl(x, y);
}
template<typename T> T gen_atan2(T y, T x);
inline float gen_atan2(float y, float x)
{
return atan2f(y, x);
}
inline long double gen_atan2(long double y, long double x)
{
return atan2l(y, x);
}
template<typename T>
T min(const T &x, const T &y)
{
return (x < y) ? x : y;
}
template<typename T>
T max(const T &x, const T &y)
{
return (x < y) ? y : x;
}
// Abreviations for integer types
typedef unsigned char u8;
typedef unsigned short u16;
typedef unsigned long u32;
typedef signed char s8;
typedef signed short s16;
typedef signed long s32;
} // namespace

View File

@ -3,107 +3,144 @@
#include "leansdr/framework.h"
namespace leansdr {
namespace leansdr
{
// HDLC deframer
struct hdlc_dec {
// HDLC deframer
struct hdlc_dec
{
hdlc_dec(int _minframesize, // Including CRC, excluding HDLC flags.
int _maxframesize,
bool _invert)
: minframesize(_minframesize), maxframesize(_maxframesize),
invertmask(_invert?0xff:0),
framebuf(new u8[maxframesize]),
debug(false)
int _maxframesize, bool _invert) :
minframesize(_minframesize), maxframesize(_maxframesize), invertmask(
_invert ? 0xff : 0), framebuf(new u8[maxframesize]), debug(
false)
{
reset();
reset();
}
void reset()
{
shiftreg = 0;
inframe = false;
}
void begin_frame()
{
framesize = 0;
crc16 = crc16_init;
}
void reset() { shiftreg=0; inframe=false; }
void begin_frame() { framesize=0; crc16=crc16_init; }
// Decode (*ppin)[count] as MSB-packed HDLC bitstream.
// Return pointer to buffer[*pdatasize], or NULL if no valid frame.
// Return number of discarded bytes in *discarded.
// Return number of checksum errors in *fcs_errors.
// *ppin will have increased by at least 1 (unless count==0).
u8 *decode(u8 **ppin, int count,
int *pdatasize, int *hdlc_errors, int *fcs_errors) {
*hdlc_errors = 0;
*fcs_errors = 0;
*pdatasize = -1;
u8 *pin=*ppin, *pend=pin+count;
for ( ; pin<pend; ++pin ) {
u8 byte_in = (*pin) ^ invertmask;
for ( int bits=8; bits--; byte_in<<=1 ) {
u8 bit_in = byte_in & 128;
shiftreg = (shiftreg>>1) | bit_in;
if ( ! inframe ) {
if ( shiftreg == 0x7e ) { // HDLC flag 01111110
inframe = true;
nbits_out = 0;
begin_frame();
}
} else {
if ( (shiftreg&0xfe) == 0x7c ) { // 0111110x HDLC stuffing
// Unstuff this 0
} else if ( shiftreg == 0x7e ) { // 01111110 HDLC flag
if ( nbits_out != 7 ) {
// Not at byte boundary
if ( debug ) fprintf(stderr, "^");
++*hdlc_errors;
} else {
// Checksum
crc16 ^= 0xffff;
if ( framesize<2 || framesize<minframesize ||
crc16!=crc16_check ) {
if ( debug ) fprintf(stderr, "!");
++*hdlc_errors;
// Do not report random noise as FCS errors
if ( framesize >= minframesize ) ++*fcs_errors;
} else {
if ( debug ) fprintf(stderr, "_");
// This will trigger output, but we finish the byte first.
*pdatasize = framesize-2;
}
}
nbits_out = 0;
begin_frame();
// Keep processing up to 7 remaining bits from byte_in.
// Special cases 0111111 and 1111111 cannot affect *pdatasize.
} else if ( shiftreg == 0xfe ) { // 11111110 HDLC invalid
if ( framesize ) {
if ( debug ) fprintf(stderr, "^");
++*hdlc_errors;
}
inframe = false;
} else { // Data bit
byte_out = (byte_out>>1) | bit_in; // HDLC is LSB first
++nbits_out;
if ( nbits_out == 8 ) {
if ( framesize < maxframesize ) {
framebuf[framesize++] = byte_out;
crc16_byte(byte_out);
}
nbits_out = 0;
}
}
} // inframe
} // bits
if ( *pdatasize != -1 ) {
// Found a complete frame
*ppin = pin+1;
return framebuf;
}
}
*ppin = pin;
return NULL;
u8 *decode(u8 **ppin, int count, int *pdatasize, int *hdlc_errors,
int *fcs_errors)
{
*hdlc_errors = 0;
*fcs_errors = 0;
*pdatasize = -1;
u8 *pin = *ppin, *pend = pin + count;
for (; pin < pend; ++pin)
{
u8 byte_in = (*pin) ^ invertmask;
for (int bits = 8; bits--; byte_in <<= 1)
{
u8 bit_in = byte_in & 128;
shiftreg = (shiftreg >> 1) | bit_in;
if (!inframe)
{
if (shiftreg == 0x7e)
{ // HDLC flag 01111110
inframe = true;
nbits_out = 0;
begin_frame();
}
}
else
{
if ((shiftreg & 0xfe) == 0x7c)
{ // 0111110x HDLC stuffing
// Unstuff this 0
}
else if (shiftreg == 0x7e)
{ // 01111110 HDLC flag
if (nbits_out != 7)
{
// Not at byte boundary
if (debug)
fprintf(stderr, "^");
++*hdlc_errors;
}
else
{
// Checksum
crc16 ^= 0xffff;
if (framesize < 2 || framesize < minframesize
|| crc16 != crc16_check)
{
if (debug)
fprintf(stderr, "!");
++*hdlc_errors;
// Do not report random noise as FCS errors
if (framesize >= minframesize)
++*fcs_errors;
}
else
{
if (debug)
fprintf(stderr, "_");
// This will trigger output, but we finish the byte first.
*pdatasize = framesize - 2;
}
}
nbits_out = 0;
begin_frame();
// Keep processing up to 7 remaining bits from byte_in.
// Special cases 0111111 and 1111111 cannot affect *pdatasize.
}
else if (shiftreg == 0xfe)
{ // 11111110 HDLC invalid
if (framesize)
{
if (debug)
fprintf(stderr, "^");
++*hdlc_errors;
}
inframe = false;
}
else
{ // Data bit
byte_out = (byte_out >> 1) | bit_in; // HDLC is LSB first
++nbits_out;
if (nbits_out == 8)
{
if (framesize < maxframesize)
{
framebuf[framesize++] = byte_out;
crc16_byte(byte_out);
}
nbits_out = 0;
}
}
} // inframe
} // bits
if (*pdatasize != -1)
{
// Found a complete frame
*ppin = pin + 1;
return framebuf;
}
}
*ppin = pin;
return NULL;
}
private:
private:
// Config
int minframesize, maxframesize;
u8 invertmask;
@ -119,151 +156,170 @@ namespace leansdr {
static const u16 crc16_init = 0xffff;
static const u16 crc16_poly = 0x8408; // 0x1021 MSB-first
static const u16 crc16_check = 0x0f47;
void crc16_byte(u8 data) {
crc16 ^= data;
for ( int bit=8; bit--; )
crc16 = (crc16&1) ? (crc16>>1)^crc16_poly : (crc16>>1);
}
public:
bool debug;
}; // hdlc_dec
// HDLC synchronizer with polarity detection
struct hdlc_sync : runnable {
hdlc_sync(scheduler *sch,
pipebuf<u8> &_in, // Packed bits
pipebuf<u8> &_out, // Bytes
int _minframesize, // Including CRC, excluding HDLC flags.
int _maxframesize,
// Status
pipebuf<int> *_lock_out=NULL,
pipebuf<int> *_framecount_out=NULL,
pipebuf<int> *_fcserrcount_out=NULL,
pipebuf<int> *_hdlcbytecount_out=NULL,
pipebuf<int> *_databytecount_out=NULL)
: runnable(sch, "hdlc_sync"),
minframesize(_minframesize),
maxframesize(_maxframesize),
chunk_size(maxframesize+2),
in(_in), out(_out, _maxframesize+chunk_size),
lock_out(opt_writer(_lock_out)),
framecount_out(opt_writer(_framecount_out)),
fcserrcount_out(opt_writer(_fcserrcount_out)),
hdlcbytecount_out(opt_writer(_hdlcbytecount_out)),
databytecount_out(opt_writer(_databytecount_out)),
cur_sync(0), resync_phase(0),
lock_state(false),
resync_period(32),
header16(false)
void crc16_byte(u8 data)
{
for ( int s=0; s<NSYNCS; ++s ) {
syncs[s].dec = new hdlc_dec(minframesize, maxframesize, s!=0);
for ( int h=0; h<NERRHIST; ++h ) syncs[s].errhist[h] = 0;
}
syncs[cur_sync].dec->debug = sch->debug;
errslot = 0;
crc16 ^= data;
for (int bit = 8; bit--;)
crc16 = (crc16 & 1) ? (crc16 >> 1) ^ crc16_poly : (crc16 >> 1);
}
void run() {
if ( ! opt_writable(lock_out) ||
! opt_writable(framecount_out) ||
! opt_writable(fcserrcount_out) ||
! opt_writable(hdlcbytecount_out) ||
! opt_writable(databytecount_out) ) return;
public:
bool debug;
};
// hdlc_dec
bool previous_lock_state = lock_state;
int fcserrcount=0, framecount=0;
int hdlcbytecount=0, databytecount=0;
// HDLC synchronizer with polarity detection
// Note: hdlc_dec may already hold one frame ready for output.
while ( in.readable() >= chunk_size &&
out.writable() >= maxframesize+chunk_size ) {
if ( ! resync_phase ) {
// Once every resync_phase, try all decoders
for ( int s=0; s<NSYNCS; ++s ) {
if ( s != cur_sync ) syncs[s].dec->reset();
syncs[s].errhist[errslot] = 0;
for ( u8 *pin=in.rd(), *pend=pin+chunk_size; pin<pend; ) {
int datasize, hdlc_errors, fcs_errors;
u8 *f = syncs[s].dec->decode(&pin, pend-pin, &datasize,
&hdlc_errors, &fcs_errors);
syncs[s].errhist[errslot] += hdlc_errors;
if ( s == cur_sync ) {
if ( f ) {
lock_state = true;
output_frame(f, datasize);
databytecount += datasize;
++framecount;
}
fcserrcount += fcs_errors;
framecount += fcs_errors;
}
}
}
errslot = (errslot+1) % NERRHIST;
// Switch to another sync option ?
// Compare total error counts over about NERRHIST frames.
int total_errors[NSYNCS];
for ( int s=0; s<NSYNCS; ++s ) {
total_errors[s] = 0;
for ( int h=0; h<NERRHIST; ++h )
total_errors[s] += syncs[s].errhist[h];
}
int best = cur_sync;
for ( int s=0; s<NSYNCS; ++s )
if ( total_errors[s] < total_errors[best] ) best = s;
if ( best != cur_sync ) {
lock_state = false;
if ( sch->debug ) fprintf(stderr, "[%d:%d->%d:%d]",
cur_sync, total_errors[cur_sync],
best, total_errors[best]);
// No verbose messages on candidate syncs
syncs[cur_sync].dec->debug = false;
cur_sync = best;
syncs[cur_sync].dec->debug = sch->debug;
}
} else {
// Use only the currently selected decoder
for ( u8 *pin=in.rd(), *pend=pin+chunk_size; pin<pend; ) {
int datasize, hdlc_errors, fcs_errors;
u8 *f = syncs[cur_sync].dec->decode(&pin, pend-pin, &datasize,
&hdlc_errors, &fcs_errors);
if ( f ) {
lock_state = true;
output_frame(f, datasize);
databytecount += datasize;
++framecount;
}
fcserrcount += fcs_errors;
framecount += fcs_errors;
}
} // resync_phase
in.read(chunk_size);
hdlcbytecount += chunk_size;
if ( ++resync_phase >= resync_period ) resync_phase = 0;
} // Work to do
if ( lock_state != previous_lock_state )
opt_write(lock_out, lock_state?1:0);
opt_write(framecount_out, framecount);
opt_write(fcserrcount_out, fcserrcount);
opt_write(hdlcbytecount_out, hdlcbytecount);
opt_write(databytecount_out, databytecount);
struct hdlc_sync: runnable
{
hdlc_sync(scheduler *sch,
pipebuf<u8> &_in, // Packed bits
pipebuf<u8> &_out, // Bytes
int _minframesize, // Including CRC, excluding HDLC flags.
int _maxframesize,
// Status
pipebuf<int> *_lock_out = NULL,
pipebuf<int> *_framecount_out = NULL,
pipebuf<int> *_fcserrcount_out = NULL,
pipebuf<int> *_hdlcbytecount_out = NULL,
pipebuf<int> *_databytecount_out = NULL) :
runnable(sch, "hdlc_sync"), minframesize(_minframesize), maxframesize(
_maxframesize), chunk_size(maxframesize + 2), in(_in), out(
_out, _maxframesize + chunk_size), lock_out(
opt_writer(_lock_out)), framecount_out(
opt_writer(_framecount_out)), fcserrcount_out(
opt_writer(_fcserrcount_out)), hdlcbytecount_out(
opt_writer(_hdlcbytecount_out)), databytecount_out(
opt_writer(_databytecount_out)), cur_sync(0), resync_phase(
0), lock_state(false), resync_period(32), header16(false)
{
for (int s = 0; s < NSYNCS; ++s)
{
syncs[s].dec = new hdlc_dec(minframesize, maxframesize, s != 0);
for (int h = 0; h < NERRHIST; ++h)
syncs[s].errhist[h] = 0;
}
syncs[cur_sync].dec->debug = sch->debug;
errslot = 0;
}
private:
void output_frame(u8 *f, int size) {
if ( header16 ) {
// Removed 16-bit CRC, add 16-bit prefix -> Still <= maxframesize.
out.write(size >> 8);
out.write(size & 255);
}
memcpy(out.wr(), f, size);
out.written(size);
opt_write(framecount_out, 1);
void run()
{
if (!opt_writable(lock_out) || !opt_writable(framecount_out)
|| !opt_writable(fcserrcount_out)
|| !opt_writable(hdlcbytecount_out)
|| !opt_writable(databytecount_out))
return;
bool previous_lock_state = lock_state;
int fcserrcount = 0, framecount = 0;
int hdlcbytecount = 0, databytecount = 0;
// Note: hdlc_dec may already hold one frame ready for output.
while ((long) in.readable() >= chunk_size
&& (long) out.writable() >= maxframesize + chunk_size)
{
if (!resync_phase)
{
// Once every resync_phase, try all decoders
for (int s = 0; s < NSYNCS; ++s)
{
if (s != cur_sync)
syncs[s].dec->reset();
syncs[s].errhist[errslot] = 0;
for (u8 *pin = in.rd(), *pend = pin + chunk_size;
pin < pend;)
{
int datasize, hdlc_errors, fcs_errors;
u8 *f = syncs[s].dec->decode(&pin, pend - pin,
&datasize, &hdlc_errors, &fcs_errors);
syncs[s].errhist[errslot] += hdlc_errors;
if (s == cur_sync)
{
if (f)
{
lock_state = true;
output_frame(f, datasize);
databytecount += datasize;
++framecount;
}
fcserrcount += fcs_errors;
framecount += fcs_errors;
}
}
}
errslot = (errslot + 1) % NERRHIST;
// Switch to another sync option ?
// Compare total error counts over about NERRHIST frames.
int total_errors[NSYNCS];
for (int s = 0; s < NSYNCS; ++s)
{
total_errors[s] = 0;
for (int h = 0; h < NERRHIST; ++h)
total_errors[s] += syncs[s].errhist[h];
}
int best = cur_sync;
for (int s = 0; s < NSYNCS; ++s)
if (total_errors[s] < total_errors[best])
best = s;
if (best != cur_sync)
{
lock_state = false;
if (sch->debug)
fprintf(stderr, "[%d:%d->%d:%d]", cur_sync,
total_errors[cur_sync], best,
total_errors[best]);
// No verbose messages on candidate syncs
syncs[cur_sync].dec->debug = false;
cur_sync = best;
syncs[cur_sync].dec->debug = sch->debug;
}
}
else
{
// Use only the currently selected decoder
for (u8 *pin = in.rd(), *pend = pin + chunk_size; pin < pend;)
{
int datasize, hdlc_errors, fcs_errors;
u8 *f = syncs[cur_sync].dec->decode(&pin, pend - pin,
&datasize, &hdlc_errors, &fcs_errors);
if (f)
{
lock_state = true;
output_frame(f, datasize);
databytecount += datasize;
++framecount;
}
fcserrcount += fcs_errors;
framecount += fcs_errors;
}
} // resync_phase
in.read(chunk_size);
hdlcbytecount += chunk_size;
if (++resync_phase >= resync_period)
resync_phase = 0;
} // Work to do
if (lock_state != previous_lock_state)
opt_write(lock_out, lock_state ? 1 : 0);
opt_write(framecount_out, framecount);
opt_write(fcserrcount_out, fcserrcount);
opt_write(hdlcbytecount_out, hdlcbytecount);
opt_write(databytecount_out, databytecount);
}
private:
void output_frame(u8 *f, int size)
{
if (header16)
{
// Removed 16-bit CRC, add 16-bit prefix -> Still <= maxframesize.
out.write(size >> 8);
out.write(size & 255);
}
memcpy(out.wr(), f, size);
out.written(size);
opt_write(framecount_out, 1);
}
int minframesize, maxframesize;
@ -275,19 +331,21 @@ namespace leansdr {
pipewriter<int> *hdlcbytecount_out, *databytecount_out;
static const int NSYNCS = 2; // Two possible polarities
static const int NERRHIST = 2; // Compare error counts over two frames
struct {
hdlc_dec *dec;
int errhist[NERRHIST];
struct
{
hdlc_dec *dec;
int errhist[NERRHIST];
} syncs[NSYNCS];
int errslot;
int cur_sync;
int resync_phase;
bool lock_state;
public:
public:
int resync_period;
bool header16; // Output length prefix
}; // hdlc_sync
};
// hdlc_sync
} // namespace
}// namespace
#endif // LEANSDR_HDLC_H

File diff suppressed because it is too large Load Diff