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