summaryrefslogtreecommitdiff
path: root/gr-atsc/src/lib/atsci_trellis_encoder.cc
diff options
context:
space:
mode:
authorjcorgan2006-08-03 04:51:51 +0000
committerjcorgan2006-08-03 04:51:51 +0000
commit5d69a524f81f234b3fbc41d49ba18d6f6886baba (patch)
treeb71312bf7f1e8d10fef0f3ac6f28784065e73e72 /gr-atsc/src/lib/atsci_trellis_encoder.cc
downloadgnuradio-5d69a524f81f234b3fbc41d49ba18d6f6886baba.tar.gz
gnuradio-5d69a524f81f234b3fbc41d49ba18d6f6886baba.tar.bz2
gnuradio-5d69a524f81f234b3fbc41d49ba18d6f6886baba.zip
Houston, we have a trunk.
git-svn-id: http://gnuradio.org/svn/gnuradio/trunk@3122 221aa14e-8319-0410-a670-987f0aec2ac5
Diffstat (limited to 'gr-atsc/src/lib/atsci_trellis_encoder.cc')
-rw-r--r--gr-atsc/src/lib/atsci_trellis_encoder.cc207
1 files changed, 207 insertions, 0 deletions
diff --git a/gr-atsc/src/lib/atsci_trellis_encoder.cc b/gr-atsc/src/lib/atsci_trellis_encoder.cc
new file mode 100644
index 000000000..8e09739f2
--- /dev/null
+++ b/gr-atsc/src/lib/atsci_trellis_encoder.cc
@@ -0,0 +1,207 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2002,2006 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * GNU Radio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Radio; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <atsci_trellis_encoder.h>
+#include <assert.h>
+#include <stdio.h>
+
+static const int DIBITS_PER_BYTE = 4;
+
+#define SEGOF(x) ( (x) / ((SEGMENT_SIZE+1) * DIBITS_PER_BYTE))
+#define SYMOF(x) (((x) % ((SEGMENT_SIZE+1) * DIBITS_PER_BYTE))-4)
+
+/* How many separate Trellis encoders / Viterbi decoders run in parallel */
+static const int NCODERS = 12;
+
+#define ENCODER_SEG_BUMP 4
+
+/* A Segment sync symbol is an 8VSB +5,-5,-5,+5 sequence that occurs at
+ the start of each 207-byte segment (including field sync segments). */
+#define DSEG_SYNC_SYM1 0x06 /* +5 */
+#define DSEG_SYNC_SYM2 0x01 /* -5 */
+#define DSEG_SYNC_SYM3 0x01 /* -5 */
+#define DSEG_SYNC_SYM4 0x06 /* +5 */
+
+
+/* Shift counts to bit numbers (high order, low order); 9x entries unused */
+static const int bit1[8] = {1, 99, 3, 98, 5, 97, 7, 96};
+static const int bit2[8] = {0, 99, 2, 98, 4, 97, 6, 96};
+
+
+atsci_trellis_encoder::atsci_trellis_encoder ()
+{
+ debug = false;
+ reset ();
+}
+
+atsci_trellis_encoder::~atsci_trellis_encoder ()
+{
+}
+
+void
+atsci_trellis_encoder::reset ()
+{
+ for (int i = 0; i < NCODERS; i++)
+ enc[i].reset ();
+}
+
+void
+atsci_trellis_encoder::encode (atsc_data_segment out[NCODERS],
+ const atsc_mpeg_packet_rs_encoded in[NCODERS])
+{
+ unsigned char out_copy[OUTPUT_SIZE];
+ unsigned char in_copy[INPUT_SIZE];
+
+ assert (sizeof (in_copy) == sizeof (in[0].data) * NCODERS);
+ assert (sizeof (out_copy) == sizeof (out[0].data) * NCODERS);
+
+ // copy input into continguous temporary buffer
+ for (int i = 0; i < NCODERS; i++){
+ assert (in[i].pli.regular_seg_p ());
+ plinfo::sanity_check (in[i].pli);
+ memcpy (&in_copy[i * INPUT_SIZE/NCODERS],
+ &in[i].data[0],
+ ATSC_MPEG_RS_ENCODED_LENGTH * sizeof (in_copy[0]));
+ }
+
+ memset (out_copy, 0, sizeof (out_copy)); // FIXME, sanity check
+
+ // do the deed...
+ encode_helper (out_copy, in_copy);
+
+ // copy output from contiguous temp buffer into final output
+ for (int i = 0; i < NCODERS; i++){
+ memcpy (&out[i].data[0],
+ &out_copy[i * OUTPUT_SIZE/NCODERS],
+ ATSC_DATA_SEGMENT_LENGTH * sizeof (out_copy[0]));
+
+ // copy pipeline info
+ out[i].pli = in[i].pli;
+
+ plinfo::sanity_check (out[i].pli);
+ assert (out[i].pli.regular_seg_p ());
+ }
+}
+
+/*
+ * This code expects contiguous arrrays. Use it as is, it computes
+ * the correct answer. Maybe someday, when we've run out of better
+ * things to do, rework to avoid the copying in encode.
+ */
+void
+atsci_trellis_encoder::encode_helper (unsigned char output[OUTPUT_SIZE],
+ const unsigned char input[INPUT_SIZE])
+{
+ int i;
+ int encoder;
+ unsigned char trellis_buffer[NCODERS];
+ int trellis_wherefrom[NCODERS];
+ unsigned char *out, *next_out_seg;
+ int chunk;
+ int shift;
+ unsigned char dibit;
+ unsigned char symbol;
+ int skip_encoder_bump;
+
+ /* FIXME, we may want special processing here
+ for a flag byte to keep track of which part of the field we're in? */
+
+ encoder = NCODERS - ENCODER_SEG_BUMP;
+ skip_encoder_bump = 0;
+ out = output;
+ next_out_seg = out;
+
+ for (chunk = 0;
+ chunk < INPUT_SIZE;
+ chunk += NCODERS) {
+ /* Load a new chunk of bytes into the Trellis encoder buffers.
+ They get loaded in an order that depends on where we are in the
+ segment sync progress (sigh).
+ GRR! When the chunk reload happens at the same time as the
+ segment boundary, we should bump the encoder NOW for the reload,
+ rather than LATER during the bitshift transition!!! */
+ if (out >= next_out_seg) {
+ encoder = (encoder + ENCODER_SEG_BUMP) % NCODERS;
+ skip_encoder_bump = 1;
+ }
+
+ for (i = 0; i < NCODERS; i++) {
+ /* for debug */ trellis_wherefrom[encoder] = chunk+i;
+ trellis_buffer[encoder] = input [chunk+i];
+ encoder++;
+ if (encoder >= NCODERS) encoder = 0;
+ }
+
+ for (shift = 6; shift >= 0; shift -= 2) {
+
+ /* Segment boundaries happen to occur on some bitshift transitions. */
+ if (out >= next_out_seg) {
+ /* Segment transition. Output a data segment sync symbol, and
+ mess with the trellis encoder mux. */
+ *out++ = DSEG_SYNC_SYM1;
+ *out++ = DSEG_SYNC_SYM2;
+ *out++ = DSEG_SYNC_SYM3;
+ *out++ = DSEG_SYNC_SYM4;
+ if (debug) printf ("SYNC SYNC SYNC SYNC\n");
+ next_out_seg = out + (SEGMENT_SIZE * DIBITS_PER_BYTE);
+
+ if (!skip_encoder_bump)
+ encoder = (encoder + ENCODER_SEG_BUMP) % NCODERS;
+ skip_encoder_bump = 0;
+ }
+
+ /* Now run each of the 12 Trellis encoders to spit out 12 symbols.
+ Each encoder takes input from the same byte of the chunk, but the
+ outputs of the encoders come out in various orders.
+ NOPE -- this is false. The encoders take input from various
+ bytes of the chunk (which changes at segment sync time), AND
+ they also come out in various orders. You really do have to
+ keep separate track of: the input bytes, the encoders, and
+ the output bytes -- because they're all moving with respect to
+ each other!!! */
+ for (i = 0; i < NCODERS; i++) {
+ dibit = 0x03 & (trellis_buffer[encoder] >> shift);
+ if (debug)
+ printf ("Seg %ld Symb %3ld Trell %2d Byte %6d Bits %d-%d = dibit %d ",
+ (long) SEGOF(out-output), (long) SYMOF(out-output),
+ encoder, trellis_wherefrom[encoder],
+ bit1[shift], bit2[shift], dibit);
+ symbol = enc[encoder].encode (dibit);
+ *out++ = symbol;
+ encoder++; if (encoder >= NCODERS) encoder = 0;
+ if (debug) printf ("sym %d\n", symbol);
+ } /* Encoders */
+ } /* Bit shifts */
+ } /* Chunks */
+
+ /* Check up on ourselves */
+#if 0
+ assertIntsEqual (0, (INPUT_SIZE * DIBITS_PER_BYTE) % NCODERS, "not %");
+ assertIntsEqual (OUTPUT_SIZE, out - output, "outptr");
+ assertIntsEqual (NCODERS - ENCODER_SEG_BUMP, encoder, "mux sync");
+#else
+ assert (0 == (INPUT_SIZE * DIBITS_PER_BYTE) % NCODERS);
+ assert (OUTPUT_SIZE == out - output);
+ assert (NCODERS - ENCODER_SEG_BUMP == encoder);
+#endif
+}
+