mirror of
https://github.com/f4exb/sdrangel.git
synced 2024-11-25 17:28:50 -05:00
DATV Demod: Add support for LDPC on Windows. Use Qt worker thread instead of external ldpc_tool process.
This commit is contained in:
parent
a65c9458ed
commit
ff26ece347
@ -25,6 +25,7 @@ set(datv_SOURCES
|
||||
|
||||
set(ldpc_SOURCES
|
||||
ldpctool/tables_handler.cpp
|
||||
ldpctool/ldpcworker.cpp
|
||||
)
|
||||
|
||||
set(datv_HEADERS
|
||||
@ -55,6 +56,7 @@ set(ldpc_HEADERS
|
||||
ldpctool/dvb_s2_tables.h
|
||||
ldpctool/dvb_s2x_tables.h
|
||||
ldpctool/dvb_t2_tables.h
|
||||
ldpctool/ldpcworker.h
|
||||
)
|
||||
|
||||
include_directories(
|
||||
@ -69,16 +71,10 @@ include_directories(
|
||||
set(TARGET_NAME demoddatv)
|
||||
set(INSTALL_FOLDER ${INSTALL_PLUGINS_DIR})
|
||||
|
||||
if (LINUX)
|
||||
add_library(${TARGET_NAME} SHARED
|
||||
${datv_SOURCES}
|
||||
${ldpc_SOURCES}
|
||||
)
|
||||
else()
|
||||
add_library(${TARGET_NAME} SHARED
|
||||
${datv_SOURCES}
|
||||
)
|
||||
endif()
|
||||
add_library(${TARGET_NAME} SHARED
|
||||
${datv_SOURCES}
|
||||
${ldpc_SOURCES}
|
||||
)
|
||||
|
||||
target_link_libraries(${TARGET_NAME}
|
||||
Qt5::Core
|
||||
@ -94,13 +90,11 @@ target_link_libraries(${TARGET_NAME}
|
||||
${SWRESAMPLE_LIBRARIES}
|
||||
)
|
||||
|
||||
if (LINUX)
|
||||
add_executable(ldpctool
|
||||
ldpctool/ldpc_tool.cpp
|
||||
ldpctool/tables_handler.cpp
|
||||
)
|
||||
install(TARGETS ldpctool DESTINATION ${INSTALL_BIN_DIR})
|
||||
endif()
|
||||
add_executable(ldpctool
|
||||
ldpctool/ldpc_tool.cpp
|
||||
ldpctool/tables_handler.cpp
|
||||
)
|
||||
install(TARGETS ldpctool DESTINATION ${INSTALL_BIN_DIR})
|
||||
|
||||
if(FFMPEG_EXTERNAL)
|
||||
add_dependencies(${TARGET_NAME} ffmpeg)
|
||||
|
@ -300,13 +300,8 @@ DATVDemodGUI::DATVDemodGUI(PluginAPI* objPluginAPI, DeviceUISet *deviceUISet, Ba
|
||||
CRightClickEnabler *audioMuteRightClickEnabler = new CRightClickEnabler(ui->audioMute);
|
||||
connect(audioMuteRightClickEnabler, SIGNAL(rightClick(const QPoint &)), this, SLOT(audioSelect()));
|
||||
|
||||
#ifdef LINUX
|
||||
CRightClickEnabler *ldpcToolRightClickEnabler = new CRightClickEnabler(ui->softLDPC);
|
||||
connect(ldpcToolRightClickEnabler, SIGNAL(rightClick(const QPoint &)), this, SLOT(ldpcToolSelect()));
|
||||
#else
|
||||
ui->softLDPC->setEnabled(false);
|
||||
ui->softLDPC->setStyleSheet("QCheckBox { color: gray }");
|
||||
#endif
|
||||
|
||||
ui->playerIndicator->setStyleSheet("QLabel { background-color: gray; border-radius: 8px; }");
|
||||
ui->udpIndicator->setStyleSheet("QLabel { background-color: gray; border-radius: 8px; }");
|
||||
@ -377,7 +372,6 @@ void DATVDemodGUI::displaySettings()
|
||||
ui->maxBitflipsLabel->setStyleSheet("QLabel { color: white }");
|
||||
}
|
||||
|
||||
#ifdef LINUX
|
||||
if (m_settings.m_standard == DATVDemodSettings::dvb_version::DVB_S)
|
||||
{
|
||||
ui->softLDPC->setEnabled(false);
|
||||
@ -388,7 +382,6 @@ void DATVDemodGUI::displaySettings()
|
||||
ui->softLDPC->setEnabled(true);
|
||||
ui->softLDPC->setStyleSheet("QCheckBox { color: white }");
|
||||
}
|
||||
#endif
|
||||
|
||||
if (m_settings.m_standard == DATVDemodSettings::dvb_version::DVB_S)
|
||||
{
|
||||
@ -658,7 +651,6 @@ void DATVDemodGUI::on_cmbStandard_currentIndexChanged(int index)
|
||||
ui->maxBitflipsLabel->setStyleSheet("QLabel { color: white }");
|
||||
}
|
||||
|
||||
#ifdef LINUX
|
||||
if (m_settings.m_standard == DATVDemodSettings::dvb_version::DVB_S)
|
||||
{
|
||||
ui->softLDPC->setEnabled(false);
|
||||
@ -669,7 +661,6 @@ void DATVDemodGUI::on_cmbStandard_currentIndexChanged(int index)
|
||||
ui->softLDPC->setEnabled(true);
|
||||
ui->softLDPC->setStyleSheet("QCheckBox { color: white }");
|
||||
}
|
||||
#endif
|
||||
|
||||
if (m_settings.m_standard == DATVDemodSettings::dvb_version::DVB_S)
|
||||
{
|
||||
@ -710,18 +701,14 @@ void DATVDemodGUI::on_cmbFEC_currentIndexChanged(int arg1)
|
||||
|
||||
void DATVDemodGUI::on_softLDPC_clicked()
|
||||
{
|
||||
#ifdef LINUX
|
||||
m_settings.m_softLDPC = ui->softLDPC->isChecked();
|
||||
applySettings();
|
||||
#endif
|
||||
}
|
||||
|
||||
void DATVDemodGUI::on_maxBitflips_valueChanged(int value)
|
||||
{
|
||||
#ifdef LINUX
|
||||
m_settings.m_maxBitflips = value;
|
||||
applySettings();
|
||||
#endif
|
||||
}
|
||||
|
||||
void DATVDemodGUI::on_chkViterbi_clicked()
|
||||
|
@ -27,6 +27,12 @@
|
||||
|
||||
#include "datvdemodsettings.h"
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#define DEFAULT_LDPCTOOLPATH "C:/Program Files/SDRangel/ldpctool.exe"
|
||||
#else
|
||||
#define DEFAULT_LDPCTOOLPATH "/opt/install/sdrangel/bin/ldpctool"
|
||||
#endif
|
||||
|
||||
DATVDemodSettings::DATVDemodSettings() :
|
||||
m_channelMarker(nullptr),
|
||||
m_rollupState(nullptr)
|
||||
@ -44,7 +50,7 @@ void DATVDemodSettings::resetToDefaults()
|
||||
m_modulation = BPSK;
|
||||
m_fec = FEC12;
|
||||
m_softLDPC = false;
|
||||
m_softLDPCToolPath = "/opt/install/sdrangel/bin/ldpctool";
|
||||
m_softLDPCToolPath = DEFAULT_LDPCTOOLPATH;
|
||||
m_softLDPCMaxTrials = 8;
|
||||
m_maxBitflips = 0;
|
||||
m_symbolRate = 250000;
|
||||
@ -208,7 +214,7 @@ bool DATVDemodSettings::deserialize(const QByteArray& data)
|
||||
|
||||
d.readBool(32, &m_softLDPC, false);
|
||||
d.readS32(33, &m_maxBitflips, 0);
|
||||
d.readString(34, &m_softLDPCToolPath, "/opt/install/sdrangel/bin/ldpctool");
|
||||
d.readString(34, &m_softLDPCToolPath, DEFAULT_LDPCTOOLPATH);
|
||||
d.readS32(35, &tmp, 8);
|
||||
m_softLDPCMaxTrials = tmp < 1 ? 1 : tmp > m_softLDPCMaxMaxTrials ? m_softLDPCMaxMaxTrials : tmp;
|
||||
d.readBool(36, &m_playerEnable, true);
|
||||
|
@ -397,7 +397,6 @@ void DATVDemodSink::CleanUpDATVFramework()
|
||||
delete (leansdr::s2_fecdec<bool, leansdr::hard_sb>*) r_fecdec;
|
||||
}
|
||||
|
||||
#ifdef LINUX
|
||||
if (r_fecdecsoft != nullptr) {
|
||||
delete (leansdr::s2_fecdec_soft<leansdr::llr_t,leansdr::llr_sb>*) r_fecdecsoft;
|
||||
}
|
||||
@ -405,7 +404,6 @@ void DATVDemodSink::CleanUpDATVFramework()
|
||||
if (r_fecdechelper != nullptr) {
|
||||
delete (leansdr::s2_fecdec_helper<leansdr::llr_t,leansdr::llr_sb>*) r_fecdechelper;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (p_deframer != nullptr) {
|
||||
delete (leansdr::s2_deframer*) p_deframer;
|
||||
@ -515,10 +513,8 @@ void DATVDemodSink::ResetDATVFrameworkPointers()
|
||||
p_bbframes = nullptr;
|
||||
p_s2_deinterleaver = nullptr;
|
||||
r_fecdec = nullptr;
|
||||
#ifdef LINUX
|
||||
r_fecdecsoft = nullptr;
|
||||
r_fecdechelper = nullptr;
|
||||
#endif
|
||||
p_deframer = nullptr;
|
||||
r_scope_symbols_dvbs2 = nullptr;
|
||||
}
|
||||
@ -1101,7 +1097,6 @@ void DATVDemodSink::InitDATVS2Framework()
|
||||
p_vbitcount= new leansdr::pipebuf<int>(m_objScheduler, "Bits processed", BUF_S2PACKETS);
|
||||
p_verrcount = new leansdr::pipebuf<int>(m_objScheduler, "Bits corrected", BUF_S2PACKETS);
|
||||
|
||||
#ifdef LINUX
|
||||
bool commandFileValid = false;
|
||||
|
||||
if (QFileInfo::exists(m_settings.m_softLDPCToolPath))
|
||||
@ -1110,7 +1105,7 @@ void DATVDemodSink::InitDATVS2Framework()
|
||||
commandFileValid = fileInfo.isExecutable();
|
||||
}
|
||||
|
||||
if (m_settings.m_softLDPC && commandFileValid)
|
||||
if (m_settings.m_softLDPC /*&& commandFileValid*/)
|
||||
{
|
||||
#if 0
|
||||
// Doesn't work...
|
||||
@ -1178,25 +1173,6 @@ void DATVDemodSink::InitDATVS2Framework()
|
||||
leansdr::s2_fecdec<bool, leansdr::hard_sb> *fecdec = (leansdr::s2_fecdec<bool, leansdr::hard_sb> * ) r_fecdec;
|
||||
fecdec->bitflips=m_settings.m_maxBitflips;
|
||||
}
|
||||
#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;
|
||||
#endif
|
||||
|
||||
// Deframe BB frames to TS packets
|
||||
p_lock = new leansdr::pipebuf<int> (m_objScheduler, "lock", BUF_SLOW);
|
||||
|
@ -58,7 +58,11 @@ void DatvDvbS2LdpcDialog::on_showFileDialog_clicked(bool checked)
|
||||
|
||||
QFileDialog fileDialog(this, "Select LDPC tool");
|
||||
fileDialog.setOption(QFileDialog::DontUseNativeDialog, true);
|
||||
#ifdef _MSC_VER
|
||||
fileDialog.setNameFilter("*.exe");
|
||||
#else
|
||||
fileDialog.setFilter(QDir::Executable | QDir::Files);
|
||||
#endif
|
||||
fileDialog.selectFile(m_fileName);
|
||||
|
||||
if (fileDialog.exec() == QDialog::Accepted)
|
||||
|
@ -8,10 +8,39 @@ Copyright 2018 Ahmet Inan <xdsopl@gmail.com>
|
||||
#define LAYERED_DECODER_HH
|
||||
|
||||
#include <stdlib.h>
|
||||
#ifdef _MSC_VER
|
||||
#include <malloc.h>
|
||||
#endif
|
||||
#include "ldpc.h"
|
||||
|
||||
namespace ldpctool {
|
||||
|
||||
class LDPCUtil
|
||||
{
|
||||
public:
|
||||
#ifndef _MSC_VER
|
||||
static void *aligned_malloc(size_t alignment, size_t size)
|
||||
{
|
||||
return aligned_alloc(alignment, size);
|
||||
}
|
||||
|
||||
static void aligned_free(void *mem)
|
||||
{
|
||||
free(mem);
|
||||
}
|
||||
#else
|
||||
static void *aligned_malloc(size_t alignment, size_t size)
|
||||
{
|
||||
return _aligned_malloc(size, alignment);
|
||||
}
|
||||
|
||||
static void aligned_free(void *mem)
|
||||
{
|
||||
_aligned_free(mem);
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
template <typename TYPE, typename ALG>
|
||||
class LDPCDecoder
|
||||
{
|
||||
@ -113,8 +142,8 @@ public:
|
||||
}
|
||||
LT = ldpc->links_total();
|
||||
delete ldpc;
|
||||
bnl = reinterpret_cast<TYPE *>(aligned_alloc(sizeof(TYPE), sizeof(TYPE) * LT));
|
||||
pty = reinterpret_cast<TYPE *>(aligned_alloc(sizeof(TYPE), sizeof(TYPE) * R));
|
||||
bnl = reinterpret_cast<TYPE *>(LDPCUtil::aligned_malloc(sizeof(TYPE), sizeof(TYPE) * LT));
|
||||
pty = reinterpret_cast<TYPE *>(LDPCUtil::aligned_malloc(sizeof(TYPE), sizeof(TYPE) * R));
|
||||
uint16_t *tmp = new uint16_t[R * CNL];
|
||||
for (int i = 0; i < q; ++i)
|
||||
for (int j = 0; j < M; ++j)
|
||||
@ -139,8 +168,8 @@ public:
|
||||
~LDPCDecoder()
|
||||
{
|
||||
if (initialized) {
|
||||
free(bnl);
|
||||
free(pty);
|
||||
LDPCUtil::aligned_free(bnl);
|
||||
LDPCUtil::aligned_free(pty);
|
||||
delete[] cnc;
|
||||
delete[] pos;
|
||||
delete[] inp;
|
||||
|
@ -7,7 +7,14 @@ Copyright 2019 <pabr@pabr.org>
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#ifndef _MSC_VER
|
||||
#include <unistd.h>
|
||||
#else
|
||||
#include <BaseTsd.h>
|
||||
typedef SSIZE_T ssize_t;
|
||||
#include <io.h>
|
||||
#include <malloc.h>
|
||||
#endif
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
#include <random>
|
||||
@ -21,6 +28,7 @@ Copyright 2019 <pabr@pabr.org>
|
||||
#include "algorithms.h"
|
||||
#include "ldpc.h"
|
||||
|
||||
|
||||
#if 0
|
||||
#include "flooding_decoder.h"
|
||||
static const int DEFAULT_TRIALS = 50;
|
||||
@ -129,7 +137,7 @@ int main(int argc, char **argv)
|
||||
|
||||
int BLOCKS = batch_size;
|
||||
ldpctool::code_type *code = new ldpctool::code_type[BLOCKS * CODE_LEN];
|
||||
void *aligned_buffer = aligned_alloc(sizeof(ldpctool::simd_type), sizeof(ldpctool::simd_type) * CODE_LEN);
|
||||
void *aligned_buffer = ldpctool::LDPCUtil::aligned_malloc(sizeof(ldpctool::simd_type), sizeof(ldpctool::simd_type) * CODE_LEN);
|
||||
ldpctool::simd_type *simd = reinterpret_cast<ldpctool::simd_type *>(aligned_buffer);
|
||||
|
||||
// Expect LLR values in int8_t format.
|
||||
@ -212,7 +220,7 @@ int main(int argc, char **argv)
|
||||
|
||||
delete ldpc;
|
||||
|
||||
free(aligned_buffer);
|
||||
ldpctool::LDPCUtil::aligned_free(aligned_buffer);
|
||||
delete[] code;
|
||||
|
||||
return 0;
|
||||
|
@ -4,6 +4,8 @@ LDPC testbench
|
||||
Copyright 2018 Ahmet Inan <xdsopl@gmail.com>
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <complex>
|
||||
#include "simd.h"
|
||||
|
@ -54,13 +54,18 @@
|
||||
#include "ldpc.h"
|
||||
#include "sdr.h"
|
||||
|
||||
#ifdef LINUX
|
||||
#include <signal.h>
|
||||
#ifdef LINUX
|
||||
#include <sys/wait.h>
|
||||
#endif
|
||||
#ifdef _MSC_VER
|
||||
#include <BaseTsd.h>
|
||||
typedef SSIZE_T ssize_t;
|
||||
#endif
|
||||
#include "ldpctool/layered_decoder.h"
|
||||
#include "ldpctool/testbench.h"
|
||||
#include "ldpctool/algorithms.h"
|
||||
#endif
|
||||
#include "ldpctool/ldpcworker.h"
|
||||
|
||||
namespace leansdr
|
||||
{
|
||||
@ -3041,8 +3046,6 @@ struct s2_fecdec : runnable
|
||||
pipewriter<int> *bitcount, *errcount;
|
||||
}; // s2_fecdec
|
||||
|
||||
#ifdef LINUX
|
||||
|
||||
// Soft LDPC decoder
|
||||
// Internally implemented LDPC tool. Replaces external LDPC decoder
|
||||
|
||||
@ -3230,6 +3233,8 @@ private:
|
||||
T q[SIZE];
|
||||
};
|
||||
|
||||
#if defined(USE_LDPC_TOOL) && !defined(_MSC_VER)
|
||||
|
||||
template <typename SOFTBIT, typename SOFTBYTE>
|
||||
struct s2_fecdec_helper : runnable
|
||||
{
|
||||
@ -3610,7 +3615,280 @@ struct s2_fecdec_helper : runnable
|
||||
std::deque<int> errcount_q;
|
||||
pipewriter<int> *bitcount, *errcount;
|
||||
}; // s2_fecdec_helper
|
||||
|
||||
#else // USE_LDPC_TOOL
|
||||
|
||||
template <typename SOFTBIT, typename SOFTBYTE>
|
||||
struct s2_fecdec_helper : runnable
|
||||
{
|
||||
int batch_size;
|
||||
int nhelpers;
|
||||
bool must_buffer;
|
||||
int max_trials;
|
||||
|
||||
s2_fecdec_helper(
|
||||
scheduler *sch,
|
||||
pipebuf<fecframe<SOFTBYTE>> &_in,
|
||||
pipebuf<bbframe> &_out,
|
||||
const char *_command,
|
||||
pipebuf<int> *_bitcount = nullptr,
|
||||
pipebuf<int> *_errcount = nullptr
|
||||
) :
|
||||
runnable(sch, "S2 fecdec io"),
|
||||
batch_size(16),
|
||||
nhelpers(1),
|
||||
must_buffer(false),
|
||||
max_trials(8),
|
||||
in(_in),
|
||||
out(_out),
|
||||
bitcount(opt_writer(_bitcount, 1)),
|
||||
errcount(opt_writer(_errcount, 1))
|
||||
{
|
||||
command = strdup(_command);
|
||||
|
||||
for (int mc = 0; mc < 32; ++mc) {
|
||||
for (int sf = 0; sf < 2; ++sf) {
|
||||
pools[mc][sf].procs = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
~s2_fecdec_helper()
|
||||
{
|
||||
free(command);
|
||||
killall(); // also deletes pools[mc][sf].procs if necessary
|
||||
}
|
||||
|
||||
void run()
|
||||
{
|
||||
// Send work until all helpers block.
|
||||
while (in.readable() >= 1 && !jobs.full())
|
||||
{
|
||||
if ((bbframe_q.size() != 0) && (out.writable() >= 1))
|
||||
{
|
||||
bbframe *pout = out.wr();
|
||||
pout->pls = bbframe_q.front().pls;
|
||||
std::copy(bbframe_q.front().bytes, bbframe_q.front().bytes + (58192 / 8), pout->bytes);
|
||||
bbframe_q.pop_front();
|
||||
out.written(1);
|
||||
}
|
||||
|
||||
if ((bitcount_q.size() != 0) && opt_writable(bitcount, 1))
|
||||
{
|
||||
opt_write(bitcount, bitcount_q.front());
|
||||
bitcount_q.pop_front();
|
||||
}
|
||||
|
||||
if ((errcount_q.size() != 0) && opt_writable(errcount, 1))
|
||||
{
|
||||
opt_write(errcount, errcount_q.front());
|
||||
errcount_q.pop_front();
|
||||
}
|
||||
|
||||
if (!jobs.empty() && jobs.peek()->h->b_out) {
|
||||
receive_frame(jobs.get());
|
||||
}
|
||||
|
||||
send_frame(in.rd());
|
||||
in.read(1);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
struct helper_instance
|
||||
{
|
||||
QThread *m_thread;
|
||||
LDPCWorker *m_worker;
|
||||
int batch_size;
|
||||
int b_in; // Jobs in input queue
|
||||
int b_out; // Jobs in output queue
|
||||
};
|
||||
struct pool
|
||||
{
|
||||
helper_instance *procs; // nullptr or [nprocs]
|
||||
int nprocs;
|
||||
int shift;
|
||||
} pools[32][2]; // [modcod][sf]
|
||||
struct helper_job
|
||||
{
|
||||
s2_pls pls;
|
||||
helper_instance *h;
|
||||
};
|
||||
|
||||
simplequeue<helper_job, 1024> jobs;
|
||||
|
||||
// Try to send a frame. Return false if helper was busy.
|
||||
bool send_frame(fecframe<SOFTBYTE> *pin)
|
||||
{
|
||||
pool *p = get_pool(&pin->pls);
|
||||
|
||||
for (int j = 0; j < p->nprocs; ++j)
|
||||
{
|
||||
int i = (p->shift + j) % p->nprocs;
|
||||
helper_instance *h = &p->procs[i];
|
||||
int iosize = (pin->pls.framebits() / 8) * sizeof(SOFTBYTE);
|
||||
|
||||
if (h->m_worker->busy()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
QByteArray data((char *)pin->bytes, iosize);
|
||||
QMetaObject::invokeMethod(h->m_worker, "process", Qt::QueuedConnection, Q_ARG(QByteArray, data));
|
||||
|
||||
p->shift = i;
|
||||
helper_job *job = jobs.put();
|
||||
job->pls = pin->pls;
|
||||
job->h = h;
|
||||
++h->b_in;
|
||||
|
||||
if (h->b_in >= h->batch_size)
|
||||
{
|
||||
h->b_in -= h->batch_size;
|
||||
h->b_out += h->batch_size;
|
||||
}
|
||||
|
||||
return true; // done sent to worker
|
||||
}
|
||||
|
||||
fprintf(stderr, "s2_fecdec_helper::send_frame: WARNING: all %d workers were busy: modcod=%d sf=%d)\n",
|
||||
p->nprocs, pin->pls.modcod, pin->pls.sf);
|
||||
return false; // all workers were busy
|
||||
}
|
||||
|
||||
// Return a pool of running helpers for a given modcod.
|
||||
pool *get_pool(const s2_pls *pls)
|
||||
{
|
||||
pool *p = &pools[pls->modcod][pls->sf];
|
||||
|
||||
if (!p->procs)
|
||||
{
|
||||
fprintf(stderr, "s2_fecdec_helper::get_pool: allocate %d workers: modcod=%d sf=%d\n",
|
||||
nhelpers, pls->modcod, pls->sf);
|
||||
p->procs = new helper_instance[nhelpers];
|
||||
|
||||
for (int i = 0; i < nhelpers; ++i) {
|
||||
spawn_helper(&p->procs[i], pls);
|
||||
}
|
||||
|
||||
p->nprocs = nhelpers;
|
||||
p->shift = 0;
|
||||
}
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
void killall()
|
||||
{
|
||||
qDebug() << "s2_fecdec_helper::killall";
|
||||
|
||||
for (int i = 0; i < 32; i++) // all MODCODs
|
||||
{
|
||||
for (int j = 0; j < 2; j++) // long and short frames
|
||||
{
|
||||
pool *p = &pools[i][j];
|
||||
|
||||
if (p->procs)
|
||||
{
|
||||
for (int i = 0; i < p->nprocs; ++i)
|
||||
{
|
||||
helper_instance *h = &p->procs[i];
|
||||
h->m_thread->quit();
|
||||
h->m_thread->wait();
|
||||
delete h->m_thread;
|
||||
h->m_thread = nullptr;
|
||||
delete h->m_worker;
|
||||
h->m_worker = nullptr;
|
||||
}
|
||||
|
||||
delete p->procs;
|
||||
p->procs = nullptr;
|
||||
p->nprocs = 0;
|
||||
}
|
||||
} // long and short frames
|
||||
} // all MODCODs
|
||||
}
|
||||
|
||||
// Spawn a helper thread.
|
||||
void spawn_helper(helper_instance *h, const s2_pls *pls)
|
||||
{
|
||||
qDebug() << "s2_fecdec_helper: Spawning LDPC thread: modcod=" << pls->modcod << " sf=" << pls->sf;
|
||||
h->m_thread = new QThread();
|
||||
h->m_worker = new LDPCWorker(pls->modcod, max_trials, batch_size, pls->sf);
|
||||
h->m_worker->moveToThread(h->m_thread);
|
||||
h->batch_size = batch_size;
|
||||
h->b_in = h->b_out = 0;
|
||||
h->m_thread->start();
|
||||
}
|
||||
|
||||
// Receive a finished job.
|
||||
void receive_frame(const helper_job *job)
|
||||
{
|
||||
// Read corrected frame from helper
|
||||
const s2_pls *pls = &job->pls;
|
||||
int iosize = (pls->framebits() / 8) * sizeof(ldpc_buf[0]);
|
||||
|
||||
// Blocking read - do we need to return faster?
|
||||
// If so, call m_worker->dataAvailable()
|
||||
QByteArray data = job->h->m_worker->data();
|
||||
memcpy(ldpc_buf, data.data(), data.size());
|
||||
|
||||
--job->h->b_out;
|
||||
// Decode BCH.
|
||||
const modcod_info *mcinfo = check_modcod(job->pls.modcod);
|
||||
const fec_info *fi = &fec_infos[job->pls.sf][mcinfo->rate];
|
||||
uint8_t *hardbytes = softbytes_harden(ldpc_buf, fi->kldpc / 8, bch_buf);
|
||||
size_t cwbytes = fi->kldpc / 8;
|
||||
//size_t msgbytes = fi->Kbch / 8;
|
||||
//size_t chkbytes = cwbytes - msgbytes;
|
||||
bch_interface *bch = s2bch.bchs[job->pls.sf][mcinfo->rate];
|
||||
int ncorr = bch->decode(hardbytes, cwbytes);
|
||||
|
||||
if (sch->debug2) {
|
||||
fprintf(stderr, "BCHCORR = %d\n", ncorr);
|
||||
}
|
||||
|
||||
bool corrupted = (ncorr < 0);
|
||||
// Report VBER
|
||||
bitcount_q.push_back(fi->Kbch);
|
||||
//opt_write(bitcount, fi->Kbch);
|
||||
errcount_q.push_front((ncorr >= 0) ? ncorr : fi->Kbch);
|
||||
//opt_write(errcount, (ncorr >= 0) ? ncorr : fi->Kbch);
|
||||
#if 0
|
||||
// TBD Some decoders want the bad packets.
|
||||
if ( corrupted ) {
|
||||
fprintf(stderr, "Passing bad frame\n");
|
||||
corrupted = false;
|
||||
}
|
||||
#endif
|
||||
if (!corrupted)
|
||||
{
|
||||
// Descramble and output
|
||||
bbframe_q.emplace_back();
|
||||
//bbframe *pout = out.wr();
|
||||
bbframe_q.back().pls = job->pls;
|
||||
bbscrambling.transform(hardbytes, fi->Kbch / 8, bbframe_q.back().bytes);
|
||||
//out.written(1);
|
||||
}
|
||||
|
||||
if (sch->debug) {
|
||||
fprintf(stderr, "%c", corrupted ? '!' : ncorr ? '.' : '_');
|
||||
}
|
||||
}
|
||||
|
||||
pipereader<fecframe<SOFTBYTE>> in;
|
||||
pipewriter<bbframe> out;
|
||||
char *command;
|
||||
SOFTBYTE ldpc_buf[64800 / 8];
|
||||
uint8_t bch_buf[64800 / 8]; // Temp storage for hardening before BCH
|
||||
s2_bch_engines s2bch;
|
||||
s2_bbscrambling bbscrambling;
|
||||
std::deque<bbframe> bbframe_q;
|
||||
std::deque<int> bitcount_q;
|
||||
std::deque<int> errcount_q;
|
||||
pipewriter<int> *bitcount, *errcount;
|
||||
}; // s2_fecdec_helper
|
||||
|
||||
#endif // USE_LDPC_TOOL
|
||||
|
||||
// S2 FRAMER
|
||||
// EN 302 307-1 section 5.1 Mode adaptation
|
||||
@ -3854,7 +4132,6 @@ private:
|
||||
{
|
||||
handle_ts(data, dfl, syncd, sync);
|
||||
}
|
||||
#ifdef LINUX
|
||||
else if (streamtype == 1)
|
||||
{
|
||||
if (fd_gse >= 0)
|
||||
@ -3874,7 +4151,6 @@ private:
|
||||
fprintf(stderr, "Unrecognized bbframe\n");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void handle_ts(uint8_t *data, uint16_t dfl, uint16_t syncd, uint8_t sync)
|
||||
|
@ -183,13 +183,11 @@ The controls specific to DVB-S are disabled and greyed out. These are: Fast Lock
|
||||
|
||||
<h5>B.2b.6: DVB-S2 specific - Soft LDPC decoder</h5>
|
||||
|
||||
This is for experimenters only working in Linux. It can be used to decode signals lower that ~10 db MER which is the limit of LDPC hard decoding as explained next (B.2b.7). Video degrades progressively down to about 7.5 dB MER and drops below this limit.
|
||||
|
||||
Runs the `ldpctool` program for soft LDPC decoding. Frames are sent on its standard input and decoded frames retrieved from its standard output. Two processes executing `ldpctool` are spawned but so far it seems that only one is effectively used.
|
||||
It can be used to decode signals lower that ~10 db MER which is the limit of LDPC hard decoding as explained next (B.2b.7). Video degrades progressively down to about 7.5 dB MER and drops below this limit.
|
||||
|
||||
Right clicking on this control opens a dialog where you can choose:
|
||||
|
||||
- The `ldpctool` executable. You have to use the `ldpctool` binary produced by the build of SDRangel.
|
||||
- The `ldpctool` executable. Obsolete.
|
||||
- The maximum of retries in LDPC decoding from 1 to 8.
|
||||
|
||||
<h5>B.2b.7: DVB-S2 specific - LDPC maximum number of bit flips allowed</h5>
|
||||
|
Loading…
Reference in New Issue
Block a user