1 //
2 // ofdmflexframesync_example.c
3 //
4 // Example demonstrating the OFDM flexible frame synchronizer.
5 //
6 
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <math.h>
10 #include <string.h>
11 #include <getopt.h>
12 #include <time.h>
13 
14 #include "liquid.h"
15 
usage()16 void usage()
17 {
18     printf("ofdmflexframesync_example [options]\n");
19     printf(" -h        : print usage\n");
20     printf(" -s  <snr> : signal-to-noise ratio [dB], default: 20\n");
21     printf(" -F <freq> : carrier frequency offset, default: 0.002\n");
22     printf(" -M  <num> : number of subcarriers (must be even), default: 64\n");
23     printf(" -C  <len> : cyclic prefix length, default: 16\n");
24     printf(" -n  <len> : payload length [bytes], default: 120\n");
25     printf(" -m  <mod> : modulation scheme (qpsk default)\n");
26     liquid_print_modulation_schemes();
27     printf(" -v  <crc> : data integrity check: crc32 default\n");
28     liquid_print_crc_schemes();
29     printf(" -c  <fec> : coding scheme (inner): h74 default\n");
30     printf(" -k  <fec> : coding scheme (outer): none default\n");
31     liquid_print_fec_schemes();
32     printf(" -d       : enable debugging\n");
33 }
34 
35 // callback function
36 int callback(unsigned char *  _header,
37              int              _header_valid,
38              unsigned char *  _payload,
39              unsigned int     _payload_len,
40              int              _payload_valid,
41              framesyncstats_s _stats,
42              void *           _userdata);
43 
main(int argc,char * argv[])44 int main(int argc, char*argv[])
45 {
46     //srand(time(NULL));
47 
48     // options
49     unsigned int      M           = 64;                 // number of subcarriers
50     unsigned int      cp_len      = 16;                 // cyclic prefix length
51     unsigned int      taper_len   = 4;                  // taper length
52     unsigned int      payload_len = 120;                // length of payload (bytes)
53     modulation_scheme ms          = LIQUID_MODEM_QPSK;  // modulation scheme
54     fec_scheme        fec0        = LIQUID_FEC_NONE;    // inner code
55     fec_scheme        fec1        = LIQUID_FEC_HAMMING128; // outer code
56     crc_scheme        check       = LIQUID_CRC_32;      // validity check
57     float             noise_floor = -80.0f;             // noise floor [dB]
58     float             SNRdB       = 20.0f;              // signal-to-noise ratio [dB]
59     float             dphi        = 0.02f;              // carrier frequency offset
60     int               debug       =  0;                 // enable debugging?
61 
62     // get options
63     int dopt;
64     while((dopt = getopt(argc,argv,"uhds:F:M:C:n:m:v:c:k:")) != EOF){
65         switch (dopt) {
66         case 'u':
67         case 'h': usage();                    return 0;
68         case 'd': debug       = 1;            break;
69         case 's': SNRdB       = atof(optarg); break;
70         case 'F': dphi        = atof(optarg); break;
71         case 'M': M           = atoi(optarg); break;
72         case 'C': cp_len      = atoi(optarg); break;
73         case 'n': payload_len = atol(optarg); break;
74         case 'm': ms          = liquid_getopt_str2mod(optarg); break;
75         case 'v': check       = liquid_getopt_str2crc(optarg); break;
76         case 'c': fec0        = liquid_getopt_str2fec(optarg); break;
77         case 'k': fec1        = liquid_getopt_str2fec(optarg); break;
78         default:
79             exit(-1);
80         }
81     }
82 
83     unsigned int i;
84 
85     // TODO : validate options
86 
87     // derived values
88     unsigned int  buf_len = 256;
89     float complex buf[buf_len]; // time-domain buffer
90 
91     // allocate memory for header, payload
92     unsigned char header[8];
93     unsigned char payload[payload_len];
94 
95     // create frame generator
96     ofdmflexframegenprops_s fgprops;
97     ofdmflexframegenprops_init_default(&fgprops);
98     fgprops.check           = check;
99     fgprops.fec0            = fec0;
100     fgprops.fec1            = fec1;
101     fgprops.mod_scheme      = ms;
102     ofdmflexframegen fg = ofdmflexframegen_create(M, cp_len, taper_len, NULL, &fgprops);
103 
104     // create frame synchronizer
105     ofdmflexframesync fs = ofdmflexframesync_create(M, cp_len, taper_len, NULL, callback, (void*)payload);
106     if (debug)
107         ofdmflexframesync_debug_enable(fs);
108 
109     // initialize header/payload and assemble frame
110     for (i=0; i<8; i++)
111         header[i] = i & 0xff;
112     for (i=0; i<payload_len; i++)
113         payload[i] = rand() & 0xff;
114     ofdmflexframegen_assemble(fg, header, payload, payload_len);
115     ofdmflexframegen_print(fg);
116     ofdmflexframesync_print(fs);
117 
118     // create channel and add impairments
119     channel_cccf channel = channel_cccf_create();
120     channel_cccf_add_awgn(channel, noise_floor, SNRdB);
121     channel_cccf_add_carrier_offset(channel, dphi, 0.0f);
122 
123     // generate frame, push through channel
124     int last_symbol=0;
125     while (!last_symbol) {
126         // generate symbol
127         last_symbol = ofdmflexframegen_write(fg, buf, buf_len);
128 
129         // apply channel to buffer (in place)
130         channel_cccf_execute_block(channel, buf, buf_len, buf);
131 
132         // push samples through synchronizer
133         ofdmflexframesync_execute(fs, buf, buf_len);
134     }
135 
136     // export debugging file
137     if (debug)
138         ofdmflexframesync_debug_print(fs, "ofdmflexframesync_debug.m");
139 
140     // destroy objects
141     ofdmflexframegen_destroy(fg);
142     ofdmflexframesync_destroy(fs);
143     channel_cccf_destroy(channel);
144 
145     printf("done.\n");
146     return 0;
147 }
148 
149 // callback function
callback(unsigned char * _header,int _header_valid,unsigned char * _payload,unsigned int _payload_len,int _payload_valid,framesyncstats_s _stats,void * _userdata)150 int callback(unsigned char *  _header,
151              int              _header_valid,
152              unsigned char *  _payload,
153              unsigned int     _payload_len,
154              int              _payload_valid,
155              framesyncstats_s _stats,
156              void *           _userdata)
157 {
158     printf("**** callback invoked : rssi = %8.3f dB, evm = %8.3f dB, cfo = %8.5f\n", _stats.rssi, _stats.evm, _stats.cfo);
159 
160     unsigned int i;
161 
162     // print header data to standard output
163     printf("  header rx  :");
164     for (i=0; i<8; i++)
165         printf(" %.2X", _header[i]);
166     printf("\n");
167 
168     // print payload data to standard output
169     printf("  payload rx :");
170     for (i=0; i<_payload_len; i++) {
171         printf(" %.2X", _payload[i]);
172         if ( ((i+1)%26)==0 && i !=_payload_len-1 )
173             printf("\n              ");
174     }
175     printf("\n");
176 
177     // count errors in received payload and print to standard output
178     unsigned char * payload_tx = (unsigned char*) _userdata;
179     unsigned int num_errors = count_bit_errors_array(_payload, payload_tx, _payload_len);
180     printf("  bit errors : %u / %u\n", num_errors, 8*_payload_len);
181 
182     return 0;
183 }
184 
185