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