3 * Copyright 2007,2008 Free Software Foundation, Inc.
5 * This file is part of GNU Radio
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)
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.
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.
27 #include <gr_ofdm_frame_sink.h>
28 #include <gr_io_signature.h>
40 gr_ofdm_frame_sink::enter_search()
43 fprintf(stderr, "@ enter_search\n");
45 d_state = STATE_SYNC_SEARCH;
50 gr_ofdm_frame_sink::enter_have_sync()
53 fprintf(stderr, "@ enter_have_sync\n");
55 d_state = STATE_HAVE_SYNC;
57 // clear state of demapper
62 d_headerbytelen_cnt = 0;
67 fill(d_dfe.begin(), d_dfe.end(), gr_complex(1.0,0.0));
71 gr_ofdm_frame_sink::enter_have_header()
73 d_state = STATE_HAVE_HEADER;
75 // header consists of two 16-bit shorts in network byte order
76 // payload length is lower 12 bits
77 // whitener offset is upper 4 bits
78 d_packetlen = (d_header >> 16) & 0x0fff;
79 d_packet_whitener_offset = (d_header >> 28) & 0x000f;
83 fprintf(stderr, "@ enter_have_header (payload_len = %d) (offset = %d)\n",
84 d_packetlen, d_packet_whitener_offset);
88 unsigned char gr_ofdm_frame_sink::slicer(const gr_complex x)
90 unsigned int table_size = d_sym_value_out.size();
91 unsigned int min_index = 0;
92 float min_euclid_dist = norm(x - d_sym_position[0]);
93 float euclid_dist = 0;
95 for (unsigned int j = 1; j < table_size; j++){
96 euclid_dist = norm(x - d_sym_position[j]);
97 if (euclid_dist < min_euclid_dist){
98 min_euclid_dist = euclid_dist;
102 return d_sym_value_out[min_index];
105 unsigned int gr_ofdm_frame_sink::demapper(const gr_complex *in,
108 unsigned int i=0, bytes_produced=0;
111 carrier=gr_expj(d_phase);
113 gr_complex accum_error = 0.0;
114 //while(i < d_occupied_carriers) {
115 while(i < d_subcarrier_map.size()) {
117 d_partial_byte |= d_resid;
118 d_byte_offset += d_nresid;
123 //while((d_byte_offset < 8) && (i < d_occupied_carriers)) {
124 while((d_byte_offset < 8) && (i < d_subcarrier_map.size())) {
125 //gr_complex sigrot = in[i]*carrier*d_dfe[i];
126 gr_complex sigrot = in[d_subcarrier_map[i]]*carrier*d_dfe[i];
128 if(d_derotated_output != NULL){
129 d_derotated_output[i] = sigrot;
132 unsigned char bits = slicer(sigrot);
134 gr_complex closest_sym = d_sym_position[bits];
136 accum_error += sigrot * conj(closest_sym);
138 // FIX THE FOLLOWING STATEMENT
139 if (norm(sigrot)> 0.001) d_dfe[i] += d_eq_gain*(closest_sym/sigrot-d_dfe[i]);
143 if((8 - d_byte_offset) >= d_nbits) {
144 d_partial_byte |= bits << (d_byte_offset);
145 d_byte_offset += d_nbits;
148 d_nresid = d_nbits-(8-d_byte_offset);
149 int mask = ((1<<(8-d_byte_offset))-1);
150 d_partial_byte |= (bits & mask) << d_byte_offset;
151 d_resid = bits >> (8-d_byte_offset);
152 d_byte_offset += (d_nbits - d_nresid);
154 //printf("demod symbol: %.4f + j%.4f bits: %x partial_byte: %x byte_offset: %d resid: %x nresid: %d\n",
155 // in[i-1].real(), in[i-1].imag(), bits, d_partial_byte, d_byte_offset, d_resid, d_nresid);
158 if(d_byte_offset == 8) {
159 //printf("demod byte: %x \n\n", d_partial_byte);
160 out[bytes_produced++] = d_partial_byte;
165 //std::cerr << "accum_error " << accum_error << std::endl;
167 float angle = arg(accum_error);
169 d_freq = d_freq - d_freq_gain*angle;
170 d_phase = d_phase + d_freq - d_phase_gain*angle;
171 if (d_phase >= 2*M_PI) d_phase -= 2*M_PI;
172 if (d_phase <0) d_phase += 2*M_PI;
175 // std::cerr << angle << "\t" << d_freq << "\t" << d_phase << "\t" << std::endl;
177 return bytes_produced;
181 gr_ofdm_frame_sink_sptr
182 gr_make_ofdm_frame_sink(const std::vector<gr_complex> &sym_position,
183 const std::vector<unsigned char> &sym_value_out,
184 gr_msg_queue_sptr target_queue, unsigned int occupied_carriers,
185 float phase_gain, float freq_gain)
187 return gr_ofdm_frame_sink_sptr(new gr_ofdm_frame_sink(sym_position, sym_value_out,
188 target_queue, occupied_carriers,
189 phase_gain, freq_gain));
193 gr_ofdm_frame_sink::gr_ofdm_frame_sink(const std::vector<gr_complex> &sym_position,
194 const std::vector<unsigned char> &sym_value_out,
195 gr_msg_queue_sptr target_queue, unsigned int occupied_carriers,
196 float phase_gain, float freq_gain)
197 : gr_sync_block ("ofdm_frame_sink",
198 gr_make_io_signature2 (2, 2, sizeof(gr_complex)*occupied_carriers, sizeof(char)),
199 gr_make_io_signature (1, 1, sizeof(gr_complex)*occupied_carriers)),
200 d_target_queue(target_queue), d_occupied_carriers(occupied_carriers),
201 d_byte_offset(0), d_partial_byte(0),
202 d_resid(0), d_nresid(0),d_phase(0),d_freq(0),d_phase_gain(phase_gain),d_freq_gain(freq_gain),
205 std::string carriers = "FE7F";
207 // A bit hacky to fill out carriers to occupied_carriers length
208 int diff = (d_occupied_carriers - 4*carriers.length());
210 carriers.insert(0, "f");
211 carriers.insert(carriers.length(), "f");
215 // if there's extras left to be processed
216 // divide remaining to put on either side of current map
217 // all of this is done to stick with the concept of a carrier map string that
218 // can be later passed by the user, even though it'd be cleaner to just do this
219 // on the carrier map itself
223 // dictionary to convert from integers to ascii hex representation
224 char abc[16] = {'0', '1', '2', '3', '4', '5', '6', '7',
225 '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
229 diff_left = (int)ceil((float)diff/2.0f); // number of carriers to put on the left side
230 c[0] = abc[(1 << diff_left) - 1]; // convert to bits and move to ASCI integer
231 carriers.insert(0, c);
233 diff_right = diff - diff_left; // number of carriers to put on the right side
234 c[0] = abc[0xF^((1 << diff_right) - 1)]; // convert to bits and move to ASCI integer
235 carriers.insert(carriers.length(), c);
238 // It seemed like such a good idea at the time...
239 // because we are only dealing with the occupied_carriers
240 // at this point, the diff_left in the following compensates
241 // for any offset from the 0th carrier introduced
243 for(i = 0; i < (d_occupied_carriers/4)+diff_left; i++) {
244 char c = carriers[i];
245 for(j = 0; j < 4; j++) {
246 k = (strtol(&c, NULL, 16) >> (3-j)) & 0x1;
248 d_subcarrier_map.push_back(4*i + j - diff_left);
253 // make sure we stay in the limit currently imposed by the occupied_carriers
254 if(d_subcarrier_map.size() > d_occupied_carriers) {
255 throw std::invalid_argument("gr_ofdm_mapper_bcv: subcarriers allocated exceeds size of occupied carriers");
258 d_bytes_out = new unsigned char[d_occupied_carriers];
259 d_dfe.resize(occupied_carriers);
260 fill(d_dfe.begin(), d_dfe.end(), gr_complex(1.0,0.0));
262 set_sym_value_out(sym_position, sym_value_out);
267 gr_ofdm_frame_sink::~gr_ofdm_frame_sink ()
269 delete [] d_bytes_out;
273 gr_ofdm_frame_sink::set_sym_value_out(const std::vector<gr_complex> &sym_position,
274 const std::vector<unsigned char> &sym_value_out)
276 if (sym_position.size() != sym_value_out.size())
279 if (sym_position.size()<1)
282 d_sym_position = sym_position;
283 d_sym_value_out = sym_value_out;
284 d_nbits = (unsigned long)ceil(log10(d_sym_value_out.size()) / log10(2.0));
291 gr_ofdm_frame_sink::work (int noutput_items,
292 gr_vector_const_void_star &input_items,
293 gr_vector_void_star &output_items)
295 const gr_complex *in = (const gr_complex *) input_items[0];
296 const char *sig = (const char *) input_items[1];
298 unsigned int bytes=0;
300 // If the output is connected, send it the derotated symbols
301 if(output_items.size() >= 1)
302 d_derotated_output = (gr_complex *)output_items[0];
304 d_derotated_output = NULL;
307 fprintf(stderr,">>> Entering state machine\n");
311 case STATE_SYNC_SEARCH: // Look for flag indicating beginning of pkt
313 fprintf(stderr,"SYNC Search, noutput=%d\n", noutput_items);
315 if (sig[0]) { // Found it, set up for header decode
320 case STATE_HAVE_SYNC:
321 // only demod after getting the preamble signal; otherwise, the
322 // equalizer taps will screw with the PLL performance
323 bytes = demapper(&in[0], d_bytes_out);
327 printf("ERROR -- Found SYNC in HAVE_SYNC\n");
328 fprintf(stderr,"Header Search bitcnt=%d, header=0x%08x\n",
329 d_headerbytelen_cnt, d_header);
334 d_header = (d_header << 8) | (d_bytes_out[j] & 0xFF);
337 if (++d_headerbytelen_cnt == HEADERBYTELEN) {
340 fprintf(stderr, "got header: 0x%08x\n", d_header);
342 // we have a full header, check to see if it has been received properly
347 printf("\nPacket Length: %d\n", d_packetlen);
349 while((j < bytes) && (d_packetlen_cnt < d_packetlen)) {
350 d_packet[d_packetlen_cnt++] = d_bytes_out[j++];
353 if(d_packetlen_cnt == d_packetlen) {
354 gr_message_sptr msg =
355 gr_make_message(0, d_packet_whitener_offset, 0, d_packetlen);
356 memcpy(msg->msg(), d_packet, d_packetlen_cnt);
357 d_target_queue->insert_tail(msg); // send it
358 msg.reset(); // free it up
364 enter_search(); // bad header
370 case STATE_HAVE_HEADER:
371 bytes = demapper(&in[0], d_bytes_out);
375 printf("ERROR -- Found SYNC in HAVE_HEADER at %d, length of %d\n", d_packetlen_cnt, d_packetlen);
376 fprintf(stderr,"Packet Build\n");
381 d_packet[d_packetlen_cnt++] = d_bytes_out[j++];
383 if (d_packetlen_cnt == d_packetlen){ // packet is filled
385 // NOTE: passing header field as arg1 is not scalable
386 gr_message_sptr msg =
387 gr_make_message(0, d_packet_whitener_offset, 0, d_packetlen_cnt);
388 memcpy(msg->msg(), d_packet, d_packetlen_cnt);
390 d_target_queue->insert_tail(msg); // send it
391 msg.reset(); // free it up