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 ------------------------------------------------------------*/ |
