diff --git a/plugins/channelrx/demoddatv/ldpctool/ldpcworker.cpp b/plugins/channelrx/demoddatv/ldpctool/ldpcworker.cpp new file mode 100644 index 000000000..4976deaed --- /dev/null +++ b/plugins/channelrx/demoddatv/ldpctool/ldpcworker.cpp @@ -0,0 +1,159 @@ +/* +LDPC testbench +Copyright 2018 Ahmet Inan + +Transformed into external decoder for third-party applications +Copyright 2019 + +Transformed again in to a Qt worker. +*/ + +#include + +#include +#ifdef _MSC_VER +#include +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#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(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(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(m_simd + i)[n]; + } + + for (int i = 0; i < BLOCKS * m_codeLen; ++i) + assert(!std::isnan(m_code[i])); + + 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(); + } +} diff --git a/plugins/channelrx/demoddatv/ldpctool/ldpcworker.h b/plugins/channelrx/demoddatv/ldpctool/ldpcworker.h new file mode 100644 index 000000000..b794107c9 --- /dev/null +++ b/plugins/channelrx/demoddatv/ldpctool/ldpcworker.h @@ -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 . // +/////////////////////////////////////////////////////////////////////////////////// + +#include +#include +#include +#include + +#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 m_dataIn; + QList 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 update_type; + //typedef SelfCorrectedUpdate update_type; + + //typedef MinSumAlgorithm algorithm_type; + //typedef OffsetMinSumAlgorithm algorithm_type; + typedef ldpctool::MinSumCAlgorithm algorithm_type; + //typedef LogDomainSPA algorithm_type; + //typedef LambdaMinAlgorithm algorithm_type; + //typedef SumProductAlgorithm algorithm_type; + + ldpctool::LDPCDecoder m_decode; +};