DATV: enhancement and fixes to DVBS2 external LDPC tool process. Implements #804

This commit is contained in:
f4exb 2021-03-10 07:46:25 +01:00
parent c575c02791
commit 233f512f9c
8 changed files with 136 additions and 45 deletions

View File

@ -197,7 +197,7 @@ bool DATVDemodSettings::deserialize(const QByteArray& data)
d.readS32(33, &m_maxBitflips, 0);
d.readString(34, &m_softLDPCToolPath, "/opt/install/sdrangel/bin/ldpctool");
d.readS32(35, &tmp, 8);
m_softLDPCMaxTrials = tmp < 1 ? 1 : tmp > 8 ? 8 : tmp;
m_softLDPCMaxTrials = tmp < 1 ? 1 : tmp > m_softLDPCMaxMaxTrials ? m_softLDPCMaxMaxTrials : tmp;
validateSystemConfiguration();

View File

@ -106,6 +106,7 @@ struct DATVDemodSettings
uint16_t m_reverseAPIPort;
uint16_t m_reverseAPIDeviceIndex;
uint16_t m_reverseAPIChannelIndex;
static const int m_softLDPCMaxMaxTrials = 25;
DATVDemodSettings();
void resetToDefaults();

View File

@ -431,6 +431,10 @@ void DATVDemodSink::CleanUpDATVFramework(bool blnRelease)
{
delete (leansdr::s2_fecdec_soft<leansdr::llr_t,leansdr::llr_sb>*) r_fecdecsoft;
}
if(r_fecdechelper != nullptr)
{
delete (leansdr::s2_fecdec_helper<leansdr::llr_t,leansdr::llr_sb>*) r_fecdechelper;
}
#endif
if(p_deframer != nullptr)
@ -442,7 +446,7 @@ void DATVDemodSink::CleanUpDATVFramework(bool blnRelease)
{
delete r_scope_symbols_dvbs2;
}
}
} // blnRelease
m_objScheduler=nullptr;
@ -547,6 +551,7 @@ void DATVDemodSink::CleanUpDATVFramework(bool blnRelease)
p_s2_deinterleaver = nullptr;
r_fecdec = nullptr;
r_fecdecsoft = nullptr;
r_fecdechelper = nullptr;
p_deframer = nullptr;
r_scope_symbols_dvbs2 = nullptr;
}
@ -893,7 +898,7 @@ void DATVDemodSink::InitDATVS2Framework()
m_blnDVBInitialized = false;
m_lngReadIQ = 0;
CleanUpDATVFramework(false);
CleanUpDATVFramework(true);
qDebug() << "DATVDemodSink::InitDATVS2Framework:"
<< " Standard: " << m_settings.m_standard
@ -1185,7 +1190,7 @@ void DATVDemodSink::InitDATVS2Framework()
*(leansdr::pipebuf< leansdr::fecframe<leansdr::llr_sb> > *) p_fecframes
);
// Decode FEC-protected frames into plain BB frames.
r_fecdec = new leansdr::s2_fecdec_helper<leansdr::llr_t, leansdr::llr_sb>(
r_fecdechelper = new leansdr::s2_fecdec_helper<leansdr::llr_t, leansdr::llr_sb>(
m_objScheduler,
*(leansdr::pipebuf< leansdr::fecframe<leansdr::llr_sb> > *) p_fecframes,
*(leansdr::pipebuf<leansdr::bbframe> *) p_bbframes,
@ -1193,8 +1198,8 @@ void DATVDemodSink::InitDATVS2Framework()
p_vbitcount,
p_verrcount)
;
leansdr::s2_fecdec_helper<leansdr::llr_t, leansdr::llr_sb> *fecdec = (leansdr::s2_fecdec_helper<leansdr::llr_t, leansdr::llr_sb> *) r_fecdec;
const int nhelpers = 2;
leansdr::s2_fecdec_helper<leansdr::llr_t, leansdr::llr_sb> *fecdec = (leansdr::s2_fecdec_helper<leansdr::llr_t, leansdr::llr_sb> *) r_fecdechelper;
const int nhelpers = 4;
fecdec->nhelpers = nhelpers;
fecdec->must_buffer = false;
fecdec->max_trials = m_settings.m_softLDPCMaxTrials;

View File

@ -225,6 +225,7 @@ private:
void *p_s2_deinterleaver;
void *r_fecdec;
void *r_fecdecsoft;
void *r_fecdechelper;
void *p_deframer;
//DECIMATION

View File

@ -19,6 +19,7 @@
#include <QFileDialog>
#include "datvdvbs2ldpcdialog.h"
#include "datvdemodsettings.h"
#include "ui_datvdvbs2ldpcdialog.h"
DatvDvbS2LdpcDialog::DatvDvbS2LdpcDialog(QWidget* parent) :
@ -46,7 +47,8 @@ void DatvDvbS2LdpcDialog::setFileName(const QString& fileName)
void DatvDvbS2LdpcDialog::setMaxTrials(int maxTrials)
{
m_maxTrials = maxTrials < 1 ? 1 : maxTrials > 8 ? 8 : maxTrials;
m_maxTrials = maxTrials < 1 ? 1 :
maxTrials > DATVDemodSettings::m_softLDPCMaxMaxTrials ? DATVDemodSettings::m_softLDPCMaxMaxTrials : maxTrials;
ui->maxTrials->setValue(m_maxTrials);
}

View File

@ -31,11 +31,17 @@
</item>
<item>
<widget class="QSpinBox" name="maxTrials">
<property name="minimumSize">
<size>
<width>55</width>
<height>0</height>
</size>
</property>
<property name="minimum">
<number>1</number>
</property>
<property name="maximum">
<number>8</number>
<number>25</number>
</property>
<property name="displayIntegerBase">
<number>10</number>

View File

@ -136,6 +136,10 @@ int main(int argc, char **argv)
if (sizeof(ldpctool::code_type) != 1)
fail("Bug: Unsupported code_type");
int trials_count = 0;
int max_count = 0;
int num_decodes = 0;
while (true)
{
ssize_t iosize = BLOCKS * CODE_LEN * sizeof(*code);
@ -153,8 +157,6 @@ int main(int argc, char **argv)
pos += nr;
}
int iterations = 0;
int num_decodes = 0;
for (int j = 0; j < BLOCKS; j += ldpctool::SIMD_WIDTH)
{
@ -164,24 +166,31 @@ int main(int argc, char **argv)
for (int i = 0; i < CODE_LEN; ++i)
reinterpret_cast<ldpctool::code_type *>(simd + i)[n] = code[(j + n) * CODE_LEN + i];
int trials = max_trials;
int count = decode(simd, simd + DATA_LEN, trials, blocks);
++num_decodes;
int count = decode(simd, simd + DATA_LEN, max_trials, blocks);
num_decodes++;
if (count < 0)
{
trials_count += max_trials;
max_count++;
}
else
{
trials_count += max_trials - count;
}
if (num_decodes == 20)
{
fprintf(stderr, "ldpc_tool: trials: %d%% max: %d%% at converging to a code word\n",
(trials_count*100)/(num_decodes*max_trials), (max_count*100)/num_decodes);
trials_count = 0;
max_count = 0;
num_decodes = 0;
}
for (int n = 0; n < blocks; ++n)
for (int i = 0; i < CODE_LEN; ++i)
code[(j + n) * CODE_LEN + i] = reinterpret_cast<ldpctool::code_type *>(simd + i)[n];
if (count < 0)
{
iterations += blocks * trials;
std::cerr << "ldpc_tool: decoder failed at converging to a code word in " << trials << " trials" << std::endl;
break;
}
else
{
iterations += blocks * (trials - count);
}
}
for (int i = 0; i < BLOCKS * CODE_LEN; ++i)

View File

@ -37,6 +37,8 @@
#include "sdr.h"
#ifdef LINUX
#include <signal.h>
#include <sys/wait.h>
#include "ldpctool/layered_decoder.h"
#include "ldpctool/testbench.h"
#include "ldpctool/algorithms.h"
@ -2379,6 +2381,7 @@ struct s2_fecdec_helper : runnable
~s2_fecdec_helper()
{
free(command);
killall();
}
void run()
@ -2424,6 +2427,7 @@ struct s2_fecdec_helper : runnable
int batch_size; // Latency
int b_in; // Jobs in input queue
int b_out; // Jobs in output queue
int pid; // PID of the child
};
struct pool
{
@ -2451,10 +2455,13 @@ struct s2_fecdec_helper : runnable
int nw = write(h->fd_tx, pin->bytes, iosize);
if (nw < 0 && errno == EWOULDBLOCK)
{
lseek(h->fd_tx, 0, SEEK_SET); // allow new writes on this worker
continue; // next worker
}
if (nw < 0)
fatal("write(LDPC helper");
if (nw != iosize)
else if (nw != iosize)
fatal("partial write(LDPC helper)");
helper_job *job = jobs.put();
@ -2471,9 +2478,9 @@ struct s2_fecdec_helper : runnable
return true; // done sent to worker
}
fprintf(stderr, "s2_fecdec_helper::send_frame: WARNING: all %d workers are busy: modcod=%d sf=%d)\n",
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 are busy
return false; // all workers were busy
}
// Return a pool of running helpers for a given modcod.
@ -2494,6 +2501,42 @@ struct s2_fecdec_helper : runnable
return p;
}
void killall()
{
fprintf(stderr, "s2_fecdec_helper::killall\n");
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];
fprintf(stderr, "s2_fecdec_helper::killall: killing %d\n", h->pid);
int rc = kill(h->pid, SIGKILL);
if (rc < 0) {
fatal("s2_fecdec_helper::killall");
} else {
int cs;
waitpid(h->pid, &cs, 0);
}
// reset pipes
lseek(h->fd_tx, 0, SEEK_SET);
lseek(h->fd_rx, 0, SEEK_SET);
}
delete p->procs;
p->procs = nullptr;
p->nprocs = 0;
}
} // long and short frames
} // all MODCODs
}
// Spawn a helper process.
void spawn_helper(helper_instance *h, const s2_pls *pls)
{
@ -2507,19 +2550,31 @@ struct s2_fecdec_helper : runnable
// macOS does not have F_SETPIPE_SZ and there
// is no way to change the buffer size
#ifndef __APPLE__
if (fcntl(tx[0], F_SETPIPE_SZ, pipesize) < 0 ||
fcntl(rx[0], F_SETPIPE_SZ, pipesize) < 0 ||
fcntl(tx[1], F_SETPIPE_SZ, pipesize) < 0 ||
fcntl(rx[1], F_SETPIPE_SZ, pipesize) < 0)
long min_pipe_size = (long) fcntl(tx[0], F_GETPIPE_SZ);
long pipe_size = (long) fcntl(rx[0], F_GETPIPE_SZ);
min_pipe_size = std::min(min_pipe_size, pipe_size);
pipe_size = (long) fcntl(tx[1], F_GETPIPE_SZ);
min_pipe_size = std::min(min_pipe_size, pipe_size);
pipe_size = (long) fcntl(rx[1], F_GETPIPE_SZ);
min_pipe_size = std::min(min_pipe_size, pipe_size);
if (min_pipe_size < pipesize)
{
fprintf(stderr,
"*** Failed to increase pipe size.\n"
"*** Try echo %d > /proc/sys/fs/pipe-max-size\n",
pipesize);
if (must_buffer)
fatal("F_SETPIPE_SZ");
else
fprintf(stderr, "*** Throughput will be suboptimal.\n");
if (fcntl(tx[0], F_SETPIPE_SZ, pipesize) < 0 ||
fcntl(rx[0], F_SETPIPE_SZ, pipesize) < 0 ||
fcntl(tx[1], F_SETPIPE_SZ, pipesize) < 0 ||
fcntl(rx[1], F_SETPIPE_SZ, pipesize) < 0)
{
fprintf(stderr,
"*** Failed to increase pipe size from %ld.\n"
"*** Try echo %d > /proc/sys/fs/pipe-max-size\n",
min_pipe_size,
pipesize);
if (must_buffer)
fatal("F_SETPIPE_SZ");
else
fprintf(stderr, "*** Throughput will be suboptimal.\n");
}
}
#endif
// vfork() differs from fork(2) in that the calling thread is
@ -2552,15 +2607,19 @@ struct s2_fecdec_helper : runnable
fatal(command);
}
h->pid = child;
h->fd_tx = tx[1];
close(tx[0]);
h->fd_rx = rx[0];
close(rx[1]);
h->batch_size = batch_size; // TBD
h->b_in = h->b_out = 0;
int flags = fcntl(h->fd_tx, F_GETFL);
if (fcntl(h->fd_tx, F_SETFL, flags | O_NONBLOCK))
fatal("fcntl(helper)");
int flags_tx = fcntl(h->fd_tx, F_GETFL);
if (fcntl(h->fd_tx, F_SETFL, flags_tx | O_NONBLOCK))
fatal("fcntl_tx(helper)");
int flags_rx = fcntl(h->fd_rx, F_GETFL);
if (fcntl(h->fd_rx, F_SETFL, flags_rx | O_NONBLOCK))
fatal("fcntl_rx(helper)");
}
// Receive a finished job.
@ -2570,10 +2629,18 @@ struct s2_fecdec_helper : runnable
const s2_pls *pls = &job->pls;
int iosize = (pls->framebits() / 8) * sizeof(ldpc_buf[0]);
int nr = read(job->h->fd_rx, ldpc_buf, iosize);
if (nr < 0)
fatal("read(LDPC helper)");
if (nr != iosize)
fatal("partial read(LDPC helper)");
{
if (errno != EAGAIN) { // if no data then try again next time
fatal("s2_fecdec_helper::receive_frame read error");
}
}
else if (nr != iosize)
{
fprintf(stderr, "s2_fecdec_helper::receive_frame: %d bytes read vs %d", nr, iosize);
}
--job->h->b_out;
// Decode BCH.
const modcod_info *mcinfo = check_modcod(job->pls.modcod);