Houston, we have a trunk.
[debian/gnuradio] / gr-error-correcting-codes / src / lib / gr_streams_encode_turbo.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 <gr_streams_encode_turbo.h>
28 #include <gr_io_signature.h>
29 #include <assert.h>
30 #include <iostream>
31
32 gr_streams_encode_turbo_sptr 
33 gr_make_streams_encode_turbo
34 (int n_code_inputs,
35  int n_code_outputs,
36  const std::vector<gr_streams_encode_convolutional_sptr> &encoders,
37  const std::vector<size_t> &interleavers)
38 {
39   return gr_streams_encode_turbo_sptr
40     (new gr_streams_encode_turbo (n_code_inputs,
41                                   n_code_outputs,
42                                   encoders,
43                                   interleavers));
44 }
45
46 gr_streams_encode_turbo::gr_streams_encode_turbo
47 (int n_code_inputs,
48  int n_code_outputs,
49  const std::vector<gr_streams_encode_convolutional_sptr> &encoders,
50  const std::vector<size_t> &interleavers)
51   : gr_block ("streams_encode_turbo",
52               gr_make_io_signature (0, 0, 0),
53               gr_make_io_signature (0, 0, 0))
54 {
55   // error checking is done by the encoder class itself;
56   // just pass items on here.
57
58   // check out individual encoders, to make sure the total input /
59   // output matches those specified by the user.
60
61   d_n_encoders = encoders.size ();
62
63   if (d_n_encoders < 2) {
64     std::cerr << "gr_streams_encode_turbo: Error: "
65       "too few (" << d_n_encoders << ") encoders specified; a Turbo "
66       "code requires at least 2 constituent encoders.\n";
67     assert (0);
68   }
69
70   // make sure that the block size and termination are consistent for
71   // all encoders; warn the user if not, since it doesn't really
72   // matter to the encoder (but it might to the decoder; remains to be
73   // seen).
74
75   encoder_convolutional_ic1_ic1* t_ec = encoders[0]->encoder ();
76   d_block_size_bits = t_ec->block_size_bits ();
77   d_do_termination = t_ec->do_termination ();
78   bool t_diff_block_size, t_diff_termination;
79   t_diff_block_size = t_diff_termination = false;
80
81   for (size_t m = 1; m < d_n_encoders; m++) {
82     t_ec = encoders[0]->encoder ();
83     size_t t_block_size_bits = t_ec->block_size_bits ();
84     if (t_block_size_bits != d_block_size_bits)
85       t_diff_block_size = true;
86     bool t_do_termination = t_ec->do_termination ();
87     if (t_do_termination != d_do_termination)
88       t_do_termination = true;
89   }
90
91   if (t_diff_block_size == true) {
92     std::cout << "gr_streams_encode_turbo: Warning: "
93       "Some constituent encoders have different block size (bits).\n";
94   }
95   if (t_diff_termination == true) {
96     std::cout << "gr_streams_encode_turbo: Warning: "
97       "Some constituent encoders are differently terminationed.\n";
98   }
99
100   std::cout << "gr_streams_encode_turbo: setup:\n"
101     "d_n_encoders = " << d_n_encoders << "\n"
102     "n_code_inputs = " << n_code_inputs << "\n"
103     "n_code_outputs = " << n_code_outputs << "\n\n"
104     "Individual Encoders:\n";
105
106   for (size_t m = 0; m < d_n_encoders; m++) {
107     t_ec = encoders[m]->encoder ();
108     std::cout << "  [" << (m+1) << "]:\n"
109       "n_code_inputs = " << (t_ec->n_code_inputs()) << "\n"
110       "n_code_outputs = " << (t_ec->n_code_outputs()) << "\n"
111       "block_size_bits = " << (t_ec->block_size_bits()) << "\n"
112       "do_termination = " <<
113       ((t_ec->do_termination()==true)?"true":"false") << "\n";
114   }
115
116 #if 1
117   assert (0);
118 #else
119   if (d_n_encoders != (interleavers.size())) {}
120
121   d_encoder = new encoder_turbo_ic1_ic1 (n_code_inputs,
122                                          n_code_outputs,
123                                          code_generators,
124                                          do_termination,
125                                          start_memory_state,
126                                          end_memory_state);
127 #endif
128
129   // create the correct input signature; 1 bit per input char
130
131   set_input_signature (gr_make_io_signature (n_code_inputs,
132                                              n_code_inputs,
133                                              sizeof (char)));
134
135   // create the correct output signature; 1 bit per output char
136
137   set_output_signature (gr_make_io_signature (n_code_outputs,
138                                               n_code_outputs,
139                                               sizeof (char)));
140
141 // set the output multiple to 1 item, then let the encoder class
142 // handle the rest internally
143
144   set_output_multiple (1);
145 }
146
147 gr_streams_encode_turbo::~gr_streams_encode_turbo
148 ()
149 {
150   if (d_encoder)
151     delete d_encoder;
152 }
153
154 /*
155  * Compute the number of input bits (items in this case, since each
156  * item has 1 bit in it) needed to produce 'n_output' bits (items in
157  * this case, since each item has 1 bit in it).
158  *
159  * For turbo encoders, there is 1 bit output per bit input per
160  * stream, with the addition of a some bits for trellis termination if
161  * selected.  Thus the input:output bit ratio will be:
162  * 
163  * if (streaming | no termination), 1:1
164  *
165  * if (not streaming & termination), roughly 1:(1+X), where "X" is the
166  * total memory size of the code divided by the block length in bits.
167  * But this also depends on the state of the FSM ... how many bits are
168  * left before termination.
169  */
170
171 void gr_streams_encode_turbo::forecast
172 (int noutput_items,
173  gr_vector_int &ninput_items_required)
174 {
175   int ninput_items = d_encoder->compute_n_input_bits (noutput_items);
176   size_t ninputs = ninput_items_required.size();
177   for (size_t n = 0; n < ninputs; n++)
178     ninput_items_required[n] = ninput_items;
179 }
180
181 int
182 gr_streams_encode_turbo::general_work
183 (int noutput_items,
184  gr_vector_int &ninput_items,
185  gr_vector_const_void_star &input_items,
186  gr_vector_void_star &output_items)
187 {
188   // FIXME: compute the actual number of output items (1 bit char's) created.
189
190   size_t t_n_input_items = d_encoder->compute_n_input_bits (noutput_items);
191   size_t t_n_output_items = d_encoder->compute_n_output_bits (t_n_input_items);
192
193   assert (t_n_output_items == ((size_t)noutput_items));
194
195   // "work" is handled by the encoder; which returns the actual number
196   // of input items (1-bit char's) used.
197
198   t_n_input_items = d_encoder->encode ((const char **)(&input_items[0]), 
199                                        (char **)(&output_items[0]),
200                                        (size_t) noutput_items);
201
202   // consume the number of used input items on all input streams
203
204   consume_each (t_n_input_items);
205
206   // returns number of items written to each output stream
207
208   return (noutput_items);
209 }