Line data Source code
1 : /******************************************************************************
2 : * ETSI TS 103 634 V1.5.1 *
3 : * Low Complexity Communication Codec Plus (LC3plus) *
4 : * *
5 : * Copyright licence is solely granted through ETSI Intellectual Property *
6 : * Rights Policy, 3rd April 2019. No patent licence is granted by implication, *
7 : * estoppel or otherwise. *
8 : ******************************************************************************/
9 :
10 : #include "options.h"
11 : #include "wmc_auto.h"
12 : #include "stdint.h"
13 : #include <assert.h>
14 : #include <stdlib.h>
15 : #include <string.h>
16 :
17 : #include "functions.h"
18 :
19 :
20 : /* channel coder specific constants and macros */
21 : #define RS16_CW_LEN_MAX 15
22 :
23 : #define FEC_N_MODES 4
24 : #define FEC_N_SYNDROMES_MAX 6
25 : #define FEC_N_ERR_POS_MAX 3
26 : #define FEC_N_ELP_COEFF_MAX 4
27 : #define FEC_N_ERR_SYMB_MAX 3
28 : #define FEC_N_MODE_DETECTION_CW 6
29 :
30 : #define SYNDROME_IDX(mode_index, cw_index) (((mode_index)*FEC_N_MODE_DETECTION_CW + (cw_index)) * FEC_N_SYNDROMES_MAX)
31 : #define ELP_IDX(mode_index, cw_index) (((mode_index)*FEC_N_MODE_DETECTION_CW + (cw_index)) * FEC_N_ELP_COEFF_MAX)
32 : #define ERR_POS_IDX(mode_index, cw_index) (((mode_index)*FEC_N_MODE_DETECTION_CW + (cw_index)) * FEC_N_ERR_POS_MAX)
33 : #define ERR_SYMB_IDX(mode_index, cw_index) (((mode_index)*FEC_N_MODE_DETECTION_CW + (cw_index)) * FEC_N_ERR_SYMB_MAX)
34 : #define DEG_ELP_IDX(mode_index, cw_index) ((mode_index)*FEC_N_MODE_DETECTION_CW + (cw_index))
35 :
36 : #define FEC_TOTAL_SYNDROME_SIZE (FEC_N_SYNDROMES_MAX * FEC_N_MODES * FEC_N_MODE_DETECTION_CW)
37 : #define FEC_TOTAL_ELP_SIZE (FEC_N_ELP_COEFF_MAX * FEC_N_MODES * FEC_N_MODE_DETECTION_CW)
38 : #define FEC_TOTAL_ERR_POS_SIZE (FEC_N_ERR_POS_MAX * FEC_N_MODES * FEC_N_MODE_DETECTION_CW)
39 : #define FEC_TOTAL_ERROR_SIZE (FEC_N_ERR_SYMB_MAX * FEC_N_MODES * FEC_N_MODE_DETECTION_CW)
40 : #define FEC_TOTAL_DEG_ELP_SIZE (FEC_N_MODES * FEC_N_MODE_DETECTION_CW)
41 :
42 : #define ERROR_REPORT_BEC_MASK ((0x0FFF)>>1)
43 : #define ERROR_REPORT_EP1_OK ((0x1000)>>1)
44 : #define ERROR_REPORT_EP2_OK ((0x2000)>>1)
45 : #define ERROR_REPORT_EP3_OK ((0x4000)>>1)
46 : #define ERROR_REPORT_EP4_OK ((0x8000)>>1)
47 : #define ERROR_REPORT_ALL_OK (ERROR_REPORT_EP1_OK | ERROR_REPORT_EP2_OK | ERROR_REPORT_EP3_OK | ERROR_REPORT_EP4_OK)
48 :
49 : /* debugging switches */
50 :
51 : /* constants concerning mode detection */
52 : #define EP_RISK_THRESH_NS_M 21990
53 : #define EP_RISK_THRESH_NS_E -23
54 : #define EP_RISK_THRESH_OS_M 25166
55 : #define EP_RISK_THRESH_OS_E -10
56 :
57 : #define SIMPLE_FLOAT_1_MANTISSA 16384
58 :
59 : #define FEC_STATIC static
60 :
61 : /* DISCLAIMER: Strict instrumentation of GF16 arithmetic would have to take into account
62 : * the initial conversion of the arguments from LC3_UINT8 to LC3_INT16 (one move16() per argument).
63 : * Behind this is the assumption that one would store GF16 elements in LC3_INT16 for strict BASOP
64 : * implementation.
65 : */
66 : #define GF16_MUL(a, b) gf16_mult_table[(a) | (b << 4)]
67 : #define GF16_MUL0(a, b) gf16_mult_table[(a) | (b)]
68 : #define GF16_ADD(a, b) ((a) ^ (b))
69 :
70 : /* tables for finite field arithmetic */
71 : /* tables for arithmetic in GF(16) *
72 : * generator polynomial: 19
73 : * unit group generator (g): 2
74 : */
75 :
76 : static const LC3_UINT8 gf16_mult_table[256] = {
77 : /* gf16_mult_table[a | (b << 4)] contains the product of a and b in GF(16) */
78 : 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,
79 : 13, 14, 15, 0, 2, 4, 6, 8, 10, 12, 14, 3, 1, 7, 5, 11, 9, 15, 13, 0, 3, 6, 5, 12, 15, 10, 9, 11, 8,
80 : 13, 14, 7, 4, 1, 2, 0, 4, 8, 12, 3, 7, 11, 15, 6, 2, 14, 10, 5, 1, 13, 9, 0, 5, 10, 15, 7, 2, 13,
81 : 8, 14, 11, 4, 1, 9, 12, 3, 6, 0, 6, 12, 10, 11, 13, 7, 1, 5, 3, 9, 15, 14, 8, 2, 4, 0, 7, 14, 9,
82 : 15, 8, 1, 6, 13, 10, 3, 4, 2, 5, 12, 11, 0, 8, 3, 11, 6, 14, 5, 13, 12, 4, 15, 7, 10, 2, 9, 1, 0,
83 : 9, 1, 8, 2, 11, 3, 10, 4, 13, 5, 12, 6, 15, 7, 14, 0, 10, 7, 13, 14, 4, 9, 3, 15, 5, 8, 2, 1, 11,
84 : 6, 12, 0, 11, 5, 14, 10, 1, 15, 4, 7, 12, 2, 9, 13, 6, 8, 3, 0, 12, 11, 7, 5, 9, 14, 2, 10, 6, 1,
85 : 13, 15, 3, 4, 8, 0, 13, 9, 4, 1, 12, 8, 5, 2, 15, 11, 6, 3, 14, 10, 7, 0, 14, 15, 1, 13, 3, 2, 12,
86 : 9, 7, 6, 8, 4, 10, 11, 5, 0, 15, 13, 2, 9, 6, 4, 11, 1, 14, 12, 3, 8, 7, 5, 10,
87 : };
88 :
89 : static const LC3_UINT8 rs16_elp_deg2_table[256] = {
90 : /* If the polynomial x^2 + ax + b has distinct non-zero roots z1 and z2 in GF(16), *
91 : * then table entry a + 16*b contains log_g(z1) | log_g(z2) << 4, and otherwise it *
92 : * contains 0. */
93 : 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 165, 0, 0, 0, 0,
94 : 105, 195, 0, 210, 0, 225, 0, 180, 120, 0, 0, 121, 0, 16, 0, 211, 0, 0, 181, 0, 0, 106,
95 : 196, 226, 0, 0, 0, 214, 64, 0, 199, 0, 0, 0, 0, 0, 49, 184, 0, 154, 0, 229, 0, 227,
96 : 182, 0, 0, 32, 0, 0, 0, 197, 0, 0, 122, 0, 212, 152, 0, 203, 0, 158, 128, 0, 0, 0,
97 : 98, 113, 218, 0, 0, 0, 53, 0, 0, 65, 0, 0, 185, 110, 215, 80, 0, 0, 200, 0, 50, 0,
98 : 0, 0, 0, 130, 205, 115, 0, 0, 160, 190, 145, 0, 0, 0, 0, 0, 0, 100, 0, 0, 168, 198,
99 : 0, 183, 33, 0, 0, 48, 228, 213, 0, 0, 0, 0, 0, 0, 0, 0, 164, 0, 179, 0, 224, 104,
100 : 0, 194, 149, 0, 0, 209, 0, 0, 0, 189, 99, 84, 0, 129, 0, 0, 0, 144, 0, 0, 234, 114,
101 : 0, 0, 82, 0, 0, 0, 0, 217, 202, 0, 112, 52, 232, 0, 97, 0, 0, 0, 126, 0, 81, 201,
102 : 0, 36, 216, 186, 0, 0, 0, 96, 0, 0, 0, 0, 0, 88, 0, 0, 0, 103, 0, 148, 178, 0,
103 : 208, 193, 0, 58, 0, 0, 0, 0, 0, 161, 206, 0, 116, 0, 101, 0, 0, 56, 146, 176, 0, 0,
104 : 147, 162, 222, 0, 132, 0, 0, 0, 0, 0, 177, 117, 192, 0,
105 : };
106 :
107 : static const LC3_UINT16 rs16_elp_deg3_table[256] = {
108 : /* If the polynomial x^3 + ax + b has distinct roots z1, z2 and z3 in GF(16), *
109 : * then table entry a + 16*b contains z1) | z2 << 4 | z3 << 8, and otherwise it *
110 : * contains 0. */
111 : 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1889, 0, 0, 0, 0, 0,
112 : 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2977, 0, 0, 0, 0, 0, 3990, 1859, 0,
113 : 0, 0, 0, 0, 0, 0, 3521, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1874, 0, 3718, 0, 0, 0,
114 : 0, 0, 0, 2433, 0, 0, 1619, 0, 0, 0, 0, 3495, 0, 0, 0, 0, 0, 0, 4065, 0, 0, 0,
115 : 0, 0, 0, 3255, 0, 0, 0, 1602, 0, 3735, 0, 0, 0, 0, 3238, 801, 0, 0, 0, 0, 0, 0,
116 : 0, 0, 0, 3510, 0, 0, 0, 0, 1345, 3975, 0, 0, 0, 0, 0, 0, 0, 0, 3778, 0, 0, 0,
117 : 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2947, 0, 0, 0, 0, 0, 0, 0,
118 : 0, 0, 3476, 0, 4005, 0, 3461, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
119 : 0, 0, 0, 0, 0, 3748, 0, 0, 2962, 0, 0, 0, 0, 4035, 0, 0, 4020, 0, 0, 0, 0, 0,
120 : 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3221, 0, 0, 0, 0, 0, 0, 2690,
121 : 0, 0, 0, 3795, 0, 0, 0, 4050, 0, 0, 0, 0, 0, 3204, 3765, 0, 0, 0, 0, 0, 2707, 0,
122 : 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
123 : };
124 :
125 : static const LC3_UINT8 gf16_g_pow[16] = {1, 2, 4, 8, 3, 6, 12, 11, 5, 10, 7, 14, 15, 13, 9, 1};
126 : /* g_pow[i] contains g^i*/
127 :
128 : static const LC3_UINT8 gf16_log_g[16] = {255, 0, 1, 4, 2, 8, 5, 10, 3, 14, 9, 7, 6, 13, 11, 12};
129 : /* log_g[n] contains contains the value i such that g^i = n for n=1, 2, ..., 15, log_g[0] is set to 255 */
130 :
131 : static const LC3_UINT8 gf16_inv_table[16] = {255, 1, 9, 14, 13, 11, 7, 6, 15, 2, 12, 5, 10, 4, 3, 8};
132 : /* gf16_inv_table[n] contains the multiplicative inverse of n in GF(16) (1/0 is set to 255)*/
133 :
134 : /* RS16 generating polynomials (from lowest to highest coefficient without leading 1)*/
135 :
136 : static const LC3_UINT8 rs16_gp_d3[] = {8, 6};
137 : static const LC3_UINT8 rs16_gp_d5[] = {7, 8, 12, 13};
138 : static const LC3_UINT8 rs16_gp_d7[] = {12, 10, 12, 3, 9, 7};
139 :
140 : /* FEC mode signaling polynomials */
141 :
142 : #define EP_SIG_POLY_DEG 12
143 :
144 : static const LC3_UINT8 sig_polys[4][15] = {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
145 : {7, 15, 5, 6, 14, 9, 1, 3, 12, 10, 13, 3, 2, 0, 0},
146 : {7, 11, 14, 1, 2, 3, 12, 11, 6, 15, 7, 6, 12, 0, 0},
147 : {6, 15, 12, 2, 9, 15, 2, 8, 12, 3, 10, 5, 4, 0, 0}};
148 :
149 : static const LC3_UINT8 sig_poly_syndr[4][6] = {
150 : {0, 0, 0, 0, 0, 0}, {0, 4, 5, 11, 5, 8}, {0, 5, 9, 0, 1, 7}, {0, 12, 5, 12, 9, 8}};
151 :
152 : /* bit count table for error report (0000 0001 0010 0011 0100 0101 0110 0111 1000 1001 1010 1011 1100 1101 1110 1111) */
153 :
154 : static const LC3_UINT8 rs16_bit_count_table[] = {0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4};
155 :
156 : /* List of RS16 generators by Hamming distance */
157 :
158 : static const LC3_UINT8 *const rs16_gp_by_hd[8] = {NULL, NULL, NULL, rs16_gp_d3, NULL, rs16_gp_d5, NULL, rs16_gp_d7};
159 :
160 : /* fec config data */
161 :
162 : static const LC3_UINT8 hamming_distance_by_mode0[] = {1, 3, 3, 5, 7};
163 : static const LC3_UINT8 hamming_distance_by_mode1[] = {1, 1, 3, 5, 7};
164 :
165 : static const LC3_UINT8 crc1_bytes_by_mode0[] = {0, 3, 2, 2, 2};
166 : static const LC3_UINT8 crc1_bytes_by_mode1[] = {0, 3, 3, 3, 3};
167 : static const LC3_UINT8 crc2_bytes_by_mode[] = {0, 0, 2, 2, 2};
168 :
169 : /* fec mode risk table */
170 : typedef struct
171 : {
172 : LC3_UINT32 mantissa;
173 : LC3_INT16 exponent;
174 : } simple_float;
175 :
176 : static const simple_float risk_table_f[4][4] = {{{16384, 0}, {16384, 0}, {16384, 0}, {16384, 0}},
177 : {{16384, -8}, {26880, -1}, {16384, 0}, {16384, 0}},
178 : {{16384, -16}, {26880, -9}, {20475, -2}, {16384, 0}},
179 : {{16384, -24}, {26880, -17}, {20475, -10}, {19195, -4}}};
180 : /* bit error limits for slot size 40 */
181 : static LC3_INT16 const low_br_max_bit_errors_by_mode[] = {0, 0, 3, 9, 18};
182 :
183 : /*
184 : corresponding float values:
185 : {1.f, 1.f, 1.f, 1.f},
186 : {0.00390625f, 0.820312f, 1.f, 1.f},
187 : {1.52588e-05f, 0.00320435f, 0.312424f, 1.f},
188 : {5.96046e-08f, 1.2517e-05f, 0.00122041f, 0.0732243f}
189 : */
190 :
191 : /* internal encoder routines */
192 :
193 : FEC_STATIC void fec_interleave_pack(LC3_UINT8 *out, LC3_UINT8 *in, LC3_INT16 n_nibbles, LC3_INT16 n_codewords);
194 :
195 : FEC_STATIC void rs16_enc(LC3_UINT8 *iobuf, LC3_INT16 codeword_length, LC3_INT16 hamming_distance, LC3_INT16 fec_mode,
196 : LC3_INT16 signal_mode);
197 :
198 : /* internal decoder routines */
199 :
200 : FEC_STATIC void fec_deinterleave_unpack(LC3_UINT8 *out, LC3_UINT8 *in, LC3_INT16 n_nibbles, LC3_INT16 n_codewords);
201 :
202 : FEC_STATIC LC3_INT16 fec_data_preproc(LC3_INT16 mode, LC3_INT16 epmr, LC3_UINT8 *iobuf, LC3_UINT8 *cw_buf, LC3_INT16 data_bytes,
203 : LC3_INT16 slot_bytes, LC3_INT16 pc_split);
204 :
205 : FEC_STATIC void fec_data_postproc(LC3_INT16 mode, LC3PLUS_EpModeRequest *epmr, LC3_UINT8 *iobuf, LC3_INT16 data_bytes, LC3_UINT8 *cw_buf,
206 : LC3_INT16 slot_bytes, LC3_INT16 pc_split, LC3_INT32 *bfi);
207 :
208 : FEC_STATIC LC3_INT32 rs16_detect_and_correct(LC3_UINT8 *iobuf, LC3_INT32 n_symb, LC3_INT32 n_codewords, LC3PLUS_EpModeRequest *epmr, LC3_INT16 *error_report,
209 : LC3_INT32 *bfi, LC3_UINT8 *array_of_trust, LC3_INT32 ccc_flag_flag, LC3_INT16 *n_pccw);
210 :
211 : FEC_STATIC void rs16_calculate_six_syndromes(LC3_UINT8 *syndromes, LC3_UINT8 *cw, LC3_INT32 cw_poly_deg);
212 :
213 : FEC_STATIC void rs16_calculate_four_syndromes(LC3_UINT8 *syndromes, LC3_UINT8 *cw, LC3_INT32 cw_poly_deg);
214 :
215 : FEC_STATIC void rs16_calculate_two_syndromes(LC3_UINT8 *syndromes, LC3_UINT8 *cw, LC3_INT32 cw_poly_deg);
216 :
217 : FEC_STATIC LC3_INT8 rs16_calculate_elp(LC3_UINT8 *elp, LC3_UINT8 *syndromes, LC3_INT16 hamming_distance);
218 :
219 : FEC_STATIC LC3_INT16 rs16_factorize_elp(LC3_UINT8 *error_locations, LC3_UINT8 *elp, LC3_INT16 deg_elp, LC3_INT16 max_pos);
220 :
221 : FEC_STATIC void rs16_calculate_errors(LC3_UINT8 *errors, LC3_UINT8 *err_pos, LC3_UINT8 *syndromes, LC3_INT8 deg_elp, LC3_INT8 t);
222 :
223 : /* auxiliary routines */
224 :
225 : FEC_STATIC LC3_INT16 crc1(LC3_UINT8 *data, LC3_INT16 data_size, LC3_INT16 epmr, LC3_UINT8 *hash_val, LC3_INT16 hash_size, LC3_INT16 check);
226 :
227 : FEC_STATIC LC3PLUS_EpModeRequest fec_estimate_epmr_from_cw0(LC3_UINT8 *cw0, LC3_INT8 *t, LC3_UINT8 *syndromes, LC3_UINT8 *elp, LC3_INT8 *deg_elp,
228 : LC3_UINT8 *err_pos, LC3_UINT8 *err_symb, LC3_INT16 n_codewords, LC3_INT16 n_symb);
229 :
230 : FEC_STATIC void dw0_bitswap(LC3_UINT8 *dw0, LC3_INT16 mode, LC3_INT16 slot_bytes);
231 :
232 : FEC_STATIC LC3PLUS_EpModeRequest cw0_get_epmr(LC3_UINT8 *cw0, LC3_INT16 epmr_position);
233 :
234 : FEC_STATIC LC3PLUS_EpModeRequest dw0_get_epmr(LC3_UINT8 *dw0, LC3_INT16 mode, LC3_INT16 slot_size);
235 :
236 : FEC_STATIC LC3_INT16 crc2(LC3_UINT8 *data, LC3_INT16 data_size, LC3_UINT8 *hash_val, LC3_INT16 hash_size, LC3_INT16 check);
237 :
238 : FEC_STATIC simple_float simple_float_mul(simple_float op1, simple_float op2);
239 :
240 : FEC_STATIC LC3_INT16 simple_float_cmp(simple_float op1, simple_float op2);
241 :
242 : FEC_STATIC LC3_INT16 get_total_crc_size(LC3_INT16 slot_bytes, LC3_INT16 fec_mode, LC3_INT16 pc_split);
243 :
244 : FEC_STATIC LC3_INT16 get_n_codewords(LC3_INT16 slot_bytes);
245 :
246 : FEC_STATIC LC3_INT16 get_codeword_length(LC3_INT16 n_codewords, LC3_INT16 slot_nibbles, LC3_INT16 codeword_index);
247 :
248 :
249 :
250 0 : LC3_INT16 fec_get_n_pccw(LC3_INT16 slot_bytes, LC3_INT16 fec_mode, LC3_INT16 ccc_flag)
251 : {
252 : LC3_INT16 n_pccw;
253 :
254 0 : if (fec_mode == 3)
255 : {
256 0 : n_pccw = (LC3_INT16) (0.080447761194030 * slot_bytes - 1.791044776119394 + 0.5);
257 : }
258 0 : else if (fec_mode == 4)
259 : {
260 0 : n_pccw = (LC3_INT16) (0.066492537313433 * slot_bytes - 1.970149253731338 + 0.5);
261 : }
262 : else
263 : {
264 0 : n_pccw = 0;
265 : }
266 :
267 0 : if (ccc_flag == 1 || slot_bytes < 80)
268 : {
269 0 : n_pccw = 0;
270 : }
271 :
272 0 : return n_pccw;
273 : }
274 :
275 0 : FEC_STATIC LC3_INT16 get_total_crc_size(LC3_INT16 slot_bytes, LC3_INT16 fec_mode, LC3_INT16 pc_split)
276 : {
277 : LC3_INT16 n_crc;
278 :
279 0 : n_crc = crc1_bytes_by_mode1[fec_mode];
280 0 : if (slot_bytes == 40)
281 : {
282 0 : n_crc = crc1_bytes_by_mode0[fec_mode];
283 : }
284 :
285 0 : if (pc_split > 0)
286 : {
287 0 : n_crc = n_crc + crc2_bytes_by_mode[fec_mode];
288 : }
289 :
290 :
291 :
292 0 : return n_crc;
293 : }
294 :
295 0 : FEC_STATIC LC3_INT16 get_n_codewords(LC3_INT16 slot_bytes)
296 : {
297 0 : return (2*slot_bytes + 14)/15;
298 : }
299 :
300 0 : FEC_STATIC LC3_INT16 get_codeword_length(LC3_INT16 n_codewords, LC3_INT16 slot_nibbles, LC3_INT16 codeword_index)
301 : {
302 0 : return (slot_nibbles - codeword_index - 1) / n_codewords + 1;
303 : }
304 :
305 : /* Encoder */
306 :
307 0 : LC3_INT16 fec_get_data_size(LC3_INT16 fec_mode, LC3_INT16 ccc_flag, LC3_INT16 slot_bytes)
308 : /* not time critical */
309 : {
310 : LC3_INT16 n_codewords, payload_size;
311 :
312 0 : n_codewords = get_n_codewords(slot_bytes);
313 :
314 0 : assert(n_codewords == (2 * slot_bytes + RS16_CW_LEN_MAX - 1) / RS16_CW_LEN_MAX);
315 0 : payload_size = slot_bytes;
316 :
317 0 : if (fec_mode > 0)
318 : {
319 0 : if (fec_mode == 1)
320 : {
321 0 : payload_size --;
322 : }
323 : else
324 : {
325 0 : payload_size -= (fec_mode - 1) * n_codewords;
326 : }
327 0 : if (slot_bytes == 40)
328 : {
329 0 : payload_size -= crc1_bytes_by_mode0[fec_mode];
330 : }
331 : else
332 : {
333 0 : payload_size -= crc1_bytes_by_mode1[fec_mode];
334 : }
335 :
336 0 : if (ccc_flag == 0 && fec_mode > 2 && slot_bytes >= 80)
337 : {
338 0 : payload_size -= crc2_bytes_by_mode[fec_mode];
339 : }
340 : }
341 :
342 :
343 :
344 0 : return payload_size;
345 : }
346 :
347 0 : LC3_INT16 fec_get_n_pc(LC3_INT16 fec_mode, LC3_INT16 n_pccw, LC3_INT16 slot_bytes)
348 : /* not time critical */
349 : {
350 : LC3_INT16 n_codewords, pc_split;
351 : LC3_INT32 i;
352 :
353 0 : n_codewords = get_n_codewords(slot_bytes);
354 :
355 0 : assert(n_codewords == (2 * slot_bytes + RS16_CW_LEN_MAX - 1) / RS16_CW_LEN_MAX);
356 :
357 0 : pc_split = - 2*n_pccw*(fec_mode - 1);
358 :
359 0 : if (fec_mode == 1 || slot_bytes < 80)
360 : {
361 0 : pc_split = 0;
362 : }
363 : else
364 : {
365 0 : for (i = 0; i < n_pccw; i++)
366 : {
367 0 : pc_split += (2 * slot_bytes + i) / n_codewords;
368 : }
369 : }
370 :
371 :
372 :
373 0 : return pc_split;
374 : }
375 :
376 : /* functions for EPMR handling */
377 0 : FEC_STATIC void dw0_bitswap(LC3_UINT8 *dw0, LC3_INT16 mode, LC3_INT16 slot_bytes)
378 : /* swap epmr bits with bits that will be positioned at 30 and 32 in code word 0 */
379 : {
380 : LC3_UINT8 tmp;
381 : LC3_INT32 ind0, ind1, position;
382 :
383 0 : position = get_codeword_length(get_n_codewords(slot_bytes), 2*slot_bytes, 0) - 1;
384 :
385 0 : if (slot_bytes == 40)
386 : {
387 0 : ind0 = 2*crc1_bytes_by_mode0[mode] - 1;
388 : }
389 : else
390 : {
391 0 : ind0 = 2*crc1_bytes_by_mode1[mode] - 1;
392 : }
393 :
394 0 : ind1 = position - hamming_distance_by_mode0[mode] + 1;
395 :
396 : /* swap bits 2 and 3 of dw0[ind0] with bits 0 and 1 of dw0[ind1] */
397 0 : tmp = (dw0[ind0] >> 2) & 3;
398 0 : dw0[ind0] = dw0[ind0] & 3;
399 0 : dw0[ind0] = dw0[ind0] | ((dw0[ind1] & 3) << 2);
400 0 : dw0[ind1] = dw0[ind1] & 12;
401 0 : dw0[ind1] = dw0[ind1] | tmp;
402 :
403 :
404 0 : }
405 :
406 0 : FEC_STATIC LC3PLUS_EpModeRequest cw0_get_epmr(LC3_UINT8 *cw0, LC3_INT16 position)
407 : {
408 0 : return (LC3PLUS_EpModeRequest)(cw0[position] & 3);
409 : }
410 :
411 0 : FEC_STATIC LC3PLUS_EpModeRequest dw0_get_epmr(LC3_UINT8 *dw0, LC3_INT16 mode, LC3_INT16 slot_size)
412 : {
413 : LC3_INT32 ncrc1;
414 : LC3PLUS_EpModeRequest epmr;
415 :
416 0 : ncrc1 = crc1_bytes_by_mode1[mode];
417 :
418 0 : if (slot_size == 40)
419 : {
420 0 : ncrc1 = crc1_bytes_by_mode0[mode];
421 : }
422 :
423 0 : epmr = (LC3PLUS_EpModeRequest)(dw0[2 * ncrc1 - 1] >> 2);
424 :
425 :
426 :
427 0 : return epmr;
428 : }
429 :
430 :
431 0 : FEC_STATIC LC3_INT16 fec_data_preproc(LC3_INT16 mode, LC3_INT16 epmr, LC3_UINT8 *iobuf, LC3_UINT8 *cw_buf, LC3_INT16 data_bytes,
432 : LC3_INT16 slot_bytes, LC3_INT16 pc_split)
433 : {
434 : LC3_INT16 data_offset, n_crc1, n_crc2;
435 : LC3_INT32 i, j;
436 :
437 0 : data_offset = 2*(slot_bytes - data_bytes);
438 :
439 : /* extract and reverse data*/
440 0 : j = 2*slot_bytes - 1;
441 0 : for (i = 0; i < data_bytes; i++)
442 : {
443 0 : cw_buf[j--] = iobuf[i] & 15;
444 0 : cw_buf[j--] = iobuf[i] >> 4;
445 : }
446 :
447 : /* add crc hashes */
448 0 : if (slot_bytes == 40)
449 : {
450 0 : n_crc1 = crc1_bytes_by_mode0[mode];
451 : }
452 : else
453 : {
454 0 : n_crc1 = crc1_bytes_by_mode1[mode];
455 : }
456 :
457 0 : if (pc_split > 0 && mode > 1)
458 : {
459 0 : n_crc2 = crc2_bytes_by_mode[mode];
460 : }
461 : else
462 : {
463 0 : n_crc2 = 0;
464 : }
465 :
466 0 : if (n_crc2)
467 : {
468 0 : crc2(cw_buf + data_offset + 2 * data_bytes - pc_split, pc_split, cw_buf + data_offset - 2 * n_crc2, n_crc2, 0);
469 : }
470 0 : if (n_crc1)
471 : {
472 0 : crc1(cw_buf + data_offset, 2 * data_bytes - pc_split, epmr, cw_buf + data_offset - 2 * (n_crc1 + n_crc2), n_crc1,
473 : 0);
474 : }
475 :
476 0 : data_offset -= 2* (n_crc1 + n_crc2);
477 :
478 0 : dw0_bitswap(cw_buf + data_offset, mode, slot_bytes);
479 :
480 :
481 :
482 0 : return data_offset;
483 : }
484 :
485 0 : void fec_encoder(LC3_INT16 mode, LC3_INT16 epmr, LC3_UINT8 *iobuf, LC3_INT16 data_bytes, LC3_INT16 slot_bytes, LC3_INT16 n_pccw)
486 : {
487 : LC3_INT16 n_codewords, codeword_length, hd, redundancy_nibbles, cw_offset, dw_offset, pc_split;
488 : LC3_INT32 i, j;
489 : LC3_UINT8 cw_buf[2 * FEC_SLOT_BYTES_MAX];
490 :
491 0 : cw_offset = 0;
492 0 : dw_offset = 0;
493 0 : pc_split = 0;
494 :
495 0 : n_codewords = get_n_codewords(slot_bytes);
496 :
497 : /* some sanity checks */
498 : {
499 0 : LC3_INT32 tmp = slot_bytes;
500 :
501 0 : assert((slot_bytes >= FEC_SLOT_BYTES_MIN && slot_bytes <= FEC_SLOT_BYTES_MAX) &&
502 : "fec_encoder: slot_bytes out of range");
503 0 : tmp -= mode == 1 ? 1 : n_codewords * (mode - 1); // reed solomon redundancy
504 0 : tmp -= slot_bytes == 40 ? crc1_bytes_by_mode0[mode] : crc1_bytes_by_mode1[mode]; // crc1
505 0 : tmp -= (n_pccw > 0) && (mode > 1) ? crc2_bytes_by_mode[mode] : 0; // crc2
506 0 : assert(data_bytes == tmp && "fec_encoder: inconsistent payload size");
507 0 : assert(n_codewords - n_pccw >= 6);
508 : }
509 :
510 : /* data preproc: re-ordering and hash extension */
511 0 : pc_split = fec_get_n_pc(mode, n_pccw, slot_bytes);
512 :
513 0 : dw_offset = fec_data_preproc(mode, epmr, iobuf, cw_buf, data_bytes, slot_bytes, pc_split);
514 :
515 : /* encoding of first data word*/
516 0 : hd = hamming_distance_by_mode0[mode];
517 0 : redundancy_nibbles = hd - 1;
518 0 : codeword_length = get_codeword_length(n_codewords, 2 * slot_bytes, 0);
519 :
520 0 : assert(codeword_length == (2 * slot_bytes - 1) / n_codewords + 1);
521 :
522 0 : for (j = redundancy_nibbles; j < codeword_length; (j++, dw_offset++))
523 : {
524 0 : cw_buf[j] = cw_buf[dw_offset];
525 : }
526 :
527 0 : rs16_enc(cw_buf, codeword_length, hd, mode, 1);
528 :
529 0 : cw_offset += codeword_length;
530 :
531 : /* encoding of remaining data words */
532 0 : hd = hamming_distance_by_mode1[mode];
533 0 : redundancy_nibbles = hd - 1;
534 :
535 0 : for (i = 1; i < n_codewords; i++)
536 : {
537 0 : codeword_length = get_codeword_length(n_codewords, 2*slot_bytes, i);
538 :
539 0 : for (j = redundancy_nibbles; j < codeword_length; (j++, dw_offset++))
540 : {
541 0 : cw_buf[cw_offset + j] = cw_buf[dw_offset];
542 : }
543 :
544 0 : rs16_enc(cw_buf + cw_offset, codeword_length, hd, mode, i < 6);
545 :
546 0 : cw_offset += codeword_length;
547 : }
548 :
549 0 : assert(cw_offset == 2 * slot_bytes && dw_offset == 2 * slot_bytes);
550 :
551 0 : fec_interleave_pack(iobuf, cw_buf, 2 * slot_bytes, n_codewords);
552 :
553 :
554 0 : }
555 :
556 0 : FEC_STATIC void rs16_enc(LC3_UINT8 *iobuf, LC3_INT16 codeword_length, LC3_INT16 hamming_distance, LC3_INT16 fec_mode,
557 : LC3_INT16 signal_mode)
558 : /* expects (data polynomial) * x^(hamming_distance - 1) in iobuf */
559 : {
560 : LC3_UINT8 const *gp;
561 : LC3_UINT8 shift_buffer[RS16_CW_LEN_MAX + 1], lc;
562 : LC3_INT32 i, j, deg_gp;
563 :
564 0 : memset(shift_buffer, 0, sizeof(shift_buffer));
565 0 : gp = rs16_gp_by_hd[hamming_distance];
566 0 : deg_gp = hamming_distance - 1;
567 :
568 0 : if (hamming_distance > 1)
569 : {
570 0 : assert(codeword_length > deg_gp);
571 :
572 : /* initialize redundancy part to zero */
573 0 : memset(iobuf, 0, deg_gp);
574 :
575 : /* initialize shift_buffer */
576 0 : memmove(shift_buffer + 1, iobuf + codeword_length - deg_gp, deg_gp);
577 :
578 : /* calculate remainder */
579 0 : for (i = codeword_length - deg_gp - 1; i >= 0; i--)
580 : {
581 0 : shift_buffer[0] = iobuf[i];
582 0 : lc = shift_buffer[deg_gp] << 4;
583 :
584 0 : for (j = deg_gp - 1; j >= 0; j--)
585 : {
586 0 : shift_buffer[j + 1] = GF16_ADD(shift_buffer[j], GF16_MUL0(gp[j], lc));
587 : }
588 : }
589 :
590 : /* add remainder to shifted data polynomial */
591 0 : for (i = 0; i < deg_gp; i++)
592 : {
593 0 : iobuf[i] = shift_buffer[i + 1];
594 : }
595 :
596 : /* add signaling polynomial */
597 0 : if (signal_mode)
598 : {
599 0 : assert(codeword_length > EP_SIG_POLY_DEG);
600 0 : for (i = 0; i <= EP_SIG_POLY_DEG; i++)
601 : {
602 0 : iobuf[i] = GF16_ADD(iobuf[i], sig_polys[fec_mode - 1][i]);
603 : }
604 : }
605 : }
606 :
607 :
608 0 : }
609 :
610 0 : FEC_STATIC void fec_interleave_pack(LC3_UINT8 *out, LC3_UINT8 *in, LC3_INT16 n_nibbles, LC3_INT16 n_codewords)
611 : {
612 : LC3_INT16 out_offset, cw_offset, codeword_length;
613 : LC3_INT32 i, j;
614 :
615 0 : out_offset = 0;
616 0 : cw_offset = 0;
617 :
618 : /* initialize output buffer to zero */
619 0 : memset(out, 0, n_nibbles >> 1);
620 :
621 : /* interleave and pack codewords */
622 0 : for (i = 0; i < n_codewords; i++)
623 : {
624 0 : codeword_length = get_codeword_length(n_codewords, n_nibbles, i);
625 :
626 0 : for (j = 0; j < codeword_length; j++)
627 : {
628 0 : out_offset = n_nibbles - 1 - j*n_codewords - i;
629 0 : out[out_offset >> 1] |= in[cw_offset] << ((out_offset & 1) << 2);
630 0 : cw_offset = cw_offset + 1;
631 : }
632 : }
633 :
634 :
635 0 : assert(cw_offset == n_nibbles);
636 0 : }
637 :
638 : /* Decoder */
639 0 : FEC_STATIC void fec_data_postproc(LC3_INT16 mode, LC3PLUS_EpModeRequest *epmr, LC3_UINT8 *obuf, LC3_INT16 data_bytes, LC3_UINT8 *cw_buf,
640 : LC3_INT16 slot_bytes, LC3_INT16 pc_split, LC3_INT32 *bfi)
641 : {
642 : LC3_INT16 i;
643 : LC3_INT16 n_crc1, n_crc2;
644 : LC3_INT16 cw_buf_len;
645 : LC3PLUS_EpModeRequest tmp_epmr;
646 :
647 0 : n_crc1 = crc1_bytes_by_mode1[mode];
648 0 : if (slot_bytes == 40)
649 : {
650 0 : n_crc1 = crc1_bytes_by_mode0[mode];
651 : }
652 :
653 0 : n_crc2 = 0;
654 0 : if (pc_split > 0)
655 : {
656 0 : n_crc2 = crc2_bytes_by_mode[mode];
657 : }
658 :
659 0 : assert(n_crc1 == (slot_bytes == 40 ? crc1_bytes_by_mode0[mode] : crc1_bytes_by_mode1[mode]));
660 0 : assert(n_crc2 == ((pc_split > 0) && (mode > 1) ? crc2_bytes_by_mode[mode] : 0));
661 :
662 0 : cw_buf_len = 2 * (data_bytes + n_crc1 + n_crc2);
663 :
664 0 : if ((mode - 1))
665 : {
666 : /* reverse bit-swap */
667 0 : dw0_bitswap(cw_buf, mode, slot_bytes);
668 0 : tmp_epmr = dw0_get_epmr(cw_buf, mode, slot_bytes);
669 :
670 0 : if (crc1(cw_buf + ((n_crc1 + n_crc2) << 1), ((data_bytes << 1) - pc_split), tmp_epmr, cw_buf, n_crc1, 1))
671 : {
672 0 : *bfi = 1;
673 :
674 0 : return;
675 : }
676 : else
677 : {
678 0 : *epmr = tmp_epmr;
679 : }
680 : }
681 :
682 0 : if (pc_split > 0 && *bfi != 2)
683 : {
684 0 : if (crc2(cw_buf + (((data_bytes + (n_crc1 + n_crc2)) << 1) - pc_split), pc_split,
685 0 : cw_buf + (n_crc1 << 1), n_crc2, 1))
686 : {
687 0 : *bfi = 2;
688 : }
689 : }
690 :
691 0 : for (i = 0; i < data_bytes; i++)
692 : {
693 0 : obuf[i] = (LC3_UINT8)(cw_buf[cw_buf_len - 2 * i - 1] | (cw_buf[cw_buf_len - 2 * i - 2] << 4));
694 : }
695 :
696 :
697 : }
698 :
699 0 : LC3_INT32 fec_decoder(LC3_UINT8 *iobuf, LC3_INT16 slot_bytes, LC3_INT32 *data_bytes, LC3PLUS_EpModeRequest *epmr, LC3_INT16 ccc_flag, LC3_INT16 *n_pccw,
700 : LC3_INT32 *bfi, LC3_INT16 *be_bp_left, LC3_INT16 *be_bp_right, LC3_INT16 *n_pc, LC3_INT16 *m_fec)
701 : {
702 : LC3_UINT8 cw_buf[2 * FEC_SLOT_BYTES_MAX];
703 : LC3_UINT8 array_of_trust[MAX_LEN];
704 : LC3_INT16 i, j;
705 : LC3_INT16 cw_offset, dw_offset;
706 : LC3_INT16 n_codewords, redundancy_nibbles, codeword_length;
707 : LC3_INT16 mode, error_report;
708 : LC3_INT16 n_crc;
709 : LC3_INT16 first_bad_cw;
710 : LC3_INT16 pc_split;
711 :
712 : UNUSED(n_crc);
713 :
714 :
715 0 : if (*bfi == 1)
716 : {
717 0 : return ERROR_REPORT_BEC_MASK;
718 : }
719 :
720 0 : if (slot_bytes < FEC_SLOT_BYTES_MIN || slot_bytes > FEC_SLOT_BYTES_MAX)
721 : {
722 0 : *bfi = 1;
723 :
724 0 : return ERROR_REPORT_BEC_MASK;
725 : }
726 :
727 0 : if (ccc_flag == 0)
728 : {
729 0 : *be_bp_left = -1;
730 0 : *be_bp_right = -1;
731 : }
732 :
733 0 : n_codewords = get_n_codewords(slot_bytes);
734 :
735 : /* extract and de-interleave nibbles */
736 0 : fec_deinterleave_unpack(cw_buf, iobuf, 2 * slot_bytes, n_codewords);
737 :
738 : /* mode detection and error correction */
739 0 : mode = rs16_detect_and_correct(cw_buf, 2 * slot_bytes, n_codewords, epmr, &error_report, bfi, array_of_trust,
740 : ccc_flag, n_pccw);
741 :
742 : /* for normal slots the maximal number of bit errors is limited */
743 : #ifndef APPLY_MAX_ERRORS
744 0 : if (slot_bytes == 40 && mode > 0)
745 : {
746 0 : if ((error_report & ERROR_REPORT_BEC_MASK) > low_br_max_bit_errors_by_mode[mode])
747 : {
748 0 : error_report &= ERROR_REPORT_BEC_MASK;
749 0 : mode = -1;
750 0 : *bfi = 1;
751 : }
752 : else
753 : {
754 0 : if ((error_report & ERROR_REPORT_BEC_MASK) > low_br_max_bit_errors_by_mode[2])
755 : {
756 0 : error_report &= ~ERROR_REPORT_EP2_OK;
757 : }
758 0 : if ((error_report & ERROR_REPORT_BEC_MASK) > low_br_max_bit_errors_by_mode[3])
759 : {
760 0 : error_report &= ~ERROR_REPORT_EP3_OK;
761 : }
762 : }
763 : }
764 : #endif
765 :
766 0 : if (*bfi == 1)
767 : {
768 0 : *data_bytes = 0;
769 :
770 :
771 0 : return error_report;
772 : }
773 :
774 : /* initialization for decoding */
775 0 : *data_bytes = fec_get_data_size(mode, ccc_flag, slot_bytes);
776 0 : pc_split = fec_get_n_pc(mode, *n_pccw, slot_bytes);
777 0 : n_crc = get_total_crc_size(slot_bytes, mode, pc_split);
778 :
779 : /* decoding of first code word */
780 0 : redundancy_nibbles = hamming_distance_by_mode0[mode] - 1;
781 0 : codeword_length = get_codeword_length(n_codewords, slot_bytes + slot_bytes, 0);
782 :
783 0 : dw_offset = 0;
784 0 : cw_offset = 0;
785 :
786 0 : for (j = redundancy_nibbles; j < codeword_length; j++)
787 : {
788 0 : cw_buf[dw_offset++] = cw_buf[j];
789 : }
790 0 : cw_offset = cw_offset + codeword_length;
791 :
792 : /* decoding of remaining code words */
793 0 : redundancy_nibbles = hamming_distance_by_mode1[mode] - 1;
794 :
795 0 : for (i = 1; i < n_codewords; i++)
796 : {
797 0 : codeword_length = get_codeword_length(n_codewords, slot_bytes + slot_bytes, i);
798 :
799 0 : for (j = redundancy_nibbles; j < codeword_length; j++)
800 : {
801 0 : cw_buf[dw_offset++] = cw_buf[j + cw_offset];
802 : }
803 :
804 0 : cw_offset = cw_offset + codeword_length;
805 : }
806 :
807 : /* data postproc: hash validation and re-ordering */
808 :
809 0 : fec_data_postproc(mode, epmr, iobuf, *data_bytes, cw_buf, slot_bytes, pc_split, bfi);
810 :
811 0 : if (*bfi == 1)
812 : {
813 0 : *data_bytes = 0;
814 :
815 0 : error_report &= ERROR_REPORT_BEC_MASK;
816 :
817 :
818 0 : return error_report;
819 : }
820 :
821 0 : if (*bfi == 2)
822 : {
823 0 : first_bad_cw = 0;
824 0 : array_of_trust[*n_pccw] = 0;
825 0 : while (array_of_trust[first_bad_cw] != 0)
826 : {
827 0 : first_bad_cw = first_bad_cw + 1;
828 : }
829 0 : if (first_bad_cw == *n_pccw)
830 : {
831 : /* this is the case when CRC failed */
832 0 : *be_bp_left = 0;
833 : }
834 : else
835 : {
836 0 : *be_bp_left = 4*fec_get_n_pc(mode, first_bad_cw, slot_bytes);
837 : }
838 :
839 0 : for (i = *n_pccw - 1; i >= 0; i--)
840 : {
841 0 : if (!array_of_trust[i])
842 : {
843 0 : break;
844 : }
845 : }
846 0 : if (i < 0)
847 : {
848 0 : i = *n_pccw - 1;
849 : }
850 0 : *be_bp_right = 4*fec_get_n_pc(mode, i + 1, slot_bytes) - 1;
851 : }
852 :
853 0 : if (ccc_flag == 0)
854 : {
855 0 : *n_pc = pc_split;
856 0 : *m_fec = mode;
857 : }
858 :
859 :
860 0 : return error_report;
861 : }
862 :
863 0 : FEC_STATIC void fec_deinterleave_unpack(LC3_UINT8 *out, LC3_UINT8 *in, LC3_INT16 n_nibbles, LC3_INT16 n_codewords)
864 : {
865 : LC3_INT16 in_offset, out_offset, codeword_length;
866 : LC3_INT32 i, j;
867 :
868 0 : in_offset = 0;
869 0 : out_offset = 0;
870 :
871 : /* unpack nibbles in input buffer and deinterleave codewords */
872 0 : for (i = 0; i < n_codewords; i++)
873 : {
874 0 : codeword_length = get_codeword_length(n_codewords, n_nibbles, i);
875 0 : for (j = 0; j < codeword_length; (j++, out_offset++))
876 : {
877 0 : in_offset = n_nibbles - 1 - j*n_codewords - i;
878 0 : out[out_offset] = (in[in_offset >> 1] >> ((in_offset & 1) << 2)) & 15;
879 : }
880 : }
881 :
882 :
883 0 : assert(out_offset == n_nibbles);
884 :
885 0 : }
886 :
887 0 : FEC_STATIC LC3PLUS_EpModeRequest fec_estimate_epmr_from_cw0(LC3_UINT8 *cw0, LC3_INT8 *t, LC3_UINT8 *syndromes, LC3_UINT8 *elp, LC3_INT8 *deg_elp,
888 : LC3_UINT8 *err_pos, LC3_UINT8 *err_symb, LC3_INT16 n_codewords, LC3_INT16 n_symb)
889 : {
890 : LC3_INT32 epmr_lowest_risk_exp;
891 : LC3_INT32 start, inc, i, n_candidates;
892 : LC3_INT32 first_codeword_length;
893 : LC3_INT32 mode_counter;
894 : LC3PLUS_EpModeRequest epmr;
895 :
896 0 : epmr_lowest_risk_exp = 0;
897 0 : first_codeword_length = get_codeword_length(n_codewords, n_symb, 0);
898 0 : start = 2;
899 0 : inc = 1;
900 0 : n_candidates = 0;
901 :
902 : /* test if first code word decodes in mode 0 or 1 without error correction */
903 0 : if ((syndromes[SYNDROME_IDX(0, 0)] | syndromes[SYNDROME_IDX(0, 0) + 1]) == 0 ||
904 0 : (syndromes[SYNDROME_IDX(1, 0)] | syndromes[SYNDROME_IDX(1, 0) + 1]) == 0)
905 : {
906 0 : epmr_lowest_risk_exp = risk_table_f[1][0].exponent;
907 : }
908 : /* test if first code word decodes in mode 2 or 3 with lower risk */
909 0 : if (deg_elp[DEG_ELP_IDX(2, 0)] <= t[2])
910 : {
911 0 : if (risk_table_f[2][deg_elp[DEG_ELP_IDX(2, 0)]].exponent <= -8)
912 : {
913 0 : n_candidates++;
914 0 : start = 2;
915 : }
916 : }
917 :
918 0 : if (deg_elp[DEG_ELP_IDX(3, 0)] <= t[3])
919 : {
920 0 : if (risk_table_f[3][deg_elp[DEG_ELP_IDX(3, 0)]].exponent <= -8)
921 : {
922 0 : n_candidates++;
923 0 : start = 3;
924 : }
925 : }
926 :
927 0 : if (n_candidates > 1)
928 : {
929 : /* decide on order if mode 2 and 3 are considered */
930 0 : if (simple_float_cmp(risk_table_f[2][deg_elp[DEG_ELP_IDX(2, 0)]], risk_table_f[3][deg_elp[DEG_ELP_IDX(3, 0)]]) <
931 : 0)
932 : {
933 0 : start = 2;
934 0 : inc = 1;
935 : }
936 : else
937 : {
938 0 : start = 3;
939 0 : inc = -1;
940 : }
941 : }
942 :
943 0 : for (mode_counter = start, i = 0; i < n_candidates; mode_counter += inc, i++)
944 : {
945 0 : if (risk_table_f[mode_counter][deg_elp[DEG_ELP_IDX(mode_counter, 0)]].exponent < epmr_lowest_risk_exp)
946 : {
947 0 : if (!rs16_factorize_elp(err_pos + ERR_POS_IDX(mode_counter, 0), elp + ELP_IDX(mode_counter, 0),
948 0 : deg_elp[DEG_ELP_IDX(mode_counter, 0)], first_codeword_length - 1))
949 : {
950 : /* code word is decodable with error correction */
951 0 : epmr_lowest_risk_exp = risk_table_f[mode_counter][deg_elp[DEG_ELP_IDX(mode_counter, 0)]].exponent;
952 :
953 0 : rs16_calculate_errors(err_symb + ERR_SYMB_IDX(mode_counter, 0), err_pos + ERR_POS_IDX(mode_counter, 0),
954 0 : syndromes + SYNDROME_IDX(mode_counter, 0), deg_elp[DEG_ELP_IDX(mode_counter, 0)],
955 0 : t[mode_counter]);
956 :
957 0 : for (i = 0; i < deg_elp[DEG_ELP_IDX(mode_counter, 0)]; i++)
958 : {
959 0 : cw0[err_pos[ERR_POS_IDX(mode_counter, 0) + i]] = GF16_ADD(
960 : cw0[err_pos[ERR_POS_IDX(mode_counter, 0) + i]], err_symb[ERR_SYMB_IDX(mode_counter, 0) + i]);
961 : }
962 0 : break;
963 : }
964 : }
965 : }
966 :
967 0 : epmr = cw0_get_epmr(cw0, first_codeword_length - 1);
968 :
969 0 : if (epmr_lowest_risk_exp > -16)
970 : {
971 0 : epmr += 4;
972 : }
973 0 : if (epmr_lowest_risk_exp > -8)
974 : {
975 0 : epmr += 4;
976 : }
977 :
978 :
979 0 : return epmr;
980 : }
981 :
982 0 : FEC_STATIC LC3_INT32 rs16_detect_and_correct(LC3_UINT8 *iobuf, LC3_INT32 n_symb, LC3_INT32 n_codewords, LC3PLUS_EpModeRequest *epmr, LC3_INT16 *error_report,
983 : LC3_INT32 *bfi, LC3_UINT8 *array_of_trust, LC3_INT32 ccc_flag, LC3_INT16 *n_pccw)
984 : {
985 :
986 : LC3_INT16 mode_broken[4];
987 : LC3_INT16 error_report_ep_ok[4];
988 : LC3_INT16 i, cw_counter, mode_counter, cw_offset;
989 : LC3_INT16 codeword_length;
990 : LC3_INT16 mode;
991 : LC3_INT16 mode_candidates[4];
992 : LC3_INT16 n_mode_candidates;
993 : LC3_INT16 broken_cw, n_broken_cw;
994 : LC3_INT16 j, idx_min;
995 : LC3_INT16 n_pccw0;
996 : simple_float val_min_f;
997 : LC3_INT16 tmp;
998 : LC3_INT16 epmr_position;
999 : simple_float dec_risk_f[FEC_N_MODES];
1000 : simple_float risk_min_f;
1001 : simple_float ep_risk_thresh;
1002 : LC3_INT32 epmr_dec_fail_increment;
1003 : LC3_UINT8 const *hamming_distance;
1004 : LC3_UINT8 syndromes[FEC_TOTAL_SYNDROME_SIZE];
1005 : LC3_UINT8 elp[FEC_TOTAL_ELP_SIZE];
1006 : LC3_UINT8 err_pos[FEC_TOTAL_ERR_POS_SIZE];
1007 : LC3_UINT8 err_symb[FEC_TOTAL_ERROR_SIZE];
1008 : LC3_INT8 t[FEC_N_MODES];
1009 : LC3_INT8 deg_elp[FEC_TOTAL_DEG_ELP_SIZE];
1010 : LC3_UINT8 blacklist[FEC_N_MODES];
1011 : LC3_INT32 rop;
1012 :
1013 : void (*syndr_calc[3])(LC3_UINT8 *, LC3_UINT8 *, LC3_INT32);
1014 0 : rop = 0;
1015 :
1016 : /* initialization */
1017 0 : blacklist[0] = 0;
1018 0 : blacklist[1] = 0;
1019 0 : blacklist[2] = 0;
1020 0 : blacklist[3] = 0;
1021 0 : mode_broken[0] = 0;
1022 0 : mode_broken[1] = 0;
1023 0 : mode_broken[2] = 0;
1024 0 : mode_broken[3] = 0;
1025 0 : error_report_ep_ok[0] = ERROR_REPORT_EP1_OK;
1026 0 : error_report_ep_ok[1] = ERROR_REPORT_EP2_OK;
1027 0 : error_report_ep_ok[2] = ERROR_REPORT_EP3_OK;
1028 0 : error_report_ep_ok[3] = ERROR_REPORT_EP4_OK;
1029 0 : hamming_distance = &hamming_distance_by_mode0[1];
1030 0 : mode = -1;
1031 0 : n_mode_candidates = 0;
1032 0 : risk_min_f.mantissa = SIMPLE_FLOAT_1_MANTISSA;
1033 0 : risk_min_f.exponent = 0;
1034 :
1035 0 : if (n_symb <= 80)
1036 : {
1037 0 : ep_risk_thresh.mantissa = EP_RISK_THRESH_NS_M;
1038 0 : ep_risk_thresh.exponent = EP_RISK_THRESH_NS_E;
1039 : }
1040 : else
1041 : {
1042 0 : ep_risk_thresh.mantissa = EP_RISK_THRESH_OS_M;
1043 0 : ep_risk_thresh.exponent = EP_RISK_THRESH_OS_E;
1044 : }
1045 :
1046 0 : syndr_calc[0] = &rs16_calculate_two_syndromes;
1047 0 : syndr_calc[1] = &rs16_calculate_four_syndromes;
1048 0 : syndr_calc[2] = &rs16_calculate_six_syndromes;
1049 :
1050 0 : for (i = 0; i < FEC_N_MODES; i++)
1051 : {
1052 0 : t[i] = (hamming_distance[i] -1)/2;
1053 : }
1054 :
1055 0 : *error_report = 0;
1056 0 : *bfi = 0;
1057 :
1058 : /* mode detection (stage 1) */
1059 0 : codeword_length = get_codeword_length(n_codewords, n_symb, 0);
1060 :
1061 0 : epmr_position = codeword_length - 1;
1062 :
1063 0 : rs16_calculate_two_syndromes(syndromes + SYNDROME_IDX(0, 0), iobuf, codeword_length - 1);
1064 :
1065 0 : if ((syndromes[0 + SYNDROME_IDX(0, 0)] | syndromes[1 + SYNDROME_IDX(0, 0)]) == 0)
1066 : {
1067 :
1068 : /* data validation for fec mode 1 */
1069 0 : *epmr = cw0_get_epmr(iobuf, epmr_position);
1070 :
1071 0 : dw0_bitswap(iobuf + 2, 1, n_symb / 2);
1072 :
1073 0 : if (!crc1(iobuf + 8, n_symb - 8, *epmr, iobuf + 2, 3, 1))
1074 : {
1075 0 : *error_report |= ERROR_REPORT_ALL_OK;
1076 0 : mode = 0;
1077 :
1078 :
1079 0 : rop = mode + 1;
1080 0 : goto CLEANUP;
1081 : }
1082 : else
1083 : {
1084 : /* reverse bit swap */
1085 0 : dw0_bitswap(iobuf + 2, 1, n_symb / 2);
1086 :
1087 0 : *epmr += 4;
1088 : }
1089 : }
1090 :
1091 0 : blacklist[0] = 1;
1092 :
1093 : /* mode detection (stage 2) */
1094 :
1095 : /* calculate syndromes of code words 0 to 5 and modes 1 to 3 */
1096 0 : cw_offset = 0;
1097 :
1098 0 : for (cw_counter = 0; cw_counter < 6; cw_counter++)
1099 : {
1100 0 : codeword_length = get_codeword_length(n_codewords, n_symb, cw_counter);
1101 :
1102 0 : rs16_calculate_six_syndromes(syndromes + SYNDROME_IDX(1, cw_counter), iobuf + cw_offset,
1103 : codeword_length - 1);
1104 :
1105 0 : cw_offset += codeword_length;
1106 :
1107 0 : for (mode_counter = FEC_N_MODES - 1; mode_counter >= 1; mode_counter--)
1108 : {
1109 0 : for (i = 0; i < hamming_distance[mode_counter] - 1; i++)
1110 : {
1111 0 : syndromes[SYNDROME_IDX(mode_counter, cw_counter) + i] = GF16_ADD(
1112 : syndromes[SYNDROME_IDX(1, cw_counter) + i], sig_poly_syndr[mode_counter][i]);
1113 : }
1114 : }
1115 : }
1116 :
1117 : /* check for valid code words */
1118 0 : for (mode_counter = 1; mode_counter < FEC_N_MODES; mode_counter++)
1119 : {
1120 0 : n_broken_cw = 0;
1121 0 : for (cw_counter = 0; cw_counter < 6; cw_counter++)
1122 : {
1123 0 : broken_cw = 0;
1124 0 : for (i = 0; i < hamming_distance[mode_counter] - 1; i++)
1125 : {
1126 0 : broken_cw |= syndromes[SYNDROME_IDX(mode_counter, cw_counter) + i];
1127 : }
1128 0 : if (broken_cw != 0)
1129 : {
1130 0 : n_broken_cw ++;
1131 : }
1132 : }
1133 :
1134 0 : if (n_broken_cw == 0)
1135 : {
1136 0 : mode = mode_counter;
1137 0 : cw_offset = 0;
1138 :
1139 0 : *epmr = cw0_get_epmr(iobuf, epmr_position);
1140 :
1141 0 : for (cw_counter = 0; cw_counter < 6; cw_counter++)
1142 : {
1143 0 : codeword_length = get_codeword_length(n_codewords, n_symb, cw_counter);
1144 0 : for (i = 0; i <= EP_SIG_POLY_DEG; i++)
1145 : {
1146 0 : iobuf[cw_offset + i] = GF16_ADD(iobuf[cw_offset + i], sig_polys[mode][i]);
1147 : }
1148 0 : cw_offset += codeword_length;
1149 : }
1150 : }
1151 : }
1152 :
1153 0 : if (mode < 0) /* mode hasn't been detected so far -> errors occurred in transmission */
1154 : {
1155 : /* calculate error locator polynomials for code words 0 to 5 */
1156 0 : for (mode_counter = 1; mode_counter < FEC_N_MODES; mode_counter++)
1157 : {
1158 0 : for (cw_counter = 0; cw_counter < 6; cw_counter++)
1159 : {
1160 0 : deg_elp[DEG_ELP_IDX(mode_counter, cw_counter)] = rs16_calculate_elp(
1161 0 : elp + ELP_IDX(mode_counter, cw_counter), syndromes + SYNDROME_IDX(mode_counter, cw_counter),
1162 0 : t[mode_counter]);
1163 0 : if (deg_elp[DEG_ELP_IDX(mode_counter, cw_counter)] > t[mode_counter])
1164 : {
1165 0 : blacklist[mode_counter] = 1;
1166 0 : break;
1167 : }
1168 : }
1169 : }
1170 :
1171 : /* risk analysis for mode candidate selection */
1172 0 : for (mode_counter = 1; mode_counter < FEC_N_MODES; mode_counter++)
1173 : {
1174 0 : dec_risk_f[mode_counter].mantissa = SIMPLE_FLOAT_1_MANTISSA;
1175 0 : dec_risk_f[mode_counter].exponent = 0;
1176 :
1177 0 : if (blacklist[mode_counter] == 0)
1178 : {
1179 0 : for (cw_counter = 0; cw_counter < 6; cw_counter++)
1180 : {
1181 0 : dec_risk_f[mode_counter] = simple_float_mul(
1182 : dec_risk_f[mode_counter],
1183 0 : risk_table_f[mode_counter][deg_elp[DEG_ELP_IDX(mode_counter, cw_counter)]]);
1184 : }
1185 :
1186 0 : if (simple_float_cmp(dec_risk_f[mode_counter], ep_risk_thresh) <= 0)
1187 : {
1188 0 : mode_candidates[n_mode_candidates++] = mode_counter;
1189 : }
1190 :
1191 0 : if (simple_float_cmp(dec_risk_f[mode_counter], risk_min_f) < 0)
1192 : {
1193 0 : risk_min_f = dec_risk_f[mode_counter];
1194 : }
1195 : }
1196 : }
1197 0 : assert(n_mode_candidates <= 4); // suppress false gcc warning when OPTIM=3
1198 :
1199 : /* sort mode candidates by risk */
1200 0 : for (i = 0; i < n_mode_candidates; i++)
1201 : {
1202 0 : idx_min = i;
1203 0 : val_min_f = dec_risk_f[mode_candidates[i]];
1204 :
1205 0 : for (j = i + 1; j < n_mode_candidates; j++)
1206 : {
1207 0 : if (simple_float_cmp(dec_risk_f[mode_candidates[j]], val_min_f) < 0)
1208 : {
1209 0 : val_min_f = dec_risk_f[mode_candidates[j]];
1210 0 : idx_min = j;
1211 : }
1212 : }
1213 :
1214 0 : if (idx_min > i)
1215 : {
1216 0 : tmp = mode_candidates[i];
1217 0 : mode_candidates[i] = mode_candidates[idx_min];
1218 0 : mode_candidates[idx_min] = tmp;
1219 : }
1220 : }
1221 :
1222 : /* try out candidate modes */
1223 0 : for (i = 0; i < n_mode_candidates; i++)
1224 : {
1225 0 : mode = mode_candidates[i];
1226 :
1227 0 : for (cw_counter = 0; cw_counter < 6; cw_counter++)
1228 : {
1229 0 : codeword_length = get_codeword_length(n_codewords, n_symb, cw_counter);
1230 :
1231 0 : if (deg_elp[DEG_ELP_IDX(mode, cw_counter)])
1232 : {
1233 0 : if (rs16_factorize_elp(err_pos + ERR_POS_IDX(mode, cw_counter), elp + ELP_IDX(mode, cw_counter),
1234 0 : deg_elp[DEG_ELP_IDX(mode, cw_counter)], codeword_length - 1))
1235 : {
1236 : /* elp did not split into distinct linear factors or error position was out of range */
1237 0 : mode = -1;
1238 0 : break;
1239 : }
1240 : }
1241 : }
1242 0 : if (mode > 0)
1243 : {
1244 : /* decodable mode with lowest risk has been found */
1245 0 : break;
1246 : }
1247 : }
1248 :
1249 0 : if (mode < 0)
1250 : {
1251 : /* no decodable mode has been found */
1252 0 : *error_report = ERROR_REPORT_BEC_MASK;
1253 0 : *bfi = 1;
1254 0 : mode = -1;
1255 :
1256 0 : *epmr = fec_estimate_epmr_from_cw0(iobuf, t, syndromes, elp, deg_elp, err_pos, err_symb, n_codewords,
1257 : n_symb);
1258 :
1259 :
1260 0 : rop = mode;
1261 0 : goto CLEANUP;
1262 : }
1263 :
1264 : /* perform error correction */
1265 0 : cw_offset = 0;
1266 0 : *error_report = 0;
1267 0 : for (cw_counter = 0; cw_counter < 6; cw_counter++)
1268 : {
1269 0 : codeword_length = get_codeword_length(n_codewords, n_symb, cw_counter);
1270 :
1271 0 : if (deg_elp[DEG_ELP_IDX(mode, cw_counter)])
1272 : {
1273 0 : rs16_calculate_errors(
1274 0 : err_symb + ERR_SYMB_IDX(mode, cw_counter), err_pos + ERR_POS_IDX(mode, cw_counter),
1275 0 : syndromes + SYNDROME_IDX(mode, cw_counter), deg_elp[DEG_ELP_IDX(mode, cw_counter)], t[mode]);
1276 :
1277 : /* correct errors and sum up number of corrected bits */
1278 0 : for (i = 0; i < deg_elp[DEG_ELP_IDX(mode, cw_counter)]; i++)
1279 : {
1280 0 : iobuf[err_pos[ERR_POS_IDX(mode, cw_counter) + i] + cw_offset] =
1281 0 : GF16_ADD(iobuf[err_pos[ERR_POS_IDX(mode, cw_counter) + i] + cw_offset],
1282 : err_symb[ERR_SYMB_IDX(mode, cw_counter) + i]);
1283 0 : *error_report += rs16_bit_count_table[err_symb[ERR_SYMB_IDX(mode, cw_counter) + i]];
1284 : }
1285 :
1286 0 : for (i = 0; i < mode; i ++)
1287 : {
1288 0 : if(deg_elp[DEG_ELP_IDX(mode, cw_counter)] > i)
1289 : {
1290 0 : mode_broken[i] = 1;
1291 : }
1292 : }
1293 :
1294 : }
1295 :
1296 0 : for (i = 0; i <= EP_SIG_POLY_DEG; i++)
1297 : {
1298 0 : iobuf[cw_offset + i] = GF16_ADD(iobuf[cw_offset + i], sig_polys[mode][i]);
1299 : }
1300 0 : cw_offset += codeword_length;
1301 : }
1302 :
1303 : /* set epmr according to risk value of cw0 */
1304 0 : epmr_dec_fail_increment = 8;
1305 :
1306 0 : if (risk_table_f[mode][deg_elp[DEG_ELP_IDX(mode, 0)]].exponent <= -8)
1307 : {
1308 0 : epmr_dec_fail_increment -= 4;
1309 : }
1310 0 : if (risk_table_f[mode][deg_elp[DEG_ELP_IDX(mode, 0)]].exponent <= -16)
1311 : {
1312 0 : epmr_dec_fail_increment -= 4;
1313 : }
1314 :
1315 0 : *epmr = (LC3PLUS_EpModeRequest)(cw0_get_epmr(iobuf, epmr_position) + epmr_dec_fail_increment);
1316 : }
1317 :
1318 : /* mode has been successfully detected -> now check and try to correct remaining code words*/
1319 0 : *n_pccw = fec_get_n_pccw(n_symb / 2, mode + 1, ccc_flag);
1320 0 : if (ccc_flag == 0)
1321 : {
1322 0 : n_pccw0 = fec_get_n_pccw(n_symb / 2, mode + 1, ccc_flag);
1323 0 : *n_pccw = n_pccw0;
1324 : }
1325 : else
1326 : {
1327 0 : n_pccw0 = 0;
1328 : }
1329 :
1330 0 : for (cw_counter = 6; cw_counter < n_codewords; cw_counter++)
1331 : {
1332 : /* usual error correction scheme: syndromes -> elp's, errors, etc. */
1333 0 : codeword_length = get_codeword_length(n_codewords, n_symb, cw_counter);
1334 0 : array_of_trust[n_codewords - 1 - cw_counter] = 1;
1335 :
1336 0 : syndr_calc[t[mode] - 1](syndromes, iobuf + cw_offset, codeword_length -1);
1337 :
1338 0 : deg_elp[0] = rs16_calculate_elp(elp, syndromes, t[mode]);
1339 :
1340 0 : for (i = 0; i < mode; i ++)
1341 : {
1342 0 : if (deg_elp[0] > i)
1343 : {
1344 0 : mode_broken[i] = 1;
1345 : }
1346 : }
1347 :
1348 0 : if (deg_elp[0] > t[mode])
1349 : {
1350 0 : for (i = 0; i < 4; i ++)
1351 : {
1352 0 : mode_broken[i] = 1;
1353 : }
1354 0 : cw_offset += codeword_length;
1355 0 : if (cw_counter < n_codewords - n_pccw0)
1356 : {
1357 0 : *error_report = ERROR_REPORT_BEC_MASK;
1358 0 : mode = -1;
1359 0 : *bfi = 1;
1360 0 : break;
1361 : }
1362 : else
1363 : {
1364 0 : *bfi = 2;
1365 0 : array_of_trust[n_codewords - 1 - cw_counter] = 0;
1366 0 : continue;
1367 : }
1368 : }
1369 :
1370 0 : if (deg_elp[0])
1371 : {
1372 0 : if (rs16_factorize_elp(err_pos, elp, deg_elp[0], codeword_length - 1))
1373 : {
1374 0 : cw_offset += codeword_length;
1375 0 : for (i = 0; i < 4; i ++)
1376 : {
1377 0 : mode_broken[i] = 1;
1378 : }
1379 0 : if (cw_counter < n_codewords - n_pccw0)
1380 : {
1381 0 : *error_report = ERROR_REPORT_BEC_MASK;
1382 0 : mode = -1;
1383 0 : *bfi = 1;
1384 :
1385 0 : break;
1386 : }
1387 : else
1388 : {
1389 0 : *bfi = 2;
1390 0 : array_of_trust[n_codewords - 1 - cw_counter] = 0;
1391 0 : continue;
1392 : }
1393 : }
1394 :
1395 0 : rs16_calculate_errors(err_symb, err_pos, syndromes, deg_elp[0], t[mode]);
1396 :
1397 : /* correct errors and sum up number of corrected bits */
1398 0 : for (i = 0; i < deg_elp[0]; i++)
1399 : {
1400 0 : iobuf[err_pos[i] + cw_offset] = GF16_ADD(iobuf[err_pos[i] + cw_offset], err_symb[i]);
1401 0 : *error_report += rs16_bit_count_table[err_symb[i]];
1402 : }
1403 : }
1404 0 : cw_offset += codeword_length;
1405 0 : if (risk_table_f[mode][deg_elp[0]].exponent > -16)
1406 : {
1407 0 : array_of_trust[n_codewords - 1 - cw_counter] = 0;
1408 : }
1409 : }
1410 :
1411 0 : *error_report &= ERROR_REPORT_BEC_MASK;
1412 0 : for (i = 0; i < 4; i ++)
1413 : {
1414 0 : if (!mode_broken[i])
1415 : {
1416 0 : *error_report |= error_report_ep_ok[i];
1417 : }
1418 : }
1419 :
1420 0 : if (mode >= 0)
1421 : {
1422 0 : rop = mode + 1;
1423 : } else {
1424 0 : rop = -1;
1425 : }
1426 :
1427 :
1428 :
1429 0 : CLEANUP:
1430 0 : return rop;
1431 : }
1432 :
1433 0 : FEC_STATIC void rs16_calculate_six_syndromes(LC3_UINT8 *syndromes, LC3_UINT8 *cw, LC3_INT32 cw_poly_deg)
1434 : {
1435 : LC3_INT32 i;
1436 : LC3_UINT8 buffer[15];
1437 :
1438 0 : assert(cw_poly_deg >= 12);
1439 :
1440 0 : for (i = 0; i <= cw_poly_deg; i++)
1441 : {
1442 0 : buffer[i] = cw[i];
1443 : }
1444 :
1445 0 : syndromes[0] = buffer[0];
1446 0 : syndromes[1] = buffer[0];
1447 0 : syndromes[2] = buffer[0];
1448 0 : syndromes[3] = buffer[0];
1449 0 : syndromes[4] = buffer[0];
1450 0 : syndromes[5] = buffer[0];
1451 :
1452 0 : syndromes[0] = GF16_ADD(syndromes[0], GF16_MUL0(buffer[1], 32));
1453 0 : syndromes[1] = GF16_ADD(syndromes[1], GF16_MUL0(buffer[1], 64));
1454 0 : syndromes[2] = GF16_ADD(syndromes[2], GF16_MUL0(buffer[1], 128));
1455 0 : syndromes[3] = GF16_ADD(syndromes[3], GF16_MUL0(buffer[1], 48));
1456 0 : syndromes[4] = GF16_ADD(syndromes[4], GF16_MUL0(buffer[1], 96));
1457 0 : syndromes[5] = GF16_ADD(syndromes[5], GF16_MUL0(buffer[1], 192));
1458 :
1459 0 : syndromes[0] = GF16_ADD(syndromes[0], GF16_MUL0(buffer[2], 64));
1460 0 : syndromes[1] = GF16_ADD(syndromes[1], GF16_MUL0(buffer[2], 48));
1461 0 : syndromes[2] = GF16_ADD(syndromes[2], GF16_MUL0(buffer[2], 192));
1462 0 : syndromes[3] = GF16_ADD(syndromes[3], GF16_MUL0(buffer[2], 80));
1463 0 : syndromes[4] = GF16_ADD(syndromes[4], GF16_MUL0(buffer[2], 112));
1464 0 : syndromes[5] = GF16_ADD(syndromes[5], GF16_MUL0(buffer[2], 240));
1465 :
1466 0 : syndromes[0] = GF16_ADD(syndromes[0], GF16_MUL0(buffer[3], 128));
1467 0 : syndromes[1] = GF16_ADD(syndromes[1], GF16_MUL0(buffer[3], 192));
1468 0 : syndromes[2] = GF16_ADD(syndromes[2], GF16_MUL0(buffer[3], 160));
1469 0 : syndromes[3] = GF16_ADD(syndromes[3], GF16_MUL0(buffer[3], 240));
1470 0 : syndromes[4] = GF16_ADD(syndromes[4], GF16_MUL0(buffer[3], 16));
1471 0 : syndromes[5] = GF16_ADD(syndromes[5], GF16_MUL0(buffer[3], 128));
1472 :
1473 0 : syndromes[0] = GF16_ADD(syndromes[0], GF16_MUL0(buffer[4], 48));
1474 0 : syndromes[1] = GF16_ADD(syndromes[1], GF16_MUL0(buffer[4], 80));
1475 0 : syndromes[2] = GF16_ADD(syndromes[2], GF16_MUL0(buffer[4], 240));
1476 0 : syndromes[3] = GF16_ADD(syndromes[3], GF16_MUL0(buffer[4], 32));
1477 0 : syndromes[4] = GF16_ADD(syndromes[4], GF16_MUL0(buffer[4], 96));
1478 0 : syndromes[5] = GF16_ADD(syndromes[5], GF16_MUL0(buffer[4], 160));
1479 :
1480 0 : syndromes[0] = GF16_ADD(syndromes[0], GF16_MUL0(buffer[5], 96));
1481 0 : syndromes[1] = GF16_ADD(syndromes[1], GF16_MUL0(buffer[5], 112));
1482 0 : syndromes[2] = GF16_ADD(syndromes[2], GF16_MUL0(buffer[5], 16));
1483 0 : syndromes[3] = GF16_ADD(syndromes[3], GF16_MUL0(buffer[5], 96));
1484 0 : syndromes[4] = GF16_ADD(syndromes[4], GF16_MUL0(buffer[5], 112));
1485 0 : syndromes[5] = GF16_ADD(syndromes[5], GF16_MUL0(buffer[5], 16));
1486 :
1487 0 : syndromes[0] = GF16_ADD(syndromes[0], GF16_MUL0(buffer[6], 192));
1488 0 : syndromes[1] = GF16_ADD(syndromes[1], GF16_MUL0(buffer[6], 240));
1489 0 : syndromes[2] = GF16_ADD(syndromes[2], GF16_MUL0(buffer[6], 128));
1490 0 : syndromes[3] = GF16_ADD(syndromes[3], GF16_MUL0(buffer[6], 160));
1491 0 : syndromes[4] = GF16_ADD(syndromes[4], GF16_MUL0(buffer[6], 16));
1492 0 : syndromes[5] = GF16_ADD(syndromes[5], GF16_MUL0(buffer[6], 192));
1493 :
1494 0 : syndromes[0] = GF16_ADD(syndromes[0], GF16_MUL0(buffer[7], 176));
1495 0 : syndromes[1] = GF16_ADD(syndromes[1], GF16_MUL0(buffer[7], 144));
1496 0 : syndromes[2] = GF16_ADD(syndromes[2], GF16_MUL0(buffer[7], 192));
1497 0 : syndromes[3] = GF16_ADD(syndromes[3], GF16_MUL0(buffer[7], 208));
1498 0 : syndromes[4] = GF16_ADD(syndromes[4], GF16_MUL0(buffer[7], 96));
1499 0 : syndromes[5] = GF16_ADD(syndromes[5], GF16_MUL0(buffer[7], 240));
1500 :
1501 0 : syndromes[0] = GF16_ADD(syndromes[0], GF16_MUL0(buffer[8], 80));
1502 0 : syndromes[1] = GF16_ADD(syndromes[1], GF16_MUL0(buffer[8], 32));
1503 0 : syndromes[2] = GF16_ADD(syndromes[2], GF16_MUL0(buffer[8], 160));
1504 0 : syndromes[3] = GF16_ADD(syndromes[3], GF16_MUL0(buffer[8], 64));
1505 0 : syndromes[4] = GF16_ADD(syndromes[4], GF16_MUL0(buffer[8], 112));
1506 0 : syndromes[5] = GF16_ADD(syndromes[5], GF16_MUL0(buffer[8], 128));
1507 :
1508 0 : syndromes[0] = GF16_ADD(syndromes[0], GF16_MUL0(buffer[9], 160));
1509 0 : syndromes[1] = GF16_ADD(syndromes[1], GF16_MUL0(buffer[9], 128));
1510 0 : syndromes[2] = GF16_ADD(syndromes[2], GF16_MUL0(buffer[9], 240));
1511 0 : syndromes[3] = GF16_ADD(syndromes[3], GF16_MUL0(buffer[9], 192));
1512 0 : syndromes[4] = GF16_ADD(syndromes[4], GF16_MUL0(buffer[9], 16));
1513 0 : syndromes[5] = GF16_ADD(syndromes[5], GF16_MUL0(buffer[9], 160));
1514 :
1515 0 : syndromes[0] = GF16_ADD(syndromes[0], GF16_MUL0(buffer[10], 112));
1516 0 : syndromes[1] = GF16_ADD(syndromes[1], GF16_MUL0(buffer[10], 96));
1517 0 : syndromes[2] = GF16_ADD(syndromes[2], GF16_MUL0(buffer[10], 16));
1518 0 : syndromes[3] = GF16_ADD(syndromes[3], GF16_MUL0(buffer[10], 112));
1519 0 : syndromes[4] = GF16_ADD(syndromes[4], GF16_MUL0(buffer[10], 96));
1520 0 : syndromes[5] = GF16_ADD(syndromes[5], GF16_MUL0(buffer[10], 16));
1521 :
1522 0 : syndromes[0] = GF16_ADD(syndromes[0], GF16_MUL0(buffer[11], 224));
1523 0 : syndromes[1] = GF16_ADD(syndromes[1], GF16_MUL0(buffer[11], 176));
1524 0 : syndromes[2] = GF16_ADD(syndromes[2], GF16_MUL0(buffer[11], 128));
1525 0 : syndromes[3] = GF16_ADD(syndromes[3], GF16_MUL0(buffer[11], 144));
1526 0 : syndromes[4] = GF16_ADD(syndromes[4], GF16_MUL0(buffer[11], 112));
1527 0 : syndromes[5] = GF16_ADD(syndromes[5], GF16_MUL0(buffer[11], 192));
1528 :
1529 0 : syndromes[0] = GF16_ADD(syndromes[0], GF16_MUL0(buffer[12], 240));
1530 0 : syndromes[1] = GF16_ADD(syndromes[1], GF16_MUL0(buffer[12], 160));
1531 0 : syndromes[2] = GF16_ADD(syndromes[2], GF16_MUL0(buffer[12], 192));
1532 0 : syndromes[3] = GF16_ADD(syndromes[3], GF16_MUL0(buffer[12], 128));
1533 0 : syndromes[4] = GF16_ADD(syndromes[4], GF16_MUL0(buffer[12], 16));
1534 0 : syndromes[5] = GF16_ADD(syndromes[5], GF16_MUL0(buffer[12], 240));
1535 :
1536 0 : if (cw_poly_deg >= 13)
1537 : {
1538 0 : syndromes[0] = GF16_ADD(syndromes[0], GF16_MUL0(buffer[13], 208));
1539 0 : syndromes[1] = GF16_ADD(syndromes[1], GF16_MUL0(buffer[13], 224));
1540 0 : syndromes[2] = GF16_ADD(syndromes[2], GF16_MUL0(buffer[13], 160));
1541 0 : syndromes[3] = GF16_ADD(syndromes[3], GF16_MUL0(buffer[13], 176));
1542 0 : syndromes[4] = GF16_ADD(syndromes[4], GF16_MUL0(buffer[13], 96));
1543 0 : syndromes[5] = GF16_ADD(syndromes[5], GF16_MUL0(buffer[13], 128));
1544 : }
1545 :
1546 0 : if (cw_poly_deg >= 14)
1547 : {
1548 0 : syndromes[0] = GF16_ADD(syndromes[0], GF16_MUL0(buffer[14], 144));
1549 0 : syndromes[1] = GF16_ADD(syndromes[1], GF16_MUL0(buffer[14], 208));
1550 0 : syndromes[2] = GF16_ADD(syndromes[2], GF16_MUL0(buffer[14], 240));
1551 0 : syndromes[3] = GF16_ADD(syndromes[3], GF16_MUL0(buffer[14], 224));
1552 0 : syndromes[4] = GF16_ADD(syndromes[4], GF16_MUL0(buffer[14], 112));
1553 0 : syndromes[5] = GF16_ADD(syndromes[5], GF16_MUL0(buffer[14], 160));
1554 : }
1555 :
1556 :
1557 0 : }
1558 :
1559 0 : FEC_STATIC void rs16_calculate_four_syndromes(LC3_UINT8 *syndromes, LC3_UINT8 *cw, LC3_INT32 cw_poly_deg)
1560 : {
1561 : LC3_INT32 i;
1562 : LC3_UINT8 buffer[15];
1563 :
1564 0 : assert(cw_poly_deg >= 12);
1565 :
1566 0 : for (i = 0; i <= cw_poly_deg; i++)
1567 : {
1568 0 : buffer[i] = cw[i];
1569 : }
1570 :
1571 0 : syndromes[0] = buffer[0];
1572 0 : syndromes[1] = buffer[0];
1573 0 : syndromes[2] = buffer[0];
1574 0 : syndromes[3] = buffer[0];
1575 :
1576 0 : syndromes[0] = GF16_ADD(syndromes[0], GF16_MUL0(buffer[1], 32));
1577 0 : syndromes[1] = GF16_ADD(syndromes[1], GF16_MUL0(buffer[1], 64));
1578 0 : syndromes[2] = GF16_ADD(syndromes[2], GF16_MUL0(buffer[1], 128));
1579 0 : syndromes[3] = GF16_ADD(syndromes[3], GF16_MUL0(buffer[1], 48));
1580 :
1581 0 : syndromes[0] = GF16_ADD(syndromes[0], GF16_MUL0(buffer[2], 64));
1582 0 : syndromes[1] = GF16_ADD(syndromes[1], GF16_MUL0(buffer[2], 48));
1583 0 : syndromes[2] = GF16_ADD(syndromes[2], GF16_MUL0(buffer[2], 192));
1584 0 : syndromes[3] = GF16_ADD(syndromes[3], GF16_MUL0(buffer[2], 80));
1585 :
1586 0 : syndromes[0] = GF16_ADD(syndromes[0], GF16_MUL0(buffer[3], 128));
1587 0 : syndromes[1] = GF16_ADD(syndromes[1], GF16_MUL0(buffer[3], 192));
1588 0 : syndromes[2] = GF16_ADD(syndromes[2], GF16_MUL0(buffer[3], 160));
1589 0 : syndromes[3] = GF16_ADD(syndromes[3], GF16_MUL0(buffer[3], 240));
1590 :
1591 0 : syndromes[0] = GF16_ADD(syndromes[0], GF16_MUL0(buffer[4], 48));
1592 0 : syndromes[1] = GF16_ADD(syndromes[1], GF16_MUL0(buffer[4], 80));
1593 0 : syndromes[2] = GF16_ADD(syndromes[2], GF16_MUL0(buffer[4], 240));
1594 0 : syndromes[3] = GF16_ADD(syndromes[3], GF16_MUL0(buffer[4], 32));
1595 :
1596 0 : syndromes[0] = GF16_ADD(syndromes[0], GF16_MUL0(buffer[5], 96));
1597 0 : syndromes[1] = GF16_ADD(syndromes[1], GF16_MUL0(buffer[5], 112));
1598 0 : syndromes[2] = GF16_ADD(syndromes[2], GF16_MUL0(buffer[5], 16));
1599 0 : syndromes[3] = GF16_ADD(syndromes[3], GF16_MUL0(buffer[5], 96));
1600 :
1601 0 : syndromes[0] = GF16_ADD(syndromes[0], GF16_MUL0(buffer[6], 192));
1602 0 : syndromes[1] = GF16_ADD(syndromes[1], GF16_MUL0(buffer[6], 240));
1603 0 : syndromes[2] = GF16_ADD(syndromes[2], GF16_MUL0(buffer[6], 128));
1604 0 : syndromes[3] = GF16_ADD(syndromes[3], GF16_MUL0(buffer[6], 160));
1605 :
1606 0 : syndromes[0] = GF16_ADD(syndromes[0], GF16_MUL0(buffer[7], 176));
1607 0 : syndromes[1] = GF16_ADD(syndromes[1], GF16_MUL0(buffer[7], 144));
1608 0 : syndromes[2] = GF16_ADD(syndromes[2], GF16_MUL0(buffer[7], 192));
1609 0 : syndromes[3] = GF16_ADD(syndromes[3], GF16_MUL0(buffer[7], 208));
1610 :
1611 0 : syndromes[0] = GF16_ADD(syndromes[0], GF16_MUL0(buffer[8], 80));
1612 0 : syndromes[1] = GF16_ADD(syndromes[1], GF16_MUL0(buffer[8], 32));
1613 0 : syndromes[2] = GF16_ADD(syndromes[2], GF16_MUL0(buffer[8], 160));
1614 0 : syndromes[3] = GF16_ADD(syndromes[3], GF16_MUL0(buffer[8], 64));
1615 :
1616 0 : syndromes[0] = GF16_ADD(syndromes[0], GF16_MUL0(buffer[9], 160));
1617 0 : syndromes[1] = GF16_ADD(syndromes[1], GF16_MUL0(buffer[9], 128));
1618 0 : syndromes[2] = GF16_ADD(syndromes[2], GF16_MUL0(buffer[9], 240));
1619 0 : syndromes[3] = GF16_ADD(syndromes[3], GF16_MUL0(buffer[9], 192));
1620 :
1621 0 : syndromes[0] = GF16_ADD(syndromes[0], GF16_MUL0(buffer[10], 112));
1622 0 : syndromes[1] = GF16_ADD(syndromes[1], GF16_MUL0(buffer[10], 96));
1623 0 : syndromes[2] = GF16_ADD(syndromes[2], GF16_MUL0(buffer[10], 16));
1624 0 : syndromes[3] = GF16_ADD(syndromes[3], GF16_MUL0(buffer[10], 112));
1625 :
1626 0 : syndromes[0] = GF16_ADD(syndromes[0], GF16_MUL0(buffer[11], 224));
1627 0 : syndromes[1] = GF16_ADD(syndromes[1], GF16_MUL0(buffer[11], 176));
1628 0 : syndromes[2] = GF16_ADD(syndromes[2], GF16_MUL0(buffer[11], 128));
1629 0 : syndromes[3] = GF16_ADD(syndromes[3], GF16_MUL0(buffer[11], 144));
1630 :
1631 0 : syndromes[0] = GF16_ADD(syndromes[0], GF16_MUL0(buffer[12], 240));
1632 0 : syndromes[1] = GF16_ADD(syndromes[1], GF16_MUL0(buffer[12], 160));
1633 0 : syndromes[2] = GF16_ADD(syndromes[2], GF16_MUL0(buffer[12], 192));
1634 0 : syndromes[3] = GF16_ADD(syndromes[3], GF16_MUL0(buffer[12], 128));
1635 :
1636 0 : if (cw_poly_deg >= 13)
1637 : {
1638 0 : syndromes[0] = GF16_ADD(syndromes[0], GF16_MUL0(buffer[13], 208));
1639 0 : syndromes[1] = GF16_ADD(syndromes[1], GF16_MUL0(buffer[13], 224));
1640 0 : syndromes[2] = GF16_ADD(syndromes[2], GF16_MUL0(buffer[13], 160));
1641 0 : syndromes[3] = GF16_ADD(syndromes[3], GF16_MUL0(buffer[13], 176));
1642 : }
1643 :
1644 0 : if (cw_poly_deg >= 14)
1645 : {
1646 0 : syndromes[0] = GF16_ADD(syndromes[0], GF16_MUL0(buffer[14], 144));
1647 0 : syndromes[1] = GF16_ADD(syndromes[1], GF16_MUL0(buffer[14], 208));
1648 0 : syndromes[2] = GF16_ADD(syndromes[2], GF16_MUL0(buffer[14], 240));
1649 0 : syndromes[3] = GF16_ADD(syndromes[3], GF16_MUL0(buffer[14], 224));
1650 : }
1651 :
1652 :
1653 0 : }
1654 :
1655 0 : FEC_STATIC void rs16_calculate_two_syndromes(LC3_UINT8 *syndromes, LC3_UINT8 *cw, LC3_INT32 cw_poly_deg)
1656 : {
1657 : LC3_INT32 i;
1658 : LC3_UINT8 buffer[15];
1659 :
1660 0 : assert(cw_poly_deg >= 12);
1661 :
1662 0 : for (i = 0; i <= cw_poly_deg; i++)
1663 : {
1664 0 : buffer[i] = cw[i];
1665 : }
1666 :
1667 0 : syndromes[0] = buffer[0];
1668 0 : syndromes[1] = buffer[0];
1669 :
1670 0 : syndromes[0] = GF16_ADD(syndromes[0], GF16_MUL0(buffer[1], 32));
1671 0 : syndromes[1] = GF16_ADD(syndromes[1], GF16_MUL0(buffer[1], 64));
1672 :
1673 0 : syndromes[0] = GF16_ADD(syndromes[0], GF16_MUL0(buffer[2], 64));
1674 0 : syndromes[1] = GF16_ADD(syndromes[1], GF16_MUL0(buffer[2], 48));
1675 :
1676 0 : syndromes[0] = GF16_ADD(syndromes[0], GF16_MUL0(buffer[3], 128));
1677 0 : syndromes[1] = GF16_ADD(syndromes[1], GF16_MUL0(buffer[3], 192));
1678 :
1679 0 : syndromes[0] = GF16_ADD(syndromes[0], GF16_MUL0(buffer[4], 48));
1680 0 : syndromes[1] = GF16_ADD(syndromes[1], GF16_MUL0(buffer[4], 80));
1681 :
1682 0 : syndromes[0] = GF16_ADD(syndromes[0], GF16_MUL0(buffer[5], 96));
1683 0 : syndromes[1] = GF16_ADD(syndromes[1], GF16_MUL0(buffer[5], 112));
1684 :
1685 0 : syndromes[0] = GF16_ADD(syndromes[0], GF16_MUL0(buffer[6], 192));
1686 0 : syndromes[1] = GF16_ADD(syndromes[1], GF16_MUL0(buffer[6], 240));
1687 :
1688 0 : syndromes[0] = GF16_ADD(syndromes[0], GF16_MUL0(buffer[7], 176));
1689 0 : syndromes[1] = GF16_ADD(syndromes[1], GF16_MUL0(buffer[7], 144));
1690 :
1691 0 : syndromes[0] = GF16_ADD(syndromes[0], GF16_MUL0(buffer[8], 80));
1692 0 : syndromes[1] = GF16_ADD(syndromes[1], GF16_MUL0(buffer[8], 32));
1693 :
1694 0 : syndromes[0] = GF16_ADD(syndromes[0], GF16_MUL0(buffer[9], 160));
1695 0 : syndromes[1] = GF16_ADD(syndromes[1], GF16_MUL0(buffer[9], 128));
1696 :
1697 0 : syndromes[0] = GF16_ADD(syndromes[0], GF16_MUL0(buffer[10], 112));
1698 0 : syndromes[1] = GF16_ADD(syndromes[1], GF16_MUL0(buffer[10], 96));
1699 :
1700 0 : syndromes[0] = GF16_ADD(syndromes[0], GF16_MUL0(buffer[11], 224));
1701 0 : syndromes[1] = GF16_ADD(syndromes[1], GF16_MUL0(buffer[11], 176));
1702 :
1703 0 : syndromes[0] = GF16_ADD(syndromes[0], GF16_MUL0(buffer[12], 240));
1704 0 : syndromes[1] = GF16_ADD(syndromes[1], GF16_MUL0(buffer[12], 160));
1705 :
1706 0 : if (cw_poly_deg >= 13)
1707 : {
1708 0 : syndromes[0] = GF16_ADD(syndromes[0], GF16_MUL0(buffer[13], 208));
1709 0 : syndromes[1] = GF16_ADD(syndromes[1], GF16_MUL0(buffer[13], 224));
1710 : }
1711 :
1712 0 : if (cw_poly_deg >= 14)
1713 : {
1714 0 : syndromes[0] = GF16_ADD(syndromes[0], GF16_MUL0(buffer[14], 144));
1715 0 : syndromes[1] = GF16_ADD(syndromes[1], GF16_MUL0(buffer[14], 208));
1716 : }
1717 :
1718 :
1719 0 : }
1720 :
1721 0 : FEC_STATIC LC3_INT8 rs16_calculate_elp(LC3_UINT8 *elp, LC3_UINT8 *syndromes, LC3_INT16 t)
1722 : /* calculates error locator polynomial vie Petterson's algorithm */
1723 : {
1724 : LC3_INT8 ret;
1725 : LC3_UINT8 det, det_inv, aux, all_s, *s;
1726 : LC3_UINT8 s22, s33, s44, s13, s14, s15;
1727 : LC3_UINT8 s23, s24, s25, s34, s35;
1728 : LC3_UINT8 a, b, c, d, e, f;
1729 :
1730 0 : ret = 0;
1731 0 : all_s = 0;
1732 0 : s = syndromes;
1733 0 : elp[0] = 1;
1734 0 : memset(elp + 1, 0, 3);
1735 :
1736 0 : switch (t)
1737 : {
1738 0 : case 3:
1739 : {
1740 : /* check for errors */
1741 0 : all_s = s[0] | s[1] | s[2] | s[3] | s[4] | s[5];
1742 :
1743 0 : if (all_s == 0)
1744 : {
1745 0 : break;
1746 : }
1747 :
1748 : /* assume 3 errors */
1749 0 : s22 = GF16_MUL(s[1], s[1]);
1750 0 : s33 = GF16_MUL(s[2], s[2]);
1751 0 : s44 = GF16_MUL(s[3], s[3]);
1752 0 : s13 = GF16_MUL(s[0], s[2]);
1753 :
1754 0 : det = GF16_ADD(GF16_ADD(GF16_MUL(s13, s[4]), GF16_MUL(s44, s[0])),
1755 : GF16_ADD(GF16_MUL(s22, s[4]), GF16_MUL(s33, s[2])));
1756 :
1757 0 : if (det)
1758 : {
1759 0 : det_inv = gf16_inv_table[det] << 4;
1760 :
1761 0 : s14 = GF16_MUL(s[0], s[3]);
1762 0 : s15 = GF16_MUL(s[0], s[4]);
1763 :
1764 0 : s23 = GF16_MUL(s[1], s[2]);
1765 0 : s24 = GF16_MUL(s[1], s[3]);
1766 0 : s25 = GF16_MUL(s[1], s[4]);
1767 :
1768 0 : s34 = GF16_MUL(s[2], s[3]);
1769 0 : s35 = GF16_MUL(s[2], s[4]);
1770 :
1771 0 : a = GF16_ADD(s35, s44) << 4;
1772 0 : b = GF16_ADD(s15, s33) << 4;
1773 0 : c = GF16_ADD(s13, s22) << 4;
1774 0 : d = GF16_ADD(s34, s25) << 4;
1775 0 : e = GF16_ADD(s23, s14) << 4;
1776 0 : f = GF16_ADD(s24, s33) << 4;
1777 :
1778 0 : aux = GF16_ADD(GF16_ADD(GF16_MUL0(a, s[3]), GF16_MUL0(d, s[4])), GF16_MUL0(f, s[5]));
1779 0 : elp[3] = GF16_MUL0(aux, det_inv);
1780 :
1781 0 : aux = GF16_ADD(GF16_ADD(GF16_MUL0(d, s[3]), GF16_MUL0(b, s[4])), GF16_MUL0(e, s[5]));
1782 0 : elp[2] = GF16_MUL0(aux, det_inv);
1783 :
1784 0 : aux = GF16_ADD(GF16_ADD(GF16_MUL0(f, s[3]), GF16_MUL0(e, s[4])), GF16_MUL0(c, s[5]));
1785 0 : elp[1] = GF16_MUL0(aux, det_inv);
1786 :
1787 0 : if (elp[3] == 0)
1788 : {
1789 0 : ret = t+1;
1790 : }
1791 : else
1792 : {
1793 0 : ret = 3;
1794 : }
1795 0 : break;
1796 : }
1797 :
1798 : /* assume two errors */
1799 0 : det = GF16_ADD(GF16_MUL(syndromes[0], syndromes[2]), GF16_MUL(syndromes[1], syndromes[1]));
1800 :
1801 0 : if (det)
1802 : {
1803 0 : det_inv = gf16_inv_table[det] << 4;
1804 :
1805 0 : aux = GF16_ADD(GF16_MUL(syndromes[1], syndromes[2]), GF16_MUL(syndromes[0], syndromes[3]));
1806 0 : elp[1] = GF16_MUL0(aux, det_inv);
1807 :
1808 0 : aux = GF16_ADD(GF16_MUL(syndromes[2], syndromes[2]), GF16_MUL(syndromes[1], syndromes[3]));
1809 0 : elp[2] = GF16_MUL0(aux, det_inv);
1810 :
1811 : /* check remaining LSF relations */
1812 0 : aux = GF16_ADD(GF16_ADD(GF16_MUL(elp[2], s[2]), GF16_MUL(elp[1], s[3])), s[4])
1813 0 : | GF16_ADD(GF16_ADD(GF16_MUL(elp[2], s[3]), GF16_MUL(elp[1], s[4])), s[5]);
1814 :
1815 0 : aux |= elp[2] == 0;
1816 :
1817 0 : if (aux != 0)
1818 : {
1819 0 : ret = t + 1;
1820 : }
1821 : else
1822 : {
1823 0 : ret = 2;
1824 : }
1825 0 : break;
1826 : }
1827 :
1828 : /* assume one error */
1829 0 : if (syndromes[0] != 0)
1830 : {
1831 0 : elp[1] = GF16_MUL(syndromes[1], gf16_inv_table[syndromes[0]]);
1832 :
1833 : /* check remaining LSF relations */
1834 0 : aux = GF16_ADD(GF16_MUL(elp[1], s[1]), s[2])
1835 0 : | GF16_ADD(GF16_MUL(elp[1], s[2]), s[3])
1836 0 : | GF16_ADD(GF16_MUL(elp[1], s[3]), s[4])
1837 0 : | GF16_ADD(GF16_MUL(elp[1], s[4]), s[5]);
1838 :
1839 0 : aux |= elp[1] == 0;
1840 :
1841 0 : if (aux != 0)
1842 : {
1843 0 : ret = t + 1;
1844 : }
1845 : else
1846 : {
1847 0 : ret = 1;
1848 : }
1849 0 : break;
1850 : }
1851 :
1852 0 : ret = t + 1;
1853 0 : break;
1854 : }
1855 0 : case 2:
1856 : {
1857 0 : all_s = s[0] | s[1] | s[2] | s[3];
1858 :
1859 0 : if (all_s == 0)
1860 : {
1861 0 : break;
1862 : }
1863 :
1864 : /* assume two errors */
1865 0 : det = GF16_ADD(GF16_MUL(syndromes[0], syndromes[2]), GF16_MUL(syndromes[1], syndromes[1]));
1866 :
1867 0 : if (det)
1868 : {
1869 0 : det_inv = gf16_inv_table[det] << 4;
1870 :
1871 0 : aux = GF16_ADD(GF16_MUL(syndromes[1], syndromes[2]), GF16_MUL(syndromes[0], syndromes[3]));
1872 0 : elp[1] = GF16_MUL0(aux, det_inv);
1873 :
1874 0 : aux = GF16_ADD(GF16_MUL(syndromes[2], syndromes[2]), GF16_MUL(syndromes[1], syndromes[3]));
1875 0 : elp[2] = GF16_MUL0(aux, det_inv);
1876 :
1877 0 : if (elp[2] == 0)
1878 : {
1879 0 : ret = t + 1;
1880 : }
1881 : else
1882 : {
1883 0 : ret = 2;
1884 : }
1885 0 : break;
1886 : }
1887 :
1888 : /* assume one error */
1889 0 : if (syndromes[0] != 0)
1890 : {
1891 0 : elp[1] = GF16_MUL(syndromes[1], gf16_inv_table[syndromes[0]]);
1892 :
1893 : /* check remaining LSF relation */
1894 0 : aux = GF16_ADD(GF16_MUL(elp[1], s[1]), s[2]) | GF16_ADD(GF16_MUL(elp[1], s[2]), s[3]);
1895 0 : aux |= elp[1] == 0;
1896 :
1897 0 : if (aux != 0)
1898 : {
1899 0 : ret = t + 1;
1900 : }
1901 : else
1902 : {
1903 0 : ret = 1;
1904 : }
1905 0 : break;
1906 : }
1907 :
1908 0 : ret = t + 1;
1909 0 : break;
1910 : }
1911 0 : case 1:
1912 : {
1913 0 : all_s = s[0] | s[1];
1914 :
1915 0 : if (all_s == 0)
1916 : {
1917 0 : break;
1918 : }
1919 :
1920 0 : if (syndromes[0] != 0)
1921 : {
1922 0 : elp[1] = GF16_MUL(syndromes[1], gf16_inv_table[syndromes[0]]);
1923 0 : if (elp[1] == 0)
1924 : {
1925 0 : ret = t + 1;
1926 : }
1927 : else
1928 : {
1929 0 : ret = 1;
1930 : }
1931 0 : break;
1932 : }
1933 :
1934 0 : ret = t + 1;
1935 0 : break;
1936 : }
1937 0 : default: assert(0 && "calculating elp of this degree not implemented");
1938 : }
1939 :
1940 :
1941 0 : return ret;
1942 : }
1943 :
1944 0 : FEC_STATIC LC3_INT16 rs16_factorize_elp(LC3_UINT8 *err_pos, LC3_UINT8 *elp, LC3_INT16 deg_elp, LC3_INT16 max_pos)
1945 : {
1946 : LC3_UINT8 beta, gamma;
1947 : LC3_INT16 zeros, err_pos0, err_pos1, err_pos2, ret;
1948 :
1949 0 : beta = 0;
1950 0 : gamma = 0;
1951 0 : zeros = 0;
1952 0 : ret = 0;
1953 :
1954 0 : switch (deg_elp)
1955 : {
1956 0 : case 0: break;
1957 :
1958 0 : case 1:
1959 0 : err_pos0 = gf16_log_g[elp[1]];
1960 0 : if (err_pos0 > max_pos)
1961 : {
1962 0 : ret = 1;
1963 0 : break;
1964 : }
1965 :
1966 0 : err_pos[0] = (LC3_UINT8)err_pos0;
1967 0 : break;
1968 :
1969 0 : case 2:
1970 0 : zeros = rs16_elp_deg2_table[elp[1] | (elp[2] << 4)];
1971 0 : if (zeros == 0)
1972 : {
1973 :
1974 0 : return 1;
1975 : }
1976 :
1977 0 : err_pos0 = zeros & 15;
1978 0 : err_pos1 = (zeros >> 4) & 15;
1979 :
1980 0 : if (err_pos0 > max_pos || err_pos1 > max_pos)
1981 : {
1982 0 : ret = 1;
1983 0 : break;
1984 : }
1985 :
1986 0 : err_pos[0] = (LC3_UINT8)err_pos0;
1987 0 : err_pos[1] = (LC3_UINT8)err_pos1;
1988 0 : break;
1989 :
1990 0 : case 3:
1991 : /* beta = a*a + b, gamma = a*b + c */
1992 0 : beta = GF16_ADD(GF16_MUL(elp[1], elp[1]), elp[2]);
1993 0 : gamma = GF16_ADD(GF16_MUL(elp[1], elp[2]), elp[3]);
1994 0 : zeros = rs16_elp_deg3_table[beta | gamma << 4];
1995 :
1996 0 : if (zeros == 0)
1997 : /* elp does not split over GF(16) or has multiple zeros */
1998 : {
1999 0 : ret = 1;
2000 0 : break;
2001 : }
2002 :
2003 : /* remove shift from zeros */
2004 0 : err_pos0 = GF16_ADD(zeros & 15, elp[1]);
2005 0 : err_pos1 = GF16_ADD((zeros >> 4) & 15, elp[1]);
2006 0 : err_pos2 = GF16_ADD((zeros >> 8) & 15, elp[1]);
2007 :
2008 0 : if (err_pos0 == 0 || err_pos1 == 0 || err_pos2 == 0)
2009 : {
2010 :
2011 0 : return 1;
2012 : }
2013 :
2014 0 : err_pos0 = gf16_log_g[err_pos0];
2015 0 : err_pos1 = gf16_log_g[err_pos1];
2016 0 : err_pos2 = gf16_log_g[err_pos2];
2017 :
2018 0 : if (err_pos0 > max_pos || err_pos1 > max_pos || err_pos2 > max_pos)
2019 : {
2020 0 : ret = 1;
2021 0 : break;
2022 : }
2023 :
2024 0 : err_pos[0] = (LC3_UINT8)err_pos0;
2025 0 : err_pos[1] = (LC3_UINT8)err_pos1;
2026 0 : err_pos[2] = (LC3_UINT8)err_pos2;
2027 :
2028 0 : break;
2029 :
2030 0 : default: assert(0 && "invalid degree in rs16_error_locator");
2031 : }
2032 :
2033 :
2034 0 : return ret;
2035 : }
2036 :
2037 0 : FEC_STATIC void rs16_calculate_errors(LC3_UINT8 *err_symb, LC3_UINT8 *err_pos, LC3_UINT8 *syndromes, LC3_INT8 deg_elp, LC3_INT8 t)
2038 : {
2039 : LC3_UINT8 det_inv;
2040 : LC3_UINT8 x0, x1, x2;
2041 : LC3_UINT8 x0sq, x1sq, x2sq;
2042 : LC3_UINT8 c0, c1, c2;
2043 : LC3_UINT8 s0, s1, s2;
2044 : LC3_UINT8 tmp;
2045 :
2046 : UNUSED(t);
2047 :
2048 0 : assert(deg_elp <= t);
2049 :
2050 0 : switch (deg_elp)
2051 : {
2052 0 : case 0: break;
2053 :
2054 0 : case 1:
2055 0 : err_symb[0] = GF16_MUL(gf16_g_pow[15 - err_pos[0]], syndromes[0]);
2056 :
2057 0 : break;
2058 :
2059 0 : case 2:
2060 0 : s0 = (LC3_UINT8) (syndromes[0] << 4);
2061 0 : s1 = (LC3_UINT8) (syndromes[1] << 4);
2062 :
2063 0 : x0 = gf16_g_pow[err_pos[0]];
2064 0 : x1 = gf16_g_pow[err_pos[1]];
2065 :
2066 0 : x0sq = GF16_MUL(x0, x0);
2067 0 : x1sq = GF16_MUL(x1, x1);
2068 :
2069 0 : tmp = GF16_ADD(GF16_MUL(x0sq, x1), GF16_MUL(x1sq, x0));
2070 0 : det_inv = gf16_inv_table[tmp] << 4;
2071 :
2072 0 : tmp = GF16_ADD(GF16_MUL0(x1sq, s0), GF16_MUL0(x1, s1));
2073 0 : err_symb[0] = GF16_MUL0(tmp, det_inv);
2074 :
2075 0 : tmp = GF16_ADD(GF16_MUL0(x0sq, s0), GF16_MUL0(x0, s1));
2076 0 : err_symb[1] = GF16_MUL0(tmp, det_inv);
2077 :
2078 0 : break;
2079 :
2080 0 : case 3:
2081 0 : s0 = syndromes[0] << 4;
2082 0 : s1 = syndromes[1] << 4;
2083 0 : s2 = syndromes[2] << 4;
2084 :
2085 0 : x0 = gf16_g_pow[err_pos[0]];
2086 0 : x1 = gf16_g_pow[err_pos[1]];
2087 0 : x2 = gf16_g_pow[err_pos[2]];
2088 :
2089 0 : x0sq = GF16_MUL(x0, x0);
2090 0 : x1sq = GF16_MUL(x1, x1);
2091 0 : x2sq = GF16_MUL(x2, x2);
2092 :
2093 0 : tmp = GF16_MUL(GF16_ADD(x1, x0), GF16_ADD(x2, x0));
2094 0 : tmp = GF16_MUL(GF16_ADD(x2, x1), tmp);
2095 0 : det_inv = gf16_inv_table[tmp] << 4;
2096 :
2097 0 : c0 = GF16_ADD(GF16_MUL(x1, x2sq), GF16_MUL(x2, x1sq));
2098 0 : c1 = GF16_ADD(x2sq, x1sq);
2099 0 : c2 = GF16_ADD(x2, x1);
2100 :
2101 0 : err_symb[0] = GF16_ADD(GF16_ADD(GF16_MUL0(c0, s0), GF16_MUL0(c1, s1)), GF16_MUL0(c2, s2));
2102 :
2103 0 : c0 = GF16_ADD(GF16_MUL(x0, x2sq), GF16_MUL(x2, x0sq));
2104 0 : c1 = GF16_ADD(x2sq, x0sq);
2105 0 : c2 = GF16_ADD(x2, x0);
2106 :
2107 0 : err_symb[1] = GF16_ADD(GF16_ADD(GF16_MUL0(c0, s0), GF16_MUL0(c1, s1)), GF16_MUL0(c2, s2));
2108 :
2109 0 : c0 = GF16_ADD(GF16_MUL(x0, x1sq), GF16_MUL(x1, x0sq));
2110 0 : c1 = GF16_ADD(x1sq, x0sq);
2111 0 : c2 = GF16_ADD(x1, x0);
2112 :
2113 0 : err_symb[2] = GF16_ADD(GF16_ADD(GF16_MUL0(c0, s0), GF16_MUL0(c1, s1)), GF16_MUL0(c2, s2));
2114 :
2115 0 : tmp = GF16_MUL0(err_symb[0], det_inv);
2116 0 : err_symb[0] = GF16_MUL(tmp, gf16_inv_table[x0]);
2117 :
2118 0 : tmp = GF16_MUL0(err_symb[1], det_inv);
2119 0 : err_symb[1] = GF16_MUL(tmp, gf16_inv_table[x1]);
2120 :
2121 0 : tmp = GF16_MUL0(err_symb[2], det_inv);
2122 0 : err_symb[2] = GF16_MUL(tmp, gf16_inv_table[x2]);
2123 :
2124 0 : break;
2125 :
2126 0 : default: assert(0 && "method not implemented\n"); break;
2127 : }
2128 :
2129 :
2130 0 : }
2131 :
2132 : /* hash functions for data validation */
2133 :
2134 : /* hamming distance 4 */
2135 : static const LC3_UINT32 crc14_mask[16] = {0, 17989, 35978, 51919, 71956, 89937, 103838, 119771,
2136 : 143912, 160877, 179874, 194791, 207676, 224633, 239542, 254451};
2137 :
2138 : /* hamming distance 4 */
2139 : static const LC3_UINT32 crc22_mask[16] = {0, 4788009, 9576018, 14356859, 19152036, 23933837, 28713718, 33500639,
2140 : 33650273, 38304072, 43214899, 47867674, 52775621, 57427436, 62346391, 67001278};
2141 :
2142 0 : FEC_STATIC LC3_INT16 crc1(LC3_UINT8 *data, LC3_INT16 data_size, LC3_INT16 epmr, LC3_UINT8 *hash_val, LC3_INT16 hash_size, LC3_INT16 check)
2143 : {
2144 : LC3_UINT32 const *mask;
2145 : LC3_INT32 shift, i, fail;
2146 : LC3_UINT32 rem;
2147 :
2148 0 : fail = 0;
2149 0 : rem = 0;
2150 :
2151 0 : assert(hash_size > 0);
2152 :
2153 0 : switch (hash_size)
2154 : {
2155 0 : case 2:
2156 0 : shift = 14;
2157 0 : mask = crc14_mask;
2158 0 : break;
2159 0 : case 3:
2160 0 : shift = 22;
2161 0 : mask = crc22_mask;
2162 0 : break;
2163 0 : default:
2164 0 : shift = 0;
2165 0 : mask = 0;
2166 0 : assert(0 && "crc hash size not implemented");
2167 : }
2168 :
2169 : /* data array contains 4-bit words */
2170 0 : for (i = data_size - 1; i >= 0; i--)
2171 : {
2172 0 : rem = (rem << 4) ^ data[i];
2173 0 : rem ^= mask[(rem >> shift) & 15];
2174 : }
2175 :
2176 0 : rem = (rem << 4) ^ (epmr << 2);
2177 0 : rem ^= mask[(rem >> shift) & 15];
2178 :
2179 0 : for (i = 0; i < 2 * hash_size - 1; i++)
2180 : {
2181 0 : rem <<= 4;
2182 0 : rem ^= mask[(rem >> shift) & 15];
2183 : }
2184 :
2185 0 : rem ^= ((LC3_UINT32) epmr) << shift;
2186 :
2187 0 : if (check)
2188 : {
2189 : /* test hash value */
2190 0 : for (i = 0; i < 2 * hash_size; i++)
2191 : {
2192 0 : fail |= hash_val[i] ^ ((rem >> (4*i)) & 15);
2193 : }
2194 : }
2195 : else
2196 : {
2197 : /* write hash value */
2198 0 : for (i = 0; i < 2 * hash_size; i++)
2199 : {
2200 0 : hash_val[i] = (LC3_UINT8) ((rem >> (4*i)) & 15);
2201 : }
2202 : }
2203 :
2204 :
2205 0 : return fail;
2206 : }
2207 :
2208 : /* hamming distance = 4 */
2209 : static const LC3_UINT32 crc16_mask[16] = {0, 107243, 190269, 214486, 289937, 380538, 428972, 469319,
2210 : 579874, 621513, 671263, 761076, 832947, 857944, 938638, 1044581};
2211 :
2212 0 : FEC_STATIC LC3_INT16 crc2(LC3_UINT8 *data, LC3_INT16 data_size, LC3_UINT8 *hash_val, LC3_INT16 hash_size, LC3_INT16 check)
2213 : {
2214 : LC3_UINT32 const *mask;
2215 : LC3_INT32 shift, i, fail;
2216 : LC3_UINT32 rem;
2217 :
2218 0 : fail = 0;
2219 0 : rem = 0;
2220 :
2221 0 : assert(hash_size > 0);
2222 :
2223 0 : switch (hash_size)
2224 : {
2225 0 : case 2:
2226 0 : shift = 16;
2227 0 : mask = crc16_mask;
2228 0 : break;
2229 0 : default:
2230 0 : shift = 0;
2231 0 : mask = 0;
2232 0 : assert(0 && "crc hash size not implemented");
2233 : }
2234 :
2235 : /* data array contains 4-bit words */
2236 0 : for (i = data_size - 1; i >= 0; i--)
2237 : {
2238 0 : rem = (rem << 4) ^ data[i];
2239 0 : rem ^= mask[(rem >> shift) & 15];
2240 : }
2241 :
2242 0 : for (i = 0; i < 2 * hash_size; i++)
2243 : {
2244 0 : rem <<= 4;
2245 0 : rem ^= mask[(rem >> shift) & 15];
2246 : }
2247 :
2248 0 : if (check)
2249 : {
2250 : /* test hash value */
2251 0 : for (i = 0; i < 2 * hash_size; i++)
2252 : {
2253 0 : fail |= hash_val[i] ^ ((rem >> (4*i)) & 15);
2254 : }
2255 : }
2256 : else
2257 : {
2258 : /* write hash value */
2259 0 : for (i = 0; i < 2 * hash_size; i++)
2260 : {
2261 0 : hash_val[i] = (LC3_UINT8) ((rem >> (4*i)) & 15);
2262 : }
2263 : }
2264 :
2265 :
2266 0 : return fail;
2267 : }
2268 :
2269 : /* simple float implementation */
2270 0 : FEC_STATIC simple_float simple_float_mul(simple_float op1, simple_float op2)
2271 : {
2272 : simple_float rop;
2273 : LC3_INT32 aux;
2274 :
2275 0 : aux = (op1.mantissa * op2.mantissa) >> 14;
2276 0 : rop.exponent = op1.exponent + op2.exponent;
2277 0 : if (aux & 32768L)
2278 : {
2279 0 : aux >>= 1;
2280 0 : rop.exponent ++;
2281 : }
2282 0 : rop.mantissa = (LC3_INT16) aux;
2283 :
2284 :
2285 0 : return rop;
2286 : }
2287 :
2288 : /* Auxiliary */
2289 :
2290 0 : FEC_STATIC LC3_INT16 simple_float_cmp(simple_float op1, simple_float op2)
2291 : /* returns 1 if op1 > op2, 0 if op1 = op2, and -1 if op1 < op2 */
2292 : {
2293 : LC3_INT16 rval;
2294 : LC3_INT16 mdiff;
2295 : LC3_INT16 ediff;
2296 :
2297 0 : rval = 0;
2298 :
2299 0 : ediff = op1.exponent - op2.exponent;
2300 0 : mdiff = (LC3_INT16) op1.mantissa - (LC3_INT16) op2.mantissa;
2301 :
2302 0 : if (ediff == 0)
2303 : {
2304 0 : if (mdiff > 0)
2305 : {
2306 0 : rval = 1;
2307 : }
2308 0 : if (mdiff < 0)
2309 : {
2310 0 : rval = -1;
2311 : }
2312 : }
2313 : else
2314 : {
2315 0 : if (ediff > 0)
2316 : {
2317 0 : rval = 1;
2318 : }
2319 0 : if (ediff < 0)
2320 : {
2321 0 : rval = -1;
2322 : }
2323 : }
2324 :
2325 :
2326 0 : return rval;
2327 : }
2328 :
|