1 /* -*- c++ -*- */
2 /*
3 * Copyright 2016,2017 Free Software Foundation, Inc.
4 *
5 * This is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 3, or (at your option)
8 * any later version.
9 *
10 * This software is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this software; see the file COPYING. If not, write to
17 * the Free Software Foundation, Inc., 51 Franklin Street,
18 * Boston, MA 02110-1301, USA.
19 */
20
21 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #endif
24
25 #include "catv_trellis_enc_bb_impl.h"
26 #include <gnuradio/io_signature.h>
27
28 namespace gr {
29 namespace dtv {
30
make(catv_constellation_t constellation)31 catv_trellis_enc_bb::sptr catv_trellis_enc_bb::make(catv_constellation_t constellation)
32 {
33 return gnuradio::get_initial_sptr(new catv_trellis_enc_bb_impl(constellation));
34 }
35
36 /*
37 * The private constructor
38 */
catv_trellis_enc_bb_impl(catv_constellation_t constellation)39 catv_trellis_enc_bb_impl::catv_trellis_enc_bb_impl(catv_constellation_t constellation)
40 : gr::block("catv_trellis_enc_bb",
41 gr::io_signature::make(1, 1, sizeof(unsigned char)),
42 gr::io_signature::make(1, 1, sizeof(unsigned char)))
43 {
44 if (constellation == CATV_MOD_64QAM) {
45 set_output_multiple(5);
46 } else {
47 set_output_multiple(5 * 6);
48 }
49
50 init_trellis();
51
52 Xq = 0;
53 Yq = 0;
54 XYp = 0;
55 signal_constellation = constellation;
56 trellis_group = 0;
57 }
58
59 /*
60 * Our virtual destructor.
61 */
~catv_trellis_enc_bb_impl()62 catv_trellis_enc_bb_impl::~catv_trellis_enc_bb_impl() {}
63
forecast(int noutput_items,gr_vector_int & ninput_items_required)64 void catv_trellis_enc_bb_impl::forecast(int noutput_items,
65 gr_vector_int& ninput_items_required)
66 {
67 if (signal_constellation == CATV_MOD_64QAM) {
68 ninput_items_required[0] = noutput_items / 5 * 28;
69 } else {
70 ninput_items_required[0] = (noutput_items / (5 * 6)) * (38 * 6);
71 }
72 }
73
diff_precoder(unsigned char W,unsigned char Z,unsigned char * Xp,unsigned char * Yp)74 void catv_trellis_enc_bb_impl::diff_precoder(unsigned char W,
75 unsigned char Z,
76 unsigned char* Xp,
77 unsigned char* Yp)
78 {
79 unsigned char common, newX, newY;
80
81 common = (Z & (*Xp ^ *Yp));
82 newX = W ^ *Xp ^ common;
83 newY = Z ^ W ^ *Yp ^ common;
84
85 *Xp = newX;
86 *Yp = newY;
87 }
88
init_trellis()89 void catv_trellis_enc_bb_impl::init_trellis()
90 {
91 unsigned char XYp, W, Z, X, Y, Xp, Yp, state, xy, Xq;
92 int i, n;
93
94 for (XYp = 0; XYp < 4; XYp++) {
95 for (W = 0; W < 16; W++) {
96 for (Z = 0; Z < 16; Z++) {
97 X = 0;
98 Y = 0;
99 Xp = (XYp & 0x02) >> 1;
100 Yp = (XYp & 0x01);
101 for (i = 0; i < 4; i++) {
102 diff_precoder((W >> i) & 1, (Z >> i) & 1, &Xp, &Yp);
103 X |= (Xp << i);
104 Y |= (Yp << i);
105 }
106 diff_precoder_table[XYp][W][Z][0] = (Xp << 1) + Yp;
107 diff_precoder_table[XYp][W][Z][1] = X;
108 diff_precoder_table[XYp][W][Z][2] = Y;
109 }
110 }
111 }
112
113 for (i = 0; i < 32; i++) {
114 G1table[i] = (i >> 4) ^ ((i & 0x04) >> 2) ^ (i & 1);
115 G2table[i] = (i >> 4) ^ ((i & 0x08) >> 3) ^ ((i & 0x04) >> 2) ^
116 ((i & 0x02) >> 1) ^ (i & 1);
117 }
118
119 memset(trellis_table_x, 0, 16 * 16 * 6);
120 memset(trellis_table_y, 0, 16 * 16 * 6);
121 for (state = 0; state < 16; state++) {
122 for (xy = 0; xy < 16; xy++) {
123 i = 0;
124 Xq = state;
125 for (n = 0; n < 4; n++) {
126 Xq = (Xq << 1) + ((xy >> n) & 1);
127
128 if (n == 3) {
129 trellis_table_x[state][xy][i + 1] |= G1table[Xq] << 3;
130 trellis_table_y[state][xy][i + 1] |= G1table[Xq];
131 i += 1;
132 }
133 trellis_table_x[state][xy][i + 1] |= G2table[Xq] << 3;
134 trellis_table_y[state][xy][i + 1] |= G2table[Xq];
135 i += 1;
136
137 Xq &= 0x0F;
138 }
139
140 trellis_table_x[state][xy][0] = Xq;
141 trellis_table_y[state][xy][0] = Xq;
142 }
143 }
144 }
145
trellis_code_64qam(const unsigned char * rs,unsigned char * qs)146 void catv_trellis_enc_bb_impl::trellis_code_64qam(const unsigned char* rs,
147 unsigned char* qs)
148 {
149 unsigned char X, Y;
150 int A, B, n;
151
152 memset(qs, 0, 5);
153
154 qs[0] |= rs[6] << 4; /* A1 */
155 qs[0] |= rs[5] << 5; /* A2 */
156 qs[0] |= rs[20] << 1; /* B1 */
157 qs[0] |= rs[19] << 2; /* B2 */
158 qs[1] |= rs[4] << 4; /* A4 */
159 qs[1] |= rs[3] << 5; /* A5 */
160 qs[1] |= rs[18] << 1; /* B4 */
161 qs[1] |= rs[17] << 2; /* B5 */
162 qs[2] |= rs[2] << 4; /* A7 */
163 qs[2] |= rs[1] << 5; /* A8 */
164 qs[2] |= rs[16] << 1; /* B7 */
165 qs[2] |= rs[15] << 2; /* B8 */
166 qs[3] |= rs[0] << 4; /* A10 */
167 qs[3] |= rs[13] << 5; /* A11 */
168 qs[3] |= rs[14] << 1; /* B10 */
169 qs[3] |= rs[27] << 2; /* B11 */
170 qs[4] |= rs[12] << 4; /* A12 */
171 qs[4] |= rs[11] << 5; /* A13 */
172 qs[4] |= rs[26] << 1; /* B12 */
173 qs[4] |= rs[25] << 2; /* B13 */
174
175 A = (rs[7] << 3) | (rs[8] << 2) | (rs[9] << 1) | rs[10];
176 B = (rs[21] << 3) | (rs[22] << 2) | (rs[23] << 1) | rs[24];
177 X = diff_precoder_table[XYp][A][B][1];
178 Y = diff_precoder_table[XYp][A][B][2];
179 XYp = diff_precoder_table[XYp][A][B][0];
180
181 for (n = 0; n < 5; n++) {
182 qs[n] |= trellis_table_x[Xq][X][1 + n];
183 qs[n] |= trellis_table_y[Yq][Y][1 + n];
184 }
185 Xq = trellis_table_x[Xq][X][0];
186 Yq = trellis_table_y[Yq][Y][0];
187 }
188
trellis_code_256qam(const unsigned char * rs,unsigned char * qs)189 void catv_trellis_enc_bb_impl::trellis_code_256qam(const unsigned char* rs,
190 unsigned char* qs)
191 {
192 unsigned char X, Y;
193 int A, B, n;
194
195 for (int i = 0; i < 6; i++) {
196 memset(&qs[0 + (i * 5)], 0, 5);
197 if (trellis_group == 2071) {
198 for (int j = 0; j < 5; j++) {
199 qs[j + (i * 5)] |= rs[38 + (j * 6)] << 5;
200 qs[j + (i * 5)] |= rs[39 + (j * 6)] << 6;
201 qs[j + (i * 5)] |= rs[40 + (j * 6)] << 7;
202 qs[j + (i * 5)] |= rs[41 + (j * 6)] << 1;
203 qs[j + (i * 5)] |= rs[42 + (j * 6)] << 2;
204 qs[j + (i * 5)] |= rs[43 + (j * 6)] << 3;
205 }
206
207 A = (rs[194] << 3) | (rs[192] << 2) | (rs[190] << 1) | rs[188];
208 B = (rs[195] << 3) | (rs[193] << 2) | (rs[191] << 1) | rs[189];
209 } else if (trellis_group == 2072) {
210 for (int j = 0; j < 5; j++) {
211 qs[j + (i * 5)] |= rs[68 + (j * 6)] << 5;
212 qs[j + (i * 5)] |= rs[69 + (j * 6)] << 6;
213 qs[j + (i * 5)] |= rs[70 + (j * 6)] << 7;
214 qs[j + (i * 5)] |= rs[71 + (j * 6)] << 1;
215 qs[j + (i * 5)] |= rs[72 + (j * 6)] << 2;
216 qs[j + (i * 5)] |= rs[73 + (j * 6)] << 3;
217 }
218
219 A = (rs[202] << 3) | (rs[200] << 2) | (rs[198] << 1) | rs[196];
220 B = (rs[203] << 3) | (rs[201] << 2) | (rs[199] << 1) | rs[197];
221 } else if (trellis_group == 2073) {
222 for (int j = 0; j < 5; j++) {
223 qs[j + (i * 5)] |= rs[98 + (j * 6)] << 5;
224 qs[j + (i * 5)] |= rs[99 + (j * 6)] << 6;
225 qs[j + (i * 5)] |= rs[100 + (j * 6)] << 7;
226 qs[j + (i * 5)] |= rs[101 + (j * 6)] << 1;
227 qs[j + (i * 5)] |= rs[102 + (j * 6)] << 2;
228 qs[j + (i * 5)] |= rs[103 + (j * 6)] << 3;
229 }
230
231 A = (rs[210] << 3) | (rs[208] << 2) | (rs[206] << 1) | rs[204];
232 B = (rs[211] << 3) | (rs[209] << 2) | (rs[207] << 1) | rs[205];
233 } else if (trellis_group == 2074) {
234 for (int j = 0; j < 5; j++) {
235 qs[j + (i * 5)] |= rs[128 + (j * 6)] << 5;
236 qs[j + (i * 5)] |= rs[129 + (j * 6)] << 6;
237 qs[j + (i * 5)] |= rs[130 + (j * 6)] << 7;
238 qs[j + (i * 5)] |= rs[131 + (j * 6)] << 1;
239 qs[j + (i * 5)] |= rs[132 + (j * 6)] << 2;
240 qs[j + (i * 5)] |= rs[133 + (j * 6)] << 3;
241 }
242
243 A = (rs[218] << 3) | (rs[216] << 2) | (rs[214] << 1) | rs[212];
244 B = (rs[219] << 3) | (rs[217] << 2) | (rs[215] << 1) | rs[213];
245 } else if (trellis_group == 2075) {
246 for (int j = 0; j < 5; j++) {
247 qs[j + (i * 5)] |= rs[158 + (j * 6)] << 5;
248 qs[j + (i * 5)] |= rs[159 + (j * 6)] << 6;
249 qs[j + (i * 5)] |= rs[160 + (j * 6)] << 7;
250 qs[j + (i * 5)] |= rs[161 + (j * 6)] << 1;
251 qs[j + (i * 5)] |= rs[162 + (j * 6)] << 2;
252 qs[j + (i * 5)] |= rs[163 + (j * 6)] << 3;
253 }
254
255 A = (rs[226] << 3) | (rs[224] << 2) | (rs[222] << 1) | rs[220];
256 B = (rs[227] << 3) | (rs[225] << 2) | (rs[223] << 1) | rs[221];
257 } else {
258 qs[0 + (i * 5)] |= rs[2 + (i * 38)] << 5; /* A1 */
259 qs[0 + (i * 5)] |= rs[3 + (i * 38)] << 6; /* A2 */
260 qs[0 + (i * 5)] |= rs[4 + (i * 38)] << 7; /* A3 */
261 qs[0 + (i * 5)] |= rs[5 + (i * 38)] << 1; /* B1 */
262 qs[0 + (i * 5)] |= rs[6 + (i * 38)] << 2; /* B2 */
263 qs[0 + (i * 5)] |= rs[7 + (i * 38)] << 3; /* B3 */
264 qs[1 + (i * 5)] |= rs[10 + (i * 38)] << 5; /* A5 */
265 qs[1 + (i * 5)] |= rs[11 + (i * 38)] << 6; /* A6 */
266 qs[1 + (i * 5)] |= rs[12 + (i * 38)] << 7; /* A7 */
267 qs[1 + (i * 5)] |= rs[13 + (i * 38)] << 1; /* B5 */
268 qs[1 + (i * 5)] |= rs[14 + (i * 38)] << 2; /* B6 */
269 qs[1 + (i * 5)] |= rs[15 + (i * 38)] << 3; /* B7 */
270 qs[2 + (i * 5)] |= rs[18 + (i * 38)] << 5; /* A9 */
271 qs[2 + (i * 5)] |= rs[19 + (i * 38)] << 6; /* A10 */
272 qs[2 + (i * 5)] |= rs[20 + (i * 38)] << 7; /* A11 */
273 qs[2 + (i * 5)] |= rs[21 + (i * 38)] << 1; /* B9 */
274 qs[2 + (i * 5)] |= rs[22 + (i * 38)] << 2; /* B10 */
275 qs[2 + (i * 5)] |= rs[23 + (i * 38)] << 3; /* B11 */
276 qs[3 + (i * 5)] |= rs[26 + (i * 38)] << 5; /* A13 */
277 qs[3 + (i * 5)] |= rs[27 + (i * 38)] << 6; /* A14 */
278 qs[3 + (i * 5)] |= rs[28 + (i * 38)] << 7; /* A15 */
279 qs[3 + (i * 5)] |= rs[29 + (i * 38)] << 1; /* B13 */
280 qs[3 + (i * 5)] |= rs[30 + (i * 38)] << 2; /* B14 */
281 qs[3 + (i * 5)] |= rs[31 + (i * 38)] << 3; /* B15 */
282 qs[4 + (i * 5)] |= rs[32 + (i * 38)] << 5; /* A16 */
283 qs[4 + (i * 5)] |= rs[33 + (i * 38)] << 6; /* A17 */
284 qs[4 + (i * 5)] |= rs[34 + (i * 38)] << 7; /* A18 */
285 qs[4 + (i * 5)] |= rs[35 + (i * 38)] << 1; /* B16 */
286 qs[4 + (i * 5)] |= rs[36 + (i * 38)] << 2; /* B17 */
287 qs[4 + (i * 5)] |= rs[37 + (i * 38)] << 3; /* B18 */
288
289 A = (rs[24 + (i * 38)] << 3) | (rs[16 + (i * 38)] << 2) |
290 (rs[8 + (i * 38)] << 1) | rs[0 + (i * 38)];
291 B = (rs[25 + (i * 38)] << 3) | (rs[17 + (i * 38)] << 2) |
292 (rs[9 + (i * 38)] << 1) | rs[1 + (i * 38)];
293 }
294
295 X = diff_precoder_table[XYp][A][B][1];
296 Y = diff_precoder_table[XYp][A][B][2];
297 XYp = diff_precoder_table[XYp][A][B][0];
298
299 for (n = 0; n < 5; n++) {
300 qs[n + (i * 5)] |= trellis_table_x[Xq][X][1 + n] << 1;
301 qs[n + (i * 5)] |= trellis_table_y[Yq][Y][1 + n];
302 }
303 Xq = trellis_table_x[Xq][X][0];
304 Yq = trellis_table_y[Yq][Y][0];
305 trellis_group++;
306 if (trellis_group == 2076) {
307 trellis_group = 0;
308 }
309 }
310 }
311
general_work(int noutput_items,gr_vector_int & ninput_items,gr_vector_const_void_star & input_items,gr_vector_void_star & output_items)312 int catv_trellis_enc_bb_impl::general_work(int noutput_items,
313 gr_vector_int& ninput_items,
314 gr_vector_const_void_star& input_items,
315 gr_vector_void_star& output_items)
316 {
317 const unsigned char* in = (const unsigned char*)input_items[0];
318 unsigned char* out = (unsigned char*)output_items[0];
319
320 int i = 0, j = 0;
321
322 while (i < noutput_items) {
323 if (signal_constellation == CATV_MOD_64QAM) {
324 trellis_code_64qam(in + j, out + i);
325 i += 5;
326 j += 28;
327 } else {
328 trellis_code_256qam(in + j, out + i);
329 i += 5 * 6;
330 j += 38 * 6;
331 }
332 }
333
334 // Tell runtime system how many input items we consumed on
335 // each input stream.
336 consume_each(j);
337
338 // Tell runtime system how many output items we produced.
339 return noutput_items;
340 }
341
342 } /* namespace dtv */
343 } /* namespace gr */
344