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