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