1
0
mirror of https://github.com/f4exb/sdrangel.git synced 2025-09-03 05:37:50 -04: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) add_subdirectory(demoddsd)
endif(LIBDSDCC_FOUND AND LIBMBE_FOUND) endif(LIBDSDCC_FOUND AND LIBMBE_FOUND)
if (NOT RX_SAMPLE_24BIT) #if (NOT RX_SAMPLE_24BIT)
add_subdirectory(demoddatv) add_subdirectory(demoddatv)
endif() #endif()
if (BUILD_DEBIAN) if (BUILD_DEBIAN)
add_subdirectory(demoddsd) add_subdirectory(demoddsd)

View File

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

View File

@ -27,72 +27,82 @@
namespace leansdr 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;
void run()
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()
{
//Symbols //Symbols
while ( in.readable() >= pixels_per_frame ) while (in.readable() >= pixels_per_frame)
{ {
if ( ! phase ) if (!phase)
{ {
m_objDATVScreen->resetImage(); 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->selectRow(
m_objDATVScreen->setDataColor(256- 256*((p->im-xymin)/(xymax-xymin)),255,0,255); 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 ) 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 )
{ {
m_objDATVScreen->selectRow(x+d); complex<signed char> *p = &(*cstln)->symbols[i];
m_objDATVScreen->setDataColor(y,5,250,250); int x = 256 * (p->re - xymin) / (xymax - xymin);
m_objDATVScreen->selectRow(x); int y = 256 - 256 * (p->im - xymin) / (xymax - xymin);
m_objDATVScreen->setDataColor(y+d,5,250,250);
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); m_objDATVScreen->renderImage(NULL);
@ -101,27 +111,25 @@ namespace leansdr
in.read(pixels_per_frame); in.read(pixels_per_frame);
if ( ++phase >= decimation ) if (++phase >= decimation)
{ {
phase = 0; phase = 0;
} }
} }
} }
//private: //private:
pipereader< complex<T> > in; //gfx g;
unsigned long phase;
//gfx g;
void draw_begin() void draw_begin()
{ {
//g.clear(); //g.clear();
//g.setfg(0, 255, 0); //g.setfg(0, 255, 0);
//g.line(g.w/2,0, g.w/2, g.h); //g.line(g.w/2,0, g.w/2, g.h);
//g.line(0,g.h/2, g.w,g.h/2); //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) : DATVDemod::DATVDemod(DeviceSourceAPI *deviceAPI) :
ChannelSinkAPI(m_channelIdURI), 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_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"); setObjectName("DATVDemod");
qDebug("DATVDemod::DATVDemod: sizeof FixReal: %lu: SDR_RX_SAMP_SZ: %u", sizeof(FixReal), (unsigned int) SDR_RX_SAMP_SZ);
//*************** DATV PARAMETERS *************** //*************** DATV PARAMETERS ***************
m_blnInitialized=false; m_blnInitialized=false;
CleanUpDATVFramework(false); CleanUpDATVFramework();
m_objVideoStream = new DATVideostream(); m_objVideoStream = new DATVideostream();
@ -102,6 +103,7 @@ DATVDemod::~DATVDemod()
bool DATVDemod::SetDATVScreen(DATVScreen *objScreen) bool DATVDemod::SetDATVScreen(DATVScreen *objScreen)
{ {
m_objRegisteredDATVScreen = objScreen; m_objRegisteredDATVScreen = objScreen;
return true;
} }
DATVideostream * DATVDemod::SetVideoRender(DATVideoRender *objScreen) DATVideostream * DATVDemod::SetVideoRender(DATVideoRender *objScreen)
@ -240,185 +242,185 @@ void DATVDemod::InitDATVParameters(int intMsps,
m_blnInitialized=true; m_blnInitialized=true;
} }
void DATVDemod::CleanUpDATVFramework(bool blnRelease) void DATVDemod::CleanUpDATVFramework()
{ {
//if(blnRelease==true) //if(blnRelease==true)
if(false) // if (false)
{ // {
if(m_objScheduler!=NULL) // if(m_objScheduler!=NULL)
{ // {
m_objScheduler->shutdown(); // m_objScheduler->shutdown();
delete m_objScheduler; // 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 m_objScheduler = 0;
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;
// INPUT // INPUT
p_rawiq = NULL; p_rawiq = 0;
p_rawiq_writer = NULL; p_rawiq_writer = 0;
p_preprocessed = NULL; p_preprocessed = 0;
// NOTCH FILTER // NOTCH FILTER
r_auto_notch = NULL; r_auto_notch = 0;
p_autonotched = NULL; p_autonotched = 0;
// FREQUENCY CORRECTION : DEROTATOR // FREQUENCY CORRECTION : DEROTATOR
p_derot = NULL; p_derot = 0;
r_derot=NULL; r_derot = 0;
// CNR ESTIMATION // CNR ESTIMATION
p_cnr = NULL; p_cnr = 0;
r_cnr = NULL; r_cnr = 0;
//FILTERING //FILTERING
r_resample = NULL; r_resample = 0;
p_resampled = NULL; p_resampled = 0;
coeffs = NULL; coeffs = 0;
ncoeffs=0; ncoeffs = 0;
// OUTPUT PREPROCESSED DATA // OUTPUT PREPROCESSED DATA
sampler = NULL; sampler = 0;
coeffs_sampler=NULL; coeffs_sampler = 0;
ncoeffs_sampler=0; ncoeffs_sampler = 0;
p_symbols = NULL; p_symbols = 0;
p_freq = NULL; p_freq = 0;
p_ss = NULL; p_ss = 0;
p_mer = NULL; p_mer = 0;
p_sampled = NULL; p_sampled = 0;
//DECIMATION //DECIMATION
p_decimated = NULL; p_decimated = 0;
p_decim = NULL; p_decim = 0;
r_ppout = NULL; r_ppout = 0;
//GENERIC CONSTELLATION RECEIVER //GENERIC CONSTELLATION RECEIVER
m_objDemodulator = NULL; m_objDemodulator = 0;
//DECONVOLUTION AND SYNCHRONIZATION //DECONVOLUTION AND SYNCHRONIZATION
p_bytes=NULL; p_bytes = 0;
r_deconv=NULL; r_deconv = 0;
r = NULL; r = 0;
p_descrambled = NULL; p_descrambled = 0;
p_frames = NULL; p_frames = 0;
r_etr192_descrambler = NULL; r_etr192_descrambler = 0;
r_sync = NULL; r_sync = 0;
p_mpegbytes = NULL; p_mpegbytes = 0;
p_lock = NULL; p_lock = 0;
p_locktime = NULL; p_locktime = 0;
r_sync_mpeg = NULL; r_sync_mpeg = 0;
// DEINTERLEAVING // DEINTERLEAVING
p_rspackets = NULL; p_rspackets = 0;
r_deinter = NULL; r_deinter = 0;
p_vbitcount = NULL; p_vbitcount = 0;
p_verrcount = NULL; p_verrcount = 0;
p_rtspackets = NULL; p_rtspackets = 0;
r_rsdec = NULL; r_rsdec = 0;
//BER ESTIMATION //BER ESTIMATION
p_vber = NULL; p_vber = 0;
r_vber = NULL; r_vber = 0;
// DERANDOMIZATION // DERANDOMIZATION
p_tspackets = NULL; p_tspackets = 0;
r_derand = NULL; r_derand = 0;
//OUTPUT : To remove //OUTPUT : To remove
r_stdout = NULL; r_stdout = 0;
r_videoplayer = NULL; r_videoplayer = 0;
//CONSTELLATION //CONSTELLATION
r_scope_symbols = NULL; r_scope_symbols = 0;
} }
void DATVDemod::InitDATVFramework() void DATVDemod::InitDATVFramework()
@ -516,7 +518,7 @@ void DATVDemod::InitDATVFramework()
m_lngExpectedReadIQ = BUF_BASEBAND; m_lngExpectedReadIQ = BUF_BASEBAND;
CleanUpDATVFramework(true); CleanUpDATVFramework();
m_objScheduler = new scheduler(); m_objScheduler = new scheduler();
@ -819,7 +821,7 @@ void DATVDemod::InitDATVFramework()
m_blnDVBInitialized=true; 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 fltI;
float fltQ; float fltQ;
@ -964,12 +966,12 @@ bool DATVDemod::handleMessage(const Message& cmd)
m_channelizer->configure(m_channelizer->getInputMessageQueue(), m_channelizer->configure(m_channelizer->getInputMessageQueue(),
m_channelizer->getInputSampleRate(), m_channelizer->getInputSampleRate(),
m_objRunning.intCenterFrequency); cfg.getCenterFrequency());
//m_objRunning.intCenterFrequency);
qDebug() << "DATVDemod::handleMessage: MsgConfigureChannelizer: sampleRate: " << m_channelizer->getInputSampleRate()
<< " centerFrequency: " << cfg.getCenterFrequency();
qDebug() << "ATVDemod::handleMessage: MsgConfigureChannelizer: sampleRate: " << m_channelizer->getInputSampleRate() //<< " centerFrequency: " << m_objRunning.intCenterFrequency;
<< " centerFrequency: " << m_objRunning.intCenterFrequency;
return true; return true;
} }

View File

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

View File

@ -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; return false;
} }
@ -233,7 +233,7 @@ void DATVDemodGUI::channelSampleRateChanged()
applySettings(); applySettings();
} }
void DATVDemodGUI::onWidgetRolled(QWidget* widget, bool rollDown) void DATVDemodGUI::onWidgetRolled(QWidget* widget __attribute__((unused)), bool rollDown __attribute__((unused)))
{ {
} }
@ -506,12 +506,12 @@ void DATVDemodGUI::tick()
return; return;
} }
void DATVDemodGUI::on_cmbStandard_currentIndexChanged(const QString &arg1) void DATVDemodGUI::on_cmbStandard_currentIndexChanged(const QString &arg1 __attribute__((unused)))
{ {
applySettings(); applySettings();
} }
void DATVDemodGUI::on_cmbModulation_currentIndexChanged(const QString &arg1) void DATVDemodGUI::on_cmbModulation_currentIndexChanged(const QString &arg1 __attribute__((unused)))
{ {
QString strModulation; QString strModulation;
QString strFEC; QString strFEC;
@ -563,7 +563,7 @@ 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; QString strFEC;
@ -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(); applySettings();
} }
void DATVDemodGUI::on_spiNotchFilters_valueChanged(int arg1) void DATVDemodGUI::on_spiNotchFilters_valueChanged(int arg1 __attribute__((unused)))
{ {
applySettings(); applySettings();
} }
@ -701,7 +701,7 @@ void DATVDemodGUI::on_pushButton_4_clicked()
} }
void DATVDemodGUI::on_mouseEvent(QMouseEvent* obj) void DATVDemodGUI::on_mouseEvent(QMouseEvent* obj __attribute__((unused)))
{ {
} }
@ -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))); ui->lblStatus->setText(QString("Decod: %1B").arg(formatBytes(*intTotalReceived)));
m_intLastDecodedData = *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(); applySettings();
} }

View File

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

File diff suppressed because it is too large Load Diff

View File

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

View File

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

File diff suppressed because it is too large Load Diff