Houston, we have a trunk.
[debian/gnuradio] / gr-error-correcting-codes / src / lib / libecc / encoder_convolutional.cc
1 /* -*- c++ -*- */
2 /*
3  * Copyright 2006 Free Software Foundation, Inc.
4  * 
5  * This file is part of GNU Radio
6  * 
7  * GNU Radio is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2, or (at your option)
10  * any later version.
11  * 
12  * GNU Radio is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  * 
17  * You should have received a copy of the GNU General Public License
18  * along with GNU Radio; see the file COPYING.  If not, write to
19  * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20  * Boston, MA 02111-1307, USA.
21  */
22
23 #ifdef HAVE_CONFIG_H
24 #include "config.h"
25 #endif
26
27 #include "encoder_convolutional.h"
28 #include <assert.h>
29 #include <iostream>
30
31 #define DO_TIME_THOUGHPUT 0
32 #define DO_PRINT_DEBUG 1
33
34 #include <mld/mld_timer.h>
35 #include <mld/n2bs.h>
36
37 static const int g_max_block_size_bits = 10000000;
38 static const int g_max_num_streams = 10;
39 static const int g_num_bits_per_byte = 8;
40
41 void encoder_convolutional::encoder_convolutional_init
42 (int block_size_bits,
43  int n_code_inputs,
44  int n_code_outputs,
45  const std::vector<int>& code_generators,
46  const std::vector<int>* code_feedback,
47  bool do_termination,
48  int start_memory_state,
49  int end_memory_state)
50 {
51   // error checking on the input arguments is done by the trellis class
52
53   if (code_feedback)
54     d_trellis = new code_convolutional_trellis
55       (block_size_bits,
56        n_code_inputs,
57        n_code_outputs,
58        code_generators,
59        *code_feedback,
60        do_termination,
61        end_memory_state);
62   else
63     d_trellis = new code_convolutional_trellis
64       (block_size_bits,
65        n_code_inputs,
66        n_code_outputs,
67        code_generators,
68        do_termination,
69        end_memory_state);
70
71   // set the initial FSM state to 'init'
72
73   d_fsm_state = fsm_enc_conv_init;
74
75   // create the class block variables
76
77   d_block_size_bits = block_size_bits;
78   d_n_code_inputs = n_code_inputs;
79   d_n_code_outputs = n_code_outputs;
80   d_do_streaming = d_trellis->do_streaming ();
81   d_do_termination = d_trellis->do_termination ();
82   d_total_n_delays = d_trellis->total_n_delays ();
83
84   // parse the init state
85
86   memory_t t_mask = (memory_t)((2 << d_total_n_delays) - 1);
87   size_t t_n_states = (1 << d_total_n_delays);
88
89   if (start_memory_state & t_mask) {
90     std::cout << "encoder_convolutional: Warning: " <<
91       "provided end memory state out (" << end_memory_state <<
92       ") is out of the state range [0, " <<
93       (t_n_states-1) << "]; masking off the unused bits.\n";
94
95     start_memory_state &= t_mask;
96   }
97
98   d_init_state = start_memory_state;
99
100   d_current_inputs.assign (d_n_code_inputs, 0);
101   d_current_outputs.assign (d_n_code_outputs, 0);
102 }
103
104 void
105 encoder_convolutional::encode_private
106 (const char** in_buf,
107  char** out_buf)
108 {
109   struct timeval t_tp;
110   if (DO_TIME_THOUGHPUT) {
111     start_timer (&t_tp);
112   }
113
114   // reset buffer indices
115
116   d_total_n_enc_bits = d_in_buf_ndx = d_out_buf_ndx =
117     d_in_bit_shift = d_out_bit_shift = 0;
118
119   if (DO_PRINT_DEBUG) {
120     std::cout << "Beginning this encode() call; starting parameters.\n";
121     std::cout << "d_n_input_bits_left = " << d_n_input_bits_left << '\n';
122     std::cout << "d_n_output_bits_left = " << d_n_output_bits_left << '\n';
123   }
124
125   // while there are inputs and outputs left to process ...
126
127   while ((d_n_input_bits_left != 0) & (d_n_output_bits_left != 0)) {
128
129     // jump to the correct state in the fsm
130
131     switch (d_fsm_state) {
132
133     case fsm_enc_conv_init:
134
135       // copy the init states to the current memory
136
137       d_memory = d_init_state;
138
139       // if not doing streaming, things to do; else nothing more do
140
141       if (d_do_streaming == false) {
142
143         // reset the number of encoded bits in this block (which is
144         // used to compare with the number of bits in the block)
145
146         d_n_enc_bits = 0;
147       }
148
149       // move to the 'input' state
150
151       d_fsm_state = fsm_enc_conv_doing_input;
152       break;
153
154     case fsm_enc_conv_doing_input:
155
156       // working through the trellis section which requires input bits
157       // from external sources; loop up to the block size (before
158       // termination bits, if any), counting down the number of
159       // available input bits.
160
161       encode_loop (in_buf, out_buf, &d_n_input_bits_left, d_block_size_bits);
162
163       // finished this loop; check for jumping to the next state
164
165       if ((d_n_enc_bits == d_block_size_bits) & (d_do_streaming == false)) {
166
167         // jump to another state, depending on termination requirement
168
169         if (d_do_termination == true) {
170           d_n_enc_bits = 0;
171           d_fsm_state = fsm_enc_conv_doing_term;
172         } else {
173           d_fsm_state = fsm_enc_conv_init;
174         }
175       }
176       break;
177
178     case fsm_enc_conv_doing_term:
179
180       // terminating the trellis, trying to get to a specific state;
181       // better get here only when do_termination is true, but check
182       // just in case; lop up to the max memory, counting down the
183       // number of output bits left
184
185       if (d_do_termination == true) {
186         encode_loop (in_buf, out_buf, &d_n_output_bits_left, d_total_n_delays);
187
188         // finished this loop; check for jumping to the next state
189
190         if (d_n_enc_bits == d_total_n_delays)
191           d_fsm_state = fsm_enc_conv_init;
192
193       } else {
194         // should never get here!
195         assert (0);
196       }
197       break;
198
199     default:
200       // better never get here!
201       assert (0);
202       break;
203
204       // done (switch) with FSM
205     }
206
207     // done (while) there are inputs and outputs
208   }
209
210   if (DO_PRINT_DEBUG) {
211     std::cout << "Done with this encode() call; ending parameters.\n"
212       "d_in_bit_shift = " << d_in_bit_shift << "\n"
213       "d_out_bit_shift = " << d_out_bit_shift << "\n"
214       "d_in_buf_ndx = " << d_in_buf_ndx << "\n"
215       "d_out_buf_ndx = " << d_out_buf_ndx << "\n"
216       "d_n_input_bits_left = " << d_n_input_bits_left << "\n"
217       "d_n_output_bits_left = " << d_n_output_bits_left << "\n"
218       "d_total_n_enc_bits = " << d_total_n_enc_bits << "\n";
219   }
220
221   if (DO_TIME_THOUGHPUT) {
222     // compute the throughput for this particular function call
223     u_long d_t = end_timer (&t_tp);
224     std::cout << "Completed " << d_total_n_enc_bits <<
225       " bits in " << d_t << " usec => " <<
226       1e6*(((double) d_total_n_enc_bits)/((double) d_t)) <<
227       " b/s\n";
228   }
229 }
230
231 void
232 encoder_convolutional::encode_loop
233 (const char** in_buf,
234  char** out_buf,
235  size_t* which_counter,
236  size_t how_many)
237 {
238   // generic encode_loop
239
240   if (DO_PRINT_DEBUG) {
241     std::cout << "Starting encode_loop.\n";
242   }
243
244   while (((*which_counter) > 0) & (d_n_enc_bits < how_many)) {
245     if (DO_PRINT_DEBUG) {
246       std::cout << "*w_c = " << (*which_counter) << ", "
247         "# enc_bits = " << d_n_enc_bits << " of " << how_many << ".\n"
248         "Getting new inputs.\n";
249     }
250
251     // get the next set of input bits from all streams;
252     // written into d_current_inputs
253
254     get_next_inputs (in_buf);
255
256     // use the trellis to do the encoding;
257     // updates the input memory to the new memory state for the given input
258     // and writes the output bits to the current_outputs
259
260     d_trellis->encode_lookup (d_memory, d_current_inputs, d_current_outputs);
261
262     // write the bits in d_current_outputs into the output buffer
263
264     write_output_bits (out_buf);
265
266     // increment the number of encoded bits for the current block, and
267     // the total number of bits for this running of "encode()"
268
269     d_n_enc_bits++;
270     d_total_n_enc_bits++;
271   }
272
273   if (DO_PRINT_DEBUG) {
274     std::cout << "ending encode_loop.\n";
275   }
276 }
277
278 void
279 encoder_convolutional::get_next_inputs__term
280 ()
281 {
282   // FIXME: how to figure out which term bit to get?
283   // loop to set each entry of "d_current_inputs"
284
285   // need to do feedback separately, since it involves determining the
286   // FB bit value & using that as the input value to cancel it out
287
288   d_current_inputs.assign (d_n_code_inputs, 0);
289   //   return (d_term_states[code_input_n] & 1);
290 }