1 /*
2 * Copyright (c) 2007 - 2015 Joseph Gaeddert
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a copy
5 * of this software and associated documentation files (the "Software"), to deal
6 * in the Software without restriction, including without limitation the rights
7 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 * copies of the Software, and to permit persons to whom the Software is
9 * furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 * THE SOFTWARE.
21 */
22
23 //
24 // FEC (generic functions)
25 //
26
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30
31 #include "liquid.internal.h"
32
33 // object-independent methods
34
35 const char * fec_scheme_str[LIQUID_FEC_NUM_SCHEMES][2] = {
36 // short name, long name
37 {"unknown", "unknown"},
38 {"none", "none"},
39 {"rep3", "repeat(3)"},
40 {"rep5", "repeat(5)"},
41 {"h74", "Hamming(7,4)"},
42 {"h84", "Hamming(8,4)"},
43 {"h128", "Hamming(12,8)"},
44 {"g2412", "Golay(24,12)"},
45 {"secded2216", "SEC-DEC(22,16)"},
46 {"secded3932", "SEC-DEC(39,32)"},
47 {"secded7264", "SEC-DEC(72,64)"},
48 {"v27", "convolutional r1/2 K=7"},
49 {"v29", "convolutional r1/2 K=9"},
50 {"v39", "convolutional r1/3 K=9"},
51 {"v615", "convolutional r1/6 K=15"},
52 {"v27p23", "convolutional r2/3 K=7 (punctured)"},
53 {"v27p34", "convolutional r3/4 K=7 (punctured)"},
54 {"v27p45", "convolutional r4/5 K=7 (punctured)"},
55 {"v27p56", "convolutional r5/6 K=7 (punctured)"},
56 {"v27p67", "convolutional r6/7 K=7 (punctured)"},
57 {"v27p78", "convolutional r7/8 K=7 (punctured)"},
58 {"v29p23", "convolutional r2/3 K=9 (punctured)"},
59 {"v29p34", "convolutional r3/4 K=9 (punctured)"},
60 {"v29p45", "convolutional r4/5 K=9 (punctured)"},
61 {"v29p56", "convolutional r5/6 K=9 (punctured)"},
62 {"v29p67", "convolutional r6/7 K=9 (punctured)"},
63 {"v29p78", "convolutional r7/8 K=9 (punctured)"},
64 {"rs8", "Reed-Solomon, 223/255"}
65 };
66
67 // Print compact list of existing and available fec schemes
liquid_print_fec_schemes()68 void liquid_print_fec_schemes()
69 {
70 unsigned int i;
71 unsigned int len = 10;
72
73 // print all available MOD schemes
74 printf(" ");
75 for (i=0; i<LIQUID_FEC_NUM_SCHEMES; i++) {
76 #if !LIBFEC_ENABLED
77 if ( fec_scheme_is_convolutional(i) || fec_scheme_is_reedsolomon(i) )
78 continue;
79 #endif
80 printf("%s", fec_scheme_str[i][0]);
81
82 if (i != LIQUID_FEC_NUM_SCHEMES-1)
83 printf(", ");
84
85 len += strlen(fec_scheme_str[i][0]);
86 if (len > 48 && i != LIQUID_FEC_NUM_SCHEMES-1) {
87 len = 10;
88 printf("\n ");
89 }
90 }
91 printf("\n");
92 }
93
94
liquid_getopt_str2fec(const char * _str)95 fec_scheme liquid_getopt_str2fec(const char * _str)
96 {
97 // compare each string to short name
98 unsigned int i;
99 for (i=0; i<LIQUID_FEC_NUM_SCHEMES; i++) {
100 if (strcmp(_str,fec_scheme_str[i][0])==0) {
101 return i;
102 }
103 }
104
105 fprintf(stderr,"warning: liquid_getopt_str2fec(), unknown/unsupported fec scheme : %s\n", _str);
106 return LIQUID_FEC_UNKNOWN;
107 }
108
109 // is scheme convolutional?
fec_scheme_is_convolutional(fec_scheme _scheme)110 int fec_scheme_is_convolutional(fec_scheme _scheme)
111 {
112 switch (_scheme) {
113 // convolutional codes (punctured or otherwise)
114 case LIQUID_FEC_CONV_V27:
115 case LIQUID_FEC_CONV_V29:
116 case LIQUID_FEC_CONV_V39:
117 case LIQUID_FEC_CONV_V615:
118 case LIQUID_FEC_CONV_V27P23:
119 case LIQUID_FEC_CONV_V27P34:
120 case LIQUID_FEC_CONV_V27P45:
121 case LIQUID_FEC_CONV_V27P56:
122 case LIQUID_FEC_CONV_V27P67:
123 case LIQUID_FEC_CONV_V27P78:
124
125 case LIQUID_FEC_CONV_V29P23:
126 case LIQUID_FEC_CONV_V29P34:
127 case LIQUID_FEC_CONV_V29P45:
128 case LIQUID_FEC_CONV_V29P56:
129 case LIQUID_FEC_CONV_V29P67:
130 case LIQUID_FEC_CONV_V29P78:
131 return 1;
132
133 default:;
134 }
135
136 return 0;
137 }
138
139 // is scheme punctured?
fec_scheme_is_punctured(fec_scheme _scheme)140 int fec_scheme_is_punctured(fec_scheme _scheme)
141 {
142 switch (_scheme) {
143 // convolutional codes (punctured)
144 case LIQUID_FEC_CONV_V27P23:
145 case LIQUID_FEC_CONV_V27P34:
146 case LIQUID_FEC_CONV_V27P45:
147 case LIQUID_FEC_CONV_V27P56:
148 case LIQUID_FEC_CONV_V27P67:
149 case LIQUID_FEC_CONV_V27P78:
150
151 case LIQUID_FEC_CONV_V29P23:
152 case LIQUID_FEC_CONV_V29P34:
153 case LIQUID_FEC_CONV_V29P45:
154 case LIQUID_FEC_CONV_V29P56:
155 case LIQUID_FEC_CONV_V29P67:
156 case LIQUID_FEC_CONV_V29P78:
157 return 1;
158
159 default:;
160 }
161
162 return 0;
163 }
164
165 // is scheme Reed-Solomon?
fec_scheme_is_reedsolomon(fec_scheme _scheme)166 int fec_scheme_is_reedsolomon(fec_scheme _scheme)
167 {
168 switch (_scheme) {
169 // Reed-Solomon codes
170 case LIQUID_FEC_RS_M8:
171 return 1;
172 default:;
173 }
174 return 0;
175 }
176
177 // is scheme Hamming?
fec_scheme_is_hamming(fec_scheme _scheme)178 int fec_scheme_is_hamming(fec_scheme _scheme)
179 {
180 switch (_scheme) {
181 case LIQUID_FEC_HAMMING74:
182 case LIQUID_FEC_HAMMING84:
183 case LIQUID_FEC_HAMMING128:
184 return 1;
185 default:;
186 }
187 return 0;
188 }
189
190 // is scheme repeat?
fec_scheme_is_repeat(fec_scheme _scheme)191 int fec_scheme_is_repeat(fec_scheme _scheme)
192 {
193 switch (_scheme) {
194 case LIQUID_FEC_REP3:
195 case LIQUID_FEC_REP5:
196 return 1;
197 default:;
198 }
199 return 0;
200 }
201
202
203 // return the encoded message length using a particular error-
204 // correction scheme (object-independent method)
205 // _scheme : forward error-correction scheme
206 // _msg_len : raw, uncoded message length
fec_get_enc_msg_length(fec_scheme _scheme,unsigned int _msg_len)207 unsigned int fec_get_enc_msg_length(fec_scheme _scheme,
208 unsigned int _msg_len)
209 {
210 switch (_scheme) {
211 case LIQUID_FEC_UNKNOWN: return 0;
212 case LIQUID_FEC_NONE: return _msg_len;
213 case LIQUID_FEC_REP3: return 3*_msg_len;
214 case LIQUID_FEC_REP5: return 5*_msg_len;
215 case LIQUID_FEC_HAMMING74: return fec_block_get_enc_msg_len(_msg_len,4,7);
216 case LIQUID_FEC_HAMMING84: return fec_block_get_enc_msg_len(_msg_len,4,8);
217 case LIQUID_FEC_HAMMING128: return fec_block_get_enc_msg_len(_msg_len,8,12);
218 case LIQUID_FEC_GOLAY2412: return fec_block_get_enc_msg_len(_msg_len,12,24);
219 case LIQUID_FEC_SECDED2216: return _msg_len + _msg_len/2 + ((_msg_len%2) ? 1 : 0);
220 case LIQUID_FEC_SECDED3932: return _msg_len + _msg_len/4 + ((_msg_len%4) ? 1 : 0);
221 case LIQUID_FEC_SECDED7264: return _msg_len + _msg_len/8 + ((_msg_len%8) ? 1 : 0);
222
223 #if LIBFEC_ENABLED
224 // convolutional codes
225 case LIQUID_FEC_CONV_V27: return 2*_msg_len + 2; // (K-1)/r=12, round up to 2 bytes
226 case LIQUID_FEC_CONV_V29: return 2*_msg_len + 2; // (K-1)/r=16, 2 bytes
227 case LIQUID_FEC_CONV_V39: return 3*_msg_len + 3; // (K-1)/r=24, 3 bytes
228 case LIQUID_FEC_CONV_V615: return 6*_msg_len + 11; // (K-1)/r=84, round up to 11 bytes
229 case LIQUID_FEC_CONV_V27P23: return fec_conv_get_enc_msg_len(_msg_len,7,2);
230 case LIQUID_FEC_CONV_V27P34: return fec_conv_get_enc_msg_len(_msg_len,7,3);
231 case LIQUID_FEC_CONV_V27P45: return fec_conv_get_enc_msg_len(_msg_len,7,4);
232 case LIQUID_FEC_CONV_V27P56: return fec_conv_get_enc_msg_len(_msg_len,7,5);
233 case LIQUID_FEC_CONV_V27P67: return fec_conv_get_enc_msg_len(_msg_len,7,6);
234 case LIQUID_FEC_CONV_V27P78: return fec_conv_get_enc_msg_len(_msg_len,7,7);
235
236 case LIQUID_FEC_CONV_V29P23: return fec_conv_get_enc_msg_len(_msg_len,9,2);
237 case LIQUID_FEC_CONV_V29P34: return fec_conv_get_enc_msg_len(_msg_len,9,3);
238 case LIQUID_FEC_CONV_V29P45: return fec_conv_get_enc_msg_len(_msg_len,9,4);
239 case LIQUID_FEC_CONV_V29P56: return fec_conv_get_enc_msg_len(_msg_len,9,5);
240 case LIQUID_FEC_CONV_V29P67: return fec_conv_get_enc_msg_len(_msg_len,9,6);
241 case LIQUID_FEC_CONV_V29P78: return fec_conv_get_enc_msg_len(_msg_len,9,7);
242
243 // Reed-Solomon codes
244 case LIQUID_FEC_RS_M8: return fec_rs_get_enc_msg_len(_msg_len,32,255,223);
245 #else
246 case LIQUID_FEC_CONV_V27:
247 case LIQUID_FEC_CONV_V29:
248 case LIQUID_FEC_CONV_V39:
249 case LIQUID_FEC_CONV_V615:
250
251 case LIQUID_FEC_CONV_V27P23:
252 case LIQUID_FEC_CONV_V27P34:
253 case LIQUID_FEC_CONV_V27P45:
254 case LIQUID_FEC_CONV_V27P56:
255 case LIQUID_FEC_CONV_V27P67:
256 case LIQUID_FEC_CONV_V27P78:
257
258 case LIQUID_FEC_CONV_V29P23:
259 case LIQUID_FEC_CONV_V29P34:
260 case LIQUID_FEC_CONV_V29P45:
261 case LIQUID_FEC_CONV_V29P56:
262 case LIQUID_FEC_CONV_V29P67:
263 case LIQUID_FEC_CONV_V29P78:
264 fprintf(stderr, "error: fec_get_enc_msg_length(), convolutional codes unavailable (install libfec)\n");
265 exit(-1);
266
267 case LIQUID_FEC_RS_M8:
268 fprintf(stderr, "error: fec_get_enc_msg_length(), Reed-Solomon codes unavailable (install libfec)\n");
269 exit(-1);
270 #endif
271 default:
272 printf("error: fec_get_enc_msg_length(), unknown/unsupported scheme: %d\n", _scheme);
273 exit(-1);
274 }
275
276 return 0;
277 }
278
279 // compute encoded message length for block codes
280 // _dec_msg_len : decoded message length (bytes)
281 // _m : input block size (bits)
282 // _k : output block size (bits)
fec_block_get_enc_msg_len(unsigned int _dec_msg_len,unsigned int _m,unsigned int _k)283 unsigned int fec_block_get_enc_msg_len(unsigned int _dec_msg_len,
284 unsigned int _m,
285 unsigned int _k)
286 {
287 // validate input
288 if (_m == 0) {
289 fprintf(stderr,"fec_block_get_enc_msg_len(), input block size cannot be zero\n");
290 exit(1);
291 } else if (_k < _m) {
292 fprintf(stderr,"fec_block_get_enc_msg_len(), output block size cannot be smaller than input\n");
293 exit(1);
294 }
295
296 // compute total number of bits in decoded message
297 unsigned int num_bits_in = _dec_msg_len*8;
298
299 // compute total number of blocks: ceil(num_bits_in/_m)
300 unsigned int num_blocks = num_bits_in / _m + (num_bits_in%_m ? 1 : 0);
301
302 // compute total number of bits out
303 unsigned int num_bits_out = num_blocks * _k;
304
305 // compute total number of bytes out: ceil(num_bits_out/8)
306 unsigned int num_bytes_out = num_bits_out/8 + (num_bits_out%8 ? 1 : 0);
307 #if 0
308 printf("fec_block_get_enc_msg_len(%u,%u,%u)\n", _dec_msg_len, _m, _k);
309 printf(" dec msg len : %u bytes\n", _dec_msg_len);
310 printf(" m : %u bits\n", _m);
311 printf(" k : %u bits\n", _k);
312 printf(" num bits in : %u bits\n", num_bits_in);
313 printf(" num blocks : %u\n", num_blocks);
314 printf(" num bits out: %u bits\n", num_bits_out);
315 printf(" enc msg len : %u bytes\n", num_bytes_out);
316 #endif
317 return num_bytes_out;
318 }
319
320 // compute encoded message length for convolutional codes
321 // _dec_msg_len : decoded message length
322 // _K : constraint length
323 // _p : puncturing rate, r = _p / (_p+1)
fec_conv_get_enc_msg_len(unsigned int _dec_msg_len,unsigned int _K,unsigned int _p)324 unsigned int fec_conv_get_enc_msg_len(unsigned int _dec_msg_len,
325 unsigned int _K,
326 unsigned int _p)
327 {
328 unsigned int num_bits_in = _dec_msg_len*8;
329 unsigned int n = num_bits_in + _K - 1;
330 unsigned int num_bits_out = n + (n+_p-1)/_p;
331 unsigned int num_bytes_out = num_bits_out/8 + (num_bits_out%8 ? 1 : 0);
332 #if 0
333 printf("msg len : %3u\n", _dec_msg_len);
334 printf("num bits in : %3u\n", num_bits_in);
335 printf("n (constraint): %3u\n", n);
336 printf("num bits out: %3u", num_bits_out);
337 printf(" = n+(n+p-1)/p = %u+(%u+%u-1)/%u\n", n,n,_p,_p);
338 printf("num bytes out: %3u\n", num_bytes_out);
339 #endif
340 return num_bytes_out;
341 }
342
343 // compute encoded message length for Reed-Solomon codes
344 // _dec_msg_len : decoded message length
345 // _nroots : number of roots in polynomial
346 // _nn :
347 // _kk :
348 // Example : if we are using the 8-bit code,
349 // _nroots = 32
350 // _nn = 255
351 // _kk = 223
352 // Let _dec_msg_len = 1024, then
353 // num_blocks = ceil(1024/223)
354 // = ceil(4.5919)
355 // = 5
356 // dec_block_len = ceil(1024/num_blocks)
357 // = ceil(204.8)
358 // = 205
359 // enc_block_len = dec_block_len + nroots
360 // = 237
361 // enc_msg_len = num_blocks * enc_block_len
362 // = 1185
fec_rs_get_enc_msg_len(unsigned int _dec_msg_len,unsigned int _nroots,unsigned int _nn,unsigned int _kk)363 unsigned int fec_rs_get_enc_msg_len(unsigned int _dec_msg_len,
364 unsigned int _nroots,
365 unsigned int _nn,
366 unsigned int _kk)
367 {
368 // validate input
369 if (_dec_msg_len == 0) {
370 fprintf(stderr,"error: fec_rs_get_enc_msg_len(), _dec_msg_len must be greater than 0\n");
371 exit(1);
372 }
373
374 div_t d;
375
376 // compute the number of blocks in the full message sequence
377 d = div(_dec_msg_len, _kk);
378 unsigned int num_blocks = d.quot + (d.rem==0 ? 0 : 1);
379
380 // compute the length of each decoded block
381 d = div(_dec_msg_len, num_blocks);
382 unsigned int dec_block_len = d.quot + (d.rem == 0 ? 0 : 1);
383
384 // compute the encoded block length
385 unsigned int enc_block_len = dec_block_len + _nroots;
386
387 // compute the number of bytes in the full encoded message
388 unsigned int enc_msg_len = enc_block_len * num_blocks;
389 #if 0
390 printf("dec_msg_len : %u\n", _dec_msg_len);
391 printf("num_blocks : %u\n", num_blocks);
392 printf("dec_block_len : %u\n", dec_block_len);
393 printf("enc_block_len : %u\n", enc_block_len);
394 printf("enc_msg_len : %u\n", enc_msg_len);
395 #endif
396 return enc_msg_len;
397 }
398
399
400 // get the theoretical rate of a particular forward error-
401 // correction scheme (object-independent method)
fec_get_rate(fec_scheme _scheme)402 float fec_get_rate(fec_scheme _scheme)
403 {
404 switch (_scheme) {
405 case LIQUID_FEC_UNKNOWN: return 0;
406 case LIQUID_FEC_NONE: return 1.;
407 case LIQUID_FEC_REP3: return 1./3.;
408 case LIQUID_FEC_REP5: return 1./5.;
409 case LIQUID_FEC_HAMMING74: return 4./7.;
410 case LIQUID_FEC_HAMMING84: return 4./8.;
411 case LIQUID_FEC_HAMMING128: return 8./12.;
412 case LIQUID_FEC_GOLAY2412: return 1./2.;
413 case LIQUID_FEC_SECDED2216: return 2./3.; // ultimately 16/22 ~ 0.72727
414 case LIQUID_FEC_SECDED3932: return 4./5.; // ultimately 32/39 ~ 0.82051
415 case LIQUID_FEC_SECDED7264: return 8./9.;
416
417 // convolutional codes
418 #if LIBFEC_ENABLED
419 case LIQUID_FEC_CONV_V27: return 1./2.;
420 case LIQUID_FEC_CONV_V29: return 1./2.;
421 case LIQUID_FEC_CONV_V39: return 1./3.;
422 case LIQUID_FEC_CONV_V615: return 1./6.;
423 case LIQUID_FEC_CONV_V27P23: return 2./3.;
424 case LIQUID_FEC_CONV_V27P34: return 3./4.;
425 case LIQUID_FEC_CONV_V27P45: return 4./5.;
426 case LIQUID_FEC_CONV_V27P56: return 5./6.;
427 case LIQUID_FEC_CONV_V27P67: return 6./7.;
428 case LIQUID_FEC_CONV_V27P78: return 7./8.;
429 case LIQUID_FEC_CONV_V29P23: return 2./3.;
430 case LIQUID_FEC_CONV_V29P34: return 3./4.;
431 case LIQUID_FEC_CONV_V29P45: return 4./5.;
432 case LIQUID_FEC_CONV_V29P56: return 5./6.;
433 case LIQUID_FEC_CONV_V29P67: return 6./7.;
434 case LIQUID_FEC_CONV_V29P78: return 7./8.;
435
436 // Reed-Solomon codes
437 case LIQUID_FEC_RS_M8: return 223./255.;
438 #else
439 case LIQUID_FEC_CONV_V27:
440 case LIQUID_FEC_CONV_V29:
441 case LIQUID_FEC_CONV_V39:
442 case LIQUID_FEC_CONV_V615:
443
444 case LIQUID_FEC_CONV_V27P23:
445 case LIQUID_FEC_CONV_V27P34:
446 case LIQUID_FEC_CONV_V27P45:
447 case LIQUID_FEC_CONV_V27P56:
448 case LIQUID_FEC_CONV_V27P67:
449 case LIQUID_FEC_CONV_V27P78:
450
451 case LIQUID_FEC_CONV_V29P23:
452 case LIQUID_FEC_CONV_V29P34:
453 case LIQUID_FEC_CONV_V29P45:
454 case LIQUID_FEC_CONV_V29P56:
455 case LIQUID_FEC_CONV_V29P67:
456 case LIQUID_FEC_CONV_V29P78:
457 fprintf(stderr,"error: fec_get_rate(), convolutional codes unavailable (install libfec)\n");
458 exit(-1);
459
460 case LIQUID_FEC_RS_M8:
461 fprintf(stderr,"error: fec_get_rate(), Reed-Solomon codes unavailable (install libfec)\n");
462 exit(-1);
463 #endif
464
465 default:
466 printf("error: fec_get_rate(), unknown/unsupported scheme: %d\n", _scheme);
467 exit(-1);
468 }
469 return 0;
470 }
471
472 // create a fec object of a particular scheme
473 // _scheme : error-correction scheme
474 // _opts : (ignored)
fec_create(fec_scheme _scheme,void * _opts)475 fec fec_create(fec_scheme _scheme, void *_opts)
476 {
477 switch (_scheme) {
478 case LIQUID_FEC_UNKNOWN:
479 printf("error: fec_create(), cannot create fec object of type \"UNKNOWN\"\n");
480 exit(-1);
481 case LIQUID_FEC_NONE:
482 return fec_pass_create(NULL);
483 case LIQUID_FEC_REP3:
484 return fec_rep3_create(_opts);
485 case LIQUID_FEC_REP5:
486 return fec_rep5_create(_opts);
487 case LIQUID_FEC_HAMMING74:
488 return fec_hamming74_create(_opts);
489 case LIQUID_FEC_HAMMING84:
490 return fec_hamming84_create(_opts);
491 case LIQUID_FEC_HAMMING128:
492 return fec_hamming128_create(_opts);
493
494 case LIQUID_FEC_GOLAY2412:
495 return fec_golay2412_create(_opts);
496
497 // SEC-DED codecs (single error correction, double error detection)
498 case LIQUID_FEC_SECDED2216:
499 return fec_secded2216_create(_opts);
500 case LIQUID_FEC_SECDED3932:
501 return fec_secded3932_create(_opts);
502 case LIQUID_FEC_SECDED7264:
503 return fec_secded7264_create(_opts);
504
505 // convolutional codes
506 #if LIBFEC_ENABLED
507 case LIQUID_FEC_CONV_V27:
508 case LIQUID_FEC_CONV_V29:
509 case LIQUID_FEC_CONV_V39:
510 case LIQUID_FEC_CONV_V615:
511 return fec_conv_create(_scheme);
512
513 // punctured
514 case LIQUID_FEC_CONV_V27P23:
515 case LIQUID_FEC_CONV_V27P34:
516 case LIQUID_FEC_CONV_V27P45:
517 case LIQUID_FEC_CONV_V27P56:
518 case LIQUID_FEC_CONV_V27P67:
519 case LIQUID_FEC_CONV_V27P78:
520
521 case LIQUID_FEC_CONV_V29P23:
522 case LIQUID_FEC_CONV_V29P34:
523 case LIQUID_FEC_CONV_V29P45:
524 case LIQUID_FEC_CONV_V29P56:
525 case LIQUID_FEC_CONV_V29P67:
526 case LIQUID_FEC_CONV_V29P78:
527 return fec_conv_punctured_create(_scheme);
528
529 // Reed-Solomon codes
530 case LIQUID_FEC_RS_M8:
531 return fec_rs_create(_scheme);
532 #else
533 case LIQUID_FEC_CONV_V27:
534 case LIQUID_FEC_CONV_V29:
535 case LIQUID_FEC_CONV_V39:
536 case LIQUID_FEC_CONV_V615:
537
538 case LIQUID_FEC_CONV_V27P23:
539 case LIQUID_FEC_CONV_V27P34:
540 case LIQUID_FEC_CONV_V27P45:
541 case LIQUID_FEC_CONV_V27P56:
542 case LIQUID_FEC_CONV_V27P67:
543 case LIQUID_FEC_CONV_V27P78:
544
545 case LIQUID_FEC_CONV_V29P23:
546 case LIQUID_FEC_CONV_V29P34:
547 case LIQUID_FEC_CONV_V29P45:
548 case LIQUID_FEC_CONV_V29P56:
549 case LIQUID_FEC_CONV_V29P67:
550 case LIQUID_FEC_CONV_V29P78:
551 fprintf(stderr,"error: fec_create(), convolutional codes unavailable (install libfec)\n");
552 exit(-1);
553
554 case LIQUID_FEC_RS_M8:
555 fprintf(stderr,"error: fec_create(), Reed-Solomon codes unavailable (install libfec)\n");
556 exit(-1);
557 #endif
558
559 default:
560 printf("error: fec_create(), unknown/unsupported scheme: %d\n", _scheme);
561 exit(-1);
562 }
563
564 // should never get to this point, but return NULL to keep
565 // compiler happy
566 return NULL;
567 }
568
569 // recreate a fec object
570 // _q : initial fec object
571 // _scheme : new scheme
572 // _opts : options (ignored)
fec_recreate(fec _q,fec_scheme _scheme,void * _opts)573 fec fec_recreate(fec _q,
574 fec_scheme _scheme,
575 void *_opts)
576 {
577 if (_q->scheme != _scheme) {
578 // destroy old object and create new one
579 fec_destroy(_q);
580 _q = fec_create(_scheme,_opts);
581 }
582
583 // scheme hasn't changed; just return original object
584 return _q;
585 }
586
587 // destroy fec object
fec_destroy(fec _q)588 void fec_destroy(fec _q)
589 {
590 switch (_q->scheme) {
591 case LIQUID_FEC_UNKNOWN:
592 printf("error: fec_destroy(), cannot destroy fec object of type \"UNKNOWN\"\n");
593 exit(-1);
594 case LIQUID_FEC_NONE:
595 fec_pass_destroy(_q);
596 return;
597 case LIQUID_FEC_REP3:
598 fec_rep3_destroy(_q);
599 return;
600 case LIQUID_FEC_REP5:
601 fec_rep5_destroy(_q);
602 return;
603 case LIQUID_FEC_HAMMING74:
604 fec_hamming74_destroy(_q);
605 return;
606 case LIQUID_FEC_HAMMING84:
607 fec_hamming84_destroy(_q);
608 return;
609 case LIQUID_FEC_HAMMING128:
610 fec_hamming128_destroy(_q);
611 return;
612
613 case LIQUID_FEC_GOLAY2412:
614 fec_golay2412_destroy(_q);
615 return;
616
617 // SEC-DED codecs (single error correction, double error detection)
618 case LIQUID_FEC_SECDED2216:
619 fec_secded2216_destroy(_q);
620 return;
621 case LIQUID_FEC_SECDED3932:
622 fec_secded3932_destroy(_q);
623 return;
624 case LIQUID_FEC_SECDED7264:
625 fec_secded7264_destroy(_q);
626 return;
627
628 // convolutional codes
629 #if LIBFEC_ENABLED
630 case LIQUID_FEC_CONV_V27:
631 case LIQUID_FEC_CONV_V29:
632 case LIQUID_FEC_CONV_V39:
633 case LIQUID_FEC_CONV_V615:
634 fec_conv_destroy(_q);
635 return;
636
637 // punctured
638 case LIQUID_FEC_CONV_V27P23:
639 case LIQUID_FEC_CONV_V27P34:
640 case LIQUID_FEC_CONV_V27P45:
641 case LIQUID_FEC_CONV_V27P56:
642 case LIQUID_FEC_CONV_V27P67:
643 case LIQUID_FEC_CONV_V27P78:
644
645 case LIQUID_FEC_CONV_V29P23:
646 case LIQUID_FEC_CONV_V29P34:
647 case LIQUID_FEC_CONV_V29P45:
648 case LIQUID_FEC_CONV_V29P56:
649 case LIQUID_FEC_CONV_V29P67:
650 case LIQUID_FEC_CONV_V29P78:
651 fec_conv_punctured_destroy(_q);
652 return;
653
654 // Reed-Solomon codes
655 case LIQUID_FEC_RS_M8:
656 fec_rs_destroy(_q);
657 return;
658 #else
659 case LIQUID_FEC_CONV_V27:
660 case LIQUID_FEC_CONV_V29:
661 case LIQUID_FEC_CONV_V39:
662 case LIQUID_FEC_CONV_V615:
663
664 case LIQUID_FEC_CONV_V27P23:
665 case LIQUID_FEC_CONV_V27P34:
666 case LIQUID_FEC_CONV_V27P45:
667 case LIQUID_FEC_CONV_V27P56:
668 case LIQUID_FEC_CONV_V27P67:
669 case LIQUID_FEC_CONV_V27P78:
670
671 case LIQUID_FEC_CONV_V29P23:
672 case LIQUID_FEC_CONV_V29P34:
673 case LIQUID_FEC_CONV_V29P45:
674 case LIQUID_FEC_CONV_V29P56:
675 case LIQUID_FEC_CONV_V29P67:
676 case LIQUID_FEC_CONV_V29P78:
677 fprintf(stderr,"error: fec_destroy(), convolutional codes unavailable (install libfec)\n");
678 exit(-1);
679
680 case LIQUID_FEC_RS_M8:
681 fprintf(stderr,"error: fec_destroy(), Reed-Solomon codes unavailable (install libfec)\n");
682 exit(-1);
683 #endif
684
685 default:
686 printf("error: fec_destroy(), unknown/unsupported scheme: %d\n", _q->scheme);
687 exit(-1);
688 }
689 }
690
691 // print basic fec object internals
fec_print(fec _q)692 void fec_print(fec _q)
693 {
694 printf("fec: %s [rate: %4.3f]\n",
695 fec_scheme_str[_q->scheme][1],
696 _q->rate);
697 }
698
699 // encode a block of data using a fec scheme
700 // _q : fec object
701 // _dec_msg_len : decoded message length
702 // _msg_dec : decoded message
703 // _msg_enc : encoded message
fec_encode(fec _q,unsigned int _dec_msg_len,unsigned char * _msg_dec,unsigned char * _msg_enc)704 void fec_encode(fec _q,
705 unsigned int _dec_msg_len,
706 unsigned char * _msg_dec,
707 unsigned char * _msg_enc)
708 {
709 // call internal encoding method
710 _q->encode_func(_q, _dec_msg_len, _msg_dec, _msg_enc);
711 }
712
713 // decode a block of data using a fec scheme
714 // _q : fec object
715 // _dec_msg_len : decoded message length
716 // _msg_enc : encoded message
717 // _msg_dec : decoded message
fec_decode(fec _q,unsigned int _dec_msg_len,unsigned char * _msg_enc,unsigned char * _msg_dec)718 void fec_decode(fec _q,
719 unsigned int _dec_msg_len,
720 unsigned char * _msg_enc,
721 unsigned char * _msg_dec)
722 {
723 // call internal decoding method
724 _q->decode_func(_q, _dec_msg_len, _msg_enc, _msg_dec);
725 }
726
727 // decode a block of data using a fec scheme
728 // _q : fec object
729 // _dec_msg_len : decoded message length
730 // _msg_enc : encoded message
731 // _msg_dec : decoded message
fec_decode_soft(fec _q,unsigned int _dec_msg_len,unsigned char * _msg_enc,unsigned char * _msg_dec)732 void fec_decode_soft(fec _q,
733 unsigned int _dec_msg_len,
734 unsigned char * _msg_enc,
735 unsigned char * _msg_dec)
736 {
737 if (_q->decode_soft_func != NULL) {
738 // call internal decoding method
739 _q->decode_soft_func(_q, _dec_msg_len, _msg_enc, _msg_dec);
740 } else {
741 // pack bytes and use hard-decision decoding
742 unsigned enc_msg_len = fec_get_enc_msg_length(_q->scheme, _dec_msg_len);
743 unsigned char msg_enc_hard[enc_msg_len];
744 unsigned int i;
745 for (i=0; i<enc_msg_len; i++) {
746 // TODO : use pack bytes
747 msg_enc_hard[i] = 0;
748 msg_enc_hard[i] |= (_msg_enc[8*i+0] >> 0) & 0x80;
749 msg_enc_hard[i] |= (_msg_enc[8*i+1] >> 1) & 0x40;
750 msg_enc_hard[i] |= (_msg_enc[8*i+2] >> 2) & 0x20;
751 msg_enc_hard[i] |= (_msg_enc[8*i+3] >> 3) & 0x10;
752 msg_enc_hard[i] |= (_msg_enc[8*i+4] >> 4) & 0x08;
753 msg_enc_hard[i] |= (_msg_enc[8*i+5] >> 5) & 0x04;
754 msg_enc_hard[i] |= (_msg_enc[8*i+6] >> 6) & 0x02;
755 msg_enc_hard[i] |= (_msg_enc[8*i+7] >> 7) & 0x01;
756 }
757
758 // use hard-decoding method
759 fec_decode(_q, _dec_msg_len, msg_enc_hard, _msg_dec);
760 }
761 }
762
763
764