Imported Upstream version 3.2.2
[debian/gnuradio] / gnuradio-core / src / lib / general / gr_ofdm_mapper_bcv.cc
1 /* -*- c++ -*- */
2 /*
3  * Copyright 2006,2007,2008 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 3, 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., 51 Franklin Street,
20  * Boston, MA 02110-1301, USA.
21  */
22
23
24 #ifdef HAVE_CONFIG_H
25 #include "config.h"
26 #endif
27
28 #include <gr_ofdm_mapper_bcv.h>
29 #include <gr_io_signature.h>
30 #include <stdexcept>
31 #include <string.h>
32
33 gr_ofdm_mapper_bcv_sptr
34 gr_make_ofdm_mapper_bcv (const std::vector<gr_complex> &constellation, unsigned int msgq_limit, 
35                          unsigned int occupied_carriers, unsigned int fft_length)
36 {
37   return gr_ofdm_mapper_bcv_sptr (new gr_ofdm_mapper_bcv (constellation, msgq_limit, 
38                                                           occupied_carriers, fft_length));
39 }
40
41 // Consumes 1 packet and produces as many OFDM symbols of fft_length to hold the full packet
42 gr_ofdm_mapper_bcv::gr_ofdm_mapper_bcv (const std::vector<gr_complex> &constellation, unsigned int msgq_limit, 
43                                         unsigned int occupied_carriers, unsigned int fft_length)
44   : gr_sync_block ("ofdm_mapper_bcv",
45                    gr_make_io_signature (0, 0, 0),
46                    gr_make_io_signature2 (1, 2, sizeof(gr_complex)*fft_length, sizeof(char))),
47     d_constellation(constellation),
48     d_msgq(gr_make_msg_queue(msgq_limit)), d_msg_offset(0), d_eof(false),
49     d_occupied_carriers(occupied_carriers),
50     d_fft_length(fft_length),
51     d_bit_offset(0),
52     d_pending_flag(0),
53     d_resid(0),
54     d_nresid(0)
55 {
56   if (!(d_occupied_carriers <= d_fft_length))
57     throw std::invalid_argument("gr_ofdm_mapper_bcv: occupied carriers must be <= fft_length");
58
59   // this is not the final form of this solution since we still use the occupied_tones concept,
60   // which would get us into trouble if the number of carriers we seek is greater than the occupied carriers.
61   // Eventually, we will get rid of the occupied_carriers concept.
62   std::string carriers = "FE7F";
63
64   // A bit hacky to fill out carriers to occupied_carriers length
65   int diff = (d_occupied_carriers - 4*carriers.length()); 
66   while(diff > 7) {
67     carriers.insert(0, "f");
68     carriers.insert(carriers.length(), "f");
69     diff -= 8;
70   }
71
72   // if there's extras left to be processed
73   // divide remaining to put on either side of current map
74   // all of this is done to stick with the concept of a carrier map string that
75   // can be later passed by the user, even though it'd be cleaner to just do this
76   // on the carrier map itself
77   int diff_left=0;
78   int diff_right=0;
79
80   // dictionary to convert from integers to ascii hex representation
81   char abc[16] = {'0', '1', '2', '3', '4', '5', '6', '7', 
82                   '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
83   if(diff > 0) {
84     char c[2] = {0,0};
85
86     diff_left = (int)ceil((float)diff/2.0f);   // number of carriers to put on the left side
87     c[0] = abc[(1 << diff_left) - 1];          // convert to bits and move to ASCI integer
88     carriers.insert(0, c);
89     
90     diff_right = diff - diff_left;             // number of carriers to put on the right side
91     c[0] = abc[0xF^((1 << diff_right) - 1)];   // convert to bits and move to ASCI integer
92         carriers.insert(carriers.length(), c);
93   }
94   
95   // find out how many zeros to pad on the sides; the difference between the fft length and the subcarrier
96   // mapping size in chunks of four. This is the number to pack on the left and this number plus any 
97   // residual nulls (if odd) will be packed on the right. 
98   diff = (d_fft_length/4 - carriers.length())/2; 
99
100   unsigned int i,j,k;
101   for(i = 0; i < carriers.length(); i++) {
102     char c = carriers[i];                            // get the current hex character from the string
103     for(j = 0; j < 4; j++) {                         // walk through all four bits
104       k = (strtol(&c, NULL, 16) >> (3-j)) & 0x1;     // convert to int and extract next bit
105       if(k) {                                        // if bit is a 1, 
106         d_subcarrier_map.push_back(4*(i+diff) + j);  // use this subcarrier
107       }
108     }
109   }
110
111   // make sure we stay in the limit currently imposed by the occupied_carriers
112   if(d_subcarrier_map.size() > d_occupied_carriers) {
113     throw std::invalid_argument("gr_ofdm_mapper_bcv: subcarriers allocated exceeds size of occupied carriers");
114   }
115   
116   d_nbits = (unsigned long)ceil(log10(d_constellation.size()) / log10(2.0));
117 }
118
119 gr_ofdm_mapper_bcv::~gr_ofdm_mapper_bcv(void)
120 {
121 }
122
123 int gr_ofdm_mapper_bcv::randsym()
124 {
125   return (rand() % d_constellation.size());
126 }
127
128 int
129 gr_ofdm_mapper_bcv::work(int noutput_items,
130                           gr_vector_const_void_star &input_items,
131                           gr_vector_void_star &output_items)
132 {
133   gr_complex *out = (gr_complex *)output_items[0];
134   
135   unsigned int i=0;
136
137   //printf("OFDM BPSK Mapper:  ninput_items: %d   noutput_items: %d\n", ninput_items[0], noutput_items);
138
139   if(d_eof) {
140     return -1;
141   }
142   
143   if(!d_msg) {
144     d_msg = d_msgq->delete_head();         // block, waiting for a message
145     d_msg_offset = 0;
146     d_bit_offset = 0;
147     d_pending_flag = 1;                    // new packet, write start of packet flag
148     
149     if((d_msg->length() == 0) && (d_msg->type() == 1)) {
150       d_msg.reset();
151       return -1;                // We're done; no more messages coming.
152     }
153   }
154
155   char *out_flag = 0;
156   if(output_items.size() == 2)
157     out_flag = (char *) output_items[1];
158   
159
160   // Build a single symbol:
161   // Initialize all bins to 0 to set unused carriers
162   memset(out, 0, d_fft_length*sizeof(gr_complex));
163   
164   i = 0;
165   unsigned char bits = 0;
166   //while((d_msg_offset < d_msg->length()) && (i < d_occupied_carriers)) {
167   while((d_msg_offset < d_msg->length()) && (i < d_subcarrier_map.size())) {
168
169     // need new data to process
170     if(d_bit_offset == 0) {
171       d_msgbytes = d_msg->msg()[d_msg_offset];
172       //printf("mod message byte: %x\n", d_msgbytes);
173     }
174
175     if(d_nresid > 0) {
176       // take the residual bits, fill out nbits with info from the new byte, and put them in the symbol
177       d_resid |= (((1 << d_nresid)-1) & d_msgbytes) << (d_nbits - d_nresid);
178       bits = d_resid;
179
180       out[d_subcarrier_map[i]] = d_constellation[bits];
181       i++;
182
183       d_bit_offset += d_nresid;
184       d_nresid = 0;
185       d_resid = 0;
186       //printf("mod bit(r): %x   resid: %x   nresid: %d    bit_offset: %d\n", 
187       //     bits, d_resid, d_nresid, d_bit_offset);
188     }
189     else {
190       if((8 - d_bit_offset) >= d_nbits) {  // test to make sure we can fit nbits
191         // take the nbits number of bits at a time from the byte to add to the symbol
192         bits = ((1 << d_nbits)-1) & (d_msgbytes >> d_bit_offset);
193         d_bit_offset += d_nbits;
194         
195         out[d_subcarrier_map[i]] = d_constellation[bits];
196         i++;
197       }
198       else {  // if we can't fit nbits, store them for the next 
199         // saves d_nresid bits of this message where d_nresid < d_nbits
200         unsigned int extra = 8-d_bit_offset;
201         d_resid = ((1 << extra)-1) & (d_msgbytes >> d_bit_offset);
202         d_bit_offset += extra;
203         d_nresid = d_nbits - extra;
204       }
205       
206     }
207             
208     if(d_bit_offset == 8) {
209       d_bit_offset = 0;
210       d_msg_offset++;
211     }
212   }
213
214   // Ran out of data to put in symbol
215   if (d_msg_offset == d_msg->length()) {
216     if(d_nresid > 0) {
217       d_resid |= 0x00;
218       bits = d_resid;
219       d_nresid = 0;
220       d_resid = 0;
221     }
222
223     //while(i < d_occupied_carriers) {   // finish filling out the symbol
224     while(i < d_subcarrier_map.size()) {   // finish filling out the symbol
225       out[d_subcarrier_map[i]] = d_constellation[randsym()];
226
227       i++;
228     }
229
230     if (d_msg->type() == 1)             // type == 1 sets EOF
231       d_eof = true;
232     d_msg.reset();                      // finished packet, free message
233     assert(d_bit_offset == 0);
234   }
235
236   if (out_flag)
237     out_flag[0] = d_pending_flag;
238   d_pending_flag = 0;
239
240   return 1;  // produced symbol
241 }