Line data Source code
1 : /******************************************************************************
2 : * ETSI TS 103 634 V1.6.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 333838 : 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 333838 : if (fec_mode == 3)
255 : {
256 0 : n_pccw = (LC3_INT16) (0.080447761194030 * slot_bytes - 1.791044776119394 + 0.5);
257 : }
258 333838 : 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 333838 : n_pccw = 0;
265 : }
266 :
267 333838 : if (ccc_flag == 1 || slot_bytes < 80)
268 : {
269 45685 : n_pccw = 0;
270 : }
271 :
272 333838 : 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 667676 : FEC_STATIC LC3_INT16 get_n_codewords(LC3_INT16 slot_bytes)
296 : {
297 667676 : 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 333838 : 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 333838 : n_codewords = get_n_codewords(slot_bytes);
313 :
314 333838 : assert(n_codewords == (2 * slot_bytes + RS16_CW_LEN_MAX - 1) / RS16_CW_LEN_MAX);
315 333838 : payload_size = slot_bytes;
316 :
317 333838 : 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 333838 : return payload_size;
345 : }
346 :
347 333838 : 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 333838 : n_codewords = get_n_codewords(slot_bytes);
354 :
355 333838 : assert(n_codewords == (2 * slot_bytes + RS16_CW_LEN_MAX - 1) / RS16_CW_LEN_MAX);
356 :
357 333838 : pc_split = - 2*n_pccw*(fec_mode - 1);
358 :
359 333838 : if (fec_mode == 1 || slot_bytes < 80)
360 : {
361 45685 : pc_split = 0;
362 : }
363 : else
364 : {
365 288153 : for (i = 0; i < n_pccw; i++)
366 : {
367 0 : pc_split += (2 * slot_bytes + i) / n_codewords;
368 : }
369 : }
370 :
371 :
372 :
373 333838 : 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 : (void)tmp;
509 : }
510 :
511 : /* data preproc: re-ordering and hash extension */
512 0 : pc_split = fec_get_n_pc(mode, n_pccw, slot_bytes);
513 :
514 0 : dw_offset = fec_data_preproc(mode, epmr, iobuf, cw_buf, data_bytes, slot_bytes, pc_split);
515 :
516 : /* encoding of first data word*/
517 0 : hd = hamming_distance_by_mode0[mode];
518 0 : redundancy_nibbles = hd - 1;
519 0 : codeword_length = get_codeword_length(n_codewords, 2 * slot_bytes, 0);
520 :
521 0 : assert(codeword_length == (2 * slot_bytes - 1) / n_codewords + 1);
522 :
523 0 : for (j = redundancy_nibbles; j < codeword_length; (j++, dw_offset++))
524 : {
525 0 : cw_buf[j] = cw_buf[dw_offset];
526 : }
527 :
528 0 : rs16_enc(cw_buf, codeword_length, hd, mode, 1);
529 :
530 0 : cw_offset += codeword_length;
531 :
532 : /* encoding of remaining data words */
533 0 : hd = hamming_distance_by_mode1[mode];
534 0 : redundancy_nibbles = hd - 1;
535 :
536 0 : for (i = 1; i < n_codewords; i++)
537 : {
538 0 : codeword_length = get_codeword_length(n_codewords, 2*slot_bytes, i);
539 :
540 0 : for (j = redundancy_nibbles; j < codeword_length; (j++, dw_offset++))
541 : {
542 0 : cw_buf[cw_offset + j] = cw_buf[dw_offset];
543 : }
544 :
545 0 : rs16_enc(cw_buf + cw_offset, codeword_length, hd, mode, i < 6);
546 :
547 0 : cw_offset += codeword_length;
548 : }
549 :
550 0 : assert(cw_offset == 2 * slot_bytes && dw_offset == 2 * slot_bytes);
551 :
552 0 : fec_interleave_pack(iobuf, cw_buf, 2 * slot_bytes, n_codewords);
553 :
554 :
555 0 : }
556 :
557 0 : FEC_STATIC void rs16_enc(LC3_UINT8 *iobuf, LC3_INT16 codeword_length, LC3_INT16 hamming_distance, LC3_INT16 fec_mode,
558 : LC3_INT16 signal_mode)
559 : /* expects (data polynomial) * x^(hamming_distance - 1) in iobuf */
560 : {
561 : LC3_UINT8 const *gp;
562 : LC3_UINT8 shift_buffer[RS16_CW_LEN_MAX + 1], lc;
563 : LC3_INT32 i, j, deg_gp;
564 :
565 0 : memset(shift_buffer, 0, sizeof(shift_buffer));
566 0 : gp = rs16_gp_by_hd[hamming_distance];
567 0 : deg_gp = hamming_distance - 1;
568 :
569 0 : if (hamming_distance > 1)
570 : {
571 0 : assert(codeword_length > deg_gp);
572 :
573 : /* initialize redundancy part to zero */
574 0 : memset(iobuf, 0, deg_gp);
575 :
576 : /* initialize shift_buffer */
577 0 : memmove(shift_buffer + 1, iobuf + codeword_length - deg_gp, deg_gp);
578 :
579 : /* calculate remainder */
580 0 : for (i = codeword_length - deg_gp - 1; i >= 0; i--)
581 : {
582 0 : shift_buffer[0] = iobuf[i];
583 0 : lc = shift_buffer[deg_gp] << 4;
584 :
585 0 : for (j = deg_gp - 1; j >= 0; j--)
586 : {
587 0 : shift_buffer[j + 1] = GF16_ADD(shift_buffer[j], GF16_MUL0(gp[j], lc));
588 : }
589 : }
590 :
591 : /* add remainder to shifted data polynomial */
592 0 : for (i = 0; i < deg_gp; i++)
593 : {
594 0 : iobuf[i] = shift_buffer[i + 1];
595 : }
596 :
597 : /* add signaling polynomial */
598 0 : if (signal_mode)
599 : {
600 0 : assert(codeword_length > EP_SIG_POLY_DEG);
601 0 : for (i = 0; i <= EP_SIG_POLY_DEG; i++)
602 : {
603 0 : iobuf[i] = GF16_ADD(iobuf[i], sig_polys[fec_mode - 1][i]);
604 : }
605 : }
606 : }
607 :
608 :
609 0 : }
610 :
611 0 : FEC_STATIC void fec_interleave_pack(LC3_UINT8 *out, LC3_UINT8 *in, LC3_INT16 n_nibbles, LC3_INT16 n_codewords)
612 : {
613 : LC3_INT16 out_offset, cw_offset, codeword_length;
614 : LC3_INT32 i, j;
615 :
616 0 : out_offset = 0;
617 0 : cw_offset = 0;
618 :
619 : /* initialize output buffer to zero */
620 0 : memset(out, 0, n_nibbles >> 1);
621 :
622 : /* interleave and pack codewords */
623 0 : for (i = 0; i < n_codewords; i++)
624 : {
625 0 : codeword_length = get_codeword_length(n_codewords, n_nibbles, i);
626 :
627 0 : for (j = 0; j < codeword_length; j++)
628 : {
629 0 : out_offset = n_nibbles - 1 - j*n_codewords - i;
630 0 : out[out_offset >> 1] |= in[cw_offset] << ((out_offset & 1) << 2);
631 0 : cw_offset = cw_offset + 1;
632 : }
633 : }
634 :
635 :
636 0 : assert(cw_offset == n_nibbles);
637 0 : }
638 :
639 : /* Decoder */
640 0 : FEC_STATIC void fec_data_postproc(LC3_INT16 mode, LC3PLUS_EpModeRequest *epmr, LC3_UINT8 *obuf, LC3_INT16 data_bytes, LC3_UINT8 *cw_buf,
641 : LC3_INT16 slot_bytes, LC3_INT16 pc_split, LC3_INT32 *bfi)
642 : {
643 : LC3_INT16 i;
644 : LC3_INT16 n_crc1, n_crc2;
645 : LC3_INT16 cw_buf_len;
646 : LC3PLUS_EpModeRequest tmp_epmr;
647 :
648 0 : n_crc1 = crc1_bytes_by_mode1[mode];
649 0 : if (slot_bytes == 40)
650 : {
651 0 : n_crc1 = crc1_bytes_by_mode0[mode];
652 : }
653 :
654 0 : n_crc2 = 0;
655 0 : if (pc_split > 0)
656 : {
657 0 : n_crc2 = crc2_bytes_by_mode[mode];
658 : }
659 :
660 0 : assert(n_crc1 == (slot_bytes == 40 ? crc1_bytes_by_mode0[mode] : crc1_bytes_by_mode1[mode]));
661 0 : assert(n_crc2 == ((pc_split > 0) && (mode > 1) ? crc2_bytes_by_mode[mode] : 0));
662 :
663 0 : cw_buf_len = 2 * (data_bytes + n_crc1 + n_crc2);
664 :
665 0 : if ((mode - 1))
666 : {
667 : /* reverse bit-swap */
668 0 : dw0_bitswap(cw_buf, mode, slot_bytes);
669 0 : tmp_epmr = dw0_get_epmr(cw_buf, mode, slot_bytes);
670 :
671 0 : if (crc1(cw_buf + ((n_crc1 + n_crc2) << 1), ((data_bytes << 1) - pc_split), tmp_epmr, cw_buf, n_crc1, 1))
672 : {
673 0 : *bfi = 1;
674 :
675 0 : return;
676 : }
677 : else
678 : {
679 0 : *epmr = tmp_epmr;
680 : }
681 : }
682 :
683 0 : if (pc_split > 0 && *bfi != 2)
684 : {
685 0 : if (crc2(cw_buf + (((data_bytes + (n_crc1 + n_crc2)) << 1) - pc_split), pc_split,
686 0 : cw_buf + (n_crc1 << 1), n_crc2, 1))
687 : {
688 0 : *bfi = 2;
689 : }
690 : }
691 :
692 0 : for (i = 0; i < data_bytes; i++)
693 : {
694 0 : obuf[i] = (LC3_UINT8)(cw_buf[cw_buf_len - 2 * i - 1] | (cw_buf[cw_buf_len - 2 * i - 2] << 4));
695 : }
696 :
697 :
698 : }
699 :
700 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,
701 : LC3_INT32 *bfi, LC3_INT16 *be_bp_left, LC3_INT16 *be_bp_right, LC3_INT16 *n_pc, LC3_INT16 *m_fec)
702 : {
703 : LC3_UINT8 cw_buf[2 * FEC_SLOT_BYTES_MAX];
704 : LC3_UINT8 array_of_trust[MAX_LEN];
705 : LC3_INT16 i, j;
706 : LC3_INT16 cw_offset, dw_offset;
707 : LC3_INT16 n_codewords, redundancy_nibbles, codeword_length;
708 : LC3_INT16 mode, error_report;
709 : LC3_INT16 n_crc;
710 : LC3_INT16 first_bad_cw;
711 : LC3_INT16 pc_split;
712 :
713 : UNUSED(n_crc);
714 :
715 :
716 0 : if (*bfi == 1)
717 : {
718 0 : return ERROR_REPORT_BEC_MASK;
719 : }
720 :
721 0 : if (slot_bytes < FEC_SLOT_BYTES_MIN || slot_bytes > FEC_SLOT_BYTES_MAX)
722 : {
723 0 : *bfi = 1;
724 :
725 0 : return ERROR_REPORT_BEC_MASK;
726 : }
727 :
728 0 : if (ccc_flag == 0)
729 : {
730 0 : *be_bp_left = -1;
731 0 : *be_bp_right = -1;
732 : }
733 :
734 0 : n_codewords = get_n_codewords(slot_bytes);
735 :
736 : /* extract and de-interleave nibbles */
737 0 : fec_deinterleave_unpack(cw_buf, iobuf, 2 * slot_bytes, n_codewords);
738 :
739 : /* mode detection and error correction */
740 0 : mode = rs16_detect_and_correct(cw_buf, 2 * slot_bytes, n_codewords, epmr, &error_report, bfi, array_of_trust,
741 : ccc_flag, n_pccw);
742 :
743 : /* for normal slots the maximal number of bit errors is limited */
744 : #ifndef APPLY_MAX_ERRORS
745 0 : if (slot_bytes == 40 && mode > 0)
746 : {
747 0 : if ((error_report & ERROR_REPORT_BEC_MASK) > low_br_max_bit_errors_by_mode[mode])
748 : {
749 0 : error_report &= ERROR_REPORT_BEC_MASK;
750 0 : mode = -1;
751 0 : *bfi = 1;
752 : }
753 : else
754 : {
755 0 : if ((error_report & ERROR_REPORT_BEC_MASK) > low_br_max_bit_errors_by_mode[2])
756 : {
757 0 : error_report &= ~ERROR_REPORT_EP2_OK;
758 : }
759 0 : if ((error_report & ERROR_REPORT_BEC_MASK) > low_br_max_bit_errors_by_mode[3])
760 : {
761 0 : error_report &= ~ERROR_REPORT_EP3_OK;
762 : }
763 : }
764 : }
765 : #endif
766 :
767 0 : if (*bfi == 1)
768 : {
769 0 : *data_bytes = 0;
770 :
771 :
772 0 : return error_report;
773 : }
774 :
775 : /* initialization for decoding */
776 0 : *data_bytes = fec_get_data_size(mode, ccc_flag, slot_bytes);
777 0 : pc_split = fec_get_n_pc(mode, *n_pccw, slot_bytes);
778 0 : n_crc = get_total_crc_size(slot_bytes, mode, pc_split);
779 :
780 : /* decoding of first code word */
781 0 : redundancy_nibbles = hamming_distance_by_mode0[mode] - 1;
782 0 : codeword_length = get_codeword_length(n_codewords, slot_bytes + slot_bytes, 0);
783 :
784 0 : dw_offset = 0;
785 0 : cw_offset = 0;
786 :
787 0 : for (j = redundancy_nibbles; j < codeword_length; j++)
788 : {
789 0 : cw_buf[dw_offset++] = cw_buf[j];
790 : }
791 0 : cw_offset = cw_offset + codeword_length;
792 :
793 : /* decoding of remaining code words */
794 0 : redundancy_nibbles = hamming_distance_by_mode1[mode] - 1;
795 :
796 0 : for (i = 1; i < n_codewords; i++)
797 : {
798 0 : codeword_length = get_codeword_length(n_codewords, slot_bytes + slot_bytes, i);
799 :
800 0 : for (j = redundancy_nibbles; j < codeword_length; j++)
801 : {
802 0 : cw_buf[dw_offset++] = cw_buf[j + cw_offset];
803 : }
804 :
805 0 : cw_offset = cw_offset + codeword_length;
806 : }
807 :
808 : /* data postproc: hash validation and re-ordering */
809 :
810 0 : fec_data_postproc(mode, epmr, iobuf, *data_bytes, cw_buf, slot_bytes, pc_split, bfi);
811 :
812 0 : if (*bfi == 1)
813 : {
814 0 : *data_bytes = 0;
815 :
816 0 : error_report &= ERROR_REPORT_BEC_MASK;
817 :
818 :
819 0 : return error_report;
820 : }
821 :
822 0 : if (*bfi == 2)
823 : {
824 0 : first_bad_cw = 0;
825 0 : array_of_trust[*n_pccw] = 0;
826 0 : while (array_of_trust[first_bad_cw] != 0)
827 : {
828 0 : first_bad_cw = first_bad_cw + 1;
829 : }
830 0 : if (first_bad_cw == *n_pccw)
831 : {
832 : /* this is the case when CRC failed */
833 0 : *be_bp_left = 0;
834 : }
835 : else
836 : {
837 0 : *be_bp_left = 4*fec_get_n_pc(mode, first_bad_cw, slot_bytes);
838 : }
839 :
840 0 : for (i = *n_pccw - 1; i >= 0; i--)
841 : {
842 0 : if (!array_of_trust[i])
843 : {
844 0 : break;
845 : }
846 : }
847 0 : if (i < 0)
848 : {
849 0 : i = *n_pccw - 1;
850 : }
851 0 : *be_bp_right = 4*fec_get_n_pc(mode, i + 1, slot_bytes) - 1;
852 : }
853 :
854 0 : if (ccc_flag == 0)
855 : {
856 0 : *n_pc = pc_split;
857 0 : *m_fec = mode;
858 : }
859 :
860 :
861 0 : return error_report;
862 : }
863 :
864 0 : FEC_STATIC void fec_deinterleave_unpack(LC3_UINT8 *out, LC3_UINT8 *in, LC3_INT16 n_nibbles, LC3_INT16 n_codewords)
865 : {
866 : LC3_INT16 in_offset, out_offset, codeword_length;
867 : LC3_INT32 i, j;
868 :
869 0 : in_offset = 0;
870 0 : out_offset = 0;
871 :
872 : /* unpack nibbles in input buffer and deinterleave codewords */
873 0 : for (i = 0; i < n_codewords; i++)
874 : {
875 0 : codeword_length = get_codeword_length(n_codewords, n_nibbles, i);
876 0 : for (j = 0; j < codeword_length; (j++, out_offset++))
877 : {
878 0 : in_offset = n_nibbles - 1 - j*n_codewords - i;
879 0 : out[out_offset] = (in[in_offset >> 1] >> ((in_offset & 1) << 2)) & 15;
880 : }
881 : }
882 :
883 :
884 0 : assert(out_offset == n_nibbles);
885 :
886 0 : }
887 :
888 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,
889 : LC3_UINT8 *err_pos, LC3_UINT8 *err_symb, LC3_INT16 n_codewords, LC3_INT16 n_symb)
890 : {
891 : LC3_INT32 epmr_lowest_risk_exp;
892 : LC3_INT32 start, inc, i, n_candidates;
893 : LC3_INT32 first_codeword_length;
894 : LC3_INT32 mode_counter;
895 : LC3PLUS_EpModeRequest epmr;
896 :
897 0 : epmr_lowest_risk_exp = 0;
898 0 : first_codeword_length = get_codeword_length(n_codewords, n_symb, 0);
899 0 : start = 2;
900 0 : inc = 1;
901 0 : n_candidates = 0;
902 :
903 : /* test if first code word decodes in mode 0 or 1 without error correction */
904 0 : if ((syndromes[SYNDROME_IDX(0, 0)] | syndromes[SYNDROME_IDX(0, 0) + 1]) == 0 ||
905 0 : (syndromes[SYNDROME_IDX(1, 0)] | syndromes[SYNDROME_IDX(1, 0) + 1]) == 0)
906 : {
907 0 : epmr_lowest_risk_exp = risk_table_f[1][0].exponent;
908 : }
909 : /* test if first code word decodes in mode 2 or 3 with lower risk */
910 0 : if (deg_elp[DEG_ELP_IDX(2, 0)] <= t[2])
911 : {
912 0 : if (risk_table_f[2][deg_elp[DEG_ELP_IDX(2, 0)]].exponent <= -8)
913 : {
914 0 : n_candidates++;
915 0 : start = 2;
916 : }
917 : }
918 :
919 0 : if (deg_elp[DEG_ELP_IDX(3, 0)] <= t[3])
920 : {
921 0 : if (risk_table_f[3][deg_elp[DEG_ELP_IDX(3, 0)]].exponent <= -8)
922 : {
923 0 : n_candidates++;
924 0 : start = 3;
925 : }
926 : }
927 :
928 0 : if (n_candidates > 1)
929 : {
930 : /* decide on order if mode 2 and 3 are considered */
931 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)]]) <
932 : 0)
933 : {
934 0 : start = 2;
935 0 : inc = 1;
936 : }
937 : else
938 : {
939 0 : start = 3;
940 0 : inc = -1;
941 : }
942 : }
943 :
944 0 : for (mode_counter = start, i = 0; i < n_candidates; mode_counter += inc, i++)
945 : {
946 0 : if (risk_table_f[mode_counter][deg_elp[DEG_ELP_IDX(mode_counter, 0)]].exponent < epmr_lowest_risk_exp)
947 : {
948 0 : if (!rs16_factorize_elp(err_pos + ERR_POS_IDX(mode_counter, 0), elp + ELP_IDX(mode_counter, 0),
949 0 : deg_elp[DEG_ELP_IDX(mode_counter, 0)], first_codeword_length - 1))
950 : {
951 : /* code word is decodable with error correction */
952 0 : epmr_lowest_risk_exp = risk_table_f[mode_counter][deg_elp[DEG_ELP_IDX(mode_counter, 0)]].exponent;
953 :
954 0 : rs16_calculate_errors(err_symb + ERR_SYMB_IDX(mode_counter, 0), err_pos + ERR_POS_IDX(mode_counter, 0),
955 0 : syndromes + SYNDROME_IDX(mode_counter, 0), deg_elp[DEG_ELP_IDX(mode_counter, 0)],
956 0 : t[mode_counter]);
957 :
958 0 : for (i = 0; i < deg_elp[DEG_ELP_IDX(mode_counter, 0)]; i++)
959 : {
960 0 : cw0[err_pos[ERR_POS_IDX(mode_counter, 0) + i]] = GF16_ADD(
961 : cw0[err_pos[ERR_POS_IDX(mode_counter, 0) + i]], err_symb[ERR_SYMB_IDX(mode_counter, 0) + i]);
962 : }
963 0 : break;
964 : }
965 : }
966 : }
967 :
968 0 : epmr = cw0_get_epmr(cw0, first_codeword_length - 1);
969 :
970 0 : if (epmr_lowest_risk_exp > -16)
971 : {
972 0 : epmr += 4;
973 : }
974 0 : if (epmr_lowest_risk_exp > -8)
975 : {
976 0 : epmr += 4;
977 : }
978 :
979 :
980 0 : return epmr;
981 : }
982 :
983 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,
984 : LC3_INT32 *bfi, LC3_UINT8 *array_of_trust, LC3_INT32 ccc_flag, LC3_INT16 *n_pccw)
985 : {
986 :
987 : LC3_INT16 mode_broken[4];
988 : LC3_INT16 error_report_ep_ok[4];
989 : LC3_INT16 i, cw_counter, mode_counter, cw_offset;
990 : LC3_INT16 codeword_length;
991 : LC3_INT16 mode;
992 : LC3_INT16 mode_candidates[4];
993 : LC3_INT16 n_mode_candidates;
994 : LC3_INT16 broken_cw, n_broken_cw;
995 : LC3_INT16 j, idx_min;
996 : LC3_INT16 n_pccw0;
997 : simple_float val_min_f;
998 : LC3_INT16 tmp;
999 : LC3_INT16 epmr_position;
1000 : simple_float dec_risk_f[FEC_N_MODES];
1001 : simple_float risk_min_f;
1002 : simple_float ep_risk_thresh;
1003 : LC3_INT32 epmr_dec_fail_increment;
1004 : LC3_UINT8 const *hamming_distance;
1005 : LC3_UINT8 syndromes[FEC_TOTAL_SYNDROME_SIZE];
1006 : LC3_UINT8 elp[FEC_TOTAL_ELP_SIZE];
1007 : LC3_UINT8 err_pos[FEC_TOTAL_ERR_POS_SIZE];
1008 : LC3_UINT8 err_symb[FEC_TOTAL_ERROR_SIZE];
1009 : LC3_INT8 t[FEC_N_MODES];
1010 : LC3_INT8 deg_elp[FEC_TOTAL_DEG_ELP_SIZE];
1011 : LC3_UINT8 blacklist[FEC_N_MODES];
1012 : LC3_INT32 rop;
1013 :
1014 : void (*syndr_calc[3])(LC3_UINT8 *, LC3_UINT8 *, LC3_INT32);
1015 0 : rop = 0;
1016 :
1017 : /* initialization */
1018 0 : blacklist[0] = 0;
1019 0 : blacklist[1] = 0;
1020 0 : blacklist[2] = 0;
1021 0 : blacklist[3] = 0;
1022 0 : mode_broken[0] = 0;
1023 0 : mode_broken[1] = 0;
1024 0 : mode_broken[2] = 0;
1025 0 : mode_broken[3] = 0;
1026 0 : error_report_ep_ok[0] = ERROR_REPORT_EP1_OK;
1027 0 : error_report_ep_ok[1] = ERROR_REPORT_EP2_OK;
1028 0 : error_report_ep_ok[2] = ERROR_REPORT_EP3_OK;
1029 0 : error_report_ep_ok[3] = ERROR_REPORT_EP4_OK;
1030 0 : hamming_distance = &hamming_distance_by_mode0[1];
1031 0 : mode = -1;
1032 0 : n_mode_candidates = 0;
1033 0 : risk_min_f.mantissa = SIMPLE_FLOAT_1_MANTISSA;
1034 0 : risk_min_f.exponent = 0;
1035 :
1036 0 : if (n_symb <= 80)
1037 : {
1038 0 : ep_risk_thresh.mantissa = EP_RISK_THRESH_NS_M;
1039 0 : ep_risk_thresh.exponent = EP_RISK_THRESH_NS_E;
1040 : }
1041 : else
1042 : {
1043 0 : ep_risk_thresh.mantissa = EP_RISK_THRESH_OS_M;
1044 0 : ep_risk_thresh.exponent = EP_RISK_THRESH_OS_E;
1045 : }
1046 :
1047 0 : syndr_calc[0] = &rs16_calculate_two_syndromes;
1048 0 : syndr_calc[1] = &rs16_calculate_four_syndromes;
1049 0 : syndr_calc[2] = &rs16_calculate_six_syndromes;
1050 :
1051 0 : for (i = 0; i < FEC_N_MODES; i++)
1052 : {
1053 0 : t[i] = (hamming_distance[i] -1)/2;
1054 : }
1055 :
1056 0 : *error_report = 0;
1057 0 : *bfi = 0;
1058 :
1059 : /* mode detection (stage 1) */
1060 0 : codeword_length = get_codeword_length(n_codewords, n_symb, 0);
1061 :
1062 0 : epmr_position = codeword_length - 1;
1063 :
1064 0 : rs16_calculate_two_syndromes(syndromes + SYNDROME_IDX(0, 0), iobuf, codeword_length - 1);
1065 :
1066 0 : if ((syndromes[0 + SYNDROME_IDX(0, 0)] | syndromes[1 + SYNDROME_IDX(0, 0)]) == 0)
1067 : {
1068 :
1069 : /* data validation for fec mode 1 */
1070 0 : *epmr = cw0_get_epmr(iobuf, epmr_position);
1071 :
1072 0 : dw0_bitswap(iobuf + 2, 1, n_symb / 2);
1073 :
1074 0 : if (!crc1(iobuf + 8, n_symb - 8, *epmr, iobuf + 2, 3, 1))
1075 : {
1076 0 : *error_report |= ERROR_REPORT_ALL_OK;
1077 0 : mode = 0;
1078 :
1079 :
1080 0 : rop = mode + 1;
1081 0 : goto CLEANUP;
1082 : }
1083 : else
1084 : {
1085 : /* reverse bit swap */
1086 0 : dw0_bitswap(iobuf + 2, 1, n_symb / 2);
1087 :
1088 0 : *epmr += 4;
1089 : }
1090 : }
1091 :
1092 0 : blacklist[0] = 1;
1093 :
1094 : /* mode detection (stage 2) */
1095 :
1096 : /* calculate syndromes of code words 0 to 5 and modes 1 to 3 */
1097 0 : cw_offset = 0;
1098 :
1099 0 : for (cw_counter = 0; cw_counter < 6; cw_counter++)
1100 : {
1101 0 : codeword_length = get_codeword_length(n_codewords, n_symb, cw_counter);
1102 :
1103 0 : rs16_calculate_six_syndromes(syndromes + SYNDROME_IDX(1, cw_counter), iobuf + cw_offset,
1104 : codeword_length - 1);
1105 :
1106 0 : cw_offset += codeword_length;
1107 :
1108 0 : for (mode_counter = FEC_N_MODES - 1; mode_counter >= 1; mode_counter--)
1109 : {
1110 0 : for (i = 0; i < hamming_distance[mode_counter] - 1; i++)
1111 : {
1112 0 : syndromes[SYNDROME_IDX(mode_counter, cw_counter) + i] = GF16_ADD(
1113 : syndromes[SYNDROME_IDX(1, cw_counter) + i], sig_poly_syndr[mode_counter][i]);
1114 : }
1115 : }
1116 : }
1117 :
1118 : /* check for valid code words */
1119 0 : for (mode_counter = 1; mode_counter < FEC_N_MODES; mode_counter++)
1120 : {
1121 0 : n_broken_cw = 0;
1122 0 : for (cw_counter = 0; cw_counter < 6; cw_counter++)
1123 : {
1124 0 : broken_cw = 0;
1125 0 : for (i = 0; i < hamming_distance[mode_counter] - 1; i++)
1126 : {
1127 0 : broken_cw |= syndromes[SYNDROME_IDX(mode_counter, cw_counter) + i];
1128 : }
1129 0 : if (broken_cw != 0)
1130 : {
1131 0 : n_broken_cw ++;
1132 : }
1133 : }
1134 :
1135 0 : if (n_broken_cw == 0)
1136 : {
1137 0 : mode = mode_counter;
1138 0 : cw_offset = 0;
1139 :
1140 0 : *epmr = cw0_get_epmr(iobuf, epmr_position);
1141 :
1142 0 : for (cw_counter = 0; cw_counter < 6; cw_counter++)
1143 : {
1144 0 : codeword_length = get_codeword_length(n_codewords, n_symb, cw_counter);
1145 0 : for (i = 0; i <= EP_SIG_POLY_DEG; i++)
1146 : {
1147 0 : iobuf[cw_offset + i] = GF16_ADD(iobuf[cw_offset + i], sig_polys[mode][i]);
1148 : }
1149 0 : cw_offset += codeword_length;
1150 : }
1151 : }
1152 : }
1153 :
1154 0 : if (mode < 0) /* mode hasn't been detected so far -> errors occurred in transmission */
1155 : {
1156 : /* calculate error locator polynomials for code words 0 to 5 */
1157 0 : for (mode_counter = 1; mode_counter < FEC_N_MODES; mode_counter++)
1158 : {
1159 0 : for (cw_counter = 0; cw_counter < 6; cw_counter++)
1160 : {
1161 0 : deg_elp[DEG_ELP_IDX(mode_counter, cw_counter)] = rs16_calculate_elp(
1162 0 : elp + ELP_IDX(mode_counter, cw_counter), syndromes + SYNDROME_IDX(mode_counter, cw_counter),
1163 0 : t[mode_counter]);
1164 0 : if (deg_elp[DEG_ELP_IDX(mode_counter, cw_counter)] > t[mode_counter])
1165 : {
1166 0 : blacklist[mode_counter] = 1;
1167 0 : break;
1168 : }
1169 : }
1170 : }
1171 :
1172 : /* risk analysis for mode candidate selection */
1173 0 : for (mode_counter = 1; mode_counter < FEC_N_MODES; mode_counter++)
1174 : {
1175 0 : dec_risk_f[mode_counter].mantissa = SIMPLE_FLOAT_1_MANTISSA;
1176 0 : dec_risk_f[mode_counter].exponent = 0;
1177 :
1178 0 : if (blacklist[mode_counter] == 0)
1179 : {
1180 0 : for (cw_counter = 0; cw_counter < 6; cw_counter++)
1181 : {
1182 0 : dec_risk_f[mode_counter] = simple_float_mul(
1183 : dec_risk_f[mode_counter],
1184 0 : risk_table_f[mode_counter][deg_elp[DEG_ELP_IDX(mode_counter, cw_counter)]]);
1185 : }
1186 :
1187 0 : if (simple_float_cmp(dec_risk_f[mode_counter], ep_risk_thresh) <= 0)
1188 : {
1189 0 : mode_candidates[n_mode_candidates++] = mode_counter;
1190 : }
1191 :
1192 0 : if (simple_float_cmp(dec_risk_f[mode_counter], risk_min_f) < 0)
1193 : {
1194 0 : risk_min_f = dec_risk_f[mode_counter];
1195 : }
1196 : }
1197 : }
1198 0 : assert(n_mode_candidates <= 4); /* suppress false gcc warning when OPTIM=3 */
1199 :
1200 : /* sort mode candidates by risk */
1201 0 : for (i = 0; i < n_mode_candidates; i++)
1202 : {
1203 0 : idx_min = i;
1204 0 : val_min_f = dec_risk_f[mode_candidates[i]];
1205 :
1206 0 : for (j = i + 1; j < n_mode_candidates; j++)
1207 : {
1208 0 : if (simple_float_cmp(dec_risk_f[mode_candidates[j]], val_min_f) < 0)
1209 : {
1210 0 : val_min_f = dec_risk_f[mode_candidates[j]];
1211 0 : idx_min = j;
1212 : }
1213 : }
1214 :
1215 0 : if (idx_min > i)
1216 : {
1217 0 : tmp = mode_candidates[i];
1218 0 : mode_candidates[i] = mode_candidates[idx_min];
1219 0 : mode_candidates[idx_min] = tmp;
1220 : }
1221 : }
1222 :
1223 : /* try out candidate modes */
1224 0 : for (i = 0; i < n_mode_candidates; i++)
1225 : {
1226 0 : mode = mode_candidates[i];
1227 :
1228 0 : for (cw_counter = 0; cw_counter < 6; cw_counter++)
1229 : {
1230 0 : codeword_length = get_codeword_length(n_codewords, n_symb, cw_counter);
1231 :
1232 0 : if (deg_elp[DEG_ELP_IDX(mode, cw_counter)])
1233 : {
1234 0 : if (rs16_factorize_elp(err_pos + ERR_POS_IDX(mode, cw_counter), elp + ELP_IDX(mode, cw_counter),
1235 0 : deg_elp[DEG_ELP_IDX(mode, cw_counter)], codeword_length - 1))
1236 : {
1237 : /* elp did not split into distinct linear factors or error position was out of range */
1238 0 : mode = -1;
1239 0 : break;
1240 : }
1241 : }
1242 : }
1243 0 : if (mode > 0)
1244 : {
1245 : /* decodable mode with lowest risk has been found */
1246 0 : break;
1247 : }
1248 : }
1249 :
1250 0 : if (mode < 0)
1251 : {
1252 : /* no decodable mode has been found */
1253 0 : *error_report = ERROR_REPORT_BEC_MASK;
1254 0 : *bfi = 1;
1255 0 : mode = -1;
1256 :
1257 0 : *epmr = fec_estimate_epmr_from_cw0(iobuf, t, syndromes, elp, deg_elp, err_pos, err_symb, n_codewords,
1258 : n_symb);
1259 :
1260 :
1261 0 : rop = mode;
1262 0 : goto CLEANUP;
1263 : }
1264 :
1265 : /* perform error correction */
1266 0 : cw_offset = 0;
1267 0 : *error_report = 0;
1268 0 : for (cw_counter = 0; cw_counter < 6; cw_counter++)
1269 : {
1270 0 : codeword_length = get_codeword_length(n_codewords, n_symb, cw_counter);
1271 :
1272 0 : if (deg_elp[DEG_ELP_IDX(mode, cw_counter)])
1273 : {
1274 0 : rs16_calculate_errors(
1275 0 : err_symb + ERR_SYMB_IDX(mode, cw_counter), err_pos + ERR_POS_IDX(mode, cw_counter),
1276 0 : syndromes + SYNDROME_IDX(mode, cw_counter), deg_elp[DEG_ELP_IDX(mode, cw_counter)], t[mode]);
1277 :
1278 : /* correct errors and sum up number of corrected bits */
1279 0 : for (i = 0; i < deg_elp[DEG_ELP_IDX(mode, cw_counter)]; i++)
1280 : {
1281 0 : iobuf[err_pos[ERR_POS_IDX(mode, cw_counter) + i] + cw_offset] =
1282 0 : GF16_ADD(iobuf[err_pos[ERR_POS_IDX(mode, cw_counter) + i] + cw_offset],
1283 : err_symb[ERR_SYMB_IDX(mode, cw_counter) + i]);
1284 0 : *error_report += rs16_bit_count_table[err_symb[ERR_SYMB_IDX(mode, cw_counter) + i]];
1285 : }
1286 :
1287 0 : for (i = 0; i < mode; i ++)
1288 : {
1289 0 : if(deg_elp[DEG_ELP_IDX(mode, cw_counter)] > i)
1290 : {
1291 0 : mode_broken[i] = 1;
1292 : }
1293 : }
1294 :
1295 : }
1296 :
1297 0 : for (i = 0; i <= EP_SIG_POLY_DEG; i++)
1298 : {
1299 0 : iobuf[cw_offset + i] = GF16_ADD(iobuf[cw_offset + i], sig_polys[mode][i]);
1300 : }
1301 0 : cw_offset += codeword_length;
1302 : }
1303 :
1304 : /* set epmr according to risk value of cw0 */
1305 0 : epmr_dec_fail_increment = 8;
1306 :
1307 0 : if (risk_table_f[mode][deg_elp[DEG_ELP_IDX(mode, 0)]].exponent <= -8)
1308 : {
1309 0 : epmr_dec_fail_increment -= 4;
1310 : }
1311 0 : if (risk_table_f[mode][deg_elp[DEG_ELP_IDX(mode, 0)]].exponent <= -16)
1312 : {
1313 0 : epmr_dec_fail_increment -= 4;
1314 : }
1315 :
1316 0 : *epmr = (LC3PLUS_EpModeRequest)(cw0_get_epmr(iobuf, epmr_position) + epmr_dec_fail_increment);
1317 : }
1318 :
1319 : /* mode has been successfully detected -> now check and try to correct remaining code words*/
1320 0 : *n_pccw = fec_get_n_pccw(n_symb / 2, mode + 1, ccc_flag);
1321 0 : if (ccc_flag == 0)
1322 : {
1323 0 : n_pccw0 = fec_get_n_pccw(n_symb / 2, mode + 1, ccc_flag);
1324 0 : *n_pccw = n_pccw0;
1325 : }
1326 : else
1327 : {
1328 0 : n_pccw0 = 0;
1329 : }
1330 :
1331 0 : for (cw_counter = 6; cw_counter < n_codewords; cw_counter++)
1332 : {
1333 : /* usual error correction scheme: syndromes -> elp's, errors, etc. */
1334 0 : codeword_length = get_codeword_length(n_codewords, n_symb, cw_counter);
1335 0 : array_of_trust[n_codewords - 1 - cw_counter] = 1;
1336 :
1337 0 : syndr_calc[t[mode] - 1](syndromes, iobuf + cw_offset, codeword_length -1);
1338 :
1339 0 : deg_elp[0] = rs16_calculate_elp(elp, syndromes, t[mode]);
1340 :
1341 0 : for (i = 0; i < mode; i ++)
1342 : {
1343 0 : if (deg_elp[0] > i)
1344 : {
1345 0 : mode_broken[i] = 1;
1346 : }
1347 : }
1348 :
1349 0 : if (deg_elp[0] > t[mode])
1350 : {
1351 0 : for (i = 0; i < 4; i ++)
1352 : {
1353 0 : mode_broken[i] = 1;
1354 : }
1355 0 : cw_offset += codeword_length;
1356 0 : if (cw_counter < n_codewords - n_pccw0)
1357 : {
1358 0 : *error_report = ERROR_REPORT_BEC_MASK;
1359 0 : mode = -1;
1360 0 : *bfi = 1;
1361 0 : break;
1362 : }
1363 : else
1364 : {
1365 0 : *bfi = 2;
1366 0 : array_of_trust[n_codewords - 1 - cw_counter] = 0;
1367 0 : continue;
1368 : }
1369 : }
1370 :
1371 0 : if (deg_elp[0])
1372 : {
1373 0 : if (rs16_factorize_elp(err_pos, elp, deg_elp[0], codeword_length - 1))
1374 : {
1375 0 : cw_offset += codeword_length;
1376 0 : for (i = 0; i < 4; i ++)
1377 : {
1378 0 : mode_broken[i] = 1;
1379 : }
1380 0 : if (cw_counter < n_codewords - n_pccw0)
1381 : {
1382 0 : *error_report = ERROR_REPORT_BEC_MASK;
1383 0 : mode = -1;
1384 0 : *bfi = 1;
1385 :
1386 0 : break;
1387 : }
1388 : else
1389 : {
1390 0 : *bfi = 2;
1391 0 : array_of_trust[n_codewords - 1 - cw_counter] = 0;
1392 0 : continue;
1393 : }
1394 : }
1395 :
1396 0 : rs16_calculate_errors(err_symb, err_pos, syndromes, deg_elp[0], t[mode]);
1397 :
1398 : /* correct errors and sum up number of corrected bits */
1399 0 : for (i = 0; i < deg_elp[0]; i++)
1400 : {
1401 0 : iobuf[err_pos[i] + cw_offset] = GF16_ADD(iobuf[err_pos[i] + cw_offset], err_symb[i]);
1402 0 : *error_report += rs16_bit_count_table[err_symb[i]];
1403 : }
1404 : }
1405 0 : cw_offset += codeword_length;
1406 0 : if (risk_table_f[mode][deg_elp[0]].exponent > -16)
1407 : {
1408 0 : array_of_trust[n_codewords - 1 - cw_counter] = 0;
1409 : }
1410 : }
1411 :
1412 0 : *error_report &= ERROR_REPORT_BEC_MASK;
1413 0 : for (i = 0; i < 4; i ++)
1414 : {
1415 0 : if (!mode_broken[i])
1416 : {
1417 0 : *error_report |= error_report_ep_ok[i];
1418 : }
1419 : }
1420 :
1421 0 : if (mode >= 0)
1422 : {
1423 0 : rop = mode + 1;
1424 : } else {
1425 0 : rop = -1;
1426 : }
1427 :
1428 :
1429 :
1430 0 : CLEANUP:
1431 0 : return rop;
1432 : }
1433 :
1434 0 : FEC_STATIC void rs16_calculate_six_syndromes(LC3_UINT8 *syndromes, LC3_UINT8 *cw, LC3_INT32 cw_poly_deg)
1435 : {
1436 : LC3_INT32 i;
1437 : LC3_UINT8 buffer[15];
1438 :
1439 0 : assert(cw_poly_deg >= 12);
1440 :
1441 0 : for (i = 0; i <= cw_poly_deg; i++)
1442 : {
1443 0 : buffer[i] = cw[i];
1444 : }
1445 :
1446 0 : syndromes[0] = buffer[0];
1447 0 : syndromes[1] = buffer[0];
1448 0 : syndromes[2] = buffer[0];
1449 0 : syndromes[3] = buffer[0];
1450 0 : syndromes[4] = buffer[0];
1451 0 : syndromes[5] = buffer[0];
1452 :
1453 0 : syndromes[0] = GF16_ADD(syndromes[0], GF16_MUL0(buffer[1], 32));
1454 0 : syndromes[1] = GF16_ADD(syndromes[1], GF16_MUL0(buffer[1], 64));
1455 0 : syndromes[2] = GF16_ADD(syndromes[2], GF16_MUL0(buffer[1], 128));
1456 0 : syndromes[3] = GF16_ADD(syndromes[3], GF16_MUL0(buffer[1], 48));
1457 0 : syndromes[4] = GF16_ADD(syndromes[4], GF16_MUL0(buffer[1], 96));
1458 0 : syndromes[5] = GF16_ADD(syndromes[5], GF16_MUL0(buffer[1], 192));
1459 :
1460 0 : syndromes[0] = GF16_ADD(syndromes[0], GF16_MUL0(buffer[2], 64));
1461 0 : syndromes[1] = GF16_ADD(syndromes[1], GF16_MUL0(buffer[2], 48));
1462 0 : syndromes[2] = GF16_ADD(syndromes[2], GF16_MUL0(buffer[2], 192));
1463 0 : syndromes[3] = GF16_ADD(syndromes[3], GF16_MUL0(buffer[2], 80));
1464 0 : syndromes[4] = GF16_ADD(syndromes[4], GF16_MUL0(buffer[2], 112));
1465 0 : syndromes[5] = GF16_ADD(syndromes[5], GF16_MUL0(buffer[2], 240));
1466 :
1467 0 : syndromes[0] = GF16_ADD(syndromes[0], GF16_MUL0(buffer[3], 128));
1468 0 : syndromes[1] = GF16_ADD(syndromes[1], GF16_MUL0(buffer[3], 192));
1469 0 : syndromes[2] = GF16_ADD(syndromes[2], GF16_MUL0(buffer[3], 160));
1470 0 : syndromes[3] = GF16_ADD(syndromes[3], GF16_MUL0(buffer[3], 240));
1471 0 : syndromes[4] = GF16_ADD(syndromes[4], GF16_MUL0(buffer[3], 16));
1472 0 : syndromes[5] = GF16_ADD(syndromes[5], GF16_MUL0(buffer[3], 128));
1473 :
1474 0 : syndromes[0] = GF16_ADD(syndromes[0], GF16_MUL0(buffer[4], 48));
1475 0 : syndromes[1] = GF16_ADD(syndromes[1], GF16_MUL0(buffer[4], 80));
1476 0 : syndromes[2] = GF16_ADD(syndromes[2], GF16_MUL0(buffer[4], 240));
1477 0 : syndromes[3] = GF16_ADD(syndromes[3], GF16_MUL0(buffer[4], 32));
1478 0 : syndromes[4] = GF16_ADD(syndromes[4], GF16_MUL0(buffer[4], 96));
1479 0 : syndromes[5] = GF16_ADD(syndromes[5], GF16_MUL0(buffer[4], 160));
1480 :
1481 0 : syndromes[0] = GF16_ADD(syndromes[0], GF16_MUL0(buffer[5], 96));
1482 0 : syndromes[1] = GF16_ADD(syndromes[1], GF16_MUL0(buffer[5], 112));
1483 0 : syndromes[2] = GF16_ADD(syndromes[2], GF16_MUL0(buffer[5], 16));
1484 0 : syndromes[3] = GF16_ADD(syndromes[3], GF16_MUL0(buffer[5], 96));
1485 0 : syndromes[4] = GF16_ADD(syndromes[4], GF16_MUL0(buffer[5], 112));
1486 0 : syndromes[5] = GF16_ADD(syndromes[5], GF16_MUL0(buffer[5], 16));
1487 :
1488 0 : syndromes[0] = GF16_ADD(syndromes[0], GF16_MUL0(buffer[6], 192));
1489 0 : syndromes[1] = GF16_ADD(syndromes[1], GF16_MUL0(buffer[6], 240));
1490 0 : syndromes[2] = GF16_ADD(syndromes[2], GF16_MUL0(buffer[6], 128));
1491 0 : syndromes[3] = GF16_ADD(syndromes[3], GF16_MUL0(buffer[6], 160));
1492 0 : syndromes[4] = GF16_ADD(syndromes[4], GF16_MUL0(buffer[6], 16));
1493 0 : syndromes[5] = GF16_ADD(syndromes[5], GF16_MUL0(buffer[6], 192));
1494 :
1495 0 : syndromes[0] = GF16_ADD(syndromes[0], GF16_MUL0(buffer[7], 176));
1496 0 : syndromes[1] = GF16_ADD(syndromes[1], GF16_MUL0(buffer[7], 144));
1497 0 : syndromes[2] = GF16_ADD(syndromes[2], GF16_MUL0(buffer[7], 192));
1498 0 : syndromes[3] = GF16_ADD(syndromes[3], GF16_MUL0(buffer[7], 208));
1499 0 : syndromes[4] = GF16_ADD(syndromes[4], GF16_MUL0(buffer[7], 96));
1500 0 : syndromes[5] = GF16_ADD(syndromes[5], GF16_MUL0(buffer[7], 240));
1501 :
1502 0 : syndromes[0] = GF16_ADD(syndromes[0], GF16_MUL0(buffer[8], 80));
1503 0 : syndromes[1] = GF16_ADD(syndromes[1], GF16_MUL0(buffer[8], 32));
1504 0 : syndromes[2] = GF16_ADD(syndromes[2], GF16_MUL0(buffer[8], 160));
1505 0 : syndromes[3] = GF16_ADD(syndromes[3], GF16_MUL0(buffer[8], 64));
1506 0 : syndromes[4] = GF16_ADD(syndromes[4], GF16_MUL0(buffer[8], 112));
1507 0 : syndromes[5] = GF16_ADD(syndromes[5], GF16_MUL0(buffer[8], 128));
1508 :
1509 0 : syndromes[0] = GF16_ADD(syndromes[0], GF16_MUL0(buffer[9], 160));
1510 0 : syndromes[1] = GF16_ADD(syndromes[1], GF16_MUL0(buffer[9], 128));
1511 0 : syndromes[2] = GF16_ADD(syndromes[2], GF16_MUL0(buffer[9], 240));
1512 0 : syndromes[3] = GF16_ADD(syndromes[3], GF16_MUL0(buffer[9], 192));
1513 0 : syndromes[4] = GF16_ADD(syndromes[4], GF16_MUL0(buffer[9], 16));
1514 0 : syndromes[5] = GF16_ADD(syndromes[5], GF16_MUL0(buffer[9], 160));
1515 :
1516 0 : syndromes[0] = GF16_ADD(syndromes[0], GF16_MUL0(buffer[10], 112));
1517 0 : syndromes[1] = GF16_ADD(syndromes[1], GF16_MUL0(buffer[10], 96));
1518 0 : syndromes[2] = GF16_ADD(syndromes[2], GF16_MUL0(buffer[10], 16));
1519 0 : syndromes[3] = GF16_ADD(syndromes[3], GF16_MUL0(buffer[10], 112));
1520 0 : syndromes[4] = GF16_ADD(syndromes[4], GF16_MUL0(buffer[10], 96));
1521 0 : syndromes[5] = GF16_ADD(syndromes[5], GF16_MUL0(buffer[10], 16));
1522 :
1523 0 : syndromes[0] = GF16_ADD(syndromes[0], GF16_MUL0(buffer[11], 224));
1524 0 : syndromes[1] = GF16_ADD(syndromes[1], GF16_MUL0(buffer[11], 176));
1525 0 : syndromes[2] = GF16_ADD(syndromes[2], GF16_MUL0(buffer[11], 128));
1526 0 : syndromes[3] = GF16_ADD(syndromes[3], GF16_MUL0(buffer[11], 144));
1527 0 : syndromes[4] = GF16_ADD(syndromes[4], GF16_MUL0(buffer[11], 112));
1528 0 : syndromes[5] = GF16_ADD(syndromes[5], GF16_MUL0(buffer[11], 192));
1529 :
1530 0 : syndromes[0] = GF16_ADD(syndromes[0], GF16_MUL0(buffer[12], 240));
1531 0 : syndromes[1] = GF16_ADD(syndromes[1], GF16_MUL0(buffer[12], 160));
1532 0 : syndromes[2] = GF16_ADD(syndromes[2], GF16_MUL0(buffer[12], 192));
1533 0 : syndromes[3] = GF16_ADD(syndromes[3], GF16_MUL0(buffer[12], 128));
1534 0 : syndromes[4] = GF16_ADD(syndromes[4], GF16_MUL0(buffer[12], 16));
1535 0 : syndromes[5] = GF16_ADD(syndromes[5], GF16_MUL0(buffer[12], 240));
1536 :
1537 0 : if (cw_poly_deg >= 13)
1538 : {
1539 0 : syndromes[0] = GF16_ADD(syndromes[0], GF16_MUL0(buffer[13], 208));
1540 0 : syndromes[1] = GF16_ADD(syndromes[1], GF16_MUL0(buffer[13], 224));
1541 0 : syndromes[2] = GF16_ADD(syndromes[2], GF16_MUL0(buffer[13], 160));
1542 0 : syndromes[3] = GF16_ADD(syndromes[3], GF16_MUL0(buffer[13], 176));
1543 0 : syndromes[4] = GF16_ADD(syndromes[4], GF16_MUL0(buffer[13], 96));
1544 0 : syndromes[5] = GF16_ADD(syndromes[5], GF16_MUL0(buffer[13], 128));
1545 : }
1546 :
1547 0 : if (cw_poly_deg >= 14)
1548 : {
1549 0 : syndromes[0] = GF16_ADD(syndromes[0], GF16_MUL0(buffer[14], 144));
1550 0 : syndromes[1] = GF16_ADD(syndromes[1], GF16_MUL0(buffer[14], 208));
1551 0 : syndromes[2] = GF16_ADD(syndromes[2], GF16_MUL0(buffer[14], 240));
1552 0 : syndromes[3] = GF16_ADD(syndromes[3], GF16_MUL0(buffer[14], 224));
1553 0 : syndromes[4] = GF16_ADD(syndromes[4], GF16_MUL0(buffer[14], 112));
1554 0 : syndromes[5] = GF16_ADD(syndromes[5], GF16_MUL0(buffer[14], 160));
1555 : }
1556 :
1557 :
1558 0 : }
1559 :
1560 0 : FEC_STATIC void rs16_calculate_four_syndromes(LC3_UINT8 *syndromes, LC3_UINT8 *cw, LC3_INT32 cw_poly_deg)
1561 : {
1562 : LC3_INT32 i;
1563 : LC3_UINT8 buffer[15];
1564 :
1565 0 : assert(cw_poly_deg >= 12);
1566 :
1567 0 : for (i = 0; i <= cw_poly_deg; i++)
1568 : {
1569 0 : buffer[i] = cw[i];
1570 : }
1571 :
1572 0 : syndromes[0] = buffer[0];
1573 0 : syndromes[1] = buffer[0];
1574 0 : syndromes[2] = buffer[0];
1575 0 : syndromes[3] = buffer[0];
1576 :
1577 0 : syndromes[0] = GF16_ADD(syndromes[0], GF16_MUL0(buffer[1], 32));
1578 0 : syndromes[1] = GF16_ADD(syndromes[1], GF16_MUL0(buffer[1], 64));
1579 0 : syndromes[2] = GF16_ADD(syndromes[2], GF16_MUL0(buffer[1], 128));
1580 0 : syndromes[3] = GF16_ADD(syndromes[3], GF16_MUL0(buffer[1], 48));
1581 :
1582 0 : syndromes[0] = GF16_ADD(syndromes[0], GF16_MUL0(buffer[2], 64));
1583 0 : syndromes[1] = GF16_ADD(syndromes[1], GF16_MUL0(buffer[2], 48));
1584 0 : syndromes[2] = GF16_ADD(syndromes[2], GF16_MUL0(buffer[2], 192));
1585 0 : syndromes[3] = GF16_ADD(syndromes[3], GF16_MUL0(buffer[2], 80));
1586 :
1587 0 : syndromes[0] = GF16_ADD(syndromes[0], GF16_MUL0(buffer[3], 128));
1588 0 : syndromes[1] = GF16_ADD(syndromes[1], GF16_MUL0(buffer[3], 192));
1589 0 : syndromes[2] = GF16_ADD(syndromes[2], GF16_MUL0(buffer[3], 160));
1590 0 : syndromes[3] = GF16_ADD(syndromes[3], GF16_MUL0(buffer[3], 240));
1591 :
1592 0 : syndromes[0] = GF16_ADD(syndromes[0], GF16_MUL0(buffer[4], 48));
1593 0 : syndromes[1] = GF16_ADD(syndromes[1], GF16_MUL0(buffer[4], 80));
1594 0 : syndromes[2] = GF16_ADD(syndromes[2], GF16_MUL0(buffer[4], 240));
1595 0 : syndromes[3] = GF16_ADD(syndromes[3], GF16_MUL0(buffer[4], 32));
1596 :
1597 0 : syndromes[0] = GF16_ADD(syndromes[0], GF16_MUL0(buffer[5], 96));
1598 0 : syndromes[1] = GF16_ADD(syndromes[1], GF16_MUL0(buffer[5], 112));
1599 0 : syndromes[2] = GF16_ADD(syndromes[2], GF16_MUL0(buffer[5], 16));
1600 0 : syndromes[3] = GF16_ADD(syndromes[3], GF16_MUL0(buffer[5], 96));
1601 :
1602 0 : syndromes[0] = GF16_ADD(syndromes[0], GF16_MUL0(buffer[6], 192));
1603 0 : syndromes[1] = GF16_ADD(syndromes[1], GF16_MUL0(buffer[6], 240));
1604 0 : syndromes[2] = GF16_ADD(syndromes[2], GF16_MUL0(buffer[6], 128));
1605 0 : syndromes[3] = GF16_ADD(syndromes[3], GF16_MUL0(buffer[6], 160));
1606 :
1607 0 : syndromes[0] = GF16_ADD(syndromes[0], GF16_MUL0(buffer[7], 176));
1608 0 : syndromes[1] = GF16_ADD(syndromes[1], GF16_MUL0(buffer[7], 144));
1609 0 : syndromes[2] = GF16_ADD(syndromes[2], GF16_MUL0(buffer[7], 192));
1610 0 : syndromes[3] = GF16_ADD(syndromes[3], GF16_MUL0(buffer[7], 208));
1611 :
1612 0 : syndromes[0] = GF16_ADD(syndromes[0], GF16_MUL0(buffer[8], 80));
1613 0 : syndromes[1] = GF16_ADD(syndromes[1], GF16_MUL0(buffer[8], 32));
1614 0 : syndromes[2] = GF16_ADD(syndromes[2], GF16_MUL0(buffer[8], 160));
1615 0 : syndromes[3] = GF16_ADD(syndromes[3], GF16_MUL0(buffer[8], 64));
1616 :
1617 0 : syndromes[0] = GF16_ADD(syndromes[0], GF16_MUL0(buffer[9], 160));
1618 0 : syndromes[1] = GF16_ADD(syndromes[1], GF16_MUL0(buffer[9], 128));
1619 0 : syndromes[2] = GF16_ADD(syndromes[2], GF16_MUL0(buffer[9], 240));
1620 0 : syndromes[3] = GF16_ADD(syndromes[3], GF16_MUL0(buffer[9], 192));
1621 :
1622 0 : syndromes[0] = GF16_ADD(syndromes[0], GF16_MUL0(buffer[10], 112));
1623 0 : syndromes[1] = GF16_ADD(syndromes[1], GF16_MUL0(buffer[10], 96));
1624 0 : syndromes[2] = GF16_ADD(syndromes[2], GF16_MUL0(buffer[10], 16));
1625 0 : syndromes[3] = GF16_ADD(syndromes[3], GF16_MUL0(buffer[10], 112));
1626 :
1627 0 : syndromes[0] = GF16_ADD(syndromes[0], GF16_MUL0(buffer[11], 224));
1628 0 : syndromes[1] = GF16_ADD(syndromes[1], GF16_MUL0(buffer[11], 176));
1629 0 : syndromes[2] = GF16_ADD(syndromes[2], GF16_MUL0(buffer[11], 128));
1630 0 : syndromes[3] = GF16_ADD(syndromes[3], GF16_MUL0(buffer[11], 144));
1631 :
1632 0 : syndromes[0] = GF16_ADD(syndromes[0], GF16_MUL0(buffer[12], 240));
1633 0 : syndromes[1] = GF16_ADD(syndromes[1], GF16_MUL0(buffer[12], 160));
1634 0 : syndromes[2] = GF16_ADD(syndromes[2], GF16_MUL0(buffer[12], 192));
1635 0 : syndromes[3] = GF16_ADD(syndromes[3], GF16_MUL0(buffer[12], 128));
1636 :
1637 0 : if (cw_poly_deg >= 13)
1638 : {
1639 0 : syndromes[0] = GF16_ADD(syndromes[0], GF16_MUL0(buffer[13], 208));
1640 0 : syndromes[1] = GF16_ADD(syndromes[1], GF16_MUL0(buffer[13], 224));
1641 0 : syndromes[2] = GF16_ADD(syndromes[2], GF16_MUL0(buffer[13], 160));
1642 0 : syndromes[3] = GF16_ADD(syndromes[3], GF16_MUL0(buffer[13], 176));
1643 : }
1644 :
1645 0 : if (cw_poly_deg >= 14)
1646 : {
1647 0 : syndromes[0] = GF16_ADD(syndromes[0], GF16_MUL0(buffer[14], 144));
1648 0 : syndromes[1] = GF16_ADD(syndromes[1], GF16_MUL0(buffer[14], 208));
1649 0 : syndromes[2] = GF16_ADD(syndromes[2], GF16_MUL0(buffer[14], 240));
1650 0 : syndromes[3] = GF16_ADD(syndromes[3], GF16_MUL0(buffer[14], 224));
1651 : }
1652 :
1653 :
1654 0 : }
1655 :
1656 0 : FEC_STATIC void rs16_calculate_two_syndromes(LC3_UINT8 *syndromes, LC3_UINT8 *cw, LC3_INT32 cw_poly_deg)
1657 : {
1658 : LC3_INT32 i;
1659 : LC3_UINT8 buffer[15];
1660 :
1661 0 : assert(cw_poly_deg >= 12);
1662 :
1663 0 : for (i = 0; i <= cw_poly_deg; i++)
1664 : {
1665 0 : buffer[i] = cw[i];
1666 : }
1667 :
1668 0 : syndromes[0] = buffer[0];
1669 0 : syndromes[1] = buffer[0];
1670 :
1671 0 : syndromes[0] = GF16_ADD(syndromes[0], GF16_MUL0(buffer[1], 32));
1672 0 : syndromes[1] = GF16_ADD(syndromes[1], GF16_MUL0(buffer[1], 64));
1673 :
1674 0 : syndromes[0] = GF16_ADD(syndromes[0], GF16_MUL0(buffer[2], 64));
1675 0 : syndromes[1] = GF16_ADD(syndromes[1], GF16_MUL0(buffer[2], 48));
1676 :
1677 0 : syndromes[0] = GF16_ADD(syndromes[0], GF16_MUL0(buffer[3], 128));
1678 0 : syndromes[1] = GF16_ADD(syndromes[1], GF16_MUL0(buffer[3], 192));
1679 :
1680 0 : syndromes[0] = GF16_ADD(syndromes[0], GF16_MUL0(buffer[4], 48));
1681 0 : syndromes[1] = GF16_ADD(syndromes[1], GF16_MUL0(buffer[4], 80));
1682 :
1683 0 : syndromes[0] = GF16_ADD(syndromes[0], GF16_MUL0(buffer[5], 96));
1684 0 : syndromes[1] = GF16_ADD(syndromes[1], GF16_MUL0(buffer[5], 112));
1685 :
1686 0 : syndromes[0] = GF16_ADD(syndromes[0], GF16_MUL0(buffer[6], 192));
1687 0 : syndromes[1] = GF16_ADD(syndromes[1], GF16_MUL0(buffer[6], 240));
1688 :
1689 0 : syndromes[0] = GF16_ADD(syndromes[0], GF16_MUL0(buffer[7], 176));
1690 0 : syndromes[1] = GF16_ADD(syndromes[1], GF16_MUL0(buffer[7], 144));
1691 :
1692 0 : syndromes[0] = GF16_ADD(syndromes[0], GF16_MUL0(buffer[8], 80));
1693 0 : syndromes[1] = GF16_ADD(syndromes[1], GF16_MUL0(buffer[8], 32));
1694 :
1695 0 : syndromes[0] = GF16_ADD(syndromes[0], GF16_MUL0(buffer[9], 160));
1696 0 : syndromes[1] = GF16_ADD(syndromes[1], GF16_MUL0(buffer[9], 128));
1697 :
1698 0 : syndromes[0] = GF16_ADD(syndromes[0], GF16_MUL0(buffer[10], 112));
1699 0 : syndromes[1] = GF16_ADD(syndromes[1], GF16_MUL0(buffer[10], 96));
1700 :
1701 0 : syndromes[0] = GF16_ADD(syndromes[0], GF16_MUL0(buffer[11], 224));
1702 0 : syndromes[1] = GF16_ADD(syndromes[1], GF16_MUL0(buffer[11], 176));
1703 :
1704 0 : syndromes[0] = GF16_ADD(syndromes[0], GF16_MUL0(buffer[12], 240));
1705 0 : syndromes[1] = GF16_ADD(syndromes[1], GF16_MUL0(buffer[12], 160));
1706 :
1707 0 : if (cw_poly_deg >= 13)
1708 : {
1709 0 : syndromes[0] = GF16_ADD(syndromes[0], GF16_MUL0(buffer[13], 208));
1710 0 : syndromes[1] = GF16_ADD(syndromes[1], GF16_MUL0(buffer[13], 224));
1711 : }
1712 :
1713 0 : if (cw_poly_deg >= 14)
1714 : {
1715 0 : syndromes[0] = GF16_ADD(syndromes[0], GF16_MUL0(buffer[14], 144));
1716 0 : syndromes[1] = GF16_ADD(syndromes[1], GF16_MUL0(buffer[14], 208));
1717 : }
1718 :
1719 :
1720 0 : }
1721 :
1722 0 : FEC_STATIC LC3_INT8 rs16_calculate_elp(LC3_UINT8 *elp, LC3_UINT8 *syndromes, LC3_INT16 t)
1723 : /* calculates error locator polynomial vie Petterson's algorithm */
1724 : {
1725 : LC3_INT8 ret;
1726 : LC3_UINT8 det, det_inv, aux, all_s, *s;
1727 : LC3_UINT8 s22, s33, s44, s13, s14, s15;
1728 : LC3_UINT8 s23, s24, s25, s34, s35;
1729 : LC3_UINT8 a, b, c, d, e, f;
1730 :
1731 0 : ret = 0;
1732 0 : all_s = 0;
1733 0 : s = syndromes;
1734 0 : elp[0] = 1;
1735 0 : memset(elp + 1, 0, 3);
1736 :
1737 0 : switch (t)
1738 : {
1739 0 : case 3:
1740 : {
1741 : /* check for errors */
1742 0 : all_s = s[0] | s[1] | s[2] | s[3] | s[4] | s[5];
1743 :
1744 0 : if (all_s == 0)
1745 : {
1746 0 : break;
1747 : }
1748 :
1749 : /* assume 3 errors */
1750 0 : s22 = GF16_MUL(s[1], s[1]);
1751 0 : s33 = GF16_MUL(s[2], s[2]);
1752 0 : s44 = GF16_MUL(s[3], s[3]);
1753 0 : s13 = GF16_MUL(s[0], s[2]);
1754 :
1755 0 : det = GF16_ADD(GF16_ADD(GF16_MUL(s13, s[4]), GF16_MUL(s44, s[0])),
1756 : GF16_ADD(GF16_MUL(s22, s[4]), GF16_MUL(s33, s[2])));
1757 :
1758 0 : if (det)
1759 : {
1760 0 : det_inv = gf16_inv_table[det] << 4;
1761 :
1762 0 : s14 = GF16_MUL(s[0], s[3]);
1763 0 : s15 = GF16_MUL(s[0], s[4]);
1764 :
1765 0 : s23 = GF16_MUL(s[1], s[2]);
1766 0 : s24 = GF16_MUL(s[1], s[3]);
1767 0 : s25 = GF16_MUL(s[1], s[4]);
1768 :
1769 0 : s34 = GF16_MUL(s[2], s[3]);
1770 0 : s35 = GF16_MUL(s[2], s[4]);
1771 :
1772 0 : a = GF16_ADD(s35, s44) << 4;
1773 0 : b = GF16_ADD(s15, s33) << 4;
1774 0 : c = GF16_ADD(s13, s22) << 4;
1775 0 : d = GF16_ADD(s34, s25) << 4;
1776 0 : e = GF16_ADD(s23, s14) << 4;
1777 0 : f = GF16_ADD(s24, s33) << 4;
1778 :
1779 0 : aux = GF16_ADD(GF16_ADD(GF16_MUL0(a, s[3]), GF16_MUL0(d, s[4])), GF16_MUL0(f, s[5]));
1780 0 : elp[3] = GF16_MUL0(aux, det_inv);
1781 :
1782 0 : aux = GF16_ADD(GF16_ADD(GF16_MUL0(d, s[3]), GF16_MUL0(b, s[4])), GF16_MUL0(e, s[5]));
1783 0 : elp[2] = GF16_MUL0(aux, det_inv);
1784 :
1785 0 : aux = GF16_ADD(GF16_ADD(GF16_MUL0(f, s[3]), GF16_MUL0(e, s[4])), GF16_MUL0(c, s[5]));
1786 0 : elp[1] = GF16_MUL0(aux, det_inv);
1787 :
1788 0 : if (elp[3] == 0)
1789 : {
1790 0 : ret = t+1;
1791 : }
1792 : else
1793 : {
1794 0 : ret = 3;
1795 : }
1796 0 : break;
1797 : }
1798 :
1799 : /* assume two errors */
1800 0 : det = GF16_ADD(GF16_MUL(syndromes[0], syndromes[2]), GF16_MUL(syndromes[1], syndromes[1]));
1801 :
1802 0 : if (det)
1803 : {
1804 0 : det_inv = gf16_inv_table[det] << 4;
1805 :
1806 0 : aux = GF16_ADD(GF16_MUL(syndromes[1], syndromes[2]), GF16_MUL(syndromes[0], syndromes[3]));
1807 0 : elp[1] = GF16_MUL0(aux, det_inv);
1808 :
1809 0 : aux = GF16_ADD(GF16_MUL(syndromes[2], syndromes[2]), GF16_MUL(syndromes[1], syndromes[3]));
1810 0 : elp[2] = GF16_MUL0(aux, det_inv);
1811 :
1812 : /* check remaining LSF relations */
1813 0 : aux = GF16_ADD(GF16_ADD(GF16_MUL(elp[2], s[2]), GF16_MUL(elp[1], s[3])), s[4])
1814 0 : | GF16_ADD(GF16_ADD(GF16_MUL(elp[2], s[3]), GF16_MUL(elp[1], s[4])), s[5]);
1815 :
1816 0 : aux |= elp[2] == 0;
1817 :
1818 0 : if (aux != 0)
1819 : {
1820 0 : ret = t + 1;
1821 : }
1822 : else
1823 : {
1824 0 : ret = 2;
1825 : }
1826 0 : break;
1827 : }
1828 :
1829 : /* assume one error */
1830 0 : if (syndromes[0] != 0)
1831 : {
1832 0 : elp[1] = GF16_MUL(syndromes[1], gf16_inv_table[syndromes[0]]);
1833 :
1834 : /* check remaining LSF relations */
1835 0 : aux = GF16_ADD(GF16_MUL(elp[1], s[1]), s[2])
1836 0 : | GF16_ADD(GF16_MUL(elp[1], s[2]), s[3])
1837 0 : | GF16_ADD(GF16_MUL(elp[1], s[3]), s[4])
1838 0 : | GF16_ADD(GF16_MUL(elp[1], s[4]), s[5]);
1839 :
1840 0 : aux |= elp[1] == 0;
1841 :
1842 0 : if (aux != 0)
1843 : {
1844 0 : ret = t + 1;
1845 : }
1846 : else
1847 : {
1848 0 : ret = 1;
1849 : }
1850 0 : break;
1851 : }
1852 :
1853 0 : ret = t + 1;
1854 0 : break;
1855 : }
1856 0 : case 2:
1857 : {
1858 0 : all_s = s[0] | s[1] | s[2] | s[3];
1859 :
1860 0 : if (all_s == 0)
1861 : {
1862 0 : break;
1863 : }
1864 :
1865 : /* assume two errors */
1866 0 : det = GF16_ADD(GF16_MUL(syndromes[0], syndromes[2]), GF16_MUL(syndromes[1], syndromes[1]));
1867 :
1868 0 : if (det)
1869 : {
1870 0 : det_inv = gf16_inv_table[det] << 4;
1871 :
1872 0 : aux = GF16_ADD(GF16_MUL(syndromes[1], syndromes[2]), GF16_MUL(syndromes[0], syndromes[3]));
1873 0 : elp[1] = GF16_MUL0(aux, det_inv);
1874 :
1875 0 : aux = GF16_ADD(GF16_MUL(syndromes[2], syndromes[2]), GF16_MUL(syndromes[1], syndromes[3]));
1876 0 : elp[2] = GF16_MUL0(aux, det_inv);
1877 :
1878 0 : if (elp[2] == 0)
1879 : {
1880 0 : ret = t + 1;
1881 : }
1882 : else
1883 : {
1884 0 : ret = 2;
1885 : }
1886 0 : break;
1887 : }
1888 :
1889 : /* assume one error */
1890 0 : if (syndromes[0] != 0)
1891 : {
1892 0 : elp[1] = GF16_MUL(syndromes[1], gf16_inv_table[syndromes[0]]);
1893 :
1894 : /* check remaining LSF relation */
1895 0 : aux = GF16_ADD(GF16_MUL(elp[1], s[1]), s[2]) | GF16_ADD(GF16_MUL(elp[1], s[2]), s[3]);
1896 0 : aux |= elp[1] == 0;
1897 :
1898 0 : if (aux != 0)
1899 : {
1900 0 : ret = t + 1;
1901 : }
1902 : else
1903 : {
1904 0 : ret = 1;
1905 : }
1906 0 : break;
1907 : }
1908 :
1909 0 : ret = t + 1;
1910 0 : break;
1911 : }
1912 0 : case 1:
1913 : {
1914 0 : all_s = s[0] | s[1];
1915 :
1916 0 : if (all_s == 0)
1917 : {
1918 0 : break;
1919 : }
1920 :
1921 0 : if (syndromes[0] != 0)
1922 : {
1923 0 : elp[1] = GF16_MUL(syndromes[1], gf16_inv_table[syndromes[0]]);
1924 0 : if (elp[1] == 0)
1925 : {
1926 0 : ret = t + 1;
1927 : }
1928 : else
1929 : {
1930 0 : ret = 1;
1931 : }
1932 0 : break;
1933 : }
1934 :
1935 0 : ret = t + 1;
1936 0 : break;
1937 : }
1938 0 : default: assert(0 && "calculating elp of this degree not implemented");
1939 : }
1940 :
1941 :
1942 0 : return ret;
1943 : }
1944 :
1945 0 : FEC_STATIC LC3_INT16 rs16_factorize_elp(LC3_UINT8 *err_pos, LC3_UINT8 *elp, LC3_INT16 deg_elp, LC3_INT16 max_pos)
1946 : {
1947 : LC3_UINT8 beta, gamma;
1948 : LC3_INT16 zeros, err_pos0, err_pos1, err_pos2, ret;
1949 :
1950 0 : beta = 0;
1951 0 : gamma = 0;
1952 0 : zeros = 0;
1953 0 : ret = 0;
1954 :
1955 0 : switch (deg_elp)
1956 : {
1957 0 : case 0: break;
1958 :
1959 0 : case 1:
1960 0 : err_pos0 = gf16_log_g[elp[1]];
1961 0 : if (err_pos0 > max_pos)
1962 : {
1963 0 : ret = 1;
1964 0 : break;
1965 : }
1966 :
1967 0 : err_pos[0] = (LC3_UINT8)err_pos0;
1968 0 : break;
1969 :
1970 0 : case 2:
1971 0 : zeros = rs16_elp_deg2_table[elp[1] | (elp[2] << 4)];
1972 0 : if (zeros == 0)
1973 : {
1974 :
1975 0 : return 1;
1976 : }
1977 :
1978 0 : err_pos0 = zeros & 15;
1979 0 : err_pos1 = (zeros >> 4) & 15;
1980 :
1981 0 : if (err_pos0 > max_pos || err_pos1 > max_pos)
1982 : {
1983 0 : ret = 1;
1984 0 : break;
1985 : }
1986 :
1987 0 : err_pos[0] = (LC3_UINT8)err_pos0;
1988 0 : err_pos[1] = (LC3_UINT8)err_pos1;
1989 0 : break;
1990 :
1991 0 : case 3:
1992 : /* beta = a*a + b, gamma = a*b + c */
1993 0 : beta = GF16_ADD(GF16_MUL(elp[1], elp[1]), elp[2]);
1994 0 : gamma = GF16_ADD(GF16_MUL(elp[1], elp[2]), elp[3]);
1995 0 : zeros = rs16_elp_deg3_table[beta | gamma << 4];
1996 :
1997 0 : if (zeros == 0)
1998 : /* elp does not split over GF(16) or has multiple zeros */
1999 : {
2000 0 : ret = 1;
2001 0 : break;
2002 : }
2003 :
2004 : /* remove shift from zeros */
2005 0 : err_pos0 = GF16_ADD(zeros & 15, elp[1]);
2006 0 : err_pos1 = GF16_ADD((zeros >> 4) & 15, elp[1]);
2007 0 : err_pos2 = GF16_ADD((zeros >> 8) & 15, elp[1]);
2008 :
2009 0 : if (err_pos0 == 0 || err_pos1 == 0 || err_pos2 == 0)
2010 : {
2011 :
2012 0 : return 1;
2013 : }
2014 :
2015 0 : err_pos0 = gf16_log_g[err_pos0];
2016 0 : err_pos1 = gf16_log_g[err_pos1];
2017 0 : err_pos2 = gf16_log_g[err_pos2];
2018 :
2019 0 : if (err_pos0 > max_pos || err_pos1 > max_pos || err_pos2 > max_pos)
2020 : {
2021 0 : ret = 1;
2022 0 : break;
2023 : }
2024 :
2025 0 : err_pos[0] = (LC3_UINT8)err_pos0;
2026 0 : err_pos[1] = (LC3_UINT8)err_pos1;
2027 0 : err_pos[2] = (LC3_UINT8)err_pos2;
2028 :
2029 0 : break;
2030 :
2031 0 : default: assert(0 && "invalid degree in rs16_error_locator");
2032 : }
2033 :
2034 :
2035 0 : return ret;
2036 : }
2037 :
2038 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)
2039 : {
2040 : LC3_UINT8 det_inv;
2041 : LC3_UINT8 x0, x1, x2;
2042 : LC3_UINT8 x0sq, x1sq, x2sq;
2043 : LC3_UINT8 c0, c1, c2;
2044 : LC3_UINT8 s0, s1, s2;
2045 : LC3_UINT8 tmp;
2046 :
2047 : UNUSED(t);
2048 :
2049 0 : assert(deg_elp <= t);
2050 :
2051 0 : switch (deg_elp)
2052 : {
2053 0 : case 0: break;
2054 :
2055 0 : case 1:
2056 0 : err_symb[0] = GF16_MUL(gf16_g_pow[15 - err_pos[0]], syndromes[0]);
2057 :
2058 0 : break;
2059 :
2060 0 : case 2:
2061 0 : s0 = (LC3_UINT8) (syndromes[0] << 4);
2062 0 : s1 = (LC3_UINT8) (syndromes[1] << 4);
2063 :
2064 0 : x0 = gf16_g_pow[err_pos[0]];
2065 0 : x1 = gf16_g_pow[err_pos[1]];
2066 :
2067 0 : x0sq = GF16_MUL(x0, x0);
2068 0 : x1sq = GF16_MUL(x1, x1);
2069 :
2070 0 : tmp = GF16_ADD(GF16_MUL(x0sq, x1), GF16_MUL(x1sq, x0));
2071 0 : det_inv = gf16_inv_table[tmp] << 4;
2072 :
2073 0 : tmp = GF16_ADD(GF16_MUL0(x1sq, s0), GF16_MUL0(x1, s1));
2074 0 : err_symb[0] = GF16_MUL0(tmp, det_inv);
2075 :
2076 0 : tmp = GF16_ADD(GF16_MUL0(x0sq, s0), GF16_MUL0(x0, s1));
2077 0 : err_symb[1] = GF16_MUL0(tmp, det_inv);
2078 :
2079 0 : break;
2080 :
2081 0 : case 3:
2082 0 : s0 = syndromes[0] << 4;
2083 0 : s1 = syndromes[1] << 4;
2084 0 : s2 = syndromes[2] << 4;
2085 :
2086 0 : x0 = gf16_g_pow[err_pos[0]];
2087 0 : x1 = gf16_g_pow[err_pos[1]];
2088 0 : x2 = gf16_g_pow[err_pos[2]];
2089 :
2090 0 : x0sq = GF16_MUL(x0, x0);
2091 0 : x1sq = GF16_MUL(x1, x1);
2092 0 : x2sq = GF16_MUL(x2, x2);
2093 :
2094 0 : tmp = GF16_MUL(GF16_ADD(x1, x0), GF16_ADD(x2, x0));
2095 0 : tmp = GF16_MUL(GF16_ADD(x2, x1), tmp);
2096 0 : det_inv = gf16_inv_table[tmp] << 4;
2097 :
2098 0 : c0 = GF16_ADD(GF16_MUL(x1, x2sq), GF16_MUL(x2, x1sq));
2099 0 : c1 = GF16_ADD(x2sq, x1sq);
2100 0 : c2 = GF16_ADD(x2, x1);
2101 :
2102 0 : err_symb[0] = GF16_ADD(GF16_ADD(GF16_MUL0(c0, s0), GF16_MUL0(c1, s1)), GF16_MUL0(c2, s2));
2103 :
2104 0 : c0 = GF16_ADD(GF16_MUL(x0, x2sq), GF16_MUL(x2, x0sq));
2105 0 : c1 = GF16_ADD(x2sq, x0sq);
2106 0 : c2 = GF16_ADD(x2, x0);
2107 :
2108 0 : err_symb[1] = GF16_ADD(GF16_ADD(GF16_MUL0(c0, s0), GF16_MUL0(c1, s1)), GF16_MUL0(c2, s2));
2109 :
2110 0 : c0 = GF16_ADD(GF16_MUL(x0, x1sq), GF16_MUL(x1, x0sq));
2111 0 : c1 = GF16_ADD(x1sq, x0sq);
2112 0 : c2 = GF16_ADD(x1, x0);
2113 :
2114 0 : err_symb[2] = GF16_ADD(GF16_ADD(GF16_MUL0(c0, s0), GF16_MUL0(c1, s1)), GF16_MUL0(c2, s2));
2115 :
2116 0 : tmp = GF16_MUL0(err_symb[0], det_inv);
2117 0 : err_symb[0] = GF16_MUL(tmp, gf16_inv_table[x0]);
2118 :
2119 0 : tmp = GF16_MUL0(err_symb[1], det_inv);
2120 0 : err_symb[1] = GF16_MUL(tmp, gf16_inv_table[x1]);
2121 :
2122 0 : tmp = GF16_MUL0(err_symb[2], det_inv);
2123 0 : err_symb[2] = GF16_MUL(tmp, gf16_inv_table[x2]);
2124 :
2125 0 : break;
2126 :
2127 0 : default: assert(0 && "method not implemented\n"); break;
2128 : }
2129 :
2130 :
2131 0 : }
2132 :
2133 : /* hash functions for data validation */
2134 :
2135 : /* hamming distance 4 */
2136 : static const LC3_UINT32 crc14_mask[16] = {0, 17989, 35978, 51919, 71956, 89937, 103838, 119771,
2137 : 143912, 160877, 179874, 194791, 207676, 224633, 239542, 254451};
2138 :
2139 : /* hamming distance 4 */
2140 : static const LC3_UINT32 crc22_mask[16] = {0, 4788009, 9576018, 14356859, 19152036, 23933837, 28713718, 33500639,
2141 : 33650273, 38304072, 43214899, 47867674, 52775621, 57427436, 62346391, 67001278};
2142 :
2143 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)
2144 : {
2145 : LC3_UINT32 const *mask;
2146 : LC3_INT32 shift, i, fail;
2147 : LC3_UINT32 rem;
2148 :
2149 0 : fail = 0;
2150 0 : rem = 0;
2151 :
2152 0 : assert(hash_size > 0);
2153 :
2154 0 : switch (hash_size)
2155 : {
2156 0 : case 2:
2157 0 : shift = 14;
2158 0 : mask = crc14_mask;
2159 0 : break;
2160 0 : case 3:
2161 0 : shift = 22;
2162 0 : mask = crc22_mask;
2163 0 : break;
2164 0 : default:
2165 0 : shift = 0;
2166 0 : mask = 0;
2167 0 : assert(0 && "crc hash size not implemented");
2168 : }
2169 :
2170 : /* data array contains 4-bit words */
2171 0 : for (i = data_size - 1; i >= 0; i--)
2172 : {
2173 0 : rem = (rem << 4) ^ data[i];
2174 0 : rem ^= mask[(rem >> shift) & 15];
2175 : }
2176 :
2177 0 : rem = (rem << 4) ^ (epmr << 2);
2178 0 : rem ^= mask[(rem >> shift) & 15];
2179 :
2180 0 : for (i = 0; i < 2 * hash_size - 1; i++)
2181 : {
2182 0 : rem <<= 4;
2183 0 : rem ^= mask[(rem >> shift) & 15];
2184 : }
2185 :
2186 0 : rem ^= ((LC3_UINT32) epmr) << shift;
2187 :
2188 0 : if (check)
2189 : {
2190 : /* test hash value */
2191 0 : for (i = 0; i < 2 * hash_size; i++)
2192 : {
2193 0 : fail |= hash_val[i] ^ ((rem >> (4*i)) & 15);
2194 : }
2195 : }
2196 : else
2197 : {
2198 : /* write hash value */
2199 0 : for (i = 0; i < 2 * hash_size; i++)
2200 : {
2201 0 : hash_val[i] = (LC3_UINT8) ((rem >> (4*i)) & 15);
2202 : }
2203 : }
2204 :
2205 :
2206 0 : return fail;
2207 : }
2208 :
2209 : /* hamming distance = 4 */
2210 : static const LC3_UINT32 crc16_mask[16] = {0, 107243, 190269, 214486, 289937, 380538, 428972, 469319,
2211 : 579874, 621513, 671263, 761076, 832947, 857944, 938638, 1044581};
2212 :
2213 0 : FEC_STATIC LC3_INT16 crc2(LC3_UINT8 *data, LC3_INT16 data_size, LC3_UINT8 *hash_val, LC3_INT16 hash_size, LC3_INT16 check)
2214 : {
2215 : LC3_UINT32 const *mask;
2216 : LC3_INT32 shift, i, fail;
2217 : LC3_UINT32 rem;
2218 :
2219 0 : fail = 0;
2220 0 : rem = 0;
2221 :
2222 0 : assert(hash_size > 0);
2223 :
2224 0 : switch (hash_size)
2225 : {
2226 0 : case 2:
2227 0 : shift = 16;
2228 0 : mask = crc16_mask;
2229 0 : break;
2230 0 : default:
2231 0 : shift = 0;
2232 0 : mask = 0;
2233 0 : assert(0 && "crc hash size not implemented");
2234 : }
2235 :
2236 : /* data array contains 4-bit words */
2237 0 : for (i = data_size - 1; i >= 0; i--)
2238 : {
2239 0 : rem = (rem << 4) ^ data[i];
2240 0 : rem ^= mask[(rem >> shift) & 15];
2241 : }
2242 :
2243 0 : for (i = 0; i < 2 * hash_size; i++)
2244 : {
2245 0 : rem <<= 4;
2246 0 : rem ^= mask[(rem >> shift) & 15];
2247 : }
2248 :
2249 0 : if (check)
2250 : {
2251 : /* test hash value */
2252 0 : for (i = 0; i < 2 * hash_size; i++)
2253 : {
2254 0 : fail |= hash_val[i] ^ ((rem >> (4*i)) & 15);
2255 : }
2256 : }
2257 : else
2258 : {
2259 : /* write hash value */
2260 0 : for (i = 0; i < 2 * hash_size; i++)
2261 : {
2262 0 : hash_val[i] = (LC3_UINT8) ((rem >> (4*i)) & 15);
2263 : }
2264 : }
2265 :
2266 :
2267 0 : return fail;
2268 : }
2269 :
2270 : /* simple float implementation */
2271 0 : FEC_STATIC simple_float simple_float_mul(simple_float op1, simple_float op2)
2272 : {
2273 : simple_float rop;
2274 : LC3_INT32 aux;
2275 :
2276 0 : aux = (op1.mantissa * op2.mantissa) >> 14;
2277 0 : rop.exponent = op1.exponent + op2.exponent;
2278 0 : if (aux & 32768L)
2279 : {
2280 0 : aux >>= 1;
2281 0 : rop.exponent ++;
2282 : }
2283 0 : rop.mantissa = (LC3_INT16) aux;
2284 :
2285 :
2286 0 : return rop;
2287 : }
2288 :
2289 : /* Auxiliary */
2290 :
2291 0 : FEC_STATIC LC3_INT16 simple_float_cmp(simple_float op1, simple_float op2)
2292 : /* returns 1 if op1 > op2, 0 if op1 = op2, and -1 if op1 < op2 */
2293 : {
2294 : LC3_INT16 rval;
2295 : LC3_INT16 mdiff;
2296 : LC3_INT16 ediff;
2297 :
2298 0 : rval = 0;
2299 :
2300 0 : ediff = op1.exponent - op2.exponent;
2301 0 : mdiff = (LC3_INT16) op1.mantissa - (LC3_INT16) op2.mantissa;
2302 :
2303 0 : if (ediff == 0)
2304 : {
2305 0 : if (mdiff > 0)
2306 : {
2307 0 : rval = 1;
2308 : }
2309 0 : if (mdiff < 0)
2310 : {
2311 0 : rval = -1;
2312 : }
2313 : }
2314 : else
2315 : {
2316 0 : if (ediff > 0)
2317 : {
2318 0 : rval = 1;
2319 : }
2320 0 : if (ediff < 0)
2321 : {
2322 0 : rval = -1;
2323 : }
2324 : }
2325 :
2326 :
2327 0 : return rval;
2328 : }
2329 :
|