1 //
2 // dsssframesync_example.c
3 //
4 
5 #include <assert.h>
6 #include <getopt.h>
7 #include <math.h>
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <string.h>
11 #include <time.h>
12 
13 #include "liquid.h"
14 
usage()15 void usage()
16 {
17     printf("dsssframesync_example [options]\n");
18     printf("  u/h   : print usage\n");
19     printf("  s     : signal-to-noise ratio [dB], default: 20\n");
20     printf("  F     : carrier frequency offset, default: 0.01\n");
21     printf("  n     : payload length [bytes], default: 480\n");
22     printf("  v     : data integrity check: crc32 default\n");
23     liquid_print_crc_schemes();
24     printf("  c     : coding scheme (inner): h74 default\n");
25     printf("  k     : coding scheme (outer): none default\n");
26     liquid_print_fec_schemes();
27     printf("  d     : enable debugging\n");
28 }
29 
30 // dsssframesync callback function
31 static int callback(unsigned char *  _header,
32                     int              _header_valid,
33                     unsigned char *  _payload,
34                     unsigned int     _payload_len,
35                     int              _payload_valid,
36                     framesyncstats_s _stats,
37                     void *           _userdata);
38 
main(int argc,char * argv[])39 int main(int argc, char * argv[])
40 {
41     srand(time(NULL));
42 
43     // options
44     crc_scheme   check         = LIQUID_CRC_32;   // data validity check
45     fec_scheme   fec0          = LIQUID_FEC_NONE; // fec (inner)
46     fec_scheme   fec1          = LIQUID_FEC_NONE; // fec (outer)
47     unsigned int payload_len   = 20;              // payload length
48     int          debug_enabled = 0;               // enable debugging?
49     float        noise_floor   = -60.0f;          // noise floor
50     float        SNRdB         = -3.0f;           // signal-to-noise ratio
51     float        dphi          = 0.03f;           // carrier frequency offset
52 
53     // get options
54     int dopt;
55     while ((dopt = getopt(argc, argv, "uhs:F:n:m:v:c:k:d")) != EOF) {
56         switch (dopt) {
57         case 'u':
58         case 'h': usage(); return 0;
59         case 's': SNRdB = atof(optarg); break;
60         case 'F': dphi = atof(optarg); break;
61         case 'n': payload_len = atol(optarg); break;
62         case 'v': check = liquid_getopt_str2crc(optarg); break;
63         case 'c': fec0 = liquid_getopt_str2fec(optarg); break;
64         case 'k': fec1 = liquid_getopt_str2fec(optarg); break;
65         case 'd': debug_enabled = 1; break;
66         default: exit(-1);
67         }
68     }
69 
70     // derived values
71     unsigned int i;
72     float        nstd  = powf(10.0f, noise_floor / 20.0f);           // noise std. dev.
73     float        gamma = powf(10.0f, (SNRdB + noise_floor) / 20.0f); // channel gain
74 
75     // create dsssframegen object
76     dsssframegenprops_s fgprops;
77     fgprops.check   = check;
78     fgprops.fec0    = fec0;
79     fgprops.fec1    = fec1;
80     dsssframegen fg = dsssframegen_create(&fgprops);
81 
82     // create dsssframesync object
83     dsssframesync fs = dsssframesync_create(callback, NULL);
84     if (debug_enabled) {
85         // dsssframesync_debug_enable(fs);
86     }
87 
88     // assemble the frame (NULL pointers for default values)
89     dsssframegen_assemble(fg, NULL, NULL, payload_len);
90     // dsssframegen_print(fg);
91 
92     // generate the frame in blocks
93     unsigned int buf_len  = 256;
94     float complex x[buf_len];
95     float complex y[buf_len];
96 
97     int   frame_complete = 0;
98     float phi            = 0.0f;
99     while (!frame_complete) {
100         frame_complete = dsssframegen_write_samples(fg, x, buf_len);
101 
102         // add noise and push through synchronizer
103         for (i = 0; i < buf_len; i++) {
104             // apply channel gain and carrier offset to input
105             y[i] = gamma * x[i] * cexpf(_Complex_I * phi);
106             phi += dphi;
107 
108             // add noise
109             y[i] += nstd * (randnf() + _Complex_I * randnf()) * M_SQRT1_2;
110         }
111 
112         // run through frame synchronizer
113         dsssframesync_execute(fs, y, buf_len);
114     }
115 
116     // export debugging file
117     if (debug_enabled) {
118         // dsssframesync_debug_print(fs, "dsssframesync_debug.m");
119     }
120 
121     // dsssframesync_print(fs);
122     // destroy allocated objects
123     dsssframegen_destroy(fg);
124     dsssframesync_destroy(fs);
125 
126     printf("done.\n");
127     return 0;
128 }
129 
callback(unsigned char * _header,int _header_valid,unsigned char * _payload,unsigned int _payload_len,int _payload_valid,framesyncstats_s _stats,void * _userdata)130 static int callback(unsigned char *  _header,
131                     int              _header_valid,
132                     unsigned char *  _payload,
133                     unsigned int     _payload_len,
134                     int              _payload_valid,
135                     framesyncstats_s _stats,
136                     void *           _userdata)
137 {
138     printf("******** callback invoked\n");
139 
140     // count bit errors (assuming all-zero message)
141     unsigned int bit_errors = 0;
142     unsigned int i;
143     for (i = 0; i < _payload_len; i++)
144         bit_errors += liquid_count_ones(_payload[i]);
145 
146     framesyncstats_print(&_stats);
147     printf("    header crc          :   %s\n", _header_valid ? "pass" : "FAIL");
148     printf("    payload length      :   %u\n", _payload_len);
149     printf("    payload crc         :   %s\n", _payload_valid ? "pass" : "FAIL");
150     printf("    payload bit errors  :   %u / %u\n", bit_errors, 8 * _payload_len);
151 
152     return 0;
153 }
154