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_encoder_impl.h"
28 #include <gnuradio/fec/cc_common.h>
29 #include <gnuradio/fec/generic_encoder.h>
30 #include <math.h>
31 #include <stdio.h>
32 #include <volk/volk.h>
33 #include <volk/volk_typedefs.h>
34 #include <boost/assign/list_of.hpp>
35 #include <sstream>
36 #include <vector>
37 
38 namespace gr {
39 namespace fec {
40 namespace code {
41 
make(int frame_size,int k,int rate,std::vector<int> polys,int start_state,cc_mode_t mode,bool padded)42 generic_encoder::sptr cc_encoder::make(int frame_size,
43                                        int k,
44                                        int rate,
45                                        std::vector<int> polys,
46                                        int start_state,
47                                        cc_mode_t mode,
48                                        bool padded)
49 {
50     return generic_encoder::sptr(
51         new cc_encoder_impl(frame_size, k, rate, polys, start_state, mode, padded));
52 }
53 
cc_encoder_impl(int frame_size,int k,int rate,std::vector<int> polys,int start_state,cc_mode_t mode,bool padded)54 cc_encoder_impl::cc_encoder_impl(int frame_size,
55                                  int k,
56                                  int rate,
57                                  std::vector<int> polys,
58                                  int start_state,
59                                  cc_mode_t mode,
60                                  bool padded)
61     : generic_encoder("cc_encoder"),
62       d_rate(rate),
63       d_k(k),
64       d_polys(polys),
65       d_start_state(start_state),
66       d_mode(mode),
67       d_padding(0)
68 {
69     if (static_cast<size_t>(d_rate) != d_polys.size()) {
70         throw std::runtime_error(
71             "cc_encoder: Number of polynomials must be the same as the value of rate");
72     }
73 
74     if (d_rate < 2) {
75         throw std::runtime_error("cc_encoder: inverse rate r must be > 2");
76     }
77 
78     if (k < 2 || k > 31) {
79         throw std::runtime_error(
80             "cc_encoder: constraint length K must in be the range [2, 31]");
81     }
82 
83     if (d_start_state >= (1u << (d_k - 1))) {
84         throw std::runtime_error("cc_encoder: start state is invalid; must be in range "
85                                  "[0, 2^(K-1)-1] where K is the constraint length");
86     }
87 
88     if (frame_size < 1) {
89         throw std::runtime_error("cc_encoder: frame_size must be > 0");
90     }
91 
92     if (mode != CC_STREAMING && mode != CC_TRUNCATED && mode != CC_TAILBITING &&
93         mode != CC_TERMINATED) {
94         throw std::runtime_error("cc_encoder: invalid mode passed");
95     }
96 
97     partab_init();
98 
99     // set up a padding factor. If padding, extends the encoding
100     // by this many bits to fit into a full byte.
101     if (padded && (mode == CC_TERMINATED)) {
102         d_padding = static_cast<int>(8.0f * ceilf(d_rate * (d_k - 1) / 8.0f) -
103                                      (d_rate * (d_k - 1)));
104     }
105 
106     d_max_frame_size = frame_size;
107     set_frame_size(frame_size);
108 }
109 
~cc_encoder_impl()110 cc_encoder_impl::~cc_encoder_impl() {}
111 
get_output_size()112 int cc_encoder_impl::get_output_size() { return d_output_size; }
113 
get_input_size()114 int cc_encoder_impl::get_input_size() { return d_frame_size; }
115 
set_frame_size(unsigned int frame_size)116 bool cc_encoder_impl::set_frame_size(unsigned int frame_size)
117 {
118     bool ret = true;
119     if (frame_size > d_max_frame_size) {
120         GR_LOG_INFO(d_logger,
121                     boost::format("tried to set frame to %1%; max possible is %2%") %
122                         frame_size % d_max_frame_size);
123         frame_size = d_max_frame_size;
124         ret = false;
125     }
126 
127     d_frame_size = frame_size;
128 
129     if (d_mode == CC_TERMINATED) {
130         d_output_size = d_rate * (d_frame_size + d_k - 1) + d_padding;
131     }
132     /*
133     else if(d_trunc_intrinsic) {
134       int cnt = 0;
135       for(int i = 0; i < d_rate; ++i) {
136         if (d_polys[i] != 1) {
137           cnt++;
138         }
139       }
140       d_output_size = (d_rate * (d_frame_size)) + (cnt * (d_k - 1));
141     }
142     */
143     else {
144         d_output_size = d_rate * d_frame_size;
145     }
146 
147     return ret;
148 }
149 
rate()150 double cc_encoder_impl::rate() { return static_cast<double>(d_rate); }
151 
parity(int x)152 int cc_encoder_impl::parity(int x)
153 {
154     x ^= (x >> 16);
155     x ^= (x >> 8);
156     return parityb(x);
157 }
158 
parityb(unsigned char x)159 int cc_encoder_impl::parityb(unsigned char x) { return Partab[x]; }
160 
partab_init(void)161 void cc_encoder_impl::partab_init(void)
162 {
163     int i, cnt, ti;
164 
165     /* Initialize parity lookup table */
166     for (i = 0; i < 256; i++) {
167         cnt = 0;
168         ti = i;
169         while (ti) {
170             if (ti & 1)
171                 cnt++;
172             ti >>= 1;
173         }
174         Partab[i] = cnt & 1;
175     }
176 }
177 
generic_work(void * in_buffer,void * out_buffer)178 void cc_encoder_impl::generic_work(void* in_buffer, void* out_buffer)
179 {
180     const unsigned char* in = (const unsigned char*)in_buffer;
181     unsigned char* out = (unsigned char*)out_buffer;
182 
183     unsigned my_state = d_start_state;
184 
185     if (d_mode == CC_TAILBITING) {
186         for (unsigned int i = 0; i < d_k - 1; ++i) {
187             my_state = (my_state << 1) | (in[d_frame_size - (d_k - 1) + i] & 1);
188         }
189     }
190 
191     for (unsigned int i = 0; i < d_frame_size; ++i) {
192         my_state = (my_state << 1) | (in[i] & 1);
193         for (unsigned int j = 0; j < d_rate; ++j) {
194             out[i * d_rate + j] =
195                 (d_polys[j] < 0) ^ parity(my_state & abs(d_polys[j])) ? 1 : 0;
196         }
197     }
198 
199     if (d_mode == CC_TERMINATED) {
200         for (unsigned int i = 0; i < d_k - 1; ++i) {
201             my_state = (my_state << 1) | ((d_start_state >> (d_k - 2 - i)) & 1);
202             for (unsigned int j = 0; j < d_rate; ++j) {
203                 out[(i + d_frame_size) * d_rate + j] =
204                     (d_polys[j] < 0) ^ parity(my_state & abs(d_polys[j])) ? 1 : 0;
205             }
206         }
207     }
208 
209     if (d_mode == CC_TRUNCATED) {
210         my_state = d_start_state;
211     }
212 
213     d_start_state = my_state;
214 }
215 
216 } /* namespace code */
217 } /* namespace fec */
218 } /* namespace gr */
219