3 * Copyright 2007 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>
39 gr_ofdm_frame_sink::enter_search()
42 fprintf(stderr, "@ enter_search\n");
44 d_state = STATE_SYNC_SEARCH;
49 gr_ofdm_frame_sink::enter_have_sync()
52 fprintf(stderr, "@ enter_have_sync\n");
54 d_state = STATE_HAVE_SYNC;
56 // clear state of demapper
61 d_headerbytelen_cnt = 0;
66 fill(d_dfe.begin(), d_dfe.end(), gr_complex(1.0,0.0));
70 gr_ofdm_frame_sink::enter_have_header()
72 d_state = STATE_HAVE_HEADER;
74 // header consists of two 16-bit shorts in network byte order
75 // payload length is lower 12 bits
76 // whitener offset is upper 4 bits
77 d_packetlen = (d_header >> 16) & 0x0fff;
78 d_packet_whitener_offset = (d_header >> 28) & 0x000f;
82 fprintf(stderr, "@ enter_have_header (payload_len = %d) (offset = %d)\n",
83 d_packetlen, d_packet_whitener_offset);
87 unsigned char gr_ofdm_frame_sink::slicer(const gr_complex x)
89 unsigned int table_size = d_sym_value_out.size();
90 unsigned int min_index = 0;
91 float min_euclid_dist = norm(x - d_sym_position[0]);
92 float euclid_dist = 0;
94 for (unsigned int j = 1; j < table_size; j++){
95 euclid_dist = norm(x - d_sym_position[j]);
96 if (euclid_dist < min_euclid_dist){
97 min_euclid_dist = euclid_dist;
101 return d_sym_value_out[min_index];
104 unsigned int gr_ofdm_frame_sink::demapper(const gr_complex *in,
107 unsigned int i=0, bytes_produced=0;
110 carrier=gr_expj(d_phase);
112 gr_complex accum_error = 0.0;
113 while(i < d_occupied_carriers) {
115 d_partial_byte |= d_resid;
116 d_byte_offset += d_nresid;
121 while((d_byte_offset < 8) && (i < d_occupied_carriers)) {
122 gr_complex sigrot = in[i]*carrier*d_dfe[i];
124 if(d_derotated_output != NULL){
125 d_derotated_output[i] = sigrot;
128 unsigned char bits = slicer(sigrot);
130 gr_complex closest_sym = d_sym_position[bits];
132 accum_error += sigrot * conj(closest_sym);
134 // FIX THE FOLLOWING STATEMENT
135 if (norm(sigrot)> 0.001) d_dfe[i] += d_eq_gain*(closest_sym/sigrot-d_dfe[i]);
139 if((8 - d_byte_offset) >= d_nbits) {
140 d_partial_byte |= bits << (d_byte_offset);
141 d_byte_offset += d_nbits;
144 d_nresid = d_nbits-(8-d_byte_offset);
145 int mask = ((1<<(8-d_byte_offset))-1);
146 d_partial_byte |= (bits & mask) << d_byte_offset;
147 d_resid = bits >> (8-d_byte_offset);
148 d_byte_offset += (d_nbits - d_nresid);
150 //printf("demod symbol: %.4f + j%.4f bits: %x partial_byte: %x byte_offset: %d resid: %x nresid: %d\n",
151 // in[i-1].real(), in[i-1].imag(), bits, d_partial_byte, d_byte_offset, d_resid, d_nresid);
154 if(d_byte_offset == 8) {
155 //printf("demod byte: %x \n\n", d_partial_byte);
156 out[bytes_produced++] = d_partial_byte;
161 //std::cerr << "accum_error " << accum_error << std::endl;
163 float angle = arg(accum_error);
165 d_freq = d_freq - d_freq_gain*angle;
166 d_phase = d_phase + d_freq - d_phase_gain*angle;
167 if (d_phase >= 2*M_PI) d_phase -= 2*M_PI;
168 if (d_phase <0) d_phase += 2*M_PI;
171 // std::cerr << angle << "\t" << d_freq << "\t" << d_phase << "\t" << std::endl;
173 return bytes_produced;
177 gr_ofdm_frame_sink_sptr
178 gr_make_ofdm_frame_sink(const std::vector<gr_complex> &sym_position,
179 const std::vector<unsigned char> &sym_value_out,
180 gr_msg_queue_sptr target_queue, unsigned int occupied_carriers,
181 float phase_gain, float freq_gain)
183 return gr_ofdm_frame_sink_sptr(new gr_ofdm_frame_sink(sym_position, sym_value_out,
184 target_queue, occupied_carriers,
185 phase_gain, freq_gain));
189 gr_ofdm_frame_sink::gr_ofdm_frame_sink(const std::vector<gr_complex> &sym_position,
190 const std::vector<unsigned char> &sym_value_out,
191 gr_msg_queue_sptr target_queue, unsigned int occupied_carriers,
192 float phase_gain, float freq_gain)
193 : gr_sync_block ("ofdm_frame_sink",
194 gr_make_io_signature2 (2, 2, sizeof(gr_complex)*occupied_carriers, sizeof(char)),
195 gr_make_io_signature (1, 1, sizeof(gr_complex)*occupied_carriers)),
196 d_target_queue(target_queue), d_occupied_carriers(occupied_carriers),
197 d_byte_offset(0), d_partial_byte(0),
198 d_resid(0), d_nresid(0),d_phase(0),d_freq(0),d_phase_gain(phase_gain),d_freq_gain(freq_gain),
201 d_bytes_out = new unsigned char[d_occupied_carriers];
202 d_dfe.resize(occupied_carriers);
203 fill(d_dfe.begin(), d_dfe.end(), gr_complex(1.0,0.0));
205 set_sym_value_out(sym_position, sym_value_out);
210 gr_ofdm_frame_sink::~gr_ofdm_frame_sink ()
212 delete [] d_bytes_out;
216 gr_ofdm_frame_sink::set_sym_value_out(const std::vector<gr_complex> &sym_position,
217 const std::vector<unsigned char> &sym_value_out)
219 if (sym_position.size() != sym_value_out.size())
222 if (sym_position.size()<1)
225 d_sym_position = sym_position;
226 d_sym_value_out = sym_value_out;
227 d_nbits = (unsigned long)ceil(log10(d_sym_value_out.size()) / log10(2.0));
234 gr_ofdm_frame_sink::work (int noutput_items,
235 gr_vector_const_void_star &input_items,
236 gr_vector_void_star &output_items)
238 const gr_complex *in = (const gr_complex *) input_items[0];
239 const char *sig = (const char *) input_items[1];
241 unsigned int bytes=0;
243 // If the output is connected, send it the derotated symbols
244 if(output_items.size() >= 1)
245 d_derotated_output = (gr_complex *)output_items[0];
247 d_derotated_output = NULL;
250 fprintf(stderr,">>> Entering state machine\n");
254 case STATE_SYNC_SEARCH: // Look for flag indicating beginning of pkt
256 fprintf(stderr,"SYNC Search, noutput=%d\n", noutput_items);
258 if (sig[0]) { // Found it, set up for header decode
263 case STATE_HAVE_SYNC:
264 // only demod after getting the preamble signal; otherwise, the
265 // equalizer taps will screw with the PLL performance
266 bytes = demapper(&in[0], d_bytes_out);
270 printf("ERROR -- Found SYNC in HAVE_SYNC\n");
271 fprintf(stderr,"Header Search bitcnt=%d, header=0x%08x\n",
272 d_headerbytelen_cnt, d_header);
277 d_header = (d_header << 8) | (d_bytes_out[j] & 0xFF);
280 if (++d_headerbytelen_cnt == HEADERBYTELEN) {
283 fprintf(stderr, "got header: 0x%08x\n", d_header);
285 // we have a full header, check to see if it has been received properly
290 printf("\nPacket Length: %d\n", d_packetlen);
292 while((j < bytes) && (d_packetlen_cnt < d_packetlen)) {
293 d_packet[d_packetlen_cnt++] = d_bytes_out[j++];
296 if(d_packetlen_cnt == d_packetlen) {
297 gr_message_sptr msg =
298 gr_make_message(0, d_packet_whitener_offset, 0, d_packetlen);
299 memcpy(msg->msg(), d_packet, d_packetlen_cnt);
300 d_target_queue->insert_tail(msg); // send it
301 msg.reset(); // free it up
307 enter_search(); // bad header
313 case STATE_HAVE_HEADER:
314 bytes = demapper(&in[0], d_bytes_out);
318 printf("ERROR -- Found SYNC in HAVE_HEADER at %d, length of %d\n", d_packetlen_cnt, d_packetlen);
319 fprintf(stderr,"Packet Build\n");
324 d_packet[d_packetlen_cnt++] = d_bytes_out[j++];
326 if (d_packetlen_cnt == d_packetlen){ // packet is filled
328 // NOTE: passing header field as arg1 is not scalable
329 gr_message_sptr msg =
330 gr_make_message(0, d_packet_whitener_offset, 0, d_packetlen_cnt);
331 memcpy(msg->msg(), d_packet, d_packetlen_cnt);
333 d_target_queue->insert_tail(msg); // send it
334 msg.reset(); // free it up