/////////////////////////////////////////////////////////////////////////////////////// // Copyright (C) 2021 Edouard Griffiths, F4EXB // // 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 . // /////////////////////////////////////////////////////////////////////////////////////// /* LDPC testbench Copyright 2018 Ahmet Inan Transformed into external decoder for third-party applications Copyright 2019 */ #include #ifndef _MSC_VER #include #else #include typedef SSIZE_T ssize_t; #include #include #endif #include #include #include #include #include #include #include #include #include #include "testbench.h" #include "algorithms.h" #include "ldpc.h" #if 0 #include "flooding_decoder.h" static const int DEFAULT_TRIALS = 50; #else #include "layered_decoder.h" static const int DEFAULT_TRIALS = 25; #endif static const int DEFAULT_BATCH_SIZE = 32; //ldpctool::LDPCInterface *create_ldpc(char *standard, char prefix, int number); void fail(const char *msg) { std::cerr << "** plugin: " << msg << std::endl; exit(1); } void fatal(const char *msg) { fprintf(stderr, "** plugin: "); perror(msg); exit(1); } void usage(const char *name, FILE *f, int c, const char *info = NULL) { fprintf(f, "Usage: %s [--standard DVB-S2] --modcod INT [--trials 25] [--batch-size 32] [--shortframes] < FECFRAMES.int8 > FECFRAMES.int8\n", name); if (info) fprintf(f, "** Error while processing '%s'\n", info); exit(c); } int main(int argc, char **argv) { const char *standard = "DVB-S2"; int modcod = -1; int max_trials = DEFAULT_TRIALS; int batch_size = DEFAULT_BATCH_SIZE; bool shortframes = false; for (int i = 1; i < argc; ++i) { if (!strcmp(argv[i], "--standard") && i + 1 < argc) standard = argv[++i]; else if (!strcmp(argv[i], "--modcod") && i + 1 < argc) modcod = atoi(argv[++i]); else if (!strcmp(argv[i], "--trials") && i + 1 < argc) max_trials = atoi(argv[++i]); else if (!strcmp(argv[i], "--batch-size") && i + 1 < argc) batch_size = atoi(argv[++i]); else if (!strcmp(argv[i], "--shortframes")) shortframes = true; else if (!strcmp(argv[i], "-h")) usage(argv[0], stdout, 0); else usage(argv[0], stderr, 1, argv[i]); } if (strcmp(standard, "DVB-S2")) fail("Only DVB-S2 is supported."); if (modcod < 0 || modcod > 31) usage(argv[0], stderr, 1); 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 decode; // 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) fail("unsupported modcod"); ldpctool::LDPCInterface *ldpc = ldpctool::create_ldpc((char *)"S2", tabname[0], atoi(tabname + 1)); if (!ldpc) { std::cerr << "no such table!" << std::endl; return -1; } const int CODE_LEN = ldpc->code_len(); const int DATA_LEN = ldpc->data_len(); decode.init(ldpc); int BLOCKS = batch_size; ldpctool::code_type *code = new ldpctool::code_type[BLOCKS * 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(aligned_buffer); // Expect LLR values in int8_t format. 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); for (ssize_t pos = 0; pos < iosize;) { int nr = read(0, code + pos, iosize - pos); if (!nr) exit(0); if (nr < 0) fatal("read"); pos += nr; } 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 < CODE_LEN; ++i) reinterpret_cast(simd + i)[n] = code[(j + n) * CODE_LEN + i]; 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 (max trials: %d)\n", (trials_count*100)/(num_decodes*max_trials), (max_count*100)/num_decodes, max_trials); 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]; } for (ssize_t pos = 0; pos < iosize;) { ssize_t nw = write(1, code + pos, iosize - pos); if (!nw) exit(0); if (nw < 0) fatal("write"); pos += nw; } } // main loop delete ldpc; ldpctool::LDPCUtil::aligned_free(aligned_buffer); delete[] code; return 0; }