1
0
mirror of https://github.com/f4exb/sdrangel.git synced 2026-07-27 12:34:18 -04:00
Files
sdrangel/plugins/channelrx/demoddatv/datvdemodsink.cpp
T
Robin Getz e86e95feab DATV: Convert leansdr fail and fatal errors into C++ exceptions
The original leansdr code uses fatal() and fail() for unrecoverable errors by
terminating execution. When integrated into SDRangel, these error paths did
not provide a mechanism for the plugin to handle failures locally, allowing
initialization failures to escape the normal plugin lifecycle.

Convert leansdr fatal() and fail() handling into C++ exceptions so DATV can
detect framework initialization failures, report them, and cleanly return
control to SDRangel instead of allowing the error to terminate the application.
This behavior is desirable because a DATV framework configuration failure
should not bring down the entire application.

Catch initialization exceptions in DATVDemodSink::feed(), report the failure,
clean up the partially initialized framework, and return to the caller.

Add noreturn annotations to the leansdr error functions and include the
leansdr source in exception messages to make failures easier to diagnose.

This does not redesign leansdr error handling or provide recovery from
runtime DSP failures. It only adds an exception boundary between the
leansdr library code and the SDRangel plugin lifecycle.

noticed via cppcheck indicating many Array indexes could go out of bounds
due to fail and fatal returning.

Signed-off-by: Robin Getz <rgetz503@gmail.com>
2026-07-25 18:50:40 -04:00

1533 lines
50 KiB
C++

///////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2018-2021, 2023 Edouard Griffiths, F4EXB <f4exb06@gmail.com> //
// Copyright (C) 2022 Jiří Pinkava <jiri.pinkava@rossum.ai> //
// Copyright (C) 2022 Jon Beniston, M7RCE <jon@beniston.com> //
// //
// This program is free software; you can redistribute it and/or modify //
// it under the terms of the GNU General Public License as published by //
// the Free Software Foundation as version 3 of the License, or //
// (at your option) any later version. //
// //
// This program is distributed in the hope that it will be useful, //
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
// GNU General Public License V3 for more details. //
// //
// You should have received a copy of the GNU General Public License //
// along with this program. If not, see <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#ifndef SERVER_MODE
#include "datvideorender.h"
#endif
#include "datvcstlnlut.h"
#include "datvdemodsink.h"
#include "leansdr/dvbs2.h"
#include <QDebug>
#include <QObject>
#include <QFileInfo>
#include <QMutexLocker>
#include "datvdemodreport.h"
#ifndef SERVER_MODE
#include "datvideorender.h"
#endif
const unsigned int DATVDemodSink::m_rfFilterFftLength = 512;
DATVDemodSink::DATVDemodSink() :
m_blnNeedConfigUpdate(false),
m_tvScreen(nullptr),
#ifndef SERVER_MODE
m_videoRender(nullptr),
#endif
m_videoStream(new DATVideostream()),
m_udpStream(leansdr::tspacket::SIZE),
m_videoThread(nullptr),
m_audioFifo(48000),
m_blnRenderingVideo(false),
m_cstlnSetByModcod(false),
m_modcodModulation(-1),
m_modcodCodeRate(-1),
m_enmModulation(DATVDemodSettings::BPSK /*DATV_FM1*/),
m_channelSampleRate(1024000),
m_messageQueueToGUI(nullptr)
{
//*************** DATV PARAMETERS ***************
m_blnInitialized=false;
ResetDATVFrameworkPointers();
}
DATVDemodSink::~DATVDemodSink()
{
m_blnInitialized = false;
//Immediately exit from DATVideoStream if waiting for data before killing thread
m_videoStream->setThreadTimeout(0);
m_videoStream->deleteLater();
stopVideo();
CleanUpDATVFramework();
#ifndef SERVER_MODE
if (m_videoThread) {
delete m_videoThread;
}
#endif
}
void DATVDemodSink::stopVideo()
{
#ifndef SERVER_MODE
if (m_videoThread)
{
if (m_videoThread->isRunning())
{
m_videoThread->stopRendering();
m_videoThread->quit();
m_videoThread->wait();
}
}
#endif
}
void DATVDemodSink::setTVScreen(TVScreen *tvScreen)
{
m_tvScreen = tvScreen;
}
void DATVDemodSink::SetVideoRender(DATVideoRender *screen)
{
#ifndef SERVER_MODE
m_videoRender = screen;
m_videoRender->setAudioFIFO(&m_audioFifo);
m_videoThread = new DATVideoRenderThread(m_videoRender, m_videoStream);
m_videoThread->setObjectName("vtDATVDemodSink");
#else
(void) screen;
#endif
}
bool DATVDemodSink::audioActive()
{
#ifndef SERVER_MODE
if (m_videoRender) {
return m_videoRender->getAudioStreamIndex() >= 0;
} else {
return false;
}
#else
return false;
#endif
}
bool DATVDemodSink::videoActive()
{
#ifndef SERVER_MODE
if (m_videoRender) {
return m_videoRender->getVideoStreamIndex() >= 0;
} else {
return false;
}
#else
return false;
#endif
}
bool DATVDemodSink::audioDecodeOK()
{
#ifndef SERVER_MODE
if (m_videoRender) {
return m_videoRender->getAudioDecodeOK();
} else {
return false;
}
#else
return false;
#endif
}
bool DATVDemodSink::videoDecodeOK()
{
#ifndef SERVER_MODE
if (m_videoRender) {
return m_videoRender->getVideoDecodeOK();
} else {
return false;
}
#else
return false;
#endif
}
bool DATVDemodSink::udpRunning()
{
if (!r_videoplayer) {
return false;
}
bool udpRunning = r_videoplayer->isUDPRunning();
return udpRunning;
}
bool DATVDemodSink::playVideo()
{
QMutexLocker mlock(&m_mutex);
#ifndef SERVER_MODE
if (m_videoStream == nullptr) {
return false;
}
if (m_videoRender == nullptr) {
return false;
}
if (m_videoThread == nullptr) {
return false;
}
if (m_videoThread->isRunning()) {
return true;
}
if (m_videoStream->bytesAvailable() > 0)
{
m_videoStream->setMultiThreaded(true);
m_videoStream->setThreadTimeout(DATVideoRenderThread::videoThreadTimeoutMs);
m_videoThread->start();
}
#endif
return false;
}
void DATVDemodSink::CleanUpDATVFramework()
{
if (m_videoStream) {
m_videoStream->cleanUp();
}
if (m_objScheduler != nullptr)
{
m_objScheduler->shutdown();
delete m_objScheduler;
}
// NOTCH FILTER
if (r_auto_notch != nullptr) {
delete r_auto_notch;
}
if (p_autonotched != nullptr) {
delete p_autonotched;
}
// FREQUENCY CORRECTION : DEROTATOR
if (p_derot != nullptr) {
delete p_derot;
}
if (r_derot != nullptr) {
delete r_derot;
}
// CNR ESTIMATION
if (p_cnr != nullptr) {
delete p_cnr;
}
if (r_cnr != nullptr) {
delete r_cnr;
}
if (r_cnrMeter != nullptr) {
delete r_cnrMeter;
}
//FILTERING
if (r_resample != nullptr) {
delete r_resample;
}
if (p_resampled != nullptr) {
delete p_resampled;
}
if (coeffs != nullptr) {
delete coeffs;
}
// OUTPUT PREPROCESSED DATA
if (sampler != nullptr) {
delete sampler;
}
if (coeffs_sampler != nullptr) {
delete coeffs_sampler;
}
if (p_symbols != nullptr) {
delete p_symbols;
}
if (p_freq != nullptr) {
delete p_freq;
}
if (p_ss != nullptr) {
delete p_ss;
}
if (p_mer != nullptr) {
delete p_mer;
}
if (r_merMeter != nullptr) {
delete r_merMeter;
}
if (p_sampled != nullptr) {
delete p_sampled;
}
//DECIMATION
if (p_decimated != nullptr) {
delete p_decimated;
}
if (p_decim != nullptr) {
delete p_decim;
}
if (r_ppout != nullptr) {
delete r_ppout;
}
//GENERIC CONSTELLATION RECEIVER
if (m_objDemodulator != nullptr) {
delete m_objDemodulator;
}
//DECONVOLUTION AND SYNCHRONIZATION
if (p_bytes != nullptr) {
delete p_bytes;
}
if (r_deconv != nullptr) {
delete r_deconv;
}
if (r != nullptr) {
delete r;
}
if (p_descrambled != nullptr) {
delete p_descrambled;
}
if (p_frames != nullptr) {
delete p_frames;
}
if (r_etr192_descrambler != nullptr) {
delete r_etr192_descrambler;
}
if (r_sync != nullptr) {
delete r_sync;
}
if (p_mpegbytes != nullptr) {
delete p_mpegbytes;
}
if (p_lock != nullptr) {
delete p_lock;
}
if (p_locktime != nullptr) {
delete p_locktime;
}
if (r_sync_mpeg != nullptr) {
delete r_sync_mpeg;
}
// DEINTERLEAVING
if (p_rspackets != nullptr) {
delete p_rspackets;
}
if (r_deinter != nullptr) {
delete r_deinter;
}
if (p_vbitcount != nullptr) {
delete p_vbitcount;
}
if (p_verrcount != nullptr) {
delete p_verrcount;
}
if (p_rtspackets != nullptr) {
delete p_rtspackets;
}
if (r_rsdec != nullptr) {
delete r_rsdec;
}
//BER ESTIMATION
if (p_vber != nullptr) {
delete p_vber;
}
if (r_vber != nullptr) {
delete r_vber;
}
// DERANDOMIZATION
if (p_tspackets != nullptr) {
delete p_tspackets;
}
if (r_derand != nullptr) {
delete r_derand;
}
//OUTPUT
if (r_videoplayer != nullptr) {
delete r_videoplayer;
}
//CONSTELLATION
#ifndef SERVER_MODE
if (r_scope_symbols != nullptr) {
delete r_scope_symbols;
}
#endif
// INPUT
if (p_rawiq != nullptr) {
delete p_rawiq;
}
if (p_rawiq_writer != nullptr) {
delete p_rawiq_writer;
}
//if(p_preprocessed!=nullptr) delete p_preprocessed;
//DVB-S2
if (p_slots_dvbs2 != nullptr) {
delete (leansdr::pipebuf< leansdr::plslot<leansdr::llr_ss> >*) p_slots_dvbs2;
}
if (p_cstln != nullptr) {
delete p_cstln;
}
if (p_cstln_pls != nullptr) {
delete p_cstln_pls;
}
if (p_framelock != nullptr) {
delete p_framelock;
}
if (m_objDemodulatorDVBS2 != nullptr) {
delete (leansdr::s2_frame_receiver<leansdr::f32, leansdr::llr_ss>*) m_objDemodulatorDVBS2;
}
if (p_fecframes != nullptr) {
delete (leansdr::pipebuf< leansdr::fecframe<leansdr::hard_sb> >*) p_fecframes;
}
if (p_bbframes != nullptr) {
delete (leansdr::pipebuf<leansdr::bbframe>*) p_bbframes;
}
if (p_s2_deinterleaver != nullptr) {
delete (leansdr::s2_deinterleaver<leansdr::llr_ss,leansdr::hard_sb>*) p_s2_deinterleaver;
}
if (r_fecdec != nullptr) {
delete (leansdr::s2_fecdec<bool, leansdr::hard_sb>*) r_fecdec;
}
#if 0
if (r_fecdecsoft != nullptr) {
delete (leansdr::s2_fecdec_soft<leansdr::llr_t,leansdr::llr_sb>*) r_fecdecsoft;
}
#endif
if (r_fecdechelper != nullptr) {
delete (leansdr::s2_fecdec_helper<leansdr::llr_t,leansdr::llr_sb>*) r_fecdechelper;
}
if (p_deframer != nullptr) {
delete (leansdr::s2_deframer*) p_deframer;
}
#ifndef SERVER_MODE
if (r_scope_symbols_dvbs2 != nullptr) {
delete r_scope_symbols_dvbs2;
}
#endif
ResetDATVFrameworkPointers();
}
void DATVDemodSink::ResetDATVFrameworkPointers()
{
// INPUT
m_objScheduler = nullptr;
p_rawiq = nullptr;
p_rawiq_writer = nullptr;
p_preprocessed = nullptr;
// NOTCH FILTER
r_auto_notch = nullptr;
p_autonotched = nullptr;
// FREQUENCY CORRECTION : DEROTATOR
p_derot = nullptr;
r_derot=nullptr;
// CNR ESTIMATION
p_cnr = nullptr;
r_cnr = nullptr;
r_cnrMeter = nullptr;
//FILTERING
r_resample = nullptr;
p_resampled = nullptr;
coeffs = nullptr;
ncoeffs=0;
// OUTPUT PREPROCESSED DATA
sampler = nullptr;
coeffs_sampler = nullptr;
ncoeffs_sampler = 0;
p_symbols = nullptr;
p_freq = nullptr;
p_ss = nullptr;
p_mer = nullptr;
r_merMeter = nullptr;
p_sampled = nullptr;
//DECIMATION
p_decimated = nullptr;
p_decim = nullptr;
r_ppout = nullptr;
//GENERIC CONSTELLATION RECEIVER
m_objDemodulator = nullptr;
//DECONVOLUTION AND SYNCHRONIZATION
p_bytes = nullptr;
r_deconv = nullptr;
r = nullptr;
p_descrambled = nullptr;
p_frames = nullptr;
r_etr192_descrambler = nullptr;
r_sync = nullptr;
p_mpegbytes = nullptr;
p_lock = nullptr;
p_locktime = nullptr;
r_sync_mpeg = nullptr;
// DEINTERLEAVING
p_rspackets = nullptr;
r_deinter = nullptr;
p_vbitcount = nullptr;
p_verrcount = nullptr;
p_rtspackets = nullptr;
r_rsdec = nullptr;
//BER ESTIMATION
p_vber = nullptr;
r_vber = nullptr;
// DERANDOMIZATION
p_tspackets = nullptr;
r_derand = nullptr;
//OUTPUT : To remove void *
r_videoplayer = nullptr;
//CONSTELLATION
#ifndef SERVER_MODE
r_scope_symbols = nullptr;
#endif
//DVB-S2
p_slots_dvbs2 = nullptr;
p_cstln = nullptr;
p_cstln_pls = nullptr;
p_framelock = nullptr;
m_objDemodulatorDVBS2 = nullptr;
p_fecframes = nullptr;
p_bbframes = nullptr;
p_s2_deinterleaver = nullptr;
r_fecdec = nullptr;
r_fecdecsoft = nullptr;
r_fecdechelper = nullptr;
p_deframer = nullptr;
#ifndef SERVER_MODE
r_scope_symbols_dvbs2 = nullptr;
#endif
}
void DATVDemodSink::InitDATVFramework()
{
m_blnDVBInitialized = false;
m_lngReadIQ = 0;
CleanUpDATVFramework();
qDebug() << "DATVDemodSink::InitDATVFramework:"
<< " Standard: " << m_settings.m_standard
<< " Symbol Rate: " << m_settings.m_symbolRate
<< " Modulation: " << m_settings.m_modulation
<< " Notch Filters: " << m_settings.m_notchFilters
<< " Allow Drift: " << m_settings.m_allowDrift
<< " Fast Lock: " << m_settings.m_fastLock
<< " Filter: " << m_settings.m_filter
<< " HARD METRIC: " << m_settings.m_hardMetric
<< " RollOff: " << m_settings.m_rollOff
<< " Viterbi: " << m_settings.m_viterbi
<< " Excursion: " << m_settings.m_excursion
<< " channel Sample rate: " << m_channelSampleRate
<< " Input sample rate: " << 2 * m_settings.m_symbolRate;
m_objCfg.standard = m_settings.m_standard;
m_objCfg.fec = (leansdr::code_rate) getLeanDVBCodeRateFromDATV(m_settings.m_fec);
m_objCfg.Fs = (float) 2 * m_settings.m_symbolRate; // maintained at twice the symbol rate
m_objCfg.Fm = (float) m_settings.m_symbolRate;
m_objCfg.fastlock = m_settings.m_fastLock;
m_objCfg.sampler = m_settings.m_filter;
m_objCfg.rolloff = m_settings.m_rollOff; //0...1
m_objCfg.rrc_rej = (float) m_settings.m_excursion; //dB
m_objCfg.rrc_steps = 0; //auto
m_videoStream->resetTotalReceived();
m_udpStream.resetTotalReceived();
switch(m_settings.m_modulation)
{
case DATVDemodSettings::BPSK:
m_objCfg.constellation = leansdr::cstln_lut<leansdr::eucl_ss, 256>::BPSK;
break;
case DATVDemodSettings::QPSK:
m_objCfg.constellation = leansdr::cstln_lut<leansdr::eucl_ss, 256>::QPSK;
break;
case DATVDemodSettings::PSK8:
m_objCfg.constellation = leansdr::cstln_lut<leansdr::eucl_ss, 256>::PSK8;
break;
case DATVDemodSettings::APSK16:
m_objCfg.constellation = leansdr::cstln_lut<leansdr::eucl_ss, 256>::APSK16;
break;
case DATVDemodSettings::APSK32:
m_objCfg.constellation = leansdr::cstln_lut<leansdr::eucl_ss, 256>::APSK32;
break;
case DATVDemodSettings::APSK64E:
m_objCfg.constellation = leansdr::cstln_lut<leansdr::eucl_ss, 256>::APSK64E;
break;
case DATVDemodSettings::QAM16:
m_objCfg.constellation = leansdr::cstln_lut<leansdr::eucl_ss, 256>::QAM16;
break;
case DATVDemodSettings::QAM64:
m_objCfg.constellation = leansdr::cstln_lut<leansdr::eucl_ss, 256>::QAM64;
break;
case DATVDemodSettings::QAM256:
m_objCfg.constellation = leansdr::cstln_lut<leansdr::eucl_ss, 256>::QAM256;
break;
default:
m_objCfg.constellation = leansdr::cstln_lut<leansdr::eucl_ss, 256>::BPSK;
break;
}
m_objCfg.allow_drift = m_settings.m_allowDrift;
m_objCfg.anf = m_settings.m_notchFilters;
m_objCfg.hard_metric = m_settings.m_hardMetric;
m_objCfg.sampler = m_settings.m_filter;
m_objCfg.viterbi = m_settings.m_viterbi;
// Min buffer size for baseband data
// scopes: 1024
// ss_estimator: 1024
// anf: 4096
// cstln_receiver: reads in chunks of 128+1
BUF_BASEBAND = 4096 * m_objCfg.buf_factor;
// Min buffer size for IQ symbols
// cstln_receiver: writes in chunks of 128/omega symbols (margin 128)
// deconv_sync: reads at least 64+32
// A larger buffer improves performance significantly.
BUF_SYMBOLS = 1024 * m_objCfg.buf_factor;
// Min buffer size for unsynchronized bytes
// deconv_sync: writes 32 bytes
// mpeg_sync: reads up to 204*scan_syncs = 1632 bytes
BUF_BYTES = 2048 * m_objCfg.buf_factor;
// Min buffer size for synchronized (but interleaved) bytes
// mpeg_sync: writes 1 rspacket
// deinterleaver: reads 17*11*12+204 = 2448 bytes
BUF_MPEGBYTES = 2448 * m_objCfg.buf_factor;
// Min buffer size for packets: 1
BUF_PACKETS = m_objCfg.buf_factor;
// Min buffer size for misc measurements: 1
BUF_SLOW = m_objCfg.buf_factor;
m_lngExpectedReadIQ = BUF_BASEBAND;
m_objScheduler = new leansdr::scheduler();
//***************
p_rawiq = new leansdr::pipebuf<leansdr::cf32>(m_objScheduler, "rawiq", BUF_BASEBAND);
p_rawiq_writer = new leansdr::pipewriter<leansdr::cf32>(*p_rawiq, m_RawIQMinWrite);
p_preprocessed = p_rawiq;
// NOTCH FILTER
if (m_objCfg.anf>0)
{
p_autonotched = new leansdr::pipebuf<leansdr::cf32>(m_objScheduler, "autonotched", BUF_BASEBAND);
r_auto_notch = new leansdr::auto_notch<leansdr::f32>(m_objScheduler, *p_preprocessed, *p_autonotched, m_objCfg.anf, 0);
p_preprocessed = p_autonotched;
}
// FREQUENCY CORRECTION
//******** -> if ( m_objCfg.Fderot>0 )
// CNR ESTIMATION
p_cnr = new leansdr::pipebuf<leansdr::f32>(m_objScheduler, "cnr", BUF_SLOW);
if (m_objCfg.cnr == true)
{
r_cnr = new leansdr::cnr_fft<leansdr::f32>(m_objScheduler, *p_preprocessed, *p_cnr, m_objCfg.Fm/m_objCfg.Fs, 1024);
r_cnr->decimation = decimation(m_objCfg.Fs, 5); // 5 Hz
}
// FILTERING
int decim = 1;
//******** -> if ( m_objCfg.resample )
// DECIMATION
// (Unless already done in resampler)
//******** -> if ( !m_objCfg.resample && m_objCfg.decim>1 )
//Resampling FS
// Generic constellation receiver
p_symbols = new leansdr::pipebuf<leansdr::eucl_ss>(m_objScheduler, "PSK soft-symbols", BUF_SYMBOLS);
p_freq = new leansdr::pipebuf<leansdr::f32> (m_objScheduler, "freq", BUF_SLOW);
p_ss = new leansdr::pipebuf<leansdr::f32> (m_objScheduler, "SS", BUF_SLOW);
p_mer = new leansdr::pipebuf<leansdr::f32> (m_objScheduler, "MER", BUF_SLOW);
p_sampled = new leansdr::pipebuf<leansdr::cf32> (m_objScheduler, "PSK symbols", BUF_BASEBAND);
switch (m_objCfg.sampler)
{
case DATVDemodSettings::SAMP_NEAREST:
sampler = new leansdr::nearest_sampler<float>();
break;
case DATVDemodSettings::SAMP_LINEAR:
sampler = new leansdr::linear_sampler<float>();
break;
case DATVDemodSettings::SAMP_RRC:
{
if (m_objCfg.rrc_steps == 0)
{
// At least 64 discrete sampling points between symbols
m_objCfg.rrc_steps = std::max(1, (int)(64*m_objCfg.Fm / m_objCfg.Fs));
}
float Frrc = m_objCfg.Fs * m_objCfg.rrc_steps; // Sample freq of the RRC filter
float transition = (m_objCfg.Fm/2) * m_objCfg.rolloff;
int order = m_objCfg.rrc_rej * Frrc / (22*transition);
ncoeffs_sampler = leansdr::filtergen::root_raised_cosine(order, m_objCfg.Fm/Frrc, m_objCfg.rolloff, &coeffs_sampler);
sampler = new leansdr::fir_sampler<float,float>(ncoeffs_sampler, coeffs_sampler, m_objCfg.rrc_steps);
break;
}
default:
qCritical("DATVDemodSink::InitDATVFramework: Interpolator not implemented");
return;
}
m_objDemodulator = new leansdr::cstln_receiver<leansdr::f32, leansdr::eucl_ss>(
m_objScheduler,
sampler,
*p_preprocessed,
*p_symbols,
p_freq,
p_ss,
p_mer,
p_sampled);
if (m_objCfg.standard == DATVDemodSettings::DVB_S)
{
if ( m_objCfg.constellation != leansdr::cstln_lut<leansdr::eucl_ss, 256>::QPSK
&& m_objCfg.constellation != leansdr::cstln_lut<leansdr::eucl_ss, 256>::BPSK )
{
qWarning("DATVDemodSink::InitDATVFramework: non-standard constellation for DVB-S");
}
}
if (m_objCfg.standard == DATVDemodSettings::DVB_S2)
{
// For DVB-S2 testing only.
// Constellation should be determined from PL signalling.
qDebug("DATVDemodSink::InitDATVFramework: DVB-S2: Testing symbol sampler only.");
}
m_objDemodulator->cstln = make_dvbs_constellation(m_objCfg.constellation, m_objCfg.fec);
if (m_objCfg.hard_metric) {
m_objDemodulator->cstln->harden();
}
m_objDemodulator->set_omega(m_objCfg.Fs/m_objCfg.Fm);
//******** if ( m_objCfg.Ftune )
//{
// m_objDemodulator->set_freq(m_objCfg.Ftune/m_objCfg.Fs);
//}
if (m_objCfg.allow_drift) {
m_objDemodulator->set_allow_drift(true);
}
//******** -> if ( m_objCfg.viterbi )
if (m_objCfg.viterbi) {
m_objDemodulator->pll_adjustment /= 6;
}
m_objDemodulator->meas_decimation = decimation(m_objCfg.Fs, m_objCfg.Finfo);
// TRACKING FILTERS
if (r_cnr)
{
r_cnr->freq_tap = &m_objDemodulator->freq_tap;
r_cnr->tap_multiplier = 1.0 / decim;
}
//constellation
#ifndef SERVER_MODE
if (m_tvScreen)
{
qDebug("DATVDemodSink::InitDATVFramework: Register DVB constellation TV screen");
r_scope_symbols = new leansdr::datvconstellation<leansdr::f32>(m_objScheduler, *p_sampled, -128,128, nullptr, m_tvScreen);
r_scope_symbols->decimation = 1;
r_scope_symbols->cstln = &m_objDemodulator->cstln;
r_scope_symbols->calculate_cstln_points();
}
#endif
r_merMeter = new leansdr::datvmeter(m_objScheduler, *p_mer);
r_cnrMeter = new leansdr::datvmeter(m_objScheduler, *p_cnr);
// DECONVOLUTION AND SYNCHRONIZATION
p_bytes = new leansdr::pipebuf<leansdr::u8>(m_objScheduler, "bytes", BUF_BYTES);
r_deconv = nullptr;
//******** -> if ( m_objCfg.viterbi )
if (m_objCfg.viterbi)
{
if (m_objCfg.fec == leansdr::FEC23 && (m_objDemodulator->cstln->nsymbols == 4 || m_objDemodulator->cstln->nsymbols == 64)) {
m_objCfg.fec = leansdr::FEC46;
}
//To uncomment -> Linking Problem : undefined symbol: _ZN7leansdr21viterbi_dec_interfaceIhhiiE6updateEPiS2_
r = new leansdr::viterbi_sync(m_objScheduler, (*p_symbols), (*p_bytes), m_objDemodulator->cstln, m_objCfg.fec);
if (m_objCfg.fastlock) {
r->resync_period = 1;
}
}
else
{
r_deconv = make_deconvol_sync_simple(m_objScheduler, (*p_symbols), (*p_bytes), m_objCfg.fec);
r_deconv->fastlock = m_objCfg.fastlock;
}
//******* -> if ( m_objCfg.hdlc )
p_mpegbytes = new leansdr::pipebuf<leansdr::u8> (m_objScheduler, "mpegbytes", BUF_MPEGBYTES);
p_lock = new leansdr::pipebuf<int> (m_objScheduler, "lock", BUF_SLOW);
p_locktime = new leansdr::pipebuf<leansdr::u32> (m_objScheduler, "locktime", BUF_PACKETS);
r_sync_mpeg = new leansdr::mpeg_sync<leansdr::u8, 0>(m_objScheduler, *p_bytes, *p_mpegbytes, r_deconv, p_lock, p_locktime);
r_sync_mpeg->fastlock = m_objCfg.fastlock;
// DEINTERLEAVING
p_rspackets = new leansdr::pipebuf<leansdr::rspacket<leansdr::u8> >(m_objScheduler, "RS-enc packets", BUF_PACKETS);
r_deinter = new leansdr::deinterleaver<leansdr::u8>(m_objScheduler, *p_mpegbytes, *p_rspackets);
// REED-SOLOMON
p_vbitcount = new leansdr::pipebuf<int>(m_objScheduler, "Bits processed", BUF_PACKETS);
p_verrcount = new leansdr::pipebuf<int>(m_objScheduler, "Bits corrected", BUF_PACKETS);
p_rtspackets = new leansdr::pipebuf<leansdr::tspacket>(m_objScheduler, "rand TS packets", BUF_PACKETS);
r_rsdec = new leansdr::rs_decoder<leansdr::u8, 0>(m_objScheduler, *p_rspackets, *p_rtspackets, p_vbitcount, p_verrcount);
// BER ESTIMATION
/*
p_vber = new pipebuf<float> (m_objScheduler, "VBER", BUF_SLOW);
r_vber = new rate_estimator<float> (m_objScheduler, *p_verrcount, *p_vbitcount, *p_vber);
r_vber->sample_size = m_objCfg.Fm/2; // About twice per second, depending on CR
// Require resolution better than 2E-5
if ( r_vber->sample_size < 50000 )
{
r_vber->sample_size = 50000;
}
*/
// DERANDOMIZATION
p_tspackets = new leansdr::pipebuf<leansdr::tspacket>(m_objScheduler, "TS packets", BUF_PACKETS);
r_derand = new leansdr::derandomizer(m_objScheduler, *p_rtspackets, *p_tspackets);
// OUTPUT
if (m_settings.m_playerEnable) {
r_videoplayer = new leansdr::datvvideoplayer<leansdr::tspacket>(m_objScheduler, *p_tspackets, m_videoStream, &m_udpStream);
} else {
r_videoplayer = new leansdr::datvvideoplayer<leansdr::tspacket>(m_objScheduler, *p_tspackets, nullptr, &m_udpStream);
}
r_videoplayer->setSymbolRate(m_settings.m_symbolRate);
m_blnDVBInitialized = true;
}
//************ DVB-S2 Decoder ************
void DATVDemodSink::InitDATVS2Framework()
{
leansdr::s2_frame_receiver<leansdr::f32, leansdr::llr_ss> * objDemodulatorDVBS2;
m_blnDVBInitialized = false;
m_lngReadIQ = 0;
CleanUpDATVFramework();
qDebug() << "DATVDemodSink::InitDATVS2Framework:"
<< " Standard: " << m_settings.m_standard
<< " Symbol Rate: " << m_settings.m_symbolRate
<< " Modulation: " << m_settings.m_modulation
<< " Notch Filters: " << m_settings.m_notchFilters
<< " Allow Drift: " << m_settings.m_allowDrift
<< " Fast Lock: " << m_settings.m_fastLock
<< " Filter: " << m_settings.m_filter
<< " HARD METRIC: " << m_settings.m_hardMetric
<< " RollOff: " << m_settings.m_rollOff
<< " Viterbi: " << m_settings.m_viterbi
<< " Excursion: " << m_settings.m_excursion
<< " Channel sample rate: " << m_channelSampleRate
<< " Input sample rate: " << 2 * m_settings.m_symbolRate
<< " m_softLDPCMaxTrials: " << m_settings.m_softLDPCMaxTrials;
m_objCfg.standard = m_settings.m_standard;
m_objCfg.fec = (leansdr::code_rate) getLeanDVBCodeRateFromDATV(m_settings.m_fec);
m_objCfg.Fs = (float) 2 * m_settings.m_symbolRate; // maintained at twice the symbol rate
m_objCfg.Fm = (float) m_settings.m_symbolRate;
m_objCfg.fastlock = m_settings.m_fastLock;
m_objCfg.sampler = m_settings.m_filter;
m_objCfg.rolloff = m_settings.m_rollOff * 0.999f; //0...1 and correct 0.2 bug
m_objCfg.rrc_rej = (float) m_settings.m_excursion; //dB
m_objCfg.rrc_steps = 0; //auto
m_videoStream->resetTotalReceived();
m_udpStream.resetTotalReceived();
switch(m_settings.m_modulation)
{
case DATVDemodSettings::BPSK:
m_objCfg.constellation = leansdr::cstln_lut<leansdr::llr_ss, 256>::BPSK;
break;
case DATVDemodSettings::QPSK:
m_objCfg.constellation = leansdr::cstln_lut<leansdr::llr_ss, 256>::QPSK;
break;
case DATVDemodSettings::PSK8:
m_objCfg.constellation = leansdr::cstln_lut<leansdr::llr_ss, 256>::PSK8;
break;
case DATVDemodSettings::APSK16:
m_objCfg.constellation = leansdr::cstln_lut<leansdr::llr_ss, 256>::APSK16;
break;
case DATVDemodSettings::APSK32:
m_objCfg.constellation = leansdr::cstln_lut<leansdr::llr_ss, 256>::APSK32;
break;
case DATVDemodSettings::APSK64E:
m_objCfg.constellation = leansdr::cstln_lut<leansdr::llr_ss, 256>::APSK64E;
break;
case DATVDemodSettings::QAM16:
m_objCfg.constellation = leansdr::cstln_lut<leansdr::llr_ss, 256>::QAM16;
break;
case DATVDemodSettings::QAM64:
m_objCfg.constellation = leansdr::cstln_lut<leansdr::llr_ss, 256>::QAM64;
break;
case DATVDemodSettings::QAM256:
m_objCfg.constellation = leansdr::cstln_lut<leansdr::llr_ss, 256>::QAM256;
break;
default:
m_objCfg.constellation = leansdr::cstln_lut<leansdr::llr_ss, 256>::BPSK;
break;
}
m_objCfg.allow_drift = m_settings.m_allowDrift;
m_objCfg.anf = m_settings.m_notchFilters;
m_objCfg.hard_metric = m_settings.m_hardMetric;
m_objCfg.sampler = m_settings.m_filter;
m_objCfg.viterbi = m_settings.m_viterbi;
// Min buffer size for baseband data
S2_MAX_SYMBOLS = (90*(1+360)+36*((360-1)/16));
BUF_BASEBAND = S2_MAX_SYMBOLS * 2 * (m_objCfg.Fs/m_objCfg.Fm) * m_objCfg.buf_factor;
// Min buffer size for IQ symbols
// cstln_receiver: writes in chunks of 128/omega symbols (margin 128)
// deconv_sync: reads at least 64+32
// A larger buffer improves performance significantly.
BUF_SYMBOLS = 1024 * m_objCfg.buf_factor;
// Min buffer size for misc measurements: 1
BUF_SLOW = m_objCfg.buf_factor;
// dvbs2 : Min buffer size for slots: 4 for deinterleaver
BUF_SLOTS = leansdr::modcod_info::MAX_SLOTS_PER_FRAME * m_objCfg.buf_factor;
BUF_FRAMES = m_objCfg.buf_factor;
// Min buffer size for TS packets: Up to 39 per BBFRAME
BUF_S2PACKETS = (leansdr::fec_info::KBCH_MAX/188/8+1) * m_objCfg.buf_factor;
m_lngExpectedReadIQ = BUF_BASEBAND;
m_objScheduler = new leansdr::scheduler();
//***************
p_rawiq = new leansdr::pipebuf<leansdr::cf32>(m_objScheduler, "rawiq", BUF_BASEBAND);
p_rawiq_writer = new leansdr::pipewriter<leansdr::cf32>(*p_rawiq, m_RawIQMinWrite);
p_preprocessed = p_rawiq;
// NOTCH FILTER
if (m_objCfg.anf>0)
{
p_autonotched = new leansdr::pipebuf<leansdr::cf32>(m_objScheduler, "autonotched", BUF_BASEBAND);
r_auto_notch = new leansdr::auto_notch<leansdr::f32>(m_objScheduler, *p_preprocessed, *p_autonotched, m_objCfg.anf, 0);
p_preprocessed = p_autonotched;
}
// FREQUENCY CORRECTION
//******** -> if ( m_objCfg.Fderot>0 )
// CNR ESTIMATION
p_cnr = new leansdr::pipebuf<leansdr::f32>(m_objScheduler, "cnr", BUF_SLOW);
if (m_objCfg.cnr == true)
{
r_cnr = new leansdr::cnr_fft<leansdr::f32>(m_objScheduler, *p_preprocessed, *p_cnr, m_objCfg.Fm/m_objCfg.Fs, 1024);
r_cnr->decimation = decimation(m_objCfg.Fs, 5); // 5 Hz
}
// FILTERING
//******** -> if ( m_objCfg.resample )
// DECIMATION
// (Unless already done in resampler)
//******** -> if ( !m_objCfg.resample && m_objCfg.decim>1 )
//Resampling FS
// Generic constellation receiver
p_freq = new leansdr::pipebuf<leansdr::f32> (m_objScheduler, "freq", BUF_SLOW);
p_ss = new leansdr::pipebuf<leansdr::f32> (m_objScheduler, "SS", BUF_SLOW);
p_mer = new leansdr::pipebuf<leansdr::f32> (m_objScheduler, "MER", BUF_SLOW);
switch (m_objCfg.sampler)
{
case DATVDemodSettings::SAMP_NEAREST:
sampler = new leansdr::nearest_sampler<float>();
break;
case DATVDemodSettings::SAMP_LINEAR:
sampler = new leansdr::linear_sampler<float>();
break;
case DATVDemodSettings::SAMP_RRC:
{
if (m_objCfg.rrc_steps == 0)
{
// At least 64 discrete sampling points between symbols
m_objCfg.rrc_steps = std::max(1, (int)(64*m_objCfg.Fm / m_objCfg.Fs));
}
float Frrc = m_objCfg.Fs * m_objCfg.rrc_steps; // Sample freq of the RRC filter
float transition = (m_objCfg.Fm/2) * m_objCfg.rolloff;
int order = m_objCfg.rrc_rej * Frrc / (22*transition);
ncoeffs_sampler = leansdr::filtergen::root_raised_cosine(order, m_objCfg.Fm/Frrc, m_objCfg.rolloff, &coeffs_sampler);
sampler = new leansdr::fir_sampler<float,float>(ncoeffs_sampler, coeffs_sampler, m_objCfg.rrc_steps);
break;
}
default:
qCritical("DATVDemodSink::InitDATVS2Framework: Interpolator not implemented");
return;
}
p_slots_dvbs2 = new leansdr::pipebuf< leansdr::plslot<leansdr::llr_ss> > (m_objScheduler, "PL slots", BUF_SLOTS);
p_cstln = new leansdr::pipebuf<leansdr::cf32>(m_objScheduler, "cstln", BUF_BASEBAND);
p_cstln_pls = new leansdr::pipebuf<leansdr::cf32>(m_objScheduler, "PLS cstln", BUF_BASEBAND);
p_framelock = new leansdr::pipebuf<int>(m_objScheduler, "frame lock", BUF_SLOW);
m_objDemodulatorDVBS2 = new leansdr::s2_frame_receiver<leansdr::f32, leansdr::llr_ss>(
m_objScheduler,
sampler,
*p_preprocessed,
*(leansdr::pipebuf< leansdr::plslot<leansdr::llr_ss> > *) p_slots_dvbs2,
/* p_freq */ nullptr,
/* p_ss */ nullptr,
p_mer,
p_cstln,
/* p_cstln_pls */ nullptr,
/*p_iqsymbols*/ nullptr,
/* p_framelock */nullptr
);
objDemodulatorDVBS2 = (leansdr::s2_frame_receiver<leansdr::f32, leansdr::llr_ss> *) m_objDemodulatorDVBS2;
objDemodulatorDVBS2->omega0 = m_objCfg.Fs/m_objCfg.Fm;
//objDemodulatorDVBS2->mu=1;
m_objCfg.Ftune=0.0f;
objDemodulatorDVBS2->Ftune = m_objCfg.Ftune / m_objCfg.Fm;
/*
demod.strongpls = cfg.strongpls;
*/
objDemodulatorDVBS2->meas_decimation = decimation(m_objCfg.Fs, m_objCfg.Finfo);
objDemodulatorDVBS2->strongpls = false;
objDemodulatorDVBS2->cstln = make_dvbs2_constellation(m_objCfg.constellation, m_objCfg.fec);
m_cstlnSetByModcod = false;
//constellation
#ifndef SERVER_MODE
if (m_tvScreen)
{
qDebug("DATVDemodSink::InitDATVS2Framework: Register DVBS 2 TVSCREEN");
r_scope_symbols_dvbs2 = new leansdr::datvdvbs2constellation<leansdr::f32>(m_objScheduler, *p_cstln /* *p_sampled */ /* *p_cstln */, -128,128, nullptr, m_tvScreen);
r_scope_symbols_dvbs2->decimation = 1;
r_scope_symbols_dvbs2->cstln = (leansdr::cstln_base**) &objDemodulatorDVBS2->cstln;
r_scope_symbols_dvbs2->calculate_cstln_points();
}
#endif
r_merMeter = new leansdr::datvmeter(m_objScheduler, *p_mer);
r_cnrMeter = new leansdr::datvmeter(m_objScheduler, *p_cnr);
// Bit-flipping mode.
// Deinterleave into hard bits.
p_bbframes = new leansdr::pipebuf<leansdr::bbframe>(m_objScheduler, "BB frames", BUF_FRAMES);
// p_fecframes = new leansdr::pipebuf< leansdr::fecframe<leansdr::hard_sb> >(m_objScheduler, "FEC frames", BUF_FRAMES);
// p_s2_deinterleaver = new leansdr::s2_deinterleaver<leansdr::llr_ss,leansdr::hard_sb>(
// m_objScheduler,
// *(leansdr::pipebuf< leansdr::plslot<leansdr::llr_ss> > *) p_slots_dvbs2,
// *(leansdr::pipebuf< leansdr::fecframe<leansdr::hard_sb> > * ) p_fecframes
// );
p_vbitcount= new leansdr::pipebuf<int>(m_objScheduler, "Bits processed", BUF_S2PACKETS);
p_verrcount = new leansdr::pipebuf<int>(m_objScheduler, "Bits corrected", BUF_S2PACKETS);
// bool commandFileValid = false;
if (m_settings.m_softLDPC /*&& commandFileValid*/)
{
#if 0
// Doesn't work...
// Soft LDPC decoder mode.
// Deinterleave into soft bits.
p_fecframes = new leansdr::pipebuf<leansdr::fecframe<leansdr::llr_sb> >(m_objScheduler, "FEC frames", BUF_FRAMES);
p_s2_deinterleaver = new leansdr::s2_deinterleaver<leansdr::llr_ss, leansdr::llr_sb>(
m_objScheduler,
*(leansdr::pipebuf< leansdr::plslot<leansdr::llr_ss> > *) p_slots_dvbs2,
*(leansdr::pipebuf< leansdr::fecframe<leansdr::llr_sb> > * ) p_fecframes
);
r_fecdecsoft = new leansdr::s2_fecdec_soft<leansdr::llr_t,leansdr::llr_sb>(
m_objScheduler, *(leansdr::pipebuf< leansdr::fecframe<leansdr::llr_sb> > * ) p_fecframes,
*(leansdr::pipebuf<leansdr::bbframe> *) p_bbframes,
m_modcodModulation < 0 ? 0 : m_modcodModulation,
true, 5,
p_vbitcount,
p_verrcount
);
#else
// External LDPC decoder mode.
// Deinterleave into soft bits.
// TBD Latency
p_fecframes = new leansdr::pipebuf<leansdr::fecframe<leansdr::llr_sb> >(m_objScheduler, "FEC frames", BUF_FRAMES);
p_s2_deinterleaver = new leansdr::s2_deinterleaver<leansdr::llr_ss, leansdr::llr_sb>(
m_objScheduler,
*(leansdr::pipebuf< leansdr::plslot<leansdr::llr_ss> > *) p_slots_dvbs2,
*(leansdr::pipebuf< leansdr::fecframe<leansdr::llr_sb> > *) p_fecframes
);
// Decode FEC-protected frames into plain BB frames.
r_fecdechelper = new leansdr::s2_fecdec_helper<leansdr::llr_t, leansdr::llr_sb>(
m_objScheduler,
*(leansdr::pipebuf< leansdr::fecframe<leansdr::llr_sb> > *) p_fecframes,
*(leansdr::pipebuf<leansdr::bbframe> *) p_bbframes,
p_vbitcount,
p_verrcount)
;
leansdr::s2_fecdec_helper<leansdr::llr_t, leansdr::llr_sb> *fecdec = (leansdr::s2_fecdec_helper<leansdr::llr_t, leansdr::llr_sb> *) r_fecdechelper;
const int nhelpers = 2;
fecdec->nhelpers = nhelpers;
fecdec->must_buffer = false;
fecdec->max_trials = m_settings.m_softLDPCMaxTrials;
#endif
}
else
{
// Bit-flipping mode.
// Deinterleave into hard bits.
p_fecframes = new leansdr::pipebuf< leansdr::fecframe<leansdr::hard_sb> >(m_objScheduler, "FEC frames", BUF_FRAMES);
p_s2_deinterleaver = new leansdr::s2_deinterleaver<leansdr::llr_ss,leansdr::hard_sb>(
m_objScheduler,
*(leansdr::pipebuf< leansdr::plslot<leansdr::llr_ss> > *) p_slots_dvbs2,
*(leansdr::pipebuf< leansdr::fecframe<leansdr::hard_sb> > * ) p_fecframes
);
r_fecdec = new leansdr::s2_fecdec<bool, leansdr::hard_sb>(
m_objScheduler,
*(leansdr::pipebuf< leansdr::fecframe<leansdr::hard_sb> > * ) p_fecframes,
*(leansdr::pipebuf<leansdr::bbframe> *) p_bbframes,
p_vbitcount,
p_verrcount
);
leansdr::s2_fecdec<bool, leansdr::hard_sb> *fecdec = (leansdr::s2_fecdec<bool, leansdr::hard_sb> * ) r_fecdec;
fecdec->bitflips=m_settings.m_maxBitflips;
}
// Deframe BB frames to TS packets
p_lock = new leansdr::pipebuf<int> (m_objScheduler, "lock", BUF_SLOW);
p_locktime = new leansdr::pipebuf<leansdr::u32> (m_objScheduler, "locktime", BUF_S2PACKETS);
p_tspackets = new leansdr::pipebuf<leansdr::tspacket>(m_objScheduler, "TS packets", BUF_S2PACKETS);
p_deframer = new leansdr::s2_deframer(m_objScheduler,*(leansdr::pipebuf<leansdr::bbframe> *) p_bbframes, *p_tspackets, p_lock, p_locktime);
/*
if ( cfg.fd_gse >= 0 ) deframer.fd_gse = cfg.fd_gse;
*/
// OUTPUT
if (m_settings.m_playerEnable) {
r_videoplayer = new leansdr::datvvideoplayer<leansdr::tspacket>(m_objScheduler, *p_tspackets, m_videoStream, &m_udpStream);
} else {
r_videoplayer = new leansdr::datvvideoplayer<leansdr::tspacket>(m_objScheduler, *p_tspackets, nullptr, &m_udpStream);
}
r_videoplayer->setSymbolRate(m_settings.m_symbolRate);
m_blnDVBInitialized = true;
}
void DATVDemodSink::feed(const SampleVector::const_iterator& begin, const SampleVector::const_iterator& end)
{
leansdr::s2_frame_receiver<leansdr::f32, leansdr::llr_ss> *objDemodulatorDVBS2 =
(leansdr::s2_frame_receiver<leansdr::f32, leansdr::llr_ss> *) m_objDemodulatorDVBS2;
// DVBS2: Track change of constellation via MODCOD
if ((m_settings.m_standard == DATVDemodSettings::DVB_S2) && objDemodulatorDVBS2)
{
if (objDemodulatorDVBS2->cstln->m_setByModcod && !m_cstlnSetByModcod)
{
qDebug("DATVDemodSink::feed: change by MODCOD detected");
// Update constellation
#ifndef SERVER_MODE
if (r_scope_symbols_dvbs2) {
r_scope_symbols_dvbs2->calculate_cstln_points();
}
#endif
if (getMessageQueueToGUI())
{
DATVDemodReport::MsgReportModcodCstlnChange *msg = DATVDemodReport::MsgReportModcodCstlnChange::create(
DATVDemodSettings::getModulationFromLeanDVBCode(objDemodulatorDVBS2->cstln->m_typeCode),
DATVDemodSettings::getCodeRateFromLeanDVBCode(objDemodulatorDVBS2->cstln->m_rateCode)
);
getMessageQueueToGUI()->push(msg);
}
if (
(
(m_modcodModulation != objDemodulatorDVBS2->m_modcodType) &&
(m_modcodModulation >= 0) &&
(objDemodulatorDVBS2->m_modcodType >= 0)
) ||
(
(m_modcodCodeRate != objDemodulatorDVBS2->m_modcodRate) &&
(m_modcodCodeRate >= 0) &&
(objDemodulatorDVBS2->m_modcodRate >= 0)
)
)
{
m_blnNeedConfigUpdate = true;
}
}
m_cstlnSetByModcod = objDemodulatorDVBS2->cstln->m_setByModcod;
m_modcodModulation = objDemodulatorDVBS2->m_modcodType;
m_modcodCodeRate = objDemodulatorDVBS2->m_modcodRate;
} // DVBS2: Track change of constellation via MODCOD
//********** init leandvb framework **********
if (m_blnNeedConfigUpdate)
{
QMutexLocker mlock(&m_mutex);
stopVideo();
qDebug("DATVDemodSink::feed: Settings applied. Standard : %d...", m_settings.m_standard);
m_blnNeedConfigUpdate = false;
try
{
if(m_settings.m_standard==DATVDemodSettings::DVB_S2)
{
qDebug("DATVDemodSink::feed: init DVBS-2");
InitDATVS2Framework();
}
else
{
qDebug("DATVDemodSink::feed: init DVBS");
InitDATVFramework();
}
}
catch (const std::exception& e)
{
// leansdr uses fail() for unrecoverable internal errors.
// Convert these into a DATV initialization failure instead of
// allowing them to terminate the application.
qCritical("DATVDemodSink::feed: DATV framework initialization failed: %s", e.what());
CleanUpDATVFramework();
return;
}
}
//********** Bis repetita : Let's rock and roll buddy ! **********
for (SampleVector::const_iterator it = begin; it != end; ++it /* ++it **/)
{
Complex c(it->real(), it->imag());
if (m_interpolatorDistance < 1.0f) // interpolate - should never get there...
{
Complex ci;
c *= m_nco.nextIQ();
while (!m_interpolator.interpolate(&m_interpolatorDistanceRemain, c, &ci))
{
processOneSample(ci);
m_interpolatorDistanceRemain += m_interpolatorDistance;
}
}
else // decimate
{
Complex ci;
c *= m_nco.nextIQ();
if (m_interpolator.decimate(&m_interpolatorDistanceRemain, c, &ci))
{
processOneSample(ci);
m_interpolatorDistanceRemain += m_interpolatorDistance;
}
}
} // Samples for loop
}
void DATVDemodSink::processOneSample(Complex &ci)
{
m_objMagSqAverage(norm(ci));
if (m_blnDVBInitialized
&& (p_rawiq_writer != nullptr)
&& (m_objScheduler != nullptr))
{
p_rawiq_writer->write(ci);
m_lngReadIQ++;
int writable = p_rawiq_writer->writable();
//Leave +1 by safety
//if(((m_lngReadIQ+1)>=lngWritable) || (m_lngReadIQ>=768))
if ((m_lngReadIQ + 1) >= writable)
{
m_objScheduler->step();
m_lngReadIQ = 0;
p_rawiq_writer->reset(m_RawIQMinWrite);
}
}
}
void DATVDemodSink::applyChannelSettings(int channelSampleRate, int channelFrequencyOffset, bool force)
{
qDebug() << "DATVDemodSink::applyChannelSettings:"
<< " channelSampleRate: " << channelSampleRate
<< " channelFrequencyOffset: " << channelFrequencyOffset;
bool callApplySettings = false;
if ((m_settings.m_centerFrequency != channelFrequencyOffset) ||
(m_channelSampleRate != channelSampleRate) || force)
{
m_nco.setFreq(-(float) channelFrequencyOffset, (float) channelSampleRate);
qDebug("DATVDemodSink::applyChannelSettings: NCO: IF: %d <> TF: %d ISR: %d",
channelFrequencyOffset, m_settings.m_centerFrequency, channelSampleRate);
callApplySettings = true;
}
if ((m_channelSampleRate != channelSampleRate) || force)
{
m_interpolator.create(m_interpolatorPhaseSteps, channelSampleRate, m_settings.m_rfBandwidth / 2.2, m_interpolatorTapsPerPhase);
m_interpolatorDistanceRemain = 0;
m_interpolatorDistance = (Real) channelSampleRate / (Real) (2 * m_settings.m_symbolRate);
qDebug("DATVDemodSink::applyChannelSettings: m_interpolatorDistance: %f", m_interpolatorDistance);
}
m_channelSampleRate = channelSampleRate;
m_settings.m_centerFrequency = channelFrequencyOffset;
if (callApplySettings) {
applySettings(QStringList(), m_settings, true);
}
}
void DATVDemodSink::applySettings(const QStringList& settingsKeys, const DATVDemodSettings& settings, bool force)
{
QString msg = QObject::tr("DATVDemodSink::applySettings: force: %1").arg(force);
settings.debug(msg);
qDebug("DATVDemodSink::applySettings: m_channelSampleRate: %d", m_channelSampleRate);
if (m_channelSampleRate == 0) {
return;
}
#ifndef SERVER_MODE
if ((settingsKeys.contains("audioVolume") && (settings.m_audioVolume != m_settings.m_audioVolume)) || force)
{
if (m_videoRender) {
m_videoRender->setAudioVolume(settings.m_audioVolume);
}
}
if ((settingsKeys.contains("audioMute") && (settings.m_audioMute != m_settings.m_audioMute)) || force)
{
if (m_videoRender) {
m_videoRender->setAudioMute(settings.m_audioMute);
}
}
if ((settingsKeys.contains("videoMute") && (settings.m_videoMute != m_settings.m_videoMute)) || force)
{
if (m_videoRender) {
m_videoRender->setVideoMute(settings.m_videoMute);
}
}
#endif
if (settingsKeys.contains("rfBandwidth") ||
settingsKeys.contains("symbolRate") ||
settingsKeys.contains("centerFrequency") || force)
{
m_interpolator.create(m_interpolatorPhaseSteps, m_channelSampleRate, settings.m_rfBandwidth / 2.2, m_interpolatorTapsPerPhase);
m_interpolatorDistanceRemain = 0;
m_interpolatorDistance = (Real) m_channelSampleRate / (Real) (2 * settings.m_symbolRate);
m_nco.setFreq(-(float) settings.m_centerFrequency, (float) m_channelSampleRate);
}
if ((settingsKeys.contains("udpTS") && (m_settings.m_udpTS != settings.m_udpTS)) || force)
{
m_udpStream.setActive(settings.m_udpTS);
if (r_videoplayer && !settings.m_udpTS) {
r_videoplayer->resetUDPRunning();
}
}
if ((settingsKeys.contains("symbolRate") && (m_settings.m_symbolRate != settings.m_symbolRate)) || force) {
if (r_videoplayer) {
r_videoplayer->setSymbolRate(settings.m_symbolRate);
}
}
if ((settingsKeys.contains("udpTSAddress") && (m_settings.m_udpTSAddress != settings.m_udpTSAddress)) || force) {
m_udpStream.setAddress(settings.m_udpTSAddress);
}
if ((settingsKeys.contains("udpTSPort") && (m_settings.m_udpTSPort != settings.m_udpTSPort)) || force) {
m_udpStream.setPort(settings.m_udpTSPort);
}
if (m_settings.isDifferent(settings) || force) {
m_blnNeedConfigUpdate = true;
}
if (force) {
m_settings = settings;
} else {
m_settings.applySettings(settingsKeys, settings);
}
}
int DATVDemodSink::getLeanDVBCodeRateFromDATV(DATVDemodSettings::DATVCodeRate datvCodeRate)
{
if (datvCodeRate == DATVDemodSettings::DATVCodeRate::FEC12) {
return (int) leansdr::code_rate::FEC12;
} else if (datvCodeRate == DATVDemodSettings::DATVCodeRate::FEC13) {
return (int) leansdr::code_rate::FEC13;
} else if (datvCodeRate == DATVDemodSettings::DATVCodeRate::FEC14) {
return (int) leansdr::code_rate::FEC14;
} else if (datvCodeRate == DATVDemodSettings::DATVCodeRate::FEC23) {
return (int) leansdr::code_rate::FEC23;
} else if (datvCodeRate == DATVDemodSettings::DATVCodeRate::FEC25) {
return (int) leansdr::code_rate::FEC25;
} else if (datvCodeRate == DATVDemodSettings::DATVCodeRate::FEC34) {
return (int) leansdr::code_rate::FEC34;
} else if (datvCodeRate == DATVDemodSettings::DATVCodeRate::FEC35) {
return (int) leansdr::code_rate::FEC35;
} else if (datvCodeRate == DATVDemodSettings::DATVCodeRate::FEC45) {
return (int) leansdr::code_rate::FEC45;
} else if (datvCodeRate == DATVDemodSettings::DATVCodeRate::FEC46) {
return (int) leansdr::code_rate::FEC46;
} else if (datvCodeRate == DATVDemodSettings::DATVCodeRate::FEC56) {
return (int) leansdr::code_rate::FEC56;
} else if (datvCodeRate == DATVDemodSettings::DATVCodeRate::FEC78) {
return (int) leansdr::code_rate::FEC78;
} else if (datvCodeRate == DATVDemodSettings::DATVCodeRate::FEC89) {
return (int) leansdr::code_rate::FEC89;
} else if (datvCodeRate == DATVDemodSettings::DATVCodeRate::FEC910) {
return (int) leansdr::code_rate::FEC910;
} else {
return -1;
}
}
int DATVDemodSink::getLeanDVBModulationFromDATV(DATVDemodSettings::DATVModulation datvModulation)
{
if (datvModulation == DATVDemodSettings::DATVModulation::APSK16) {
return (int) leansdr::cstln_base::predef::APSK16;
} else if (datvModulation == DATVDemodSettings::DATVModulation::APSK32) {
return (int) leansdr::cstln_base::predef::APSK32;
} else if (datvModulation == DATVDemodSettings::DATVModulation::APSK64E) {
return (int) leansdr::cstln_base::predef::APSK64E;
} else if (datvModulation == DATVDemodSettings::DATVModulation::BPSK) {
return (int) leansdr::cstln_base::predef::BPSK;
} else if (datvModulation == DATVDemodSettings::DATVModulation::PSK8) {
return (int) leansdr::cstln_base::predef::PSK8;
} else if (datvModulation == DATVDemodSettings::DATVModulation::QAM16) {
return (int) leansdr::cstln_base::predef::QAM16;
} else if (datvModulation == DATVDemodSettings::DATVModulation::QAM64) {
return (int) leansdr::cstln_base::predef::QAM64;
} else if (datvModulation == DATVDemodSettings::DATVModulation::QAM256) {
return (int) leansdr::cstln_base::predef::QAM256;
} else if (datvModulation == DATVDemodSettings::DATVModulation::QPSK) {
return (int) leansdr::cstln_base::predef::QPSK;
} else {
return -1;
}
}