acaf1258bd2858534c13b1c5bc6b65142fb1a9ed
[debian/gnuradio] / gnuradio-core / src / lib / general / gr_ofdm_frame_sink.cc
1 /* -*- c++ -*- */
2 /*
3  * Copyright 2007 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., 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 <cstdio>
30 #include <stdexcept>
31
32 #define VERBOSE 0
33
34 inline void
35 gr_ofdm_frame_sink::enter_search()
36 {
37   if (VERBOSE)
38     fprintf(stderr, "@ enter_search\n");
39
40   d_state = STATE_SYNC_SEARCH;
41
42 }
43     
44 inline void
45 gr_ofdm_frame_sink::enter_have_sync()
46 {
47   if (VERBOSE)
48     fprintf(stderr, "@ enter_have_sync\n");
49
50   d_state = STATE_HAVE_SYNC;
51
52   // clear state of demapper
53   d_byte_offset = 0;
54   d_partial_byte = 0;
55
56   d_header = 0;
57   d_headerbytelen_cnt = 0;
58 }
59
60 inline void
61 gr_ofdm_frame_sink::enter_have_header()
62 {
63   d_state = STATE_HAVE_HEADER;
64
65   // header consists of two 16-bit shorts in network byte order
66   // payload length is lower 12 bits
67   // whitener offset is upper 4 bits
68   d_packetlen = (d_header >> 16) & 0x0fff;
69   d_packet_whitener_offset = (d_header >> 28) & 0x000f;
70   d_packetlen_cnt = 0;
71
72   if (VERBOSE)
73     fprintf(stderr, "@ enter_have_header (payload_len = %d) (offset = %d)\n", 
74             d_packetlen, d_packet_whitener_offset);
75 }
76
77 unsigned char gr_ofdm_frame_sink::bpsk_slicer(gr_complex x)
78 {
79   return (unsigned char)(x.real() > 0 ? 1 : 0);
80 }
81
82 unsigned int gr_ofdm_frame_sink::bpsk_demapper(const gr_complex *in,
83                                                unsigned char *out)
84 {
85   unsigned int i=0, bytes_produced=0;
86
87   while(i < d_occupied_carriers) {
88
89     while((d_byte_offset < 8) && (i < d_occupied_carriers)) {
90       //fprintf(stderr, "%f+j%f\n", in[i].real(), in[i].imag()); 
91       d_partial_byte |= bpsk_slicer(in[i++]) << (d_byte_offset++);
92     }
93
94     if(d_byte_offset == 8) {
95       out[bytes_produced++] = d_partial_byte;
96       d_byte_offset = 0;
97       d_partial_byte = 0;
98     }
99   }
100
101   return bytes_produced;
102 }
103
104
105
106 gr_ofdm_frame_sink_sptr
107 gr_make_ofdm_frame_sink(gr_msg_queue_sptr target_queue, unsigned int occupied_carriers)
108 {
109   return gr_ofdm_frame_sink_sptr(new gr_ofdm_frame_sink(target_queue, occupied_carriers));
110 }
111
112
113 gr_ofdm_frame_sink::gr_ofdm_frame_sink(gr_msg_queue_sptr target_queue, unsigned int occupied_carriers)
114   : gr_sync_block ("ofdm_frame_sink",
115                    gr_make_io_signature2 (2, 2, sizeof(gr_complex)*occupied_carriers, sizeof(char)),
116                    gr_make_io_signature (0, 0, 0)),
117     d_target_queue(target_queue), d_occupied_carriers(occupied_carriers), 
118     d_byte_offset(0), d_partial_byte(0)
119 {
120   d_bytes_out = new unsigned char[(int)ceil(d_occupied_carriers/8.0)];
121
122   enter_search();
123 }
124
125 gr_ofdm_frame_sink::~gr_ofdm_frame_sink ()
126 {
127   delete [] d_bytes_out;
128 }
129
130 int
131 gr_ofdm_frame_sink::work (int noutput_items,
132                           gr_vector_const_void_star &input_items,
133                           gr_vector_void_star &output_items)
134 {
135   const gr_complex *in = (const gr_complex *) input_items[0];
136   const char *sig = (const char *) input_items[1];
137   int count_tones=0, count_items=0;
138   unsigned int j = 0;
139   unsigned int bytes=0;
140   
141   if (VERBOSE)
142     fprintf(stderr,">>> Entering state machine\n");
143   
144   bytes = bpsk_demapper(&in[0], d_bytes_out);
145   
146   switch(d_state) {
147       
148   case STATE_SYNC_SEARCH:    // Look for flag indicating beginning of pkt
149     if (VERBOSE)
150       fprintf(stderr,"SYNC Search, noutput=%d\n", noutput_items);
151     
152     if (sig[0]) {  // Found it, set up for header decode
153       enter_have_sync();
154     }
155     break;
156
157   case STATE_HAVE_SYNC:
158     if(sig[0])
159       printf("ERROR -- Found SYNC in HAVE_SYNC\n");
160     if (VERBOSE)
161       fprintf(stderr,"Header Search bitcnt=%d, header=0x%08x\n",
162               d_headerbytelen_cnt, d_header);
163     
164     j = 0;
165     while(j < bytes) {
166       d_header = (d_header << 8) | (d_bytes_out[j] & 0xFF);
167       j++;
168       
169       if (++d_headerbytelen_cnt == HEADERBYTELEN) {
170         
171         if (VERBOSE)
172           fprintf(stderr, "got header: 0x%08x\n", d_header);
173         
174         // we have a full header, check to see if it has been received properly
175         if (header_ok()){
176           enter_have_header();
177           printf("\nPacket Length: %d\n", d_packetlen);
178           //for(int k=0; k < d_packetlen; k++)
179           //  printf("%02x", d_packet[k]);
180           //printf("\n");
181           
182           while((j < bytes) && (d_packetlen_cnt < d_packetlen)) {
183             d_packet[d_packetlen_cnt++] = d_bytes_out[j++];
184           }
185           
186           if(d_packetlen_cnt == d_packetlen) {
187             gr_message_sptr msg =
188               gr_make_message(0, d_packet_whitener_offset, 0, d_packetlen);
189             memcpy(msg->msg(), d_packet, d_packetlen_cnt);
190             d_target_queue->insert_tail(msg);           // send it
191             msg.reset();                                // free it up
192             
193             enter_search();                             
194           }
195         }
196         else {
197           enter_search();                               // bad header
198         }
199       }
200     }
201     break;
202       
203   case STATE_HAVE_HEADER:
204     if(sig[0])
205       printf("ERROR -- Found SYNC in HAVE_HEADER at %d, length of %d\n", d_packetlen_cnt, d_packetlen);
206     if (VERBOSE)
207         fprintf(stderr,"Packet Build\n");
208     
209     j = 0;
210     while(j < bytes) {
211       d_packet[d_packetlen_cnt++] = d_bytes_out[j++];
212       
213       if (d_packetlen_cnt == d_packetlen){              // packet is filled
214         // build a message
215         // NOTE: passing header field as arg1 is not scalable
216         gr_message_sptr msg =
217           gr_make_message(0, d_packet_whitener_offset, 0, d_packetlen_cnt);
218         memcpy(msg->msg(), d_packet, d_packetlen_cnt);
219         
220         d_target_queue->insert_tail(msg);               // send it
221         msg.reset();                            // free it up
222         
223         enter_search();
224         break;
225       }
226     }
227     break;
228     
229   default:
230     assert(0);
231     
232   } // switch
233   
234   return 1;
235 }