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>
27 static const int DIBITS_PER_BYTE = 4;
29 #define SEGOF(x) ( (x) / ((SEGMENT_SIZE+1) * DIBITS_PER_BYTE))
30 #define SYMOF(x) (((x) % ((SEGMENT_SIZE+1) * DIBITS_PER_BYTE))-4)
32 /* How many separate Trellis encoders / Viterbi decoders run in parallel */
33 static const int NCODERS = 12;
35 #define ENCODER_SEG_BUMP 4
37 /* A Segment sync symbol is an 8VSB +5,-5,-5,+5 sequence that occurs at
38 the start of each 207-byte segment (including field sync segments). */
39 #define DSEG_SYNC_SYM1 0x06 /* +5 */
40 #define DSEG_SYNC_SYM2 0x01 /* -5 */
41 #define DSEG_SYNC_SYM3 0x01 /* -5 */
42 #define DSEG_SYNC_SYM4 0x06 /* +5 */
45 /* Shift counts to bit numbers (high order, low order); 9x entries unused */
46 static const int bit1[8] = {1, 99, 3, 98, 5, 97, 7, 96};
47 static const int bit2[8] = {0, 99, 2, 98, 4, 97, 6, 96};
50 atsci_trellis_encoder::atsci_trellis_encoder ()
56 atsci_trellis_encoder::~atsci_trellis_encoder ()
61 atsci_trellis_encoder::reset ()
63 for (int i = 0; i < NCODERS; i++)
68 atsci_trellis_encoder::encode (atsc_data_segment out[NCODERS],
69 const atsc_mpeg_packet_rs_encoded in[NCODERS])
71 unsigned char out_copy[OUTPUT_SIZE];
72 unsigned char in_copy[INPUT_SIZE];
74 assert (sizeof (in_copy) == sizeof (in[0].data) * NCODERS);
75 assert (sizeof (out_copy) == sizeof (out[0].data) * NCODERS);
77 // copy input into continguous temporary buffer
78 for (int i = 0; i < NCODERS; i++){
79 assert (in[i].pli.regular_seg_p ());
80 plinfo::sanity_check (in[i].pli);
81 memcpy (&in_copy[i * INPUT_SIZE/NCODERS],
83 ATSC_MPEG_RS_ENCODED_LENGTH * sizeof (in_copy[0]));
86 memset (out_copy, 0, sizeof (out_copy)); // FIXME, sanity check
89 encode_helper (out_copy, in_copy);
91 // copy output from contiguous temp buffer into final output
92 for (int i = 0; i < NCODERS; i++){
93 memcpy (&out[i].data[0],
94 &out_copy[i * OUTPUT_SIZE/NCODERS],
95 ATSC_DATA_SEGMENT_LENGTH * sizeof (out_copy[0]));
98 out[i].pli = in[i].pli;
100 plinfo::sanity_check (out[i].pli);
101 assert (out[i].pli.regular_seg_p ());
106 * This code expects contiguous arrrays. Use it as is, it computes
107 * the correct answer. Maybe someday, when we've run out of better
108 * things to do, rework to avoid the copying in encode.
111 atsci_trellis_encoder::encode_helper (unsigned char output[OUTPUT_SIZE],
112 const unsigned char input[INPUT_SIZE])
116 unsigned char trellis_buffer[NCODERS];
117 int trellis_wherefrom[NCODERS];
118 unsigned char *out, *next_out_seg;
122 unsigned char symbol;
123 int skip_encoder_bump;
125 /* FIXME, we may want special processing here
126 for a flag byte to keep track of which part of the field we're in? */
128 encoder = NCODERS - ENCODER_SEG_BUMP;
129 skip_encoder_bump = 0;
136 /* Load a new chunk of bytes into the Trellis encoder buffers.
137 They get loaded in an order that depends on where we are in the
138 segment sync progress (sigh).
139 GRR! When the chunk reload happens at the same time as the
140 segment boundary, we should bump the encoder NOW for the reload,
141 rather than LATER during the bitshift transition!!! */
142 if (out >= next_out_seg) {
143 encoder = (encoder + ENCODER_SEG_BUMP) % NCODERS;
144 skip_encoder_bump = 1;
147 for (i = 0; i < NCODERS; i++) {
148 /* for debug */ trellis_wherefrom[encoder] = chunk+i;
149 trellis_buffer[encoder] = input [chunk+i];
151 if (encoder >= NCODERS) encoder = 0;
154 for (shift = 6; shift >= 0; shift -= 2) {
156 /* Segment boundaries happen to occur on some bitshift transitions. */
157 if (out >= next_out_seg) {
158 /* Segment transition. Output a data segment sync symbol, and
159 mess with the trellis encoder mux. */
160 *out++ = DSEG_SYNC_SYM1;
161 *out++ = DSEG_SYNC_SYM2;
162 *out++ = DSEG_SYNC_SYM3;
163 *out++ = DSEG_SYNC_SYM4;
164 if (debug) printf ("SYNC SYNC SYNC SYNC\n");
165 next_out_seg = out + (SEGMENT_SIZE * DIBITS_PER_BYTE);
167 if (!skip_encoder_bump)
168 encoder = (encoder + ENCODER_SEG_BUMP) % NCODERS;
169 skip_encoder_bump = 0;
172 /* Now run each of the 12 Trellis encoders to spit out 12 symbols.
173 Each encoder takes input from the same byte of the chunk, but the
174 outputs of the encoders come out in various orders.
175 NOPE -- this is false. The encoders take input from various
176 bytes of the chunk (which changes at segment sync time), AND
177 they also come out in various orders. You really do have to
178 keep separate track of: the input bytes, the encoders, and
179 the output bytes -- because they're all moving with respect to
181 for (i = 0; i < NCODERS; i++) {
182 dibit = 0x03 & (trellis_buffer[encoder] >> shift);
184 printf ("Seg %ld Symb %3ld Trell %2d Byte %6d Bits %d-%d = dibit %d ",
185 (long) SEGOF(out-output), (long) SYMOF(out-output),
186 encoder, trellis_wherefrom[encoder],
187 bit1[shift], bit2[shift], dibit);
188 symbol = enc[encoder].encode (dibit);
190 encoder++; if (encoder >= NCODERS) encoder = 0;
191 if (debug) printf ("sym %d\n", symbol);
196 /* Check up on ourselves */
198 assertIntsEqual (0, (INPUT_SIZE * DIBITS_PER_BYTE) % NCODERS, "not %");
199 assertIntsEqual (OUTPUT_SIZE, out - output, "outptr");
200 assertIntsEqual (NCODERS - ENCODER_SEG_BUMP, encoder, "mux sync");
202 assert (0 == (INPUT_SIZE * DIBITS_PER_BYTE) % NCODERS);
203 assert (OUTPUT_SIZE == out - output);
204 assert (NCODERS - ENCODER_SEG_BUMP == encoder);