Mercurial > hg > audiostuff
comparison spandsp-0.0.3/spandsp-0.0.3/src/adsi.c @ 5:f762bf195c4b
import spandsp-0.0.3
author | Peter Meerwald <pmeerw@cosy.sbg.ac.at> |
---|---|
date | Fri, 25 Jun 2010 16:00:21 +0200 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
4:26cd8f1ef0b1 | 5:f762bf195c4b |
---|---|
1 /* | |
2 * SpanDSP - a series of DSP components for telephony | |
3 * | |
4 * adsi.c - Analogue display service interfaces of various types, including | |
5 * ADSI, TDD and most caller ID formats. | |
6 * | |
7 * Written by Steve Underwood <steveu@coppice.org> | |
8 * | |
9 * Copyright (C) 2003 Steve Underwood | |
10 * | |
11 * All rights reserved. | |
12 * | |
13 * This program is free software; you can redistribute it and/or modify | |
14 * it under the terms of the GNU General Public License version 2, as | |
15 * published by the Free Software Foundation. | |
16 * | |
17 * This program is distributed in the hope that it will be useful, | |
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
20 * GNU General Public License for more details. | |
21 * | |
22 * You should have received a copy of the GNU General Public License | |
23 * along with this program; if not, write to the Free Software | |
24 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |
25 * | |
26 * $Id: adsi.c,v 1.36 2006/11/19 14:07:23 steveu Exp $ | |
27 */ | |
28 | |
29 /*! \file */ | |
30 | |
31 #ifdef HAVE_CONFIG_H | |
32 #include <config.h> | |
33 #endif | |
34 | |
35 #include <inttypes.h> | |
36 #include <stdlib.h> | |
37 #include <stdio.h> | |
38 #include <string.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 <assert.h> | |
46 | |
47 #include "spandsp/telephony.h" | |
48 #include "spandsp/logging.h" | |
49 #include "spandsp/dds.h" | |
50 #include "spandsp/power_meter.h" | |
51 #include "spandsp/async.h" | |
52 #include "spandsp/hdlc.h" | |
53 #include "spandsp/fsk.h" | |
54 #include "spandsp/tone_detect.h" | |
55 #include "spandsp/tone_generate.h" | |
56 #include "spandsp/dtmf.h" | |
57 #include "spandsp/adsi.h" | |
58 | |
59 #define BAUDOT_FIGURE_SHIFT 0x1B | |
60 #define BAUDOT_LETTER_SHIFT 0x1F | |
61 | |
62 #define SOH 0x01 | |
63 #define STX 0x02 | |
64 #define ETX 0x03 | |
65 #define DLE 0x10 | |
66 #define SUB 0x1A | |
67 | |
68 static uint8_t adsi_encode_baudot(adsi_tx_state_t *s, uint8_t ch); | |
69 static uint8_t adsi_decode_baudot(adsi_rx_state_t *s, uint8_t ch); | |
70 | |
71 static int adsi_tx_get_bit(void *user_data) | |
72 { | |
73 int bit; | |
74 adsi_tx_state_t *s; | |
75 | |
76 s = (adsi_tx_state_t *) user_data; | |
77 /* This is similar to the async. handling code in fsk.c, but a few special | |
78 things are needed in the preamble, and postamble of an ADSI message. */ | |
79 if (s->bitno < 300) | |
80 { | |
81 /* Alternating bit preamble */ | |
82 bit = s->bitno & 1; | |
83 s->bitno++; | |
84 } | |
85 else if (s->bitno < 300 + s->ones_len) | |
86 { | |
87 /* All 1s for receiver conditioning */ | |
88 /* NB: The receiver is an async one. It needs a rest after the | |
89 alternating 1/0 sequence so it can reliably pick up on | |
90 the next start bit, and sync to the byte stream. */ | |
91 /* The length of this period varies with the circumstance */ | |
92 bit = 1; | |
93 s->bitno++; | |
94 } | |
95 else if (s->bitno < 300 + s->ones_len + 1) | |
96 { | |
97 if (s->bitpos == 0) | |
98 { | |
99 /* Start bit */ | |
100 bit = 0; | |
101 s->bitpos++; | |
102 } | |
103 else if (s->bitpos < 9) | |
104 { | |
105 bit = (s->msg[s->byteno] >> (s->bitpos - 1)) & 1; | |
106 s->bitpos++; | |
107 } | |
108 else | |
109 { | |
110 /* Stop bit */ | |
111 bit = 1; | |
112 s->bitpos = 0; | |
113 s->byteno++; | |
114 if (s->byteno > s->msg_len) | |
115 s->bitno++; | |
116 } | |
117 } | |
118 else if (s->bitno < 300 + s->ones_len + 5) | |
119 { | |
120 /* Extra stop bits beyond the last character, to meet the specs., and ensure | |
121 all bits are out of the DSP before we shut off the FSK modem. */ | |
122 bit = 1; | |
123 s->bitno++; | |
124 } | |
125 else | |
126 { | |
127 bit = 2; | |
128 if (s->tx_signal_on) | |
129 { | |
130 /* The FSK should now be switched off. */ | |
131 s->tx_signal_on = FALSE; | |
132 s->msg_len = 0; | |
133 } | |
134 } | |
135 return bit; | |
136 } | |
137 /*- End of function --------------------------------------------------------*/ | |
138 | |
139 static int adsi_tdd_get_async_byte(void *user_data) | |
140 { | |
141 adsi_tx_state_t *s; | |
142 | |
143 s = (adsi_tx_state_t *) user_data; | |
144 if (s->byteno < s->msg_len) | |
145 return s->msg[s->byteno++]; | |
146 if (s->tx_signal_on) | |
147 { | |
148 /* The FSK should now be switched off. */ | |
149 s->tx_signal_on = FALSE; | |
150 s->msg_len = 0; | |
151 } | |
152 return 0x1F; | |
153 } | |
154 /*- End of function --------------------------------------------------------*/ | |
155 | |
156 static void adsi_rx_put_bit(void *user_data, int bit) | |
157 { | |
158 adsi_rx_state_t *s; | |
159 int i; | |
160 int sum; | |
161 | |
162 s = (adsi_rx_state_t *) user_data; | |
163 if (bit < 0) | |
164 { | |
165 /* Special conditions */ | |
166 switch (bit) | |
167 { | |
168 case PUTBIT_CARRIER_UP: | |
169 span_log(&s->logging, SPAN_LOG_FLOW, "Carrier up.\n"); | |
170 s->consecutive_ones = 0; | |
171 s->bitpos = 0; | |
172 s->in_progress = 0; | |
173 s->msg_len = 0; | |
174 s->baudot_shift = 0; | |
175 break; | |
176 case PUTBIT_CARRIER_DOWN: | |
177 span_log(&s->logging, SPAN_LOG_FLOW, "Carrier down.\n"); | |
178 break; | |
179 default: | |
180 span_log(&s->logging, SPAN_LOG_WARNING, "Unexpected special put bit value - %d!\n", bit); | |
181 break; | |
182 } | |
183 return; | |
184 } | |
185 bit &= 1; | |
186 if (s->bitpos == 0) | |
187 { | |
188 if (bit == 0) | |
189 { | |
190 /* Start bit */ | |
191 s->bitpos++; | |
192 if (s->consecutive_ones > 10) | |
193 { | |
194 /* This is a line idle condition, which means we should | |
195 restart message acquisition */ | |
196 s->msg_len = 0; | |
197 } | |
198 s->consecutive_ones = 0; | |
199 } | |
200 else | |
201 { | |
202 s->consecutive_ones++; | |
203 } | |
204 } | |
205 else if (s->bitpos <= 8) | |
206 { | |
207 s->in_progress >>= 1; | |
208 if (bit) | |
209 s->in_progress |= 0x80; | |
210 s->bitpos++; | |
211 } | |
212 else | |
213 { | |
214 /* Stop bit */ | |
215 if (bit) | |
216 { | |
217 if (s->msg_len < 256) | |
218 { | |
219 if (s->standard == ADSI_STANDARD_JCLIP) | |
220 { | |
221 if (s->msg_len == 0) | |
222 { | |
223 /* A message should start DLE SOH, but let's just check | |
224 we are starting with a DLE for now */ | |
225 if (s->in_progress == (0x80 | DLE)) | |
226 s->msg[s->msg_len++] = (uint8_t) s->in_progress; | |
227 } | |
228 else | |
229 { | |
230 s->msg[s->msg_len++] = (uint8_t) s->in_progress; | |
231 } | |
232 if (s->msg_len >= 11 && s->msg_len == ((s->msg[6] & 0x7F) + 11)) | |
233 { | |
234 /* Test the CRC-16 */ | |
235 if (crc_itu16_calc(s->msg + 2, s->msg_len - 2, 0) == 0) | |
236 { | |
237 /* Strip off the parity bits. It doesn't seem | |
238 worthwhile actually checking the parity if a | |
239 CRC check has succeeded. */ | |
240 for (i = 0; i < s->msg_len - 2; i++) | |
241 s->msg[i] &= 0x7F; | |
242 /* Put everything, except the CRC octets */ | |
243 s->put_msg(s->user_data, s->msg, s->msg_len - 2); | |
244 } | |
245 else | |
246 { | |
247 span_log(&s->logging, SPAN_LOG_WARNING, "CRC failed\n"); | |
248 } | |
249 s->msg_len = 0; | |
250 } | |
251 } | |
252 else | |
253 { | |
254 s->msg[s->msg_len++] = (uint8_t) s->in_progress; | |
255 if (s->msg_len >= 3 && s->msg_len == (s->msg[1] + 3)) | |
256 { | |
257 /* Test the checksum */ | |
258 sum = 0; | |
259 for (i = 0; i < s->msg_len - 1; i++) | |
260 sum += s->msg[i]; | |
261 if ((-sum & 0xFF) == s->msg[i]) | |
262 s->put_msg(s->user_data, s->msg, s->msg_len - 1); | |
263 else | |
264 span_log(&s->logging, SPAN_LOG_WARNING, "Sumcheck failed\n"); | |
265 s->msg_len = 0; | |
266 } | |
267 } | |
268 } | |
269 } | |
270 else | |
271 { | |
272 s->framing_errors++; | |
273 } | |
274 s->bitpos = 0; | |
275 s->in_progress = 0; | |
276 } | |
277 } | |
278 /*- End of function --------------------------------------------------------*/ | |
279 | |
280 static void adsi_tdd_put_async_byte(void *user_data, int byte) | |
281 { | |
282 adsi_rx_state_t *s; | |
283 uint8_t octet; | |
284 | |
285 s = (adsi_rx_state_t *) user_data; | |
286 if (byte < 0) | |
287 { | |
288 /* Special conditions */ | |
289 switch (byte) | |
290 { | |
291 case PUTBIT_CARRIER_UP: | |
292 span_log(&s->logging, SPAN_LOG_FLOW, "Carrier up.\n"); | |
293 s->consecutive_ones = 0; | |
294 s->bitpos = 0; | |
295 s->in_progress = 0; | |
296 s->msg_len = 0; | |
297 s->baudot_shift = 0; | |
298 break; | |
299 case PUTBIT_CARRIER_DOWN: | |
300 span_log(&s->logging, SPAN_LOG_FLOW, "Carrier down.\n"); | |
301 if (s->msg_len > 0) | |
302 { | |
303 /* Whatever we have to date constitutes the message */ | |
304 s->put_msg(s->user_data, s->msg, s->msg_len); | |
305 s->msg_len = 0; | |
306 } | |
307 break; | |
308 default: | |
309 span_log(&s->logging, SPAN_LOG_WARNING, "Unexpected special put byte value - %d!\n", byte); | |
310 break; | |
311 } | |
312 return; | |
313 } | |
314 if ((octet = adsi_decode_baudot(s, (uint8_t) byte))) | |
315 s->msg[s->msg_len++] = octet; | |
316 if (s->msg_len >= 256) | |
317 { | |
318 s->put_msg(s->user_data, s->msg, s->msg_len); | |
319 s->msg_len = 0; | |
320 } | |
321 } | |
322 /*- End of function --------------------------------------------------------*/ | |
323 | |
324 static void adsi_rx_dtmf(void *user_data, const char *digits, int len) | |
325 { | |
326 adsi_rx_state_t *s; | |
327 | |
328 s = (adsi_rx_state_t *) user_data; | |
329 if (s->msg_len == 0) | |
330 { | |
331 /* Message starting. Start a 10s timeout, to make things more noise | |
332 tolerant for a detector running continuously when on hook. */ | |
333 s->in_progress = 80000; | |
334 } | |
335 for ( ; len && s->msg_len < 256; len--) | |
336 { | |
337 if (*digits == '#') | |
338 { | |
339 s->put_msg(s->user_data, s->msg, s->msg_len); | |
340 s->msg_len = 0; | |
341 } | |
342 else | |
343 { | |
344 s->msg[s->msg_len++] = *digits++; | |
345 } | |
346 } | |
347 } | |
348 /*- End of function --------------------------------------------------------*/ | |
349 | |
350 static void start_tx(adsi_tx_state_t *s) | |
351 { | |
352 switch (s->standard) | |
353 { | |
354 case ADSI_STANDARD_CLASS: | |
355 fsk_tx_init(&(s->fsktx), &preset_fsk_specs[FSK_BELL202], adsi_tx_get_bit, s); | |
356 break; | |
357 case ADSI_STANDARD_CLIP: | |
358 case ADSI_STANDARD_ACLIP: | |
359 case ADSI_STANDARD_JCLIP: | |
360 fsk_tx_init(&(s->fsktx), &preset_fsk_specs[FSK_V23CH1], adsi_tx_get_bit, s); | |
361 break; | |
362 case ADSI_STANDARD_CLIP_DTMF: | |
363 dtmf_tx_init(&(s->dtmftx)); | |
364 break; | |
365 case ADSI_STANDARD_TDD: | |
366 fsk_tx_init(&(s->fsktx), &preset_fsk_specs[FSK_WEITBRECHT], async_tx_get_bit, &(s->asynctx)); | |
367 async_tx_init(&(s->asynctx), 5, ASYNC_PARITY_NONE, 2, FALSE, adsi_tdd_get_async_byte, s); | |
368 /* Schedule an explicit shift at the start of baudot transmission */ | |
369 s->baudot_shift = 2; | |
370 break; | |
371 } | |
372 s->tx_signal_on = TRUE; | |
373 } | |
374 /*- End of function --------------------------------------------------------*/ | |
375 | |
376 void adsi_rx(adsi_rx_state_t *s, const int16_t *amp, int len) | |
377 { | |
378 switch (s->standard) | |
379 { | |
380 case ADSI_STANDARD_CLIP_DTMF: | |
381 /* Apply a message timeout. */ | |
382 s->in_progress -= len; | |
383 if (s->in_progress <= 0) | |
384 s->msg_len = 0; | |
385 dtmf_rx(&(s->dtmfrx), amp, len); | |
386 break; | |
387 default: | |
388 fsk_rx(&(s->fskrx), amp, len); | |
389 break; | |
390 } | |
391 } | |
392 /*- End of function --------------------------------------------------------*/ | |
393 | |
394 void adsi_rx_init(adsi_rx_state_t *s, | |
395 int standard, | |
396 put_msg_func_t put_msg, | |
397 void *user_data) | |
398 { | |
399 memset(s, 0, sizeof(*s)); | |
400 s->put_msg = put_msg; | |
401 s->user_data = user_data; | |
402 switch (standard) | |
403 { | |
404 case ADSI_STANDARD_CLASS: | |
405 fsk_rx_init(&(s->fskrx), &preset_fsk_specs[FSK_BELL202], FALSE, adsi_rx_put_bit, s); | |
406 break; | |
407 case ADSI_STANDARD_CLIP: | |
408 case ADSI_STANDARD_ACLIP: | |
409 case ADSI_STANDARD_JCLIP: | |
410 fsk_rx_init(&(s->fskrx), &preset_fsk_specs[FSK_V23CH1], FALSE, adsi_rx_put_bit, s); | |
411 break; | |
412 case ADSI_STANDARD_CLIP_DTMF: | |
413 dtmf_rx_init(&(s->dtmfrx), adsi_rx_dtmf, s); | |
414 break; | |
415 case ADSI_STANDARD_TDD: | |
416 fsk_rx_init(&(s->fskrx), &preset_fsk_specs[FSK_WEITBRECHT], FALSE, async_rx_put_bit, &(s->asyncrx)); | |
417 async_rx_init(&(s->asyncrx), 5, ASYNC_PARITY_NONE, 2, TRUE, adsi_tdd_put_async_byte, s); | |
418 break; | |
419 } | |
420 s->standard = standard; | |
421 span_log_init(&s->logging, SPAN_LOG_NONE, NULL); | |
422 } | |
423 /*- End of function --------------------------------------------------------*/ | |
424 | |
425 int adsi_tx(adsi_tx_state_t *s, int16_t *amp, int max_len) | |
426 { | |
427 int len; | |
428 | |
429 len = tone_gen(&(s->alert_tone_gen), amp, max_len); | |
430 switch (s->standard) | |
431 { | |
432 case ADSI_STANDARD_CLIP_DTMF: | |
433 if (len < max_len) | |
434 len += dtmf_tx(&(s->dtmftx), amp, max_len - len); | |
435 break; | |
436 default: | |
437 if (len < max_len && s->tx_signal_on) | |
438 len += fsk_tx(&(s->fsktx), amp + len, max_len - len); | |
439 break; | |
440 } | |
441 return len; | |
442 } | |
443 /*- End of function --------------------------------------------------------*/ | |
444 | |
445 void adsi_send_alert_tone(adsi_tx_state_t *s) | |
446 { | |
447 tone_gen_init(&(s->alert_tone_gen), &(s->alert_tone_desc)); | |
448 } | |
449 /*- End of function --------------------------------------------------------*/ | |
450 | |
451 int adsi_put_message(adsi_tx_state_t *s, uint8_t *msg, int len) | |
452 { | |
453 int i; | |
454 int j; | |
455 int k; | |
456 int byte; | |
457 int parity; | |
458 int sum; | |
459 size_t ii; | |
460 uint16_t crc_value; | |
461 | |
462 /* Don't inject a new message when a previous one is still in progress */ | |
463 if (s->msg_len > 0) | |
464 return 0; | |
465 if (!s->tx_signal_on) | |
466 { | |
467 /* We need to restart the modem */ | |
468 start_tx(s); | |
469 } | |
470 switch (s->standard) | |
471 { | |
472 case ADSI_STANDARD_CLIP_DTMF: | |
473 if (len >= 128) | |
474 return -1; | |
475 msg[len] = '\0'; | |
476 len -= (int) dtmf_tx_put(&(s->dtmftx), (char *) msg); | |
477 break; | |
478 case ADSI_STANDARD_JCLIP: | |
479 if (len > 128 - 9) | |
480 return -1; | |
481 i = 0; | |
482 s->msg[i++] = DLE; | |
483 s->msg[i++] = SOH; | |
484 s->msg[i++] = 0x07; //header | |
485 s->msg[i++] = DLE; | |
486 s->msg[i++] = STX; | |
487 s->msg[i++] = msg[0]; | |
488 s->msg[i++] = (uint8_t) (len - 2); | |
489 /* We might need to byte stuff the overall length, but the rest of the | |
490 message should already be stuffed. */ | |
491 if (len - 2 == DLE) | |
492 s->msg[i++] = DLE; | |
493 memcpy(&s->msg[i], &msg[2], len - 2); | |
494 i += len - 2; | |
495 s->msg[i++] = DLE; | |
496 s->msg[i++] = ETX; | |
497 | |
498 /* Set the parity bits */ | |
499 for (j = 0; j < i; j++) | |
500 { | |
501 byte = s->msg[j]; | |
502 parity = 0; | |
503 for (k = 1; k <= 7; k++) | |
504 parity ^= (byte << k); | |
505 s->msg[j] = (s->msg[j] & 0x7F) | ((uint8_t) parity & 0x80); | |
506 } | |
507 | |
508 crc_value = crc_itu16_calc(s->msg + 2, i - 2, 0); | |
509 s->msg[i++] = (uint8_t) (crc_value & 0xFF); | |
510 s->msg[i++] = (uint8_t) ((crc_value >> 8) & 0xFF); | |
511 s->msg_len = i; | |
512 | |
513 s->ones_len = 80; | |
514 break; | |
515 case ADSI_STANDARD_TDD: | |
516 if (len > 255) | |
517 return -1; | |
518 memcpy(s->msg, msg, len); | |
519 s->msg_len = len; | |
520 break; | |
521 default: | |
522 if (len > 255) | |
523 return -1; | |
524 memcpy(s->msg, msg, len); | |
525 /* Force the length in case it is wrong */ | |
526 s->msg[1] = (uint8_t) (len - 2); | |
527 /* Add the sumcheck */ | |
528 sum = 0; | |
529 for (ii = 0; ii < (size_t) len; ii++) | |
530 sum += s->msg[ii]; | |
531 s->msg[len] = (uint8_t) ((-sum) & 0xFF); | |
532 s->msg_len = len + 1; | |
533 s->ones_len = 80; | |
534 break; | |
535 } | |
536 /* Prepare the bit sequencing */ | |
537 s->byteno = 0; | |
538 s->bitpos = 0; | |
539 s->bitno = 0; | |
540 return len; | |
541 } | |
542 /*- End of function --------------------------------------------------------*/ | |
543 | |
544 void adsi_tx_init(adsi_tx_state_t *s, int standard) | |
545 { | |
546 memset(s, 0, sizeof(*s)); | |
547 make_tone_gen_descriptor(&(s->alert_tone_desc), | |
548 2130, | |
549 -13, | |
550 2750, | |
551 -13, | |
552 110, | |
553 60, | |
554 0, | |
555 0, | |
556 FALSE); | |
557 s->standard = standard; | |
558 span_log_init(&s->logging, SPAN_LOG_NONE, NULL); | |
559 start_tx(s); | |
560 } | |
561 /*- End of function --------------------------------------------------------*/ | |
562 | |
563 static uint8_t adsi_encode_baudot(adsi_tx_state_t *s, uint8_t ch) | |
564 { | |
565 static const uint8_t conv[128] = | |
566 { | |
567 0x00, /* NUL */ | |
568 0xFF, /* */ | |
569 0xFF, /* */ | |
570 0xFF, /* */ | |
571 0xFF, /* */ | |
572 0xFF, /* */ | |
573 0xFF, /* */ | |
574 0xFF, /* */ | |
575 0xFF, /* */ | |
576 0xFF, /* */ | |
577 0x42, /* LF */ | |
578 0xFF, /* */ | |
579 0xFF, /* */ | |
580 0x48, /* CR */ | |
581 0xFF, /* */ | |
582 0xFF, /* */ | |
583 0xFF, /* */ | |
584 0xFF, /* */ | |
585 0xFF, /* */ | |
586 0xFF, /* */ | |
587 0xFF, /* */ | |
588 0xFF, /* */ | |
589 0xFF, /* */ | |
590 0xFF, /* */ | |
591 0xFF, /* */ | |
592 0xFF, /* */ | |
593 0xFF, /* */ | |
594 0xFF, /* */ | |
595 0xFF, /* */ | |
596 0xFF, /* */ | |
597 0xFF, /* */ | |
598 0xFF, /* */ | |
599 0x44, /* */ | |
600 0xFF, /* ! */ | |
601 0xFF, /* " */ | |
602 0x94, /* # */ | |
603 0x89, /* $ */ | |
604 0xFF, /* % */ | |
605 0xFF, /* & */ | |
606 0x85, /* ' */ | |
607 0x8F, /* ( */ | |
608 0x92, /* ) */ | |
609 0x8B, /* * */ | |
610 0x91, /* + */ | |
611 0x8C, /* , */ | |
612 0x83, /* - */ | |
613 0x9C, /* . */ | |
614 0x9D, /* / */ | |
615 0x96, /* 0 */ | |
616 0x97, /* 1 */ | |
617 0x93, /* 2 */ | |
618 0x81, /* 3 */ | |
619 0x8A, /* 4 */ | |
620 0x90, /* 5 */ | |
621 0x95, /* 6 */ | |
622 0x87, /* 7 */ | |
623 0x86, /* 8 */ | |
624 0x98, /* 9 */ | |
625 0x8E, /* : */ | |
626 0xFF, /* ; */ | |
627 0xFF, /* < */ | |
628 0x9E, /* = */ | |
629 0xFF, /* > */ | |
630 0x99, /* ? */ | |
631 0xFF, /* @ */ | |
632 0x03, /* A */ | |
633 0x19, /* B */ | |
634 0x0E, /* C */ | |
635 0x09, /* D */ | |
636 0x01, /* E */ | |
637 0x0D, /* F */ | |
638 0x1A, /* G */ | |
639 0x14, /* H */ | |
640 0x06, /* I */ | |
641 0x0B, /* J */ | |
642 0x0F, /* K */ | |
643 0x12, /* L */ | |
644 0x1C, /* M */ | |
645 0x0C, /* N */ | |
646 0x18, /* O */ | |
647 0x16, /* P */ | |
648 0x17, /* Q */ | |
649 0x0A, /* R */ | |
650 0x05, /* S */ | |
651 0x10, /* T */ | |
652 0x07, /* U */ | |
653 0x1E, /* V */ | |
654 0x13, /* W */ | |
655 0x1D, /* X */ | |
656 0x15, /* Y */ | |
657 0x11, /* Z */ | |
658 0xFF, /* [ */ | |
659 0xFF, /* \ */ | |
660 0xFF, /* ] */ | |
661 0x9B, /* ^ */ | |
662 0xFF, /* _ */ | |
663 0xFF, /* ` */ | |
664 0x03, /* a */ | |
665 0x19, /* b */ | |
666 0x0E, /* c */ | |
667 0x09, /* d */ | |
668 0x01, /* e */ | |
669 0x0D, /* f */ | |
670 0x1A, /* g */ | |
671 0x14, /* h */ | |
672 0x06, /* i */ | |
673 0x0B, /* j */ | |
674 0x0F, /* k */ | |
675 0x12, /* l */ | |
676 0x1C, /* m */ | |
677 0x0C, /* n */ | |
678 0x18, /* o */ | |
679 0x16, /* p */ | |
680 0x17, /* q */ | |
681 0x0A, /* r */ | |
682 0x05, /* s */ | |
683 0x10, /* t */ | |
684 0x07, /* u */ | |
685 0x1E, /* v */ | |
686 0x13, /* w */ | |
687 0x1D, /* x */ | |
688 0x15, /* y */ | |
689 0x11, /* z */ | |
690 0xFF, /* { */ | |
691 0xFF, /* | */ | |
692 0xFF, /* } */ | |
693 0xFF, /* ~ */ | |
694 0xFF, /* DEL */ | |
695 }; | |
696 | |
697 ch = conv[ch]; | |
698 if (ch != 0xFF) | |
699 { | |
700 if ((ch & 0x40)) | |
701 return ch & 0x1F; | |
702 if ((ch & 0x80)) | |
703 { | |
704 if (s->baudot_shift == 1) | |
705 return ch & 0x1F; | |
706 s->baudot_shift = 1; | |
707 return (BAUDOT_FIGURE_SHIFT << 5) | (ch & 0x1F); | |
708 } | |
709 else | |
710 { | |
711 if (s->baudot_shift == 0) | |
712 return ch & 0x1F; | |
713 s->baudot_shift = 0; | |
714 return (BAUDOT_LETTER_SHIFT << 5) | (ch & 0x1F); | |
715 } | |
716 } | |
717 return 0; | |
718 } | |
719 /*- End of function --------------------------------------------------------*/ | |
720 | |
721 static uint8_t adsi_decode_baudot(adsi_rx_state_t *s, uint8_t ch) | |
722 { | |
723 static const uint8_t conv[2][32] = | |
724 { | |
725 {"\000E\nA SIU\rDRJNFCKTZLWHYPQOBG^MXV^"}, | |
726 {"\0003\n- '87\r$4*,*:(5+)2#6019?*^./=^"} | |
727 }; | |
728 | |
729 switch (ch) | |
730 { | |
731 case BAUDOT_FIGURE_SHIFT: | |
732 s->baudot_shift = 1; | |
733 break; | |
734 case BAUDOT_LETTER_SHIFT: | |
735 s->baudot_shift = 0; | |
736 break; | |
737 default: | |
738 return conv[s->baudot_shift][ch]; | |
739 } | |
740 /* return 0 if we did not produce a character */ | |
741 return 0; | |
742 } | |
743 /*- End of function --------------------------------------------------------*/ | |
744 | |
745 int adsi_next_field(adsi_rx_state_t *s, const uint8_t *msg, int msg_len, int pos, uint8_t *field_type, uint8_t const **field_body, int *field_len) | |
746 { | |
747 int i; | |
748 | |
749 /* Return -1 for no more fields. Return -2 for message structure corrupt. */ | |
750 switch (s->standard) | |
751 { | |
752 case ADSI_STANDARD_CLASS: | |
753 case ADSI_STANDARD_CLIP: | |
754 case ADSI_STANDARD_ACLIP: | |
755 if (pos >= msg_len) | |
756 return -1; | |
757 /* For MDMF type messages, these standards all use "IE" type fields - type, | |
758 length, contents - and similar headers */ | |
759 if (pos <= 0) | |
760 { | |
761 /* Return the message type */ | |
762 *field_type = msg[0]; | |
763 *field_len = 0; | |
764 *field_body = NULL; | |
765 pos = 2; | |
766 } | |
767 else | |
768 { | |
769 if ((msg[0] & 0x80)) | |
770 { | |
771 /* MDMF messages seem to always have a message type with the MSB set. Is that | |
772 guaranteed? */ | |
773 *field_type = msg[pos++]; | |
774 *field_len = msg[pos++]; | |
775 *field_body = msg + pos; | |
776 } | |
777 else | |
778 { | |
779 /* SDMF */ | |
780 *field_type = 0; | |
781 *field_len = msg_len - pos; | |
782 *field_body = msg + pos; | |
783 } | |
784 pos += *field_len; | |
785 } | |
786 if (pos > msg_len) | |
787 return -2; | |
788 break; | |
789 case ADSI_STANDARD_JCLIP: | |
790 if (pos >= msg_len - 2) | |
791 return -1; | |
792 if (pos <= 0) | |
793 { | |
794 /* Return the message type */ | |
795 pos = 5; | |
796 *field_type = msg[pos++]; | |
797 if (*field_type == DLE) | |
798 pos++; | |
799 if (msg[pos++] == DLE) | |
800 pos++; | |
801 *field_len = 0; | |
802 *field_body = NULL; | |
803 } | |
804 else | |
805 { | |
806 *field_type = msg[pos++]; | |
807 if (*field_type == DLE) | |
808 pos++; | |
809 *field_len = msg[pos++]; | |
810 if (*field_len == DLE) | |
811 pos++; | |
812 /* TODO: we assume here that the body contains no DLE's that would have been stuffed */ | |
813 *field_body = msg + pos; | |
814 pos += *field_len; | |
815 } | |
816 if (pos > msg_len - 2) | |
817 return -2; | |
818 break; | |
819 case ADSI_STANDARD_CLIP_DTMF: | |
820 if (pos >= msg_len) | |
821 return -1; | |
822 if (pos < 0) | |
823 pos = 0; | |
824 *field_type = msg[pos++]; | |
825 *field_body = msg + pos; | |
826 i = pos; | |
827 while (i < msg_len && msg[i] != '#') | |
828 i++; | |
829 *field_len = i - pos; | |
830 pos = i; | |
831 if (msg[pos] == '#') | |
832 pos++; | |
833 if (pos > msg_len) | |
834 return -2; | |
835 break; | |
836 case ADSI_STANDARD_TDD: | |
837 if (pos >= msg_len) | |
838 return -1; | |
839 *field_type = 0; | |
840 *field_body = msg; | |
841 *field_len = msg_len; | |
842 pos = msg_len; | |
843 break; | |
844 } | |
845 return pos; | |
846 } | |
847 /*- End of function --------------------------------------------------------*/ | |
848 | |
849 int adsi_add_field(adsi_tx_state_t *s, uint8_t *msg, int len, uint8_t field_type, uint8_t const *field_body, int field_len) | |
850 { | |
851 int i; | |
852 int x; | |
853 | |
854 switch (s->standard) | |
855 { | |
856 case ADSI_STANDARD_CLASS: | |
857 case ADSI_STANDARD_CLIP: | |
858 case ADSI_STANDARD_ACLIP: | |
859 /* These standards all use "IE" type fields - type, length, value - and similar headers */ | |
860 if (len <= 0) | |
861 { | |
862 /* Initialise a new message. The field type is actually the message type. */ | |
863 msg[0] = field_type; | |
864 msg[1] = 0; | |
865 len = 2; | |
866 } | |
867 else | |
868 { | |
869 /* Add to a message in progress. */ | |
870 if (field_type) | |
871 { | |
872 msg[len++] = field_type; | |
873 msg[len++] = (uint8_t) field_len; | |
874 if (field_len == DLE) | |
875 msg[len++] = (uint8_t) field_len; | |
876 memcpy(msg + len, field_body, field_len); | |
877 len += field_len; | |
878 } | |
879 else | |
880 { | |
881 /* No field type or length, for restricted single message formats */ | |
882 memcpy(msg + len, field_body, field_len); | |
883 len += field_len; | |
884 } | |
885 } | |
886 break; | |
887 case ADSI_STANDARD_JCLIP: | |
888 /* This standard uses "IE" type fields - type, length, value - but escapes DLE characters, | |
889 to prevent immitation of a control octet. */ | |
890 if (len <= 0) | |
891 { | |
892 /* Initialise a new message. The field type is actually the message type. */ | |
893 msg[0] = field_type; | |
894 msg[1] = 0; | |
895 len = 2; | |
896 } | |
897 else | |
898 { | |
899 /* Add to a message in progress. */ | |
900 msg[len++] = field_type; | |
901 if (field_type == DLE) | |
902 msg[len++] = field_type; | |
903 msg[len++] = (uint8_t) field_len; | |
904 if (field_len == DLE) | |
905 msg[len++] = (uint8_t) field_len; | |
906 for (i = 0; i < field_len; i++) | |
907 { | |
908 msg[len++] = field_body[i]; | |
909 if (field_body[i] == DLE) | |
910 msg[len++] = field_body[i]; | |
911 } | |
912 } | |
913 break; | |
914 case ADSI_STANDARD_CLIP_DTMF: | |
915 if (len < 0) | |
916 { | |
917 len = 0; | |
918 } | |
919 else | |
920 { | |
921 msg[len] = field_type; | |
922 memcpy(msg + len + 1, field_body, field_len); | |
923 msg[len + field_len + 1] = '#'; | |
924 len += (field_len + 2); | |
925 } | |
926 break; | |
927 case ADSI_STANDARD_TDD: | |
928 if (len < 0) | |
929 len = 0; | |
930 for (i = 0; i < field_len; i++) | |
931 { | |
932 if ((x = adsi_encode_baudot(s, field_body[i]))) | |
933 { | |
934 if ((x & 0x3E0)) | |
935 msg[len++] = (uint8_t) ((x >> 5) & 0x1F); | |
936 msg[len++] = (uint8_t) (x & 0x1F); | |
937 } | |
938 } | |
939 break; | |
940 } | |
941 | |
942 return len; | |
943 } | |
944 /*- End of function --------------------------------------------------------*/ | |
945 | |
946 const char *adsi_standard_to_str(int standard) | |
947 { | |
948 switch (standard) | |
949 { | |
950 case ADSI_STANDARD_CLASS: | |
951 return "CLASS"; | |
952 case ADSI_STANDARD_CLIP: | |
953 return "CLIP"; | |
954 case ADSI_STANDARD_ACLIP: | |
955 return "A-CLIP"; | |
956 case ADSI_STANDARD_JCLIP: | |
957 return "J-CLIP"; | |
958 case ADSI_STANDARD_CLIP_DTMF: | |
959 return "CLIP-DTMF"; | |
960 case ADSI_STANDARD_TDD: | |
961 return "TDD"; | |
962 } | |
963 return "???"; | |
964 } | |
965 /*- End of function --------------------------------------------------------*/ | |
966 /*- End of file ------------------------------------------------------------*/ |