Merge branch 'upstream' into dfsg-orig
[debian/gnuradio] / gr-atsc / src / lib / atsci_viterbi_decoder.cc
diff --git a/gr-atsc/src/lib/atsci_viterbi_decoder.cc b/gr-atsc/src/lib/atsci_viterbi_decoder.cc
new file mode 100644 (file)
index 0000000..5b9ae4e
--- /dev/null
@@ -0,0 +1,176 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2002 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 3, 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., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include <atsci_viterbi_decoder.h>
+#include <assert.h>
+#include <stdio.h>
+#include <cmath>
+#include "atsci_viterbi_mux.cc"
+#include <string.h>
+
+
+/* How many separate Trellis encoders / Viterbi decoders run in parallel */
+static const int       NCODERS = 12;
+
+static const float     DSEG_SYNC_SYM1 =  5;
+static const float     DSEG_SYNC_SYM2 = -5;
+static const float     DSEG_SYNC_SYM3 = -5;
+static const float     DSEG_SYNC_SYM4 =  5;
+
+atsci_viterbi_decoder::atsci_viterbi_decoder ()
+{
+  debug = true;
+
+  /*
+   * These fifo's handle the alignment problem caused by the
+   * inherent decoding delay of the individual viterbi decoders.
+   * The net result is that this entire block has a pipeline latency
+   * of 12 complete segments.
+   *
+   * If anybody cares, it is possible to do it with less delay, but
+   * this approach is at least somewhat understandable...
+   */
+  
+  // the -4 is for the 4 sync symbols
+  int  fifo_size = ATSC_DATA_SEGMENT_LENGTH - 4 - viterbi[0].delay ();
+  for (int i = 0; i < NCODERS; i++)
+    fifo[i] = new fifo_t(fifo_size);
+
+  reset ();
+}
+
+atsci_viterbi_decoder::~atsci_viterbi_decoder ()
+{
+  for (int i = 0; i < NCODERS; i++)
+    delete fifo[i];
+}
+
+void
+atsci_viterbi_decoder::reset ()
+{
+  for (int i = 0; i < NCODERS; i++){
+    viterbi[i].reset ();
+    fifo[i]->reset ();
+  }
+}
+
+
+void
+atsci_viterbi_decoder::decode (atsc_mpeg_packet_rs_encoded out[NCODERS],
+                             const atsc_soft_data_segment in[NCODERS])
+{
+  unsigned char out_copy[OUTPUT_SIZE];
+  float        in_copy[INPUT_SIZE];
+
+  // copy input into continguous temporary buffer
+  for (int i = 0; i < NCODERS; i++){
+    assert (in[i].pli.regular_seg_p ());
+    memcpy (&in_copy[i * INPUT_SIZE/NCODERS],
+           &in[i].data[0],
+           ATSC_DATA_SEGMENT_LENGTH * sizeof (in_copy[0]));
+  }
+
+  memset (out_copy, 0, sizeof (out_copy));     // sanity check
+  
+  // do the deed...
+  decode_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_MPEG_RS_ENCODED_LENGTH * sizeof (out_copy[0]));
+           
+           
+    // adjust pipeline info to reflect 12 segment delay
+    plinfo::delay (out[i].pli, in[i].pli, NCODERS);
+  }
+}
+
+void
+atsci_viterbi_decoder::decode_helper (unsigned char out[OUTPUT_SIZE],
+                                    const float symbols_in[INPUT_SIZE])
+{
+  int encoder;
+  unsigned int i;
+  int dbi;
+  int dbwhere;
+  int dbindex;
+  int shift;
+  unsigned char dibit;
+  float symbol;
+
+  /* Memset is not necessary if it's all working... */
+  memset (out, 0, OUTPUT_SIZE);
+
+#define VERBOSE 0
+
+#if 1
+  /* Check for sync symbols in the incoming data stream */
+  /* For now, all we do is complain to stdout.  FIXME, pass it back to
+     caller as an error/quality signal.  */
+  for (i = 0; i < sync_symbol_indices_max; i++) {
+    int j = sync_symbol_indices[i];
+    if (fabsf (symbols_in[j] - DSEG_SYNC_SYM1) > 1.0)
+      if (VERBOSE) fprintf (stderr, "** Missing dataseg sync 1 at %d, expect %g, got %g.\n",
+                           j, DSEG_SYNC_SYM1, symbols_in[j]);
+    j++;
+    if (fabsf (symbols_in[j] - DSEG_SYNC_SYM2) > 1.0)
+      if (VERBOSE) fprintf (stderr, "** Missing dataseg sync 2 at %d, expect %g, got %g.\n",
+                           j, DSEG_SYNC_SYM2, symbols_in[j]);
+    j++;
+    if (fabsf (symbols_in[j] - DSEG_SYNC_SYM3) > 1.0)
+      if (VERBOSE) fprintf (stderr, "** Missing dataseg sync 3 at %d, expect %g, got %g.\n",
+                           j, DSEG_SYNC_SYM3, symbols_in[j]);
+    j++;
+    if (fabsf (symbols_in[j] - DSEG_SYNC_SYM4) > 1.0)
+      if (VERBOSE) fprintf (stderr, "** Missing dataseg sync 4 at %d, expect %g, got %g.\n",
+                           j, DSEG_SYNC_SYM4, symbols_in[j]);
+  }
+#endif
+#undef VERBOSE
+
+  // printf ("@@@ DIBITS @@@\n");
+  
+  /* Now run each of the 12 Trellis encoders over their subset of
+     the input symbols */
+  for (encoder = 0; encoder < NCODERS; encoder++) {
+    dbi = 0;                   /* Reinitialize dibit index for new encoder */
+    fifo_t     *dibit_fifo = fifo[encoder];
+    
+    /* Feed all the incoming symbols into one encoder;
+       pump them into the relevant dibits. */
+    for (i = 0; i < enco_which_max; i++) {
+      symbol = symbols_in[enco_which_syms[encoder][i]];
+      dibit = dibit_fifo->stuff (viterbi[encoder].decode (symbol));
+      // printf ("%d\n", dibit);
+      /* Store the dibit into the output data segment */
+      dbwhere = enco_which_dibits[encoder][dbi++];
+      dbindex = dbwhere >> 3;
+      shift = dbwhere & 0x7;
+      out[dbindex] =
+       (out[dbindex] & ~(0x03 << shift)) | (dibit << shift);
+    } /* Symbols fed into one encoder */
+  } /* Encoders */
+
+  // fflush (stdout);
+}