diff --git a/plugins/channelrx/demoddatv/datvdemodsettings.cpp b/plugins/channelrx/demoddatv/datvdemodsettings.cpp index d4e44b5ef..4f98364bb 100644 --- a/plugins/channelrx/demoddatv/datvdemodsettings.cpp +++ b/plugins/channelrx/demoddatv/datvdemodsettings.cpp @@ -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(); diff --git a/plugins/channelrx/demoddatv/datvdemodsettings.h b/plugins/channelrx/demoddatv/datvdemodsettings.h index fe03272b8..a52cf806b 100644 --- a/plugins/channelrx/demoddatv/datvdemodsettings.h +++ b/plugins/channelrx/demoddatv/datvdemodsettings.h @@ -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(); diff --git a/plugins/channelrx/demoddatv/datvdemodsink.cpp b/plugins/channelrx/demoddatv/datvdemodsink.cpp index 496e97259..1877b2465 100644 --- a/plugins/channelrx/demoddatv/datvdemodsink.cpp +++ b/plugins/channelrx/demoddatv/datvdemodsink.cpp @@ -431,6 +431,10 @@ void DATVDemodSink::CleanUpDATVFramework(bool blnRelease) { delete (leansdr::s2_fecdec_soft*) r_fecdecsoft; } + if(r_fecdechelper != nullptr) + { + delete (leansdr::s2_fecdec_helper*) 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 > *) p_fecframes ); // Decode FEC-protected frames into plain BB frames. - r_fecdec = new leansdr::s2_fecdec_helper( + r_fecdechelper = new leansdr::s2_fecdec_helper( m_objScheduler, *(leansdr::pipebuf< leansdr::fecframe > *) p_fecframes, *(leansdr::pipebuf *) p_bbframes, @@ -1193,8 +1198,8 @@ void DATVDemodSink::InitDATVS2Framework() p_vbitcount, p_verrcount) ; - leansdr::s2_fecdec_helper *fecdec = (leansdr::s2_fecdec_helper *) r_fecdec; - const int nhelpers = 2; + leansdr::s2_fecdec_helper *fecdec = (leansdr::s2_fecdec_helper *) r_fecdechelper; + const int nhelpers = 4; fecdec->nhelpers = nhelpers; fecdec->must_buffer = false; fecdec->max_trials = m_settings.m_softLDPCMaxTrials; diff --git a/plugins/channelrx/demoddatv/datvdemodsink.h b/plugins/channelrx/demoddatv/datvdemodsink.h index bc5754446..be81bc909 100644 --- a/plugins/channelrx/demoddatv/datvdemodsink.h +++ b/plugins/channelrx/demoddatv/datvdemodsink.h @@ -225,6 +225,7 @@ private: void *p_s2_deinterleaver; void *r_fecdec; void *r_fecdecsoft; + void *r_fecdechelper; void *p_deframer; //DECIMATION diff --git a/plugins/channelrx/demoddatv/datvdvbs2ldpcdialog.cpp b/plugins/channelrx/demoddatv/datvdvbs2ldpcdialog.cpp index a098acd8f..6b9e5fd2d 100644 --- a/plugins/channelrx/demoddatv/datvdvbs2ldpcdialog.cpp +++ b/plugins/channelrx/demoddatv/datvdvbs2ldpcdialog.cpp @@ -19,6 +19,7 @@ #include #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); } diff --git a/plugins/channelrx/demoddatv/datvdvbs2ldpcdialog.ui b/plugins/channelrx/demoddatv/datvdvbs2ldpcdialog.ui index 62cac97f7..521dc5638 100644 --- a/plugins/channelrx/demoddatv/datvdvbs2ldpcdialog.ui +++ b/plugins/channelrx/demoddatv/datvdvbs2ldpcdialog.ui @@ -31,11 +31,17 @@ + + + 55 + 0 + + 1 - 8 + 25 10 diff --git a/plugins/channelrx/demoddatv/ldpctool/ldpc_tool.cpp b/plugins/channelrx/demoddatv/ldpctool/ldpc_tool.cpp index 7aa7344b0..ef4b2a8ea 100644 --- a/plugins/channelrx/demoddatv/ldpctool/ldpc_tool.cpp +++ b/plugins/channelrx/demoddatv/ldpctool/ldpc_tool.cpp @@ -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(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(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) diff --git a/plugins/channelrx/demoddatv/leansdr/dvbs2.h b/plugins/channelrx/demoddatv/leansdr/dvbs2.h index 3d3ca2427..ef8642dd1 100644 --- a/plugins/channelrx/demoddatv/leansdr/dvbs2.h +++ b/plugins/channelrx/demoddatv/leansdr/dvbs2.h @@ -37,6 +37,8 @@ #include "sdr.h" #ifdef LINUX +#include +#include #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);