commit-gnuradio
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Commit-gnuradio] gr-error-correcting-codes/src/lib Makefile.am _...


From: Michael Dickens
Subject: [Commit-gnuradio] gr-error-correcting-codes/src/lib Makefile.am _...
Date: Mon, 03 Jul 2006 02:12:54 +0000

CVSROOT:        /sources/gnuradio
Module name:    gr-error-correcting-codes
Changes by:     Michael Dickens <michaelld>     06/07/03 02:12:53

Added files:
        src/lib        : Makefile.am __init__.py ecc.i 
                         gr_decoder_viterbi_block_soft_full.cc 
                         gr_decoder_viterbi_block_soft_full.h 
                         gr_decoder_viterbi_block_soft_full.i 
                         gr_streams_encode_convolutional.cc 
                         gr_streams_encode_convolutional.h 
                         gr_streams_encode_convolutional.i 
                         gr_syms_to_metrics.cc gr_syms_to_metrics.h 
                         gr_syms_to_metrics.i qa_ecc.py 

Log message:
        Initial checkin.  Work in progress.  More blocks coming.

CVSWeb URLs:
http://cvs.savannah.gnu.org/viewcvs/gr-error-correcting-codes/src/lib/Makefile.am?cvsroot=gnuradio&rev=1.1
http://cvs.savannah.gnu.org/viewcvs/gr-error-correcting-codes/src/lib/__init__.py?cvsroot=gnuradio&rev=1.1
http://cvs.savannah.gnu.org/viewcvs/gr-error-correcting-codes/src/lib/ecc.i?cvsroot=gnuradio&rev=1.1
http://cvs.savannah.gnu.org/viewcvs/gr-error-correcting-codes/src/lib/gr_decoder_viterbi_block_soft_full.cc?cvsroot=gnuradio&rev=1.1
http://cvs.savannah.gnu.org/viewcvs/gr-error-correcting-codes/src/lib/gr_decoder_viterbi_block_soft_full.h?cvsroot=gnuradio&rev=1.1
http://cvs.savannah.gnu.org/viewcvs/gr-error-correcting-codes/src/lib/gr_decoder_viterbi_block_soft_full.i?cvsroot=gnuradio&rev=1.1
http://cvs.savannah.gnu.org/viewcvs/gr-error-correcting-codes/src/lib/gr_streams_encode_convolutional.cc?cvsroot=gnuradio&rev=1.1
http://cvs.savannah.gnu.org/viewcvs/gr-error-correcting-codes/src/lib/gr_streams_encode_convolutional.h?cvsroot=gnuradio&rev=1.1
http://cvs.savannah.gnu.org/viewcvs/gr-error-correcting-codes/src/lib/gr_streams_encode_convolutional.i?cvsroot=gnuradio&rev=1.1
http://cvs.savannah.gnu.org/viewcvs/gr-error-correcting-codes/src/lib/gr_syms_to_metrics.cc?cvsroot=gnuradio&rev=1.1
http://cvs.savannah.gnu.org/viewcvs/gr-error-correcting-codes/src/lib/gr_syms_to_metrics.h?cvsroot=gnuradio&rev=1.1
http://cvs.savannah.gnu.org/viewcvs/gr-error-correcting-codes/src/lib/gr_syms_to_metrics.i?cvsroot=gnuradio&rev=1.1
http://cvs.savannah.gnu.org/viewcvs/gr-error-correcting-codes/src/lib/qa_ecc.py?cvsroot=gnuradio&rev=1.1

Patches:
Index: Makefile.am
===================================================================
RCS file: Makefile.am
diff -N Makefile.am
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ Makefile.am 3 Jul 2006 02:12:53 -0000       1.1
@@ -0,0 +1,96 @@
+#
+# Copyright 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 $(top_srcdir)/Makefile.common
+
+SUBDIRS = libecc .
+
+# Install this stuff so that it ends up as the gnuradio.und module
+# This usually ends up at:
+#   ${prefix}/lib/python${python_version}/site-packages/gnuradio
+
+ourpythondir = $(grpythondir)
+ourlibdir    = $(grpythondir)
+
+INCLUDES = $(STD_DEFINES_AND_INCLUDES) $(PYTHON_CPPFLAGS) $(GNURADIO_INCLUDES)
+
+SWIGCPPPYTHONARGS = -fvirtual -python -modern $(PYTHON_CPPFLAGS) \
+       $(GNURADIO_INCLUDES)
+
+ALL_IFILES =                           \
+       $(LOCAL_IFILES)                 \
+       $(NON_LOCAL_IFILES)
+
+NON_LOCAL_IFILES =                     \
+       $(GNURADIO_CORE_INCLUDEDIR)/swig/gnuradio.i
+
+LOCAL_IFILES =                                         \
+       gr_syms_to_metrics.i                    \
+       gr_decoder_viterbi_block_soft_full.i    \
+       gr_streams_encode_convolutional.i       \
+       ecc.i
+
+# These files are built by SWIG.  The first is the C++ glue.
+# The second is the python wrapper that loads the _howto shared library
+# and knows how to call our extensions.
+
+BUILT_SOURCES =        \
+       ecc.cc          \
+       ecc.py          
+
+# This gets ecc.py installed in the right place
+ourpython_PYTHON =                     \
+       __init__.py                     \
+       ecc.py
+
+ourlib_LTLIBRARIES = _ecc.la
+
+# These are the source files that go into the shared library
+_ecc_la_SOURCES =              \
+       gr_syms_to_metrics.cc                   \
+       gr_decoder_viterbi_block_soft_full.cc   \
+       gr_streams_encode_convolutional.cc      \
+       ecc.cc
+
+# magic flags
+_ecc_la_LDFLAGS = $(NO_UNDEFINED) -module -avoid-version
+
+# link the library against the c++ standard library
+_ecc_la_LIBADD =               \
+       libecc/libecc.la        \
+       $(PYTHON_LDFLAGS)       \
+       -lstdc++
+
+ecc.cc ecc.py: ecc.i $(ALL_IFILES)
+       $(SWIG) $(SWIGCPPPYTHONARGS) -module ecc -o ecc.cc $<
+
+# These headers get installed in ${prefix}/include/gnuradio
+grinclude_HEADERS =                            \
+       gr_syms_to_metrics.h                    \
+       gr_decoder_viterbi_block_soft_full.h    \
+       gr_streams_encode_convolutional.h
+
+# These swig headers get installed in ${prefix}/include/gnuradio/swig
+swiginclude_HEADERS = $(LOCAL_IFILES)
+
+MOSTLYCLEANFILES = $(BUILT_SOURCES) *.pyc *.loT *~
+
+CONFIG_CLEAN_FILES = *.in

Index: __init__.py
===================================================================
RCS file: __init__.py
diff -N __init__.py
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ __init__.py 3 Jul 2006 02:12:53 -0000       1.1
@@ -0,0 +1,20 @@
+#
+# Copyright 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.
+# 

Index: ecc.i
===================================================================
RCS file: ecc.i
diff -N ecc.i
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ ecc.i       3 Jul 2006 02:12:53 -0000       1.1
@@ -0,0 +1,39 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 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.
+ */
+
+%feature("autodoc","1");
+%include "exception.i"
+%import "gnuradio.i"
+
+%{
+
+#include "gnuradio_swig_bug_workaround.h"      // mandatory bug fix
+#include <gr_streams_encode_convolutional.h>
+#include <gr_decoder_viterbi_block_soft_full.h>
+#include <gr_syms_to_metrics.h>
+#include <stdexcept>
+
+%}
+
+%include "gr_streams_encode_convolutional.i"
+%include "gr_decoder_viterbi_block_soft_full.i"
+%include "gr_syms_to_metrics.i"

Index: gr_decoder_viterbi_block_soft_full.cc
===================================================================
RCS file: gr_decoder_viterbi_block_soft_full.cc
diff -N gr_decoder_viterbi_block_soft_full.cc
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ gr_decoder_viterbi_block_soft_full.cc       3 Jul 2006 02:12:53 -0000       
1.1
@@ -0,0 +1,1485 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 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.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <gr_dec_blk_conv_soft_full.h>
+#include <gr_io_signature.h>
+#include <assert.h>
+#include <iostream>
+
+const int g_max_frame_size_bits = 10000000;
+const int g_max_num_streams = 10;
+const int g_num_bits_per_byte = 8;
+const int g_max_stream_el_size_bytes = 128;
+
+#define DO_TIME_THOUGHPUT 0
+#define DO_PRINT_DEBUG_INST 0
+#define DO_PRINT_DEBUG_INST_0 0
+#define DO_PRINT_DEBUG_INST_1 0
+#define DO_PRINT_DEBUG_INST_2 0
+#define DO_PRINT_DEBUG_FSM 0
+#define DO_PRINT_DEBUG_INIT 0
+#define DO_PRINT_DEBUG_UP 0
+#define DO_PRINT_DEBUG_UP_0 0
+#define DO_PRINT_DEBUG_UP_1 0
+#define DO_PRINT_DEBUG_MIDDLE 0
+#define DO_PRINT_DEBUG_MIDDLE_0 0
+#define DO_PRINT_DEBUG_MIDDLE_1 0
+#define DO_PRINT_DEBUG_TERM 0
+#define DO_PRINT_DEBUG_TERM_1 0
+#define DO_PRINT_DEBUG_OUTPUT 0
+#define DO_PRINT_DEBUG_OUTPUT_0 0
+#define DO_PRINT_DEBUG_EXIT 0
+#define DO_PRINT_DEBUG 0
+
+#if DO_TIME_THOUGHPUT
+#include <mld/mld_timer.h>
+#endif
+#if DO_PRINT_DEBUG
+#include <mld/n2bs.h>
+#endif
+
+gr_decoder_viterbi_block_soft_full_sptr
+gr_make_dec_blk_conv_soft_full
+(int frame_size_bits,
+ int num_input_streams,
+ int num_output_streams,
+ std::vector<int> code_generator,
+ bool do_termination)
+{
+  return gr_decoder_viterbi_block_soft_full_sptr
+    (new gr_decoder_viterbi_block_soft_full (frame_size_bits,
+                                            num_input_streams,
+                                            num_output_streams,
+                                            code_generator,
+                                            do_termination));
+}
+
+gr_decoder_viterbi_block_soft_full::gr_decoder_viterbi_block_soft_full
+(int frame_size_bits,
+ int num_input_streams,
+ int num_output_streams,
+ std::vector<int> code_generator,
+ bool do_termination)
+  : gr_block ("dec_blk_conv_soft_full",
+             gr_make_io_signature (0, 0, 0),
+             gr_make_io_signature (0, 0, 0))
+{
+// make sure the frame length makes sense, #1 - more later
+  if (frame_size_bits > g_max_frame_size_bits) {
+    std::cerr << "gr_decoder_viterbi_block_soft_full: " <<
+      "Requested frame length (" << frame_size_bits <<
+      " bits) must be at most " << g_max_frame_size_bits << " bits.\n";
+    assert (0);
+  }
+
+// check to make sure the number of input streams makes sense
+  if ((n_code_inputs <= 0) | (n_code_inputs > g_max_num_streams)) {
+    std::cerr << "gr_decoder_viterbi_block_soft_full: " <<
+      "Requested number of input streams (" <<
+      n_code_inputs << ") must be between 1 and " <<
+      g_max_num_streams << ".\n";
+    assert (0);
+  }
+
+// check to make sure the number of output streams makes sense
+  if ((n_code_outputs <= 0) | (n_code_outputs > g_max_num_streams)) {
+    std::cerr << "gr_decoder_viterbi_block_soft_full: " <<
+      "Requested number of output streams (" <<
+      n_code_outputs << ") must be between 1 and " <<
+      g_max_num_streams << ".\n";
+    assert (0);
+  }
+
+// make sure the code_generator is the correct length
+  if (code_generators.size () !=
+      ((size_t)(n_code_inputs * n_code_outputs))) {
+    std::cerr << "gr_decoder_viterbi_block_soft_full: " <<
+      "Number of code generator entries (" << code_generators.size () <<
+      ") is not equal to the product of the number of input and output" <<
+      " streams (" << (n_code_inputs * n_code_outputs) << ").\n";
+    assert (0);
+  }
+
+// create the class frame variables
+  d_frame_size_bits = frame_size_bits;
+  d_out_stream_el_size_bytes = out_stream_el_size_bytes;
+  d_n_code_inputs = n_code_inputs;
+  d_n_code_outputs = n_code_outputs;
+  d_do_streaming = (frame_size_bits == 0);
+  d_do_termination = (d_do_streaming == true) ? false : do_termination;
+  d_do_mux_inputs = do_mux_inputs;
+
+// allocate the vectors for doing the encoding.  use 32-bit int's
+// actual bits to represent memory and the code, as it makes the
+// operations quite simple the state vectors.
+// code generates are for each I/O combination
+
+  d_code_generators.resize (d_n_code_inputs * d_n_code_outputs, 0);
+
+// check the input code_generator for correctness & find the memory order
+// t_max_mem will be the mamimum number of memories used by the generator
+// t_code_ndx is a counter over all input code_generator elements
+  int t_max_mem = 0, t_code_ndx = d_code_generators.size() - 1;
+// loop over all input streams first, output streams second
+  for (int n = d_n_code_outputs - 1; n >= 0; n--) {
+    int t_all_inputs_zero = 0;
+    for (int m = d_n_code_inputs - 1; m >= 0; m--) {
+      int t_in_code = code_generators[t_code_ndx];
+      t_all_inputs_zero |= t_in_code;
+      int t_code_mem = 0;
+// find the memory requirement for this code generator
+      while (t_in_code != 0) {
+       t_in_code >>= 1;
+       t_code_mem++;
+      }
+      if (t_code_mem > t_max_mem)
+       t_max_mem = t_code_mem;
+// store in d_code_generators in output-first ordering
+      d_code_generators[(m*d_n_code_outputs) + n] =
+       code_generators[t_code_ndx--];
+    }
+    if (t_all_inputs_zero == 0) {
+      std::cerr << "gr_decoder_viterbi_block_soft_full: " <<
+       "At least 1 generator code for encode-output " << n+1 <<
+       " must be non-0.\n";
+      assert (0);
+    }
+  }
+
+// store the maximum memory order (e.g. "2" -> D^2)
+  d_max_memory = t_max_mem - 1;
+
+// make sure the frame length makes sense, #2
+  if (d_frame_size_bits < d_max_memory) {
+    std::cerr << "gr_decoder_viterbi_block_soft_full: " <<
+      "Requested frame length (" << d_frame_size_bits <<
+      " bit" << (d_frame_size_bits > 1 ? "s" : "") <<
+      ") must be at least 1 memory length (" << d_max_memory <<
+      " bit" << (d_max_memory > 1 ? "s" : "") <<
+      " for this code).\n";
+    assert (0);
+  }
+
+// NOTE: d_n_states is a 'u_long', and thus is quite limited in terms
+// of max memory and # of input streams to 2^32 states
+// This is OK, since that many states would be impossibly slow to decode!
+// might make this a "long long" (64 bits) in the future
+  d_n_states = 1 << (d_max_memory * d_n_code_inputs);
+  d_n_input_combinations = 1 << d_n_code_inputs;
+
+#if DO_PRINT_DEBUG_INST_0
+  std::cout << "Init:\n" <<
+    "d_frame_size_bits          = " << d_frame_size_bits << "\n" <<
+    "d_out_stream_el_size_bytes = " << d_out_stream_el_size_bytes << "\n" <<
+    "d_n_code_inputs            = " << d_n_code_inputs << "\n" <<
+    "d_n_code_outputs           = " << d_n_code_outputs << "\n" <<
+    "d_do_streaming             = " <<
+    ((d_do_streaming == true) ? "true" : "false") << "\n" <<
+    "d_do_termination           = " <<
+    ((d_do_termination == true) ? "true" : "false") << "\n" <<
+    "d_do_mux_inputs            = " <<
+    ((d_do_mux_inputs == true) ? "true" : "false") << "\n" <<
+    "d_max_memory               = " << d_max_memory << "\n" <<
+    "d_n_states                 = " << d_n_states << "\n" <<
+    "d_n_input_combinations     = " << d_n_input_combinations << "\n";
+#endif
+
+// leave the output multiple at 1 (element); will save any incomplete
+// output data (int's) in "d_save_buffer"; all input data will be consumed
+
+// create the correct input signature
+  int t_n_input_streams = ((d_do_mux_inputs == true) ?
+                          1 : n_code_outputs);
+
+  set_input_signature (gr_make_io_signature (t_n_input_streams,
+                                            t_n_input_streams,
+                                            sizeof (float)));
+// create the correct output signature
+  set_output_signature (gr_make_io_signature (n_code_inputs,
+                                             n_code_inputs,
+                                             d_out_stream_el_size_bytes));
+#if DO_PRINT_DEBUG_INST_0
+  std::cout <<
+    "input_signature            = [" << t_n_input_streams << ", " <<
+    t_n_input_streams << ", " << sizeof (float) << "]\n" <<
+    "output_signature           = [" << n_code_outputs << ", " <<
+    n_code_outputs << ", " << d_out_stream_el_size_bytes << "]\n";
+#endif
+
+// always start the fsm in the "init" state
+  d_fsm = fsm_dec_init;
+
+// create a vector of indexes to states when doing "up" or "termination";
+  d_up_term_states_ndx[0] = new size_t [d_n_states];
+  d_up_term_states_ndx[1] = new size_t [d_n_states];
+
+// create the traceback buffers
+// get the total number of out bits per stream
+  d_n_total_input_bits_per_stream = d_frame_size_bits;
+  if (d_do_termination == true)
+    d_n_total_input_bits_per_stream += d_max_memory;
+  d_n_traceback_els = d_n_total_input_bits_per_stream + 1;
+// create the output buffers:
+// this is a 2d matrix structure, where the first dimension
+// is the number of output bits; the second dimension is
+// the number of states.
+// When doing full frames (no tau), each bit-time's state's traceback
+// contains just the pointer to the previous bit-time's state's traceback
+// as well as the inputs for that connection.
+// No further work is required because each reverse-path is unique
+// once a given end-bit-time's state is determined to be "the one"
+  traceback_t_hdl t_out_buf =
+    d_out_buf = new traceback_t_ptr [d_n_traceback_els];
+  for (size_t n = d_n_traceback_els; n > 0; n--) {
+    (*t_out_buf++) = new traceback_t [d_n_states];
+  }
+
+  // create the save buffers
+  char** t_save_buffer = d_save_buffer = new char* [d_n_code_inputs];
+  size_t t_n_out_bytes = ((d_frame_size_bits / g_num_bits_per_byte) +
+                         ((d_frame_size_bits % g_num_bits_per_byte) ? 1 : 0));
+  for (size_t n = 0; n < d_n_code_inputs; n++) {
+    (*t_save_buffer++) = new char [t_n_out_bytes];
+  }
+
+// reset the number of saved bits
+  d_n_saved_bits_start_ndx = d_n_saved_bits = 0;
+
+// setup the internal structures for exiting and entering states
+
+#if DO_PRINT_DEBUG_INST_0
+  std::cout <<
+    "d_n_total in bits / stream = " << d_n_total_input_bits_per_stream << "\n" 
<<
+    "d_n_traceback_els          = " << d_n_traceback_els << "\n" <<
+    "t_n_out_bytes / stream     = " << t_n_out_bytes << "\n";
+#endif
+
+// Find the approximate output rate / input rate
+// each input item produces 1 bit of an output item w/o termination
+  double t_rel_rate = (double)(d_out_stream_el_size_bytes * 
g_num_bits_per_byte);
+  if (d_do_termination == true) {
+// include termination bits
+    t_rel_rate *= (((double) d_frame_size_bits) /
+                  ((double) d_n_total_input_bits_per_stream));
+  }
+// Set the approximate output rate / input rate
+  set_relative_rate (t_rel_rate);
+
+// 'new' everything first; no connections yet
+  state_t_ptr t_state = d_states[0] = new state_t [d_n_states];
+  for (size_t n = d_n_states; n > 0; n--, t_state++) {
+    connection_t_ptr t_connection = t_state->d_connections
+      = new connection_t [d_n_input_combinations];
+    for (size_t m = d_n_input_combinations; m > 0; m--, t_connection++) {
+      t_connection->d_output_bits = new float [d_n_code_outputs];
+    }
+  }
+
+// 'new' everything first; no connections yet
+  t_state = d_states[1] = new state_t [d_n_states];
+  for (size_t n = d_n_states; n > 0; n--, t_state++) {
+    connection_t_ptr t_connection = t_state->d_connections
+      = new connection_t [d_n_input_combinations];
+    for (size_t m = d_n_input_combinations; m > 0; m--, t_connection++) {
+      t_connection->d_output_bits = new float [d_n_code_outputs];
+    }
+  }
+
+// temporary memory and mask for output bit computations
+  size_t t_memory[d_n_code_inputs];
+  size_t t_memory_mask = ((2 << d_max_memory) - 1) ^ 1;
+
+#if DO_PRINT_DEBUG
+  size_t t_state_print_bits = (d_max_memory * d_n_code_inputs) + 1;
+  size_t t_mem_print_bits = d_max_memory + 2;
+
+  std::cout << "Setting States and Connections\n";
+#endif
+
+// loop over all possible memory states
+  state_t_ptr t_state0 = d_states[0];
+  state_t_ptr t_state1 = d_states[1];
+  for (size_t n = 0; n < d_n_states; n++, t_state0++, t_state1++) {
+#if DO_PRINT_DEBUG_INST_1
+    std::cout << "Starting state # " << n << " == " <<
+      n2bs (n, t_state_print_bits) << "\n";
+#endif
+// retrieve the memory values for this state
+// probably a faster way to do this, but since this is
+// executed only upon instantiation, whatever.
+    size_t* t_mem_ptr = t_memory;
+    for (size_t p = 0; p < d_n_code_inputs; p++) {
+      int t_mem = state_get_from (n, p, d_max_memory);
+#if DO_PRINT_DEBUG_INST_1
+      std::cout << "s_g_f (" <<
+       n2bs (n, t_state_print_bits) << ", " <<
+       p << ", " << d_max_memory << ") => t_m = " <<
+       n2bs (t_mem, t_mem_print_bits) << "\n";
+#endif
+// shift them by 1 (and mask) to make updating for all inputs simple
+      (*t_mem_ptr++) = t_mem << 1;
+#if DO_PRINT_DEBUG_INST_1
+      std::cout << "t_m_p[" << p << "] = " <<
+       n2bs (t_mem << 1, t_mem_print_bits) << " == (" <<
+       n2bs (t_mem, t_mem_print_bits) << " << 1)\n";
+#endif
+    }
+
+// loop over all possible input values, 1 bit per input stream
+    connection_t_ptr t_connection0 = t_state0->d_connections;
+    connection_t_ptr t_connection1 = t_state1->d_connections;
+    for (size_t q = 0; q < d_n_input_combinations;
+        q++, t_connection0++, t_connection1++) {
+#if DO_PRINT_DEBUG_INST_1
+      std::cout << "Starting inputs " << q << " == " <<
+       n2bs (q, d_n_code_inputs + 1) << "\n";
+#endif
+
+// update memory for this set of inputs
+      t_mem_ptr = t_memory;
+      size_t t_this_input = q;
+
+// loop over all code inputs, and update just the single input bit
+      for (size_t r = d_n_code_inputs; r > 0; r--) {
+       int t_mem = (*t_mem_ptr) & t_memory_mask;
+#if DO_PRINT_DEBUG_INST_1
+       std::cout << "t_m = " << n2bs (t_mem, t_mem_print_bits) <<
+         " == " << n2bs (*t_mem_ptr, t_mem_print_bits) <<
+         " & " << n2bs (t_memory_mask, t_mem_print_bits) << "\n";
+#endif
+       (*t_mem_ptr++) = t_mem | (t_this_input & 1);
+#if DO_PRINT_DEBUG_INST_1
+       std::cout << "t_m_p[" << (d_n_code_inputs - r) << "] = " <<
+         n2bs (t_mem | (t_this_input & 1), t_mem_print_bits) <<
+         " == t_m | " << (t_this_input & 1) << "\n";
+#endif
+       t_this_input >>= 1;
+      }
+
+// got the updated memory for this particular state & inputs
+// recreate the "to" state from the updated memory
+      t_mem_ptr = t_memory;
+      size_t t_out_state = 0;
+      for (size_t p = 0; p < d_n_code_inputs; p++) {
+#if DO_PRINT_DEBUG_INST_1
+       std::cout << "s_a_t (" <<
+         n2bs (t_out_state, t_state_print_bits) <<
+         ", " << n2bs (*t_mem_ptr, t_mem_print_bits) << ", " << p <<
+         ", " << d_max_memory << ") ==> t_o_s out = ";
+#endif
+       state_add_to (t_out_state, *t_mem_ptr++, p, d_max_memory);
+#if DO_PRINT_DEBUG_INST_1
+       std::cout << n2bs (t_out_state, t_state_print_bits) << "\n";
+#endif
+      }
+
+// get the "to" state pointers from d_states[0] to [1]
+      state_t_ptr t_to_state = &(d_states[1][t_out_state]);
+      t_connection0->d_to = t_to_state;
+      t_connection0->d_to_ndx = t_out_state;
+      float* t_output_bit0 = t_connection0->d_output_bits;
+
+// get the "to" state pointers from d_states[1] to [0]
+      t_to_state = &(d_states[0][t_out_state]);
+      t_connection1->d_to = t_to_state;
+      t_connection1->d_to_ndx = t_out_state;
+      float* t_output_bit1 = t_connection1->d_output_bits;
+
+// determine the ideal output values: loop over all outputs
+      size_t t_vec_ctr = 0;
+      for (size_t s = 0; s < d_n_code_outputs; s++) {
+
+// loop over all inputs, xor'ing the result each time
+       int t_out_result = 0;
+       t_mem_ptr = t_memory;
+       for (size_t t = 0; t < d_n_code_inputs; t++) {
+#if DO_PRINT_DEBUG_INST_1
+         std::cout << "b_i = " << n2bs (t_out_result, t_mem_print_bits) <<
+           ", st[" << t << "] = " << n2bs ((*t_mem_ptr), t_mem_print_bits) <<
+           ", cg[" << t_vec_ctr << "] = " <<
+           n2bs (d_code_generators[t_vec_ctr], t_mem_print_bits) <<
+           ", st[] & cg[] = " << n2bs ((*t_mem_ptr) &
+                                       d_code_generators[t_vec_ctr],
+                                       t_mem_print_bits);
+#endif
+         t_out_result ^= ((*t_mem_ptr++) &
+                          d_code_generators[t_vec_ctr++]);
+#if DO_PRINT_DEBUG_INST_1
+         std::cout << ", b_o = " <<
+           n2bs (t_out_result, t_mem_print_bits) << '\n';
+#endif
+       }
+#if DO_PRINT_DEBUG_INST_1
+       std::cout << "b_r = " << n2bs (t_out_result, t_mem_print_bits);
+#endif
+// sum the number of set bits, mod 2, for the output bit
+       size_t t_out_bit = t_out_result & 1;
+       for (size_t v = d_max_memory; v > 0; v--) {
+         t_out_result >>= 1;
+         t_out_bit ^= (t_out_result & 1);
+       }
+
+// store the result for this particular output stream,
+// converting the bit 1 -> +1.0, and 0 -> -1.0
+        float t_out_value = (float)(((int)(t_out_bit << 1)) - 1);
+       *t_output_bit0++ = t_out_value;
+       *t_output_bit1++ = t_out_value;
+#if DO_PRINT_DEBUG_INST_1
+       std::cout << ", o_v = " << t_out_value << "\n";
+#endif
+
+// finished (for) all output values
+      }
+// finished (for) over all possible input values
+    }
+// finished (for) over all possible states
+  }
+
+// so now d_states is/are completely populated!
+// These make for simple access to looping over all possible inputs or
+// outputs for a given state to determine what the path with the best
+// metric is.
+
+#if DO_PRINT_DEBUG_INST_2
+// loop over all possible memory states
+  std::cout << "State Tables\n";
+  t_state0 = d_states[0];
+  t_state1 = d_states[1];
+  for (size_t n = 0; n < d_n_states; n++, t_state0++, t_state1++) {
+    std::cout << "d_s[0][" << n << "] = " << t_state0 << "\n";
+// loop over all possible input values, 1 bit per input stream
+    connection_t_ptr t_connection0 = t_state0->d_connections;
+    for (size_t q = 0; q < d_n_input_combinations; q++, t_connection0++) {
+      std::cout << "s0[" << n2bs (n, t_state_print_bits) << "][" <<
+       n2bs (q, d_n_code_inputs+1) << "] = " << t_connection0 <<
+       " -> s1[" << n2bs (t_connection0->d_to_ndx, t_state_print_bits) <<
+       "] = " << t_connection0->d_to << "\n";
+    }
+    std::cout << "d_s[1][" << n << "] = " << t_state1 << "\n";
+    connection_t_ptr t_connection1 = t_state1->d_connections;
+    for (size_t q = 0; q < d_n_input_combinations; q++, t_connection1++) {
+      std::cout << "s1[" << n2bs (n, t_state_print_bits) << "][" <<
+       n2bs (q, d_n_code_inputs+1) << "] = " << t_connection1 <<
+       " -> s0[" << n2bs (t_connection1->d_to_ndx, t_state_print_bits) <<
+       "] = " << t_connection1->d_to << "\n";
+    }
+  }
+
+  traceback_t_hdl t_out_bufs = d_out_buf;
+  for (size_t n = 0; n < d_n_traceback_els; n++, *t_out_bufs++) {
+    traceback_t_ptr t_out_buf = *t_out_bufs;
+    for (size_t m = 0; m < d_n_states; m++, t_out_buf++) {
+      std::cout << "tb[" << n << "] = " << t_out_bufs <<
+       ", &tb[" << n << "][" << m << "] = " << (&d_out_buf[n][m]) <<
+       ", tb[" << n << "," << m << "] = " << t_out_buf << "\n";
+    }
+  }
+
+  std::cout << "Done with instantiation.\n";
+#endif
+}
+
+gr_decoder_viterbi_block_soft_full::~gr_decoder_viterbi_block_soft_full
+()
+{
+// reverse over from allocation
+
+  delete [] d_up_term_states_ndx[0];
+  delete [] d_up_term_states_ndx[1];
+
+// delete the state's structures
+  state_t_ptr t_state = d_states[0];
+  for (size_t n = d_n_states; n > 0; n--, t_state++) {
+    connection_t_ptr t_connection = t_state->d_connections;
+    for (size_t m = d_n_input_combinations; m > 0; m--, t_connection++) {
+      delete [] t_connection->d_output_bits;
+    }
+    delete [] t_state->d_connections;
+  }
+  delete [] d_states[0];
+
+  t_state = d_states[1];
+  for (size_t n = d_n_states; n > 0; n--, t_state++) {
+    connection_t_ptr t_connection = t_state->d_connections;
+    for (size_t m = d_n_input_combinations; m > 0; m--, t_connection++) {
+      delete [] t_connection->d_output_bits;
+    }
+    delete [] t_state->d_connections;
+  }
+  delete [] d_states[1];
+
+// delete the save buffer
+  char** t_save_buffer = d_save_buffer;
+  for (size_t n = 0; n < d_n_code_inputs; n++) {
+    delete [] (*t_save_buffer++);
+  }
+  delete [] d_save_buffer;
+
+// delete the output buffer
+  traceback_t_hdl t_out_buf = d_out_buf;
+  for (size_t n = d_n_traceback_els; n > 0; n--) {
+    delete [] (*t_out_buf++);
+  }
+  delete [] d_out_buf;
+}
+
+void gr_decoder_viterbi_block_soft_full::reset_metrics (u_char which)
+{
+  state_t_ptr t_state = d_states[which&1];
+  for (size_t n = d_n_states; n > 0; n--, t_state++) {
+    t_state->d_max_metric = -1e10;
+#if 0
+// probably don't need to do these, try removing them later
+    t_state->d_max_state_ndx = 0;
+    t_state->d_max_input = -1;
+#endif
+  }
+}
+
+void gr_decoder_viterbi_block_soft_full::zero_metrics (u_char which)
+{
+  state_t_ptr t_state = d_states[which&1];
+  for (size_t n = d_n_states; n > 0; n--, t_state++) {
+    t_state->d_max_metric = 0;
+#if 0
+// probably don't need to do these, try removing them later
+    t_state->d_max_state_ndx = -1;
+    t_state->d_max_input = -1;
+#endif
+  }
+}
+
+void gr_decoder_viterbi_block_soft_full::forecast
+(int noutput_items,
+ gr_vector_int &ninput_items_required)
+{
+  int ninput_items = fixed_rate_noutput_to_ninput (noutput_items);
+
+  int ninputs = ninput_items_required.size();
+  for (int n = 0; n < ninputs; n++)
+    ninput_items_required[n] = ninput_items;
+}
+
+/*
+ * Compute the number of input items (soft symbols [floats]) needed to produce
+ * 'noutput' items (elements).  For convolutional decoders, there is 1
+ * bit output per bit input per stream, with the addition of a some
+ * bits for trellis termination if selected.  Without termination,
+ * there is exactly 1:1 input to output (1 symbol in to 1 bit out),
+ * no matter the encoding type.
+ *
+ * if (not terminating), then get the number of output bytes.
+ *
+ * otherwise, find the number of frames (not necessarily and integer),
+ * and then compute the number of input bits (including termination)
+ * required to produce those frames.  Subtract the number of bits
+ * leftover from the previous computation, then find the number of input
+ * elements (soft symbols), ceil'd to make sure there are enough.
+ *
+ * finally, if the input streams are mux'ed, then multiply by the
+ * number of inputs.
+ */
+
+int
+gr_decoder_viterbi_block_soft_full::fixed_rate_noutput_to_ninput
+(int noutput_items)
+{
+  int t_ninput_items = 0;
+  int t_noutput_bits = (noutput_items * d_out_stream_el_size_bytes *
+                        g_num_bits_per_byte) - d_n_saved_bits;
+// if there are enough saved bits, just use those, no inputs required
+  if (t_noutput_bits <= 0)
+    return (t_ninput_items);
+
+// remove any bits already in the decoding trellis
+  if (d_time_count != 0) {
+    int t_time_bits = ((d_time_count > d_frame_size_bits) ? 0 :
+                      d_frame_size_bits - d_time_count);
+    t_noutput_bits -= t_time_bits;
+    t_ninput_items += t_time_bits;
+  }
+// if completing this trellis doesn't create enough outputs ...
+  if (t_noutput_bits > 0) {
+
+// there is a 1:1 ratio between input symbols and output bits (per
+// stream), except for termination bits which are already taken into
+// account in the total # of input bits per stream class variable;
+// need to round the # output bits to the
+
+// find the number of frames, ceil'd to the next higher integer
+    int t_nframes = (int) ceilf (((float) t_noutput_bits) /
+                                ((float) d_frame_size_bits));
+// find the number of required input bits
+    t_ninput_items += t_nframes * d_n_total_input_bits_per_stream;
+  }
+
+// if doing mux'ing, there are more elements in the single input
+  if (d_do_mux_inputs == true) {
+    t_ninput_items *= d_n_code_outputs;
+  }
+  return (t_ninput_items);
+}
+
+int
+gr_decoder_viterbi_block_soft_full::general_work
+(int noutput_items,
+ gr_vector_int &ninput_items,
+ gr_vector_const_void_star &input_items,
+ gr_vector_void_star &output_items)
+{
+#if DO_TIME_THOUGHPUT
+  struct timeval t_tp;
+  start_timer (&t_tp);
+#endif
+#if DO_PRINT_DEBUG
+  size_t t_state_print_bits = (d_max_memory * d_n_code_inputs) + 1;
+  size_t t_mem_print_bits = d_max_memory + 2;
+#endif
+// setup variables for quicker access
+  const float **in_buf = (const float **) &input_items[0];
+  char **out_buf = (char **) &output_items[0];
+  int t_in_buf_ndx = 0, t_out_buf_ndx = 0;
+  int t_out_bit_shift = 0;
+  int t_ninput_items = fixed_rate_noutput_to_ninput (noutput_items);
+  int t_noutput_bytes = noutput_items * d_out_stream_el_size_bytes;
+
+#if DO_PRINT_DEBUG_INST
+  std::cout << "# output items = " << noutput_items << " (" <<
+    t_noutput_bytes << " Bytes, " << (t_noutput_bytes * g_num_bits_per_byte) <<
+    " bits), # input items = " << t_ninput_items << " Symbols\n";
+  for (size_t n = 0; n < ninput_items.size(); n++) {
+    std::cout << "# input items [" << n << "] = " << ninput_items[n] << "\n";
+  }
+#endif
+
+// put any leftover bits into the output
+  if (d_n_saved_bits != 0) {
+// copy the leftover from the save buffer
+// check to make sure it will all fit
+    size_t t_noutput_bits = t_noutput_bytes * g_num_bits_per_byte;
+    size_t t_n_copy;
+    if (t_noutput_bits < d_n_saved_bits) {
+// asking for fewer bits than available; set to copy
+// just what's being asked for
+      t_n_copy = t_noutput_bytes;
+    } else {
+// asking for at least as many bits as available; set to copy all
+      t_out_buf_ndx = d_n_saved_bits / g_num_bits_per_byte;
+      t_out_bit_shift = d_n_saved_bits % g_num_bits_per_byte;
+      t_n_copy = t_out_buf_ndx + (t_out_bit_shift != 0 ? 1 : 0);
+    }
+// do the copy for all output streams (code inputs)
+// copy starting at save buffer index "start"
+    for (size_t n = 0; n < d_n_code_inputs; n++)
+      bcopy (&(d_save_buffer[n][d_n_saved_bits_start_ndx]),
+            out_buf[n], t_n_copy);
+#if DO_PRINT_DEBUG_INST
+    std::cout << "Copied " << t_n_copy << " Byte" <<
+      (t_n_copy != 1 ? "s" : "") << ": s_b[][" <<
+      d_n_saved_bits_start_ndx << "] => o_b[][0]\n" <<
+      "# saved bits = " << d_n_saved_bits <<
+      ", o_b_ndx = " << t_out_buf_ndx <<
+      ", bit shift = " << t_out_bit_shift << "\n";
+#endif
+//  update the number of saved bits and start
+    if (t_noutput_bits < d_n_saved_bits) {
+// asking for fewer bit than available: update
+// the number of saved bits and their starting index
+      d_n_saved_bits_start_ndx += t_noutput_bytes;
+      d_n_saved_bits -= (t_noutput_bytes * g_num_bits_per_byte);
+#if DO_PRINT_DEBUG_INST
+      std::cout << "Updated # saved bits = " << d_n_saved_bits <<
+       ", index = " << d_n_saved_bits_start_ndx << "\n";
+#endif
+// nothing to consume; return the desired number of output items
+      return (noutput_items);
+    } else {
+      d_n_saved_bits_start_ndx = d_n_saved_bits = 0;
+    }
+  }
+#if DO_PRINT_DEBUG_INST
+  std::cout << "Starting FSM in state: " <<
+    (d_fsm == fsm_dec_init ? "init" :
+     (d_fsm == fsm_dec_doing_up ? "up" :
+      (d_fsm == fsm_dec_doing_middle ? "middle" :
+       (d_fsm == fsm_dec_doing_term ? "term" :
+       (d_fsm == fsm_dec_output ? "output" : "unknown"))))) << "\n";
+#endif
+
+// while there are input items to create
+  while (t_out_buf_ndx < t_noutput_bytes) {
+#if DO_PRINT_DEBUG_FMS
+    std::cout << "Starting 'while': processing " << t_in_buf_ndx << " of " <<
+      t_ninput_items << " items.\nJumping to state '" <<
+      (d_fsm == fsm_dec_init ? "init" :
+       (d_fsm == fsm_dec_doing_up ? "up" :
+       (d_fsm == fsm_dec_doing_middle ? "middle" :
+        (d_fsm == fsm_dec_doing_term ? "term" :
+         (d_fsm == fsm_dec_output ? "output" : "unknown"))))) << "'\n";
+#endif
+// jump to the correct state in the fsm
+    switch (d_fsm) {
+    case fsm_dec_doing_up:
+#if DO_PRINT_DEBUG_FSM
+      std::cout << "Starting fsm_dec_doing_up\n";
+#endif
+// set the number of up_down indices
+      size_t t_n_up_down_ndx = 1 << (d_n_code_inputs *
+                                    d_time_count);
+// stay in this state until the correct number of input symbols are
+// reached; exit also if we run out of input symbols to process
+      while ((d_time_count < d_max_memory) &
+            (t_in_buf_ndx < t_ninput_items)) {
+#if DO_PRINT_DEBUG_UP_0
+       std::cout << "Doing 'while' loop:\n" <<
+         "t_n_up_down_ndx    = " << t_n_up_down_ndx << "\n" <<
+         "d_time_count       = " << d_time_count << "\n" <<
+         "d_max_memory       = " << d_max_memory << "\n" <<
+         "t_in_buf_ndx       = " << t_in_buf_ndx << "\n" <<
+         "t_ninput_items     = " << t_ninput_items << "\n";
+#endif
+// use the "from" states, loop over all inputs and compute the metric for
+// each & store it in the "to" state at the end of the connection.
+// no need to compare metrics yet, since none join into any given state
+
+#if 0
+// reset the "to" state's metrics
+// probably don't need to do this; try removing later
+        reset_metrics (d_states_ndx ^ 1);
+#if DO_PRINT_DEBUG_UP
+       std::cout << "Reset Metrics\n";
+#endif
+#endif
+
+// reset the state's index for each set of new inputs
+       size_t* t_state_ndx_ptr = d_up_term_states_ndx[d_up_term_ndx];
+       size_t* t_next_state_ndx_ptr = d_up_term_states_ndx[d_up_term_ndx ^ 1];
+// loop over all current stored "up" states
+       for (size_t n = 0; n < t_n_up_down_ndx; n++) {
+         size_t t_state_ndx = *t_state_ndx_ptr++;
+// get a pointer to this state's structure
+         state_t_ptr t_state = &(d_states[d_states_ndx][t_state_ndx]);
+// get the connections for all inputs
+         connection_t_ptr t_connection = t_state->d_connections;
+#if DO_PRINT_DEBUG_UP_0
+         std::cout << "Looping over all 'up' states:\n" <<
+           "n                  = " << n << "\n" <<
+           "t_n_up_down_ndx    = " << t_n_up_down_ndx << "\n" <<
+           "d_states_ndx       = " << d_states_ndx << "\n" <<
+           "t_state_ndx        = " << t_state_ndx << "\n" <<
+           "d_n_input_combs    = " << d_n_input_combinations << "\n" <<
+           "t_state            = " << t_state << "\n" <<
+           "t_connection       = " << t_connection << "\n";
+#endif
+// loop over all possible input values, 1 bit per input stream
+         for (size_t q = 0; q < d_n_input_combinations; q++, t_connection++) {
+// find the "to" state for this connection
+           state_t_ptr t_to_state = t_connection->d_to;
+// get the output bits for this connection
+           float* t_output_bit = t_connection->d_output_bits;
+// start with this state's metric
+           float t_metric = t_state->d_max_metric;
+#if DO_PRINT_DEBUG_UP_0
+           std::cout <<
+             "to state index     = " << t_connection->d_to_ndx << "\n" <<
+             "current metric     = " << t_metric << "\n";
+#endif
+           if (d_do_mux_inputs == true) {
+// if using mux'ed input streams, handle differently
+              const float* t_in_buf = &(in_buf[0][t_in_buf_ndx]);
+// loop over all encoder-output values
+             for (size_t r = d_n_code_outputs; r > 0; r--) {
+#if DO_PRINT_DEBUG_UP
+               std::cout << "in_sym = " << *t_in_buf << ", code_out_bit = " <<
+                 *t_output_bit << " ==> metric -> ";
+#endif
+               t_metric += ((*t_in_buf++) * (*t_output_bit++));
+#if DO_PRINT_DEBUG_UP
+               std::cout << t_metric << "\n";
+#endif
+             }
+           } else {
+// loop over all encoder-output values
+             for (size_t r = 0; r < d_n_code_outputs; r++) {
+#if DO_PRINT_DEBUG_UP
+               std::cout << "in_sym = " << in_buf[r][t_in_buf_ndx] <<
+                 ", code_out_bit = " << *t_output_bit << " ==> metric -> ";
+#endif
+               t_metric += (in_buf[r][t_in_buf_ndx] * (*t_output_bit++));
+#if DO_PRINT_DEBUG_UP
+               std::cout << t_metric << "\n";
+#endif
+             }
+           }
+// get the "to" state index
+           size_t t_to_ndx = t_connection->d_to_ndx;
+// store the metric in the "to" state; should not have been used before
+           t_to_state->d_max_metric = t_metric;
+// add the "to" state index to the "up" state list
+           *t_next_state_ndx_ptr++ = t_to_ndx;
+// update the traceback structure, depending on which variety it is
+// doing full trellis before decoding; use d_out_buf
+// simple: get the current state & output state
+           traceback_t_ptr t_out_buf = &(d_out_buf[d_time_count]
+                                         [t_state_ndx]);
+           traceback_t_ptr t_next_out_buf = &(d_out_buf[d_time_count+1]
+                                              [t_to_ndx]);
+#if DO_PRINT_DEBUG_UP_1
+           std::cout << "d_o_b[" << d_time_count+1 << "] => d_o_b prev\n" <<
+             "ndx[" << n << "] == " << t_state_ndx <<
+             ", s[" << n2bs(t_state_ndx,t_state_print_bits) <<
+             "]: max_ndx = " <<
+             n2bs(t_state->d_max_state_ndx,t_state_print_bits) <<
+             ", input = " << n2bs(q, d_n_code_inputs+1) <<
+             ": " << t_next_out_buf << " => " << t_out_buf << "\n";
+#endif
+// and connect output to the current, set inputs on output
+           t_next_out_buf->d_prev = t_out_buf;
+           t_next_out_buf->d_inputs = q;
+// finished (for) this input value
+         }
+// finished (for) this "up_term" state
+       }
+// increment the in_buf index, depending on mux'ing or not
+       t_in_buf_ndx += (d_do_mux_inputs == false) ? 1 : d_n_code_outputs;
+// increment the time counter
+        d_time_count++;
+// update the number of "up_term" states
+        d_up_term_ndx ^= 1;
+// increase the number of using states
+        t_n_up_down_ndx <<= d_n_code_inputs;
+// change which d_states' index to use as starting
+        d_states_ndx ^= 1;
+// finished (while) staying in this fsm state or not
+      }
+// if reached the end of doing the "up" part of the trellis,
+// switch states into the middle
+      if (d_time_count == d_max_memory) {
+#if DO_PRINT_DEBUG_FSM
+       std::cout << "Setting FSM to fsm_dec_doing_middle\n";
+#endif
+        d_fsm = fsm_dec_doing_middle;
+      }
+#if DO_PRINT_DEBUG_FSM
+      std::cout << "Exited fsm_dec_doing_up\n";
+#endif
+      break;
+    case (fsm_dec_doing_middle):
+#if DO_PRINT_DEBUG_FSM
+      std::cout << "Entered fsm_dec_doing_middle\n";
+#endif
+// stay in this state until the correct number of input symbols is
+// reached (if doing block coding), or until there are no more input
+// symbols to parse
+      while (((d_frame_size_bits != 0) &
+             (d_time_count < d_frame_size_bits) &
+             (t_in_buf_ndx < t_ninput_items)) |
+            ((d_frame_size_bits == 0) &
+             (t_in_buf_ndx < t_ninput_items))) {
+// use all states, loop over all inputs, compute the metric for
+// each; compare the current metric with all previous stored metric in the
+// endpoint of the connection to find the highest one.
+
+// reset the "to" state's metrics
+        reset_metrics (d_states_ndx ^ 1);
+// get the state's index for each set of new inputs
+       state_t_ptr t_state = d_states[d_states_ndx];
+#if DO_PRINT_DEBUG_MIDDLE
+       std::cout << "Time Count " << (d_time_count+1) << " of " <<
+         d_frame_size_bits << "\n" <<
+         "d_states_ndx = " << d_states_ndx << "\n";;
+#endif
+// loop over all current states
+       for (size_t n = 0; n < d_n_states; n++, t_state++) {
+// loop over all possible input values, 1 bit per input stream
+         connection_t_ptr t_connection = t_state->d_connections;
+#if DO_PRINT_DEBUG_MIDDLE_0
+         std::cout << "Looping over all 'middle' states: " <<
+           n << " of " << d_n_states << "\n";
+#endif
+         for (size_t q = 0; q < d_n_input_combinations; q++, t_connection++) {
+#if DO_PRINT_DEBUG_MIDDLE_0
+           std::cout << "Input = " << n2bs(q, d_n_code_inputs+1) << "\n";
+#endif
+// start with this state's metric
+           float t_metric = t_state->d_max_metric;
+// get the "to" state
+            state_t_ptr t_to_state = t_connection->d_to;
+// get that state's metric
+            float t_to_metric = t_to_state->d_max_metric;
+// see if the computation is even needed;
+// maximum change is d_n_code_outputs if all bits match exactly
+            if ((t_to_metric - t_metric) > ((float) 2*d_n_code_outputs)) {
+#if DO_PRINT_DEBUG_MIDDLE_0
+             std::cout << "!not computing metric!\n";
+#endif
+              continue;
+           }
+// metrics are close enough; do the computation and the compare
+// get the output bits for this connection
+           float* t_output_bit = t_connection->d_output_bits;
+           if (d_do_mux_inputs == true) {
+// if using mux'ed input streams, handle differently
+              const float* t_in_buf = &(in_buf[0][t_in_buf_ndx]);
+// loop over all encoder-output values
+             for (size_t r = d_n_code_outputs; r > 0; r--) {
+#if DO_PRINT_DEBUG_MIDDLE_0
+               std::cout << "in_sym = " << *t_in_buf << ", code_out_bit = " <<
+                 *t_output_bit << " ==> metric -> ";
+#endif
+               t_metric += ((*t_in_buf++) * (*t_output_bit++));
+#if DO_PRINT_DEBUG_MIDDLE_0
+               std::cout << t_metric << "\n";
+#endif
+             }
+           } else {
+// loop over all encoder-output values
+             for (size_t r = 0; r < d_n_code_outputs; r++) {
+#if DO_PRINT_DEBUG_MIDDLE_0
+               std::cout << "in_sym = " << in_buf[r][t_in_buf_ndx] <<
+                 ", code_out_bit = " << *t_output_bit << " ==> metric -> ";
+#endif
+               t_metric += (in_buf[r][t_in_buf_ndx] * (*t_output_bit++));
+#if DO_PRINT_DEBUG_MIDDLE_0
+               std::cout << t_metric << "\n";
+#endif
+             }
+           }
+// done with this input value; compare old and new metrics
+            if (t_metric > t_to_metric) {
+#if DO_PRINT_DEBUG_MIDDLE
+             std::cout << "New Metric to s[" <<
+               n2bs (t_connection->d_to_ndx,t_state_print_bits) << "]: ";
+             if (t_to_state->d_max_metric == -1e10) {
+               std::cout << "setting to ";
+             } else {
+               std::cout << "was s[" <<
+                 n2bs(t_to_state->d_max_state_ndx,t_state_print_bits) <<
+                 "]i[" << n2bs (t_to_state->d_max_input, d_n_code_inputs+1) <<
+                 "]@ " << t_to_state->d_max_metric << "  now ";
+             }
+             std::cout << "s[" << n2bs(n,t_state_print_bits) << "] i[" <<
+               n2bs (q, d_n_code_inputs+1) << "]@ " << t_metric << "\n";
+#endif
+// new metric is better; copy that info into the "to" state
+              t_to_state->d_max_metric = t_metric;
+              t_to_state->d_max_state_ndx = n;
+              t_to_state->d_max_input = q;
+            }
+// finished (for) this input value
+         }
+// finished (for) this state
+       }
+// done with all states and all inputs; now update the traceback structure
+// change which d_states' index to use as starting
+        d_states_ndx ^= 1;
+// get the state's index for the "to" set of new inputs to get the
+// "max" stuff from
+       t_state = d_states[d_states_ndx];
+// update the traceback structure
+// loop over all current states
+       traceback_t_ptr t_prev_out_bufs = d_out_buf[d_time_count];
+       traceback_t_ptr t_out_bufs = d_out_buf[d_time_count+1];
+#if DO_PRINT_DEBUG_MIDDLE_1
+       std::cout << "d_o_b[" << d_time_count+1 << "] => d_o_b prev\n";
+#endif
+       for (size_t n = d_n_states; n > 0; n--, t_state++) {
+// simple: get the current state & output state
+// and connect output to the current, set inputs on output
+         traceback_t_ptr t_out_buf = t_out_bufs++;
+         traceback_t_ptr t_prev_out_buf =
+           &(t_prev_out_bufs[t_state->d_max_state_ndx]);
+#if DO_PRINT_DEBUG_MIDDLE_1
+         std::cout << "s[" << n2bs(d_n_states-n,t_state_print_bits) <<
+           "]: max_ndx = " <<
+           n2bs(t_state->d_max_state_ndx,t_state_print_bits) <<
+           ", input = " << n2bs(t_state->d_max_input, d_n_code_inputs+1) <<
+           ": " << t_out_buf << " => " << t_prev_out_buf << "\n";
+#endif
+         t_out_buf->d_prev = t_prev_out_buf;
+         t_out_buf->d_inputs = t_state->d_max_input;
+// finished doing this state
+       }
+// increment the in_buf index, depending on mux'ing or not
+       t_in_buf_ndx += (d_do_mux_inputs == false) ? 1 : d_n_code_outputs;
+// increment the time counter
+        d_time_count++;
+// finished (while) staying in this fsm state or not
+      }
+      if ((d_frame_size_bits != 0) &
+          (d_time_count == d_frame_size_bits)) {
+#if DO_PRINT_DEBUG_FSM
+       std::cout << "Setting FSM to fsm_dec_doing_term\n";
+#endif
+        d_fsm = fsm_dec_doing_term;
+      }
+      break;
+#if DO_PRINT_DEBUG_FSM
+      std::cout << "Exited fsm_dec_doing_middle\n";
+#endif
+    case (fsm_dec_doing_term):
+#if DO_PRINT_DEBUG_FSM
+      std::cout << "Entered fsm_dec_doing_term\n";
+#endif
+// set the "next" up_down index to the end of their states
+      size_t t_time_count = d_max_memory - (d_time_count - d_frame_size_bits);
+      t_n_up_down_ndx = 1 << (d_n_code_inputs * t_time_count);
+// stay in this state until the correct number of input symbols are
+// reached; exit also if we run out of input symbols to process
+      while ((t_time_count > 0) &
+            (t_in_buf_ndx < t_ninput_items)) {
+#if DO_PRINT_DEBUG_TERM
+       std::cout << "Doing time " << (d_max_memory - t_time_count + 1) <<
+         " of " << d_max_memory << "; starting buf[" << t_in_buf_ndx <<
+         "] of [" << t_ninput_items << "]\n";
+#endif
+// use the "to" states,
+// FIXME: loop over just the "0" inputs
+// and compute the metric for
+// each, compare & store it in the "to" state at the end of the connection.
+
+// reset the "to" state's metrics
+        reset_metrics (d_states_ndx ^ 1);
+// reset the state's index for each set of new inputs
+       size_t* t_state_ndx_ptr = d_up_term_states_ndx[d_up_term_ndx];
+       size_t* t_next_state_ndx_ptr = d_up_term_states_ndx[d_up_term_ndx ^ 1];
+// loop over all current stored "term" state indeces
+       for (size_t n = 0; n < t_n_up_down_ndx; n++) {
+         size_t t_state_ndx = *t_state_ndx_ptr++;
+         state_t_ptr t_state = &(d_states[d_states_ndx][t_state_ndx]);
+// loop over just the all 0 input value (d_connections[0])
+         connection_t_ptr t_connection = t_state->d_connections;
+// get the "to" state
+          state_t_ptr t_to_state = t_connection->d_to;
+// start with this state's metric
+          float t_metric = t_state->d_max_metric;
+// get that state's metric
+          float t_to_metric = t_to_state->d_max_metric;
+#if DO_PRINT_DEBUG_TERM
+         std::cout << "Term state " << (n+1) << " of " << t_n_up_down_ndx <<
+           "; using d_s[" << d_states_ndx << "][" <<
+           n2bs(t_state_ndx,t_state_print_bits) << "]\n";
+#endif
+// see if the computation is even needed;
+// maximum change is d_n_code_outputs if all bits match exactly
+          if ((t_to_metric - t_metric) > ((float) 2*d_n_code_outputs)) {
+#if DO_PRINT_DEBUG_TERM
+           std::cout << "!not computing metric!\n";
+#endif
+           continue;
+         }
+// metrics are close enough; do the computation and the compare
+// get the output bits for this connection
+          float* t_output_bit = t_connection->d_output_bits;
+         if (d_do_mux_inputs == true) {
+// if using mux'ed input streams, handle differently
+            const float* t_in_buf = &(in_buf[0][t_in_buf_ndx]);
+// loop over all encoder-output values
+           for (size_t r = d_n_code_outputs; r > 0; r--) {
+             t_metric += ((*t_in_buf++) * (*t_output_bit++));
+           }
+         } else {
+// loop over all encoder-output values
+           for (size_t r = 0; r < d_n_code_outputs; r++) {
+              t_metric += (in_buf[r][t_in_buf_ndx] * (*t_output_bit++));
+           }
+         }
+// done with this input value; compare old and new metrics
+// see if it's the best metric
+          if (t_metric > t_to_metric) {
+#if DO_PRINT_DEBUG_TERM
+           std::cout << "New Metric to s[" <<
+             n2bs (t_connection->d_to_ndx,t_state_print_bits) << "]: ";
+           if (t_to_state->d_max_metric == -1e10) {
+             std::cout << "setting to ";
+           } else {
+             std::cout << "was s[" <<
+               n2bs(t_to_state->d_max_state_ndx,t_state_print_bits) <<
+               "]i[" << n2bs (t_to_state->d_max_input, d_n_code_inputs+1) <<
+               "]@ " << t_to_state->d_max_metric << "  now ";
+           }
+           std::cout << "s[" << n2bs(t_state_ndx,t_state_print_bits) <<
+             "] i[" << n2bs (0, d_n_code_inputs+1) << "]@ " << t_metric << 
"\n";
+#endif
+            t_to_state->d_max_metric = t_metric;
+            t_to_state->d_max_state_ndx = t_state_ndx;
+            t_to_state->d_max_input = 0;
+         }
+// add the "to" state's index to the "next" set of state's indices list
+          *t_next_state_ndx_ptr++ = t_connection->d_to_ndx;
+// finished (for) this state
+       }
+// done with all states and all inputs; now update the traceback structure
+// change which d_states' index to use as starting
+        d_states_ndx ^= 1;
+// update the number of "up_term" states
+        d_up_term_ndx ^= 1;
+// reduce the number of using states
+        t_n_up_down_ndx >>= d_n_code_inputs;
+// reset the state's index for each set of new inputs
+       t_state_ndx_ptr = d_up_term_states_ndx[d_up_term_ndx];
+// update the traceback structure
+// loop over all current states
+       traceback_t_ptr t_prev_out_bufs = d_out_buf[d_time_count];
+       traceback_t_ptr t_out_bufs = d_out_buf[d_time_count+1];
+#if DO_PRINT_DEBUG_TERM_1
+       std::cout << "d_o_b[" << d_time_count+1 << "] => d_o_b prev\n";
+#endif
+// loop over all current stored "term" state indices
+       for (size_t n = 0; n < t_n_up_down_ndx; n++) {
+// get the start index and then pointer to each of the "to" states,
+// which hold the newest "max" stuff
+         size_t t_state_ndx = *t_state_ndx_ptr++;
+         state_t_ptr t_state = &(d_states[d_states_ndx][t_state_ndx]);
+// simple: get the current state & output state
+// and connect output to the current, set inputs on output
+         traceback_t_ptr t_out_buf = &(t_out_bufs[t_state_ndx]);
+         traceback_t_ptr t_prev_out_buf =
+           &(t_prev_out_bufs[t_state->d_max_state_ndx]);
+#if DO_PRINT_DEBUG_TERM_1
+         std::cout << "ndx[" << n << "] == " << t_state_ndx <<
+           ", s[" << n2bs(t_state_ndx,t_state_print_bits) <<
+           "]: max_ndx = " <<
+           n2bs(t_state->d_max_state_ndx,t_state_print_bits) <<
+           ", input = " << n2bs(t_state->d_max_input, d_n_code_inputs+1) <<
+           ": " << t_out_buf << " => " << t_prev_out_buf << "\n";
+#endif
+         t_out_buf->d_prev = t_prev_out_buf;
+         t_out_buf->d_inputs = t_state->d_max_input;
+// finished (for) this state
+       }
+// increment the in_buf index, depending on mux'ing or not
+       t_in_buf_ndx += (d_do_mux_inputs == false) ? 1 : d_n_code_outputs;
+// increment the time counters
+        t_time_count--;
+        d_time_count++;
+// finished (while) staying in this fsm state or not
+      }
+      if (t_time_count == 0) {
+// finished this trellis, now move as much of the decoded input to the
+// output buffer as possible
+#if DO_PRINT_DEBUG_FSM
+       std::cout << "Setting FSM to fsm_dec_output\n";
+#endif
+       d_fsm = fsm_dec_output;
+      }
+#if DO_PRINT_DEBUG_FSM
+      std::cout << "Exited fsm_dec_doing_term\n";
+#endif
+      break;
+    case (fsm_dec_output):
+#if DO_PRINT_DEBUG_FSM
+      std::cout << "Entered fsm_dec_output.\n";
+#endif
+// this is done in reverse bit order (last time to first time)
+// using the traceback structure in d_out_buf, starting with
+// the maximum valued one in the last time slot, then using
+// the traceback's "d_prev" link to trace the trellis back
+
+// see where the output data will terminate
+      int t_next_out_buf_ndx = (t_out_buf_ndx +
+                               (d_frame_size_bits / g_num_bits_per_byte));
+      int t_next_out_bit_shift = (t_out_bit_shift +
+                                 (d_frame_size_bits % g_num_bits_per_byte));
+      if (t_next_out_bit_shift >= g_num_bits_per_byte) {
+       t_next_out_bit_shift -= g_num_bits_per_byte;
+       t_next_out_buf_ndx++;
+      }
+#if DO_PRINT_DEBUG_OUTPUT
+      std::cout << "First bit in at out[][" << t_out_buf_ndx << "].[" <<
+       t_out_bit_shift << "] -> " << d_frame_size_bits << " bits == " <<
+       (d_frame_size_bits / g_num_bits_per_byte) << " Byte" <<
+       ((d_frame_size_bits / g_num_bits_per_byte) != 1 ? "s" : "") <<
+       " + " << (d_frame_size_bits % g_num_bits_per_byte) << " bit" <<
+       ((d_frame_size_bits % g_num_bits_per_byte) != 1 ? "s" : "") <<
+       "\nNext set of bits start at out[][" << t_next_out_buf_ndx <<
+       "].[" << t_next_out_bit_shift << "]\n";
+#endif
+// find the starting traceback structure
+      traceback_t_ptr t_out_buf;
+      if (d_do_termination == true) {
+// FIXME: assume termination state == 0
+#if DO_PRINT_DEBUG_OUTPUT_0
+       std::cout << "Using termination; going through trellis for " <<
+         d_max_memory << " bit" <<
+         ((d_max_memory != 1) ? "s" : "") << "\n";
+#endif
+       t_out_buf = &(d_out_buf[d_time_count][0]);
+#if DO_PRINT_DEBUG_OUTPUT_0
+       std::cout << "Starting traceback ptr " << t_out_buf << "\n";
+#endif
+// skip over the termination bits
+       for (size_t n = d_max_memory; n > 0; n--) {
+         t_out_buf = t_out_buf->d_prev;
+#if DO_PRINT_DEBUG_OUTPUT_0
+         std::cout << "Next traceback ptr " << t_out_buf << "\n";
+#endif
+       }
+      } else {
+// no termination but doing block coding;
+// FIXME: use the state with the bext metric
+// get the state's index for each set of new inputs
+       state_t_ptr t_state = d_states[d_states_ndx];
+       float t_max_metric = t_state->d_max_metric;
+       size_t t_max_state_ndx = 0;
+       t_state++;
+// loop over all current states
+       for (size_t n = 1; n < d_n_states; n++, t_state++) {
+// start with this state's metric
+         float t_metric = t_state->d_max_metric;
+// compare with current max
+         if (t_metric > t_max_metric) {
+           t_max_metric = t_metric;
+           t_max_state_ndx = n;
+         }
+       }
+// get the correct out_buf reference to start with
+       t_out_buf = &(d_out_buf[d_time_count][t_max_state_ndx]);
+      }
+#if DO_PRINT_DEBUG_OUTPUT
+      std::cout << "Found starting traceback ptr " << t_out_buf <<
+       "; getting all " << d_frame_size_bits << " bits per stream.\n";
+#endif
+// now we've got the starting traceback structure address;
+// check to make sure there is enough space in each output buffer
+      size_t t_frame_bit_ndx = d_frame_size_bits;
+      if ((t_next_out_buf_ndx > t_noutput_bytes) |
+         ((t_next_out_buf_ndx == t_noutput_bytes) &
+          (t_next_out_bit_shift != 0))) {
+// not enough space for all output bits;
+// find the number of extra bits to save
+       size_t t_save_buf_ndx = t_next_out_buf_ndx - t_noutput_bytes;
+       size_t t_n_extra_bits = ((t_save_buf_ndx * g_num_bits_per_byte) +
+                                t_next_out_bit_shift);
+// set the number of saved bits
+       d_n_saved_bits = t_n_extra_bits;
+// remove the extra bits from the number to copy to the output buffer
+       t_frame_bit_ndx -= t_n_extra_bits;
+// find the actual output buf index, once we get there
+       t_next_out_buf_ndx -= t_save_buf_ndx;
+#if DO_PRINT_DEBUG_OUTPUT
+       std::cout << "Not enough output buffer space:\n" <<
+         "len (o_b) = " << t_noutput_bytes << " ==> " <<
+         t_n_extra_bits << " extra bit" <<
+         (t_n_extra_bits != 1 ? "s" : "") << " == " <<
+         t_save_buf_ndx << " Byte" <<
+         (t_save_buf_ndx != 1 ? "s" : "") << ", " <<
+         t_next_out_bit_shift << " bit" <<
+         (t_next_out_bit_shift != 1 ? "s" : "") << "\n";
+#endif
+// zero each output buffers' bytes
+       size_t t_n_zero = t_save_buf_ndx + (t_next_out_bit_shift ? 1 : 0);
+#if DO_PRINT_DEBUG_OUTPUT
+       size_t t_n_out_bytes = ((d_frame_size_bits / g_num_bits_per_byte) +
+                               ((d_frame_size_bits % g_num_bits_per_byte) ? 1 
: 0));
+       std::cout << "Zeroing save buffer from for " << t_n_zero <<
+         " Byte" << (t_n_zero != 1 ? "s" : "") << " (of " <<
+         d_frame_size_bits << " bit" <<
+         (d_frame_size_bits != 1 ? "s" : "") << " == " << t_n_out_bytes <<
+         " Byte" << (t_n_out_bytes != 1 ? "s" : "") << ")\n";
+#endif
+       for (size_t m = 0; m < d_n_code_inputs; m++)
+         bzero (d_save_buffer[m], t_n_zero);
+// loop over all extra bits
+       for (size_t n = t_n_extra_bits; n > 0; n--) {
+// first decrement the output bit & byte as necessary
+         if (--t_next_out_bit_shift < 0) {
+           t_next_out_bit_shift += g_num_bits_per_byte;
+           t_save_buf_ndx--;
+         }
+// get the encoder inputs to output
+         size_t t_inputs = t_out_buf->d_inputs;
+// loop over all code inputs (decoder-outputs), 1 bit per stream
+         for (size_t m = 0; m < d_n_code_inputs; m++) {
+           d_save_buffer[m][t_save_buf_ndx] |=
+             ((t_inputs & 1) << t_next_out_bit_shift);
+           t_inputs >>= 1;
+         }
+         t_out_buf = t_out_buf->d_prev;
+#if DO_PRINT_DEBUG_OUTPUT_0
+         std::cout << "Next traceback ptr " << t_out_buf << "\n";
+#endif
+       }
+// at exit, "t_out_buf_ndx" should be == t_noutput_bytes, and
+// "t_out_bit_shift" should be 0; check these!
+#if DO_PRINT_DEBUG_OUTPUT
+       std::cout << "n_o_b_ndx (" << t_next_out_buf_ndx << ") ?=? " <<
+         "#o_B (" << t_noutput_bytes << ") & t_o_b_sh (" <<
+         t_next_out_bit_shift << ") ?=? 0\n";
+       assert (t_next_out_buf_ndx == t_noutput_bytes);
+       assert (t_next_out_bit_shift == 0);
+#endif
+      }
+// set the correct output buffer index and bit shift
+      t_out_bit_shift = t_next_out_bit_shift;
+      t_out_buf_ndx = t_next_out_buf_ndx;
+// copy any remaining bits looping backwards in bit-time
+// through the traceback trellis
+      for (size_t n = t_frame_bit_ndx; n > 0; n--) {
+// first decrement the output bit & byte as necessary
+       if (--t_out_bit_shift < 0) {
+         t_out_bit_shift += g_num_bits_per_byte;
+         t_out_buf_ndx--;
+       }
+// get the encoder inputs to output
+       size_t t_inputs = t_out_buf->d_inputs;
+// loop over all code inputs (decoder-outputs), 1 bit per stream
+       for (size_t m = 0; m < d_n_code_inputs; m++) {
+         out_buf[m][t_out_buf_ndx] |= ((t_inputs & 1) << t_out_bit_shift);
+         t_inputs >>= 1;
+       }
+       t_out_buf = t_out_buf->d_prev;
+#if DO_PRINT_DEBUG_OUTPUT_0
+       std::cout << "Next traceback ptr " << t_out_buf << "\n";
+#endif
+      }
+// set the next output byte and bit-shift
+      t_out_bit_shift = t_next_out_bit_shift;
+      t_out_buf_ndx = t_next_out_buf_ndx;
+#if DO_PRINT_DEBUG_FSM
+      std::cout << "Set FSM to fsm_dec_init\n";
+#endif
+      d_fsm = fsm_dec_init;
+#if DO_PRINT_DEBUG_FSM
+      std::cout << "Exited fsm_dec_output\n";
+#endif
+      break;
+    case (fsm_dec_init):
+#if DO_PRINT_DEBUG_FSM
+      std::cout << "Entered fsm_dec_init\n";
+#endif
+// this is called immediately (first input bit upon startup),
+// or after termination of a trellis.
+
+// reset states to the 0'th one
+      d_up_term_ndx = d_states_ndx = 0;
+// zero the metrics for those states
+      zero_metrics (0);
+#if 0
+// might not need to do this; check and see after it works
+// reset up_term states and number so that there is 1 item, the "0" state.
+      bzero (d_up_term_states_ndx[0], sizeof (size_t) * d_n_states);
+      bzero (d_up_term_states_ndx[1], sizeof (size_t) * d_n_states);
+#else
+      d_up_term_states_ndx[0][0] = 0;
+#endif
+// reset time count back to the start
+      d_time_count = 0;
+#if 0
+// reset the traceback structures
+// might not need to do this; check and see after it works
+      traceback_t_hdl t_out_bufs = d_out_buf;
+      for (size_t n = d_n_traceback_els; n > 0; n--) {
+       traceback_t_ptr t_out_buf = (*t_out_bufs++);
+       for (size_t m = d_n_states; m > 0; m--, t_out_buf++) {
+         t_out_buf->d_prev = NULL;
+         t_out_buf->d_inputs = -1;
+       }
+      }
+#endif
+// set the fsm to "doing up"
+#if DO_PRINT_DEBUG_FSM
+      std::cout << "Set FSM to fsm_dec_doing_up\n";
+#endif
+      d_fsm = fsm_dec_doing_up;
+#if DO_PRINT_DEBUG_FSM
+      std::cout << "Exited fsm_dec_init\n";
+#endif
+      break;
+// should never get here!
+    default:
+      assert (0);
+// done (switch) with FSM
+    }
+// done (while) there are inputs
+  }
+
+// consume all of the input items on all input streams
+// "ninput_items[]" doesn't seem to be reliable,
+// so compute this from the actual number of frames processed
+#if DO_PRINT_DEBUG_EXIT
+  std::cout << "Exiting FSM in state: " <<
+    (d_fsm == fsm_dec_init ? "init" :
+     (d_fsm == fsm_dec_doing_up ? "up" :
+      (d_fsm == fsm_dec_doing_middle ? "middle" :
+       (d_fsm == fsm_dec_doing_term ? "term" :
+       (d_fsm == fsm_dec_output ? "output" : "unknown"))))) << "\n" <<
+    "Consuming " << t_in_buf_ndx <<
+    " input items on each input stream (of " << t_ninput_items << ").\n";
+#endif
+  consume_each (t_in_buf_ndx);
+
+// make sure the number of output items makes sense
+// t_out_buf_ndx always points to the current index
+// t_out_bit_shift always points to the next bit position to be written
+  int t_leftover_bytes = t_out_buf_ndx % d_out_stream_el_size_bytes;
+  int t_leftover_bits = ((t_leftover_bytes * g_num_bits_per_byte) +
+                        t_out_bit_shift);
+  int t_noutput_items = noutput_items;
+#if DO_PRINT_DEBUG_EXIT
+  std::cout << "Final o_b[" << t_out_buf_ndx << "][" <<
+    t_out_bit_shift << "] of " << t_noutput_bytes <<
+    ", el_size = " << d_out_stream_el_size_bytes <<
+    ", lo_Bytes = " << t_leftover_bytes <<
+    ", t_lo_bits = " << t_leftover_bits << "\n" <<
+    "Desired # output items = " << noutput_items << "\n";
+#endif
+  if (t_leftover_bits != 0) {
+    // should never get here!
+#if 1
+    assert (0);
+#else
+    int t_ndx = t_out_buf_ndx - t_leftover_bytes;
+    size_t t_n_copy = t_leftover_bytes + ((t_out_bit_shift != 0) ? 1 : 0);
+    assert (t_n_copy <= d_out_stream_el_size_bytes);
+// copy the leftover into the save buffer
+    for (size_t n = 0; n < d_n_code_inputs; n++) {
+      bcopy (&(out_buf[n][t_ndx]), d_save_buffer[n], t_n_copy);
+    }
+    t_noutput_items = t_ndx / d_out_stream_el_size_bytes;
+    d_n_saved_bits = t_leftover_bits;
+#if DO_PRINT_DEBUG_EXIT
+    std::cout << "Copied " << t_n_copy << " Byte" <<
+      (t_n_copy != 1 ? "s" : "") << " from o_b[][" << t_ndx <<
+      "] into each save buffer.\n" <<
+      "Actual #output items = " << t_noutput_items <<
+      ", # saved bit(s) = " << d_n_saved_bits << "\n";
+#endif
+#endif
+  }
+
+#if DO_TIME_THOUGHPUT
+  u_long d_t = end_timer (&t_tp);
+
+  std::cout << "dec_blk_conv_soft_full: Completed " << t_ninput_items <<
+    " bits in " << d_t << " usec => " <<
+    1e6*(((double)(t_ninput_items))/((double) d_t)) <<
+    " b/s\n";
+#endif
+
+// returns number of items written to each output stream
+  return (t_noutput_items);
+}

Index: gr_decoder_viterbi_block_soft_full.h
===================================================================
RCS file: gr_decoder_viterbi_block_soft_full.h
diff -N gr_decoder_viterbi_block_soft_full.h
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ gr_decoder_viterbi_block_soft_full.h        3 Jul 2006 02:12:53 -0000       
1.1
@@ -0,0 +1,238 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 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.
+ */
+
+#ifndef INCLUDED_GR_DECODER_VITERBI_BLOCK_SOFT_FULL_H
+#define INCLUDED_GR_DECODER_VITERBI_BLOCK_SOFT_FULL_H
+
+#include <gr_block.h>
+#include <vector>
+#include <sys/types.h>
+
+struct state_t;
+
+/*
+ * connection_t: describes an output connection from the current
+ *     time-bit memory state to the next time-bit memory state
+ *
+ * d_to: state pointer to which this connection going
+ *
+ * d_to_ndx: index of the "to" state
+ *
+ * d_output_bits: what are the output bits, coverted into
+ *     1->+1.0, 0->-1.0, for this connection
+ */
+
+typedef struct connection_t {
+  struct state_t *d_to;
+  int d_to_ndx;
+  float* d_output_bits;
+} connection_t, *connection_t_ptr;
+
+/*
+ * state_t: describes a given memory state
+ *
+ * d_connections:  a pointer to an array of these structures
+ *     will be used to describes a given time-bit's memory state;
+ *     an entry will be referenced via "state_add_to", to find the
+ *     connections to the next time-bit memory states.  There is
+ *     one entry per each input bit combination -> 2^#I connections in all.
+ *     e.g. [0] means the all 0 input;
+ *     [1] means that input #1 was 1 while all the others were 0;
+ *     [2] means that input #2 was 1, while all the others were 0;
+ *     [3] means that inputs #1 and #2 were 1, while the others were 0.
+ *
+ * d_max_metric: the maximum metric thus far for this state
+ *
+ * d_max_state: the state from which the maximum metric was attained
+ *
+ * d_max_input: the input bits from which the maximum metric was attained
+ */
+
+typedef struct state_t {
+  connection_t_ptr d_connections;
+  float d_max_metric;
+  int d_max_state_ndx;
+  int d_max_input;
+} state_t, *state_t_ptr;
+
+/*
+ * state_get_from(v,i,k): use to retrieve a given bit-memory state,
+ *     from the inputs:
+ *
+ * int v: the value from which to retrieve the given state
+ * int i: for which input stream (0 to #I-1)
+ * int k: the number of memory slots per input (e.g. 1+D^2 -> 2)
+ */
+
+#define state_get_from(v,i,k) (((v)>>((i)*(k)))&((1<<(k))-1))
+
+/*
+ * state_add_to(s,i,v,k): use to create a given bit-memory state,
+ *     from the inputs:
+ *
+ * int s: the state value to modify
+ * int i: for which input stream (0 to #I-1)
+ * int v: value to set the state to for this input
+ * int k: the number of memory slots per input (e.g. 1+D^2 -> 2)
+ */
+
+#define state_add_to(s,v,i,k) (s)|=(((v)&((1<<(k))-1))<<((i)*(k)))
+
+/*
+ * fsm_dec_t: finite state machine for the decoder
+ *
+ * fsm_dec_init: initialize for a new frame / block; this is already
+ *     done at instantiation, so do it only at the end of a block.
+ *
+ * fsm_dec_doing_up: starting the trellis; done for all types
+ *
+ * fsm_dec_doing_middle: full trellis; done for all types
+ *
+ * fsm_dec_doing_term: termination trellis, if requested
+ *
+ * fsm_dec_doing_output: output all bits
+ */
+
+typedef enum {
+  fsm_dec_init, fsm_dec_doing_up, fsm_dec_doing_middle,
+  fsm_dec_doing_term, fsm_dec_output
+} fsm_dec_t;
+
+/*
+ * traceback_t: used to store all encode-input bits for
+ *     all possible paths, when computing all trellis bits before
+ *     determining the ML decode-output sequence.
+ *
+ * d_prev: the connection to the previous bit's traceback structure
+ *
+ * d_inputs: the inputs (one per bit) for this connection
+ */
+
+typedef struct traceback_t {
+  struct traceback_t *d_prev;
+  int d_inputs;
+} traceback_t, *traceback_t_ptr, **traceback_t_hdl;
+
+// GR stuff
+
+class gr_decoder_viterbi_block_soft_full;
+typedef boost::shared_ptr<gr_decoder_viterbi_block_soft_full>
+gr_decoder_viterbi_block_soft_full_sptr;
+
+gr_decoder_viterbi_block_soft_full_sptr gr_make_dec_blk_conv_soft_full
+(int frame_size_bits,
+ int num_input_streams,
+ int num_output_streams,
+ std::vector<int> code_generator,
+ bool do_termination);
+
+/*!
+ * \brief Decode the incoming streams using a Viterbi-style decoder
+ *
+ * input: encoded data as soft symbols, either as individual
+ *     streams or mux'ed into 1 stream.
+ *
+ * output: stream(s) of user-defined element size.
+ */
+
+class gr_decoder_viterbi_block_soft_full : public gr_block
+{
+  friend gr_decoder_viterbi_block_soft_full_sptr
+  gr_make_dec_blk_conv_soft_full (int frame_size_bits,
+                                 int num_input_streams,
+                                 int num_output_streams,
+                                 std::vector<int> code_generator,
+                                 bool do_termination);
+/*
+ * frame_size_bits: if == 0, then do streaming decoding (infinite
+ *     trellis); otherwise this is the block size to decode before
+ *     terminating the trellis.
+ *
+ * code_generator: vector of integers (32 bit) representing the code
+ *     to be implemented in octal form.  E.g. "04" in binary is "100",
+ *     which would be "D^2" for code generation.  "06" == 110b == "D^2 + D"
+ *  ==> The vector is listed in order for each input stream, so if there
+ *     are 2 input streams (I1, I2) [specified in "n_code_inputs"]
+ *     and 2 output streams (O1, O2) [specified in "n_code_outputs"],
+ *     then the vector would be the code generator for:
+ *       [I1->O1, I1->O2, I2->O1, I2->O2]
+ *     with each element being the octal representation of the code.
+ *
+ * do_termination is valid only if frame_size_bits != 0, and defines
+ *     whether or not to to trellis termination.
+ *
+ * do_mux_input: is true, then the one input stream will be
+ *     interpreted as the multiplexing all of the input bits.  For
+ *     example for a 3 input decoder, the input stream would be
+ *     [I1[k], I2[k], I3[k], I1[k+1], I2[k+1], ...], where "k" is the
+ *     input sample time, and "I1" through "I3" are the 3 input
+ *     streams.
+ *
+ * n_code_inputs: the number of decoder-input (encoder-output)
+ *     streams, no matter if separate or mux'ed
+ *
+ * n_code_outputs: the number of decoder-output (encoder-input) streams
+ */
+
+  gr_decoder_viterbi_block_soft_full (int frame_size_bits,
+                                     int num_input_streams,
+                                     int num_output_streams,
+                                     std::vector<int> code_generator,
+                                     bool do_termination);
+
+public:
+  ~gr_decoder_viterbi_block_soft_full ();
+
+  virtual void forecast (int noutput_items,
+                        gr_vector_int &ninput_items_required);
+
+  virtual int general_work (int noutput_items,
+                           gr_vector_int &ninput_items,
+                           gr_vector_const_void_star &input_items,
+                           gr_vector_void_star &output_items);
+
+  virtual int fixed_rate_noutput_to_ninput (int noutput_items);
+
+private:
+  void reset_metrics (u_char which);
+  void zero_metrics (u_char which);
+
+/*
+ * d_n_total_input_bits_per_stream: how many bits to store for each
+ *     state to determine the best decoder-output (encoder-input) bits 
+ */
+  size_t d_frame_size_bits;
+  size_t d_n_code_outputs, d_n_code_inputs, d_max_memory;
+  size_t d_time_count, d_n_total_input_bits_per_stream;
+  size_t d_n_saved_bits, d_n_saved_bits_start_ndx, d_n_traceback_els;
+  size_t d_n_states, d_n_input_combinations;
+  size_t d_states_ndx, d_up_term_ndx;
+  bool d_do_streaming, d_do_termination, d_do_mux_inputs;
+  char **d_save_buffer;
+  std::vector<int> d_code_generators;
+  state_t_ptr d_states[2];
+  fsm_dec_t d_fsm;
+  size_t* d_up_term_states_ndx[2];
+  traceback_t_hdl d_out_buf;
+};
+
+#endif /* INCLUDED_GR_DECODER_VITERBI_BLOCK_SOFT_FULL_H */

Index: gr_decoder_viterbi_block_soft_full.i
===================================================================
RCS file: gr_decoder_viterbi_block_soft_full.i
diff -N gr_decoder_viterbi_block_soft_full.i
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ gr_decoder_viterbi_block_soft_full.i        3 Jul 2006 02:12:53 -0000       
1.1
@@ -0,0 +1,39 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 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.
+ */
+
+GR_SWIG_BLOCK_MAGIC(gr,dec_blk_conv_soft_full);
+
+gr_decoder_viterbi_block_soft_full_sptr
+gr_make_decoder_viterbi_block_soft_full (int frame_size_bits,
+                                        int num_input_streams,
+                                        int num_output_streams,
+                                        std::vector<int> code_generator,
+                                        bool do_termination);
+
+class gr_decoder_viterbi_block_soft_full : public gr_block
+{
+  gr_decoder_viterbi_block_soft_full (int frame_size_bits,
+                                     int num_input_streams,
+                                     int num_output_streams,
+                                     std::vector<int> code_generator,
+                                     bool do_termination);
+};

Index: gr_streams_encode_convolutional.cc
===================================================================
RCS file: gr_streams_encode_convolutional.cc
diff -N gr_streams_encode_convolutional.cc
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ gr_streams_encode_convolutional.cc  3 Jul 2006 02:12:53 -0000       1.1
@@ -0,0 +1,137 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 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.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <gr_streams_encode_convolutional.h>
+#include <gr_io_signature.h>
+#include <assert.h>
+#include <iostream>
+
+gr_streams_encode_convolutional_sptr 
+gr_make_streams_encode_convolutional (int frame_size_bits,
+                                     int n_code_inputs,
+                                     int n_code_outputs,
+                                     std::vector<int> &code_generator,
+                                     bool do_termination,
+                                     int start_memory_state,
+                                     int end_memory_state)
+{
+  return gr_streams_encode_convolutional_sptr
+    (new gr_streams_encode_convolutional (frame_size_bits,
+                                         n_code_inputs,
+                                         n_code_outputs,
+                                         code_generator,
+                                         do_termination,
+                                         start_memory_state,
+                                         end_memory_state));
+}
+
+gr_streams_encode_convolutional::gr_streams_encode_convolutional
+(int frame_size_bits,
+ int n_code_inputs,
+ int n_code_outputs,
+ std::vector<int> &code_generators,
+ bool do_termination,
+ int start_memory_state,
+ int end_memory_state)
+  : gr_block ("streams_encode_convolutional",
+             gr_make_io_signature (0, 0, 0),
+             gr_make_io_signature (0, 0, 0))
+{
+// error checking is done by the encoder class itself;
+// just pass items on here.
+
+  d_encoder = new encoder_convolutional (frame_size_bits,
+                                        n_code_inputs,
+                                        n_code_outputs,
+                                        code_generators,
+                                        do_termination,
+                                        start_memory_state,
+                                        end_memory_state);
+
+// create the correct input signature; 1 bit per input char
+  set_input_signature (gr_make_io_signature (n_code_inputs,
+                                            n_code_inputs,
+                                            sizeof (char)));
+
+// create the correct output signature; 1 bit per output char
+  set_output_signature (gr_make_io_signature (n_code_outputs,
+                                             n_code_outputs,
+                                             sizeof (char)));
+
+// set the output multiple to 1 item, handle the rest internally
+  set_output_multiple (1);
+}
+
+gr_streams_encode_convolutional::~gr_streams_encode_convolutional
+()
+{
+  if (d_encoder)
+    delete d_encoder;
+}
+
+/*
+ * Compute the number of input bits (items in this case, since each
+ * item has 1 bit in it) needed to produce 'n_output' bits (items in
+ * this case, since each item has 1 bit in it).
+ *
+ * For convolutional encoders, there is 1 bit output per bit input per
+ * stream, with the addition of a some bits for trellis termination if
+ * selected.  Thus the input:output bit ratio will be:
+ * 
+ * if (streaming | no termination), 1:1
+ *
+ * if (not streaming & termination), roughly 1:(1+X), where "X" is the
+ * total memory size of the code divided by the block length in bits.
+ * But this also depends on the state of the FSM ... how many bits are
+ * left before termination.
+ */
+
+void gr_streams_encode_convolutional::forecast
+(int noutput_items,
+ gr_vector_int &ninput_items_required)
+{
+  int ninput_items = d_encoder->compute_n_input_bits (noutput_items);
+  for (int n = ninput_items_required.size() - 1; n >= 0; n--)
+    ninput_items_required[n] = ninput_items;
+}
+
+int
+gr_streams_encode_convolutional::general_work
+(int noutput_items,
+ gr_vector_int &ninput_items,
+ gr_vector_const_void_star &input_items,
+ gr_vector_void_star &output_items)
+{
+  size_t t_n_input_items = d_encoder->encode ((const char 
**)(&input_items[0]), 
+                                            (char **)(&output_items[0]),
+                                            (size_t) noutput_items);
+
+// consume the number of used input items on all input streams
+  consume_each (t_n_input_items);
+
+// returns number of items written to each output stream
+  return (noutput_items);
+}

Index: gr_streams_encode_convolutional.h
===================================================================
RCS file: gr_streams_encode_convolutional.h
diff -N gr_streams_encode_convolutional.h
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ gr_streams_encode_convolutional.h   3 Jul 2006 02:12:53 -0000       1.1
@@ -0,0 +1,120 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 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.
+ */
+
+#ifndef INCLUDED_GR_STREAMS_ENCODE_CONVOLUTIONAL_H
+#define INCLUDED_GR_STREAMS_ENCODE_CONVOLUTIONAL_H
+
+#include <gr_block.h>
+#include <vector>
+#include <libecc/encoder_convolutional.h>
+#include <sys/types.h>
+
+class gr_streams_encode_convolutional;
+typedef boost::shared_ptr<gr_streams_encode_convolutional> 
gr_streams_encode_convolutional_sptr;
+
+gr_streams_encode_convolutional_sptr gr_make_streams_encode_convolutional
+(int frame_size_bits,
+ int n_code_inputs,
+ int n_code_outputs,
+ std::vector<int> &code_generator,
+ bool do_termination = true,
+ int start_memory_state = 0,
+ int end_memory_state = 0);
+
+/*!
+ * \brief Encode the incoming streams using a convolutional encoder
+ *
+ * input: streams of char, one stream per input as defined by the
+ *     instantiated code, using only the right-most justified bit as
+ *     the single input bit per input item.
+ *
+ * output: streams of char, one stream per output as defined by the
+ *     instantiated code, using only the right-most justified bit as
+ *     the single output bit per output item.
+ */
+
+class gr_streams_encode_convolutional : public gr_block
+{
+  friend gr_streams_encode_convolutional_sptr
+  gr_make_streams_encode_convolutional (int frame_size_bits,
+                                       int n_code_inputs,
+                                       int n_code_outputs,
+                                       std::vector<int> &code_generator,
+                                       bool do_termination,
+                                       int start_memory_state,
+                                       int end_memory_state);
+/*
+ * frame_size_bits: if == 0, then do streaming encoding ("infinite"
+ *     trellis); otherwise this is the frame size in bits to encode
+ *     before terminating the trellis.  This value -does not- include
+ *     any termination bits.
+ *
+ * n_code_inputs:
+ * n_code_outputs:
+ * code_generator: vector of integers (32 bit) representing the code
+ *     to be implemented in octal form.  E.g. "04" in binary is "100",
+ *     which would be "D^2" for code generation.  "06" == 110b == "D^2 + D"
+ *  ==> The vector is listed in order for each input stream, so if there
+ *     are 2 input streams (I1, I2) [specified in "n_code_inputs"]
+ *     and 2 output streams (O1, O2) [specified in "n_code_outputs"],
+ *     then the vector would be the code generator for:
+ *       [I1->O1, I1->O2, I2->O1, I2->O2]
+ *     with each element being the octal representation of the code.
+ *
+ * do_termination: valid only if frame_size_bits != 0, and defines
+ *     whether or not to use trellis termination.  Default is to use
+ *     termination when doing block coding.
+ *
+ * start_memory_state: when starting a new block, the starting memory
+ *     state to begin encoding; there will be a helper function to
+ *     assist in creating this value for a given set of inputs;
+ *     default is the "all zero" state.
+ * 
+ * end_memory_state: when terminating a block, the ending memory
+ *     state to stop encoding; there will be a helper function to
+ *     assist in creating this value for a given set of inputs;
+ *     default is the "all zero" state.
+ */
+
+  gr_streams_encode_convolutional (int frame_size_bits,
+                                  int n_code_inputs,
+                                  int n_code_outputs,
+                                  std::vector<int> &code_generator,
+                                  bool do_termination = true,
+                                  int start_memory_state = 0,
+                                  int end_memory_state = 0);
+
+  encoder_convolutional* d_encoder;
+
+public:
+  ~gr_streams_encode_convolutional ();
+
+  virtual void forecast (int noutput_items,
+                        gr_vector_int &ninput_items_required);
+
+  virtual int general_work (int noutput_items,
+                           gr_vector_int &ninput_items,
+                           gr_vector_const_void_star &input_items,
+                           gr_vector_void_star &output_items);
+};
+
+#endif /* INCLUDED_GR_STREAMS_ENCODE_CONVOLUTIONAL_H */

Index: gr_streams_encode_convolutional.i
===================================================================
RCS file: gr_streams_encode_convolutional.i
diff -N gr_streams_encode_convolutional.i
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ gr_streams_encode_convolutional.i   3 Jul 2006 02:12:53 -0000       1.1
@@ -0,0 +1,43 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 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.
+ */
+
+GR_SWIG_BLOCK_MAGIC(gr,streams_encode_convolutional);
+
+gr_streams_encode_convolutional_sptr
+gr_make_streams_encode_convolutional (int frame_size_bits,
+                                     int n_code_inputs,
+                                     int n_code_outputs,
+                                     std::vector<int> &code_generator,
+                                     bool do_termination,
+                                     int start_memory_state,
+                                     int end_memory_state);
+
+class gr_streams_encode_convolutional : public gr_block
+{
+  gr_streams_encode_convolutional (int frame_size_bits,
+                                  int n_code_inputs,
+                                  int n_code_outputs,
+                                  std::vector<int> &code_generator,
+                                  bool do_termination,
+                                  int start_memory_state,
+                                  int end_memory_state);
+};

Index: gr_syms_to_metrics.cc
===================================================================
RCS file: gr_syms_to_metrics.cc
diff -N gr_syms_to_metrics.cc
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ gr_syms_to_metrics.cc       3 Jul 2006 02:12:53 -0000       1.1
@@ -0,0 +1,162 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 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.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <gr_syms_to_metrics.h>
+#include <gr_io_signature.h>
+#include <assert.h>
+
+gr_syms_to_metrics_sptr 
+gr_make_syms_to_metrics (gr_feval_ff* pdf_fcn_0_bit,
+                        gr_feval_ff* pdf_fcn_1_bit,
+                        int n_samples,
+                        float min_sample,
+                        float max_sample,
+                        int sample_precision)
+{
+  return gr_syms_to_metrics_sptr
+    (new gr_syms_to_metrics (pdf_fcn_0_bit,
+                            pdf_fcn_1_bit,
+                            n_samples,
+                            min_sample,
+                            max_sample,
+                            sample_precision));
+}
+
+// dummy functions to get the float(*)(float) function to work
+// properly with the gr_feval_XX stuff.
+
+static gr_feval_ff* l_pdf_fcn_0_bit;
+static gr_feval_ff* l_pdf_fcn_1_bit;
+
+static float pdf_fcn_0 (float x)
+{
+  return (l_pdf_fcn_0_bit->eval (x));
+}
+
+static float pdf_fcn_1 (float x)
+{
+  return (l_pdf_fcn_1_bit->eval (x));
+}
+
+gr_syms_to_metrics::gr_syms_to_metrics
+(gr_feval_ff* pdf_fcn_0_bit,
+ gr_feval_ff* pdf_fcn_1_bit,
+ int n_samples,
+ float min_sample,
+ float max_sample,
+ int sample_precision)
+  : gr_block ("syms_to_metrics",
+             gr_make_io_signature (1, -1, sizeof (float)),
+             gr_make_io_signature (0, 0, 0))
+{
+  if ((sample_precision < 0) | (sample_precision > 32)) {
+    fprintf (stderr, "gr_syms_to_metrics: sample_precision must be "
+            " between 0 and 32.\n");
+    assert (0);
+  }
+
+  l_pdf_fcn_0_bit = pdf_fcn_0_bit;
+  l_pdf_fcn_1_bit = pdf_fcn_1_bit;
+
+  if (sample_precision == 0) {
+// float
+    d_out_item_size_bytes = 4;
+    d_code_metrics = new code_metric_ff (&pdf_fcn_0,
+                                        &pdf_fcn_1,
+                                        n_samples,
+                                        min_sample,
+                                        max_sample);
+  } else if (sample_precision <= 8) {
+// use char 
+    d_out_item_size_bytes = 1;
+    d_code_metrics = new code_metric_fb (&pdf_fcn_0,
+                                        &pdf_fcn_1,
+                                        n_samples,
+                                        min_sample,
+                                        max_sample,
+                                        sample_precision);
+  } else if (sample_precision <= 16) {
+// use short 
+    d_out_item_size_bytes = 2;
+    d_code_metrics = new code_metric_fs (&pdf_fcn_0,
+                                        &pdf_fcn_1,
+                                        n_samples,
+                                        min_sample,
+                                        max_sample,
+                                        sample_precision);
+  } else {
+// use long 
+    d_out_item_size_bytes = 4;
+    d_code_metrics = new code_metric_fl (&pdf_fcn_0,
+                                        &pdf_fcn_1,
+                                        n_samples,
+                                        min_sample,
+                                        max_sample,
+                                        sample_precision);
+  }
+
+  set_output_signature (gr_make_io_signature (1, -1, d_out_item_size_bytes));
+}
+
+bool gr_syms_to_metrics::check_topology (int ninputs, int noutputs)
+{
+  return ((noutputs == (2*ninputs)) ? true : false);
+}
+
+void
+gr_syms_to_metrics::forecast
+(int noutput_items,
+ gr_vector_int &ninput_items_required)
+{
+// always 1:1, for all streams
+  for (size_t n = 0; n < ninput_items_required.size(); n++) {
+    ninput_items_required[n] = noutput_items;
+  }
+}
+
+int
+gr_syms_to_metrics::general_work (int noutput_items,
+                                 gr_vector_int &ninput_items,
+                                 gr_vector_const_void_star &input_items,
+                                 gr_vector_void_star &output_items)
+{
+  size_t l_n_output_items = noutput_items;
+
+  for (size_t n = 0; n < input_items.size(); n++) {
+    float* t_in_buf = (float*)(&input_items[n]);
+    void* t_out_buf_0_bit = (void*)(&(output_items[2*n]));
+    void* t_out_buf_1_bit = (void*)(&(output_items[(2*n)+1]));
+
+    d_code_metrics->convert (l_n_output_items, t_in_buf,
+                            t_out_buf_0_bit, t_out_buf_1_bit);
+  }
+
+// consume the number of used input items on all input streams
+  consume_each (noutput_items);
+
+// returns number of items written to each output stream
+  return (noutput_items);
+}

Index: gr_syms_to_metrics.h
===================================================================
RCS file: gr_syms_to_metrics.h
diff -N gr_syms_to_metrics.h
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ gr_syms_to_metrics.h        3 Jul 2006 02:12:53 -0000       1.1
@@ -0,0 +1,121 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 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.
+ */
+
+#ifndef INCLUDED_SYMS_TO_METRICS_H
+#define INCLUDED_SYMS_TO_METRICS_H
+
+#include <gr_block.h>
+#include <gr_feval.h>
+#include <vector>
+#include <libecc/code_metrics.h>
+
+class gr_syms_to_metrics;
+typedef boost::shared_ptr<gr_syms_to_metrics> gr_syms_to_metrics_sptr;
+
+gr_syms_to_metrics_sptr gr_make_syms_to_metrics
+(gr_feval_ff* pdf_fcn_0_bit,
+ gr_feval_ff* pdf_fcn_1_bit,
+ int n_samples,
+ float min_sample,
+ float max_sample,
+ int sample_precision);
+
+/*!
+ * \brief Convert the input stream(s) of soft (float) symbols to
+ * log-probability metrics of user-specified precision; output is 2
+ * streams per input stream, each stream consisting of the metric for
+ * receiving a 0-bit and 1-bit, respectively, with the lower-numbered
+ * stream being the 0-bit.
+ *
+ * input: stream(s) of float; output: stream(s) of metrics
+ */
+
+class gr_syms_to_metrics : public gr_block
+{
+  friend gr_syms_to_metrics_sptr
+  gr_make_syms_to_metrics (gr_feval_ff* pdf_fcn_0_bit,
+                          gr_feval_ff* pdf_fcn_1_bit,
+                          int n_samples,
+                          float min_sample,
+                          float max_sample,
+                          int sample_precision);
+
+/*
+ * gr_syms_to_metrics: Convert the input soft (float) symbols into
+ *     log-probabilities (metrics) for use in the convolutional
+ *     decoder.  Samples the provided PDF function in 'n_samples'
+ *     places from 'min_sample' to 'max_sample', takes the log of that
+ *     value, then converts the result into a given precision and
+ *     stores all results in a "handy dandy" lookup table for much
+ *     faster processing.
+ *
+ * pdf_fcn_0_bit: point to a probability distribution function which
+ *     takes a float and returns a float, for the 0-bit probabilities.
+ *
+ * pdf_fcn_1_bit: point to a probability distribution function which
+ *     takes a float and returns a float, for the 1-bit probabilities.
+ *
+ * n_samples: the number of samples between min_sample and max_sample
+ *     to store in the lookup table.  Must be at least 2, but
+ *     otherwise is limited only by the amount of available memory;
+ *     generally, 65536 (1 << 16) is plenty of samples.
+ *
+ * min_sample: the minimum value below which any incoming value is
+ *     "rounded" up.
+ *
+ * max_sample: the maximum value above which any incoming value is
+ *     "rounded" down.
+ *
+ * sample_precision: the precision with which to sample the returned
+ *     value of the PDF function.
+ *  +  Cannot be < 0 or > 32.
+ *  +  "soft float" == 0
+ *  + otherwise, convert to an integer of the given value
+ *
+ * in "work", finds the (linearly) closest sample value for the given
+ *     input and outputs the metric for a 0-bit input on the first
+ *     stream and a 1-bit input on the second stream.
+ *
+ */
+
+  gr_syms_to_metrics (gr_feval_ff* pdf_fcn_0_bit,
+                     gr_feval_ff* pdf_fcn_1_bit,
+                     int n_samples,
+                     float min_sample,
+                     float max_sample,
+                     int sample_precision);
+
+  size_t d_out_item_size_bytes;
+  code_metrics* d_code_metrics;
+
+public:
+  bool check_topology (int ninputs, int noutputs);
+
+  void forecast (int noutput_items, gr_vector_int &ninput_items_required);
+
+  int general_work (int noutput_items,
+                   gr_vector_int &ninput_items,
+                   gr_vector_const_void_star &input_items,
+                   gr_vector_void_star &output_items);
+};
+
+#endif /* INCLUDED_SYMS_TO_METRICS_H */

Index: gr_syms_to_metrics.i
===================================================================
RCS file: gr_syms_to_metrics.i
diff -N gr_syms_to_metrics.i
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ gr_syms_to_metrics.i        3 Jul 2006 02:12:53 -0000       1.1
@@ -0,0 +1,41 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 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.
+ */
+
+GR_SWIG_BLOCK_MAGIC(gr,syms_to_metrics);
+
+gr_syms_to_metrics_sptr gr_make_syms_to_metrics
+(gr_feval_ff* pdf_fcn_0_bit,
+ gr_feval_ff* pdf_fcn_1_bit,
+ int n_samples,
+ float min_sample, 
+ float max_sample,
+ int sample_precision);
+
+class gr_syms_to_metrics : public gr_block
+{
+  gr_syms_to_metrics (gr_feval_ff* pdf_fcn_0_bit,
+                     gr_feval_ff* pdf_fcn_1_bit,
+                     int n_samples,
+                     float min_sample, 
+                     float max_sample,
+                     int sample_precision);
+};

Index: qa_ecc.py
===================================================================
RCS file: qa_ecc.py
diff -N qa_ecc.py
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ qa_ecc.py   3 Jul 2006 02:12:53 -0000       1.1
@@ -0,0 +1,39 @@
+#!/usr/bin/env python
+#
+# Copyright 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.
+# 
+
+from gnuradio import gr, gr_unittest, ecc
+
+class qa_error-correcting-codes (gr_unittest.TestCase):
+
+    def setUp (self):
+        self.fg = gr.flow_graph ()
+
+    def tearDown (self):
+        self.fg = None
+
+    def test_000_nop (self):
+        """Just see if we can import the module...
+        They may not have drivers, etc.  Don't try to run anything"""
+        pass
+
+if __name__ == '__main__':
+    gr_unittest.main ()




reply via email to

[Prev in Thread] Current Thread [Next in Thread]