3 * Copyright 2002,2006 Free Software Foundation, Inc.
5 * This file is part of GNU Radio
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)
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.
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.
23 #include <atsci_trellis_encoder.h>
28 static const int DIBITS_PER_BYTE = 4;
30 #define SEGOF(x) ( (x) / ((SEGMENT_SIZE+1) * DIBITS_PER_BYTE))
31 #define SYMOF(x) (((x) % ((SEGMENT_SIZE+1) * DIBITS_PER_BYTE))-4)
33 /* How many separate Trellis encoders / Viterbi decoders run in parallel */
34 static const int NCODERS = 12;
36 #define ENCODER_SEG_BUMP 4
38 /* A Segment sync symbol is an 8VSB +5,-5,-5,+5 sequence that occurs at
39 the start of each 207-byte segment (including field sync segments). */
40 #define DSEG_SYNC_SYM1 0x06 /* +5 */
41 #define DSEG_SYNC_SYM2 0x01 /* -5 */
42 #define DSEG_SYNC_SYM3 0x01 /* -5 */
43 #define DSEG_SYNC_SYM4 0x06 /* +5 */
46 /* Shift counts to bit numbers (high order, low order); 9x entries unused */
47 static const int bit1[8] = {1, 99, 3, 98, 5, 97, 7, 96};
48 static const int bit2[8] = {0, 99, 2, 98, 4, 97, 6, 96};
51 atsci_trellis_encoder::atsci_trellis_encoder ()
57 atsci_trellis_encoder::~atsci_trellis_encoder ()
62 atsci_trellis_encoder::reset ()
64 for (int i = 0; i < NCODERS; i++)
69 atsci_trellis_encoder::encode (atsc_data_segment out[NCODERS],
70 const atsc_mpeg_packet_rs_encoded in[NCODERS])
72 unsigned char out_copy[OUTPUT_SIZE];
73 unsigned char in_copy[INPUT_SIZE];
75 assert (sizeof (in_copy) == sizeof (in[0].data) * NCODERS);
76 assert (sizeof (out_copy) == sizeof (out[0].data) * NCODERS);
78 // copy input into continguous temporary buffer
79 for (int i = 0; i < NCODERS; i++){
80 assert (in[i].pli.regular_seg_p ());
81 plinfo::sanity_check (in[i].pli);
82 memcpy (&in_copy[i * INPUT_SIZE/NCODERS],
84 ATSC_MPEG_RS_ENCODED_LENGTH * sizeof (in_copy[0]));
87 memset (out_copy, 0, sizeof (out_copy)); // FIXME, sanity check
90 encode_helper (out_copy, in_copy);
92 // copy output from contiguous temp buffer into final output
93 for (int i = 0; i < NCODERS; i++){
94 memcpy (&out[i].data[0],
95 &out_copy[i * OUTPUT_SIZE/NCODERS],
96 ATSC_DATA_SEGMENT_LENGTH * sizeof (out_copy[0]));
99 out[i].pli = in[i].pli;
101 plinfo::sanity_check (out[i].pli);
102 assert (out[i].pli.regular_seg_p ());
107 * This code expects contiguous arrrays. Use it as is, it computes
108 * the correct answer. Maybe someday, when we've run out of better
109 * things to do, rework to avoid the copying in encode.
112 atsci_trellis_encoder::encode_helper (unsigned char output[OUTPUT_SIZE],
113 const unsigned char input[INPUT_SIZE])
117 unsigned char trellis_buffer[NCODERS];
118 int trellis_wherefrom[NCODERS];
119 unsigned char *out, *next_out_seg;
123 unsigned char symbol;
124 int skip_encoder_bump;
126 /* FIXME, we may want special processing here
127 for a flag byte to keep track of which part of the field we're in? */
129 encoder = NCODERS - ENCODER_SEG_BUMP;
130 skip_encoder_bump = 0;
137 /* Load a new chunk of bytes into the Trellis encoder buffers.
138 They get loaded in an order that depends on where we are in the
139 segment sync progress (sigh).
140 GRR! When the chunk reload happens at the same time as the
141 segment boundary, we should bump the encoder NOW for the reload,
142 rather than LATER during the bitshift transition!!! */
143 if (out >= next_out_seg) {
144 encoder = (encoder + ENCODER_SEG_BUMP) % NCODERS;
145 skip_encoder_bump = 1;
148 for (i = 0; i < NCODERS; i++) {
149 /* for debug */ trellis_wherefrom[encoder] = chunk+i;
150 trellis_buffer[encoder] = input [chunk+i];
152 if (encoder >= NCODERS) encoder = 0;
155 for (shift = 6; shift >= 0; shift -= 2) {
157 /* Segment boundaries happen to occur on some bitshift transitions. */
158 if (out >= next_out_seg) {
159 /* Segment transition. Output a data segment sync symbol, and
160 mess with the trellis encoder mux. */
161 *out++ = DSEG_SYNC_SYM1;
162 *out++ = DSEG_SYNC_SYM2;
163 *out++ = DSEG_SYNC_SYM3;
164 *out++ = DSEG_SYNC_SYM4;
165 if (debug) printf ("SYNC SYNC SYNC SYNC\n");
166 next_out_seg = out + (SEGMENT_SIZE * DIBITS_PER_BYTE);
168 if (!skip_encoder_bump)
169 encoder = (encoder + ENCODER_SEG_BUMP) % NCODERS;
170 skip_encoder_bump = 0;
173 /* Now run each of the 12 Trellis encoders to spit out 12 symbols.
174 Each encoder takes input from the same byte of the chunk, but the
175 outputs of the encoders come out in various orders.
176 NOPE -- this is false. The encoders take input from various
177 bytes of the chunk (which changes at segment sync time), AND
178 they also come out in various orders. You really do have to
179 keep separate track of: the input bytes, the encoders, and
180 the output bytes -- because they're all moving with respect to
182 for (i = 0; i < NCODERS; i++) {
183 dibit = 0x03 & (trellis_buffer[encoder] >> shift);
185 printf ("Seg %ld Symb %3ld Trell %2d Byte %6d Bits %d-%d = dibit %d ",
186 (long) SEGOF(out-output), (long) SYMOF(out-output),
187 encoder, trellis_wherefrom[encoder],
188 bit1[shift], bit2[shift], dibit);
189 symbol = enc[encoder].encode (dibit);
191 encoder++; if (encoder >= NCODERS) encoder = 0;
192 if (debug) printf ("sym %d\n", symbol);
197 /* Check up on ourselves */
199 assertIntsEqual (0, (INPUT_SIZE * DIBITS_PER_BYTE) % NCODERS, "not %");
200 assertIntsEqual (OUTPUT_SIZE, out - output, "outptr");
201 assertIntsEqual (NCODERS - ENCODER_SEG_BUMP, encoder, "mux sync");
203 assert (0 == (INPUT_SIZE * DIBITS_PER_BYTE) % NCODERS);
204 assert (OUTPUT_SIZE == out - output);
205 assert (NCODERS - ENCODER_SEG_BUMP == encoder);