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