Statistics
| Branch: | Tag: | Revision:

root / gr-atsc / src / lib / atsci_trellis_encoder.cc @ b866f364

History | View | Annotate | Download (6.6 kB)

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