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