mirror of
https://github.com/f4exb/sdrangel.git
synced 2025-07-31 13:02:27 -04:00
Merge pull request #1345 from srcejon/fix_1341
DATV Demod: Add support for LDPC on Windows
This commit is contained in:
commit
1057bc2882
@ -25,6 +25,7 @@ set(datv_SOURCES
|
|||||||
|
|
||||||
set(ldpc_SOURCES
|
set(ldpc_SOURCES
|
||||||
ldpctool/tables_handler.cpp
|
ldpctool/tables_handler.cpp
|
||||||
|
ldpctool/ldpcworker.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
set(datv_HEADERS
|
set(datv_HEADERS
|
||||||
@ -55,6 +56,7 @@ set(ldpc_HEADERS
|
|||||||
ldpctool/dvb_s2_tables.h
|
ldpctool/dvb_s2_tables.h
|
||||||
ldpctool/dvb_s2x_tables.h
|
ldpctool/dvb_s2x_tables.h
|
||||||
ldpctool/dvb_t2_tables.h
|
ldpctool/dvb_t2_tables.h
|
||||||
|
ldpctool/ldpcworker.h
|
||||||
)
|
)
|
||||||
|
|
||||||
include_directories(
|
include_directories(
|
||||||
@ -69,16 +71,10 @@ include_directories(
|
|||||||
set(TARGET_NAME demoddatv)
|
set(TARGET_NAME demoddatv)
|
||||||
set(INSTALL_FOLDER ${INSTALL_PLUGINS_DIR})
|
set(INSTALL_FOLDER ${INSTALL_PLUGINS_DIR})
|
||||||
|
|
||||||
if (LINUX)
|
add_library(${TARGET_NAME} SHARED
|
||||||
add_library(${TARGET_NAME} SHARED
|
${datv_SOURCES}
|
||||||
${datv_SOURCES}
|
${ldpc_SOURCES}
|
||||||
${ldpc_SOURCES}
|
)
|
||||||
)
|
|
||||||
else()
|
|
||||||
add_library(${TARGET_NAME} SHARED
|
|
||||||
${datv_SOURCES}
|
|
||||||
)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
target_link_libraries(${TARGET_NAME}
|
target_link_libraries(${TARGET_NAME}
|
||||||
Qt5::Core
|
Qt5::Core
|
||||||
@ -94,13 +90,11 @@ target_link_libraries(${TARGET_NAME}
|
|||||||
${SWRESAMPLE_LIBRARIES}
|
${SWRESAMPLE_LIBRARIES}
|
||||||
)
|
)
|
||||||
|
|
||||||
if (LINUX)
|
add_executable(ldpctool
|
||||||
add_executable(ldpctool
|
ldpctool/ldpc_tool.cpp
|
||||||
ldpctool/ldpc_tool.cpp
|
ldpctool/tables_handler.cpp
|
||||||
ldpctool/tables_handler.cpp
|
)
|
||||||
)
|
install(TARGETS ldpctool DESTINATION ${INSTALL_BIN_DIR})
|
||||||
install(TARGETS ldpctool DESTINATION ${INSTALL_BIN_DIR})
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if(FFMPEG_EXTERNAL)
|
if(FFMPEG_EXTERNAL)
|
||||||
add_dependencies(${TARGET_NAME} ffmpeg)
|
add_dependencies(${TARGET_NAME} ffmpeg)
|
||||||
|
@ -300,13 +300,8 @@ DATVDemodGUI::DATVDemodGUI(PluginAPI* objPluginAPI, DeviceUISet *deviceUISet, Ba
|
|||||||
CRightClickEnabler *audioMuteRightClickEnabler = new CRightClickEnabler(ui->audioMute);
|
CRightClickEnabler *audioMuteRightClickEnabler = new CRightClickEnabler(ui->audioMute);
|
||||||
connect(audioMuteRightClickEnabler, SIGNAL(rightClick(const QPoint &)), this, SLOT(audioSelect()));
|
connect(audioMuteRightClickEnabler, SIGNAL(rightClick(const QPoint &)), this, SLOT(audioSelect()));
|
||||||
|
|
||||||
#ifdef LINUX
|
|
||||||
CRightClickEnabler *ldpcToolRightClickEnabler = new CRightClickEnabler(ui->softLDPC);
|
CRightClickEnabler *ldpcToolRightClickEnabler = new CRightClickEnabler(ui->softLDPC);
|
||||||
connect(ldpcToolRightClickEnabler, SIGNAL(rightClick(const QPoint &)), this, SLOT(ldpcToolSelect()));
|
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->playerIndicator->setStyleSheet("QLabel { background-color: gray; border-radius: 8px; }");
|
||||||
ui->udpIndicator->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 }");
|
ui->maxBitflipsLabel->setStyleSheet("QLabel { color: white }");
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef LINUX
|
|
||||||
if (m_settings.m_standard == DATVDemodSettings::dvb_version::DVB_S)
|
if (m_settings.m_standard == DATVDemodSettings::dvb_version::DVB_S)
|
||||||
{
|
{
|
||||||
ui->softLDPC->setEnabled(false);
|
ui->softLDPC->setEnabled(false);
|
||||||
@ -388,7 +382,6 @@ void DATVDemodGUI::displaySettings()
|
|||||||
ui->softLDPC->setEnabled(true);
|
ui->softLDPC->setEnabled(true);
|
||||||
ui->softLDPC->setStyleSheet("QCheckBox { color: white }");
|
ui->softLDPC->setStyleSheet("QCheckBox { color: white }");
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
if (m_settings.m_standard == DATVDemodSettings::dvb_version::DVB_S)
|
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 }");
|
ui->maxBitflipsLabel->setStyleSheet("QLabel { color: white }");
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef LINUX
|
|
||||||
if (m_settings.m_standard == DATVDemodSettings::dvb_version::DVB_S)
|
if (m_settings.m_standard == DATVDemodSettings::dvb_version::DVB_S)
|
||||||
{
|
{
|
||||||
ui->softLDPC->setEnabled(false);
|
ui->softLDPC->setEnabled(false);
|
||||||
@ -669,7 +661,6 @@ void DATVDemodGUI::on_cmbStandard_currentIndexChanged(int index)
|
|||||||
ui->softLDPC->setEnabled(true);
|
ui->softLDPC->setEnabled(true);
|
||||||
ui->softLDPC->setStyleSheet("QCheckBox { color: white }");
|
ui->softLDPC->setStyleSheet("QCheckBox { color: white }");
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
if (m_settings.m_standard == DATVDemodSettings::dvb_version::DVB_S)
|
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()
|
void DATVDemodGUI::on_softLDPC_clicked()
|
||||||
{
|
{
|
||||||
#ifdef LINUX
|
|
||||||
m_settings.m_softLDPC = ui->softLDPC->isChecked();
|
m_settings.m_softLDPC = ui->softLDPC->isChecked();
|
||||||
applySettings();
|
applySettings();
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void DATVDemodGUI::on_maxBitflips_valueChanged(int value)
|
void DATVDemodGUI::on_maxBitflips_valueChanged(int value)
|
||||||
{
|
{
|
||||||
#ifdef LINUX
|
|
||||||
m_settings.m_maxBitflips = value;
|
m_settings.m_maxBitflips = value;
|
||||||
applySettings();
|
applySettings();
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void DATVDemodGUI::on_chkViterbi_clicked()
|
void DATVDemodGUI::on_chkViterbi_clicked()
|
||||||
|
@ -27,6 +27,12 @@
|
|||||||
|
|
||||||
#include "datvdemodsettings.h"
|
#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() :
|
DATVDemodSettings::DATVDemodSettings() :
|
||||||
m_channelMarker(nullptr),
|
m_channelMarker(nullptr),
|
||||||
m_rollupState(nullptr)
|
m_rollupState(nullptr)
|
||||||
@ -44,7 +50,7 @@ void DATVDemodSettings::resetToDefaults()
|
|||||||
m_modulation = BPSK;
|
m_modulation = BPSK;
|
||||||
m_fec = FEC12;
|
m_fec = FEC12;
|
||||||
m_softLDPC = false;
|
m_softLDPC = false;
|
||||||
m_softLDPCToolPath = "/opt/install/sdrangel/bin/ldpctool";
|
m_softLDPCToolPath = DEFAULT_LDPCTOOLPATH;
|
||||||
m_softLDPCMaxTrials = 8;
|
m_softLDPCMaxTrials = 8;
|
||||||
m_maxBitflips = 0;
|
m_maxBitflips = 0;
|
||||||
m_symbolRate = 250000;
|
m_symbolRate = 250000;
|
||||||
@ -208,7 +214,7 @@ bool DATVDemodSettings::deserialize(const QByteArray& data)
|
|||||||
|
|
||||||
d.readBool(32, &m_softLDPC, false);
|
d.readBool(32, &m_softLDPC, false);
|
||||||
d.readS32(33, &m_maxBitflips, 0);
|
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);
|
d.readS32(35, &tmp, 8);
|
||||||
m_softLDPCMaxTrials = tmp < 1 ? 1 : tmp > m_softLDPCMaxMaxTrials ? m_softLDPCMaxMaxTrials : tmp;
|
m_softLDPCMaxTrials = tmp < 1 ? 1 : tmp > m_softLDPCMaxMaxTrials ? m_softLDPCMaxMaxTrials : tmp;
|
||||||
d.readBool(36, &m_playerEnable, true);
|
d.readBool(36, &m_playerEnable, true);
|
||||||
|
@ -397,7 +397,6 @@ void DATVDemodSink::CleanUpDATVFramework()
|
|||||||
delete (leansdr::s2_fecdec<bool, leansdr::hard_sb>*) r_fecdec;
|
delete (leansdr::s2_fecdec<bool, leansdr::hard_sb>*) r_fecdec;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef LINUX
|
|
||||||
if (r_fecdecsoft != nullptr) {
|
if (r_fecdecsoft != nullptr) {
|
||||||
delete (leansdr::s2_fecdec_soft<leansdr::llr_t,leansdr::llr_sb>*) r_fecdecsoft;
|
delete (leansdr::s2_fecdec_soft<leansdr::llr_t,leansdr::llr_sb>*) r_fecdecsoft;
|
||||||
}
|
}
|
||||||
@ -405,7 +404,6 @@ void DATVDemodSink::CleanUpDATVFramework()
|
|||||||
if (r_fecdechelper != nullptr) {
|
if (r_fecdechelper != nullptr) {
|
||||||
delete (leansdr::s2_fecdec_helper<leansdr::llr_t,leansdr::llr_sb>*) r_fecdechelper;
|
delete (leansdr::s2_fecdec_helper<leansdr::llr_t,leansdr::llr_sb>*) r_fecdechelper;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
if (p_deframer != nullptr) {
|
if (p_deframer != nullptr) {
|
||||||
delete (leansdr::s2_deframer*) p_deframer;
|
delete (leansdr::s2_deframer*) p_deframer;
|
||||||
@ -515,10 +513,8 @@ void DATVDemodSink::ResetDATVFrameworkPointers()
|
|||||||
p_bbframes = nullptr;
|
p_bbframes = nullptr;
|
||||||
p_s2_deinterleaver = nullptr;
|
p_s2_deinterleaver = nullptr;
|
||||||
r_fecdec = nullptr;
|
r_fecdec = nullptr;
|
||||||
#ifdef LINUX
|
|
||||||
r_fecdecsoft = nullptr;
|
r_fecdecsoft = nullptr;
|
||||||
r_fecdechelper = nullptr;
|
r_fecdechelper = nullptr;
|
||||||
#endif
|
|
||||||
p_deframer = nullptr;
|
p_deframer = nullptr;
|
||||||
r_scope_symbols_dvbs2 = 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_vbitcount= new leansdr::pipebuf<int>(m_objScheduler, "Bits processed", BUF_S2PACKETS);
|
||||||
p_verrcount = new leansdr::pipebuf<int>(m_objScheduler, "Bits corrected", BUF_S2PACKETS);
|
p_verrcount = new leansdr::pipebuf<int>(m_objScheduler, "Bits corrected", BUF_S2PACKETS);
|
||||||
|
|
||||||
#ifdef LINUX
|
|
||||||
bool commandFileValid = false;
|
bool commandFileValid = false;
|
||||||
|
|
||||||
if (QFileInfo::exists(m_settings.m_softLDPCToolPath))
|
if (QFileInfo::exists(m_settings.m_softLDPCToolPath))
|
||||||
@ -1110,7 +1105,7 @@ void DATVDemodSink::InitDATVS2Framework()
|
|||||||
commandFileValid = fileInfo.isExecutable();
|
commandFileValid = fileInfo.isExecutable();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_settings.m_softLDPC && commandFileValid)
|
if (m_settings.m_softLDPC /*&& commandFileValid*/)
|
||||||
{
|
{
|
||||||
#if 0
|
#if 0
|
||||||
// Doesn't work...
|
// 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;
|
leansdr::s2_fecdec<bool, leansdr::hard_sb> *fecdec = (leansdr::s2_fecdec<bool, leansdr::hard_sb> * ) r_fecdec;
|
||||||
fecdec->bitflips=m_settings.m_maxBitflips;
|
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
|
// Deframe BB frames to TS packets
|
||||||
p_lock = new leansdr::pipebuf<int> (m_objScheduler, "lock", BUF_SLOW);
|
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");
|
QFileDialog fileDialog(this, "Select LDPC tool");
|
||||||
fileDialog.setOption(QFileDialog::DontUseNativeDialog, true);
|
fileDialog.setOption(QFileDialog::DontUseNativeDialog, true);
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
fileDialog.setNameFilter("*.exe");
|
||||||
|
#else
|
||||||
fileDialog.setFilter(QDir::Executable | QDir::Files);
|
fileDialog.setFilter(QDir::Executable | QDir::Files);
|
||||||
|
#endif
|
||||||
fileDialog.selectFile(m_fileName);
|
fileDialog.selectFile(m_fileName);
|
||||||
|
|
||||||
if (fileDialog.exec() == QDialog::Accepted)
|
if (fileDialog.exec() == QDialog::Accepted)
|
||||||
|
@ -8,10 +8,39 @@ Copyright 2018 Ahmet Inan <xdsopl@gmail.com>
|
|||||||
#define LAYERED_DECODER_HH
|
#define LAYERED_DECODER_HH
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#include <malloc.h>
|
||||||
|
#endif
|
||||||
#include "ldpc.h"
|
#include "ldpc.h"
|
||||||
|
|
||||||
namespace ldpctool {
|
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>
|
template <typename TYPE, typename ALG>
|
||||||
class LDPCDecoder
|
class LDPCDecoder
|
||||||
{
|
{
|
||||||
@ -113,8 +142,8 @@ public:
|
|||||||
}
|
}
|
||||||
LT = ldpc->links_total();
|
LT = ldpc->links_total();
|
||||||
delete ldpc;
|
delete ldpc;
|
||||||
bnl = reinterpret_cast<TYPE *>(aligned_alloc(sizeof(TYPE), sizeof(TYPE) * LT));
|
bnl = reinterpret_cast<TYPE *>(LDPCUtil::aligned_malloc(sizeof(TYPE), sizeof(TYPE) * LT));
|
||||||
pty = reinterpret_cast<TYPE *>(aligned_alloc(sizeof(TYPE), sizeof(TYPE) * R));
|
pty = reinterpret_cast<TYPE *>(LDPCUtil::aligned_malloc(sizeof(TYPE), sizeof(TYPE) * R));
|
||||||
uint16_t *tmp = new uint16_t[R * CNL];
|
uint16_t *tmp = new uint16_t[R * CNL];
|
||||||
for (int i = 0; i < q; ++i)
|
for (int i = 0; i < q; ++i)
|
||||||
for (int j = 0; j < M; ++j)
|
for (int j = 0; j < M; ++j)
|
||||||
@ -139,8 +168,8 @@ public:
|
|||||||
~LDPCDecoder()
|
~LDPCDecoder()
|
||||||
{
|
{
|
||||||
if (initialized) {
|
if (initialized) {
|
||||||
free(bnl);
|
LDPCUtil::aligned_free(bnl);
|
||||||
free(pty);
|
LDPCUtil::aligned_free(pty);
|
||||||
delete[] cnc;
|
delete[] cnc;
|
||||||
delete[] pos;
|
delete[] pos;
|
||||||
delete[] inp;
|
delete[] inp;
|
||||||
|
@ -7,7 +7,14 @@ Copyright 2019 <pabr@pabr.org>
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#ifndef _MSC_VER
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
#else
|
||||||
|
#include <BaseTsd.h>
|
||||||
|
typedef SSIZE_T ssize_t;
|
||||||
|
#include <io.h>
|
||||||
|
#include <malloc.h>
|
||||||
|
#endif
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <iomanip>
|
#include <iomanip>
|
||||||
#include <random>
|
#include <random>
|
||||||
@ -21,6 +28,7 @@ Copyright 2019 <pabr@pabr.org>
|
|||||||
#include "algorithms.h"
|
#include "algorithms.h"
|
||||||
#include "ldpc.h"
|
#include "ldpc.h"
|
||||||
|
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
#include "flooding_decoder.h"
|
#include "flooding_decoder.h"
|
||||||
static const int DEFAULT_TRIALS = 50;
|
static const int DEFAULT_TRIALS = 50;
|
||||||
@ -129,7 +137,7 @@ int main(int argc, char **argv)
|
|||||||
|
|
||||||
int BLOCKS = batch_size;
|
int BLOCKS = batch_size;
|
||||||
ldpctool::code_type *code = new ldpctool::code_type[BLOCKS * CODE_LEN];
|
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);
|
ldpctool::simd_type *simd = reinterpret_cast<ldpctool::simd_type *>(aligned_buffer);
|
||||||
|
|
||||||
// Expect LLR values in int8_t format.
|
// Expect LLR values in int8_t format.
|
||||||
@ -193,9 +201,6 @@ int main(int argc, char **argv)
|
|||||||
code[(j + n) * CODE_LEN + i] = reinterpret_cast<ldpctool::code_type *>(simd + i)[n];
|
code[(j + n) * CODE_LEN + i] = reinterpret_cast<ldpctool::code_type *>(simd + i)[n];
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < BLOCKS * CODE_LEN; ++i)
|
|
||||||
assert(!std::isnan(code[i]));
|
|
||||||
|
|
||||||
for (ssize_t pos = 0; pos < iosize;)
|
for (ssize_t pos = 0; pos < iosize;)
|
||||||
{
|
{
|
||||||
ssize_t nw = write(1, code + pos, iosize - pos);
|
ssize_t nw = write(1, code + pos, iosize - pos);
|
||||||
@ -212,7 +217,7 @@ int main(int argc, char **argv)
|
|||||||
|
|
||||||
delete ldpc;
|
delete ldpc;
|
||||||
|
|
||||||
free(aligned_buffer);
|
ldpctool::LDPCUtil::aligned_free(aligned_buffer);
|
||||||
delete[] code;
|
delete[] code;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
156
plugins/channelrx/demoddatv/ldpctool/ldpcworker.cpp
Normal file
156
plugins/channelrx/demoddatv/ldpctool/ldpcworker.cpp
Normal file
@ -0,0 +1,156 @@
|
|||||||
|
/*
|
||||||
|
LDPC testbench
|
||||||
|
Copyright 2018 Ahmet Inan <xdsopl@gmail.com>
|
||||||
|
|
||||||
|
Transformed into external decoder for third-party applications
|
||||||
|
Copyright 2019 <pabr@pabr.org>
|
||||||
|
|
||||||
|
Transformed again in to a Qt worker.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <QDebug>
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#include <malloc.h>
|
||||||
|
#endif
|
||||||
|
#include <iostream>
|
||||||
|
#include <iomanip>
|
||||||
|
#include <random>
|
||||||
|
#include <cmath>
|
||||||
|
#include <cassert>
|
||||||
|
#include <chrono>
|
||||||
|
#include <cstring>
|
||||||
|
#include <algorithm>
|
||||||
|
#include <functional>
|
||||||
|
#include "ldpcworker.h"
|
||||||
|
|
||||||
|
LDPCWorker::LDPCWorker(int modcod, int maxTrials, int batchSize, bool shortFrames) :
|
||||||
|
m_maxTrials(maxTrials),
|
||||||
|
m_aligned_buffer(nullptr),
|
||||||
|
m_ldpc(nullptr),
|
||||||
|
m_code(nullptr),
|
||||||
|
m_simd(nullptr)
|
||||||
|
{
|
||||||
|
// DVB-S2 MODCOD definitions
|
||||||
|
static const char *mc_tabnames[2][32] = { // [shortframes][modcod]
|
||||||
|
{// Normal frames
|
||||||
|
0, "B1", "B2", "B3", "B4", "B5", "B6", "B7",
|
||||||
|
"B8", "B9", "B10", "B11", "B5", "B6", "B7", "B9",
|
||||||
|
"B10", "B11", "B6", "B7", "B8", "B9", "B10", "B11",
|
||||||
|
"B7", "B8", "B8", "B10", "B11", 0, 0, 0},
|
||||||
|
{// Short frames
|
||||||
|
0, "C1", "C2", "C3", "C4", "C5", "C6", "C7",
|
||||||
|
"C8", "C9", "C10", 0, "C5", "C6", "C7", "C9",
|
||||||
|
"C10", 0, "C6", "C7", "C8", "C9", "C10", 0,
|
||||||
|
"C7", "C8", "C8", "C10", 0, 0, 0, 0}};
|
||||||
|
|
||||||
|
const char *tabname = mc_tabnames[shortFrames][modcod];
|
||||||
|
if (!tabname)
|
||||||
|
{
|
||||||
|
qCritical() << "LDPCWorker::LDPCWorker: unsupported modcod";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_ldpc = ldpctool::create_ldpc((char *)"S2", tabname[0], atoi(tabname + 1));
|
||||||
|
|
||||||
|
if (!m_ldpc)
|
||||||
|
{
|
||||||
|
qCritical() << "LDPCWorker::LDPCWorker: no such table!";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_codeLen = m_ldpc->code_len();
|
||||||
|
m_dataLen = m_ldpc->data_len();
|
||||||
|
|
||||||
|
m_decode.init(m_ldpc);
|
||||||
|
|
||||||
|
BLOCKS = batchSize;
|
||||||
|
m_code = new ldpctool::code_type[BLOCKS * m_codeLen];
|
||||||
|
m_aligned_buffer = ldpctool::LDPCUtil::aligned_malloc(sizeof(ldpctool::simd_type), sizeof(ldpctool::simd_type) * m_codeLen);
|
||||||
|
m_simd = reinterpret_cast<ldpctool::simd_type *>(m_aligned_buffer);
|
||||||
|
|
||||||
|
// Expect LLR values in int8_t format.
|
||||||
|
if (sizeof(ldpctool::code_type) != 1) {
|
||||||
|
qCritical() << "LDPCWorker::LDPCWorker: Unsupported code_type";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
LDPCWorker::~LDPCWorker()
|
||||||
|
{
|
||||||
|
m_condOut.wakeAll();
|
||||||
|
delete m_ldpc;
|
||||||
|
|
||||||
|
ldpctool::LDPCUtil::aligned_free(m_aligned_buffer);
|
||||||
|
delete[] m_code;
|
||||||
|
}
|
||||||
|
|
||||||
|
void LDPCWorker::process(QByteArray data)
|
||||||
|
{
|
||||||
|
int trials_count = 0;
|
||||||
|
int max_count = 0;
|
||||||
|
int num_decodes = 0;
|
||||||
|
|
||||||
|
int iosize = m_codeLen * sizeof(*m_code);
|
||||||
|
|
||||||
|
m_mutexIn.lock();
|
||||||
|
m_dataIn.append(data);
|
||||||
|
|
||||||
|
if (m_dataIn.size() >= BLOCKS)
|
||||||
|
{
|
||||||
|
for (int j = 0; j < BLOCKS; j++)
|
||||||
|
{
|
||||||
|
QByteArray inputData = m_dataIn.takeAt(0);
|
||||||
|
memcpy(m_code + j * m_codeLen, inputData.data(), inputData.size());
|
||||||
|
}
|
||||||
|
m_mutexIn.unlock();
|
||||||
|
|
||||||
|
for (int j = 0; j < BLOCKS; j += ldpctool::SIMD_WIDTH)
|
||||||
|
{
|
||||||
|
int blocks = j + ldpctool::SIMD_WIDTH > BLOCKS ? BLOCKS - j : ldpctool::SIMD_WIDTH;
|
||||||
|
|
||||||
|
for (int n = 0; n < blocks; ++n)
|
||||||
|
for (int i = 0; i < m_codeLen; ++i)
|
||||||
|
reinterpret_cast<ldpctool::code_type *>(m_simd + i)[n] = m_code[(j + n) * m_codeLen + i];
|
||||||
|
|
||||||
|
int count = m_decode(m_simd, m_simd + m_dataLen, m_maxTrials, blocks);
|
||||||
|
num_decodes++;
|
||||||
|
|
||||||
|
if (count < 0)
|
||||||
|
{
|
||||||
|
trials_count += m_maxTrials;
|
||||||
|
max_count++;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
trials_count += m_maxTrials - count;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (num_decodes == 20)
|
||||||
|
{
|
||||||
|
qDebug() << "ldpc_tool: trials: " << ((trials_count*100)/(num_decodes*m_maxTrials)) << "% max: "
|
||||||
|
<< ((max_count*100)/num_decodes) << "% at converging to a code word (max trials: " << m_maxTrials << ")";
|
||||||
|
trials_count = 0;
|
||||||
|
max_count = 0;
|
||||||
|
num_decodes = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int n = 0; n < blocks; ++n)
|
||||||
|
for (int i = 0; i < m_codeLen; ++i)
|
||||||
|
m_code[(j + n) * m_codeLen + i] = reinterpret_cast<ldpctool::code_type *>(m_simd + i)[n];
|
||||||
|
}
|
||||||
|
|
||||||
|
m_mutexOut.lock();
|
||||||
|
for (int j = 0; j < BLOCKS; j++)
|
||||||
|
{
|
||||||
|
QByteArray outputData((const char *)m_code + j * m_codeLen, iosize);
|
||||||
|
m_dataOut.append(outputData);
|
||||||
|
}
|
||||||
|
m_condOut.wakeAll();
|
||||||
|
m_mutexOut.unlock();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_mutexIn.unlock();
|
||||||
|
}
|
||||||
|
}
|
94
plugins/channelrx/demoddatv/ldpctool/ldpcworker.h
Normal file
94
plugins/channelrx/demoddatv/ldpctool/ldpcworker.h
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
///////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Copyright (C) 2022 Jon Beniston, M7RCE //
|
||||||
|
// //
|
||||||
|
// 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/>. //
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
#include <QByteArray>
|
||||||
|
#include <QMutex>
|
||||||
|
#include <QWaitCondition>
|
||||||
|
|
||||||
|
#include "testbench.h"
|
||||||
|
#include "algorithms.h"
|
||||||
|
#include "ldpc.h"
|
||||||
|
#include "layered_decoder.h"
|
||||||
|
|
||||||
|
class LDPCWorker : public QObject {
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
LDPCWorker(int modcod, int maxTrials, int batchSize, bool shortFrames);
|
||||||
|
~LDPCWorker();
|
||||||
|
|
||||||
|
// Are we busy
|
||||||
|
bool busy()
|
||||||
|
{
|
||||||
|
QMutexLocker locker(&m_mutexIn);
|
||||||
|
return m_dataIn.size() >= BLOCKS;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Is processed data available?
|
||||||
|
bool dataAvailable()
|
||||||
|
{
|
||||||
|
QMutexLocker locker(&m_mutexOut);
|
||||||
|
return !m_dataOut.isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get processed data
|
||||||
|
QByteArray data()
|
||||||
|
{
|
||||||
|
m_mutexOut.lock();
|
||||||
|
if (m_dataOut.isEmpty()) {
|
||||||
|
m_condOut.wait(&m_mutexOut);
|
||||||
|
}
|
||||||
|
QByteArray data = m_dataOut.takeAt(0);
|
||||||
|
m_mutexOut.unlock();
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
void process(QByteArray data);
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void finished();
|
||||||
|
|
||||||
|
private:
|
||||||
|
QMutex m_mutexIn;
|
||||||
|
QMutex m_mutexOut;
|
||||||
|
QWaitCondition m_condOut;
|
||||||
|
QList<QByteArray> m_dataIn;
|
||||||
|
QList<QByteArray> m_dataOut;
|
||||||
|
int m_maxTrials;
|
||||||
|
int BLOCKS;
|
||||||
|
int m_codeLen;
|
||||||
|
int m_dataLen;
|
||||||
|
void *m_aligned_buffer;
|
||||||
|
|
||||||
|
ldpctool::LDPCInterface *m_ldpc;
|
||||||
|
ldpctool::code_type *m_code;
|
||||||
|
ldpctool::simd_type *m_simd;
|
||||||
|
|
||||||
|
typedef ldpctool::NormalUpdate<ldpctool::simd_type> update_type;
|
||||||
|
//typedef SelfCorrectedUpdate<simd_type> update_type;
|
||||||
|
|
||||||
|
//typedef MinSumAlgorithm<simd_type, update_type> algorithm_type;
|
||||||
|
//typedef OffsetMinSumAlgorithm<simd_type, update_type, FACTOR> algorithm_type;
|
||||||
|
typedef ldpctool::MinSumCAlgorithm<ldpctool::simd_type, update_type, ldpctool::FACTOR> algorithm_type;
|
||||||
|
//typedef LogDomainSPA<simd_type, update_type> algorithm_type;
|
||||||
|
//typedef LambdaMinAlgorithm<simd_type, update_type, 3> algorithm_type;
|
||||||
|
//typedef SumProductAlgorithm<simd_type, update_type> algorithm_type;
|
||||||
|
|
||||||
|
ldpctool::LDPCDecoder<ldpctool::simd_type, algorithm_type> m_decode;
|
||||||
|
};
|
@ -4,6 +4,8 @@ LDPC testbench
|
|||||||
Copyright 2018 Ahmet Inan <xdsopl@gmail.com>
|
Copyright 2018 Ahmet Inan <xdsopl@gmail.com>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <complex>
|
#include <complex>
|
||||||
#include "simd.h"
|
#include "simd.h"
|
||||||
|
@ -54,13 +54,18 @@
|
|||||||
#include "ldpc.h"
|
#include "ldpc.h"
|
||||||
#include "sdr.h"
|
#include "sdr.h"
|
||||||
|
|
||||||
#ifdef LINUX
|
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
|
#ifdef LINUX
|
||||||
#include <sys/wait.h>
|
#include <sys/wait.h>
|
||||||
|
#endif
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#include <BaseTsd.h>
|
||||||
|
typedef SSIZE_T ssize_t;
|
||||||
|
#endif
|
||||||
#include "ldpctool/layered_decoder.h"
|
#include "ldpctool/layered_decoder.h"
|
||||||
#include "ldpctool/testbench.h"
|
#include "ldpctool/testbench.h"
|
||||||
#include "ldpctool/algorithms.h"
|
#include "ldpctool/algorithms.h"
|
||||||
#endif
|
#include "ldpctool/ldpcworker.h"
|
||||||
|
|
||||||
namespace leansdr
|
namespace leansdr
|
||||||
{
|
{
|
||||||
@ -3041,8 +3046,6 @@ struct s2_fecdec : runnable
|
|||||||
pipewriter<int> *bitcount, *errcount;
|
pipewriter<int> *bitcount, *errcount;
|
||||||
}; // s2_fecdec
|
}; // s2_fecdec
|
||||||
|
|
||||||
#ifdef LINUX
|
|
||||||
|
|
||||||
// Soft LDPC decoder
|
// Soft LDPC decoder
|
||||||
// Internally implemented LDPC tool. Replaces external LDPC decoder
|
// Internally implemented LDPC tool. Replaces external LDPC decoder
|
||||||
|
|
||||||
@ -3230,6 +3233,8 @@ private:
|
|||||||
T q[SIZE];
|
T q[SIZE];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#if defined(USE_LDPC_TOOL) && !defined(_MSC_VER)
|
||||||
|
|
||||||
template <typename SOFTBIT, typename SOFTBYTE>
|
template <typename SOFTBIT, typename SOFTBYTE>
|
||||||
struct s2_fecdec_helper : runnable
|
struct s2_fecdec_helper : runnable
|
||||||
{
|
{
|
||||||
@ -3610,7 +3615,280 @@ struct s2_fecdec_helper : runnable
|
|||||||
std::deque<int> errcount_q;
|
std::deque<int> errcount_q;
|
||||||
pipewriter<int> *bitcount, *errcount;
|
pipewriter<int> *bitcount, *errcount;
|
||||||
}; // s2_fecdec_helper
|
}; // 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
|
#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
|
// S2 FRAMER
|
||||||
// EN 302 307-1 section 5.1 Mode adaptation
|
// EN 302 307-1 section 5.1 Mode adaptation
|
||||||
@ -3854,7 +4132,6 @@ private:
|
|||||||
{
|
{
|
||||||
handle_ts(data, dfl, syncd, sync);
|
handle_ts(data, dfl, syncd, sync);
|
||||||
}
|
}
|
||||||
#ifdef LINUX
|
|
||||||
else if (streamtype == 1)
|
else if (streamtype == 1)
|
||||||
{
|
{
|
||||||
if (fd_gse >= 0)
|
if (fd_gse >= 0)
|
||||||
@ -3874,7 +4151,6 @@ private:
|
|||||||
fprintf(stderr, "Unrecognized bbframe\n");
|
fprintf(stderr, "Unrecognized bbframe\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void handle_ts(uint8_t *data, uint16_t dfl, uint16_t syncd, uint8_t sync)
|
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>
|
<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.
|
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.
|
|
||||||
|
|
||||||
Right clicking on this control opens a dialog where you can choose:
|
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.
|
- 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>
|
<h5>B.2b.7: DVB-S2 specific - LDPC maximum number of bit flips allowed</h5>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user