comparison spandsp-0.0.6pre17/src/fsk.c @ 4:26cd8f1ef0b1

import spandsp-0.0.6pre17
author Peter Meerwald <pmeerw@cosy.sbg.ac.at>
date Fri, 25 Jun 2010 15:50:58 +0200
parents
children
comparison
equal deleted inserted replaced
3:c6c5a16ce2f2 4:26cd8f1ef0b1
1 /*
2 * SpanDSP - a series of DSP components for telephony
3 *
4 * fsk.c - FSK modem transmit and receive parts
5 *
6 * Written by Steve Underwood <steveu@coppice.org>
7 *
8 * Copyright (C) 2003 Steve Underwood
9 *
10 * All rights reserved.
11 *
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU Lesser General Public License version 2.1,
14 * as published by the Free Software Foundation.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Lesser General Public License for more details.
20 *
21 * You should have received a copy of the GNU Lesser General Public
22 * License along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 *
25 * $Id: fsk.c,v 1.60 2009/11/02 13:25:20 steveu Exp $
26 */
27
28 /*! \file */
29
30 #if defined(HAVE_CONFIG_H)
31 #include "config.h"
32 #endif
33
34 #include <stdlib.h>
35 #include <inttypes.h>
36 #include <string.h>
37 #if defined(HAVE_TGMATH_H)
38 #include <tgmath.h>
39 #endif
40 #if defined(HAVE_MATH_H)
41 #include <math.h>
42 #endif
43 #include "floating_fudge.h"
44 #include <assert.h>
45
46 #include "spandsp/telephony.h"
47 #include "spandsp/complex.h"
48 #include "spandsp/dds.h"
49 #include "spandsp/power_meter.h"
50 #include "spandsp/async.h"
51 #include "spandsp/fsk.h"
52
53 #include "spandsp/private/fsk.h"
54
55 const fsk_spec_t preset_fsk_specs[] =
56 {
57 {
58 "V21 ch 1",
59 1080 + 100,
60 1080 - 100,
61 -14,
62 -30,
63 300*100
64 },
65 {
66 "V21 ch 2",
67 1750 + 100,
68 1750 - 100,
69 -14,
70 -30,
71 300*100
72 },
73 {
74 "V23 ch 1",
75 2100,
76 1300,
77 -14,
78 -30,
79 1200*100
80 },
81 {
82 "V23 ch 2",
83 450,
84 390,
85 -14,
86 -30,
87 75*100
88 },
89 {
90 "Bell103 ch 1",
91 2125 - 100,
92 2125 + 100,
93 -14,
94 -30,
95 300*100
96 },
97 {
98 "Bell103 ch 2",
99 1170 - 100,
100 1170 + 100,
101 -14,
102 -30,
103 300*100
104 },
105 {
106 "Bell202",
107 2200,
108 1200,
109 -14,
110 -30,
111 1200*100
112 },
113 {
114 "Weitbrecht 45.45", /* Used for TDD (Telecoms Device for the Deaf) */
115 1800,
116 1400,
117 -14,
118 -30,
119 4545
120 },
121 {
122 "Weitbrecht 50", /* Used for TDD (Telecoms Device for the Deaf) */
123 1800,
124 1400,
125 -14,
126 -30,
127 5000
128 }
129 };
130
131 SPAN_DECLARE(int) fsk_tx_restart(fsk_tx_state_t *s, const fsk_spec_t *spec)
132 {
133 s->baud_rate = spec->baud_rate;
134 s->phase_rates[0] = dds_phase_rate((float) spec->freq_zero);
135 s->phase_rates[1] = dds_phase_rate((float) spec->freq_one);
136 s->scaling = dds_scaling_dbm0((float) spec->tx_level);
137 /* Initialise fractional sample baud generation. */
138 s->phase_acc = 0;
139 s->baud_frac = 0;
140 s->current_phase_rate = s->phase_rates[1];
141
142 s->shutdown = FALSE;
143 return 0;
144 }
145 /*- End of function --------------------------------------------------------*/
146
147 SPAN_DECLARE(fsk_tx_state_t *) fsk_tx_init(fsk_tx_state_t *s,
148 const fsk_spec_t *spec,
149 get_bit_func_t get_bit,
150 void *user_data)
151 {
152 if (s == NULL)
153 {
154 if ((s = (fsk_tx_state_t *) malloc(sizeof(*s))) == NULL)
155 return NULL;
156 }
157 memset(s, 0, sizeof(*s));
158
159 s->get_bit = get_bit;
160 s->get_bit_user_data = user_data;
161 fsk_tx_restart(s, spec);
162 return s;
163 }
164 /*- End of function --------------------------------------------------------*/
165
166 SPAN_DECLARE(int) fsk_tx_release(fsk_tx_state_t *s)
167 {
168 return 0;
169 }
170 /*- End of function --------------------------------------------------------*/
171
172 SPAN_DECLARE(int) fsk_tx_free(fsk_tx_state_t *s)
173 {
174 free(s);
175 return 0;
176 }
177 /*- End of function --------------------------------------------------------*/
178
179 SPAN_DECLARE_NONSTD(int) fsk_tx(fsk_tx_state_t *s, int16_t amp[], int len)
180 {
181 int sample;
182 int bit;
183
184 if (s->shutdown)
185 return 0;
186 /* Make the transitions between 0 and 1 phase coherent, but instantaneous
187 jumps. There is currently no interpolation for bauds that end mid-sample.
188 Mainstream users will not care. Some specialist users might have a problem
189 with them, if they care about accurate transition timing. */
190 for (sample = 0; sample < len; sample++)
191 {
192 if ((s->baud_frac += s->baud_rate) >= SAMPLE_RATE*100)
193 {
194 s->baud_frac -= SAMPLE_RATE*100;
195 if ((bit = s->get_bit(s->get_bit_user_data)) == SIG_STATUS_END_OF_DATA)
196 {
197 if (s->status_handler)
198 s->status_handler(s->status_user_data, SIG_STATUS_END_OF_DATA);
199 if (s->status_handler)
200 s->status_handler(s->status_user_data, SIG_STATUS_SHUTDOWN_COMPLETE);
201 s->shutdown = TRUE;
202 break;
203 }
204 s->current_phase_rate = s->phase_rates[bit & 1];
205 }
206 amp[sample] = dds_mod(&(s->phase_acc), s->current_phase_rate, s->scaling, 0);
207 }
208 return sample;
209 }
210 /*- End of function --------------------------------------------------------*/
211
212 SPAN_DECLARE(void) fsk_tx_power(fsk_tx_state_t *s, float power)
213 {
214 s->scaling = dds_scaling_dbm0(power);
215 }
216 /*- End of function --------------------------------------------------------*/
217
218 SPAN_DECLARE(void) fsk_tx_set_get_bit(fsk_tx_state_t *s, get_bit_func_t get_bit, void *user_data)
219 {
220 s->get_bit = get_bit;
221 s->get_bit_user_data = user_data;
222 }
223 /*- End of function --------------------------------------------------------*/
224
225 SPAN_DECLARE(void) fsk_tx_set_modem_status_handler(fsk_tx_state_t *s, modem_tx_status_func_t handler, void *user_data)
226 {
227 s->status_handler = handler;
228 s->status_user_data = user_data;
229 }
230 /*- End of function --------------------------------------------------------*/
231
232 SPAN_DECLARE(void) fsk_rx_signal_cutoff(fsk_rx_state_t *s, float cutoff)
233 {
234 /* The 6.04 allows for the gain of the DC blocker */
235 s->carrier_on_power = (int32_t) (power_meter_level_dbm0(cutoff + 2.5f - 6.04f));
236 s->carrier_off_power = (int32_t) (power_meter_level_dbm0(cutoff - 2.5f - 6.04f));
237 }
238 /*- End of function --------------------------------------------------------*/
239
240 SPAN_DECLARE(float) fsk_rx_signal_power(fsk_rx_state_t *s)
241 {
242 return power_meter_current_dbm0(&s->power);
243 }
244 /*- End of function --------------------------------------------------------*/
245
246 SPAN_DECLARE(void) fsk_rx_set_put_bit(fsk_rx_state_t *s, put_bit_func_t put_bit, void *user_data)
247 {
248 s->put_bit = put_bit;
249 s->put_bit_user_data = user_data;
250 }
251 /*- End of function --------------------------------------------------------*/
252
253 SPAN_DECLARE(void) fsk_rx_set_modem_status_handler(fsk_rx_state_t *s, modem_tx_status_func_t handler, void *user_data)
254 {
255 s->status_handler = handler;
256 s->status_user_data = user_data;
257 }
258 /*- End of function --------------------------------------------------------*/
259
260 SPAN_DECLARE(int) fsk_rx_restart(fsk_rx_state_t *s, const fsk_spec_t *spec, int framing_mode)
261 {
262 int chop;
263
264 s->baud_rate = spec->baud_rate;
265 s->framing_mode = framing_mode;
266 fsk_rx_signal_cutoff(s, (float) spec->min_level);
267
268 /* Detect by correlating against the tones we want, over a period
269 of one baud. The correlation must be quadrature. */
270
271 /* First we need the quadrature tone generators to correlate
272 against. */
273 s->phase_rate[0] = dds_phase_rate((float) spec->freq_zero);
274 s->phase_rate[1] = dds_phase_rate((float) spec->freq_one);
275 s->phase_acc[0] = 0;
276 s->phase_acc[1] = 0;
277 s->last_sample = 0;
278
279 /* The correlation should be over one baud. */
280 s->correlation_span = SAMPLE_RATE*100/spec->baud_rate;
281 /* But limit it for very slow baud rates, so we do not overflow our
282 buffer. */
283 if (s->correlation_span > FSK_MAX_WINDOW_LEN)
284 s->correlation_span = FSK_MAX_WINDOW_LEN;
285
286 /* We need to scale, to avoid overflow in the correlation. */
287 s->scaling_shift = 0;
288 chop = s->correlation_span;
289 while (chop != 0)
290 {
291 s->scaling_shift++;
292 chop >>= 1;
293 }
294
295 /* Initialise the baud/bit rate tracking. */
296 s->baud_phase = 0;
297 s->frame_state = 0;
298 s->frame_bits = 0;
299 s->last_bit = 0;
300
301 /* Initialise a power detector, so sense when a signal is present. */
302 power_meter_init(&(s->power), 4);
303 s->signal_present = 0;
304 return 0;
305 }
306 /*- End of function --------------------------------------------------------*/
307
308 SPAN_DECLARE(fsk_rx_state_t *) fsk_rx_init(fsk_rx_state_t *s,
309 const fsk_spec_t *spec,
310 int framing_mode,
311 put_bit_func_t put_bit,
312 void *user_data)
313 {
314 if (s == NULL)
315 {
316 if ((s = (fsk_rx_state_t *) malloc(sizeof(*s))) == NULL)
317 return NULL;
318 }
319 memset(s, 0, sizeof(*s));
320
321 s->put_bit = put_bit;
322 s->put_bit_user_data = user_data;
323 fsk_rx_restart(s, spec, framing_mode);
324 return s;
325 }
326 /*- End of function --------------------------------------------------------*/
327
328 SPAN_DECLARE(int) fsk_rx_release(fsk_rx_state_t *s)
329 {
330 return 0;
331 }
332 /*- End of function --------------------------------------------------------*/
333
334 SPAN_DECLARE(int) fsk_rx_free(fsk_rx_state_t *s)
335 {
336 free(s);
337 return 0;
338 }
339 /*- End of function --------------------------------------------------------*/
340
341 static void report_status_change(fsk_rx_state_t *s, int status)
342 {
343 if (s->status_handler)
344 s->status_handler(s->status_user_data, status);
345 else if (s->put_bit)
346 s->put_bit(s->put_bit_user_data, status);
347 }
348 /*- End of function --------------------------------------------------------*/
349
350 SPAN_DECLARE_NONSTD(int) fsk_rx(fsk_rx_state_t *s, const int16_t *amp, int len)
351 {
352 int buf_ptr;
353 int baudstate;
354 int i;
355 int j;
356 int16_t x;
357 int32_t dot;
358 int32_t sum[2];
359 int32_t power;
360 complexi_t ph;
361
362 buf_ptr = s->buf_ptr;
363
364 for (i = 0; i < len; i++)
365 {
366 /* The *totally* asynchronous character to character behaviour of these
367 modems, when carrying async. data, seems to force a sample by sample
368 approach. */
369 for (j = 0; j < 2; j++)
370 {
371 s->dot[j].re -= s->window[j][buf_ptr].re;
372 s->dot[j].im -= s->window[j][buf_ptr].im;
373
374 ph = dds_complexi(&(s->phase_acc[j]), s->phase_rate[j]);
375 s->window[j][buf_ptr].re = (ph.re*amp[i]) >> s->scaling_shift;
376 s->window[j][buf_ptr].im = (ph.im*amp[i]) >> s->scaling_shift;
377
378 s->dot[j].re += s->window[j][buf_ptr].re;
379 s->dot[j].im += s->window[j][buf_ptr].im;
380
381 dot = s->dot[j].re >> 15;
382 sum[j] = dot*dot;
383 dot = s->dot[j].im >> 15;
384 sum[j] += dot*dot;
385 }
386 /* If there isn't much signal, don't demodulate - it will only produce
387 useless junk results. */
388 /* There should be no DC in the signal, but sometimes there is.
389 We need to measure the power with the DC blocked, but not using
390 a slow to respond DC blocker. Use the most elementary HPF. */
391 x = amp[i] >> 1;
392 power = power_meter_update(&(s->power), x - s->last_sample);
393 s->last_sample = x;
394 if (s->signal_present)
395 {
396 /* Look for power below turn-off threshold to turn the carrier off */
397 if (power < s->carrier_off_power)
398 {
399 if (--s->signal_present <= 0)
400 {
401 /* Count down a short delay, to ensure we push the last
402 few bits through the filters before stopping. */
403 report_status_change(s, SIG_STATUS_CARRIER_DOWN);
404 s->baud_phase = 0;
405 continue;
406 }
407 }
408 }
409 else
410 {
411 /* Look for power exceeding turn-on threshold to turn the carrier on */
412 if (power < s->carrier_on_power)
413 {
414 s->baud_phase = 0;
415 continue;
416 }
417 if (s->baud_phase < (s->correlation_span >> 1) - 30)
418 {
419 s->baud_phase++;
420 continue;
421 }
422 s->signal_present = 1;
423 /* Initialise the baud/bit rate tracking. */
424 s->baud_phase = 0;
425 s->frame_state = 0;
426 s->frame_bits = 0;
427 s->last_bit = 0;
428 report_status_change(s, SIG_STATUS_CARRIER_UP);
429 }
430 /* Non-coherent FSK demodulation by correlation with the target tones
431 over a one baud interval. The slow V.xx specs. are too open ended
432 to allow anything fancier to be used. The dot products are calculated
433 using a sliding window approach, so the compute load is not that great. */
434
435 baudstate = (sum[0] < sum[1]);
436 switch (s->framing_mode)
437 {
438 case FSK_FRAME_MODE_SYNC:
439 /* Synchronous serial operation - e.g. for HDLC */
440 if (s->last_bit != baudstate)
441 {
442 /* On a transition we check our timing */
443 s->last_bit = baudstate;
444 /* For synchronous use (e.g. HDLC channels in FAX modems), nudge
445 the baud phase gently, trying to keep it centred on the bauds. */
446 if (s->baud_phase < (SAMPLE_RATE*50))
447 s->baud_phase += (s->baud_rate >> 3);
448 else
449 s->baud_phase -= (s->baud_rate >> 3);
450 }
451 if ((s->baud_phase += s->baud_rate) >= (SAMPLE_RATE*100))
452 {
453 /* We should be in the middle of a baud now, so report the current
454 state as the next bit */
455 s->baud_phase -= (SAMPLE_RATE*100);
456 s->put_bit(s->put_bit_user_data, baudstate);
457 }
458 break;
459 case FSK_FRAME_MODE_ASYNC:
460 /* Fully asynchronous mode */
461 if (s->last_bit != baudstate)
462 {
463 /* On a transition we check our timing */
464 s->last_bit = baudstate;
465 /* For async. operation, believe transitions completely, and
466 sample appropriately. This allows instant start on the first
467 transition. */
468 /* We must now be about half way to a sampling point. We do not do
469 any fractional sample estimation of the transitions, so this is
470 the most accurate baud alignment we can do. */
471 s->baud_phase = SAMPLE_RATE*50;
472 }
473 if ((s->baud_phase += s->baud_rate) >= (SAMPLE_RATE*100))
474 {
475 /* We should be in the middle of a baud now, so report the current
476 state as the next bit */
477 s->baud_phase -= (SAMPLE_RATE*100);
478 s->put_bit(s->put_bit_user_data, baudstate);
479 }
480 break;
481 default:
482 /* Gather the specified number of bits, with robust checking to ensure reasonable voice immunity.
483 The first bit should be a start bit (0), and the last bit should be a stop bit (1) */
484 if (s->frame_state == 0)
485 {
486 /* Looking for the start of a zero bit, which hopefully the start of a start bit */
487 if (baudstate == 0)
488 {
489 s->baud_phase = SAMPLE_RATE*(100 - 40)/2;
490 s->frame_state = -1;
491 s->frame_bits = 0;
492 s->last_bit = -1;
493 }
494 }
495 else if (s->frame_state == -1)
496 {
497 /* Look for a continuous zero from the start of the start bit until
498 beyond the middle */
499 if (baudstate != 0)
500 {
501 /* If we aren't looking at a stable start bit, restart */
502 s->frame_state = 0;
503 }
504 else
505 {
506 s->baud_phase += s->baud_rate;
507 if (s->baud_phase >= SAMPLE_RATE*100)
508 {
509 s->frame_state = 1;
510 s->last_bit = baudstate;
511 }
512 }
513 }
514 else
515 {
516 s->baud_phase += s->baud_rate;
517 if (s->baud_phase >= SAMPLE_RATE*(100 - 40))
518 {
519 if (s->last_bit < 0)
520 s->last_bit = baudstate;
521 /* Look for the bit being consistent over the central 20% of the bit time. */
522 if (s->last_bit != baudstate)
523 {
524 s->frame_state = 0;
525 }
526 else if (s->baud_phase >= SAMPLE_RATE*100)
527 {
528 /* We should be in the middle of a baud now, so report the current
529 state as the next bit */
530 if (s->last_bit == baudstate)
531 {
532 s->frame_bits |= (baudstate << s->framing_mode);
533 s->frame_bits >>= 1;
534 s->baud_phase -= (SAMPLE_RATE*100);
535 if (++s->frame_state > s->framing_mode)
536 {
537 /* Check we have a stop bit */
538 if (baudstate == 1)
539 {
540 /* Check we have a start bit */
541 if ((s->frame_bits & 1) == 0)
542 {
543 /* Drop the start bit, and pass the rest back */
544 s->frame_bits >>= 1;
545 s->put_bit(s->put_bit_user_data, s->frame_bits);
546 }
547 }
548 s->frame_state = 0;
549 }
550 }
551 else
552 {
553 s->frame_state = 0;
554 }
555 s->last_bit = -1;
556 }
557 }
558 }
559 break;
560 }
561 if (++buf_ptr >= s->correlation_span)
562 buf_ptr = 0;
563 }
564 s->buf_ptr = buf_ptr;
565 return 0;
566 }
567 /*- End of function --------------------------------------------------------*/
568
569 SPAN_DECLARE(int) fsk_rx_fillin(fsk_rx_state_t *s, int len)
570 {
571 /* The valid choice here is probably to do nothing. We don't change state
572 (i.e carrier on<->carrier off), and we'll just output less bits than we
573 should. */
574 /* TODO: Advance the symbol phase the appropriate amount */
575 return 0;
576 }
577 /*- End of function --------------------------------------------------------*/
578 /*- End of file ------------------------------------------------------------*/

Repositories maintained by Peter Meerwald, pmeerw@pmeerw.net.