commit-gnuradio
[Top][All Lists]
Advanced

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

[Commit-gnuradio] [gnuradio] 01/11: fec: adding TPC encoder and decoder


From: git
Subject: [Commit-gnuradio] [gnuradio] 01/11: fec: adding TPC encoder and decoder
Date: Sun, 5 Apr 2015 23:58:07 +0000 (UTC)

This is an automated email from the git hooks/post-receive script.

jcorgan pushed a commit to branch master
in repository gnuradio.

commit a99950a9353b54feac9a1ea61fcc02d347063f3a
Author: Tim O'Shea <address@hidden>
Date:   Sun Apr 5 12:46:36 2015 -0700

    fec: adding TPC encoder and decoder
---
 gr-fec/grc/fec_block_tree.xml             |   2 +
 gr-fec/grc/ldpc_decoder_def_list.xml      |   5 -
 gr-fec/grc/ldpc_encoder_def_list.xml      |   5 -
 gr-fec/grc/tpc_decoder_def_list.xml       | 139 +++++
 gr-fec/grc/tpc_encoder_def_list.xml       | 108 ++++
 gr-fec/include/gnuradio/fec/tpc_common.h  |  28 +
 gr-fec/include/gnuradio/fec/tpc_decoder.h | 134 +++++
 gr-fec/include/gnuradio/fec/tpc_encoder.h |  89 +++
 gr-fec/lib/CMakeLists.txt                 |   3 +
 gr-fec/lib/tpc_common.cc                  |  82 +++
 gr-fec/lib/tpc_decoder.cc                 | 894 ++++++++++++++++++++++++++++++
 gr-fec/lib/tpc_encoder.cc                 | 334 +++++++++++
 gr-fec/swig/fec_swig.i                    |   4 +
 13 files changed, 1817 insertions(+), 10 deletions(-)

diff --git a/gr-fec/grc/fec_block_tree.xml b/gr-fec/grc/fec_block_tree.xml
index 97610f0..0fddcf3 100644
--- a/gr-fec/grc/fec_block_tree.xml
+++ b/gr-fec/grc/fec_block_tree.xml
@@ -13,6 +13,7 @@
       <block>variable_cc_decoder_def</block>
       <block>variable_repetition_decoder_def</block>
       <block>variable_ldpc_decoder_def</block>
+      <block>variable_tpc_decoder_def</block>
       <block>variable_dummy_decoder_def</block>
     </cat>
     <cat>
@@ -21,6 +22,7 @@
       <block>variable_ccsds_encoder_def</block>
       <block>variable_repetition_encoder_def</block>
       <block>variable_ldpc_encoder_def</block>
+      <block>variable_tpc_encoder_def</block>
       <block>variable_dummy_encoder_def</block>
     </cat>
     <block>fec_extended_encoder</block>
diff --git a/gr-fec/grc/ldpc_decoder_def_list.xml 
b/gr-fec/grc/ldpc_decoder_def_list.xml
index 22df939..8304e03 100644
--- a/gr-fec/grc/ldpc_decoder_def_list.xml
+++ b/gr-fec/grc/ldpc_decoder_def_list.xml
@@ -1,9 +1,4 @@
 <?xml version="1.0"?>
-<!--
-###################################################
-# FEC MAKING FOR GREAT JUSTICE
-###################################################
- -->
 <block>
     <name>LDPC Decoder Definition</name>
     <key>variable_ldpc_decoder_def</key>
diff --git a/gr-fec/grc/ldpc_encoder_def_list.xml 
b/gr-fec/grc/ldpc_encoder_def_list.xml
index 5975f78..c9ad615 100755
--- a/gr-fec/grc/ldpc_encoder_def_list.xml
+++ b/gr-fec/grc/ldpc_encoder_def_list.xml
@@ -1,9 +1,4 @@
 <?xml version="1.0"?>
-<!--
-###################################################
-# FEC MAKING FOR GREAT JUSTICE
-###################################################
- -->
 <block>
     <name>LDPC Encoder Definition</name>
     <key>variable_ldpc_encoder_def</key>
diff --git a/gr-fec/grc/tpc_decoder_def_list.xml 
b/gr-fec/grc/tpc_decoder_def_list.xml
new file mode 100644
index 0000000..3c92c63
--- /dev/null
+++ b/gr-fec/grc/tpc_decoder_def_list.xml
@@ -0,0 +1,139 @@
+<?xml version="1.0"?>
+<block>
+    <name>TPC Decoder Definition</name>
+    <key>variable_tpc_decoder_def</key>
+    <import>from gnuradio import fec</import>
+    <var_make>
+#if int($ndim())==0 #
+self.$(id) = $(id) = fec.tpc_decoder_make($row_poly, $col_poly, $krow, $kcol, 
$bval, $qval, $max_iter, $decoder_type); #slurp
+#else if int($ndim())==1 #
+self.$(id) = $(id) = map( (lambda a: fec.tpc_decoder_make($row_poly, 
$col_poly, $krow, $kcol, $bval, $qval, $max_iter, $decoder_type)), 
range(0,$dim1) ); #slurp
+#else
+self.$(id) = $(id) = map( (lambda b: map( ( lambda a: 
fec.tpc_decoder_make($row_poly, $col_poly, $krow, $kcol, $bval, $qval, 
$max_iter, $decoder_type)), range(0,$dim2) ) ), range(0,$dim1)); #slurp
+#end if</var_make>
+    <make></make>
+
+<!-- This definition below is wierd, it seems required for the GRC to be 
happy, im confused -->
+    <param>
+        <name>Ignore Me</name>
+        <key>value</key>
+        <value>"ok"</value>
+        <type>raw</type>
+        <hide>all</hide>
+    </param>
+
+    <param>
+        <name>Threading Dimensions</name>
+        <key>ndim</key>
+        <value></value>
+        <type>enum</type>
+        <option>
+            <name>2</name>
+            <key>2</key>
+        </option>
+        <option>
+            <name>1</name>
+            <key>1</key>
+        </option>
+
+    </param>
+
+    <param>
+        <name>Dimension 1</name>
+        <key>dim1</key>
+        <value>4</value>
+        <type>int</type>
+        <hide>#if (int($ndim()) >= 1) then 'none' else 'all' #</hide>
+    </param>
+
+    <param>
+        <name>Dimension 2</name>
+        <key>dim2</key>
+        <value>4</value>
+        <type>int</type>
+        <hide>#if (int($ndim()) >= 2) then 'none' else 'all' #</hide>
+    </param>
+
+    <param>
+        <name>Row Encoder Polynomials</name>
+        <key>row_poly</key>
+        <value>[3]</value>
+        <type>int_vector</type>
+    </param>
+    
+    <param>
+        <name>Column Encoder Polynomials</name>
+        <key>col_poly</key>
+        <value>[43]</value>
+        <type>int_vector</type>
+    </param>
+    
+    <param>
+        <name>K Row</name>
+        <key>krow</key>
+        <value>26</value>
+        <type>int</type>
+    </param>
+    
+    <param>
+        <name>K Col</name>
+        <key>kcol</key>
+        <value>6</value>
+        <type>int</type>
+    </param>
+    
+    <param>
+        <name>B</name>
+        <key>bval</key>
+        <value>9</value>
+        <type>int</type>
+    </param>
+    
+    <param>
+        <name>Q</name>
+        <key>qval</key>
+        <value>3</value>
+        <type>int</type>
+    </param>
+
+    <param>
+        <name>NUM Turbo Iterations</name>
+        <key>max_iter</key>
+        <value>6</value>
+        <type>int</type>
+    </param>
+
+    <param>
+        <name>Decoder Type</name>
+        <key>decoder_type</key>
+        <value></value>
+        <type>enum</type>
+        <option>
+            <name>Linear LOG-MAP</name>
+            <key>0</key>
+        </option>
+        <option>
+            <name>MAX LOG-MAP</name>
+            <key>1</key>
+        </option>
+        <option>
+            <name>Constant LOG-MAP</name>
+            <key>2</key>
+        </option>
+        <option>
+            <name>LOG-MAP (LUT Correction Factor)</name>
+            <key>3</key>
+        </option>
+        <option>
+            <name>LOG-MAP (C Correction Factor)</name>
+            <key>4</key>
+        </option>
+    </param>
+
+
+    <doc>
+        This instantiates a 1-dim array or 2-dim array fo Turbo Product 
Encoders (TPC).
+        Restrictions: B and Q must be carefully chosen such that when the 
matrices are setup,
+        and the first B outputs are removed, they (the first B outputs) are 
all 0's.
+    </doc>
+</block>
diff --git a/gr-fec/grc/tpc_encoder_def_list.xml 
b/gr-fec/grc/tpc_encoder_def_list.xml
new file mode 100755
index 0000000..0346d40
--- /dev/null
+++ b/gr-fec/grc/tpc_encoder_def_list.xml
@@ -0,0 +1,108 @@
+<?xml version="1.0"?>
+<block>
+    <name>TPC Encoder Definition</name>
+    <key>variable_tpc_encoder_def</key>
+    <import>from gnuradio import fec</import>
+    <var_make>
+#if int($ndim())==0 #
+self.$(id) = $(id) = fec.tpc_encoder_make($row_poly, $col_poly, $krow, $kcol, 
$bval, $qval); #slurp
+#else if int($ndim())==1 #
+self.$(id) = $(id) = map( (lambda a: fec.tpc_encoder_make($row_poly, 
$col_poly, $krow, $kcol, $bval, $qval)), range(0,$dim1) ); #slurp
+#else
+self.$(id) = $(id) = map( (lambda b: map( ( lambda a: 
fec.tpc_encoder_make($row_poly, $col_poly, $krow, $kcol, $bval, $qval)), 
range(0,$dim2) ) ), range(0,$dim1)); #slurp
+#end if</var_make>
+    <make></make>
+
+<!-- This definition below is wierd, it seems required for the GRC to be 
happy, im confused -->
+    <param>
+        <name>Ignore Me</name>
+        <key>value</key>
+        <value>"ok"</value>
+        <type>raw</type>
+        <hide>all</hide>
+    </param>
+
+    <param>
+        <name>Parallelism</name>
+        <key>ndim</key>
+        <value>0</value>
+        <type>enum</type>
+        <option>
+            <name>0</name>
+            <key>0</key>
+        </option>
+        <option>
+            <name>1</name>
+            <key>1</key>
+        </option>
+        <option>
+            <name>2</name>
+            <key>2</key>
+        </option>
+
+    </param>
+
+    <param>
+        <name>Dimension 1</name>
+        <key>dim1</key>
+        <value>4</value>
+        <type>int</type>
+        <hide>#if (int($ndim()) >= 1) then 'none' else 'all' #</hide>
+    </param>
+
+    <param>
+        <name>Dimension 2</name>
+        <key>dim2</key>
+        <value>4</value>
+        <type>int</type>
+        <hide>#if (int($ndim()) >= 2) then 'none' else 'all' #</hide>
+    </param>
+
+    <param>
+        <name>Row Encoder Polynomials</name>
+        <key>row_poly</key>
+        <value>[3]</value>
+        <type>int_vector</type>
+    </param>
+    
+    <param>
+        <name>Column Encoder Polynomials</name>
+        <key>col_poly</key>
+        <value>[43]</value>
+        <type>int_vector</type>
+    </param>
+    
+    <param>
+        <name>K Row</name>
+        <key>krow</key>
+        <value>26</value>
+        <type>int</type>
+    </param>
+    
+    <param>
+        <name>K Col</name>
+        <key>kcol</key>
+        <value>6</value>
+        <type>int</type>
+    </param>
+    
+    <param>
+        <name>B</name>
+        <key>bval</key>
+        <value>9</value>
+        <type>int</type>
+    </param>
+    
+    <param>
+        <name>Q</name>
+        <key>qval</key>
+        <value>3</value>
+        <type>int</type>
+    </param>
+
+    <doc>
+        This instantiates a 1-dim array or 2-dim array fo Turbo Product 
Encoders (TPC).
+        Restrictions: B and Q must be carefully chosen such that when the 
matrices are setup,
+        and the first B outputs are removed, they (the first B outputs) are 
all 0's.
+    </doc>
+</block>
diff --git a/gr-fec/include/gnuradio/fec/tpc_common.h 
b/gr-fec/include/gnuradio/fec/tpc_common.h
new file mode 100644
index 0000000..a5b0144
--- /dev/null
+++ b/gr-fec/include/gnuradio/fec/tpc_common.h
@@ -0,0 +1,28 @@
+#ifndef INCLUDED_TPC_COMMON_H
+#define INCLUDED_TPC_COMMON_H
+
+#include <vector>
+
+namespace gr {
+namespace fec { 
+
+class tpc_common {
+public:
+    static int parity_counter( int symbol, int length );
+    static void rsc_enc_bit(int input, int state_in, std::vector<int> g, int 
KK, int nn, 
+                    std::vector< std::vector<int> > &output, std::vector< 
std::vector<int> > &nextStates);
+    static void precomputeStateTransitionMatrix_RSCPoly(
+        int numStates,
+        std::vector<int> g, 
+        int KK, 
+        int nn, 
+        std::vector< std::vector<int> > &output, 
+        std::vector< std::vector<int> > &nextStates);
+    static void rsc_tail( std::vector<int> &tail_p, std::vector<int> g, int 
max_states, int mm );
+    static void itob(std::vector<int> &binVec, int symbol, int length);
+};
+
+}
+}
+
+#endif  /* INCLUDED_TPC_COMMON_H */
diff --git a/gr-fec/include/gnuradio/fec/tpc_decoder.h 
b/gr-fec/include/gnuradio/fec/tpc_decoder.h
new file mode 100644
index 0000000..8175132
--- /dev/null
+++ b/gr-fec/include/gnuradio/fec/tpc_decoder.h
@@ -0,0 +1,134 @@
+#ifndef INCLUDED_TPC_DECODER_H
+#define INCLUDED_TPC_DECODER_H
+
+typedef float INPUT_DATATYPE;
+typedef unsigned char OUTPUT_DATATYPE;
+
+#include <map>
+#include <string>
+#include <gnuradio/fec/decoder.h>
+#include <vector>
+
+namespace gr {
+ namespace fec { 
+
+
+#define MAXLOG 1e7
+
+class FEC_API tpc_decoder : public generic_decoder {
+    //private constructor
+    tpc_decoder (std::vector<int> row_polys, std::vector<int> col_polys, int 
krow, int kcol, int bval, int qval, int max_iter, int decoder_type);
+
+    //plug into the generic fec api
+    int get_history();
+       float get_shift();
+       int get_input_item_size();
+       int get_output_item_size();
+       const char* get_conversion();
+    void generic_work(void *inBuffer, void *outbuffer);
+    int get_output_size();
+    int get_input_size();
+
+    unsigned int d_krow;
+    unsigned int d_kcol;
+    
+    std::vector<int> d_rowpolys;
+    std::vector<int> d_colpolys;
+    
+    int d_bval;
+    int d_qval;
+        
+    int d_max_iter;
+    int d_decoder_type;
+    
+    // store the state transitions & outputs
+    int rowNumStates;
+    std::vector< std::vector<int> > rowOutputs;
+    std::vector< std::vector<int> > rowNextStates;
+    int colNumStates;
+    std::vector< std::vector<int> > colOutputs;
+    std::vector< std::vector<int> > colNextStates;
+        
+    int rowEncoder_K;
+    int rowEncoder_n;
+    int rowEncoder_m;
+    int colEncoder_K;
+    int colEncoder_n;
+    int colEncoder_m;
+    int outputSize;
+    int inputSize;
+    
+    int codeword_M;
+    int codeword_N;
+    
+    int mInit, nInit;
+
+    // memory allocated for processing
+    int inputSizeWithPad;
+    
+    std::vector< std::vector<float> > channel_llr;
+    std::vector< std::vector<float> > Z;
+    std::vector<float> extrinsic_info;
+    std::vector<float> input_u_rows;
+    std::vector<float> input_u_cols;
+    std::vector<float> input_c_rows;
+    std::vector<float> input_c_cols;
+    std::vector<float> output_u_rows;
+    std::vector<float> output_u_cols;
+    std::vector<float> output_c_rows;
+    std::vector<float> output_c_cols;
+    
+    int numInitLoadIter;
+    int numInitRemaining;
+    int output_c_col_idx;
+
+    bool earlyExit;
+
+    FILE *fp;
+    
+    // soft input soft output decoding
+    int mm_row, max_states_row, num_symbols_row;
+    std::vector< std::vector<float> > beta_row;
+    std::vector<float> alpha_prime_row;
+    std::vector<float> alpha_row;
+    std::vector<float> metric_c_row;
+    std::vector<float> rec_array_row;
+    std::vector<float> num_llr_c_row;
+    std::vector<float> den_llr_c_row;
+    void siso_decode_row();
+    
+    int mm_col, max_states_col, num_symbols_col;
+    std::vector< std::vector<float> > beta_col;
+    std::vector<float> alpha_prime_col;
+    std::vector<float> alpha_col;
+    std::vector<float> metric_c_col;
+    std::vector<float> rec_array_col;
+    std::vector<float> num_llr_c_col;
+    std::vector<float> den_llr_c_col;
+    void siso_decode_col();
+
+    // Computes the branch metric used for decoding, returning a metric 
between the
+    // hypothetical symbol and received vector
+    float gamma(const std::vector<float> rec_array, const int symbol);
+    
+    float (tpc_decoder::*max_star)(const float, const float);
+    
+    float linear_log_map(const float delta1, const float delta2);
+    float max_log_map(const float delta1, const float delta2);
+    float constant_log_map(const float delta1, const float delta2);
+    float log_map_lut_correction(const float delta1, const float delta2);
+    float log_map_cfunction_correction(const float delta1, const float delta2);
+    
+    template <typename T> static int sgn(T val);
+
+ public:
+    static generic_decoder::sptr make (std::vector<int> row_poly, 
std::vector<int> col_poly, int krow, int kcol, int bval, int qval, int 
max_iter, int decoder_type);
+    ~tpc_decoder ();
+    double rate() { return (1.0*get_output_size() / get_input_size()); }
+    bool set_frame_size(unsigned int frame_size){ return false; }
+};
+
+}
+}
+
+#endif /* INCLUDED_TPC_DECODER_H */
diff --git a/gr-fec/include/gnuradio/fec/tpc_encoder.h 
b/gr-fec/include/gnuradio/fec/tpc_encoder.h
new file mode 100755
index 0000000..4a14a8b
--- /dev/null
+++ b/gr-fec/include/gnuradio/fec/tpc_encoder.h
@@ -0,0 +1,89 @@
+#ifndef INCLUDED_TPC_ENCODER_H
+#define INCLUDED_TPC_ENCODER_H
+
+#include <map>
+#include <string>
+#include <gnuradio/fec/encoder.h>
+#include <gnuradio/fec/generic_encoder.h>
+#include <vector>
+
+
+namespace gr { 
+namespace fec { 
+
+class FEC_API tpc_encoder : public generic_encoder {
+
+    //private constructor
+    tpc_encoder (std::vector<int> row_polys, std::vector<int> col_polys, int 
krow, int kcol, int bval, int qval);
+
+    //plug into the generic fec api
+    void generic_work(void *inBuffer, void *outbuffer);
+    int get_output_size();
+    int get_input_size();
+
+    unsigned int d_krow;
+    unsigned int d_kcol;
+    
+    std::vector<int> d_rowpolys;
+    std::vector<int> d_colpolys;
+    
+    int d_bval;
+    int d_qval;
+        
+    // store the state transitions & outputs
+    int rowNumStates;
+    std::vector< std::vector<int> > rowOutputs;
+    std::vector< std::vector<int> > rowNextStates;
+    int colNumStates;
+    std::vector< std::vector<int> > colOutputs;
+    std::vector< std::vector<int> > colNextStates;
+    
+    std::vector<int> rowTail;
+    std::vector<int> colTail;
+    
+    int rowEncoder_K;
+    int rowEncoder_n;
+    int rowEncoder_m;
+    int colEncoder_K;
+    int colEncoder_n;
+    int colEncoder_m;
+    int outputSize;
+    int inputSize;
+    
+    // memory allocated for processing
+    int inputSizeWithPad;
+    std::vector<unsigned char> inputWithPad;
+    
+    std::vector< std::vector<float> > rowEncodedBits;
+    std::vector<unsigned char> rowToEncode;
+    int numRowsToEncode;
+    std::vector<float> rowEncoded_block;
+    
+    std::vector< std::vector<float> > colEncodedBits;
+    std::vector<unsigned char> colToEncode;
+    int numColsToEncode;
+    std::vector<float> colEncoded_block;
+    
+    void block_conv_encode( std::vector<float> &output,
+                               std::vector<unsigned char> input, 
+                               std::vector< std::vector<int> > transOutputVec,
+                               std::vector< std::vector<int> > 
transNextStateVec,
+                               std::vector<int> tail,
+                               int KK, 
+                               int nn);
+
+    FILE *fp;
+    
+ public:
+    ~tpc_encoder ();
+    static generic_encoder::sptr make(std::vector<int> row_poly, 
std::vector<int> col_poly, int krow, int kcol, int bval, int qval);
+    double rate() { return (1.0*get_input_size() / get_output_size()); }
+    bool set_frame_size( unsigned int ){ return false; }
+
+};
+
+
+}
+}
+
+#endif /* INCLUDED_TPC_ENCODER_H */
diff --git a/gr-fec/lib/CMakeLists.txt b/gr-fec/lib/CMakeLists.txt
index 99f701c..2c116fe 100644
--- a/gr-fec/lib/CMakeLists.txt
+++ b/gr-fec/lib/CMakeLists.txt
@@ -78,6 +78,9 @@ list(APPEND gnuradio_fec_sources
   gf2vec.cc
   gf2mat.cc
   alist.cc
+  tpc_common.cc
+  tpc_decoder.cc
+  tpc_encoder.cc 
 )
 
 #Add Windows DLL resource file if using MSVC
diff --git a/gr-fec/lib/tpc_common.cc b/gr-fec/lib/tpc_common.cc
new file mode 100644
index 0000000..d8b2e17
--- /dev/null
+++ b/gr-fec/lib/tpc_common.cc
@@ -0,0 +1,82 @@
+/**
+ * This code borrows from the CML library for the CC Encode functionality, 
+ * and for the RSC_Encode functionality.  Please have a look @:
+ * https://code.google.com/p/iscml
+ * 
+ */
+
+#include <gnuradio/fec/tpc_common.h>
+
+namespace gr { 
+ namespace fec { 
+
+int tpc_common::parity_counter( int symbol, int length ) {
+    int counter;
+    int temp_parity = 0;
+
+    for (counter=0;counter<length;counter++) {
+        temp_parity = temp_parity^(symbol&1);
+        symbol = symbol>>1;
+    }
+
+    return( temp_parity );
+}
+
+void tpc_common::rsc_enc_bit(int input, int state_in, std::vector<int> g, int 
KK, int nn, 
+                              std::vector< std::vector<int> > &outputVec, 
std::vector< std::vector<int> > &nextStateVec) {
+    int state, i, out, a_k;
+
+    // systematic output
+    out = input;
+
+    // determine feedback bit
+    a_k = input^tpc_common::parity_counter( g[0]&state_in, KK );
+
+    // create a word made up of state and feedback bit
+    state = (a_k<<(KK-1))^state_in;
+
+    // AND the word with the generators
+    for (i=1;i<nn;i++) {
+        // update output symbol
+        out = (out<<1) + tpc_common::parity_counter( state&g[i], KK );
+    }
+
+    outputVec[input][state_in] = out;
+    nextStateVec[input][state_in] = (state>>1);
+}
+
+void tpc_common::precomputeStateTransitionMatrix_RSCPoly(
+        int numStates,
+        std::vector<int> g, 
+        int KK, 
+        int nn, 
+        std::vector< std::vector<int> > &output, 
+        std::vector< std::vector<int> > &nextStates) {
+    
+    for(int input=0; input<2; input++) {
+        for(int state=0; state<numStates; state++) {
+            tpc_common::rsc_enc_bit(input, state, g, KK, nn, output, 
nextStates);
+        }
+    }
+}
+
+void tpc_common::rsc_tail( std::vector<int> &tail_p, std::vector<int> g, int 
max_states, int mm ) {
+    // Determine the tail for each state
+    for(int state=0;state<max_states;state++) {
+        // determine feedback word
+        tail_p[state] = tpc_common::parity_counter( g[0]&state, mm );
+    }
+    return;
+}
+
+void tpc_common::itob(std::vector<int> &binVec, int symbol, int length) {
+    /// Go through each bit in the vector
+    for (int counter=0;counter<length;counter++) {
+        binVec[length-counter-1] = (symbol&1);
+        symbol = symbol>>1;
+    }
+    
+}
+
+}
+}
diff --git a/gr-fec/lib/tpc_decoder.cc b/gr-fec/lib/tpc_decoder.cc
new file mode 100644
index 0000000..332bd9b
--- /dev/null
+++ b/gr-fec/lib/tpc_decoder.cc
@@ -0,0 +1,894 @@
+#include <gnuradio/fec/tpc_decoder.h>
+#include <gnuradio/fec/tpc_common.h>
+#include <volk/volk.h>
+
+#include <math.h>
+#include <boost/assign/list_of.hpp>
+#include <sstream>
+#include <stdio.h>
+#include <vector>
+
+#include <algorithm>            // for std::reverse
+#include <string.h>             // for memcpy
+
+#include <gnuradio/fec/maxstar.h>
+
+/**
+ * This code borrows from the CML library for the SISO Decode functionality, 
+ * and for the RSC_Encode functionality.  Please have a look @:
+ * https://code.google.com/p/iscml
+ * 
+ */
+
+namespace gr { 
+ namespace fec { 
+
+generic_decoder::sptr
+tpc_decoder::make(std::vector<int> row_polys, std::vector<int> col_polys, int 
krow, int kcol, int bval, int qval, int max_iter, int decoder_type)
+{
+    return generic_decoder::sptr(new tpc_decoder(row_polys, col_polys, krow, 
kcol, bval, qval, max_iter, decoder_type));
+}
+
+tpc_decoder::tpc_decoder (std::vector<int> row_polys, std::vector<int> 
col_polys, int krow, int kcol, int bval, int qval, int max_iter, int 
decoder_type)
+    : generic_decoder("tpc_decoder"), d_rowpolys(row_polys), 
d_colpolys(col_polys), d_krow(krow), d_kcol(kcol),
+      d_bval(bval), d_qval(qval), d_max_iter(max_iter), 
d_decoder_type(decoder_type)
+{
+    // first we operate on data chunks of get_input_size()
+    // TODO: should we verify this and throw an error if it doesn't match?  YES
+    // hwo do we do that?
+    
+    rowEncoder_K = ceil(log(d_rowpolys[0])/log(2));    // rowEncoder_K is the 
constraint length of the row encoder polynomial
+    rowEncoder_n = d_rowpolys.size();
+    rowEncoder_m = rowEncoder_K - 1;
+    colEncoder_K = ceil(log(d_colpolys[0])/log(2));    // colEncoder_K is the 
constraint length of the col encoder polynomial
+    colEncoder_n = d_colpolys.size();
+    colEncoder_m = colEncoder_K - 1;
+    
+    // calculate the input and output sizes
+    inputSize = 
((d_krow+rowEncoder_m)*rowEncoder_n)*((d_kcol+colEncoder_m)*colEncoder_n) - 
d_bval;
+    outputSize = (d_krow*d_kcol - (d_bval+d_qval));
+    
+    //DEBUG_PRINT("inputSize=%d outputSize=%d\n", inputSize, outputSize);
+    fp = fopen("c_decoder_output.txt", "w");
+    
+    rowNumStates = 1 << (rowEncoder_m);       // 2^(row_mm)
+    colNumStates = 1 << (colEncoder_m);       // 2^(col_mm)
+    rowOutputs.resize(2, std::vector<int>(rowNumStates,0));
+    rowNextStates.resize(2, std::vector<int>(rowNumStates,0));
+    colOutputs.resize(2, std::vector<int>(colNumStates,0));
+    colNextStates.resize(2, std::vector<int>(colNumStates,0));;
+    
+    // precalculate the state transition matrix for the row polynomial
+    tpc_common::precomputeStateTransitionMatrix_RSCPoly(rowNumStates, 
d_rowpolys, rowEncoder_K, rowEncoder_n, 
+                                                        rowOutputs, 
rowNextStates);
+    
+    // precalculate the state transition matrix for the column polynomial
+    tpc_common::precomputeStateTransitionMatrix_RSCPoly(colNumStates, 
d_colpolys, colEncoder_K, colEncoder_n, 
+                                                        colOutputs, 
colNextStates);
+   
+    codeword_M = d_kcol + colEncoder_K - 1;
+    codeword_N = d_krow + rowEncoder_K - 1;
+    
+    // pre-allocate memory we use for encoding
+    inputSizeWithPad = inputSize + d_bval;
+        
+    channel_llr.resize(codeword_M, std::vector<float>(codeword_N, 0));
+    Z.resize(codeword_M, std::vector<float>(codeword_N, 0));
+    extrinsic_info.resize(codeword_M*codeword_N, 0);
+    
+    input_u_rows.resize(d_krow, 0);
+    input_u_cols.resize(d_kcol, 0);
+    input_c_rows.resize(codeword_N, 0);
+    input_c_cols.resize(codeword_M, 0);
+    output_u_rows.resize(d_krow, 0);
+    output_u_cols.resize(d_kcol, 0);
+    output_c_rows.resize(codeword_N, 0);
+    
+    output_c_cols.resize(codeword_M*codeword_N, 0);
+    output_c_col_idx = 0;
+    
+    // setup the max_star function based on decoder type
+    switch(d_decoder_type) {
+        case 0:
+            max_star = &tpc_decoder::linear_log_map;
+            break;
+        case 1:
+            max_star = &tpc_decoder::max_log_map;
+            break;
+        case 2:
+            max_star = &tpc_decoder::constant_log_map;
+            break;
+        case 3:
+            max_star = &tpc_decoder::log_map_lut_correction;
+            break;
+        case 4:
+            max_star = &tpc_decoder::log_map_cfunction_correction;
+            break;
+        default:
+            max_star = &tpc_decoder::linear_log_map;
+            break;
+    }
+    
+       // declare the reverse sweep trellis
+       // the beta vector is logically layed out in memory as follows, 
assuming the
+       // following values (for educational purposes)
+       // defined: LL = 6, rowEncoder_K = 3, derived: mm_row=2, 
max_states_row=4, rowEncoder_n=1, num_symbols_row=2
+       // state_idx
+       
//-------------------------------------------------------------------------
+       //    0    B(0,0) <-- the calculated beta value at state=0, time=0
+       //
+       //    1    B(0,1)
+       //
+       //    2    B(0,2)
+       //
+       //    3    B(0,3)
+       
//-------------------------------------------------------------------------
+       //k(time) =   0     1     2     3     4     5     6     7     8
+    // setup row siso decoder
+    mm_row = rowEncoder_K-1;                // encoder memory
+    max_states_row = 1 << mm_row;              // 2^mm_row
+    num_symbols_row = 1 << rowEncoder_n;    // 2^rowEncoder_n
+
+    beta_row.resize(input_u_rows.size()+rowEncoder_K, 
std::vector<float>(max_states_row, 0));
+    // forward sweep trellis for current time instant only (t=k)
+    alpha_prime_row.resize(max_states_row, 0);
+    // forward sweep trellis for next time instant only    (t=k+1)
+    alpha_row.resize(max_states_row, 0);
+    // likelihood vector that input_c[idx] corresponds to a symbol in the set 
of [0 ... num_symbols_row-1]
+    metric_c_row.resize(num_symbols_row, 0);
+    // temporary vector to store the appropriate indexes of input_c that we 
want to test the likelihood of
+    rec_array_row.resize(rowEncoder_n, 0);
+    // log-likelihood ratios of the coded bit being a 1
+    num_llr_c_row.resize(rowEncoder_n, 0);
+    // log-likelihood ratios of the coded bit being a 0
+    den_llr_c_row.resize(rowEncoder_n, 0);
+
+
+    // setup column siso decoder
+    mm_col = colEncoder_K-1;                // encoder memory
+    max_states_col = 1 << mm_col;              // 2^mm_col
+    num_symbols_col = 1 << colEncoder_n;    // 2^colEncoder_n
+    beta_col.resize(input_u_cols.size()+colEncoder_K, 
std::vector<float>(max_states_col, 0));
+       // forward sweep trellis for current time instant only (t=k)
+       alpha_prime_col.resize(max_states_col, 0);
+       // forward sweep trellis for next time instant only    (t=k+1)
+       alpha_col.resize(max_states_col, 0);
+       // likelihood vector that input_c[idx] corresponds to a symbol in the 
set of [0 ... num_symbols_col-1]
+       metric_c_col.resize(num_symbols_col, 0);
+       // temporary vector to store the appropriate indexes of input_c that we 
want to test the likelihood of
+       rec_array_col.resize(colEncoder_n, 0);
+       // log-likelihood ratios of the coded bit being a 1
+       num_llr_c_col.resize(colEncoder_n, 0);
+       // log-likelihood ratios of the coded bit being a 0
+       den_llr_c_col.resize(colEncoder_n, 0);
+
+    mInit = (d_bval+d_qval)/d_krow;            // integer division
+    nInit = (d_bval+d_qval) - mInit*d_krow;
+
+    numInitLoadIter = d_bval/codeword_N;
+       numInitRemaining = d_bval - codeword_N*numInitLoadIter;
+
+}
+
+int tpc_decoder::get_output_size() {
+    return outputSize;
+}
+
+int tpc_decoder::get_input_size() {
+    return inputSize;
+}
+
+// this code borrows heavily from CML library, please look @:
+// http://code.google.com/p/iscml
+// it has been refactored to work w/ gnuradio in C++ environment,
+// as well as some comments being added to help understand
+// exactly what is going on w/ the siso decoder
+void tpc_decoder::siso_decode_row() {
+    
+    int LL, state, k, ii, symbol, mask;
+    float app_in, delta1, delta2;
+    LL = input_u_rows.size();        // code length
+
+    // log-likelihood ratio of the uncoded bit being a 1
+    float num_llr_u;
+    // log-likelihood ratio of the uncoded bit being a 0
+    float den_llr_u;
+    
+    // initialize beta_row trellis
+    // this initialization is saying that the likelihood that the reverse sweep
+    // starts at state=0 is 100%, b/c state 1, 2, 3's likelihood's are 
basically -inf
+    // this implies that the forward trellis terminated at the 0 state
+//    for(state=1; state<max_states_row; state++) {
+//             beta_row[LL+rowEncoder_K-1][state] = -MAXLOG;
+//     }
+    // filling w/ 0xCCCC yields a value close to -MAXLOG, and memset is faster 
than for loops
+    memset(&beta_row[LL+rowEncoder_K-1][1], 0xCCCC, 
sizeof(float)*(max_states_row-1));
+    
+    // initialize alpha_prime_row (current time instant), alpha_prime_row then 
gets updated
+    // by shifting in alpha_row at the end of each time instant of processing
+    // alpha_row needs to get initialized at the beginning of each processing 
loop, so we
+    // initialize alpha_row in the forward sweep processing loop
+    // the initialization below is saying that the likelihood of starting at 
state=0 is
+    // 100%, b/c state 1, 2, 3's likelihoods are basically -inf
+    // as with the beta_row array, this implies that the forward trellis 
started at state=0
+//    for (state=1;state<max_states_row;state++) {
+//             alpha_prime_row[state] = -MAXLOG;
+//     }
+    memset(&alpha_prime_row[1], 0xCCCC, sizeof(float)*(max_states_row-1));
+    
+    // compute the beta_row matrix first, which is the reverse sweep (hence we 
start at the last
+    // time instant-1 and work our way back to t=0).  we start at last time 
instant-1 b/c
+    // we already filled in beta_row values for the last time instant, forcing 
the trellis to
+    // start at state=0
+//     DEBUG_PRINT("LL=%d KK=%d mm=%d\n", LL, rowEncoder_K, mm_row);
+//     DEBUG_PRINT_F(fp, "LL=%d KK=%d mm=%d\n", LL, rowEncoder_K, mm_row);
+    for (k=(LL+(rowEncoder_K-1)-1); k>=0; k--) {
+        // TODO: figure out why this is needed? I'm still confused by this
+        if (k<LL) {
+            app_in = input_u_rows[k];
+        }
+        else {
+            app_in = 0;
+        }
+        
+        // get the input associated w/ this time instant
+        memcpy(&rec_array_row[0], &input_c_rows[rowEncoder_n*k], 
sizeof(float)*rowEncoder_n);
+        
+//         DEBUG_PRINT("k=%d\n", k);
+//         DEBUG_PRINT_F(fp, "k=%d\n", k);
+//         
+//         DEBUG_PRINT("rec_array -->\n");
+//         DEBUG_PRINT_FLOAT_ARRAY_AS_FLOAT(&rec_array_row[0], 
rec_array_row.size());
+//         DEBUG_PRINT_F(fp, "rec_array -->\n");
+//         DEBUG_PRINT_FLOAT_ARRAY_AS_FLOAT_F(fp, &rec_array_row[0], 
rec_array_row.size());
+        
+        // for each input at this time instant, create a metric which 
+        // represents the likelihood that this input corresponds to
+        // each of the possible symbols
+        for(symbol=0; symbol<num_symbols_row; symbol++) {
+            metric_c_row[symbol] = gamma(rec_array_row, symbol);
+        }
+        
+//         DEBUG_PRINT("metric_c -->\n");
+//         DEBUG_PRINT_FLOAT_ARRAY_AS_FLOAT(&metric_c_row[0], 
metric_c_row.size());
+//         DEBUG_PRINT_F(fp, "metric_c -->\n");
+//         DEBUG_PRINT_FLOAT_ARRAY_AS_FLOAT_F(fp, &metric_c_row[0], 
metric_c_row.size());
+        
+        // step through all states -- populating the beta_row values for each 
node
+        // in the trellis diagram as shown above w/ the maximum-likelihood
+        // of this current node coming from the previous node
+        for ( state=0; state< max_states_row; state++ ) {
+            // data 0 branch
+            delta1 = beta_row[k+1][rowNextStates[0][state]] + 
metric_c_row[rowOutputs[0][state]];
+            // data 1 branch
+            delta2 = beta_row[k+1][rowNextStates[1][state]] + 
metric_c_row[rowOutputs[1][state]] + app_in;
+            // update beta_row
+            beta_row[k][state] = (*this.*max_star)(delta1, delta2);
+            
+//             DEBUG_PRINT("delta1=%f delta2=%f beta=%f\n", delta1, delta2, 
beta_row[k][state]);
+//             DEBUG_PRINT_F(fp, "delta1=%f delta2=%f beta=%f\n", delta1, 
delta2, beta_row[k][state]);
+        }
+                
+        // normalize beta_row
+        for (state=1;state<max_states_row;state++) {
+               beta_row[k][state] = beta_row[k][state] - beta_row[k][0];
+        }
+        beta_row[k][0] = 0;
+        
+    }
+    
+    // compute the forward sweep (alpha_row values), and update the llr's
+    // notice that we start at time index=1, b/c time index=0 has already been
+    // initialized, and we are forcing the trellis to start from state=0
+    for(k=1; k<LL+rowEncoder_K; k++) {
+        // initialize the llr's for the uncoded bits
+        num_llr_u = -MAXLOG;
+        den_llr_u = -MAXLOG;
+        
+        // intialize alpha_row
+//        for (state=0;state<max_states_row;state++) {
+//                     alpha_row[state] = -MAXLOG;
+//             }
+        memset(&alpha_row[0], 0xCCCC, max_states_row*sizeof(float));
+
+        // assign inputs
+        if (k-1 < LL)
+            app_in = input_u_rows[k-1];
+        else
+            app_in = 0;
+
+        // initialize the llr's for the coded bits, and get the correct
+        // input bits for this time instant
+        for (ii=0;ii<rowEncoder_n;ii++) {
+            den_llr_c_row[ii] = -MAXLOG;
+            num_llr_c_row[ii] = -MAXLOG;
+            rec_array_row[ii] = input_c_rows[rowEncoder_n*(k-1)+ii];
+        }
+        
+        // for each input at this time instant, create a metric which 
+        // represents the likelihood that this input corresponds to
+        // each of the possible symbols
+        for(symbol=0; symbol<num_symbols_row; symbol++) {
+            metric_c_row[ii] = gamma(rec_array_row, symbol);
+        }
+        
+        // compute the alpha_row vector
+        // to understand the loop below, we need to think about the forward 
trellis.
+        // we know that any node, at any time instant in the trellis diagram 
can have
+        // multiple transitions into that node (i.e. any number of nodes in 
the 
+        // previous time instance can transition into this current node, based 
on the
+        // polynomial).  SO, in the loop below, delta1 represents the 
transition from
+        // the previous time instant for input (either 0 or 1) and the current 
state
+        // we are looping over, and delta2 represents a transition from the 
previous
+        // time instant to the current time instant for input (either 0 or 1) 
that
+        // we've already calculated.  Essentially, b/c we can have multiple 
possible
+        // transitions into the current alpha_row node of interest, and we 
need to store the
+        // maximum likelihood of all those transitions, we keep delta2 as a 
previously
+        // calculated transition, and then take the max* of that, which can be 
thought
+        // of as a maximum (in the MAX-LOG-MAP approximation)
+        for ( state=0; state<max_states_row; state++ ) {
+            // Data 0 branch
+            delta1 = alpha_prime_row[state] + 
metric_c_row[rowOutputs[0][state]];
+            delta2 = alpha_row[rowNextStates[0][state]];
+            alpha_row[rowNextStates[0][state]] = (*this.*max_star)(delta1, 
delta2);
+
+            // Data 1 branch
+            delta1 = alpha_prime_row[state] + 
metric_c_row[rowOutputs[1][state]] + app_in;
+            delta2 = alpha_row[rowNextStates[1][state]];
+            alpha_row[rowNextStates[1][state]] = (*this.*max_star)(delta1, 
delta2);
+        }
+        
+        // compute the llr's
+        for (state=0;state<max_states_row;state++)  {
+            // data 0 branch (departing)
+            delta1 = alpha_prime_row[state] + 
metric_c_row[rowOutputs[0][state]] + beta_row[k][rowNextStates[0][state]];
+            // the information bit
+            delta2 = den_llr_u;
+            den_llr_u = (*this.*max_star)(delta1, delta2);
+            mask = 1<<(rowEncoder_n-1);
+            // go through all the code bits
+            for (ii=0;ii<rowEncoder_n;ii++) {
+                if ( rowOutputs[0][state]&mask ) {
+                    // this code bit 1
+                    delta2 = num_llr_c_row[ii];
+                    num_llr_c_row[ii] = (*this.*max_star)(delta1, delta2);
+                } else {
+                    // this code bit is 0
+                    delta2 = den_llr_c_row[ii];
+                    den_llr_c_row[ii] = (*this.*max_star)(delta1, delta2);
+                }
+                mask = mask>>1;
+            }
+            
+            // data 1 branch (departing)
+            delta1 = alpha_prime_row[state] + 
metric_c_row[rowOutputs[1][state]] + beta_row[k][rowNextStates[1][state]] + 
app_in;
+            // the information bit
+            delta2 = num_llr_u;
+            num_llr_u = (*this.*max_star)(delta1, delta2);
+            mask = 1<<(rowEncoder_n-1);
+            // go through all the code bits
+            for (ii=0;ii<rowEncoder_n;ii++) {
+                if ( rowOutputs[1][state]&mask ) {
+                    // this code bit 1
+                    delta2 = num_llr_c_row[ii];
+                    num_llr_c_row[ii] = (*this.*max_star)(delta1, delta2);
+                } else {
+                    // this code bit is 0
+                    delta2 = den_llr_c_row[ii];
+                    den_llr_c_row[ii] = (*this.*max_star)(delta1, delta2);
+                }
+                mask = mask>>1;
+            }
+
+            // shift alpha_row back to alpha_prime_row
+            alpha_prime_row[state] = alpha_row[state] - alpha_row[0];
+        }
+        
+        // assign uncoded outputs 
+        if (k-1<LL) {
+            output_u_rows[k-1] = num_llr_u - den_llr_u;
+        }
+        // assign coded outputs
+        volk_32f_x2_subtract_32f(&output_c_rows[rowEncoder_n*(k-1)], 
&num_llr_c_row[0], &den_llr_c_row[0], rowEncoder_n);
+    }
+}
+
+void tpc_decoder::siso_decode_col() {
+
+    int LL, state, k, ii, symbol, mask;
+    float app_in, delta1, delta2;
+    LL = input_u_cols.size();        // code length
+
+    // log-likelihood ratio of the uncoded bit being a 1
+    float num_llr_u;
+    // log-likelihood ratio of the uncoded bit being a 0
+    float den_llr_u;
+
+    // initialize beta_col trellis
+    // this initialization is saying that the likelihood that the reverse sweep
+    // starts at state=0 is 100%, b/c state 1, 2, 3's likelihood's are 
basically -inf
+    // this implies that the forward trellis terminated at the 0 state
+//    for(state=1; state<max_states_col; state++) {
+//             beta_col[LL+colEncoder_K-1][state] = -MAXLOG;
+//     }
+    memset(&beta_col[LL+colEncoder_K-1][1], 0xCCCC, 
sizeof(float)*(max_states_col-1));
+
+    // initialize alpha_prime_col (current time instant), alpha_prime_col then 
gets updated
+    // by shifting in alpha_col at the end of each time instant of processing
+    // alpha_col needs to get initialized at the beginning of each processing 
loop, so we
+    // initialize alpha_col in the forward sweep processing loop
+    // the initialization below is saying that the likelihood of starting at 
state=0 is
+    // 100%, b/c state 1, 2, 3's likelihoods are basically -inf
+    // as with the beta_col array, this implies that the forward trellis 
started at state=0
+//    for (state=1;state<max_states_col;state++) {
+//             alpha_prime_col[state] = -MAXLOG;
+//     }
+    memset(&alpha_prime_col[1], 0xCCCC, sizeof(float)*(max_states_col-1));
+
+    // compute the beta_col matrix first, which is the reverse sweep (hence we 
start at the last
+    // time instant-1 and work our way back to t=0).  we start at last time 
instant-1 b/c
+    // we already filled in beta_col values for the last time instant, forcing 
the trellis to
+    // start at state=0
+//     DEBUG_PRINT("LL=%d KK=%d mm=%d\n", LL, colEncoder_K, mm_col);
+//     DEBUG_PRINT_F(fp, "LL=%d KK=%d mm=%d\n", LL, colEncoder_K, mm_col);
+    for (k=(LL+(colEncoder_K-1)-1); k>=0; k--) {
+        // TODO: figure out why this is needed? I'm still confused by this
+        if (k<LL) {
+            app_in = input_u_cols[k];
+        }
+        else {
+            app_in = 0;
+        }
+
+        // get the input associated w/ this time instant
+        memcpy(&rec_array_col[0], &input_c_cols[colEncoder_n*k], 
sizeof(float)*colEncoder_n);
+
+//         DEBUG_PRINT("k=%d\n", k);
+//         DEBUG_PRINT_F(fp, "k=%d\n", k);
+//
+//         DEBUG_PRINT("rec_array -->\n");
+//         DEBUG_PRINT_FLOAT_ARRAY_AS_FLOAT(&rec_array[0], 
rec_array_col.size());
+//         DEBUG_PRINT_F(fp, "rec_array -->\n");
+//         DEBUG_PRINT_FLOAT_ARRAY_AS_FLOAT_F(fp, &rec_array[0], 
rec_array_col.size());
+
+        // for each input at this time instant, create a metric which
+        // represents the likelihood that this input corresponds to
+        // each of the possible symbols
+        for(symbol=0; symbol<num_symbols_col; symbol++) {
+            metric_c_col[symbol] = gamma(rec_array_col, symbol);
+        }
+
+//         DEBUG_PRINT("metric_c -->\n");
+//         DEBUG_PRINT_FLOAT_ARRAY_AS_FLOAT(&metric_c_col[0], 
metric_c_col.size());
+//         DEBUG_PRINT_F(fp, "metric_c -->\n");
+//         DEBUG_PRINT_FLOAT_ARRAY_AS_FLOAT_F(fp, &metric_c_col[0], 
metric_c_col.size());
+
+        // step through all states -- populating the beta_col values for each 
node
+        // in the trellis diagram as shown above w/ the maximum-likelihood
+        // of this current node coming from the previous node
+        for ( state=0; state< max_states_col; state++ ) {
+            // data 0 branch
+               delta1 = beta_col[k+1][colNextStates[0][state]] + 
metric_c_col[colOutputs[0][state]];
+            // data 1 branch
+            delta2 = beta_col[k+1][colNextStates[1][state]] + 
metric_c_col[colOutputs[1][state]] + app_in;
+            // update beta_col
+            beta_col[k][state] = (*this.*max_star)(delta1, delta2);
+
+//             DEBUG_PRINT("delta1=%f delta2=%f beta=%f\n", delta1, delta2, 
beta_col[k][state]);
+//             DEBUG_PRINT_F(fp, "delta1=%f delta2=%f beta=%f\n", delta1, 
delta2, beta_col[k][state]);
+        }
+
+        // normalize beta_col
+        for (state=1;state<max_states_col;state++) {
+               beta_col[k][state] = beta_col[k][state] - beta_col[k][0];
+        }
+        beta_col[k][0] = 0;
+
+    }
+
+    // compute the forward sweep (alpha_col values), and update the llr's
+    // notice that we start at time index=1, b/c time index=0 has already been
+    // initialized, and we are forcing the trellis to start from state=0
+    for(k=1; k<LL+colEncoder_K; k++) {
+        // initialize the llr's for the uncoded bits
+        num_llr_u = -MAXLOG;
+        den_llr_u = -MAXLOG;
+
+        // intialize alpha_col
+//        for (state=0;state<max_states_col;state++) {
+//                     alpha_col[state] = -MAXLOG;
+//             }
+        memset(&alpha_col[0], 0xCCCC, max_states_col*sizeof(float));
+
+        // assign inputs
+        if (k-1 < LL)
+            app_in = input_u_cols[k-1];
+        else
+            app_in = 0;
+
+        // initialize the llr's for the coded bits, and get the correct
+        // input bits for this time instant
+        for (ii=0;ii<colEncoder_n;ii++) {
+            den_llr_c_col[ii] = -MAXLOG;
+            num_llr_c_col[ii] = -MAXLOG;
+            rec_array_col[ii] = input_c_cols[colEncoder_n*(k-1)+ii];
+        }
+
+        // for each input at this time instant, create a metric which
+        // represents the likelihood that this input corresponds to
+        // each of the possible symbols
+        for(symbol=0; symbol<num_symbols_col; symbol++) {
+            metric_c_col[ii] = gamma(rec_array_col, symbol);
+        }
+
+        // compute the alpha_col vector
+        // to understand the loop below, we need to think about the forward 
trellis.
+        // we know that any node, at any time instant in the trellis diagram 
can have
+        // multiple transitions into that node (i.e. any number of nodes in the
+        // previous time instance can transition into this current node, based 
on the
+        // polynomial).  SO, in the loop below, delta1 represents the 
transition from
+        // the previous time instant for input (either 0 or 1) and the current 
state
+        // we are looping over, and delta2 represents a transition from the 
previous
+        // time instant to the current time instant for input (either 0 or 1) 
that
+        // we've already calculated.  Essentially, b/c we can have multiple 
possible
+        // transitions into the current alpha_col node of interest, and we 
need to store the
+        // maximum likelihood of all those transitions, we keep delta2 as a 
previously
+        // calculated transition, and then take the max* of that, which can be 
thought
+        // of as a maximum (in the MAX-LOG-MAP approximation)
+        for ( state=0; state<max_states_col; state++ ) {
+            // Data 0 branch
+            delta1 = alpha_prime_col[state] + 
metric_c_col[colOutputs[0][state]];
+            delta2 = alpha_col[colNextStates[0][state]];
+            alpha_col[colNextStates[0][state]] = (*this.*max_star)(delta1, 
delta2);
+
+            // Data 1 branch
+            delta1 = alpha_prime_col[state] + 
metric_c_col[colOutputs[1][state]] + app_in;
+            delta2 = alpha_col[colNextStates[1][state]];
+            alpha_col[colNextStates[1][state]] = (*this.*max_star)(delta1, 
delta2);
+        }
+
+        // compute the llr's
+        for (state=0;state<max_states_col;state++)  {
+            // data 0 branch (departing)
+            delta1 = alpha_prime_col[state] + 
metric_c_col[colOutputs[0][state]] + beta_col[k][colNextStates[0][state]];
+            // the information bit
+            delta2 = den_llr_u;
+            den_llr_u = (*this.*max_star)(delta1, delta2);
+            mask = 1<<(colEncoder_n-1);
+            // go through all the code bits
+            for (ii=0;ii<colEncoder_n;ii++) {
+                if ( colOutputs[0][state]&mask ) {
+                    // this code bit 1
+                    delta2 = num_llr_c_col[ii];
+                    num_llr_c_col[ii] = (*this.*max_star)(delta1, delta2);
+                } else {
+                    // this code bit is 0
+                    delta2 = den_llr_c_col[ii];
+                    den_llr_c_col[ii] = (*this.*max_star)(delta1, delta2);
+                }
+                mask = mask>>1;
+            }
+
+            // data 1 branch (departing)
+            delta1 = alpha_prime_col[state] + 
metric_c_col[colOutputs[1][state]] + beta_col[k][colNextStates[1][state]] + 
app_in;
+            // the information bit
+            delta2 = num_llr_u;
+            num_llr_u = (*this.*max_star)(delta1, delta2);
+            mask = 1<<(colEncoder_n-1);
+            // go through all the code bits
+            for (ii=0;ii<colEncoder_n;ii++) {
+                if ( colOutputs[1][state]&mask ) {
+                    // this code bit 1
+                    delta2 = num_llr_c_col[ii];
+                    num_llr_c_col[ii] = (*this.*max_star)(delta1, delta2);
+                } else {
+                    // this code bit is 0
+                    delta2 = den_llr_c_col[ii];
+                    den_llr_c_col[ii] = (*this.*max_star)(delta1, delta2);
+                }
+                mask = mask>>1;
+            }
+
+            // shift alpha_col back to alpha_prime_col
+            alpha_prime_col[state] = alpha_col[state] - alpha_col[0];
+        }
+
+        // assign uncoded outputs
+        if (k-1<LL) {
+            output_u_cols[k-1] = num_llr_u - den_llr_u;
+        }
+        // assign coded outputs
+        
volk_32f_x2_subtract_32f(&output_c_cols[output_c_col_idx+rowEncoder_n*(k-1)], 
&num_llr_c_col[0], &den_llr_c_col[0], colEncoder_n);
+    }
+}
+
+float tpc_decoder::linear_log_map(const float delta1, const float delta2) {
+    float diff;
+    
+    diff = delta2 - delta1;
+
+    if ( diff > TJIAN )
+        return( delta2 );
+    else if ( diff < -TJIAN )
+        return( delta1 );
+    else if ( diff > 0 )
+        return( delta2 + AJIAN*(diff-TJIAN) );
+    else
+        return( delta1 - AJIAN*(diff+TJIAN) );
+}
+
+// MAX-LOG-MAP approximation
+float tpc_decoder::max_log_map(const float delta1, const float delta2) {
+    if(delta1>delta2) return delta1;
+    return delta2;
+}
+
+float tpc_decoder::constant_log_map(const float delta1, const float delta2) {
+    // Return maximum of delta1 and delta2
+    // and in correction value if |delta1-delta2| < TVALUE
+    register float diff;    
+    diff = delta2 - delta1;
+
+    if ( diff > TVALUE )
+        return( delta2 );
+    else if ( diff < -TVALUE )
+        return( delta1 );
+    else if ( diff > 0 )
+        return( delta2 + CVALUE );
+    else
+        return( delta1 + CVALUE );
+}
+
+float tpc_decoder::log_map_lut_correction(const float delta1, const float 
delta2) {
+    float diff;
+    diff = (float) fabs( delta2 - delta1 );
+    
+    if (delta1 > delta2) {
+        if (diff > BOUNDARY8 )
+            return( delta1 );
+        else if ( diff > BOUNDARY4 ) {
+            if (diff > BOUNDARY6 ) {
+                if ( diff > BOUNDARY7 )
+                    return( delta1 + VALUE7 + SLOPE7*(diff-BOUNDARY7) );
+                else
+                    return( delta1 + VALUE6 + SLOPE6*(diff-BOUNDARY6) );
+            } else {
+                if ( diff > BOUNDARY5 )
+                    return( delta1 + VALUE5 + SLOPE5*(diff-BOUNDARY5) );
+                else
+                    return( delta1 + VALUE4 + SLOPE4*(diff-BOUNDARY4) );
+            }   
+        } else {
+            if (diff > BOUNDARY2 ) {
+                if ( diff > BOUNDARY3 )
+                    return( delta1 + VALUE3 + SLOPE3*(diff-BOUNDARY3) );
+                else
+                    return( delta1 + VALUE2 + SLOPE2*(diff-BOUNDARY2) );
+            } else {
+                if ( diff > BOUNDARY1 )
+                    return( delta1 + VALUE1 + SLOPE1*(diff-BOUNDARY1) );
+                else
+                    return( delta1 + VALUE0 + SLOPE0*(diff-BOUNDARY0) );
+            }
+        }
+    } else {
+        if (diff > BOUNDARY8 )
+            return( delta2 );
+        else if ( diff > BOUNDARY4 ) {
+            if (diff > BOUNDARY6 ) {
+                if ( diff > BOUNDARY7 )
+                    return( delta2 + VALUE7 + SLOPE7*(diff-BOUNDARY7) );
+                else
+                    return( delta2 + VALUE6 + SLOPE6*(diff-BOUNDARY6) );
+            } else {
+                if ( diff > BOUNDARY5 )
+                    return( delta2 + VALUE5 + SLOPE5*(diff-BOUNDARY5) );
+                else
+                    return( delta2 + VALUE4 + SLOPE4*(diff-BOUNDARY4) );
+            }   
+        } else {
+            if (diff > BOUNDARY2 ) {
+                if ( diff > BOUNDARY3 )
+                    return( delta2 + VALUE3 + SLOPE3*(diff-BOUNDARY3) );
+                else
+                    return( delta2 + VALUE2 + SLOPE2*(diff-BOUNDARY2) );
+            } else {
+                if ( diff > BOUNDARY1 )
+                    return( delta2 + VALUE1 + SLOPE1*(diff-BOUNDARY1) );
+                else
+                    return( delta2 + VALUE0 + SLOPE0*(diff-BOUNDARY0) );
+            }
+        }
+    }
+}
+
+float tpc_decoder::log_map_cfunction_correction(const float delta1, const 
float delta2) {
+    // Use C-function calls to compute the correction function
+    if (delta1 > delta2) {
+        return( (float) (delta1 + log( 1 + exp( delta2-delta1) ) ) );       
+    } else  {
+        return( (float) (delta2 + log( 1 + exp( delta1-delta2) ) ) );       
+    }
+}
+
+float tpc_decoder::gamma(const std::vector<float> rx_array, const int symbol) {
+    float rm = 0;
+    int ii;
+    int mask;
+    int nn = rx_array.size();
+    
+    mask = 1;
+    for (ii=0;ii<nn;ii++) {
+        if (symbol&mask)
+            rm += rx_array[nn-ii-1];
+        mask = mask<<1;
+    }
+
+//     DEBUG_PRINT("nn=%d symbol=%d rm = %f\n", nn, symbol, rm);
+//     DEBUG_PRINT_F(fp, "nn=%d symbol=%d rm = %f\n", nn, symbol, rm);
+    
+    return(rm);
+}
+
+template <typename T> int tpc_decoder::sgn(T val) {
+    return (T(0) < val) - (val < T(0));
+}
+
+void tpc_decoder::generic_work(void *inBuffer, void *outBuffer) {
+    const float *inPtr = (const float *) inBuffer;
+    unsigned char *out = (unsigned char *) outBuffer;
+    
+    int m, n, ii;
+    int iter;
+    
+    for(ii=0; ii<numInitLoadIter; ii++) {
+       memset(&channel_llr[ii][0], 0, sizeof(float)*codeword_N);
+       memset(&Z[ii][0], 0, sizeof(float)*codeword_N);
+    }
+    memset(&channel_llr[ii][0], 0, sizeof(float)*numInitRemaining);
+    memset(&Z[ii][0], 0, sizeof(float)*numInitRemaining);
+    memcpy(&channel_llr[ii][numInitRemaining], &inPtr[0], 
(codeword_N-numInitRemaining)*sizeof(float));
+    memcpy(&Z[ii][numInitRemaining], &inPtr[0], 
(codeword_N-numInitRemaining)*sizeof(float));
+    int inPtrIdx = codeword_N-numInitRemaining;
+    for(ii=ii+1; ii<codeword_M; ii++) {
+               memcpy(&channel_llr[ii][0], &inPtr[inPtrIdx], 
sizeof(float)*codeword_N);
+               memcpy(&Z[ii][0], &inPtr[inPtrIdx], sizeof(float)*codeword_N);
+               inPtrIdx += codeword_N;
+       }
+
+    // clear out extrinsic-info between blocks
+    memset(&extrinsic_info[0], 0, sizeof(float)*extrinsic_info.size());
+
+    //DEBUG_PRINT("Starting TURBO Decoding\n");
+    
+    for(iter=0; iter<d_max_iter; iter++) {
+        //DEBUG_PRINT("Turbo Iter=%d\n", iter+1);
+        //DEBUG_PRINT_F(fp, "Turbo Iter=%d\n", iter+1);
+        // decode each row
+        for(m=0; m<codeword_M; m++) {
+            // stage the data
+               volk_32f_x2_add_32f(&input_c_rows[0], &channel_llr[m][0], 
&extrinsic_info[m*codeword_N], codeword_N);
+
+            //DEBUG_PRINT("input_c_rows -->\n");
+            //DEBUG_PRINT_FLOAT_ARRAY_AS_FLOAT(&input_c_rows[0], codeword_N);
+            //DEBUG_PRINT_F(fp, "input_c_rows -->\n");
+            //DEBUG_PRINT_FLOAT_ARRAY_AS_FLOAT_F(fp, &input_c_rows[0], 
codeword_N);
+            
+            // call siso decode
+            siso_decode_row();
+            
+            //DEBUG_PRINT("output_u_rows -->\n");
+            //DEBUG_PRINT_FLOAT_ARRAY_AS_FLOAT(&output_u_rows[0], 
output_u_rows.size());
+            //DEBUG_PRINT_F(fp, "output_u_rows -->\n");
+            //DEBUG_PRINT_FLOAT_ARRAY_AS_FLOAT_F(fp, &output_u_rows[0], 
output_u_rows.size());
+            //DEBUG_PRINT("output_c_rows -->\n");
+            //DEBUG_PRINT_FLOAT_ARRAY_AS_FLOAT(&output_c_rows[0], 
output_c_rows.size());
+            //DEBUG_PRINT_F(fp, "output_c_rows -->\n");
+            //DEBUG_PRINT_FLOAT_ARRAY_AS_FLOAT_F(fp, &output_c_rows[0], 
output_c_rows.size());
+            
+            // copy the output coded back into Z, so we can feed it back 
through the decoder
+            // for more iterations
+            volk_32f_x2_subtract_32f(&Z[m][0], &output_c_rows[0], 
&extrinsic_info[m*codeword_N], codeword_N);
+        }
+        
+        // decode each col
+        earlyExit = true;
+        output_c_col_idx = 0;
+        for(n=0; n<codeword_N; n++) {
+            // stage the data
+            for(ii=0; ii<codeword_M; ii++) {
+                input_c_cols[ii] = Z[ii][n];
+            }
+            
+            //DEBUG_PRINT("input_c_cols -->\n");
+            //DEBUG_PRINT_FLOAT_ARRAY_AS_FLOAT(&input_c_cols[0], codeword_M);
+            //DEBUG_PRINT_F(fp, "input_c_cols -->\n");
+            //DEBUG_PRINT_FLOAT_ARRAY_AS_FLOAT_F(fp, &input_c_cols[0], 
codeword_M);
+            
+            // call siso decode
+            siso_decode_col();
+            
+            //DEBUG_PRINT("output_u_cols -->\n");
+            //DEBUG_PRINT_FLOAT_ARRAY_AS_FLOAT(&output_u_cols[0], 
output_u_cols.size());
+            //DEBUG_PRINT_F(fp, "output_u_cols -->\n");
+            //DEBUG_PRINT_FLOAT_ARRAY_AS_FLOAT_F(fp, &output_u_cols[0], 
output_u_cols.size());
+            //DEBUG_PRINT("output_c_cols -->\n");
+            
//DEBUG_PRINT_FLOAT_ARRAY_AS_FLOAT(&output_c_cols[output_c_col_idx], 
codeword_M);
+            //DEBUG_PRINT_F(fp, "output_c_cols -->\n");
+            //DEBUG_PRINT_FLOAT_ARRAY_AS_FLOAT_F(fp, 
&output_c_cols[output_c_col_idx], codeword_M);
+            
+            // create the extrinsic_info vector, which subtracts from 
input_c_cols to prevent feedback
+            //DEBUG_PRINT("extrinsic_info -->\n");
+            //DEBUG_PRINT_F(fp, "extrinsic_info -->\n");
+            for(ii=0; ii<codeword_M; ii++) {
+               extrinsic_info[ii*codeword_N+n] = 
output_c_cols[output_c_col_idx+ii] - input_c_cols[ii];
+                
+               if(earlyExit) {
+                       
if(sgn(output_c_cols[output_c_col_idx+ii])!=sgn(input_c_cols[ii])) {
+                                               earlyExit = false;
+                                       }
+               }
+
+
+                //DEBUG_PRINT("%f ", extrinsic_info[ii*codeword_N+n]);
+                //DEBUG_PRINT_F(fp, "%f ", extrinsic_info[ii*codeword_N+n]);
+            }
+            //DEBUG_PRINT("\n");
+            //DEBUG_PRINT_F(fp, "\n");
+            
+            output_c_col_idx += codeword_M;
+        }
+        if(earlyExit) break;
+    }
+
+    ii=0;
+       for(m=0; m<d_kcol; m++) {
+               for(n=0; n<d_krow; n++) {
+                       if(ii==0) {
+                               m = mInit;
+                               n = nInit;
+                       }
+
+                       // make a hard decision
+//                     if(output_matrix[n*codeword_M+m]>0) {
+                       if(output_c_cols[n*codeword_M+m]>0) {
+                               out[ii++] = (unsigned char) 1;
+                       }
+                       else {
+                               out[ii++] = (unsigned char) 0;
+                       }
+               }
+       }
+    
+    //DEBUG_PRINT(("Output\n"));
+    //DEBUG_PRINT_UCHAR_ARRAY(out, outputSize);
+    //DEBUG_PRINT_F(fp, "Output\n");
+    //DEBUG_PRINT_UCHAR_ARRAY_F(fp, out, outputSize);
+}
+
+int tpc_decoder::get_input_item_size() {
+    return sizeof(INPUT_DATATYPE);
+}
+
+int tpc_decoder::get_output_item_size() {
+    return sizeof(OUTPUT_DATATYPE);
+}
+
+int tpc_decoder::get_history() {
+    return 0;
+}
+
+float tpc_decoder::get_shift() {
+    return 0.0;
+}
+
+const char* tpc_decoder::get_conversion() {
+    return "none";
+}
+
+tpc_decoder::~tpc_decoder() {
+    fclose(fp);
+}
+
+}
+}
diff --git a/gr-fec/lib/tpc_encoder.cc b/gr-fec/lib/tpc_encoder.cc
new file mode 100755
index 0000000..9404654
--- /dev/null
+++ b/gr-fec/lib/tpc_encoder.cc
@@ -0,0 +1,334 @@
+#include <gnuradio/fec/tpc_encoder.h>
+#include <gnuradio/fec/tpc_common.h>
+#include <gnuradio/fec/generic_encoder.h>
+
+#include <math.h>
+#include <boost/assign/list_of.hpp>
+#include <volk/volk.h>
+#include <sstream>
+#include <stdio.h>
+#include <vector>
+
+#include <algorithm>            // for std::reverse
+#include <string.h>             // for memcpy
+
+
+/**
+ * This code borrows from the CML library for the CC Encode functionality, 
+ * and for the RSC_Encode functionality.  Please have a look @:
+ * https://code.google.com/p/iscml
+ * 
+ */
+namespace gr {
+namespace fec { 
+generic_encoder::sptr
+tpc_encoder::make(std::vector<int> row_polys, std::vector<int> col_polys, int 
krow, int kcol, int bval, int qval)
+{
+    return generic_encoder::sptr(new tpc_encoder(row_polys, col_polys, krow, 
kcol, bval, qval));
+}
+
+tpc_encoder::tpc_encoder (std::vector<int> row_polys, std::vector<int> 
col_polys, int krow, int kcol, int bval, int qval)
+    : d_rowpolys(row_polys), d_colpolys(col_polys), d_krow(krow), d_kcol(kcol),
+      d_bval(bval), d_qval(qval)
+{
+    // first we operate on data chunks of get_input_size()
+    // TODO: should we verify this and throw an error if it doesn't match?  YES
+    // hwo do we do that?
+        
+    // calculate the input and output sizes
+    inputSize = (d_krow*d_kcol - (d_bval+d_qval));
+    rowEncoder_K = ceil(log(d_rowpolys[0])/log(2));    // rowEncoder_K is the 
constraint length of the row encoder polynomial
+    rowEncoder_n = d_rowpolys.size();
+    rowEncoder_m = rowEncoder_K - 1;
+    colEncoder_K = ceil(log(d_colpolys[0])/log(2));    // colEncoder_K is the 
constraint length of the col encoder polynomial
+    colEncoder_n = d_colpolys.size();
+    colEncoder_m = colEncoder_K - 1;
+    
+    outputSize = 
((d_krow+rowEncoder_m)*rowEncoder_n)*((d_kcol+colEncoder_m)*colEncoder_n) - 
d_bval;
+    
+    //DEBUG_PRINT("inputSize=%d outputSize=%d\n", inputSize, outputSize);
+    fp = fopen("c_encoder_output.txt", "w");
+    
+    // resize internal matrices
+    rowNumStates = 1 << (rowEncoder_K-1);       // 2^(row_mm)
+    colNumStates = 1 << (colEncoder_K-1);       // 2^(col_mm)
+    rowOutputs.resize(2, std::vector<int>(rowNumStates,0));
+    rowNextStates.resize(2, std::vector<int>(rowNumStates,0));
+    colOutputs.resize(2, std::vector<int>(colNumStates,0));
+    colNextStates.resize(2, std::vector<int>(colNumStates,0));;
+    
+    rowTail.resize(rowNumStates, 0);
+    colTail.resize(colNumStates, 0);
+    
+    // precalculate the state transition matrix for the row polynomial
+    tpc_common::precomputeStateTransitionMatrix_RSCPoly(rowNumStates, 
d_rowpolys, rowEncoder_K, rowEncoder_n, 
+                                                        rowOutputs, 
rowNextStates);
+    
+    // calculate the tail for the row
+    tpc_common::rsc_tail(rowTail, d_rowpolys, rowNumStates, rowEncoder_m);
+    
+    // precalculate the state transition matrix for the column polynomial
+    tpc_common::precomputeStateTransitionMatrix_RSCPoly(colNumStates, 
d_colpolys, colEncoder_K, colEncoder_n, 
+                                                        colOutputs, 
colNextStates);
+    // calculate the tail for the col
+    tpc_common::rsc_tail(colTail, d_colpolys, colNumStates, colEncoder_m);
+    
+    // pre-allocate memory we use for encoding
+    inputSizeWithPad = d_bval+d_qval+inputSize;
+    inputWithPad.resize(inputSizeWithPad, 0);
+    
+    numRowsToEncode = inputSizeWithPad/d_krow;      // this should be OK w/ 
integer division -- TODO: check this?
+    rowToEncode.resize(d_krow,0);
+    rowEncoded_block.resize(d_krow+(rowEncoder_m*rowEncoder_n), 0);
+    rowEncodedBits.resize(d_kcol, 
std::vector<float>(rowEncoder_m*rowEncoder_n,0) );
+    
+    numColsToEncode = d_krow+(rowEncoder_m*rowEncoder_n);
+    colToEncode.resize(d_kcol,0);
+    colEncoded_block.resize(d_kcol+(colEncoder_m*colEncoder_n), 0);
+    colEncodedBits.resize(d_krow+(rowEncoder_m*rowEncoder_n), 
std::vector<float>(colEncoder_m*colEncoder_n,0) );
+}
+
+int tpc_encoder::get_output_size() {
+    return outputSize;
+}
+
+int tpc_encoder::get_input_size() {
+    return inputSize;
+}
+
+void tpc_encoder::block_conv_encode( std::vector<float> &output,
+                               std::vector<unsigned char> input, 
+                               std::vector< std::vector<int> > transOutputVec,
+                               std::vector< std::vector<int> > 
transNextStateVec,
+                               std::vector<int> tail,
+                               int KK, 
+                               int nn)
+{
+    int outsym, ii, jj;
+    int state = 0;
+    int LL = input.size();
+
+    std::vector<int> binVec(nn,0);
+    
+    // encode data bits one bit at a time
+    for (ii=0; ii<LL; ii++) {
+        
+        // determine the output symbol
+        outsym = transOutputVec[(int)input[ii]][state];
+        // determine the next state
+        state = transNextStateVec[(int)input[ii]][state];
+        
+        // Convert symbol to a binary vector 
+        tpc_common::itob( binVec, outsym, nn );
+
+        // Assign to output : TODO: investigate using memcpy for this?
+        for (jj=0;jj<nn;jj++) {
+            output[nn*ii+jj] = (float) binVec[jj];
+        }
+    }
+
+    // encode tail
+    for (ii=LL;ii<LL+KK-1;ii++) {
+       
+        // determine the output symbol
+        outsym = transOutputVec[tail[state]][state];
+        // determine the next state
+        state = transNextStateVec[tail[state]][state];
+        
+        // Convert symbol to a binary vector
+        tpc_common::itob( binVec, outsym, nn );
+
+        // Assign to output : TODO: investigate using memcpy for this?
+        for (jj=0;jj<nn;jj++) {
+            output[nn*ii+jj] = (float) binVec[jj];
+        }
+    }
+}
+
+void tpc_encoder::generic_work(void *inBuffer, void *outBuffer) {
+    const unsigned char *in = (const unsigned char *) inBuffer;
+    float *out = (float *) outBuffer;
+
+    int ii, jj;     // indexing var
+    int tmp;
+    
+    //DEBUG_PRINT_UCHAR_ARRAY(in, inputSize);
+    
+    // TODO: probably a better way to do this than memcpy?
+    memcpy(&inputWithPad[d_bval+d_qval], in, sizeof(unsigned char)*inputSize);
+    
+    //DEBUG_PRINT("Input with Pad -->\n");
+    //DEBUG_PRINT_UCHAR_ARRAY(&inputWithPad[0], inputSizeWithPad);
+    //DEBUG_PRINT_F(fp, "Input with Pad -->\n");
+    //DEBUG_PRINT_UCHAR_ARRAY_F(fp, &inputWithPad[0], inputSizeWithPad);
+    
+    // encode the row data
+    for(ii=0; ii<numRowsToEncode; ii++) {
+        // populate rowToEncode
+        memcpy(&rowToEncode[0], &inputWithPad[ii*d_krow], sizeof(unsigned 
char)*d_krow);
+        
+        //DEBUG_PRINT("Encoding row=[%d] -->\n",ii);
+        //DEBUG_PRINT_UCHAR_ARRAY(&rowToEncode[0], d_krow);
+        //DEBUG_PRINT_F(fp, "Encoding row=[%d] -->\n",ii);
+        //DEBUG_PRINT_UCHAR_ARRAY_F(fp, &rowToEncode[0], d_krow);
+        
+        // encode it
+        block_conv_encode( rowEncoded_block, 
+                           rowToEncode, 
+                           rowOutputs, 
+                           rowNextStates, 
+                           rowTail, 
+                           rowEncoder_K,
+                           rowEncoder_n);
+        
+        //DEBUG_PRINT("Row Encoded Block=[%d] -->\n",ii);
+        tmp = rowEncoded_block.size();
+        //DEBUG_PRINT_FLOAT_ARRAY_AS_UCHAR(&rowEncoded_block[0], tmp);
+        //DEBUG_PRINT_F(fp, "Row Encoded Block=[%d] -->\n",ii);
+        //DEBUG_PRINT_FLOAT_ARRAY_AS_UCHAR_F(fp, &rowEncoded_block[0], tmp);
+        
+        // store only the encoded bits, b/c we read out the data in a special 
way
+        memcpy(&rowEncodedBits[ii][0], &rowEncoded_block[d_krow], 
sizeof(float)*(rowEncoder_m*rowEncoder_n));
+        
+//         DEBUG_PRINT("Row Encoded Bits");
+//         tmp = rowEncoder_m*rowEncoder_n;
+//         DEBUG_PRINT_FLOAT_ARRAY_AS_UCHAR(&rowEncodedBits[ii][0], tmp);
+    }
+    
+    // encode the column data
+    int numDataColsToEncode = d_krow;
+    int numCheckColsToEncode = numColsToEncode-numDataColsToEncode;
+    for(ii=0; ii<numDataColsToEncode; ii++) {
+        // populate colToEncode
+        for(jj=0; jj<d_kcol; jj++) {
+            colToEncode[jj] = inputWithPad[jj*d_krow+ii];
+        }
+        
+        //DEBUG_PRINT("Encoding col=[%d] -->\n",ii);
+        //DEBUG_PRINT_UCHAR_ARRAY(&colToEncode[0], d_kcol);
+        //DEBUG_PRINT_F(fp, "Encoding col=[%d] -->\n",ii);
+        //DEBUG_PRINT_UCHAR_ARRAY_F(fp, &colToEncode[0], d_kcol);
+        
+        // encode it
+        block_conv_encode( colEncoded_block, 
+                           colToEncode, 
+                           colOutputs, 
+                           colNextStates, 
+                           colTail, 
+                           colEncoder_K,
+                           colEncoder_n);
+        
+        //DEBUG_PRINT("Col Encoded Block=[%d] -->\n",ii);
+        tmp = colEncoded_block.size();
+        //DEBUG_PRINT_FLOAT_ARRAY_AS_UCHAR(&colEncoded_block[0], tmp);
+        //DEBUG_PRINT_F(fp, "Col Encoded Block=[%d] -->\n",ii);
+        //DEBUG_PRINT_FLOAT_ARRAY_AS_UCHAR_F(fp, &colEncoded_block[0], tmp);
+        
+        // store only the encoded bits, b/c we read the data out in a special 
way
+        memcpy(&colEncodedBits[ii][0], &colEncoded_block[d_kcol], 
sizeof(float)*(colEncoder_m*colEncoder_n));
+        
+//         DEBUG_PRINT("Col Encoded Bits");
+//         tmp = colEncoder_m*colEncoder_n;
+//         DEBUG_PRINT_FLOAT_ARRAY(&colEncodedBits[ii][0], tmp);
+    }
+    
+    // encode checks on checks (encode the row-encoded bits)
+    for(ii=0; ii<numCheckColsToEncode; ii++) {
+        // populate colToEncode
+        for(jj=0; jj<d_kcol; jj++) {
+            colToEncode[jj] = rowEncodedBits[jj][ii];       // indexing is 
wierd b/c of the way we declared the vector :(
+        }
+        
+        //DEBUG_PRINT("Encoding col=[%d] -->\n",ii+numDataColsToEncode);
+        //DEBUG_PRINT_UCHAR_ARRAY(&colToEncode[0], d_kcol);
+        //DEBUG_PRINT_F(fp, "Encoding col=[%d] -->\n",ii+numDataColsToEncode);
+        //DEBUG_PRINT_UCHAR_ARRAY_F(fp, &colToEncode[0], d_kcol);
+        
+        // encode it
+        block_conv_encode( colEncoded_block, 
+                           colToEncode, 
+                           colOutputs, 
+                           colNextStates, 
+                           colTail, 
+                           colEncoder_K,
+                           colEncoder_n);
+        
+        //DEBUG_PRINT("Col Encoded Block=[%d] -->\n",ii+numDataColsToEncode);
+        tmp = colEncoded_block.size();
+        //DEBUG_PRINT_FLOAT_ARRAY_AS_UCHAR(&colEncoded_block[0], tmp);
+        
+        //DEBUG_PRINT_F(fp, "Col Encoded Block=[%d] 
-->\n",ii+numDataColsToEncode);
+        //DEBUG_PRINT_FLOAT_ARRAY_AS_UCHAR_F(fp, &colEncoded_block[0], tmp);
+        
+        
+        // store only the encoded bits, b/c we read the data out in a special 
way
+        memcpy(&colEncodedBits[ii+numDataColsToEncode][0], 
&colEncoded_block[d_kcol], sizeof(float)*(colEncoder_m*colEncoder_n));
+        
+//         DEBUG_PRINT("Col Encoded Bits");
+//         tmp = colEncoder_m*colEncoder_n;
+//         DEBUG_PRINT_FLOAT_ARRAY(&colEncodedBits[ii][0], tmp);
+    }
+    
+    unsigned char* inputDataPtr;
+    float *outputDataPtr = out;
+    float *tmpPtr = outputDataPtr;
+    
+    int curRowInRowEncodedBits = 0;
+    // read out the data along the rows into the "out" array
+    
+    // skip B zeros & do the first row
+    inputDataPtr =  &inputWithPad[d_bval];
+    int firstRowRemainingBits = d_krow-d_bval;
+    for(ii=0; ii<firstRowRemainingBits; ii++) {
+        *outputDataPtr++ = (float)(*inputDataPtr++);
+    }
+    
+    // copy the encoded bits
+    memcpy(outputDataPtr, &rowEncodedBits[curRowInRowEncodedBits++][0], 
+            sizeof(float)*(rowEncoder_m*rowEncoder_n));
+    
+    outputDataPtr += (rowEncoder_m*rowEncoder_n);
+    tmpPtr = outputDataPtr;
+    
+    // copy out the rest of the data
+    for(ii=1; ii<d_kcol; ii++) {        // ii starts at 1, b/c we already did 
idx=0
+        // copy systematic bits
+        for(jj=0; jj<d_krow; jj++) {
+            *outputDataPtr++ = (float)(*inputDataPtr++);
+        }
+        
+        // copy the encoded bits
+        memcpy(outputDataPtr, &rowEncodedBits[curRowInRowEncodedBits++][0], 
+               sizeof(float)*(rowEncoder_m*rowEncoder_n));
+        
+        outputDataPtr += (rowEncoder_m*rowEncoder_n);
+        tmpPtr = outputDataPtr;
+    }
+    
+    // copy the encoded cols
+    for(ii=0; ii<(colEncoder_m*colEncoder_n); ii++) {
+        // copy checks
+        for(jj=0; jj<d_krow; jj++) {
+            *outputDataPtr++ = colEncodedBits[jj][ii];
+        }
+        int kk = jj;
+        // copy checks on checks
+        for(jj=0; jj<(rowEncoder_m*rowEncoder_n); jj++) {
+            *outputDataPtr++ = colEncodedBits[kk++][ii];
+        }
+    }
+    
+    //DEBUG_PRINT("Output\n");
+    //DEBUG_PRINT_FLOAT_ARRAY_AS_UCHAR(out, outputSize);
+    //DEBUG_PRINT_F(fp, "Output\n");
+    //DEBUG_PRINT_FLOAT_ARRAY_AS_UCHAR_F(fp, out, outputSize);
+}
+
+
+tpc_encoder::~tpc_encoder()
+{
+    fclose(fp);
+}
+
+}
+}
diff --git a/gr-fec/swig/fec_swig.i b/gr-fec/swig/fec_swig.i
index 858c72d..abc78e3 100644
--- a/gr-fec/swig/fec_swig.i
+++ b/gr-fec/swig/fec_swig.i
@@ -60,6 +60,8 @@
 #include "gnuradio/fec/depuncture_bb.h"
 #include "gnuradio/fec/ldpc_encoder.h"
 #include "gnuradio/fec/ldpc_decoder.h"
+#include "gnuradio/fec/tpc_encoder.h"
+#include "gnuradio/fec/tpc_decoder.h"
 %}
 
 %include "gnuradio/fec/generic_decoder.h"
@@ -86,6 +88,8 @@
 %include "gnuradio/fec/depuncture_bb.h"
 %include "gnuradio/fec/ldpc_encoder.h"
 %include "gnuradio/fec/ldpc_decoder.h"
+%include "gnuradio/fec/tpc_encoder.h"
+%include "gnuradio/fec/tpc_decoder.h"
 
 GR_SWIG_BLOCK_MAGIC2(fec, decoder);
 GR_SWIG_BLOCK_MAGIC2(fec, encoder);



reply via email to

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