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    0
34 
35 #if LIBFEC_ENABLED
36 #include "fec.h"
37 
fec_conv_create(fec_scheme _fs)38 fec fec_conv_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_encode;
46     q->decode_func      = &fec_conv_decode_hard; // default to hard-decision decoding
47     q->decode_soft_func = &fec_conv_decode_soft;
48 
49     switch (q->scheme) {
50     case LIQUID_FEC_CONV_V27:  fec_conv_init_v27(q);   break;
51     case LIQUID_FEC_CONV_V29:  fec_conv_init_v29(q);   break;
52     case LIQUID_FEC_CONV_V39:  fec_conv_init_v39(q);   break;
53     case LIQUID_FEC_CONV_V615: fec_conv_init_v615(q);  break;
54     default:
55         fprintf(stderr,"error: fec_conv_create(), invalid type\n");
56         exit(1);
57     }
58 
59     // convolutional-specific decoding
60     q->num_dec_bytes = 0;
61     q->enc_bits = NULL;
62     q->vp = NULL;
63 
64     return q;
65 }
66 
fec_conv_destroy(fec _q)67 void fec_conv_destroy(fec _q)
68 {
69     // delete viterbi decoder
70     if (_q->vp != NULL)
71         _q->delete_viterbi(_q->vp);
72 
73     if (_q->enc_bits != NULL)
74         free(_q->enc_bits);
75 
76     free(_q);
77 }
78 
fec_conv_encode(fec _q,unsigned int _dec_msg_len,unsigned char * _msg_dec,unsigned char * _msg_enc)79 void fec_conv_encode(fec _q,
80                      unsigned int _dec_msg_len,
81                      unsigned char *_msg_dec,
82                      unsigned char *_msg_enc)
83 {
84     unsigned int i,j,r; // bookkeeping
85     unsigned int sr=0;  // convolutional shift register
86     unsigned int n=0;   // output bit counter
87 
88     unsigned char bit;
89     unsigned char byte_in;
90     unsigned char byte_out=0;
91 
92     for (i=0; i<_dec_msg_len; i++) {
93         byte_in = _msg_dec[i];
94 
95         // break byte into individual bits
96         for (j=0; j<8; j++) {
97             // shift bit starting with most significant
98             bit = (byte_in >> (7-j)) & 0x01;
99             sr = (sr << 1) | bit;
100 
101             // compute parity bits for each polynomial
102             for (r=0; r<_q->R; r++) {
103                 byte_out = (byte_out<<1) | parity(sr & _q->poly[r]);
104                 _msg_enc[n/8] = byte_out;
105                 n++;
106             }
107         }
108     }
109 
110     // tail bits
111     for (i=0; i<(_q->K)-1; i++) {
112         // shift register: push zeros
113         sr = (sr << 1);
114 
115         // compute parity bits for each polynomial
116         for (r=0; r<_q->R; r++) {
117             byte_out = (byte_out<<1) | parity(sr & _q->poly[r]);
118             _msg_enc[n/8] = byte_out;
119             n++;
120         }
121     }
122 
123     // ensure even number of bytes
124     while (n%8) {
125         // shift zeros
126         byte_out <<= 1;
127         _msg_enc[n/8] = byte_out;
128         n++;
129     }
130 
131     assert(n == 8*fec_get_enc_msg_length(_q->scheme,_dec_msg_len));
132 }
133 
134 //unsigned int
fec_conv_decode_hard(fec _q,unsigned int _dec_msg_len,unsigned char * _msg_enc,unsigned char * _msg_dec)135 void fec_conv_decode_hard(fec _q,
136                           unsigned int _dec_msg_len,
137                           unsigned char *_msg_enc,
138                           unsigned char *_msg_dec)
139 {
140     // re-allocate resources if necessary
141     fec_conv_setlength(_q, _dec_msg_len);
142 
143     // unpack bytes
144     unsigned int num_written;
145     liquid_unpack_bytes(_msg_enc,               // encoded message (bytes)
146                         _q->num_enc_bytes,      // encoded message length (#bytes)
147                         _q->enc_bits,           // encoded messsage (bits)
148                         _q->num_enc_bytes*8,    // encoded message length (#bits)
149                         &num_written);
150 
151 #if VERBOSE_FEC_CONV
152     unsigned int i;
153     printf("msg encoded (bits):\n");
154     for (i=0; i<8*_q->num_enc_bytes; i++) {
155         printf("%1u", _q->enc_bits[i]);
156         if (((i+1)%8)==0)
157             printf(" ");
158     }
159     printf("\n");
160 #endif
161 
162     // invoke hard-decision scaling
163     unsigned int k;
164     for (k=0; k<8*_q->num_enc_bytes; k++)
165         _q->enc_bits[k] = _q->enc_bits[k] ? LIQUID_SOFTBIT_1 : LIQUID_SOFTBIT_0;
166 
167     // run internal decoder
168     fec_conv_decode(_q, _msg_dec);
169 }
170 
171 //unsigned int
fec_conv_decode_soft(fec _q,unsigned int _dec_msg_len,unsigned char * _msg_enc,unsigned char * _msg_dec)172 void fec_conv_decode_soft(fec _q,
173                           unsigned int _dec_msg_len,
174                           unsigned char *_msg_enc,
175                           unsigned char *_msg_dec)
176 {
177     // re-allocate resources if necessary
178     fec_conv_setlength(_q, _dec_msg_len);
179 
180     // copy soft input bits
181     unsigned int k;
182     for (k=0; k<8*_q->num_enc_bytes; k++)
183         _q->enc_bits[k] = _msg_enc[k];
184 
185     // run internal decoder
186     fec_conv_decode(_q, _msg_dec);
187 }
188 
189 //unsigned int
fec_conv_decode(fec _q,unsigned char * _msg_dec)190 void fec_conv_decode(fec _q,
191                      unsigned char *_msg_dec)
192 {
193     // run decoder
194     _q->init_viterbi(_q->vp,0);
195     _q->update_viterbi_blk(_q->vp, _q->enc_bits, 8*_q->num_dec_bytes+_q->K-1);
196     _q->chainback_viterbi(_q->vp, _msg_dec, 8*_q->num_dec_bytes, 0);
197 
198 #if VERBOSE_FEC_CONV
199     for (i=0; i<_dec_msg_len; i++)
200         printf("%.2x ", _msg_dec[i]);
201     printf("\n");
202 #endif
203 }
204 
fec_conv_setlength(fec _q,unsigned int _dec_msg_len)205 void fec_conv_setlength(fec _q, unsigned int _dec_msg_len)
206 {
207     // re-allocate resources as necessary
208     unsigned int num_dec_bytes = _dec_msg_len;
209 
210     // return if length has not changed
211     if (num_dec_bytes == _q->num_dec_bytes)
212         return;
213 
214 #if VERBOSE_FEC_CONV
215     printf("(re)creating viterbi decoder, %u frame bytes\n", num_dec_bytes);
216 #endif
217 
218     // reset number of framebits
219     _q->num_dec_bytes = num_dec_bytes;
220     _q->num_enc_bytes = fec_get_enc_msg_length(_q->scheme,
221                                                _dec_msg_len);
222 
223     // delete old decoder if necessary
224     if (_q->vp != NULL)
225         _q->delete_viterbi(_q->vp);
226 
227     // re-create / re-allocate memory buffers
228     _q->vp = _q->create_viterbi(8*_q->num_dec_bytes);
229     _q->enc_bits = (unsigned char*) realloc(_q->enc_bits,
230                                             _q->num_enc_bytes*8*sizeof(unsigned char));
231 }
232 
233 //
234 // internal
235 //
236 
fec_conv_init_v27(fec _q)237 void fec_conv_init_v27(fec _q)
238 {
239     _q->R=2;
240     _q->K=7;
241     _q->poly = fec_conv27_poly;
242     _q->create_viterbi = create_viterbi27;
243     _q->init_viterbi = init_viterbi27;
244     _q->update_viterbi_blk = update_viterbi27_blk;
245     _q->chainback_viterbi = chainback_viterbi27;
246     _q->delete_viterbi = delete_viterbi27;
247 }
248 
fec_conv_init_v29(fec _q)249 void fec_conv_init_v29(fec _q)
250 {
251     _q->R=2;
252     _q->K=9;
253     _q->poly = fec_conv29_poly;
254     _q->create_viterbi = create_viterbi29;
255     _q->init_viterbi = init_viterbi29;
256     _q->update_viterbi_blk = update_viterbi29_blk;
257     _q->chainback_viterbi = chainback_viterbi29;
258     _q->delete_viterbi = delete_viterbi29;
259 }
260 
fec_conv_init_v39(fec _q)261 void fec_conv_init_v39(fec _q)
262 {
263     _q->R=3;
264     _q->K=9;
265     _q->poly = fec_conv39_poly;
266     _q->create_viterbi = create_viterbi39;
267     _q->init_viterbi = init_viterbi39;
268     _q->update_viterbi_blk = update_viterbi39_blk;
269     _q->chainback_viterbi = chainback_viterbi39;
270     _q->delete_viterbi = delete_viterbi39;
271 }
272 
fec_conv_init_v615(fec _q)273 void fec_conv_init_v615(fec _q)
274 {
275     _q->R=6;
276     _q->K=15;
277     _q->poly = fec_conv615_poly;
278     _q->create_viterbi = create_viterbi615;
279     _q->init_viterbi = init_viterbi615;
280     _q->update_viterbi_blk = update_viterbi615_blk;
281     _q->chainback_viterbi = chainback_viterbi615;
282     _q->delete_viterbi = delete_viterbi615;
283 }
284 
285 
286 
287 #else   // LIBFEC_ENABLED
288 
fec_conv_create(fec_scheme _fs)289 fec fec_conv_create(fec_scheme _fs)
290 {
291     return NULL;
292 }
293 
fec_conv_destroy(fec _q)294 void fec_conv_destroy(fec _q)
295 {
296 }
297 
298 #endif  // LIBFEC_ENABLED
299 
300