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