Updated FSF address in all files. Fixes ticket:51
[debian/gnuradio] / gr-atsc / src / lib / atsci_trellis_encoder.cc
1 /* -*- c++ -*- */
2 /*
3  * Copyright 2002,2006 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 2, 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 <atsci_trellis_encoder.h>
24 #include <assert.h>
25 #include <stdio.h>
26
27 static const int DIBITS_PER_BYTE = 4;
28
29 #define SEGOF(x)        ( (x) / ((SEGMENT_SIZE+1) * DIBITS_PER_BYTE))
30 #define SYMOF(x)        (((x) % ((SEGMENT_SIZE+1) * DIBITS_PER_BYTE))-4)
31
32 /* How many separate Trellis encoders / Viterbi decoders run in parallel */
33 static const int        NCODERS = 12;
34
35 #define ENCODER_SEG_BUMP        4
36
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 */
43
44
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};
48
49
50 atsci_trellis_encoder::atsci_trellis_encoder ()
51 {
52   debug = false;
53   reset ();
54 }
55
56 atsci_trellis_encoder::~atsci_trellis_encoder ()
57 {
58 }
59
60 void
61 atsci_trellis_encoder::reset ()
62 {
63   for (int i = 0; i < NCODERS; i++)
64     enc[i].reset ();
65 }
66
67 void 
68 atsci_trellis_encoder::encode (atsc_data_segment out[NCODERS],
69                               const atsc_mpeg_packet_rs_encoded in[NCODERS])
70 {
71   unsigned char out_copy[OUTPUT_SIZE];
72   unsigned char in_copy[INPUT_SIZE];
73
74   assert (sizeof (in_copy) == sizeof (in[0].data) * NCODERS);
75   assert (sizeof (out_copy) == sizeof (out[0].data) * NCODERS);
76
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],
82             &in[i].data[0],
83             ATSC_MPEG_RS_ENCODED_LENGTH * sizeof (in_copy[0]));
84   }
85
86   memset (out_copy, 0, sizeof (out_copy));      // FIXME, sanity check
87   
88   // do the deed...
89   encode_helper (out_copy, in_copy);
90
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]));
96
97     // copy pipeline info
98     out[i].pli = in[i].pli;
99
100     plinfo::sanity_check (out[i].pli);
101     assert (out[i].pli.regular_seg_p ());
102   }
103 }
104
105 /*
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.
109  */
110 void 
111 atsci_trellis_encoder::encode_helper (unsigned char output[OUTPUT_SIZE],
112                                      const unsigned char input[INPUT_SIZE])
113 {
114   int i;
115   int encoder;
116   unsigned char trellis_buffer[NCODERS];
117   int trellis_wherefrom[NCODERS];
118   unsigned char *out, *next_out_seg;
119   int chunk;
120   int shift;
121   unsigned char dibit;
122   unsigned char symbol;
123   int skip_encoder_bump;
124
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? */
127
128   encoder = NCODERS - ENCODER_SEG_BUMP;
129   skip_encoder_bump = 0;
130   out = output;
131   next_out_seg = out;
132
133   for (chunk = 0;
134        chunk < INPUT_SIZE;
135        chunk += NCODERS) {
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;
145     }
146       
147     for (i = 0; i < NCODERS; i++) {
148       /* for debug */ trellis_wherefrom[encoder] = chunk+i;
149       trellis_buffer[encoder] =             input [chunk+i];
150       encoder++;
151       if (encoder >= NCODERS) encoder = 0;
152     }
153
154     for (shift = 6; shift >= 0; shift -= 2) {
155
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);
166
167         if (!skip_encoder_bump)
168           encoder = (encoder + ENCODER_SEG_BUMP) % NCODERS;
169         skip_encoder_bump = 0;
170       }
171
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
180          each other!!!  */
181       for (i = 0; i < NCODERS; i++) {
182         dibit = 0x03 & (trellis_buffer[encoder] >> shift);
183         if (debug)
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);
189         *out++ = symbol;
190         encoder++; if (encoder >= NCODERS) encoder = 0;
191         if (debug) printf ("sym %d\n", symbol);
192       } /* Encoders */
193     } /* Bit shifts */
194   } /* Chunks */
195   
196   /* Check up on ourselves */
197 #if 0
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");
201 #else
202   assert (0 ==  (INPUT_SIZE * DIBITS_PER_BYTE) % NCODERS);
203   assert (OUTPUT_SIZE == out - output);
204   assert (NCODERS - ENCODER_SEG_BUMP == encoder);
205 #endif
206 }
207