1 /* -*- c++ -*- */
2 /*
3 * Copyright 2015 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 #include <gnuradio/fec/generic_encoder.h>
24 #include <gnuradio/fec/tpc_common.h>
25 #include <gnuradio/fec/tpc_encoder.h>
26
27 #include <math.h>
28 #include <stdio.h>
29 #include <volk/volk.h>
30 #include <boost/assign/list_of.hpp>
31 #include <sstream>
32 #include <vector>
33
34 #include <string.h> // for memcpy
35 #include <algorithm> // for std::reverse
36
37 namespace gr {
38 namespace fec {
make(std::vector<int> row_polys,std::vector<int> col_polys,int krow,int kcol,int bval,int qval)39 generic_encoder::sptr tpc_encoder::make(std::vector<int> row_polys,
40 std::vector<int> col_polys,
41 int krow,
42 int kcol,
43 int bval,
44 int qval)
45 {
46 return generic_encoder::sptr(
47 new tpc_encoder(row_polys, col_polys, krow, kcol, bval, qval));
48 }
49
tpc_encoder(std::vector<int> row_polys,std::vector<int> col_polys,int krow,int kcol,int bval,int qval)50 tpc_encoder::tpc_encoder(std::vector<int> row_polys,
51 std::vector<int> col_polys,
52 int krow,
53 int kcol,
54 int bval,
55 int qval)
56 : d_rowpolys(row_polys),
57 d_colpolys(col_polys),
58 d_krow(krow),
59 d_kcol(kcol),
60 d_bval(bval),
61 d_qval(qval)
62 {
63 // first we operate on data chunks of get_input_size()
64 // TODO: should we verify this and throw an error if it doesn't match? YES
65 // hwo do we do that?
66
67 // calculate the input and output sizes
68 inputSize = (d_krow * d_kcol - (d_bval + d_qval));
69 rowEncoder_K = ceil(
70 log(d_rowpolys[0]) /
71 log(2)); // rowEncoder_K is the constraint length of the row encoder polynomial
72 rowEncoder_n = d_rowpolys.size();
73 rowEncoder_m = rowEncoder_K - 1;
74 colEncoder_K = ceil(
75 log(d_colpolys[0]) /
76 log(2)); // colEncoder_K is the constraint length of the col encoder polynomial
77 colEncoder_n = d_colpolys.size();
78 colEncoder_m = colEncoder_K - 1;
79
80 outputSize = ((d_krow + rowEncoder_m) * rowEncoder_n) *
81 ((d_kcol + colEncoder_m) * colEncoder_n) -
82 d_bval;
83
84 fp = NULL;
85 // DEBUG_PRINT("inputSize=%d outputSize=%d\n", inputSize, outputSize);
86 // fp = fopen("c_encoder_output.txt", "w");
87
88 // resize internal matrices
89 rowNumStates = 1 << (rowEncoder_K - 1); // 2^(row_mm)
90 colNumStates = 1 << (colEncoder_K - 1); // 2^(col_mm)
91 rowOutputs.resize(2, std::vector<int>(rowNumStates, 0));
92 rowNextStates.resize(2, std::vector<int>(rowNumStates, 0));
93 colOutputs.resize(2, std::vector<int>(colNumStates, 0));
94 colNextStates.resize(2, std::vector<int>(colNumStates, 0));
95 ;
96
97 rowTail.resize(rowNumStates, 0);
98 colTail.resize(colNumStates, 0);
99
100 // precalculate the state transition matrix for the row polynomial
101 tpc_common::precomputeStateTransitionMatrix_RSCPoly(
102 rowNumStates, d_rowpolys, rowEncoder_K, rowEncoder_n, rowOutputs, rowNextStates);
103
104 // calculate the tail for the row
105 tpc_common::rsc_tail(rowTail, d_rowpolys, rowNumStates, rowEncoder_m);
106
107 // precalculate the state transition matrix for the column polynomial
108 tpc_common::precomputeStateTransitionMatrix_RSCPoly(
109 colNumStates, d_colpolys, colEncoder_K, colEncoder_n, colOutputs, colNextStates);
110 // calculate the tail for the col
111 tpc_common::rsc_tail(colTail, d_colpolys, colNumStates, colEncoder_m);
112
113 // pre-allocate memory we use for encoding
114 inputSizeWithPad = d_bval + d_qval + inputSize;
115 inputWithPad.resize(inputSizeWithPad, 0);
116
117 numRowsToEncode =
118 inputSizeWithPad /
119 d_krow; // this should be OK w/ integer division -- TODO: check this?
120 rowToEncode.resize(d_krow, 0);
121 rowEncoded_block.resize(d_krow + (rowEncoder_m * rowEncoder_n), 0);
122 rowEncodedBits.resize(d_kcol, std::vector<uint8_t>(rowEncoder_m * rowEncoder_n, 0));
123
124 numColsToEncode = d_krow + (rowEncoder_m * rowEncoder_n);
125 colToEncode.resize(d_kcol, 0);
126 colEncoded_block.resize(d_kcol + (colEncoder_m * colEncoder_n), 0);
127 colEncodedBits.resize(d_krow + (rowEncoder_m * rowEncoder_n),
128 std::vector<uint8_t>(colEncoder_m * colEncoder_n, 0));
129 }
130
get_output_size()131 int tpc_encoder::get_output_size() { return outputSize; }
132
get_input_size()133 int tpc_encoder::get_input_size() { return inputSize; }
134
block_conv_encode(std::vector<uint8_t> & output,std::vector<uint8_t> input,std::vector<std::vector<int>> transOutputVec,std::vector<std::vector<int>> transNextStateVec,std::vector<int> tail,size_t KK,size_t nn)135 void tpc_encoder::block_conv_encode(std::vector<uint8_t>& output,
136 std::vector<uint8_t> input,
137 std::vector<std::vector<int>> transOutputVec,
138 std::vector<std::vector<int>> transNextStateVec,
139 std::vector<int> tail,
140 size_t KK,
141 size_t nn)
142 {
143 size_t outsym, ii, jj;
144 int state = 0;
145 size_t LL = input.size();
146
147 std::vector<int> binVec(nn, 0);
148
149 // encode data bits one bit at a time
150 for (ii = 0; ii < LL; ii++) {
151
152 // determine the output symbol
153 outsym = transOutputVec[(int)input[ii]][state];
154 // determine the next state
155 state = transNextStateVec[(int)input[ii]][state];
156
157 // Convert symbol to a binary vector
158 tpc_common::itob(binVec, outsym, nn);
159
160 // Assign to output : TODO: investigate using memcpy for this?
161 for (jj = 0; jj < nn; jj++) {
162 output[nn * ii + jj] = binVec[jj];
163 }
164 }
165
166 // encode tail
167 for (ii = LL; ii < LL + KK - 1; ii++) {
168
169 // determine the output symbol
170 outsym = transOutputVec[tail[state]][state];
171 // determine the next state
172 state = transNextStateVec[tail[state]][state];
173
174 // Convert symbol to a binary vector
175 tpc_common::itob(binVec, outsym, nn);
176
177 // Assign to output : TODO: investigate using memcpy for this?
178 for (jj = 0; jj < nn; jj++) {
179 output[nn * ii + jj] = binVec[jj];
180 }
181 }
182 }
183
generic_work(void * inBuffer,void * outBuffer)184 void tpc_encoder::generic_work(void* inBuffer, void* outBuffer)
185 {
186 const uint8_t* in = (const uint8_t*)inBuffer;
187 uint8_t* out = (uint8_t*)outBuffer;
188
189 size_t ii, jj; // indexing var
190
191 // DEBUG_PRINT_UCHAR_ARRAY(in, inputSize);
192
193 // TODO: probably a better way to do this than memcpy?
194 memcpy(&inputWithPad[d_bval + d_qval], in, sizeof(unsigned char) * inputSize);
195
196 // DEBUG_PRINT("Input with Pad -->\n");
197 // DEBUG_PRINT_UCHAR_ARRAY(&inputWithPad[0], inputSizeWithPad);
198 // DEBUG_PRINT_F(fp, "Input with Pad -->\n");
199 // DEBUG_PRINT_UCHAR_ARRAY_F(fp, &inputWithPad[0], inputSizeWithPad);
200
201 // encode the row data
202 for (ii = 0; ii < numRowsToEncode; ii++) {
203 // populate rowToEncode
204 memcpy(
205 &rowToEncode[0], &inputWithPad[ii * d_krow], sizeof(unsigned char) * d_krow);
206
207 // DEBUG_PRINT("Encoding row=[%d] -->\n",ii);
208 // DEBUG_PRINT_UCHAR_ARRAY(&rowToEncode[0], d_krow);
209 // DEBUG_PRINT_F(fp, "Encoding row=[%d] -->\n",ii);
210 // DEBUG_PRINT_UCHAR_ARRAY_F(fp, &rowToEncode[0], d_krow);
211
212 // encode it
213 block_conv_encode(rowEncoded_block,
214 rowToEncode,
215 rowOutputs,
216 rowNextStates,
217 rowTail,
218 rowEncoder_K,
219 rowEncoder_n);
220
221 // DEBUG_PRINT("Row Encoded Block=[%d] -->\n",ii);
222 // DEBUG_PRINT_FLOAT_ARRAY_AS_UCHAR(&rowEncoded_block[0], tmp);
223 // DEBUG_PRINT_F(fp, "Row Encoded Block=[%d] -->\n",ii);
224 // DEBUG_PRINT_FLOAT_ARRAY_AS_UCHAR_F(fp, &rowEncoded_block[0], tmp);
225
226 // store only the encoded bits, b/c we read out the data in a special way
227 memcpy(&rowEncodedBits[ii][0],
228 &rowEncoded_block[d_krow],
229 sizeof(uint8_t) * (rowEncoder_m * rowEncoder_n));
230
231 // DEBUG_PRINT("Row Encoded Bits");
232 // tmp = rowEncoder_m*rowEncoder_n;
233 // DEBUG_PRINT_FLOAT_ARRAY_AS_UCHAR(&rowEncodedBits[ii][0], tmp);
234 }
235
236 // encode the column data
237 size_t numDataColsToEncode = d_krow;
238 size_t numCheckColsToEncode = numColsToEncode - numDataColsToEncode;
239 for (ii = 0; ii < numDataColsToEncode; ii++) {
240 // populate colToEncode
241 for (jj = 0; jj < d_kcol; jj++) {
242 colToEncode[jj] = inputWithPad[jj * d_krow + ii];
243 }
244
245 // DEBUG_PRINT("Encoding col=[%d] -->\n",ii);
246 // DEBUG_PRINT_UCHAR_ARRAY(&colToEncode[0], d_kcol);
247 // DEBUG_PRINT_F(fp, "Encoding col=[%d] -->\n",ii);
248 // DEBUG_PRINT_UCHAR_ARRAY_F(fp, &colToEncode[0], d_kcol);
249
250 // encode it
251 block_conv_encode(colEncoded_block,
252 colToEncode,
253 colOutputs,
254 colNextStates,
255 colTail,
256 colEncoder_K,
257 colEncoder_n);
258
259 // DEBUG_PRINT("Col Encoded Block=[%d] -->\n",ii);
260 // DEBUG_PRINT_FLOAT_ARRAY_AS_UCHAR(&colEncoded_block[0], tmp);
261 // DEBUG_PRINT_F(fp, "Col Encoded Block=[%d] -->\n",ii);
262 // DEBUG_PRINT_FLOAT_ARRAY_AS_UCHAR_F(fp, &colEncoded_block[0], tmp);
263
264 // store only the encoded bits, b/c we read the data out in a special way
265 memcpy(&colEncodedBits[ii][0],
266 &colEncoded_block[d_kcol],
267 sizeof(uint8_t) * (colEncoder_m * colEncoder_n));
268
269 // DEBUG_PRINT("Col Encoded Bits");
270 // tmp = colEncoder_m*colEncoder_n;
271 // DEBUG_PRINT_FLOAT_ARRAY(&colEncodedBits[ii][0], tmp);
272 }
273
274 // encode checks on checks (encode the row-encoded bits)
275 for (ii = 0; ii < numCheckColsToEncode; ii++) {
276 // populate colToEncode
277 for (jj = 0; jj < d_kcol; jj++) {
278 colToEncode[jj] = rowEncodedBits[jj][ii]; // indexing is weird b/c of the way
279 // we declared the vector :(
280 }
281
282 // DEBUG_PRINT("Encoding col=[%d] -->\n",ii+numDataColsToEncode);
283 // DEBUG_PRINT_UCHAR_ARRAY(&colToEncode[0], d_kcol);
284 // DEBUG_PRINT_F(fp, "Encoding col=[%d] -->\n",ii+numDataColsToEncode);
285 // DEBUG_PRINT_UCHAR_ARRAY_F(fp, &colToEncode[0], d_kcol);
286
287 // encode it
288 block_conv_encode(colEncoded_block,
289 colToEncode,
290 colOutputs,
291 colNextStates,
292 colTail,
293 colEncoder_K,
294 colEncoder_n);
295
296 // DEBUG_PRINT("Col Encoded Block=[%d] -->\n",ii+numDataColsToEncode);
297 // DEBUG_PRINT_FLOAT_ARRAY_AS_UCHAR(&colEncoded_block[0], tmp);
298
299 // DEBUG_PRINT_F(fp, "Col Encoded Block=[%d] -->\n",ii+numDataColsToEncode);
300 // DEBUG_PRINT_FLOAT_ARRAY_AS_UCHAR_F(fp, &colEncoded_block[0], tmp);
301
302 // store only the encoded bits, b/c we read the data out in a special way
303 memcpy(&colEncodedBits[ii + numDataColsToEncode][0],
304 &colEncoded_block[d_kcol],
305 sizeof(uint8_t) * (colEncoder_m * colEncoder_n));
306
307 // DEBUG_PRINT("Col Encoded Bits");
308 // tmp = colEncoder_m*colEncoder_n;
309 // DEBUG_PRINT_FLOAT_ARRAY(&colEncodedBits[ii][0], tmp);
310 }
311
312 unsigned char* inputDataPtr;
313 uint8_t* outputDataPtr = out;
314
315 int curRowInRowEncodedBits = 0;
316 // read out the data along the rows into the "out" array
317
318 // skip B zeros & do the first row
319 inputDataPtr = &inputWithPad[d_bval];
320 if (d_bval > d_krow) {
321 throw std::runtime_error("bval must be < krow");
322 }
323 size_t firstRowRemainingBits = d_krow - d_bval;
324 for (ii = 0; ii < firstRowRemainingBits; ii++) {
325 *outputDataPtr++ = (uint8_t)(*inputDataPtr++);
326 }
327
328 // copy the encoded bits
329 memcpy(outputDataPtr,
330 &rowEncodedBits[curRowInRowEncodedBits++][0],
331 sizeof(uint8_t) * (rowEncoder_m * rowEncoder_n));
332
333 outputDataPtr += (rowEncoder_m * rowEncoder_n);
334
335 // copy out the rest of the data
336 for (ii = 1; ii < d_kcol; ii++) { // ii starts at 1, b/c we already did idx=0
337 // copy systematic bits
338 for (jj = 0; jj < d_krow; jj++) {
339 *outputDataPtr++ = (uint8_t)(*inputDataPtr++);
340 }
341
342 // copy the encoded bits
343 memcpy(outputDataPtr,
344 &rowEncodedBits[curRowInRowEncodedBits++][0],
345 sizeof(uint8_t) * (rowEncoder_m * rowEncoder_n));
346
347 outputDataPtr += (rowEncoder_m * rowEncoder_n);
348 }
349
350 // copy the encoded cols
351 for (ii = 0; ii < (colEncoder_m * colEncoder_n); ii++) {
352 // copy checks
353 for (jj = 0; jj < d_krow; jj++) {
354 *outputDataPtr++ = colEncodedBits[jj][ii];
355 }
356 int kk = jj;
357 // copy checks on checks
358 for (jj = 0; jj < (rowEncoder_m * rowEncoder_n); jj++) {
359 *outputDataPtr++ = colEncodedBits[kk++][ii];
360 }
361 }
362
363 // DEBUG_PRINT("Output\n");
364 // DEBUG_PRINT_FLOAT_ARRAY_AS_UCHAR(out, outputSize);
365 // DEBUG_PRINT_F(fp, "Output\n");
366 // DEBUG_PRINT_FLOAT_ARRAY_AS_UCHAR_F(fp, out, outputSize);
367 }
368
~tpc_encoder()369 tpc_encoder::~tpc_encoder()
370 {
371 if (fp)
372 fclose(fp);
373 }
374
375 } // namespace fec
376 } // namespace gr
377