1 //
2 // flexframesync_example.c
3 //
4 // This example demonstrates the basic interface to the flexframegen and
5 // flexframesync objects used to completely encapsulate raw data bytes
6 // into frame samples (nearly) ready for over-the-air transmission. A
7 // 14-byte header and variable length payload are encoded into baseband
8 // symbols using the flexframegen object. The resulting symbols are
9 // interpolated using a root-Nyquist filter and the resulting samples are
10 // then fed into the flexframesync object which attempts to decode the
11 // frame. Whenever frame is found and properly decoded, its callback
12 // function is invoked.
13 //
14 // SEE ALSO: flexframesync_reconfig_example.c
15 // framesync64_example.c
16 //
17
18 #include <stdio.h>
19 #include <stdlib.h>
20 #include <string.h>
21 #include <math.h>
22 #include <time.h>
23 #include <getopt.h>
24 #include <assert.h>
25
26 #include "liquid.h"
27
usage()28 void usage()
29 {
30 printf("flexframesync_example [options]\n");
31 printf(" u/h : print usage\n");
32 printf(" s : signal-to-noise ratio [dB], default: 20\n");
33 printf(" F : carrier frequency offset, default: 0.01\n");
34 printf(" n : payload length [bytes], default: 480\n");
35 printf(" m : modulation scheme (qpsk default)\n");
36 liquid_print_modulation_schemes();
37 printf(" v : data integrity check: crc32 default\n");
38 liquid_print_crc_schemes();
39 printf(" c : coding scheme (inner): h74 default\n");
40 printf(" k : coding scheme (outer): none default\n");
41 liquid_print_fec_schemes();
42 printf(" d : enable debugging\n");
43 }
44
45 // flexframesync callback function
46 static int callback(unsigned char * _header,
47 int _header_valid,
48 unsigned char * _payload,
49 unsigned int _payload_len,
50 int _payload_valid,
51 framesyncstats_s _stats,
52 void * _userdata);
53
main(int argc,char * argv[])54 int main(int argc, char *argv[])
55 {
56 //srand( time(NULL) );
57
58 // options
59 modulation_scheme ms = LIQUID_MODEM_QPSK; // mod. scheme
60 crc_scheme check = LIQUID_CRC_32; // data validity check
61 fec_scheme fec0 = LIQUID_FEC_NONE; // fec (inner)
62 fec_scheme fec1 = LIQUID_FEC_NONE; // fec (outer)
63 unsigned int payload_len = 480; // payload length
64 int debug_enabled = 0; // enable debugging?
65 float noise_floor = -60.0f; // noise floor
66 float SNRdB = 20.0f; // signal-to-noise ratio
67 float dphi = 0.01f; // carrier frequency offset
68
69 // get options
70 int dopt;
71 while((dopt = getopt(argc,argv,"uhs:F:n:m:v:c:k:d")) != EOF){
72 switch (dopt) {
73 case 'u':
74 case 'h': usage(); return 0;
75 case 's': SNRdB = atof(optarg); break;
76 case 'F': dphi = atof(optarg); break;
77 case 'n': payload_len = atol(optarg); break;
78 case 'm': ms = liquid_getopt_str2mod(optarg); break;
79 case 'v': check = liquid_getopt_str2crc(optarg); break;
80 case 'c': fec0 = liquid_getopt_str2fec(optarg); break;
81 case 'k': fec1 = liquid_getopt_str2fec(optarg); break;
82 case 'd': debug_enabled = 1; break;
83 default:
84 exit(-1);
85 }
86 }
87
88 // derived values
89 unsigned int i;
90 float nstd = powf(10.0f, noise_floor/20.0f); // noise std. dev.
91 float gamma = powf(10.0f, (SNRdB+noise_floor)/20.0f); // channel gain
92
93 // create flexframegen object
94 flexframegenprops_s fgprops;
95 flexframegenprops_init_default(&fgprops);
96 fgprops.mod_scheme = ms;
97 fgprops.check = check;
98 fgprops.fec0 = fec0;
99 fgprops.fec1 = fec1;
100 flexframegen fg = flexframegen_create(&fgprops);
101
102 // create flexframesync object
103 flexframesync fs = flexframesync_create(callback,NULL);
104 if (debug_enabled)
105 flexframesync_debug_enable(fs);
106
107 // assemble the frame (NULL pointers for default values)
108 flexframegen_assemble(fg, NULL, NULL, payload_len);
109 flexframegen_print(fg);
110
111 // generate the frame in blocks
112 unsigned int buf_len = 256;
113 float complex x[buf_len];
114 float complex y[buf_len];
115
116 int frame_complete = 0;
117 float phi = 0.0f;
118 while (!frame_complete) {
119 // write samples to buffer
120 frame_complete = flexframegen_write_samples(fg, x, buf_len);
121
122 // add noise and push through synchronizer
123 for (i=0; i<buf_len; i++) {
124 // apply channel gain and carrier offset to input
125 y[i] = gamma * x[i] * cexpf(_Complex_I*phi);
126 phi += dphi;
127
128 // add noise
129 y[i] += nstd*( randnf() + _Complex_I*randnf())*M_SQRT1_2;
130 }
131
132 // run through frame synchronizer
133 flexframesync_execute(fs, y, buf_len);
134 }
135
136 // export debugging file
137 if (debug_enabled)
138 flexframesync_debug_print(fs, "flexframesync_debug.m");
139
140 flexframesync_print(fs);
141 // destroy allocated objects
142 flexframegen_destroy(fg);
143 flexframesync_destroy(fs);
144
145 printf("done.\n");
146 return 0;
147 }
148
callback(unsigned char * _header,int _header_valid,unsigned char * _payload,unsigned int _payload_len,int _payload_valid,framesyncstats_s _stats,void * _userdata)149 static int callback(unsigned char * _header,
150 int _header_valid,
151 unsigned char * _payload,
152 unsigned int _payload_len,
153 int _payload_valid,
154 framesyncstats_s _stats,
155 void * _userdata)
156 {
157 printf("******** callback invoked\n");
158
159 // count bit errors (assuming all-zero message)
160 unsigned int bit_errors = 0;
161 unsigned int i;
162 for (i=0; i<_payload_len; i++)
163 bit_errors += liquid_count_ones(_payload[i]);
164
165 framesyncstats_print(&_stats);
166 printf(" header crc : %s\n", _header_valid ? "pass" : "FAIL");
167 printf(" payload length : %u\n", _payload_len);
168 printf(" payload crc : %s\n", _payload_valid ? "pass" : "FAIL");
169 printf(" payload bit errors : %u / %u\n", bit_errors, 8*_payload_len);
170
171 return 0;
172 }
173
174