LCOV - code coverage report
Current view: top level - src - decode.c (source / functions) Coverage Total Hit
Test: poporon Coverage Report Lines: 93.0 % 271 252
Test Date: 2026-03-07 15:16:43 Functions: 100.0 % 14 14
Legend: Lines: hit not hit

            Line data    Source code
       1              : /*
       2              :  * libpoporon - decode.c
       3              :  *
       4              :  * This file is part of libpoporon.
       5              :  *
       6              :  * Author: Brian Armstrong (original, libcorrect)
       7              :  * SPDX-License-Identifier: BSD-3-Clause
       8              :  */
       9              : 
      10              : #include "internal/common.h"
      11              : #include "internal/ldpc.h"
      12              : #include "internal/polynomial.h"
      13              : #include "internal/rs.h"
      14              : 
      15              : #if POPORON_USE_SIMD
      16              : #include "internal/simd.h"
      17              : #endif
      18              : 
      19            6 : static inline void rs_decoder_init(poporon_rs_t *rs)
      20              : {
      21              :     uint32_t i;
      22              : 
      23            6 :     rs->has_init_decode = true;
      24            6 :     rs->syndromes = (uint16_t *)pcalloc(rs->num_roots, sizeof(uint16_t));
      25            6 :     rs->modified_syndromes = (uint16_t *)pcalloc(2 * (size_t)rs->num_roots, sizeof(uint16_t));
      26            6 :     rs->received_polynomial = polynomial_create(rs->block_length - 1);
      27            6 :     rs->error_locator = polynomial_create(rs->num_roots);
      28            6 :     rs->error_locator_log = polynomial_create(rs->num_roots);
      29            6 :     rs->erasure_locator = polynomial_create(rs->num_roots);
      30            6 :     rs->last_error_locator = polynomial_create(rs->num_roots);
      31            6 :     rs->error_evaluator = polynomial_create(rs->num_roots - 1);
      32            6 :     rs->error_locator_derivative = polynomial_create(rs->num_roots - 1);
      33            6 :     rs->error_roots = (uint16_t *)pcalloc(2 * (size_t)rs->num_roots, sizeof(uint16_t));
      34            6 :     rs->error_vals = (uint16_t *)pcalloc(rs->num_roots, sizeof(uint16_t));
      35            6 :     rs->error_locations = (uint16_t *)pcalloc(rs->num_roots, sizeof(uint16_t));
      36              : 
      37            6 :     rs->generator_root_exp = (uint16_t **)pmalloc(rs->num_roots * sizeof(uint16_t *));
      38          198 :     for (i = 0; i < rs->num_roots; i++) {
      39          192 :         rs->generator_root_exp[i] = (uint16_t *)pmalloc(rs->block_length * sizeof(uint16_t));
      40          192 :         polynomial_build_exp_lut(rs->gf, rs->generator_roots[i], rs->block_length - 1, rs->generator_root_exp[i]);
      41              :     }
      42              : 
      43            6 :     rs->element_exp = (uint16_t **)pmalloc(((size_t)rs->gf->field_size + 1) * sizeof(uint16_t *));
      44         1542 :     for (i = 0; i <= rs->gf->field_size; i++) {
      45         1536 :         rs->element_exp[i] = (uint16_t *)pmalloc(rs->num_roots * sizeof(uint16_t));
      46         1536 :         polynomial_build_exp_lut(rs->gf, (uint16_t)i, rs->num_roots - 1, rs->element_exp[i]);
      47              :     }
      48              : 
      49            6 :     rs->init_from_roots_scratch[0] = polynomial_create(rs->num_roots);
      50            6 :     rs->init_from_roots_scratch[1] = polynomial_create(rs->num_roots);
      51            6 : }
      52              : 
      53           25 : static inline bool rs_find_syndromes(poporon_rs_t *rs, uint16_t *syndromes)
      54              : {
      55           25 :     bool all_zero = true;
      56              :     uint32_t i;
      57              : 
      58          825 :     for (i = 0; i < rs->num_roots; i++) {
      59          800 :         syndromes[i] = polynomial_eval_lut(rs->gf, rs->received_polynomial, rs->generator_root_exp[i]);
      60          800 :         if (syndromes[i]) {
      61          702 :             all_zero = false;
      62              :         }
      63              :     }
      64              : 
      65           25 :     return all_zero;
      66              : }
      67              : 
      68           22 : static inline uint32_t rs_find_error_locator(poporon_rs_t *rs, uint32_t num_erasures)
      69              : {
      70           22 :     uint16_t discrepancy, last_discrepancy = 1;
      71              :     uint32_t temp_order;
      72              :     uint16_t temp;
      73           22 :     uint32_t i, j, numerrors = 0, delay_length = 1;
      74              : 
      75           22 :     pmemset(rs->error_locator.coeff, 0, (rs->num_roots + 1) * sizeof(uint16_t));
      76           22 :     rs->error_locator.coeff[0] = 1;
      77           22 :     rs->error_locator.order = 0;
      78              : 
      79           22 :     pmemcpy(rs->last_error_locator.coeff, rs->error_locator.coeff, (rs->num_roots + 1) * sizeof(uint16_t));
      80           22 :     rs->last_error_locator.order = rs->error_locator.order;
      81              : 
      82          690 :     for (i = rs->error_locator.order; i < rs->num_roots - num_erasures; i++) {
      83          668 :         discrepancy = rs->syndromes[i];
      84         4062 :         for (j = 1; j <= numerrors; j++) {
      85         3394 :             discrepancy = field_add(discrepancy, field_mul(rs->gf, rs->error_locator.coeff[j], rs->syndromes[i - j]));
      86              :         }
      87              : 
      88          668 :         if (!discrepancy) {
      89          485 :             delay_length++;
      90          485 :             continue;
      91              :         }
      92              : 
      93          183 :         if (2 * numerrors <= i) {
      94         1012 :             for (j = rs->last_error_locator.order; (int)j >= 0; j--) {
      95          850 :                 rs->last_error_locator.coeff[j + delay_length] = field_div(
      96          850 :                     rs->gf, field_mul(rs->gf, rs->last_error_locator.coeff[j], discrepancy), last_discrepancy);
      97              :             }
      98          470 :             for (j = 0; j < delay_length; j++) {
      99          308 :                 rs->last_error_locator.coeff[j] = 0;
     100              :             }
     101              : 
     102         1320 :             for (j = 0; j <= rs->last_error_locator.order + delay_length; j++) {
     103         1158 :                 temp = rs->error_locator.coeff[j];
     104         1158 :                 rs->error_locator.coeff[j] = field_add(rs->error_locator.coeff[j], rs->last_error_locator.coeff[j]);
     105         1158 :                 rs->last_error_locator.coeff[j] = temp;
     106              :             }
     107              : 
     108          162 :             temp_order = rs->error_locator.order;
     109          162 :             rs->error_locator.order = rs->last_error_locator.order + delay_length;
     110          162 :             rs->last_error_locator.order = temp_order;
     111              : 
     112          162 :             numerrors = i + 1 - numerrors;
     113          162 :             last_discrepancy = discrepancy;
     114          162 :             delay_length = 1;
     115              : 
     116          162 :             continue;
     117              :         }
     118              : 
     119           47 :         for (j = rs->last_error_locator.order; (int)j >= 0; j--) {
     120           26 :             rs->error_locator.coeff[j + delay_length] = field_add(
     121           26 :                 rs->error_locator.coeff[j + delay_length],
     122           26 :                 field_div(rs->gf, field_mul(rs->gf, rs->last_error_locator.coeff[j], discrepancy), last_discrepancy));
     123              :         }
     124              : 
     125           21 :         if (rs->last_error_locator.order + delay_length > rs->error_locator.order) {
     126            0 :             rs->error_locator.order = rs->last_error_locator.order + delay_length;
     127              :         }
     128              : 
     129           21 :         delay_length++;
     130              :     }
     131              : 
     132           22 :     return rs->error_locator.order;
     133              : }
     134              : 
     135           22 : static inline bool rs_factorize_error_locator(poporon_rs_t *rs, uint32_t num_skip)
     136              : {
     137           22 :     uint32_t root = num_skip;
     138              :     uint16_t i;
     139              : 
     140           22 :     pmemset(rs->error_roots + num_skip, 0, rs->error_locator_log.order * sizeof(uint16_t));
     141              : 
     142         5654 :     for (i = 0; i <= rs->gf->field_size; i++) {
     143         5632 :         if (!polynomial_eval_log_lut(rs->gf, rs->error_locator_log, rs->element_exp[i])) {
     144          149 :             rs->error_roots[root] = i;
     145          149 :             root++;
     146              :         }
     147              :     }
     148              : 
     149           22 :     return root == rs->error_locator_log.order + num_skip;
     150              : }
     151              : 
     152           19 : static inline void rs_find_error_evaluator(poporon_rs_t *rs)
     153              : {
     154              :     polynomial_t syndrome_poly;
     155              : 
     156           19 :     syndrome_poly.order = rs->num_roots - 1;
     157           19 :     syndrome_poly.coeff = rs->syndromes;
     158              : 
     159           19 :     pmemset(rs->error_evaluator.coeff, 0, (rs->error_evaluator.order + 1) * sizeof(uint16_t));
     160              : 
     161           19 :     polynomial_mul(rs->gf, rs->error_locator, syndrome_poly, rs->error_evaluator);
     162           19 : }
     163              : 
     164           21 : static inline void rs_find_error_values(poporon_rs_t *rs, uint32_t num_skip)
     165              : {
     166              :     uint32_t i;
     167              :     polynomial_t omega;
     168              : 
     169           21 :     if (num_skip > 0) {
     170            2 :         omega.order = rs->num_roots - 1;
     171            2 :         omega.coeff = rs->modified_syndromes;
     172              : 
     173            2 :         if (rs->erasure_locator.order > 0) {
     174            2 :             rs->error_locator_derivative.order = rs->erasure_locator.order - 1;
     175            2 :             polynomial_formal_derivative(rs->gf, rs->erasure_locator, rs->error_locator_derivative);
     176              :         } else {
     177            0 :             rs->error_locator_derivative.order = 0;
     178            0 :             rs->error_locator_derivative.coeff[0] = 0;
     179              :         }
     180              : 
     181           38 :         for (i = 0; i < num_skip; i++) {
     182           36 :             if (rs->error_roots[i] == 0) {
     183            0 :                 continue;
     184              :             }
     185           36 :             rs->error_vals[i] =
     186           36 :                 field_mul(rs->gf, field_pow(rs->gf, rs->error_roots[i], (int)rs->first_consecutive_root - 1),
     187           36 :                           field_div(rs->gf, polynomial_eval_lut(rs->gf, omega, rs->element_exp[rs->error_roots[i]]),
     188           36 :                                     polynomial_eval_lut(rs->gf, rs->error_locator_derivative,
     189           36 :                                                         rs->element_exp[rs->error_roots[i]])));
     190              :         }
     191              :     }
     192              : 
     193           21 :     if (rs->error_locator.order == 0) {
     194            2 :         return;
     195              :     }
     196              : 
     197           19 :     rs_find_error_evaluator(rs);
     198              : 
     199           19 :     rs->error_locator_derivative.order = rs->error_locator.order - 1;
     200           19 :     polynomial_formal_derivative(rs->gf, rs->error_locator, rs->error_locator_derivative);
     201              : 
     202          167 :     for (i = 0; i < rs->error_locator.order; i++) {
     203          148 :         if (rs->error_roots[i + num_skip] == 0) {
     204            0 :             continue;
     205              :         }
     206          148 :         rs->error_vals[i + num_skip] = field_mul(
     207          148 :             rs->gf, field_pow(rs->gf, rs->error_roots[i + num_skip], (int)rs->first_consecutive_root - 1),
     208          148 :             field_div(rs->gf,
     209          148 :                       polynomial_eval_lut(rs->gf, rs->error_evaluator, rs->element_exp[rs->error_roots[i + num_skip]]),
     210          148 :                       polynomial_eval_lut(rs->gf, rs->error_locator_derivative,
     211          148 :                                           rs->element_exp[rs->error_roots[i + num_skip]])));
     212              :     }
     213              : }
     214              : 
     215           21 : static inline void rs_find_error_locations(poporon_rs_t *rs, uint32_t num_errors, uint32_t num_skip)
     216              : {
     217              :     uint32_t i;
     218              :     uint16_t loc, j;
     219              : 
     220          169 :     for (i = num_skip; i < num_errors; i++) {
     221          148 :         if (rs->error_roots[i] == 0) {
     222            0 :             continue;
     223              :         }
     224              : 
     225          148 :         loc = field_div(rs->gf, 1, rs->error_roots[i]);
     226              : 
     227        21234 :         for (j = 0; j <= rs->gf->field_size; j++) {
     228        21234 :             if (field_pow(rs->gf, j, rs->generator_root_gap) == loc) {
     229          148 :                 rs->error_locations[i] = rs->gf->log[j];
     230          148 :                 break;
     231              :             }
     232              :         }
     233              :     }
     234           21 : }
     235              : 
     236            2 : static inline void rs_find_error_roots_from_locations(poporon_rs_t *rs, uint32_t num_errors)
     237              : {
     238              :     uint32_t i;
     239              :     uint16_t loc;
     240              : 
     241           38 :     for (i = 0; i < num_errors; i++) {
     242           36 :         loc = field_pow(rs->gf, rs->gf->exp[rs->error_locations[i]], rs->generator_root_gap);
     243           36 :         rs->error_roots[i] = field_div(rs->gf, 1, loc);
     244              :     }
     245            2 : }
     246              : 
     247            2 : static inline void rs_find_modified_syndromes(poporon_rs_t *rs, uint16_t *syndromes, polynomial_t erasure_locator)
     248              : {
     249              :     polynomial_t syndrome_poly, modified_poly;
     250              : 
     251            2 :     syndrome_poly.order = rs->num_roots - 1;
     252            2 :     syndrome_poly.coeff = syndromes;
     253              : 
     254            2 :     modified_poly.order = rs->num_roots - 1;
     255            2 :     modified_poly.coeff = rs->modified_syndromes;
     256              : 
     257            2 :     polynomial_mul(rs->gf, erasure_locator, syndrome_poly, modified_poly);
     258            2 : }
     259              : 
     260           25 : static inline int16_t calculate_padding_length(poporon_rs_t *rs, size_t size)
     261              : {
     262           25 :     if (size > (size_t)rs->message_length || size == 0) {
     263            0 :         return -1;
     264              :     }
     265           25 :     return (int16_t)(rs->message_length - size);
     266              : }
     267              : 
     268           25 : static inline bool rs_decode(poporon_t *pprn, uint8_t *data, size_t size, uint8_t *parity, size_t *corrected_num)
     269              : {
     270           25 :     poporon_rs_t *rs = pprn->ctx.rs.rs;
     271              :     poporon_erasure_t *eras;
     272              :     int16_t padding_length;
     273              :     uint32_t i, order, num_skip;
     274           25 :     bool success = false;
     275           25 :     size_t errors_corrected = 0;
     276              : 
     277           25 :     padding_length = calculate_padding_length(rs, size);
     278           25 :     if (padding_length < 0) {
     279            0 :         goto finish;
     280              :     }
     281              : 
     282           25 :     if (!rs->has_init_decode) {
     283            6 :         rs_decoder_init(rs);
     284              :     }
     285              : 
     286           25 :     pmemset(rs->received_polynomial.coeff, 0, (rs->received_polynomial.order + 1) * sizeof(uint16_t));
     287              : 
     288         1625 :     for (i = 0; i < size; i++) {
     289         1600 :         rs->received_polynomial.coeff[rs->received_polynomial.order - (i + (size_t)padding_length)] =
     290         1600 :             data[i] & rs->gf->field_size;
     291              :     }
     292              : 
     293          825 :     for (i = 0; i < rs->num_roots; i++) {
     294          800 :         rs->received_polynomial.coeff[rs->num_roots - 1 - i] = parity[i] & rs->gf->field_size;
     295              :     }
     296              : 
     297           25 :     if (rs_find_syndromes(rs, rs->syndromes)) {
     298            3 :         success = true;
     299            3 :         if (pprn->ctx.rs.ext_syndrome) {
     300            1 :             pmemcpy(pprn->ctx.rs.ext_syndrome, rs->syndromes, rs->num_roots * sizeof(uint16_t));
     301              :         }
     302              : 
     303            3 :         goto finish;
     304              :     }
     305              : 
     306           22 :     if (pprn->ctx.rs.ext_syndrome) {
     307            0 :         pmemcpy(pprn->ctx.rs.ext_syndrome, rs->syndromes, rs->num_roots * sizeof(uint16_t));
     308              :     }
     309              : 
     310           22 :     num_skip = 0;
     311              : 
     312           22 :     if (pprn->ctx.rs.erasure) {
     313            2 :         eras = pprn->ctx.rs.erasure;
     314            2 :         if (eras->erasure_count > rs->num_roots) {
     315            0 :             goto finish;
     316              :         }
     317              : 
     318           38 :         for (i = 0; i < eras->erasure_count; i++) {
     319           36 :             rs->error_locations[i] = rs->block_length - (eras->erasure_positions[i] + (size_t)padding_length + 1);
     320              :         }
     321            2 :         num_skip = eras->erasure_count;
     322              : 
     323            2 :         rs_find_error_roots_from_locations(rs, eras->erasure_count);
     324              : 
     325            2 :         rs->erasure_locator = polynomial_init_from_roots(rs->gf, eras->erasure_count, rs->error_roots,
     326            2 :                                                          rs->erasure_locator, rs->init_from_roots_scratch);
     327              : 
     328            2 :         rs_find_modified_syndromes(rs, rs->syndromes, rs->erasure_locator);
     329              : 
     330           30 :         for (i = eras->erasure_count; i < rs->num_roots; i++) {
     331           28 :             rs->syndromes[i - eras->erasure_count] = rs->modified_syndromes[i];
     332              :         }
     333              :     }
     334              : 
     335           22 :     order = rs_find_error_locator(rs, num_skip);
     336           22 :     rs->error_locator.order = order;
     337              : 
     338          208 :     for (i = 0; i <= rs->error_locator.order; i++) {
     339          186 :         rs->error_locator_log.coeff[i] = rs->gf->log[rs->error_locator.coeff[i]];
     340              :     }
     341              : 
     342           22 :     rs->error_locator_log.order = rs->error_locator.order;
     343              : 
     344           22 :     if (!rs_factorize_error_locator(rs, num_skip)) {
     345            1 :         goto finish;
     346              :     }
     347              : 
     348           21 :     rs_find_error_locations(rs, rs->error_locator.order + num_skip, num_skip);
     349           21 :     rs_find_error_values(rs, num_skip);
     350              : 
     351          205 :     for (i = 0; i < rs->error_locator.order + num_skip; i++) {
     352          184 :         rs->received_polynomial.coeff[rs->error_locations[i]] =
     353          184 :             field_sub(rs->received_polynomial.coeff[rs->error_locations[i]], rs->error_vals[i]);
     354              :     }
     355              : 
     356         1365 :     for (i = 0; i < size; i++) {
     357         1344 :         data[i] = (uint8_t)rs->received_polynomial.coeff[rs->received_polynomial.order - (i + (size_t)padding_length)];
     358              :     }
     359              : 
     360          693 :     for (i = 0; i < rs->num_roots; i++) {
     361          672 :         parity[i] = (uint8_t)rs->received_polynomial.coeff[rs->num_roots - 1 - i];
     362              :     }
     363              : 
     364           21 :     errors_corrected = rs->error_locator.order + num_skip;
     365           21 :     success = true;
     366              : 
     367           25 : finish:
     368           25 :     pprn->ctx.rs.last_corrected = errors_corrected;
     369              : 
     370           25 :     if (corrected_num) {
     371           24 :         *corrected_num = errors_corrected;
     372              :     }
     373              : 
     374           25 :     return success;
     375              : }
     376              : 
     377           11 : static inline bool ldpc_decode(poporon_t *pprn, uint8_t *data, size_t size, uint8_t *parity, size_t *corrected_num)
     378              : {
     379           11 :     poporon_ldpc_t *ldpc = pprn->ctx.ldpc.ldpc;
     380           11 :     uint32_t iterations_used = 0;
     381              :     uint8_t *codeword, *temp;
     382              :     size_t i;
     383              :     bool ok;
     384              : 
     385           11 :     if (size != ldpc->info_bytes) {
     386            0 :         return false;
     387              :     }
     388              : 
     389           11 :     if (ldpc->config.use_inner_interleave && ldpc->temp_interleaved) {
     390            7 :         codeword = ldpc->temp_interleaved;
     391              :     } else {
     392            4 :         codeword = ldpc->temp_codeword;
     393              :     }
     394              : 
     395           11 :     pmemcpy(codeword, data, ldpc->info_bytes);
     396           11 :     pmemcpy(codeword + ldpc->info_bytes, parity, ldpc->parity_bytes);
     397              : 
     398           11 :     if (pprn->ctx.ldpc.use_soft_decode && pprn->ctx.ldpc.soft_llr) {
     399            0 :         ok = poporon_ldpc_decode_soft(ldpc, pprn->ctx.ldpc.soft_llr, codeword, pprn->ctx.ldpc.max_iterations,
     400              :                                       &iterations_used);
     401              :     } else {
     402           11 :         ok = poporon_ldpc_decode_hard(ldpc, codeword, pprn->ctx.ldpc.max_iterations, &iterations_used);
     403              :     }
     404              : 
     405           11 :     pprn->ctx.ldpc.last_iterations = iterations_used;
     406              : 
     407           11 :     if (!ok) {
     408            0 :         return false;
     409              :     }
     410              : 
     411           11 :     if (ldpc->config.use_outer_interleave && ldpc->outer_interleaver.inverse) {
     412            7 :         temp = ldpc->temp_outer;
     413            7 :         if (!temp) {
     414            0 :             return false;
     415              :         }
     416              : 
     417          775 :         for (i = 0; i < ldpc->info_bytes; i++) {
     418          768 :             temp[ldpc->outer_interleaver.inverse[i]] = codeword[i];
     419              :         }
     420              : 
     421            7 :         pmemcpy(data, temp, ldpc->info_bytes);
     422              :     } else {
     423            4 :         pmemcpy(data, codeword, ldpc->info_bytes);
     424              :     }
     425              : 
     426           11 :     if (corrected_num) {
     427           11 :         *corrected_num = iterations_used;
     428              :     }
     429              : 
     430           11 :     return true;
     431              : }
     432              : 
     433            1 : static inline bool bch_decode(poporon_t *pprn, uint8_t *data, size_t size, uint8_t *parity, size_t *corrected_num)
     434              : {
     435            1 :     poporon_bch_t *bch = pprn->ctx.bch.bch;
     436            1 :     uint32_t data_val = 0, parity_val = 0, received = 0, corrected = 0, corrected_data;
     437              :     uint16_t i, data_len, codeword_len, parity_bits, data_bytes, parity_bytes_len;
     438            1 :     int32_t num_errors = 0;
     439              : 
     440            1 :     data_len = poporon_bch_get_data_length(bch);
     441            1 :     codeword_len = poporon_bch_get_codeword_length(bch);
     442            1 :     parity_bits = codeword_len - data_len;
     443            1 :     data_bytes = (data_len + 7) / 8;
     444            1 :     parity_bytes_len = (parity_bits + 7) / 8;
     445              : 
     446            1 :     if (size < data_bytes) {
     447            0 :         return false;
     448              :     }
     449              : 
     450            2 :     for (i = 0; i < data_bytes && i < 4; i++) {
     451            1 :         data_val |= ((uint32_t)data[i]) << (8 * (data_bytes - 1 - i));
     452              :     }
     453              : 
     454            1 :     if (data_len < 32) {
     455            1 :         data_val &= ((uint32_t)1 << data_len) - 1;
     456              :     }
     457              : 
     458            3 :     for (i = 0; i < parity_bytes_len && i < 4; i++) {
     459            2 :         parity_val |= ((uint32_t)parity[i]) << (8 * (parity_bytes_len - 1 - i));
     460              :     }
     461              : 
     462            1 :     if (parity_bits < 32) {
     463            1 :         parity_val &= ((uint32_t)1 << parity_bits) - 1;
     464              :     }
     465              : 
     466            1 :     received = (data_val << parity_bits) | parity_val;
     467              : 
     468            1 :     if (!poporon_bch_decode(bch, received, &corrected, &num_errors)) {
     469            0 :         pprn->ctx.bch.last_num_errors = -1;
     470            0 :         return false;
     471              :     }
     472              : 
     473            1 :     pprn->ctx.bch.last_num_errors = num_errors;
     474              : 
     475            1 :     corrected_data = poporon_bch_extract_data(bch, corrected);
     476            2 :     for (i = 0; i < data_bytes && i < 4; i++) {
     477            1 :         data[data_bytes - 1 - i] = (uint8_t)(corrected_data >> (8 * i));
     478              :     }
     479              : 
     480            1 :     if (corrected_num) {
     481            1 :         *corrected_num = (num_errors > 0) ? (size_t)num_errors : 0;
     482              :     }
     483              : 
     484            1 :     return true;
     485              : }
     486              : 
     487           43 : extern bool poporon_decode(poporon_t *pprn, uint8_t *data, size_t size, uint8_t *parity, size_t *corrected_num)
     488              : {
     489           43 :     if (!pprn || !data || !parity || !size) {
     490            6 :         return false;
     491              :     }
     492              : 
     493           37 :     switch (pprn->fec_type) {
     494           25 :     case PPLN_FEC_RS:
     495           25 :         return rs_decode(pprn, data, size, parity, corrected_num);
     496           11 :     case PPLN_FEC_LDPC:
     497           11 :         return ldpc_decode(pprn, data, size, parity, corrected_num);
     498            1 :     case PPLN_FEC_BCH:
     499            1 :         return bch_decode(pprn, data, size, parity, corrected_num);
     500            0 :     default:
     501            0 :         return false;
     502              :     }
     503              : }
        

Generated by: LCOV version 2.0-1