mirror of
https://github.com/f4exb/sdrangel.git
synced 2025-02-20 04:32:17 -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
|
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.
|
||||||
@ -212,7 +220,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;
|
||||||
|
@ -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…
Reference in New Issue
Block a user