1 /*
2  * Copyright (c) 2007 - 2015 Joseph Gaeddert
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a copy
5  * of this software and associated documentation files (the "Software"), to deal
6  * in the Software without restriction, including without limitation the rights
7  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8  * copies of the Software, and to permit persons to whom the Software is
9  * furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice shall be included in
12  * all copies or substantial portions of the Software.
13  *
14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20  * THE SOFTWARE.
21  */
22 
23 //
24 // ofdmflexframesync.c
25 //
26 // OFDM frame synchronizer
27 //
28 
29 #include <stdlib.h>
30 #include <stdio.h>
31 #include <string.h>
32 #include <math.h>
33 #include <assert.h>
34 
35 #include "liquid.internal.h"
36 
37 #define DEBUG_OFDMFLEXFRAMESYNC 0
38 
39 #define OFDMFLEXFRAME_P_SOFT (1)
40 
41 //
42 // ofdmflexframesync
43 //
44 
45 // internal callback
46 int ofdmflexframesync_internal_callback(float complex * _X,
47                                         unsigned char * _p,
48                                         unsigned int    _M,
49                                         void * _userdata);
50 
51 // receive header data
52 void ofdmflexframesync_rxheader(ofdmflexframesync _q,
53                                 float complex * _X);
54 
55 // decode header
56 void ofdmflexframesync_decode_header(ofdmflexframesync _q);
57 
58 // receive payload data
59 void ofdmflexframesync_rxpayload(ofdmflexframesync _q,
60                                 float complex * _X);
61 
62 static ofdmflexframegenprops_s ofdmflexframesyncprops_header_default = {
63     OFDMFLEXFRAME_H_CRC,
64     OFDMFLEXFRAME_H_FEC0,
65     OFDMFLEXFRAME_H_FEC1,
66     OFDMFLEXFRAME_H_MOD,
67 };
68 
69 struct ofdmflexframesync_s {
70     unsigned int M;         // number of subcarriers
71     unsigned int cp_len;    // cyclic prefix length
72     unsigned int taper_len; // taper length
73     unsigned char * p;      // subcarrier allocation (null, pilot, data)
74 
75     // constants
76     unsigned int M_null;    // number of null subcarriers
77     unsigned int M_pilot;   // number of pilot subcarriers
78     unsigned int M_data;    // number of data subcarriers
79     unsigned int M_S0;      // number of enabled subcarriers in S0
80     unsigned int M_S1;      // number of enabled subcarriers in S1
81 
82     // header
83     int header_soft;                    // perform soft demod of header
84     modem mod_header;                   // header modulator
85     packetizer p_header;                // header packetizer
86     unsigned char * header;             // header data (uncoded)
87     unsigned char * header_enc;         // header data (encoded)
88     unsigned char * header_mod;         // header symbols
89     unsigned int header_user_len;       // header length (user)
90     unsigned int header_dec_len;        // header length (uncoded)
91     unsigned int header_enc_len;        // header length (encoded)
92     unsigned int header_sym_len;        // header length (symbols)
93     int header_valid;                   // valid header flag
94 
95     ofdmflexframegenprops_s header_props; // header properties
96 
97     // header properties
98     modulation_scheme ms_payload;       // payload modulation scheme
99     unsigned int bps_payload;           // payload modulation depth (bits/symbol)
100     unsigned int payload_len;           // payload length (number of bytes)
101     crc_scheme check;                   // payload validity check
102     fec_scheme fec0;                    // payload FEC (inner)
103     fec_scheme fec1;                    // payload FEC (outer)
104 
105     // payload
106     int payload_soft;                   // perform soft demod of payload
107     packetizer p_payload;               // payload packetizer
108     modem mod_payload;                  // payload demodulator
109     unsigned char * payload_enc;        // payload data (encoded bytes)
110     unsigned char * payload_dec;        // payload data (decoded bytes)
111     unsigned int payload_enc_len;       // length of encoded payload
112     unsigned int payload_mod_len;       // number of payload modem symbols
113     int payload_valid;                  // valid payload flag
114     float complex * payload_syms;       // received payload symbols
115 
116     // callback
117     framesync_callback callback;        // user-defined callback function
118     void * userdata;                    // user-defined data structure
119     framesyncstats_s framestats;        // frame statistic object
120     float evm_hat;                      // average error vector magnitude
121 
122     // internal synchronizer objects
123     ofdmframesync fs;                   // internal OFDM frame synchronizer
124 
125     // counters/states
126     unsigned int symbol_counter;        // received symbol number
127     enum {
128         OFDMFLEXFRAMESYNC_STATE_HEADER, // extract header
129         OFDMFLEXFRAMESYNC_STATE_PAYLOAD // extract payload symbols
130     } state;
131     unsigned int header_symbol_index;   // number of header symbols received
132     unsigned int payload_symbol_index;  // number of payload symbols received
133     unsigned int payload_buffer_index;  // bit-level index of payload (pack array)
134 };
135 
136 // create ofdmflexframesync object
137 //  _M          :   number of subcarriers
138 //  _cp_len     :   length of cyclic prefix [samples]
139 //  _taper_len  :   taper length (OFDM symbol overlap)
140 //  _p          :   subcarrier allocation (PILOT/NULL/DATA) [size: _M x 1]
141 //  _callback   :   user-defined callback function
142 //  _userdata   :   user-defined data structure passed to callback
ofdmflexframesync_create(unsigned int _M,unsigned int _cp_len,unsigned int _taper_len,unsigned char * _p,framesync_callback _callback,void * _userdata)143 ofdmflexframesync ofdmflexframesync_create(unsigned int       _M,
144                                            unsigned int       _cp_len,
145                                            unsigned int       _taper_len,
146                                            unsigned char *    _p,
147                                            framesync_callback _callback,
148                                            void *             _userdata)
149 {
150     ofdmflexframesync q = (ofdmflexframesync) malloc(sizeof(struct ofdmflexframesync_s));
151 
152     // validate input
153     if (_M < 8) {
154         fprintf(stderr,"warning: ofdmflexframesync_create(), less than 8 subcarriers\n");
155     } else if (_M % 2) {
156         fprintf(stderr,"error: ofdmflexframesync_create(), number of subcarriers must be even\n");
157         exit(1);
158     } else if (_cp_len > _M) {
159         fprintf(stderr,"error: ofdmflexframesync_create(), cyclic prefix length cannot exceed number of subcarriers\n");
160         exit(1);
161     }
162 
163     // set internal properties
164     q->M         = _M;
165     q->cp_len    = _cp_len;
166     q->taper_len = _taper_len;
167     q->callback  = _callback;
168     q->userdata  = _userdata;
169 
170     // allocate memory for subcarrier allocation IDs
171     q->p = (unsigned char*) malloc((q->M)*sizeof(unsigned char));
172     if (_p == NULL) {
173         // initialize default subcarrier allocation
174         ofdmframe_init_default_sctype(q->M, q->p);
175     } else {
176         // copy user-defined subcarrier allocation
177         memmove(q->p, _p, q->M*sizeof(unsigned char));
178     }
179 
180     // validate and count subcarrier allocation
181     ofdmframe_validate_sctype(q->p, q->M, &q->M_null, &q->M_pilot, &q->M_data);
182 
183     // create internal framing object
184     q->fs = ofdmframesync_create(_M, _cp_len, _taper_len, _p, ofdmflexframesync_internal_callback, (void*)q);
185 
186     // create header objects
187     q->header = NULL;
188     q->p_header = NULL;
189     q->header_enc = NULL;
190     q->header_mod = NULL;
191     q->mod_header = NULL;
192     q->header_user_len = OFDMFLEXFRAME_H_USER_DEFAULT;
193     q->header_soft = 0;
194     ofdmflexframesync_set_header_props(q, NULL);
195 
196     // frame properties (default values to be overwritten when frame
197     // header is received and properly decoded)
198     q->ms_payload   = LIQUID_MODEM_QPSK;
199     q->bps_payload  = 2;
200     q->payload_len  = 1;
201     q->check        = LIQUID_CRC_NONE;
202     q->fec0         = LIQUID_FEC_NONE;
203     q->fec1         = LIQUID_FEC_NONE;
204 
205     // create payload objects (initally QPSK, etc but overridden by received properties)
206     q->mod_payload = modem_create(q->ms_payload);
207     q->payload_soft = 0;
208     q->p_payload   = packetizer_create(q->payload_len, q->check, q->fec0, q->fec1);
209     q->payload_enc_len = packetizer_get_enc_msg_len(q->p_payload);
210     q->payload_enc = (unsigned char*) malloc(q->payload_enc_len*sizeof(unsigned char));
211     q->payload_dec = (unsigned char*) malloc(q->payload_len*sizeof(unsigned char));
212     q->payload_syms = (float complex *) malloc(q->payload_len*sizeof(float complex));
213     q->payload_mod_len = 0;
214 
215     // reset state
216     ofdmflexframesync_reset(q);
217 
218     // return object
219     return q;
220 }
221 
ofdmflexframesync_destroy(ofdmflexframesync _q)222 void ofdmflexframesync_destroy(ofdmflexframesync _q)
223 {
224     // destroy internal objects
225     ofdmframesync_destroy(_q->fs);
226     packetizer_destroy(_q->p_header);
227     modem_destroy(_q->mod_header);
228     packetizer_destroy(_q->p_payload);
229     modem_destroy(_q->mod_payload);
230 
231     // free internal buffers/arrays
232     free(_q->p);
233     free(_q->payload_enc);
234     free(_q->payload_dec);
235     free(_q->payload_syms);
236     free(_q->header);
237     free(_q->header_enc);
238     free(_q->header_mod);
239 
240     // free main object memory
241     free(_q);
242 }
243 
ofdmflexframesync_print(ofdmflexframesync _q)244 void ofdmflexframesync_print(ofdmflexframesync _q)
245 {
246     printf("ofdmflexframesync:\n");
247     printf("    num subcarriers     :   %-u\n", _q->M);
248     printf("      * NULL            :   %-u\n", _q->M_null);
249     printf("      * pilot           :   %-u\n", _q->M_pilot);
250     printf("      * data            :   %-u\n", _q->M_data);
251     printf("    cyclic prefix len   :   %-u\n", _q->cp_len);
252     printf("    taper len           :   %-u\n", _q->taper_len);
253 }
254 
ofdmflexframesync_set_header_len(ofdmflexframesync _q,unsigned int _len)255 void ofdmflexframesync_set_header_len(ofdmflexframesync _q,
256                                       unsigned int     _len)
257 {
258     _q->header_user_len = _len;
259     _q->header_dec_len = OFDMFLEXFRAME_H_DEC + _q->header_user_len;
260     _q->header = realloc(_q->header, _q->header_dec_len*sizeof(unsigned char));
261 
262     if (_q->p_header) {
263         packetizer_destroy(_q->p_header);
264     }
265     _q->p_header = packetizer_create(_q->header_dec_len,
266                                      _q->header_props.check,
267                                      _q->header_props.fec0,
268                                      _q->header_props.fec1);
269     if (_q->header_soft) {
270         _q->header_enc_len = 8*packetizer_get_enc_msg_len(_q->p_header);
271         _q->header_sym_len = _q->header_enc_len;
272     } else {
273         _q->header_enc_len = packetizer_get_enc_msg_len(_q->p_header);
274         unsigned int bps = modulation_types[_q->header_props.mod_scheme].bps;
275         div_t bps_d = div(_q->header_enc_len*8, bps);
276         _q->header_sym_len = bps_d.quot + (bps_d.rem ? 1 : 0);
277     }
278     _q->header_enc = realloc(_q->header_enc, _q->header_enc_len*sizeof(unsigned char));
279 
280     _q->header_mod = realloc(_q->header_mod, _q->header_sym_len*sizeof(unsigned char));
281     // create header objects
282     if (_q->mod_header) {
283         modem_destroy(_q->mod_header);
284     }
285     _q->mod_header = modem_create(_q->header_props.mod_scheme);
286 }
287 
ofdmflexframesync_decode_header_soft(ofdmflexframesync _q,int _soft)288 void ofdmflexframesync_decode_header_soft(ofdmflexframesync _q,
289                                            int _soft) {
290     _q->header_soft = _soft;
291     ofdmflexframesync_set_header_len(_q, _q->header_user_len);
292 }
293 
ofdmflexframesync_decode_payload_soft(ofdmflexframesync _q,int _soft)294 void ofdmflexframesync_decode_payload_soft(ofdmflexframesync _q,
295                                            int _soft) {
296     _q->payload_soft = _soft;
297 }
298 
ofdmflexframesync_set_header_props(ofdmflexframesync _q,ofdmflexframegenprops_s * _props)299 void ofdmflexframesync_set_header_props(ofdmflexframesync _q,
300                                         ofdmflexframegenprops_s * _props)
301 {
302     // if properties object is NULL, initialize with defaults
303     if (_props == NULL) {
304         _props = &ofdmflexframesyncprops_header_default;
305     }
306 
307     // validate input
308     if (_props->check == LIQUID_CRC_UNKNOWN || _props->check >= LIQUID_CRC_NUM_SCHEMES) {
309         fprintf(stderr, "error: ofdmflexframesync_set_header_props(), invalid/unsupported CRC scheme\n");
310         exit(1);
311     } else if (_props->fec0 == LIQUID_FEC_UNKNOWN || _props->fec1 == LIQUID_FEC_UNKNOWN) {
312         fprintf(stderr, "error: ofdmflexframesync_set_header_props(), invalid/unsupported FEC scheme\n");
313         exit(1);
314     } else if (_props->mod_scheme == LIQUID_MODEM_UNKNOWN ) {
315         fprintf(stderr, "error: ofdmflexframesync_set_header_props(), invalid/unsupported modulation scheme\n");
316         exit(1);
317     }
318 
319     // copy properties to internal structure
320     memmove(&_q->header_props, _props, sizeof(ofdmflexframegenprops_s));
321 
322     // reconfigure internal buffers, objects, etc.
323     ofdmflexframesync_set_header_len(_q, _q->header_user_len);
324 }
325 
ofdmflexframesync_reset(ofdmflexframesync _q)326 void ofdmflexframesync_reset(ofdmflexframesync _q)
327 {
328     // reset internal state
329     _q->state = OFDMFLEXFRAMESYNC_STATE_HEADER;
330 
331     // reset internal counters
332     _q->symbol_counter=0;
333     _q->header_symbol_index=0;
334     _q->payload_symbol_index=0;
335     _q->payload_buffer_index=0;
336 
337     // reset error vector magnitude estimate
338     _q->evm_hat = 1e-12f;   // slight offset to ensure no log(0)
339 
340     // reset framestats object
341     framesyncstats_init_default(&_q->framestats);
342 
343     // reset internal OFDM frame synchronizer object
344     ofdmframesync_reset(_q->fs);
345 }
346 
ofdmflexframesync_is_frame_open(ofdmflexframesync _q)347 int ofdmflexframesync_is_frame_open(ofdmflexframesync _q)
348 {
349     return ofdmframesync_is_frame_open(_q->fs);
350 }
351 
352 // execute synchronizer object on buffer of samples
ofdmflexframesync_execute(ofdmflexframesync _q,float complex * _x,unsigned int _n)353 void ofdmflexframesync_execute(ofdmflexframesync _q,
354                                float complex * _x,
355                                unsigned int _n)
356 {
357     // push samples through ofdmframesync object
358     ofdmframesync_execute(_q->fs, _x, _n);
359 }
360 
361 //
362 // query methods
363 //
364 
365 // received signal strength indication
ofdmflexframesync_get_rssi(ofdmflexframesync _q)366 float ofdmflexframesync_get_rssi(ofdmflexframesync _q)
367 {
368     return ofdmframesync_get_rssi(_q->fs);
369 }
370 
371 // received carrier frequency offset
ofdmflexframesync_get_cfo(ofdmflexframesync _q)372 float ofdmflexframesync_get_cfo(ofdmflexframesync _q)
373 {
374     return ofdmframesync_get_cfo(_q->fs);
375 }
376 
377 //
378 // set methods
379 //
380 
381 // received carrier frequency offset
ofdmflexframesync_set_cfo(ofdmflexframesync _q,float _cfo)382 void ofdmflexframesync_set_cfo(ofdmflexframesync _q, float _cfo)
383 {
384     return ofdmframesync_set_cfo(_q->fs, _cfo);
385 }
386 
387 //
388 // debugging methods
389 //
390 
391 // enable debugging for internal ofdm frame synchronizer
ofdmflexframesync_debug_enable(ofdmflexframesync _q)392 void ofdmflexframesync_debug_enable(ofdmflexframesync _q)
393 {
394     ofdmframesync_debug_enable(_q->fs);
395 }
396 
397 // disable debugging for internal ofdm frame synchronizer
ofdmflexframesync_debug_disable(ofdmflexframesync _q)398 void ofdmflexframesync_debug_disable(ofdmflexframesync _q)
399 {
400     ofdmframesync_debug_disable(_q->fs);
401 }
402 
403 // print debugging file for internal ofdm frame synchronizer
ofdmflexframesync_debug_print(ofdmflexframesync _q,const char * _filename)404 void ofdmflexframesync_debug_print(ofdmflexframesync _q,
405                                    const char *      _filename)
406 {
407     ofdmframesync_debug_print(_q->fs, _filename);
408 }
409 
410 //
411 // internal methods
412 //
413 
414 // internal callback
415 //  _X          :   subcarrier symbols
416 //  _p          :   subcarrier allocation
417 //  _M          :   number of subcarriers
418 //  _userdata   :   user-defined data structure
ofdmflexframesync_internal_callback(float complex * _X,unsigned char * _p,unsigned int _M,void * _userdata)419 int ofdmflexframesync_internal_callback(float complex * _X,
420                                         unsigned char * _p,
421                                         unsigned int    _M,
422                                         void * _userdata)
423 {
424 #if DEBUG_OFDMFLEXFRAMESYNC
425     printf("******* ofdmflexframesync callback invoked!\n");
426 #endif
427     // type-cast userdata as ofdmflexframesync object
428     ofdmflexframesync _q = (ofdmflexframesync) _userdata;
429 
430     _q->symbol_counter++;
431 
432 #if DEBUG_OFDMFLEXFRAMESYNC
433     printf("received symbol %u\n", _q->symbol_counter);
434 #endif
435 
436     // extract symbols
437     switch (_q->state) {
438     case OFDMFLEXFRAMESYNC_STATE_HEADER:
439         ofdmflexframesync_rxheader(_q, _X);
440         break;
441     case OFDMFLEXFRAMESYNC_STATE_PAYLOAD:
442         ofdmflexframesync_rxpayload(_q, _X);
443         break;
444     default:
445         fprintf(stderr,"error: ofdmflexframesync_internal_callback(), unknown/unsupported internal state\n");
446         exit(1);
447     }
448 
449     // return
450     return 0;
451 }
452 
453 // receive header data
ofdmflexframesync_rxheader(ofdmflexframesync _q,float complex * _X)454 void ofdmflexframesync_rxheader(ofdmflexframesync _q,
455                                 float complex * _X)
456 {
457 #if DEBUG_OFDMFLEXFRAMESYNC
458     printf("  ofdmflexframesync extracting header...\n");
459 #endif
460 
461     // demodulate header symbols
462     unsigned int i;
463     int sctype;
464     for (i=0; i<_q->M; i++) {
465         // subcarrier type (PILOT/NULL/DATA)
466         sctype = _q->p[i];
467 
468         // ignore pilot and null subcarriers
469         if (sctype == OFDMFRAME_SCTYPE_DATA) {
470             // unload header symbols
471             // demodulate header symbol
472             unsigned int sym;
473             if (_q->header_soft) {
474                 unsigned int bps = modulation_types[_q->header_props.mod_scheme].bps;
475                 modem_demodulate_soft(_q->mod_header, _X[i], &sym, &_q->header_mod[bps*_q->header_symbol_index]);
476             } else {
477                 modem_demodulate(_q->mod_header, _X[i], &sym);
478                 _q->header_mod[_q->header_symbol_index] = sym;
479             }
480             _q->header_symbol_index++;
481             //printf("  extracting symbol %3u / %3u (x = %8.5f + j%8.5f)\n", _q->header_symbol_index, _q->header_sym_len, crealf(_X[i]), cimagf(_X[i]));
482 
483             // get demodulator error vector magnitude
484             float evm = modem_get_demodulator_evm(_q->mod_header);
485             _q->evm_hat += evm*evm;
486 
487             // header extracted
488             if (_q->header_symbol_index == _q->header_sym_len) {
489                 // decode header
490                 ofdmflexframesync_decode_header(_q);
491 
492                 // compute error vector magnitude estimate
493                 _q->framestats.evm = 10*log10f( _q->evm_hat/_q->header_sym_len );
494 
495                 // invoke callback if header is invalid
496                 if (_q->header_valid)
497                     _q->state = OFDMFLEXFRAMESYNC_STATE_PAYLOAD;
498                 else {
499                     //printf("**** header invalid!\n");
500                     // set framestats internals
501                     _q->framestats.rssi             = ofdmframesync_get_rssi(_q->fs);
502                     _q->framestats.cfo              = ofdmframesync_get_cfo(_q->fs);
503                     _q->framestats.framesyms        = NULL;
504                     _q->framestats.num_framesyms    = 0;
505                     _q->framestats.mod_scheme       = LIQUID_MODEM_UNKNOWN;
506                     _q->framestats.mod_bps          = 0;
507                     _q->framestats.check            = LIQUID_CRC_UNKNOWN;
508                     _q->framestats.fec0             = LIQUID_FEC_UNKNOWN;
509                     _q->framestats.fec1             = LIQUID_FEC_UNKNOWN;
510 
511                     // invoke callback method
512                     _q->callback(_q->header,
513                                  _q->header_valid,
514                                  NULL,
515                                  0,
516                                  0,
517                                  _q->framestats,
518                                  _q->userdata);
519 
520                     ofdmflexframesync_reset(_q);
521                 }
522                 break;
523             }
524         }
525     }
526 }
527 
528 // decode header
ofdmflexframesync_decode_header(ofdmflexframesync _q)529 void ofdmflexframesync_decode_header(ofdmflexframesync _q)
530 {
531     if (_q->header_soft) {
532         // TODO: ensure lengths are the same
533         memmove(_q->header_enc, _q->header_mod, _q->header_enc_len);
534 
535         // unscramble header using soft bits
536         unscramble_data_soft(_q->header_enc, _q->header_enc_len/8);
537 
538         // run packet decoder
539         _q->header_valid = packetizer_decode_soft(_q->p_header, _q->header_enc, _q->header);
540     } else {
541         // pack 1-bit header symbols into 8-bit bytes
542         unsigned int num_written;
543         unsigned int bps = modulation_types[_q->header_props.mod_scheme].bps;
544         liquid_repack_bytes(_q->header_mod, bps, _q->header_sym_len,
545                             _q->header_enc, 8,   _q->header_enc_len,
546                             &num_written);
547         assert(num_written==_q->header_enc_len);
548 
549         // unscramble header
550         unscramble_data(_q->header_enc, _q->header_enc_len);
551 
552         // run packet decoder
553         _q->header_valid = packetizer_decode(_q->p_header, _q->header_enc, _q->header);
554     }
555 
556 #if 0
557     // print header
558     printf("header rx (enc) : ");
559     for (i=0; i<_q->header_enc_len; i++)
560         printf("%.2X ", _q->header_enc[i]);
561     printf("\n");
562 
563     // print header
564     printf("header rx (dec) : ");
565     for (i=0; i<_q->header_dec_len; i++)
566         printf("%.2X ", _q->header[i]);
567     printf("\n");
568 #endif
569 
570 #if DEBUG_OFDMFLEXFRAMESYNC
571     printf("****** header extracted [%s]\n", _q->header_valid ? "valid" : "INVALID!");
572 #endif
573     if (!_q->header_valid)
574         return;
575 
576     unsigned int n = _q->header_user_len;
577 
578     // first byte is for expansion/version validation
579     if (_q->header[n+0] != OFDMFLEXFRAME_PROTOCOL) {
580         fprintf(stderr,"warning: ofdmflexframesync_decode_header(), invalid framing version\n");
581         _q->header_valid = 0;
582     }
583 
584     // strip off payload length
585     unsigned int payload_len = (_q->header[n+1] << 8) | (_q->header[n+2]);
586 
587     // strip off modulation scheme/depth
588     unsigned int mod_scheme = _q->header[n+3];
589     if (mod_scheme == 0 || mod_scheme >= LIQUID_MODEM_NUM_SCHEMES) {
590         fprintf(stderr,"warning: ofdmflexframesync_decode_header(), invalid modulation scheme\n");
591         _q->header_valid = 0;
592         return;
593     }
594 
595     // strip off CRC, forward error-correction schemes
596     //  CRC     : most-significant 3 bits of [n+4]
597     //  fec0    : least-significant 5 bits of [n+4]
598     //  fec1    : least-significant 5 bits of [n+5]
599     unsigned int check = (_q->header[n+4] >> 5 ) & 0x07;
600     unsigned int fec0  = (_q->header[n+4]      ) & 0x1f;
601     unsigned int fec1  = (_q->header[n+5]      ) & 0x1f;
602 
603     // validate properties
604     if (check >= LIQUID_CRC_NUM_SCHEMES) {
605         fprintf(stderr,"warning: ofdmflexframesync_decode_header(), decoded CRC exceeds available\n");
606         check = LIQUID_CRC_UNKNOWN;
607         _q->header_valid = 0;
608     }
609     if (fec0 >= LIQUID_FEC_NUM_SCHEMES) {
610         fprintf(stderr,"warning: ofdmflexframesync_decode_header(), decoded FEC (inner) exceeds available\n");
611         fec0 = LIQUID_FEC_UNKNOWN;
612         _q->header_valid = 0;
613     }
614     if (fec1 >= LIQUID_FEC_NUM_SCHEMES) {
615         fprintf(stderr,"warning: ofdmflexframesync_decode_header(), decoded FEC (outer) exceeds available\n");
616         fec1 = LIQUID_FEC_UNKNOWN;
617         _q->header_valid = 0;
618     }
619 
620     // print results
621 #if DEBUG_OFDMFLEXFRAMESYNC
622     printf("    properties:\n");
623     printf("      * mod scheme      :   %s\n", modulation_types[mod_scheme].fullname);
624     printf("      * fec (inner)     :   %s\n", fec_scheme_str[fec0][1]);
625     printf("      * fec (outer)     :   %s\n", fec_scheme_str[fec1][1]);
626     printf("      * CRC scheme      :   %s\n", crc_scheme_str[check][1]);
627     printf("      * payload length  :   %u bytes\n", payload_len);
628 #endif
629 
630     // configure payload receiver
631     if (_q->header_valid) {
632         // configure modem
633         if (mod_scheme != _q->ms_payload) {
634             // set new properties
635             _q->ms_payload  = mod_scheme;
636             _q->bps_payload = modulation_types[mod_scheme].bps;
637 
638             // recreate modem (destroy/create)
639             _q->mod_payload = modem_recreate(_q->mod_payload, _q->ms_payload);
640         }
641 
642         // set new packetizer properties
643         _q->payload_len = payload_len;
644         _q->check       = check;
645         _q->fec0        = fec0;
646         _q->fec1        = fec1;
647 
648         // recreate packetizer object
649         _q->p_payload = packetizer_recreate(_q->p_payload,
650                                             _q->payload_len,
651                                             _q->check,
652                                             _q->fec0,
653                                             _q->fec1);
654 
655         // re-compute payload encoded message length
656         if (_q->payload_soft) {
657             int packetizer_msg_len = packetizer_get_enc_msg_len(_q->p_payload);
658             div_t d = div((int)8*packetizer_msg_len, (int)_q->bps_payload);
659             _q->payload_mod_len = d.quot + (d.rem ? 1 : 0);
660             _q->payload_enc_len = _q->bps_payload*_q->payload_mod_len;
661         } else {
662             _q->payload_enc_len = packetizer_get_enc_msg_len(_q->p_payload);
663             // re-compute number of modulated payload symbols
664             div_t d = div(8*_q->payload_enc_len, _q->bps_payload);
665             _q->payload_mod_len = d.quot + (d.rem ? 1 : 0);
666         }
667 
668 #if DEBUG_OFDMFLEXFRAMESYNC
669         printf("      * payload encoded :   %u bytes\n", _q->payload_enc_len);
670 #endif
671 
672         // re-allocate buffers accordingly
673         _q->payload_enc = (unsigned char*) realloc(_q->payload_enc, _q->payload_enc_len*sizeof(unsigned char));
674         _q->payload_dec = (unsigned char*) realloc(_q->payload_dec, _q->payload_len*sizeof(unsigned char));
675         _q->payload_syms = (float complex*) realloc(_q->payload_syms, _q->payload_mod_len*sizeof(float complex));
676 #if DEBUG_OFDMFLEXFRAMESYNC
677         printf("      * payload mod syms:   %u symbols\n", _q->payload_mod_len);
678 #endif
679     }
680 }
681 
682 // receive payload data
ofdmflexframesync_rxpayload(ofdmflexframesync _q,float complex * _X)683 void ofdmflexframesync_rxpayload(ofdmflexframesync _q,
684                                  float complex * _X)
685 {
686     // demodulate paylod symbols
687     unsigned int i;
688     int sctype;
689     for (i=0; i<_q->M; i++) {
690         // subcarrier type (PILOT/NULL/DATA)
691         sctype = _q->p[i];
692 
693         // ignore pilot and null subcarriers
694         if (sctype == OFDMFRAME_SCTYPE_DATA) {
695             // unload payload symbols
696             unsigned int sym;
697             // store received symbol
698             _q->payload_syms[_q->payload_symbol_index] = _X[i];
699 
700             if (_q->payload_soft) {
701                 modem_demodulate_soft(_q->mod_payload, _X[i], &sym, &_q->payload_enc[_q->bps_payload*_q->payload_symbol_index]);
702             } else {
703                 modem_demodulate(_q->mod_payload, _X[i], &sym);
704 
705                 // pack decoded symbol into array
706                 liquid_pack_array(_q->payload_enc,
707                                   _q->payload_enc_len,
708                                   _q->payload_buffer_index,
709                                   _q->bps_payload,
710                                   sym);
711 
712                 // increment...
713                 _q->payload_buffer_index += _q->bps_payload;
714             }
715 
716             // increment symbol counter
717             _q->payload_symbol_index++;
718 
719             if (_q->payload_symbol_index == _q->payload_mod_len) {
720                 // payload extracted
721                 if (_q->payload_soft) {
722                     _q->payload_valid = packetizer_decode_soft(_q->p_payload, _q->payload_enc, _q->payload_dec);
723                 } else {
724                     // decode payload
725                     _q->payload_valid = packetizer_decode(_q->p_payload, _q->payload_enc, _q->payload_dec);
726                 }
727 #if DEBUG_OFDMFLEXFRAMESYNC
728                 printf("****** payload extracted [%s]\n", _q->payload_valid ? "valid" : "INVALID!");
729 #endif
730 
731                 // ignore callback if set to NULL
732                 if (_q->callback == NULL) {
733                     ofdmflexframesync_reset(_q);
734                     break;
735                 }
736 
737                 // set framestats internals
738                 _q->framestats.rssi             = ofdmframesync_get_rssi(_q->fs);
739                 _q->framestats.cfo              = ofdmframesync_get_cfo(_q->fs);
740                 _q->framestats.framesyms        = _q->payload_syms;
741                 _q->framestats.num_framesyms    = _q->payload_mod_len;
742                 _q->framestats.mod_scheme       = _q->ms_payload;
743                 _q->framestats.mod_bps          = _q->bps_payload;
744                 _q->framestats.check            = _q->check;
745                 _q->framestats.fec0             = _q->fec0;
746                 _q->framestats.fec1             = _q->fec1;
747 
748                 // invoke callback method
749                 _q->callback(_q->header,
750                              _q->header_valid,
751                              _q->payload_dec,
752                              _q->payload_len,
753                              _q->payload_valid,
754                              _q->framestats,
755                              _q->userdata);
756 
757 
758                 // reset object
759                 ofdmflexframesync_reset(_q);
760                 break;
761             }
762         }
763     }
764 }
765 
766 
767 
768