1 //
2 // gmskframesync_example.c
3 //
4 // Example demonstrating the GMSK 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 
16 #define OUTPUT_FILENAME "gmskframesync_example.m"
17 
usage()18 void usage()
19 {
20     printf("gmskframesync_example [options]\n");
21     printf("  h     : print help\n");
22     printf("  d     : enable internal synchronizer debugging\n");
23     printf("  n     : frame length [bytes], default: 40\n");
24     printf("  v     : data integrity check: crc32 default\n");
25     liquid_print_crc_schemes();
26     printf("  c     : coding scheme (inner): h74 default\n");
27     printf("  k     : coding scheme (outer): none default\n");
28     liquid_print_fec_schemes();
29     printf("  s     : signal-to-noise ratio [dB], default: 30\n");
30     printf("  F     : carrier frequency offset, default: 0.05\n");
31 }
32 
33 struct framedata_s {
34     unsigned char * payload;
35     unsigned int payload_len;
36 };
37 
38 // callback function
39 int callback(unsigned char *  _header,
40              int              _header_valid,
41              unsigned char *  _payload,
42              unsigned int     _payload_len,
43              int              _payload_valid,
44              framesyncstats_s _stats,
45              void *           _userdata);
46 
main(int argc,char * argv[])47 int main(int argc, char*argv[])
48 {
49     srand(time(NULL));
50 
51     unsigned int payload_len = 40;  // length of payload (bytes)
52     crc_scheme check = LIQUID_CRC_32;
53     fec_scheme fec0  = LIQUID_FEC_HAMMING128;
54     fec_scheme fec1  = LIQUID_FEC_NONE;
55     float noise_floor = -60.0f;     // noise floor
56     float SNRdB = 30.0f;            // signal-to-noise ratio [dB]
57     float dphi  = 0.05f;            // carrier offset
58 
59     int debug_enabled = 0;          // debug option
60 
61     // get options
62     int dopt;
63     while((dopt = getopt(argc,argv,"hdn:v:c:k:s:F:")) != EOF){
64         switch (dopt) {
65         case 'u':
66         case 'h': usage();                      return 0;
67         case 'd': debug_enabled = 1;            break;
68         case 'n': payload_len   = atoi(optarg); break;
69         case 'v':
70             // data integrity check
71             check = liquid_getopt_str2crc(optarg);
72             if (check == LIQUID_CRC_UNKNOWN) {
73                 fprintf(stderr,"error: unknown/unsupported CRC scheme \"%s\"\n\n",optarg);
74                 exit(1);
75             }
76             break;
77         case 'c':
78             // inner FEC scheme
79             fec0 = liquid_getopt_str2fec(optarg);
80             if (fec0 == LIQUID_FEC_UNKNOWN) {
81                 fprintf(stderr,"error: unknown/unsupported inner FEC scheme \"%s\"\n\n",optarg);
82                 exit(1);
83             }
84             break;
85         case 'k':
86             // outer FEC scheme
87             fec1 = liquid_getopt_str2fec(optarg);
88             if (fec1 == LIQUID_FEC_UNKNOWN) {
89                 fprintf(stderr,"error: unknown/unsupported outer FEC scheme \"%s\"\n\n",optarg);
90                 exit(1);
91             }
92             break;
93         case 's': SNRdB         = atof(optarg); break;
94         case 'F': dphi          = atof(optarg); break;
95         default:
96             exit(1);
97         }
98     }
99 
100     unsigned int i;
101 
102     // fixed values
103     unsigned int k = 2;
104 
105     // derived values
106     float nstd  = powf(10.0f, noise_floor/20.0f);
107     float gamma = powf(10.0f, (SNRdB + noise_floor)/20.0f);
108 
109     // allocate memory for payload and initialize
110     unsigned char header[8];
111     unsigned char payload[payload_len];
112     for (i=0; i<8; i++)           header[i]  = i;
113     for (i=0; i<payload_len; i++) payload[i] = rand() & 0xff;
114     struct framedata_s fd = {payload, payload_len};
115 
116     // create frame generator
117     gmskframegen fg = gmskframegen_create();
118 
119     // create frame synchronizer
120     gmskframesync fs = gmskframesync_create(callback, (void*)&fd);
121     if (debug_enabled)
122         gmskframesync_debug_enable(fs);
123 
124     // assemble frame and print
125     gmskframegen_assemble(fg, header, payload, payload_len, check, fec0, fec1);
126     gmskframegen_print(fg);
127 
128     // allocate memory for full frame (with noise)
129     unsigned int frame_len = gmskframegen_getframelen(fg);
130     unsigned int num_samples = (frame_len * k) + 800;
131     float complex x[num_samples];
132     float complex y[num_samples];
133 
134     //
135     // generate frame
136     //
137     unsigned int n=0;
138     for (n=0; n<600; n++)
139         x[n] = 0.0f;
140     int frame_complete = 0;
141     while (!frame_complete) {
142         frame_complete = gmskframegen_write_samples(fg, &x[n]);
143         n += k;
144     }
145     for ( ; n<num_samples; n++)
146         x[n] = 0.0f;
147 
148     // add channel impairments
149     for (i=0; i<num_samples; i++) {
150         y[i]  = x[i];
151         y[i] *= gamma;
152         y[i] *= cexpf(_Complex_I*M_2_PI*dphi*i);
153         y[i] += nstd*(randnf() + randnf()*_Complex_I)*M_SQRT1_2;
154     }
155 
156     // push samples through synchronizer
157     gmskframesync_execute(fs, y, num_samples);
158 
159     // write debug output if enabled
160     if (debug_enabled)
161         gmskframesync_debug_print(fs, "gmskframesync_debug.m");
162 
163     // destroy objects
164     gmskframegen_destroy(fg);
165     gmskframesync_destroy(fs);
166 
167 
168     //
169     // export output
170     //
171     FILE * fid = fopen(OUTPUT_FILENAME,"w");
172     if (fid == NULL) {
173         fprintf(stderr,"error: %s, could not open '%s' for writing\n", argv[0], OUTPUT_FILENAME);
174         exit(1);
175     }
176     fprintf(fid,"%% %s : auto-generated file\n", OUTPUT_FILENAME);
177     fprintf(fid,"\n");
178     fprintf(fid,"clear all\n");
179     fprintf(fid,"close all\n");
180     fprintf(fid,"\n");
181     fprintf(fid,"num_samples = %u;\n", num_samples);
182     fprintf(fid,"y = zeros(1,num_samples);\n");
183     fprintf(fid,"\n");
184 
185     for (i=0; i<num_samples; i++)
186         fprintf(fid,"y(%6u) = %12.4e + j*%12.4e;\n", i+1, crealf(y[i]), cimagf(y[i]));
187 
188     fprintf(fid,"\n");
189     fprintf(fid,"t = 0:(num_samples-1);\n");
190     fprintf(fid,"figure;\n");
191     fprintf(fid,"plot(t, real(y), t,imag(y));\n");
192     fprintf(fid,"xlabel('time');\n");
193     fprintf(fid,"ylabel('received signal');\n");
194     fprintf(fid,"legend('real','imag',0);\n");
195     fclose(fid);
196     printf("results written to '%s'\n", OUTPUT_FILENAME);
197 
198     printf("done.\n");
199     return 0;
200 }
201 
202 // callback function
callback(unsigned char * _header,int _header_valid,unsigned char * _payload,unsigned int _payload_len,int _payload_valid,framesyncstats_s _stats,void * _userdata)203 int callback(unsigned char *  _header,
204              int              _header_valid,
205              unsigned char *  _payload,
206              unsigned int     _payload_len,
207              int              _payload_valid,
208              framesyncstats_s _stats,
209              void *           _userdata)
210 {
211     printf("***** callback invoked *****\n");
212     printf("  header crc    :   %s\n", _header_valid ? "pass" : "FAIL");
213     printf("  header data   :  ");
214     unsigned int i;
215     for (i=0; i<8; i++)
216         printf(" %.2X", _header[i]);
217     printf("\n");
218     printf("  rssi          :   %-8.3f dB\n", _stats.rssi);
219     printf("  evm           :   %-8.3f dB\n", _stats.evm);
220     printf("  payload       :   %u bytes (crc %s)\n", _payload_len, _payload_valid ? "pass" : "FAIL");
221     printf("  check         :   %s\n", crc_scheme_str[_stats.check][1]);
222     printf("  fec (inner)   :   %s\n", fec_scheme_str[_stats.fec0][1]);
223     printf("  fec (outer)   :   %s\n", fec_scheme_str[_stats.fec1][1]);
224 
225     // count errors
226     struct framedata_s * fd = (struct framedata_s *) _userdata;
227     unsigned int bit_errors = count_bit_errors_array(fd->payload, _payload, _payload_len);
228     printf("  bit errors    :   %-4u / %-4u\n", bit_errors, 8*_payload_len);
229 
230     return 0;
231 }
232 
233