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