Mercurial > hg > audiostuff
comparison spandsp-0.0.6pre17/src/v18.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 * v18.c - V.18 text telephony for the deaf. | |
5 * | |
6 * Written by Steve Underwood <steveu@coppice.org> | |
7 * | |
8 * Copyright (C) 2004-2009 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: v18.c,v 1.12 2009/11/04 15:52:06 steveu Exp $ | |
26 */ | |
27 | |
28 /*! \file */ | |
29 | |
30 #if defined(HAVE_CONFIG_H) | |
31 #include "config.h" | |
32 #endif | |
33 | |
34 #include <inttypes.h> | |
35 #include <stdlib.h> | |
36 #include <stdio.h> | |
37 #include <string.h> | |
38 #include <memory.h> | |
39 #if defined(HAVE_TGMATH_H) | |
40 #include <tgmath.h> | |
41 #endif | |
42 #if defined(HAVE_MATH_H) | |
43 #include <math.h> | |
44 #endif | |
45 #include "floating_fudge.h" | |
46 | |
47 #include "spandsp/telephony.h" | |
48 #include "spandsp/logging.h" | |
49 #include "spandsp/queue.h" | |
50 #include "spandsp/async.h" | |
51 #include "spandsp/complex.h" | |
52 #include "spandsp/dds.h" | |
53 #include "spandsp/tone_detect.h" | |
54 #include "spandsp/tone_generate.h" | |
55 #include "spandsp/super_tone_rx.h" | |
56 #include "spandsp/power_meter.h" | |
57 #include "spandsp/fsk.h" | |
58 #include "spandsp/dtmf.h" | |
59 #include "spandsp/modem_connect_tones.h" | |
60 #include "spandsp/v8.h" | |
61 #include "spandsp/v18.h" | |
62 | |
63 #include "spandsp/private/logging.h" | |
64 #include "spandsp/private/queue.h" | |
65 #include "spandsp/private/tone_generate.h" | |
66 #include "spandsp/private/async.h" | |
67 #include "spandsp/private/fsk.h" | |
68 #include "spandsp/private/dtmf.h" | |
69 #include "spandsp/private/modem_connect_tones.h" | |
70 #include "spandsp/private/v18.h" | |
71 | |
72 #include <stdlib.h> | |
73 | |
74 /*! The baudot code to shift from alpha to digits and symbols */ | |
75 #define BAUDOT_FIGURE_SHIFT 0x1B | |
76 /*! The baudot code to shift from digits and symbols to alpha */ | |
77 #define BAUDOT_LETTER_SHIFT 0x1F | |
78 | |
79 struct dtmf_to_ascii_s | |
80 { | |
81 const char *dtmf; | |
82 char ascii; | |
83 }; | |
84 | |
85 static const struct dtmf_to_ascii_s dtmf_to_ascii[] = | |
86 { | |
87 {"###1", 'C'}, | |
88 {"###2", 'F'}, | |
89 {"###3", 'I'}, | |
90 {"###4", 'L'}, | |
91 {"###5", 'O'}, | |
92 {"###6", 'R'}, | |
93 {"###7", 'U'}, | |
94 {"###8", 'X'}, | |
95 {"###9", ';'}, | |
96 {"###0", '!'}, | |
97 {"##*1", 'A'}, | |
98 {"##*2", 'D'}, | |
99 {"##*3", 'G'}, | |
100 {"##*4", 'J'}, | |
101 {"##*5", 'M'}, | |
102 {"##*6", 'P'}, | |
103 {"##*7", 'S'}, | |
104 {"##*8", 'V'}, | |
105 {"##*9", 'Y'}, | |
106 {"##1", 'B'}, | |
107 {"##2", 'E'}, | |
108 {"##3", 'H'}, | |
109 {"##4", 'K'}, | |
110 {"##5", 'N'}, | |
111 {"##6", 'Q'}, | |
112 {"##7", 'T'}, | |
113 {"##8", 'W'}, | |
114 {"##9", 'Z'}, | |
115 {"##0", ' '}, | |
116 #if defined(WIN32) | |
117 {"#*1", 'X'}, // (Note 1) 111 1011 | |
118 {"#*2", 'X'}, // (Note 1) 111 1100 | |
119 {"#*3", 'X'}, // (Note 1) 111 1101 | |
120 {"#*4", 'X'}, // (Note 1) 101 1011 | |
121 {"#*5", 'X'}, // (Note 1) 101 1100 | |
122 {"#*6", 'X'}, // (Note 1) 101 1101 | |
123 #else | |
124 {"#*1", 'æ'}, // (Note 1) 111 1011 | |
125 {"#*2", 'ø'}, // (Note 1) 111 1100 | |
126 {"#*3", 'å'}, // (Note 1) 111 1101 | |
127 {"#*4", 'Æ'}, // (Note 1) 101 1011 | |
128 {"#*5", 'Ø'}, // (Note 1) 101 1100 | |
129 {"#*6", 'Å'}, // (Note 1) 101 1101 | |
130 #endif | |
131 {"#0", '?'}, | |
132 {"#1", 'c'}, | |
133 {"#2", 'f'}, | |
134 {"#3", 'i'}, | |
135 {"#4", 'l'}, | |
136 {"#5", 'o'}, | |
137 {"#6", 'r'}, | |
138 {"#7", 'u'}, | |
139 {"#8", 'x'}, | |
140 {"#9", '.'}, | |
141 {"*#0", '0'}, | |
142 {"*#1", '1'}, | |
143 {"*#2", '2'}, | |
144 {"*#3", '3'}, | |
145 {"*#4", '4'}, | |
146 {"*#5", '5'}, | |
147 {"*#6", '6'}, | |
148 {"*#7", '7'}, | |
149 {"*#8", '8'}, | |
150 {"*#9", '9'}, | |
151 {"**1", '+'}, | |
152 {"**2", '-'}, | |
153 {"**3", '='}, | |
154 {"**4", ':'}, | |
155 {"**5", '%'}, | |
156 {"**6", '('}, | |
157 {"**7", ')'}, | |
158 {"**8", ','}, | |
159 {"**9", '\n'}, | |
160 {"*0", '\b'}, | |
161 {"*1", 'a'}, | |
162 {"*2", 'd'}, | |
163 {"*3", 'g'}, | |
164 {"*4", 'j'}, | |
165 {"*5", 'm'}, | |
166 {"*6", 'p'}, | |
167 {"*7", 's'}, | |
168 {"*8", 'v'}, | |
169 {"*9", 'y'}, | |
170 {"0", ' '}, | |
171 {"1", 'b'}, | |
172 {"2", 'e'}, | |
173 {"3", 'h'}, | |
174 {"4", 'k'}, | |
175 {"5", 'n'}, | |
176 {"6", 'q'}, | |
177 {"7", 't'}, | |
178 {"8", 'w'}, | |
179 {"9", 'z'}, | |
180 {"", '\0'} | |
181 }; | |
182 | |
183 static const char *ascii_to_dtmf[128] = | |
184 { | |
185 "", /* NULL */ | |
186 "", /* SOH */ | |
187 "", /* STX */ | |
188 "", /* ETX */ | |
189 "", /* EOT */ | |
190 "", /* ENQ */ | |
191 "", /* ACK */ | |
192 "", /* BEL */ | |
193 "*0", /* BACK SPACE */ | |
194 "0", /* HT >> SPACE */ | |
195 "**9", /* LF */ | |
196 "**9", /* VT >> LF */ | |
197 "**9", /* FF >> LF */ | |
198 "", /* CR */ | |
199 "", /* SO */ | |
200 "", /* SI */ | |
201 "", /* DLE */ | |
202 "", /* DC1 */ | |
203 "", /* DC2 */ | |
204 "", /* DC3 */ | |
205 "", /* DC4 */ | |
206 "", /* NAK */ | |
207 "", /* SYN */ | |
208 "", /* ETB */ | |
209 "", /* CAN */ | |
210 "", /* EM */ | |
211 "#0", /* SUB >> ? */ | |
212 "", /* ESC */ | |
213 "**9", /* IS4 >> LF */ | |
214 "**9", /* IS3 >> LF */ | |
215 "**9", /* IS2 >> LF */ | |
216 "0", /* IS1 >> SPACE */ | |
217 "0", /* SPACE */ | |
218 "###0", /* ! */ | |
219 "", /* " */ | |
220 "", /* # */ | |
221 "", /* $ */ | |
222 "**5", /* % */ | |
223 "**1", /* & >> + */ | |
224 "", /* ’ */ | |
225 "**6", /* ( */ | |
226 "**7", /* ) */ | |
227 "#9", /* _ >> . */ | |
228 "**1", /* + */ | |
229 "**8", /* , */ | |
230 "**2", /* - */ | |
231 "#9", /* . */ | |
232 "", /* / */ | |
233 "*#0", /* 0 */ | |
234 "*#1", /* 1 */ | |
235 "*#2", /* 2 */ | |
236 "*#3", /* 3 */ | |
237 "*#4", /* 4 */ | |
238 "*#5", /* 5 */ | |
239 "*#6", /* 6 */ | |
240 "*#7", /* 7 */ | |
241 "*#8", /* 8 */ | |
242 "*#9", /* 9 */ | |
243 "**4", /* : */ | |
244 "###9", /* ; */ | |
245 "**6", /* < >> ( */ | |
246 "**3", /* = */ | |
247 "**7", /* > >> ) */ | |
248 "#0", /* ? */ | |
249 "###8", /* @ >> X */ | |
250 "##*1", /* A */ | |
251 "##1", /* B */ | |
252 "###1", /* C */ | |
253 "##*2", /* D */ | |
254 "##2", /* E */ | |
255 "###2", /* F */ | |
256 "##*3", /* G */ | |
257 "##3", /* H */ | |
258 "###3", /* I */ | |
259 "##*4", /* J */ | |
260 "##4", /* K */ | |
261 "###4", /* L */ | |
262 "##*5", /* M */ | |
263 "##5", /* N */ | |
264 "###5", /* O */ | |
265 "##*6", /* P */ | |
266 "##6", /* Q */ | |
267 "###6", /* R */ | |
268 "##*7", /* S */ | |
269 "##7", /* T */ | |
270 "###7", /* U */ | |
271 "##*8", /* V */ | |
272 "##8", /* W */ | |
273 "###8", /* X */ | |
274 "##*9", /* Y */ | |
275 "##9", /* Z */ | |
276 "#*4", /* Æ (National code) */ | |
277 "#*5", /* Ø (National code) */ | |
278 "#*6", /* Å (National code) */ | |
279 "", /* ^ */ | |
280 "0", /* _ >> SPACE */ | |
281 "", /* ’ */ | |
282 "*1", /* a */ | |
283 "1", /* b */ | |
284 "#1", /* c */ | |
285 "*2", /* d */ | |
286 "2", /* e */ | |
287 "#2", /* f */ | |
288 "*3", /* g */ | |
289 "3", /* h */ | |
290 "#3", /* i */ | |
291 "*4", /* j */ | |
292 "4", /* k */ | |
293 "#4", /* l */ | |
294 "*5", /* m */ | |
295 "5", /* n */ | |
296 "#5", /* o */ | |
297 "*6", /* p */ | |
298 "6", /* q */ | |
299 "#6", /* r */ | |
300 "*7", /* s */ | |
301 "7", /* t */ | |
302 "#7", /* u */ | |
303 "*8", /* v */ | |
304 "8", /* w */ | |
305 "#8", /* x */ | |
306 "*9", /* y */ | |
307 "9", /* z */ | |
308 "#*1", /* æ (National code) */ | |
309 "#*2", /* ø (National code) */ | |
310 "#*3", /* å (National code) */ | |
311 "0", /* ~ >> SPACE */ | |
312 "*0" /* DEL >> BACK SPACE */ | |
313 }; | |
314 | |
315 static int cmp(const void *s, const void *t) | |
316 { | |
317 const char *ss; | |
318 struct dtmf_to_ascii_s *tt; | |
319 | |
320 ss = (const char *) s; | |
321 tt = (struct dtmf_to_ascii_s *) t; | |
322 return strncmp(ss, tt->dtmf, strlen(tt->dtmf)); | |
323 } | |
324 | |
325 SPAN_DECLARE(int) v18_encode_dtmf(v18_state_t *s, char dtmf[], const char msg[]) | |
326 { | |
327 const char *t; | |
328 char *u; | |
329 const char *v; | |
330 | |
331 t = msg; | |
332 u = dtmf; | |
333 while (*t) | |
334 { | |
335 v = ascii_to_dtmf[*t & 0x7F]; | |
336 while (*v) | |
337 *u++ = *v++; | |
338 t++; | |
339 } | |
340 *u = '\0'; | |
341 | |
342 return u - dtmf; | |
343 } | |
344 /*- End of function --------------------------------------------------------*/ | |
345 | |
346 SPAN_DECLARE(int) v18_decode_dtmf(v18_state_t *s, char msg[], const char dtmf[]) | |
347 { | |
348 int entries; | |
349 const char *t; | |
350 char *u; | |
351 struct dtmf_to_ascii_s *ss; | |
352 | |
353 entries = sizeof(dtmf_to_ascii)/sizeof(dtmf_to_ascii[0]) - 1; | |
354 t = dtmf; | |
355 u = msg; | |
356 while (*t) | |
357 { | |
358 ss = bsearch(t, dtmf_to_ascii, entries, sizeof(dtmf_to_ascii[0]), cmp); | |
359 if (ss) | |
360 { | |
361 t += strlen(ss->dtmf); | |
362 *u++ = ss->ascii; | |
363 } | |
364 else | |
365 { | |
366 /* Can't match the code. Let's assume this is a code we just don't know, and skip over it */ | |
367 while (*t == '#' || *t == '*') | |
368 t++; | |
369 if (*t) | |
370 t++; | |
371 } | |
372 } | |
373 *u = '\0'; | |
374 return u - msg; | |
375 } | |
376 /*- End of function --------------------------------------------------------*/ | |
377 | |
378 SPAN_DECLARE(uint16_t) v18_encode_baudot(v18_state_t *s, uint8_t ch) | |
379 { | |
380 static const uint8_t conv[128] = | |
381 { | |
382 0xFF, /* NUL */ | |
383 0xFF, /* SOH */ | |
384 0xFF, /* STX */ | |
385 0xFF, /* ETX */ | |
386 0xFF, /* EOT */ | |
387 0xFF, /* ENQ */ | |
388 0xFF, /* ACK */ | |
389 0xFF, /* BEL */ | |
390 0x00, /* BS */ | |
391 0x44, /* HT >> SPACE */ | |
392 0x42, /* LF */ | |
393 0x42, /* VT >> LF */ | |
394 0x42, /* FF >> LF */ | |
395 0x48, /* CR */ | |
396 0xFF, /* SO */ | |
397 0xFF, /* SI */ | |
398 0xFF, /* DLE */ | |
399 0xFF, /* DC1 */ | |
400 0xFF, /* DC2 */ | |
401 0xFF, /* DC3 */ | |
402 0xFF, /* DC4 */ | |
403 0xFF, /* NAK */ | |
404 0xFF, /* SYN */ | |
405 0xFF, /* ETB */ | |
406 0xFF, /* CAN */ | |
407 0xFF, /* EM */ | |
408 0x99, /* SUB >> ? */ | |
409 0xFF, /* ESC */ | |
410 0x42, /* IS4 >> LF */ | |
411 0x42, /* IS3 >> LF */ | |
412 0x42, /* IS2 >> LF */ | |
413 0x44, /* IS1 >> SPACE */ | |
414 0x44, /* */ | |
415 0x8D, /* ! */ | |
416 0x91, /* " */ | |
417 0x89, /* # >> $ */ | |
418 0x89, /* $ */ | |
419 0x9D, /* % >> / */ | |
420 0x9A, /* & >> + */ | |
421 0x8B, /* ' */ | |
422 0x8F, /* ( */ | |
423 0x92, /* ) */ | |
424 0x9C, /* * >> . */ | |
425 0x9A, /* + */ | |
426 0x8C, /* , */ | |
427 0x83, /* - */ | |
428 0x9C, /* . */ | |
429 0x9D, /* / */ | |
430 0x96, /* 0 */ | |
431 0x97, /* 1 */ | |
432 0x93, /* 2 */ | |
433 0x81, /* 3 */ | |
434 0x8A, /* 4 */ | |
435 0x90, /* 5 */ | |
436 0x95, /* 6 */ | |
437 0x87, /* 7 */ | |
438 0x86, /* 8 */ | |
439 0x98, /* 9 */ | |
440 0x8E, /* : */ | |
441 0x9E, /* ; */ | |
442 0x8F, /* < >> )*/ | |
443 0x94, /* = */ | |
444 0x92, /* > >> ( */ | |
445 0x99, /* ? */ | |
446 0x1D, /* @ >> X */ | |
447 0x03, /* A */ | |
448 0x19, /* B */ | |
449 0x0E, /* C */ | |
450 0x09, /* D */ | |
451 0x01, /* E */ | |
452 0x0D, /* F */ | |
453 0x1A, /* G */ | |
454 0x14, /* H */ | |
455 0x06, /* I */ | |
456 0x0B, /* J */ | |
457 0x0F, /* K */ | |
458 0x12, /* L */ | |
459 0x1C, /* M */ | |
460 0x0C, /* N */ | |
461 0x18, /* O */ | |
462 0x16, /* P */ | |
463 0x17, /* Q */ | |
464 0x0A, /* R */ | |
465 0x05, /* S */ | |
466 0x10, /* T */ | |
467 0x07, /* U */ | |
468 0x1E, /* V */ | |
469 0x13, /* W */ | |
470 0x1D, /* X */ | |
471 0x15, /* Y */ | |
472 0x11, /* Z */ | |
473 0x8F, /* [ >> (*/ | |
474 0x9D, /* \ >> / */ | |
475 0x92, /* ] >> ) */ | |
476 0x8B, /* ^ >> ' */ | |
477 0x44, /* _ >> Space */ | |
478 0x8B, /* ` >> ' */ | |
479 0x03, /* a */ | |
480 0x19, /* b */ | |
481 0x0E, /* c */ | |
482 0x09, /* d */ | |
483 0x01, /* e */ | |
484 0x0D, /* f */ | |
485 0x1A, /* g */ | |
486 0x14, /* h */ | |
487 0x06, /* i */ | |
488 0x0B, /* j */ | |
489 0x0F, /* k */ | |
490 0x12, /* l */ | |
491 0x1C, /* m */ | |
492 0x0C, /* n */ | |
493 0x18, /* o */ | |
494 0x16, /* p */ | |
495 0x17, /* q */ | |
496 0x0A, /* r */ | |
497 0x05, /* s */ | |
498 0x10, /* t */ | |
499 0x07, /* u */ | |
500 0x1E, /* v */ | |
501 0x13, /* w */ | |
502 0x1D, /* x */ | |
503 0x15, /* y */ | |
504 0x11, /* z */ | |
505 0x8F, /* { >> ( */ | |
506 0x8D, /* | >> ! */ | |
507 0x92, /* } >> ) */ | |
508 0x44, /* ~ >> Space */ | |
509 0xFF, /* DEL */ | |
510 }; | |
511 uint16_t shift; | |
512 | |
513 if (ch == 0x7F) | |
514 { | |
515 /* DLE is a special character meaning "force a | |
516 change to the letter character set */ | |
517 shift = BAUDOT_LETTER_SHIFT; | |
518 return 0; | |
519 } | |
520 ch = conv[ch]; | |
521 /* Is it a non-existant code? */ | |
522 if (ch == 0xFF) | |
523 return 0; | |
524 /* Is it a code present in both character sets? */ | |
525 if ((ch & 0x40)) | |
526 return 0x8000 | (ch & 0x1F); | |
527 /* Need to allow for a possible character set change. */ | |
528 if ((ch & 0x80)) | |
529 { | |
530 if (s->baudot_tx_shift == 1) | |
531 return ch & 0x1F; | |
532 s->baudot_tx_shift = 1; | |
533 shift = BAUDOT_FIGURE_SHIFT; | |
534 } | |
535 else | |
536 { | |
537 if (s->baudot_tx_shift == 0) | |
538 return ch & 0x1F; | |
539 s->baudot_tx_shift = 0; | |
540 shift = BAUDOT_LETTER_SHIFT; | |
541 } | |
542 return 0x8000 | (shift << 5) | (ch & 0x1F); | |
543 } | |
544 /*- End of function --------------------------------------------------------*/ | |
545 | |
546 SPAN_DECLARE(uint8_t) v18_decode_baudot(v18_state_t *s, uint8_t ch) | |
547 { | |
548 static const uint8_t conv[2][32] = | |
549 { | |
550 {"\bE\nA SIU\rDRJNFCKTZLWHYPQOBG^MXV^"}, | |
551 {"\b3\n- -87\r$4',!:(5\")2=6019?+^./;^"} | |
552 }; | |
553 | |
554 switch (ch) | |
555 { | |
556 case BAUDOT_FIGURE_SHIFT: | |
557 s->baudot_rx_shift = 1; | |
558 break; | |
559 case BAUDOT_LETTER_SHIFT: | |
560 s->baudot_rx_shift = 0; | |
561 break; | |
562 default: | |
563 return conv[s->baudot_rx_shift][ch]; | |
564 } | |
565 /* return 0 if we did not produce a character */ | |
566 return 0; | |
567 } | |
568 /*- End of function --------------------------------------------------------*/ | |
569 | |
570 static void v18_rx_dtmf(void *user_data, const char digits[], int len) | |
571 { | |
572 v18_state_t *s; | |
573 | |
574 s = (v18_state_t *) user_data; | |
575 } | |
576 /*- End of function --------------------------------------------------------*/ | |
577 | |
578 static int v18_tdd_get_async_byte(void *user_data) | |
579 { | |
580 v18_state_t *s; | |
581 int ch; | |
582 | |
583 s = (v18_state_t *) user_data; | |
584 if ((ch = queue_read_byte(&s->queue.queue)) >= 0) | |
585 { | |
586 int space; | |
587 int cont; | |
588 space = queue_free_space(&s->queue.queue); | |
589 cont = queue_contents(&s->queue.queue); | |
590 return ch; | |
591 } | |
592 if (s->tx_signal_on) | |
593 { | |
594 /* The FSK should now be switched off. */ | |
595 s->tx_signal_on = FALSE; | |
596 } | |
597 return 0x1F; | |
598 } | |
599 /*- End of function --------------------------------------------------------*/ | |
600 | |
601 static void v18_tdd_put_async_byte(void *user_data, int byte) | |
602 { | |
603 v18_state_t *s; | |
604 uint8_t octet; | |
605 | |
606 s = (v18_state_t *) user_data; | |
607 //printf("Rx byte %x\n", byte); | |
608 if (byte < 0) | |
609 { | |
610 /* Special conditions */ | |
611 span_log(&s->logging, SPAN_LOG_FLOW, "V.18 signal status is %s (%d)\n", signal_status_to_str(byte), byte); | |
612 switch (byte) | |
613 { | |
614 case SIG_STATUS_CARRIER_UP: | |
615 s->consecutive_ones = 0; | |
616 s->bit_pos = 0; | |
617 s->in_progress = 0; | |
618 s->rx_msg_len = 0; | |
619 break; | |
620 case SIG_STATUS_CARRIER_DOWN: | |
621 if (s->rx_msg_len > 0) | |
622 { | |
623 /* Whatever we have to date constitutes the message */ | |
624 s->rx_msg[s->rx_msg_len] = '\0'; | |
625 s->put_msg(s->user_data, s->rx_msg, s->rx_msg_len); | |
626 s->rx_msg_len = 0; | |
627 } | |
628 break; | |
629 default: | |
630 span_log(&s->logging, SPAN_LOG_WARNING, "Unexpected special put byte value - %d!\n", byte); | |
631 break; | |
632 } | |
633 return; | |
634 } | |
635 if ((octet = v18_decode_baudot(s, (uint8_t) (byte & 0x1F)))) | |
636 s->rx_msg[s->rx_msg_len++] = octet; | |
637 if (s->rx_msg_len >= 256) | |
638 { | |
639 s->rx_msg[s->rx_msg_len] = '\0'; | |
640 s->put_msg(s->user_data, s->rx_msg, s->rx_msg_len); | |
641 s->rx_msg_len = 0; | |
642 } | |
643 } | |
644 /*- End of function --------------------------------------------------------*/ | |
645 | |
646 SPAN_DECLARE_NONSTD(int) v18_tx(v18_state_t *s, int16_t *amp, int max_len) | |
647 { | |
648 int len; | |
649 int lenx; | |
650 | |
651 len = tone_gen(&(s->alert_tone_gen), amp, max_len); | |
652 if (s->tx_signal_on) | |
653 { | |
654 switch (s->mode) | |
655 { | |
656 case V18_MODE_DTMF: | |
657 if (len < max_len) | |
658 len += dtmf_tx(&(s->dtmftx), amp, max_len - len); | |
659 break; | |
660 default: | |
661 if (len < max_len) | |
662 { | |
663 if ((lenx = fsk_tx(&(s->fsktx), amp + len, max_len - len)) <= 0) | |
664 s->tx_signal_on = FALSE; | |
665 len += lenx; | |
666 } | |
667 break; | |
668 } | |
669 } | |
670 return len; | |
671 } | |
672 /*- End of function --------------------------------------------------------*/ | |
673 | |
674 SPAN_DECLARE_NONSTD(int) v18_rx(v18_state_t *s, const int16_t amp[], int len) | |
675 { | |
676 switch (s->mode) | |
677 { | |
678 case V18_MODE_DTMF: | |
679 /* Apply a message timeout. */ | |
680 s->in_progress -= len; | |
681 if (s->in_progress <= 0) | |
682 s->rx_msg_len = 0; | |
683 dtmf_rx(&(s->dtmfrx), amp, len); | |
684 break; | |
685 default: | |
686 fsk_rx(&(s->fskrx), amp, len); | |
687 break; | |
688 } | |
689 return 0; | |
690 } | |
691 /*- End of function --------------------------------------------------------*/ | |
692 | |
693 SPAN_DECLARE(int) v18_put(v18_state_t *s, const char msg[], int len) | |
694 { | |
695 char buf[256 + 1]; | |
696 int x; | |
697 int n; | |
698 int i; | |
699 | |
700 /* This returns the number of characters that would not fit in the buffer. | |
701 The buffer will only be loaded if the whole string of digits will fit, | |
702 in which case zero is returned. */ | |
703 if (len < 0) | |
704 { | |
705 if ((len = strlen(msg)) == 0) | |
706 return 0; | |
707 } | |
708 switch (s->mode) | |
709 { | |
710 case V18_MODE_5BIT_45: | |
711 case V18_MODE_5BIT_50: | |
712 for (i = 0; i < len; i++) | |
713 { | |
714 n = 0; | |
715 if ((x = v18_encode_baudot(s, msg[i]))) | |
716 { | |
717 if ((x & 0x3E0)) | |
718 buf[n++] = (uint8_t) ((x >> 5) & 0x1F); | |
719 buf[n++] = (uint8_t) (x & 0x1F); | |
720 /* TODO: Deal with out of space condition */ | |
721 if (queue_write(&s->queue.queue, (const uint8_t *) buf, n) < 0) | |
722 return i; | |
723 s->tx_signal_on = TRUE; | |
724 } | |
725 } | |
726 return len; | |
727 case V18_MODE_DTMF: | |
728 break; | |
729 } | |
730 return -1; | |
731 } | |
732 /*- End of function --------------------------------------------------------*/ | |
733 | |
734 SPAN_DECLARE(logging_state_t *) v18_get_logging_state(v18_state_t *s) | |
735 { | |
736 return &s->logging; | |
737 } | |
738 /*- End of function --------------------------------------------------------*/ | |
739 | |
740 SPAN_DECLARE(v18_state_t *) v18_init(v18_state_t *s, | |
741 int calling_party, | |
742 int mode, | |
743 put_msg_func_t put_msg, | |
744 void *user_data) | |
745 { | |
746 if (s == NULL) | |
747 { | |
748 if ((s = (v18_state_t *) malloc(sizeof(*s))) == NULL) | |
749 return NULL; | |
750 } | |
751 memset(s, 0, sizeof(*s)); | |
752 s->calling_party = calling_party; | |
753 s->mode = mode; | |
754 s->put_msg = put_msg; | |
755 s->user_data = user_data; | |
756 | |
757 switch (s->mode) | |
758 { | |
759 case V18_MODE_5BIT_45: | |
760 fsk_tx_init(&(s->fsktx), &preset_fsk_specs[FSK_WEITBRECHT], async_tx_get_bit, &(s->asynctx)); | |
761 async_tx_init(&(s->asynctx), 5, ASYNC_PARITY_NONE, 2, FALSE, v18_tdd_get_async_byte, s); | |
762 /* Schedule an explicit shift at the start of baudot transmission */ | |
763 s->baudot_tx_shift = 2; | |
764 /* TDD uses 5 bit data, no parity and 1.5 stop bits. We scan for the first stop bit, and | |
765 ride over the fraction. */ | |
766 fsk_rx_init(&(s->fskrx), &preset_fsk_specs[FSK_WEITBRECHT], FSK_FRAME_MODE_5N1_FRAMES, v18_tdd_put_async_byte, s); | |
767 s->baudot_rx_shift = 0; | |
768 break; | |
769 case V18_MODE_5BIT_50: | |
770 fsk_tx_init(&(s->fsktx), &preset_fsk_specs[FSK_WEITBRECHT50], async_tx_get_bit, &(s->asynctx)); | |
771 async_tx_init(&(s->asynctx), 5, ASYNC_PARITY_NONE, 2, FALSE, v18_tdd_get_async_byte, s); | |
772 /* Schedule an explicit shift at the start of baudot transmission */ | |
773 s->baudot_tx_shift = 2; | |
774 /* TDD uses 5 bit data, no parity and 1.5 stop bits. We scan for the first stop bit, and | |
775 ride over the fraction. */ | |
776 fsk_rx_init(&(s->fskrx), &preset_fsk_specs[FSK_WEITBRECHT50], FSK_FRAME_MODE_5N1_FRAMES, v18_tdd_put_async_byte, s); | |
777 s->baudot_rx_shift = 0; | |
778 break; | |
779 case V18_MODE_DTMF: | |
780 dtmf_tx_init(&(s->dtmftx)); | |
781 dtmf_rx_init(&(s->dtmfrx), v18_rx_dtmf, s); | |
782 break; | |
783 case V18_MODE_EDT: | |
784 break; | |
785 case V18_MODE_BELL103: | |
786 break; | |
787 case V18_MODE_V23VIDEOTEX: | |
788 break; | |
789 case V18_MODE_V21TEXTPHONE: | |
790 break; | |
791 case V18_MODE_V18TEXTPHONE: | |
792 break; | |
793 } | |
794 queue_init(&s->queue.queue, 128, QUEUE_READ_ATOMIC | QUEUE_WRITE_ATOMIC); | |
795 return s; | |
796 } | |
797 /*- End of function --------------------------------------------------------*/ | |
798 | |
799 SPAN_DECLARE(int) v18_release(v18_state_t *s) | |
800 { | |
801 return 0; | |
802 } | |
803 /*- End of function --------------------------------------------------------*/ | |
804 | |
805 SPAN_DECLARE(int) v18_free(v18_state_t *s) | |
806 { | |
807 free(s); | |
808 return 0; | |
809 } | |
810 /*- End of function --------------------------------------------------------*/ | |
811 | |
812 SPAN_DECLARE(const char *) v18_mode_to_str(int mode) | |
813 { | |
814 switch (mode) | |
815 { | |
816 case V18_MODE_NONE: | |
817 return "None"; | |
818 case V18_MODE_5BIT_45: | |
819 return "Weitbrecht TDD (45.45bps)"; | |
820 case V18_MODE_5BIT_50: | |
821 return "Weitbrecht TDD (50bps)"; | |
822 case V18_MODE_DTMF: | |
823 return "DTMF"; | |
824 case V18_MODE_EDT: | |
825 return "EDT"; | |
826 case V18_MODE_BELL103: | |
827 return "Bell 103"; | |
828 case V18_MODE_V23VIDEOTEX: | |
829 return "Videotex"; | |
830 case V18_MODE_V21TEXTPHONE: | |
831 return "V.21"; | |
832 case V18_MODE_V18TEXTPHONE: | |
833 return "V.18 text telephone"; | |
834 } | |
835 return "???"; | |
836 } | |
837 /*- End of function --------------------------------------------------------*/ | |
838 /*- End of file ------------------------------------------------------------*/ |