1 /*
2  * Copyright (c) 2007 - 2015 Joseph Gaeddert
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a copy
5  * of this software and associated documentation files (the "Software"), to deal
6  * in the Software without restriction, including without limitation the rights
7  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8  * copies of the Software, and to permit persons to whom the Software is
9  * furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice shall be included in
12  * all copies or substantial portions of the Software.
13  *
14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20  * THE SOFTWARE.
21  */
22 
23 //
24 // gmskframegen.c
25 //
26 
27 #include <stdlib.h>
28 #include <stdio.h>
29 #include <string.h>
30 #include <math.h>
31 #include <assert.h>
32 #include <complex.h>
33 
34 #include "liquid.internal.h"
35 
36 #define DEBUG_GMSKFRAMEGEN    0
37 
38 // gmskframegen
39 void gmskframegen_encode_header( gmskframegen _q, const unsigned char * _header);
40 void gmskframegen_write_preamble(gmskframegen _q, float complex * _y);
41 void gmskframegen_write_header(  gmskframegen _q, float complex * _y);
42 void gmskframegen_write_payload( gmskframegen _q, float complex * _y);
43 void gmskframegen_write_tail(    gmskframegen _q, float complex * _y);
44 
45 
46 // gmskframe object structure
47 struct gmskframegen_s {
48     gmskmod mod;                // GMSK modulator
49     unsigned int k;             // filter samples/symbol
50     unsigned int m;             // filter semi-length (symbols)
51     float BT;                   // filter bandwidth-time product
52 
53     // framing lengths (symbols)
54     unsigned int preamble_len;  //
55     unsigned int header_len;    // length of header (encoded)
56     unsigned int payload_len;   //
57     unsigned int tail_len;      //
58 
59     // preamble
60     //unsigned int genpoly_header;// generator polynomial
61     msequence ms_preamble;      // preamble p/n sequence
62 
63     // header
64     unsigned int header_user_len;
65     unsigned int header_enc_len;
66     unsigned char * header_dec; // uncoded header [header_user_len + GMSKFRAME_H_DEC]
67     unsigned char * header_enc; // encoded header [header_enc_len]
68     packetizer p_header;        // header packetizer
69 
70     // payload
71     packetizer p_payload;       // payload packetizer
72     crc_scheme check;           // CRC
73     fec_scheme fec0;            // inner forward error correction
74     fec_scheme fec1;            // outer forward error correction
75     unsigned int dec_msg_len;   //
76     unsigned int enc_msg_len;   //
77     unsigned char * payload_enc;// encoded payload
78 
79     // framing state
80     enum {
81         STATE_PREAMBLE,         // preamble
82         STATE_HEADER,           // header
83         STATE_PAYLOAD,          // payload (frame)
84         STATE_TAIL,             // tail symbols
85     } state;
86     int frame_assembled;        // frame assembled flag
87     int frame_complete;         // frame completed flag
88     unsigned int symbol_counter;//
89 };
90 
91 // create gmskframegen object
gmskframegen_create()92 gmskframegen gmskframegen_create()
93 {
94     gmskframegen q = (gmskframegen) malloc(sizeof(struct gmskframegen_s));
95 
96     // set internal properties
97     q->k  = 2;      // samples/symbol
98     q->m  = 3;      // filter delay (symbols)
99     q->BT = 0.5f;   // filter bandwidth-time product
100 
101     // internal/derived values
102     q->preamble_len = 63;       // number of preamble symbols
103     q->payload_len  =  0;       // number of payload symbols
104     q->tail_len     = 2*q->m;   // number of tail symbols (flush interp)
105 
106     // create modulator
107     q->mod = gmskmod_create(q->k, q->m, q->BT);
108 
109     // preamble objects/arrays
110     q->ms_preamble = msequence_create(6, 0x6d, 1);
111 
112     // reset framing object
113     gmskframegen_reset(q);
114 
115     q->header_dec = NULL;
116     q->header_enc = NULL;
117     q->p_header   = NULL;
118     gmskframegen_set_header_len(q, GMSKFRAME_H_USER_DEFAULT);
119 
120     // payload objects/arrays
121     q->dec_msg_len = 0;
122     q->check = LIQUID_CRC_32;
123     q->fec0  = LIQUID_FEC_NONE;
124     q->fec1  = LIQUID_FEC_NONE;
125 
126     q->p_payload = packetizer_create(q->dec_msg_len,
127                                      q->check,
128                                      q->fec0,
129                                      q->fec1);
130     q->enc_msg_len = packetizer_get_enc_msg_len(q->p_payload);
131     q->payload_len = 8*q->enc_msg_len;
132 
133     // allocate memory for encoded packet
134     q->payload_enc = (unsigned char*) malloc(q->enc_msg_len*sizeof(unsigned char));
135 
136     // return object
137     return q;
138 }
139 
140 // destroy gmskframegen object
gmskframegen_destroy(gmskframegen _q)141 void gmskframegen_destroy(gmskframegen _q)
142 {
143     // destroy gmsk modulator
144     gmskmod_destroy(_q->mod);
145 
146     // destroy/free preamble objects/arrays
147     msequence_destroy(_q->ms_preamble);
148 
149     // destroy/free header objects/arrays
150     free(_q->header_dec);
151     free(_q->header_enc);
152     packetizer_destroy(_q->p_header);
153 
154     // destroy/free payload objects/arrays
155     free(_q->payload_enc);
156     packetizer_destroy(_q->p_payload);
157 
158     // free main object memory
159     free(_q);
160 }
161 
162 // reset frame generator object
gmskframegen_reset(gmskframegen _q)163 void gmskframegen_reset(gmskframegen _q)
164 {
165     // reset GMSK modulator
166     gmskmod_reset(_q->mod);
167 
168     // reset states
169     _q->state = STATE_PREAMBLE;
170     msequence_reset(_q->ms_preamble);
171     _q->frame_assembled = 0;
172     _q->frame_complete  = 0;
173     _q->symbol_counter  = 0;
174 }
175 
176 // is frame assembled?
gmskframegen_is_assembled(gmskframegen _q)177 int gmskframegen_is_assembled(gmskframegen _q)
178 {
179     return _q->frame_assembled;
180 }
181 
182 // print gmskframegen object internals
gmskframegen_print(gmskframegen _q)183 void gmskframegen_print(gmskframegen _q)
184 {
185     // plot
186     printf("gmskframegen:\n");
187     printf("  physical properties\n");
188     printf("    samples/symbol  :   %u\n", _q->k);
189     printf("    filter delay    :   %u symbols\n", _q->m);
190     printf("    bandwidth-time  :   %-8.3f\n", _q->BT);
191     printf("  framing properties\n");
192     printf("    preamble        :   %-4u symbols\n", _q->preamble_len);
193     printf("    header          :   %-4u symbols\n", _q->header_len);
194     printf("    payload         :   %-4u symbols\n", _q->payload_len);
195     printf("    tail            :   %-4u symbols\n", _q->tail_len);
196     printf("  packet properties\n");
197     printf("    crc             :   %s\n", crc_scheme_str[_q->check][1]);
198     printf("    fec (inner)     :   %s\n", fec_scheme_str[_q->fec0][1]);
199     printf("    fec (outer)     :   %s\n", fec_scheme_str[_q->fec1][1]);
200     printf("  total samples     :   %-4u sampels\n", gmskframegen_getframelen(_q));
201 }
202 
gmskframegen_set_header_len(gmskframegen _q,unsigned int _len)203 void gmskframegen_set_header_len(gmskframegen _q,
204                                  unsigned int _len)
205 {
206     if (_q->frame_assembled) {
207         fprintf(stderr, "warning: gmskframegen_set_header_len(), frame is already assembled; must reset() first\n");
208         return;
209     }
210 
211     _q->header_user_len = _len;
212     unsigned int header_dec_len = GMSKFRAME_H_DEC + _q->header_user_len;
213     _q->header_dec = (unsigned char*)realloc(_q->header_dec, header_dec_len*sizeof(unsigned char));
214 
215     if (_q->p_header) {
216         packetizer_destroy(_q->p_header);
217     }
218 
219     _q->p_header = packetizer_create(header_dec_len,
220                                      GMSKFRAME_H_CRC,
221                                      GMSKFRAME_H_FEC,
222                                      LIQUID_FEC_NONE);
223 
224     _q->header_enc_len = packetizer_get_enc_msg_len(_q->p_header);
225     _q->header_enc = (unsigned char*)realloc(_q->header_enc, _q->header_enc_len*sizeof(unsigned char));
226     _q->header_len = _q->header_enc_len * 8;
227 }
228 
229 // assemble frame
230 //  _q              :   frame generator object
231 //  _header         :   raw header
232 //  _payload        :   raw payload [size: _payload_len x 1]
233 //  _payload_len    :   raw payload length (bytes)
234 //  _check          :   data validity check
235 //  _fec0           :   inner forward error correction
236 //  _fec1           :   outer forward error correction
gmskframegen_assemble(gmskframegen _q,const unsigned char * _header,const unsigned char * _payload,unsigned int _payload_len,crc_scheme _check,fec_scheme _fec0,fec_scheme _fec1)237 void gmskframegen_assemble(gmskframegen          _q,
238                            const unsigned char * _header,
239                            const unsigned char * _payload,
240                            unsigned int          _payload_len,
241                            crc_scheme            _check,
242                            fec_scheme            _fec0,
243                            fec_scheme            _fec1)
244 {
245     // re-create frame generator if properties don't match
246     if (_q->dec_msg_len != _payload_len ||
247         _q->check       != _check       ||
248         _q->fec0        != _fec0        ||
249         _q->fec1        != _fec1)
250     {
251         // set properties
252         _q->dec_msg_len = _payload_len;
253         _q->check       = _check;
254         _q->fec0        = _fec0;
255         _q->fec1        = _fec1;
256 
257         // re-create payload packetizer
258         _q->p_payload = packetizer_recreate(_q->p_payload, _q->dec_msg_len, _q->check, _q->fec0, _q->fec1);
259 
260         // get packet length
261         _q->enc_msg_len = packetizer_get_enc_msg_len(_q->p_payload);
262         _q->payload_len = 8*_q->enc_msg_len;
263 
264         // re-allocate memory
265         _q->payload_enc = (unsigned char*) realloc(_q->payload_enc, _q->enc_msg_len*sizeof(unsigned char));
266     }
267 
268     // set assembled flag
269     _q->frame_assembled = 1;
270 
271     // encode header
272     gmskframegen_encode_header(_q, _header);
273 
274     // encode payload
275     packetizer_encode(_q->p_payload, _payload, _q->payload_enc);
276 }
277 
278 // get frame length (number of samples)
gmskframegen_getframelen(gmskframegen _q)279 unsigned int gmskframegen_getframelen(gmskframegen _q)
280 {
281     if (!_q->frame_assembled) {
282         fprintf(stderr,"warning: gmskframegen_getframelen(), frame not assembled!\n");
283         return 0;
284     }
285 
286     unsigned int num_frame_symbols =
287             _q->preamble_len +      // number of preamble p/n symbols
288             _q->header_len +        // number of header symbols
289             _q->payload_len +       // number of payload symbols
290             2*_q->m;                // number of tail symbols
291 
292     return num_frame_symbols*_q->k; // k samples/symbol
293 }
294 
295 // write sample to output buffer
gmskframegen_write_samples(gmskframegen _q,float complex * _y)296 int gmskframegen_write_samples(gmskframegen _q,
297                                float complex * _y)
298 {
299     switch (_q->state) {
300     case STATE_PREAMBLE:
301         // write preamble
302         gmskframegen_write_preamble(_q, _y);
303         break;
304 
305     case STATE_HEADER:
306         // write header
307         gmskframegen_write_header(_q, _y);
308         break;
309 
310     case STATE_PAYLOAD:
311         // write payload symbols
312         gmskframegen_write_payload(_q, _y);
313         break;
314 
315     case STATE_TAIL:
316         // write tail symbols
317         gmskframegen_write_tail(_q, _y);
318         break;
319 
320     default:
321         fprintf(stderr,"error: gmskframegen_writesymbol(), unknown/unsupported internal state\n");
322         exit(1);
323     }
324 
325     if (_q->frame_complete) {
326         // reset framing object
327 #if DEBUG_GMSKFRAMEGEN
328         printf(" ...resetting...\n");
329 #endif
330         gmskframegen_reset(_q);
331         return 1;
332     }
333 
334     return 0;
335 }
336 
337 
338 //
339 // internal methods
340 //
341 
gmskframegen_encode_header(gmskframegen _q,const unsigned char * _header)342 void gmskframegen_encode_header(gmskframegen          _q,
343                                 const unsigned char * _header)
344 {
345     // first 'n' bytes user data
346     memmove(_q->header_dec, _header, _q->header_user_len);
347     unsigned int n = _q->header_user_len;
348 
349     // first byte is for expansion/version validation
350     _q->header_dec[n+0] = GMSKFRAME_VERSION;
351 
352     // add payload length
353     _q->header_dec[n+1] = (_q->dec_msg_len >> 8) & 0xff;
354     _q->header_dec[n+2] = (_q->dec_msg_len     ) & 0xff;
355 
356     // add CRC, forward error-correction schemes
357     //  CRC     : most-significant 3 bits of [n+4]
358     //  fec0    : least-significant 5 bits of [n+4]
359     //  fec1    : least-significant 5 bits of [n+5]
360     _q->header_dec[n+3]  = (_q->check & 0x07) << 5;
361     _q->header_dec[n+3] |= (_q->fec0) & 0x1f;
362     _q->header_dec[n+4]  = (_q->fec1) & 0x1f;
363 
364     // run packet encoder
365     packetizer_encode(_q->p_header, _q->header_dec, _q->header_enc);
366 
367     // scramble header
368     scramble_data(_q->header_enc, _q->header_enc_len);
369 #if 0
370     printf("    header_enc      :");
371     unsigned int i;
372     for (i=0; i<GMSKFRAME_H_ENC; i++)
373         printf(" %.2X", _q->header_enc[i]);
374     printf("\n");
375 #endif
376 }
377 
gmskframegen_write_preamble(gmskframegen _q,float complex * _y)378 void gmskframegen_write_preamble(gmskframegen    _q,
379                                  float complex * _y)
380 {
381     unsigned char bit = msequence_advance(_q->ms_preamble);
382     gmskmod_modulate(_q->mod, bit, _y);
383 
384     // apply ramping window to first 'm' symbols
385     if (_q->symbol_counter < _q->m) {
386         unsigned int i;
387         for (i=0; i<_q->k; i++)
388             _y[i] *= hamming(_q->symbol_counter*_q->k + i, 2*_q->m*_q->k);
389     }
390 
391     _q->symbol_counter++;
392 
393     if (_q->symbol_counter == _q->preamble_len) {
394         msequence_reset(_q->ms_preamble);
395         _q->symbol_counter = 0;
396         _q->state = STATE_HEADER;
397     }
398 }
399 
gmskframegen_write_header(gmskframegen _q,float complex * _y)400 void gmskframegen_write_header(gmskframegen    _q,
401                                float complex * _y)
402 {
403     div_t d = div(_q->symbol_counter, 8);
404     unsigned int byte_index = d.quot;
405     unsigned int bit_index  = d.rem;
406     unsigned char byte = _q->header_enc[byte_index];
407     unsigned char bit  = (byte >> (8-bit_index-1)) & 0x01;
408 
409     gmskmod_modulate(_q->mod, bit, _y);
410 
411     _q->symbol_counter++;
412 
413     if (_q->symbol_counter == _q->header_len) {
414         _q->symbol_counter = 0;
415         _q->state = STATE_PAYLOAD;
416     }
417 }
418 
gmskframegen_write_payload(gmskframegen _q,float complex * _y)419 void gmskframegen_write_payload(gmskframegen    _q,
420                                 float complex * _y)
421 {
422     div_t d = div(_q->symbol_counter, 8);
423     unsigned int byte_index = d.quot;
424     unsigned int bit_index  = d.rem;
425     unsigned char byte = _q->payload_enc[byte_index];
426     unsigned char bit  = (byte >> (8-bit_index-1)) & 0x01;
427 
428     gmskmod_modulate(_q->mod, bit, _y);
429 
430     _q->symbol_counter++;
431 
432     if (_q->symbol_counter == _q->payload_len) {
433         _q->symbol_counter = 0;
434         _q->state = STATE_TAIL;
435     }
436 }
437 
gmskframegen_write_tail(gmskframegen _q,float complex * _y)438 void gmskframegen_write_tail(gmskframegen    _q,
439                              float complex * _y)
440 {
441     unsigned char bit = rand() % 2;
442     gmskmod_modulate(_q->mod, bit, _y);
443 
444     // apply ramping window to last 'm' symbols
445     if (_q->symbol_counter >= _q->m) {
446         unsigned int i;
447         for (i=0; i<_q->k; i++)
448             _y[i] *= hamming(_q->m*_q->k + (_q->symbol_counter-_q->m)*_q->k + i, 2*_q->m*_q->k);
449     }
450 
451     _q->symbol_counter++;
452 
453     if (_q->symbol_counter == _q->tail_len) {
454         _q->symbol_counter = 0;
455         _q->frame_complete = 1;
456     }
457 }
458 
459