1 /* -*- c++ -*- */
2 /*
3 * Copyright 2013-2014 Free Software Foundation, Inc.
4 *
5 * This file is part of GNU Radio
6 *
7 * GNU Radio is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 3, or (at your option)
10 * any later version.
11 *
12 * GNU Radio is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with GNU Radio; see the file COPYING. If not, write to
19 * the Free Software Foundation, Inc., 51 Franklin Street,
20 * Boston, MA 02110-1301, USA.
21 */
22
23 #ifdef HAVE_CONFIG_H
24 #include "config.h"
25 #endif
26
27 #include "cc_decoder_impl.h"
28 #include <math.h>
29 #include <stdio.h>
30 #include <volk/volk.h>
31 #include <boost/assign/list_of.hpp>
32 #include <sstream>
33 #include <vector>
34
35 namespace gr {
36 namespace fec {
37 namespace code {
38
make(int frame_size,int k,int rate,std::vector<int> polys,int start_state,int end_state,cc_mode_t mode,bool padded)39 generic_decoder::sptr cc_decoder::make(int frame_size,
40 int k,
41 int rate,
42 std::vector<int> polys,
43 int start_state,
44 int end_state,
45 cc_mode_t mode,
46 bool padded)
47 {
48 return generic_decoder::sptr(new cc_decoder_impl(
49 frame_size, k, rate, polys, start_state, end_state, mode, padded));
50 }
51
cc_decoder_impl(int frame_size,int k,int rate,std::vector<int> polys,int start_state,int end_state,cc_mode_t mode,bool padded)52 cc_decoder_impl::cc_decoder_impl(int frame_size,
53 int k,
54 int rate,
55 std::vector<int> polys,
56 int start_state,
57 int end_state,
58 cc_mode_t mode,
59 bool padded)
60 : generic_decoder("cc_decoder"),
61 d_k(k),
62 d_rate(rate),
63 d_polys(polys),
64 d_mode(mode),
65 d_padding(0),
66 d_start_state_chaining(start_state),
67 d_start_state_nonchaining(start_state),
68 d_end_state_nonchaining(end_state)
69 {
70 // Set max frame size here; all buffers and settings will be
71 // based on this value.
72 d_max_frame_size = frame_size;
73 d_frame_size = frame_size;
74
75 // set up a padding factor. If padding, the encoded frame was exteded
76 // by this many bits to fit into a full byte.
77 if (padded && (mode == CC_TERMINATED)) {
78 d_padding = static_cast<int>(8.0f * ceilf(d_rate * (d_k - 1) / 8.0f) -
79 (d_rate * (d_k - 1)));
80 }
81
82 d_vp = new struct v;
83
84 d_numstates = 1 << (d_k - 1);
85
86 d_decision_t_size = d_numstates / 8; // packed bit array
87
88 d_managed_in_size = 0;
89 switch (d_mode) {
90 case (CC_TAILBITING):
91 d_end_state = &d_end_state_chaining;
92 d_veclen = d_frame_size + (6 * (d_k - 1));
93 d_managed_in = (unsigned char*)volk_malloc(
94 d_veclen * d_rate * sizeof(unsigned char), volk_get_alignment());
95 d_managed_in_size = d_veclen * d_rate;
96 if (d_managed_in == NULL) {
97 throw std::runtime_error("cc_decoder: bad alloc for d_managed_in\n");
98 }
99 break;
100
101 case (CC_TRUNCATED):
102 d_veclen = d_frame_size;
103 d_end_state = &d_end_state_chaining;
104 break;
105
106 case (CC_TERMINATED):
107 d_veclen = d_frame_size + d_k - 1;
108 d_end_state =
109 (end_state == -1) ? &d_end_state_chaining : &d_end_state_nonchaining;
110 break;
111
112 case (CC_STREAMING):
113 d_veclen = d_frame_size + d_k - 1;
114 d_end_state = &d_end_state_chaining;
115 break;
116
117 default:
118 throw std::runtime_error("cc_decoder: mode not recognized");
119 }
120
121 d_vp->metrics = (unsigned char*)volk_malloc(2 * sizeof(unsigned char) * d_numstates,
122 volk_get_alignment());
123 if (d_vp->metrics == NULL) {
124 throw std::runtime_error("bad alloc for d_vp->metrics!\n");
125 }
126
127 d_vp->metrics1.t = d_vp->metrics;
128 d_vp->metrics2.t = d_vp->metrics + d_numstates;
129
130 d_vp->decisions = (unsigned char*)volk_malloc(
131 sizeof(unsigned char) * d_veclen * d_decision_t_size, volk_get_alignment());
132 if (d_vp->decisions == NULL) {
133 throw std::runtime_error("bad alloc for d_vp->decisions!\n");
134 }
135
136 Branchtab = (unsigned char*)volk_malloc(
137 sizeof(unsigned char) * d_numstates / 2 * rate, volk_get_alignment());
138 if (Branchtab == NULL) {
139 throw std::runtime_error("bad alloc for d_vp->decisions!\n");
140 }
141
142 create_viterbi();
143
144 if (d_k - 1 < 8) {
145 d_ADDSHIFT = (8 - (d_k - 1));
146 d_SUBSHIFT = 0;
147 } else if (d_k - 1 > 8) {
148 d_ADDSHIFT = 0;
149 d_SUBSHIFT = ((d_k - 1) - 8);
150 } else {
151 d_ADDSHIFT = 0;
152 d_SUBSHIFT = 0;
153 }
154
155 std::map<std::string, conv_kernel> yp_kernel =
156 boost::assign::map_list_of("k=7r=2", volk_8u_x4_conv_k7_r2_8u);
157
158 std::string k_ = "k=";
159 std::string r_ = "r=";
160
161 std::ostringstream kerneltype;
162 kerneltype << k_ << d_k << r_ << d_rate;
163
164 d_kernel = yp_kernel[kerneltype.str()];
165 if (d_kernel == NULL) {
166 throw std::runtime_error("cc_decoder: parameters not supported");
167 }
168 }
169
~cc_decoder_impl()170 cc_decoder_impl::~cc_decoder_impl()
171 {
172 volk_free(d_vp->decisions);
173 volk_free(Branchtab);
174 volk_free(d_vp->metrics);
175
176 delete d_vp;
177
178 if (d_mode == CC_TAILBITING) {
179 volk_free(d_managed_in);
180 }
181 }
182
get_output_size()183 int cc_decoder_impl::get_output_size()
184 {
185 // unpacked bits
186 return d_frame_size;
187 }
188
get_input_size()189 int cc_decoder_impl::get_input_size()
190 {
191 if (d_mode == CC_TERMINATED) {
192 return d_rate * (d_frame_size + d_k - 1) + d_padding;
193 } else {
194 return d_rate * d_frame_size;
195 }
196 }
197
get_input_item_size()198 int cc_decoder_impl::get_input_item_size() { return 1; }
199
get_history()200 int cc_decoder_impl::get_history()
201 {
202 if (d_mode == CC_STREAMING) {
203 return d_rate * (d_k - 1);
204 } else {
205 return 0;
206 }
207 }
208
get_shift()209 float cc_decoder_impl::get_shift() { return 128.0; }
210
get_input_conversion()211 const char* cc_decoder_impl::get_input_conversion() { return "uchar"; }
212
create_viterbi()213 void cc_decoder_impl::create_viterbi()
214 {
215 int state;
216 unsigned int i;
217 partab_init();
218 for (state = 0; state < d_numstates / 2; state++) {
219 for (i = 0; i < d_rate; i++) {
220 Branchtab[i * d_numstates / 2 + state] =
221 (d_polys[i] < 0) ^ parity((2 * state) & abs(d_polys[i])) ? 255 : 0;
222 }
223 }
224
225 switch (d_mode) {
226 case (CC_STREAMING):
227 d_start_state = &d_start_state_chaining;
228 init_viterbi_unbiased(d_vp);
229 break;
230
231 case (CC_TAILBITING):
232 d_start_state = &d_start_state_nonchaining;
233 init_viterbi_unbiased(d_vp);
234 break;
235
236 case (CC_TRUNCATED):
237 case (CC_TERMINATED):
238 d_start_state = &d_start_state_nonchaining;
239 init_viterbi(d_vp, *d_start_state);
240 break;
241
242 default:
243 throw std::runtime_error("cc_decoder: mode not recognized");
244 }
245
246 return;
247 }
248
parity(int x)249 int cc_decoder_impl::parity(int x)
250 {
251 x ^= (x >> 16);
252 x ^= (x >> 8);
253 return parityb(x);
254 }
255
parityb(unsigned char x)256 int cc_decoder_impl::parityb(unsigned char x) { return Partab[x]; }
257
partab_init(void)258 void cc_decoder_impl::partab_init(void)
259 {
260 int i, cnt, ti;
261
262 /* Initialize parity lookup table */
263 for (i = 0; i < 256; i++) {
264 cnt = 0;
265 ti = i;
266 while (ti) {
267 if (ti & 1)
268 cnt++;
269 ti >>= 1;
270 }
271 Partab[i] = cnt & 1;
272 }
273 }
274
init_viterbi(struct v * vp,int starting_state)275 int cc_decoder_impl::init_viterbi(struct v* vp, int starting_state)
276 {
277 int i;
278
279 if (vp == NULL)
280 return -1;
281 for (i = 0; i < d_numstates; i++) {
282 vp->metrics1.t[i] = 63;
283 }
284
285 vp->old_metrics = vp->metrics1;
286 vp->new_metrics = vp->metrics2;
287 vp->old_metrics.t[starting_state & (d_numstates - 1)] =
288 0; /* Bias known start state */
289 return 0;
290 }
291
init_viterbi_unbiased(struct v * vp)292 int cc_decoder_impl::init_viterbi_unbiased(struct v* vp)
293 {
294 int i;
295
296 if (vp == NULL)
297 return -1;
298 for (i = 0; i < d_numstates; i++)
299 vp->metrics1.t[i] = 31;
300
301 vp->old_metrics = vp->metrics1;
302 vp->new_metrics = vp->metrics2;
303 // no bias step
304 return 0;
305 }
306
find_endstate()307 int cc_decoder_impl::find_endstate()
308 {
309 unsigned char* met =
310 ((d_k + d_veclen) % 2 == 0) ? d_vp->new_metrics.t : d_vp->old_metrics.t;
311
312 unsigned char min = met[0];
313 int state = 0;
314 for (int i = 1; i < d_numstates; ++i) {
315 if (met[i] < min) {
316 min = met[i];
317 state = i;
318 }
319 }
320 // printf("min %d\n", state);
321 return state;
322 }
323
update_viterbi_blk(unsigned char * syms,int nbits)324 int cc_decoder_impl::update_viterbi_blk(unsigned char* syms, int nbits)
325 {
326 unsigned char* d;
327
328 d = d_vp->decisions;
329
330 memset(d, 0, d_decision_t_size * nbits);
331
332 d_kernel(d_vp->new_metrics.t,
333 d_vp->old_metrics.t,
334 syms,
335 d,
336 nbits - (d_k - 1),
337 d_k - 1,
338 Branchtab);
339
340 return 0;
341 }
342
chainback_viterbi(unsigned char * data,unsigned int nbits,unsigned int endstate,unsigned int tailsize)343 int cc_decoder_impl::chainback_viterbi(unsigned char* data,
344 unsigned int nbits,
345 unsigned int endstate,
346 unsigned int tailsize)
347 {
348 unsigned char* d;
349
350 /* ADDSHIFT and SUBSHIFT make sure that the thing returned is a byte. */
351 d = d_vp->decisions;
352 /* Make room beyond the end of the encoder register so we can
353 * accumulate a full byte of decoded data
354 */
355
356 endstate = (endstate % d_numstates) << d_ADDSHIFT;
357
358 /* The store into data[] only needs to be done every 8 bits.
359 * But this avoids a conditional branch, and the writes will
360 * combine in the cache anyway
361 */
362
363 d += tailsize * d_decision_t_size; /* Look past tail */
364 int retval;
365 int dif = tailsize - (d_k - 1);
366 decision_t dec;
367 while (nbits-- > d_frame_size - (d_k - 1)) {
368 int k;
369 dec.t = &d[nbits * d_decision_t_size];
370 k = (dec.w[(endstate >> d_ADDSHIFT) / 32] >> ((endstate >> d_ADDSHIFT) % 32)) & 1;
371
372 endstate = (endstate >> 1) | (k << (d_k - 2 + d_ADDSHIFT));
373 data[((nbits + dif) % d_frame_size)] = k;
374
375 retval = endstate;
376 }
377 nbits += 1;
378
379 while (nbits-- != 0) {
380 int k;
381
382 dec.t = &d[nbits * d_decision_t_size];
383
384 k = (dec.w[(endstate >> d_ADDSHIFT) / 32] >> ((endstate >> d_ADDSHIFT) % 32)) & 1;
385
386 endstate = (endstate >> 1) | (k << (d_k - 2 + d_ADDSHIFT));
387 data[((nbits + dif) % d_frame_size)] = k;
388 }
389
390 return retval >> d_ADDSHIFT;
391 }
392
set_frame_size(unsigned int frame_size)393 bool cc_decoder_impl::set_frame_size(unsigned int frame_size)
394 {
395 bool ret = true;
396 if (frame_size > d_max_frame_size) {
397 GR_LOG_INFO(
398 d_logger,
399 boost::format("cc_decoder: tried to set frame to %1%; max possible is %2%") %
400 frame_size % d_max_frame_size);
401 frame_size = d_max_frame_size;
402 ret = false;
403 }
404
405 d_frame_size = frame_size;
406
407 switch (d_mode) {
408 case (CC_TAILBITING):
409 d_veclen = d_frame_size + (6 * (d_k - 1));
410 if (d_veclen * d_rate > d_managed_in_size) {
411 throw std::runtime_error(
412 "cc_decoder: attempt to resize beyond d_managed_in buffer size!\n");
413 }
414 break;
415
416 case (CC_TRUNCATED):
417 d_veclen = d_frame_size;
418 break;
419
420 case (CC_STREAMING):
421 d_veclen = d_frame_size + d_k - 1;
422 break;
423
424 case (CC_TERMINATED):
425 // If the input is being padded out to a byte, we know the
426 // real frame size is without the padding.
427 d_frame_size -= d_padding * d_rate;
428 d_veclen = d_frame_size + d_k - 1;
429 break;
430
431 default:
432 throw std::runtime_error("cc_decoder: mode not recognized");
433 }
434
435 return ret;
436 }
437
rate()438 double cc_decoder_impl::rate() { return 1.0 / static_cast<double>(d_rate); }
439
generic_work(void * inbuffer,void * outbuffer)440 void cc_decoder_impl::generic_work(void* inbuffer, void* outbuffer)
441 {
442 const unsigned char* in = (const unsigned char*)inbuffer;
443 unsigned char* out = (unsigned char*)outbuffer;
444
445 switch (d_mode) {
446
447 case (CC_TAILBITING):
448 memcpy(d_managed_in, in, d_frame_size * d_rate * sizeof(unsigned char));
449 memcpy(d_managed_in + d_frame_size * d_rate * sizeof(unsigned char),
450 in,
451 (d_veclen - d_frame_size) * d_rate * sizeof(unsigned char));
452 update_viterbi_blk(d_managed_in, d_veclen);
453 d_end_state_chaining = find_endstate();
454 chainback_viterbi(&out[0], d_frame_size, *d_end_state, d_veclen - d_frame_size);
455 init_viterbi_unbiased(d_vp);
456 break;
457
458
459 case (CC_TRUNCATED):
460 update_viterbi_blk((unsigned char*)(&in[0]), d_veclen);
461 d_end_state_chaining = find_endstate();
462 for (unsigned int i = 0; i < d_k - 1; ++i) {
463 out[d_veclen - 1 - i] = ((*d_end_state) >> i) & 1;
464 }
465 d_start_state_chaining =
466 chainback_viterbi(&out[0], d_frame_size - (d_k - 1), *d_end_state, d_k - 1);
467 init_viterbi(d_vp, *d_start_state);
468 break;
469
470 case (CC_STREAMING):
471 case (CC_TERMINATED):
472 update_viterbi_blk((unsigned char*)(&in[0]), d_veclen);
473 d_end_state_chaining = find_endstate();
474 d_start_state_chaining = chainback_viterbi(
475 &out[0], d_frame_size, *d_end_state, d_veclen - d_frame_size);
476
477 init_viterbi(d_vp, *d_start_state);
478 break;
479
480 default:
481 throw std::runtime_error("cc_decoder: mode not recognized");
482 }
483 }
484
485 } /* namespace code */
486 } /* namespace fec */
487 } /* namespace gr */
488