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 // convolutional code (macros)
25 //
26 
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <assert.h>
30 
31 #include "liquid.internal.h"
32 
33 #define VERBOSE_FEC_CONV_PUNCTURED    0
34 
35 #if LIBFEC_ENABLED
36 #include "fec.h"
37 
fec_conv_punctured_create(fec_scheme _fs)38 fec fec_conv_punctured_create(fec_scheme _fs)
39 {
40     fec q = (fec) malloc(sizeof(struct fec_s));
41 
42     q->scheme = _fs;
43     q->rate = fec_get_rate(q->scheme);
44 
45     q->encode_func      = &fec_conv_punctured_encode;
46     q->decode_func      = &fec_conv_punctured_decode_hard;
47     q->decode_soft_func = &fec_conv_punctured_decode_soft;
48 
49     switch (q->scheme) {
50     case LIQUID_FEC_CONV_V27P23:   fec_conv_init_v27p23(q);    break;
51     case LIQUID_FEC_CONV_V27P34:   fec_conv_init_v27p34(q);    break;
52     case LIQUID_FEC_CONV_V27P45:   fec_conv_init_v27p45(q);    break;
53     case LIQUID_FEC_CONV_V27P56:   fec_conv_init_v27p56(q);    break;
54     case LIQUID_FEC_CONV_V27P67:   fec_conv_init_v27p67(q);    break;
55     case LIQUID_FEC_CONV_V27P78:   fec_conv_init_v27p78(q);    break;
56 
57     case LIQUID_FEC_CONV_V29P23:   fec_conv_init_v29p23(q);    break;
58     case LIQUID_FEC_CONV_V29P34:   fec_conv_init_v29p34(q);    break;
59     case LIQUID_FEC_CONV_V29P45:   fec_conv_init_v29p45(q);    break;
60     case LIQUID_FEC_CONV_V29P56:   fec_conv_init_v29p56(q);    break;
61     case LIQUID_FEC_CONV_V29P67:   fec_conv_init_v29p67(q);    break;
62     case LIQUID_FEC_CONV_V29P78:   fec_conv_init_v29p78(q);    break;
63     default:
64         fprintf(stderr,"error: fec_conv_punctured_create(), invalid type\n");
65         exit(1);
66     }
67 
68     // convolutional-specific decoding
69     q->num_dec_bytes = 0;
70     q->enc_bits = NULL;
71     q->vp = NULL;
72 
73     return q;
74 }
75 
fec_conv_punctured_destroy(fec _q)76 void fec_conv_punctured_destroy(fec _q)
77 {
78     // delete viterbi decoder
79     if (_q->vp != NULL)
80         _q->delete_viterbi(_q->vp);
81 
82     if (_q->enc_bits != NULL)
83         free(_q->enc_bits);
84 
85     free(_q);
86 }
87 
fec_conv_punctured_encode(fec _q,unsigned int _dec_msg_len,unsigned char * _msg_dec,unsigned char * _msg_enc)88 void fec_conv_punctured_encode(fec _q,
89                                unsigned int _dec_msg_len,
90                                unsigned char *_msg_dec,
91                                unsigned char *_msg_enc)
92 {
93     unsigned int i,j,r; // bookkeeping
94     unsigned int sr=0;  // convolutional shift register
95     unsigned int n=0;   // output bit counter
96     unsigned int p=0;   // puncturing matrix column index
97 
98     unsigned char bit;
99     unsigned char byte_in;
100     unsigned char byte_out=0;
101 
102     for (i=0; i<_dec_msg_len; i++) {
103         byte_in = _msg_dec[i];
104 
105         // break byte into individual bits
106         for (j=0; j<8; j++) {
107             // shift bit starting with most significant
108             bit = (byte_in >> (7-j)) & 0x01;
109             sr = (sr << 1) | bit;
110 
111             // compute parity bits for each polynomial
112             for (r=0; r<_q->R; r++) {
113                 // enable output determined by puncturing matrix
114                 if (_q->puncturing_matrix[r*(_q->P)+p]) {
115                     byte_out = (byte_out<<1) | parity(sr & _q->poly[r]);
116                     _msg_enc[n/8] = byte_out;
117                     n++;
118                 } else {
119                 }
120             }
121 
122             // update puncturing matrix column index
123             p = (p+1) % _q->P;
124         }
125     }
126     //printf("\n");
127     //printf("*** n = %u\n", n);
128 
129     // tail bits
130     for (i=0; i<_q->K-1; i++) {
131         // shift register: push zeros
132         sr = (sr << 1);
133 
134         // compute parity bits for each polynomial
135         for (r=0; r<_q->R; r++) {
136             if (_q->puncturing_matrix[r*(_q->P)+p]) {
137                 byte_out = (byte_out<<1) | parity(sr & _q->poly[r]);
138                 _msg_enc[n/8] = byte_out;
139                 n++;
140             }
141         }
142 
143         // update puncturing matrix column index
144         p = (p+1) % _q->P;
145     }
146     //printf("+++ n = %u\n", n);
147 
148     // ensure even number of bytes
149     while (n%8) {
150         // shift zeros
151         byte_out <<= 1;
152         _msg_enc[n/8] = byte_out;
153         n++;
154     }
155 
156     //printf("n = %u (expected %u)\n", n, 8*fec_get_enc_msg_length(LIQUID_FEC_CONV(_mode),_dec_msg_len));
157     assert(n == 8*fec_get_enc_msg_length(_q->scheme,_dec_msg_len));
158 }
159 
160 //unsigned int
fec_conv_punctured_decode_hard(fec _q,unsigned int _dec_msg_len,unsigned char * _msg_enc,unsigned char * _msg_dec)161 void fec_conv_punctured_decode_hard(fec _q,
162                                     unsigned int _dec_msg_len,
163                                     unsigned char *_msg_enc,
164                                     unsigned char *_msg_dec)
165 {
166     // re-allocate resources if necessary
167     fec_conv_punctured_setlength(_q, _dec_msg_len);
168 
169     // unpack bytes, adding erasures at punctured indices
170     unsigned int num_dec_bits = _q->num_dec_bytes * 8 + _q->K - 1;
171     unsigned int num_enc_bits = num_dec_bits * _q->R;
172     unsigned int i,r;
173     unsigned int n=0;   // input byte index
174     unsigned int k=0;   // intput bit index (0<=k<8)
175     unsigned int p=0;   // puncturing matrix column index
176     unsigned char bit;
177     unsigned char byte_in = _msg_enc[n];
178     for (i=0; i<num_enc_bits; i+=_q->R) {
179         //
180         for (r=0; r<_q->R; r++) {
181             if (_q->puncturing_matrix[r*(_q->P)+p]) {
182                 // push bit from input
183                 bit = (byte_in >> (7-k)) & 0x01;
184                 _q->enc_bits[i+r] = bit ? LIQUID_SOFTBIT_1 : LIQUID_SOFTBIT_0;
185                 k++;
186                 if (k==8) {
187                     k = 0;
188                     n++;
189                     byte_in = _msg_enc[n];
190                 }
191             } else {
192                 // push erasure
193                 _q->enc_bits[i+r] = LIQUID_SOFTBIT_ERASURE;
194             }
195         }
196         p = (p+1) % _q->P;
197     }
198 
199 #if VERBOSE_FEC_CONV_PUNCTURED
200     unsigned int ii;
201     printf("msg encoded (bits):\n");
202     for (ii=0; ii<num_enc_bits; ii++) {
203         printf("%3u ", _q->enc_bits[ii]);
204         if (((ii+1)%8)==0)
205             printf("\n");
206     }
207     printf("\n");
208 #endif
209 
210     // run decoder
211     _q->init_viterbi(_q->vp,0);
212     // TODO : check to see if this shouldn't be num_enc_bits (punctured)
213     _q->update_viterbi_blk(_q->vp, _q->enc_bits, 8*_q->num_dec_bytes+_q->K-1);
214     _q->chainback_viterbi(_q->vp, _msg_dec, 8*_q->num_dec_bytes, 0);
215 
216 #if VERBOSE_FEC_CONV_PUNCTURED
217     for (ii=0; ii<_dec_msg_len; ii++)
218         printf("%.2x ", _msg_dec[ii]);
219     printf("\n");
220 #endif
221 }
222 
223 //unsigned int
fec_conv_punctured_decode_soft(fec _q,unsigned int _dec_msg_len,unsigned char * _msg_enc,unsigned char * _msg_dec)224 void fec_conv_punctured_decode_soft(fec _q,
225                                     unsigned int _dec_msg_len,
226                                     unsigned char *_msg_enc,
227                                     unsigned char *_msg_dec)
228 {
229     // re-allocate resources if necessary
230     fec_conv_punctured_setlength(_q, _dec_msg_len);
231 
232     // unpack bytes, adding erasures at punctured indices
233     unsigned int num_dec_bits = _q->num_dec_bytes * 8 + _q->K - 1;
234     unsigned int num_enc_bits = num_dec_bits * _q->R;
235     unsigned int i,r;
236     unsigned int n=0;   // input soft bit index
237     unsigned int p=0;   // puncturing matrix column index
238     for (i=0; i<num_enc_bits; i+=_q->R) {
239         //
240         for (r=0; r<_q->R; r++) {
241             if (_q->puncturing_matrix[r*(_q->P)+p]) {
242                 // push bit from input
243                 _q->enc_bits[i+r] = _msg_enc[n++];
244             } else {
245                 // push erasure
246                 _q->enc_bits[i+r] = LIQUID_SOFTBIT_ERASURE;
247             }
248         }
249         p = (p+1) % _q->P;
250     }
251 
252 #if VERBOSE_FEC_CONV_PUNCTURED
253     unsigned int ii;
254     printf("msg encoded (bits):\n");
255     for (ii=0; ii<num_enc_bits; ii++) {
256         printf("%3u ", _q->enc_bits[ii]);
257         if (((ii+1)%8)==0)
258             printf("\n");
259     }
260     printf("\n");
261 #endif
262 
263     // run decoder
264     _q->init_viterbi(_q->vp,0);
265     // TODO : check to see if this shouldn't be num_enc_bits (punctured)
266     _q->update_viterbi_blk(_q->vp, _q->enc_bits, 8*_q->num_dec_bytes+_q->K-1);
267     _q->chainback_viterbi(_q->vp, _msg_dec, 8*_q->num_dec_bytes, 0);
268 
269 #if VERBOSE_FEC_CONV_PUNCTURED
270     for (ii=0; ii<_dec_msg_len; ii++)
271         printf("%.2x ", _msg_dec[ii]);
272     printf("\n");
273 #endif
274 }
275 
fec_conv_punctured_setlength(fec _q,unsigned int _dec_msg_len)276 void fec_conv_punctured_setlength(fec _q, unsigned int _dec_msg_len)
277 {
278     // re-allocate resources as necessary
279     unsigned int num_dec_bytes = _dec_msg_len;
280 
281     // return if length has not changed
282     if (num_dec_bytes == _q->num_dec_bytes)
283         return;
284 
285     // reset number of framebits
286     _q->num_dec_bytes = num_dec_bytes;
287     _q->num_enc_bytes = fec_get_enc_msg_length(_q->scheme,
288                                                _dec_msg_len);
289 
290     // puncturing: need to expand to full length (decoder
291     //             injects erasures at punctured values)
292     unsigned int num_dec_bits = 8*_q->num_dec_bytes;
293     unsigned int n = num_dec_bits + _q->K - 1;
294     unsigned int num_enc_bits = n*(_q->R);
295 #if VERBOSE_FEC_CONV_PUNCTURED
296     printf("(re)creating viterbi decoder, %u frame bytes\n", num_dec_bytes);
297     printf("  num decoded bytes         :   %u\n", _q->num_dec_bytes);
298     printf("  num encoded bytes         :   %u\n", _q->num_enc_bytes);
299     printf("  num decoded bits          :   %u\n", num_dec_bits);
300     printf("  num decoded bits (padded) :   %u\n", n);
301     printf("  num encoded bits (full)   :   %u\n", num_enc_bits);
302 #endif
303 
304     // delete old decoder if necessary
305     if (_q->vp != NULL)
306         _q->delete_viterbi(_q->vp);
307 
308     // re-create / re-allocate memory buffers
309     _q->vp = _q->create_viterbi(8*_q->num_dec_bytes);
310     _q->enc_bits = (unsigned char*) realloc(_q->enc_bits,
311                                             num_enc_bits*sizeof(unsigned char));
312 
313 }
314 
315 //
316 // internal
317 //
318 
fec_conv_init_v27p23(fec _q)319 void fec_conv_init_v27p23(fec _q)
320 {
321     // initialize R, K, polynomial, and viterbi methods
322     fec_conv_init_v27(_q);
323 
324     _q->P = 2;
325     _q->puncturing_matrix = fec_conv27p23_matrix;
326 }
327 
fec_conv_init_v27p34(fec _q)328 void fec_conv_init_v27p34(fec _q)
329 {
330     // initialize R, K, polynomial, and viterbi methods
331     fec_conv_init_v27(_q);
332 
333     _q->P = 3;
334     _q->puncturing_matrix = fec_conv27p34_matrix;
335 }
336 
fec_conv_init_v27p45(fec _q)337 void fec_conv_init_v27p45(fec _q)
338 {
339     // initialize R, K, polynomial, and viterbi methods
340     fec_conv_init_v27(_q);
341 
342     _q->P = 4;
343     _q->puncturing_matrix = fec_conv27p45_matrix;
344 }
345 
fec_conv_init_v27p56(fec _q)346 void fec_conv_init_v27p56(fec _q)
347 {
348     // initialize R, K, polynomial, and viterbi methods
349     fec_conv_init_v27(_q);
350 
351     _q->P = 5;
352     _q->puncturing_matrix = fec_conv27p56_matrix;
353 }
354 
355 
fec_conv_init_v27p67(fec _q)356 void fec_conv_init_v27p67(fec _q)
357 {
358     // initialize R, K, polynomial, and viterbi methods
359     fec_conv_init_v27(_q);
360 
361     _q->P = 6;
362     _q->puncturing_matrix = fec_conv27p67_matrix;
363 }
364 
fec_conv_init_v27p78(fec _q)365 void fec_conv_init_v27p78(fec _q)
366 {
367     // initialize R, K, polynomial, and viterbi methods
368     fec_conv_init_v27(_q);
369 
370     _q->P = 7;
371     _q->puncturing_matrix = fec_conv27p78_matrix;
372 }
373 
374 
fec_conv_init_v29p23(fec _q)375 void fec_conv_init_v29p23(fec _q)
376 {
377     // initialize R, K, polynomial, and viterbi methods
378     fec_conv_init_v29(_q);
379 
380     _q->P = 2;
381     _q->puncturing_matrix = fec_conv29p23_matrix;
382 }
383 
fec_conv_init_v29p34(fec _q)384 void fec_conv_init_v29p34(fec _q)
385 {
386     // initialize R, K, polynomial, and viterbi methods
387     fec_conv_init_v29(_q);
388 
389     _q->P = 3;
390     _q->puncturing_matrix = fec_conv29p34_matrix;
391 }
392 
fec_conv_init_v29p45(fec _q)393 void fec_conv_init_v29p45(fec _q)
394 {
395     // initialize R, K, polynomial, and viterbi methods
396     fec_conv_init_v29(_q);
397 
398     _q->P = 4;
399     _q->puncturing_matrix = fec_conv29p45_matrix;
400 }
401 
fec_conv_init_v29p56(fec _q)402 void fec_conv_init_v29p56(fec _q)
403 {
404     // initialize R, K, polynomial, and viterbi methods
405     fec_conv_init_v29(_q);
406 
407     _q->P = 5;
408     _q->puncturing_matrix = fec_conv29p56_matrix;
409 }
410 
411 
fec_conv_init_v29p67(fec _q)412 void fec_conv_init_v29p67(fec _q)
413 {
414     // initialize R, K, polynomial, and viterbi methods
415     fec_conv_init_v29(_q);
416 
417     _q->P = 6;
418     _q->puncturing_matrix = fec_conv29p67_matrix;
419 }
420 
fec_conv_init_v29p78(fec _q)421 void fec_conv_init_v29p78(fec _q)
422 {
423     // initialize R, K, polynomial, and viterbi methods
424     fec_conv_init_v29(_q);
425 
426     _q->P = 7;
427     _q->puncturing_matrix = fec_conv29p78_matrix;
428 }
429 
430 
431 #else   // LIBFEC_ENABLED
432 
fec_conv_punctured_create(fec_scheme _fs)433 fec fec_conv_punctured_create(fec_scheme _fs)
434 {
435     return NULL;
436 }
437 
fec_conv_punctured_destroy(fec _q)438 void fec_conv_punctured_destroy(fec _q)
439 {
440 }
441 
fec_conv_punctured_encode(fec _q,unsigned int _dec_msg_len,unsigned char * _msg_dec,unsigned char * _msg_enc)442 void fec_conv_punctured_encode(fec _q,
443                                unsigned int _dec_msg_len,
444                                unsigned char *_msg_dec,
445                                unsigned char *_msg_enc)
446 {
447 }
448 
449 //unsigned int
fec_conv_punctured_decode(fec _q,unsigned int _dec_msg_len,unsigned char * _msg_enc,unsigned char * _msg_dec)450 void fec_conv_punctured_decode(fec _q,
451                                unsigned int _dec_msg_len,
452                                unsigned char *_msg_enc,
453                                unsigned char *_msg_dec)
454 {
455 }
456 
457 #endif  // LIBFEC_ENABLED
458 
459