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