Statistics
| Branch: | Tag: | Revision:

root / gnuradio-core / src / lib / general / gr_ofdm_frame_sink.cc @ c96ea672

History | View | Annotate | Download (11.4 kB)

1
/* -*- c++ -*- */
2
/*
3
 * Copyright 2007,2008,2010 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
#ifdef HAVE_CONFIG_H
24
#include "config.h"
25
#endif
26
27
#include <gr_ofdm_frame_sink.h>
28
#include <gr_io_signature.h>
29
#include <gr_expj.h>
30
#include <gr_math.h>
31
#include <math.h>
32
#include <cstdio>
33
#include <stdexcept>
34
#include <iostream>
35
#include <string.h>
36
37
#define VERBOSE 0
38
39
inline void
40
gr_ofdm_frame_sink::enter_search()
41
{
42
  if (VERBOSE)
43
    fprintf(stderr, "@ enter_search\n");
44
45
  d_state = STATE_SYNC_SEARCH;
46
47
}
48
    
49
inline void
50
gr_ofdm_frame_sink::enter_have_sync()
51
{
52
  if (VERBOSE)
53
    fprintf(stderr, "@ enter_have_sync\n");
54
55
  d_state = STATE_HAVE_SYNC;
56
57
  // clear state of demapper
58
  d_byte_offset = 0;
59
  d_partial_byte = 0;
60
61
  d_header = 0;
62
  d_headerbytelen_cnt = 0;
63
64
  // Resetting PLL
65
  d_freq = 0.0;
66
  d_phase = 0.0;
67
  fill(d_dfe.begin(), d_dfe.end(), gr_complex(1.0,0.0));
68
}
69
70
inline void
71
gr_ofdm_frame_sink::enter_have_header()
72
{
73
  d_state = STATE_HAVE_HEADER;
74
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;
80
  d_packetlen_cnt = 0;
81
82
  if (VERBOSE)
83
    fprintf(stderr, "@ enter_have_header (payload_len = %d) (offset = %d)\n", 
84
            d_packetlen, d_packet_whitener_offset);
85
}
86
87
88
unsigned char gr_ofdm_frame_sink::slicer(const gr_complex x)
89
{
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;
94
  
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;
99
      min_index = j;
100
    }
101
  }
102
  return d_sym_value_out[min_index];
103
}
104
105
unsigned int gr_ofdm_frame_sink::demapper(const gr_complex *in,
106
                                          unsigned char *out)
107
{
108
  unsigned int i=0, bytes_produced=0;
109
  gr_complex carrier;
110
111
  carrier=gr_expj(d_phase);
112
113
  gr_complex accum_error = 0.0;
114
  //while(i < d_occupied_carriers) {
115
  while(i < d_subcarrier_map.size()) {
116
    if(d_nresid > 0) {
117
      d_partial_byte |= d_resid;
118
      d_byte_offset += d_nresid;
119
      d_nresid = 0;
120
      d_resid = 0;
121
    }
122
    
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];
127
      
128
      if(d_derotated_output != NULL){
129
        d_derotated_output[i] = sigrot;
130
      }
131
      
132
      unsigned char bits = slicer(sigrot);
133
134
      gr_complex closest_sym = d_sym_position[bits];
135
      
136
      accum_error += sigrot * conj(closest_sym);
137
138
      // FIX THE FOLLOWING STATEMENT
139
      if (norm(sigrot)> 0.001) d_dfe[i] +=  d_eq_gain*(closest_sym/sigrot-d_dfe[i]);
140
      
141
      i++;
142
143
      if((8 - d_byte_offset) >= d_nbits) {
144
        d_partial_byte |= bits << (d_byte_offset);
145
        d_byte_offset += d_nbits;
146
      }
147
      else {
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);
153
      }
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);
156
    }
157
158
    if(d_byte_offset == 8) {
159
      //printf("demod byte: %x \n\n", d_partial_byte);
160
      out[bytes_produced++] = d_partial_byte;
161
      d_byte_offset = 0;
162
      d_partial_byte = 0;
163
    }
164
  }
165
  //std::cerr << "accum_error " << accum_error << std::endl;
166
167
  float angle = arg(accum_error);
168
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;
173
    
174
  //if(VERBOSE)
175
  //  std::cerr << angle << "\t" << d_freq << "\t" << d_phase << "\t" << std::endl;
176
  
177
  return bytes_produced;
178
}
179
180
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)
186
{
187
  return gnuradio::get_initial_sptr(new gr_ofdm_frame_sink(sym_position, sym_value_out,
188
                                                        target_queue, occupied_carriers,
189
                                                        phase_gain, freq_gain));
190
}
191
192
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),
203
    d_eq_gain(0.05)
204
{
205
  std::string carriers = "FE7F";
206
207
  // A bit hacky to fill out carriers to occupied_carriers length
208
  int diff = (d_occupied_carriers - 4*carriers.length()); 
209
  while(diff > 7) {
210
    carriers.insert(0, "f");
211
    carriers.insert(carriers.length(), "f");
212
    diff -= 8;
213
  }
214
  
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
220
  int diff_left=0;
221
  int diff_right=0;
222
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'};
226
  if(diff > 0) {
227
    char c[2] = {0,0};
228
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);
232
    
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);
236
  }
237
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
242
  unsigned int i,j,k;
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;
247
      if(k) {
248
        d_subcarrier_map.push_back(4*i + j - diff_left);
249
      }
250
    }
251
  }
252
  
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");
256
  }
257
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));
261
262
  set_sym_value_out(sym_position, sym_value_out);
263
  
264
  enter_search();
265
}
266
267
gr_ofdm_frame_sink::~gr_ofdm_frame_sink ()
268
{
269
  delete [] d_bytes_out;
270
}
271
272
bool
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)
275
{
276
  if (sym_position.size() != sym_value_out.size())
277
    return false;
278
279
  if (sym_position.size()<1)
280
    return false;
281
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));
285
286
  return true;
287
}
288
289
290
int
291
gr_ofdm_frame_sink::work (int noutput_items,
292
                          gr_vector_const_void_star &input_items,
293
                          gr_vector_void_star &output_items)
294
{
295
  const gr_complex *in = (const gr_complex *) input_items[0];
296
  const char *sig = (const char *) input_items[1];
297
  unsigned int j = 0;
298
  unsigned int bytes=0;
299
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];
303
  else
304
    d_derotated_output = NULL;
305
  
306
  if (VERBOSE)
307
    fprintf(stderr,">>> Entering state machine\n");
308
309
  switch(d_state) {
310
      
311
  case STATE_SYNC_SEARCH:    // Look for flag indicating beginning of pkt
312
    if (VERBOSE)
313
      fprintf(stderr,"SYNC Search, noutput=%d\n", noutput_items);
314
    
315
    if (sig[0]) {  // Found it, set up for header decode
316
      enter_have_sync();
317
    }
318
    break;
319
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);
324
    
325
    if (VERBOSE) {
326
      if(sig[0])
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);
330
    }
331
332
    j = 0;
333
    while(j < bytes) {
334
      d_header = (d_header << 8) | (d_bytes_out[j] & 0xFF);
335
      j++;
336
      
337
      if (++d_headerbytelen_cnt == HEADERBYTELEN) {
338
        
339
        if (VERBOSE)
340
          fprintf(stderr, "got header: 0x%08x\n", d_header);
341
        
342
        // we have a full header, check to see if it has been received properly
343
        if (header_ok()){
344
          enter_have_header();
345
          
346
          if (VERBOSE)
347
            printf("\nPacket Length: %d\n", d_packetlen);
348
          
349
          while((j < bytes) && (d_packetlen_cnt < d_packetlen)) {
350
            d_packet[d_packetlen_cnt++] = d_bytes_out[j++];
351
          }
352
          
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
359
            
360
            enter_search();                                
361
          }
362
        }
363
        else {
364
          enter_search();                                // bad header
365
        }
366
      }
367
    }
368
    break;
369
      
370
  case STATE_HAVE_HEADER:
371
    bytes = demapper(&in[0], d_bytes_out);
372
373
    if (VERBOSE) {
374
      if(sig[0])
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");
377
    }
378
    
379
    j = 0;
380
    while(j < bytes) {
381
      d_packet[d_packetlen_cnt++] = d_bytes_out[j++];
382
      
383
      if (d_packetlen_cnt == d_packetlen){                // packet is filled
384
        // build a message
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);
389
        
390
        d_target_queue->insert_tail(msg);                // send it
391
        msg.reset();                                  // free it up
392
        
393
        enter_search();
394
        break;
395
      }
396
    }
397
    break;
398
    
399
  default:
400
    assert(0);
401
    
402
  } // switch
403
404
  return 1;
405
}