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:
parent
2e5cfcafee
commit
3354c774fc
@ -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)
|
||||
|
@ -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}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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
@ -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
|
||||
|
||||
|
@ -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
Loading…
Reference in New Issue
Block a user