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