Mercurial > hg > audiostuff
comparison spandsp-0.0.6pre17/src/v8.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 * v8.c - V.8 modem negotiation processing. | |
| 5 * | |
| 6 * Written by Steve Underwood <steveu@coppice.org> | |
| 7 * | |
| 8 * Copyright (C) 2004 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: v8.c,v 1.42.4.3 2009/12/28 12:20:47 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 <memory.h> | |
| 38 #if defined(HAVE_TGMATH_H) | |
| 39 #include <tgmath.h> | |
| 40 #endif | |
| 41 #if defined(HAVE_MATH_H) | |
| 42 #include <math.h> | |
| 43 #endif | |
| 44 #include "floating_fudge.h" | |
| 45 | |
| 46 #include "spandsp/telephony.h" | |
| 47 #include "spandsp/logging.h" | |
| 48 #include "spandsp/queue.h" | |
| 49 #include "spandsp/async.h" | |
| 50 #include "spandsp/vector_int.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/modem_connect_tones.h" | |
| 59 #include "spandsp/v8.h" | |
| 60 | |
| 61 #include "spandsp/private/logging.h" | |
| 62 #include "spandsp/private/fsk.h" | |
| 63 #include "spandsp/private/modem_connect_tones.h" | |
| 64 #include "spandsp/private/v8.h" | |
| 65 | |
| 66 enum | |
| 67 { | |
| 68 V8_WAIT_1S, | |
| 69 V8_CI_ON, | |
| 70 V8_CI_OFF, | |
| 71 V8_HEARD_ANSAM, | |
| 72 V8_CM_ON, | |
| 73 V8_CJ_ON, | |
| 74 V8_CM_WAIT, | |
| 75 | |
| 76 V8_SIGC, | |
| 77 V8_JM_ON, | |
| 78 V8_SIGA, | |
| 79 | |
| 80 V8_PARKED | |
| 81 } v8_states_e; | |
| 82 | |
| 83 enum | |
| 84 { | |
| 85 V8_SYNC_UNKNOWN = 0, | |
| 86 V8_SYNC_CI, | |
| 87 V8_SYNC_CM_JM, | |
| 88 V8_SYNC_V92 | |
| 89 } v8_sync_types_e; | |
| 90 | |
| 91 enum | |
| 92 { | |
| 93 V8_CALL_FUNCTION_TAG = 0x01, | |
| 94 V8_MODULATION_TAG = 0x05, | |
| 95 V8_PROTOCOLS_TAG = 0x0A, | |
| 96 V8_PSTN_ACCESS_TAG = 0x0D, | |
| 97 V8_NSF_TAG = 0x0F, | |
| 98 V8_PCM_MODEM_AVAILABILITY_TAG = 0x07, | |
| 99 V8_T66_TAG = 0x0E | |
| 100 }; | |
| 101 | |
| 102 enum | |
| 103 { | |
| 104 V8_CI_SYNC_OCTET = 0x00, | |
| 105 V8_CM_JM_SYNC_OCTET = 0xE0 | |
| 106 }; | |
| 107 | |
| 108 SPAN_DECLARE(const char *) v8_call_function_to_str(int call_function) | |
| 109 { | |
| 110 switch (call_function) | |
| 111 { | |
| 112 case V8_CALL_TBS: | |
| 113 return "TBS"; | |
| 114 case V8_CALL_H324: | |
| 115 return "H.324 PSTN multimedia terminal"; | |
| 116 case V8_CALL_V18: | |
| 117 return "V.18 textphone"; | |
| 118 case V8_CALL_T101: | |
| 119 return "T.101 videotext"; | |
| 120 case V8_CALL_T30_TX: | |
| 121 return "T.30 Tx FAX"; | |
| 122 case V8_CALL_T30_RX: | |
| 123 return "T.30 Rx FAX"; | |
| 124 case V8_CALL_V_SERIES: | |
| 125 return "V series modem data"; | |
| 126 case V8_CALL_FUNCTION_EXTENSION: | |
| 127 return "Call function is in extention octet"; | |
| 128 } | |
| 129 return "???"; | |
| 130 } | |
| 131 /*- End of function --------------------------------------------------------*/ | |
| 132 | |
| 133 SPAN_DECLARE(const char *) v8_modulation_to_str(int modulation_scheme) | |
| 134 { | |
| 135 switch (modulation_scheme) | |
| 136 { | |
| 137 case V8_MOD_V17: | |
| 138 return "V.17 half-duplex"; | |
| 139 case V8_MOD_V21: | |
| 140 return "V.21 duplex"; | |
| 141 case V8_MOD_V22: | |
| 142 return "V.22/V.22bis duplex"; | |
| 143 case V8_MOD_V23HALF: | |
| 144 return "V.23 half-duplex"; | |
| 145 case V8_MOD_V23: | |
| 146 return "V.23 duplex"; | |
| 147 case V8_MOD_V26BIS: | |
| 148 return "V.26bis duplex"; | |
| 149 case V8_MOD_V26TER: | |
| 150 return "V.26ter duplex"; | |
| 151 case V8_MOD_V27TER: | |
| 152 return "V.27ter duplex"; | |
| 153 case V8_MOD_V29: | |
| 154 return "V.29 half-duplex"; | |
| 155 case V8_MOD_V32: | |
| 156 return "V.32/V.32bis duplex"; | |
| 157 case V8_MOD_V34HALF: | |
| 158 return "V.34 half-duplex"; | |
| 159 case V8_MOD_V34: | |
| 160 return "V.34 duplex"; | |
| 161 case V8_MOD_V90: | |
| 162 return "V.90 duplex"; | |
| 163 case V8_MOD_V92: | |
| 164 return "V.92 duplex"; | |
| 165 case V8_MOD_FAILED: | |
| 166 return "negotiation failed"; | |
| 167 } | |
| 168 return "???"; | |
| 169 } | |
| 170 /*- End of function --------------------------------------------------------*/ | |
| 171 | |
| 172 SPAN_DECLARE(const char *) v8_protocol_to_str(int protocol) | |
| 173 { | |
| 174 switch (protocol) | |
| 175 { | |
| 176 case V8_PROTOCOL_NONE: | |
| 177 return "None"; | |
| 178 case V8_PROTOCOL_LAPM_V42: | |
| 179 return "LAPM"; | |
| 180 case V8_PROTOCOL_EXTENSION: | |
| 181 return "Extension"; | |
| 182 } | |
| 183 return "Undefined"; | |
| 184 } | |
| 185 /*- End of function --------------------------------------------------------*/ | |
| 186 | |
| 187 SPAN_DECLARE(const char *) v8_pstn_access_to_str(int pstn_access) | |
| 188 { | |
| 189 switch (pstn_access) | |
| 190 { | |
| 191 case V8_PSTN_ACCESS_CALL_DCE_CELLULAR: | |
| 192 return "Calling modem on cellular"; | |
| 193 case V8_PSTN_ACCESS_ANSWER_DCE_CELLULAR: | |
| 194 return "Answering modem on cellular"; | |
| 195 case V8_PSTN_ACCESS_ANSWER_DCE_CELLULAR | V8_PSTN_ACCESS_CALL_DCE_CELLULAR: | |
| 196 return "Answering and calling modems on cellular"; | |
| 197 case V8_PSTN_ACCESS_DCE_ON_DIGITAL: | |
| 198 return "DCE on digital"; | |
| 199 case V8_PSTN_ACCESS_DCE_ON_DIGITAL | V8_PSTN_ACCESS_CALL_DCE_CELLULAR: | |
| 200 return "DCE on digital, and calling modem on cellular"; | |
| 201 case V8_PSTN_ACCESS_DCE_ON_DIGITAL | V8_PSTN_ACCESS_ANSWER_DCE_CELLULAR: | |
| 202 return "DCE on digital, answering modem on cellular"; | |
| 203 case V8_PSTN_ACCESS_DCE_ON_DIGITAL | V8_PSTN_ACCESS_ANSWER_DCE_CELLULAR | V8_PSTN_ACCESS_CALL_DCE_CELLULAR: | |
| 204 return "DCE on digital, and answering and calling modems on cellular"; | |
| 205 } | |
| 206 return "???"; | |
| 207 } | |
| 208 /*- End of function --------------------------------------------------------*/ | |
| 209 | |
| 210 SPAN_DECLARE(const char *) v8_nsf_to_str(int nsf) | |
| 211 { | |
| 212 switch (nsf) | |
| 213 { | |
| 214 case 0: | |
| 215 return "???"; | |
| 216 } | |
| 217 return "???"; | |
| 218 } | |
| 219 /*- End of function --------------------------------------------------------*/ | |
| 220 | |
| 221 SPAN_DECLARE(const char *) v8_pcm_modem_availability_to_str(int pcm_modem_availability) | |
| 222 { | |
| 223 switch (pcm_modem_availability) | |
| 224 { | |
| 225 case 0: | |
| 226 return "PCM unavailable"; | |
| 227 case V8_PSTN_PCM_MODEM_V90_V92_ANALOGUE: | |
| 228 return "V.90/V.92 analogue available"; | |
| 229 case V8_PSTN_PCM_MODEM_V90_V92_DIGITAL: | |
| 230 return "V.90/V.92 digital available"; | |
| 231 case V8_PSTN_PCM_MODEM_V90_V92_DIGITAL | V8_PSTN_PCM_MODEM_V90_V92_ANALOGUE: | |
| 232 return "V.90/V.92 digital/analogue available"; | |
| 233 case V8_PSTN_PCM_MODEM_V91: | |
| 234 return "V.91 available"; | |
| 235 case V8_PSTN_PCM_MODEM_V91 | V8_PSTN_PCM_MODEM_V90_V92_ANALOGUE: | |
| 236 return "V.91 and V.90/V.92 analogue available"; | |
| 237 case V8_PSTN_PCM_MODEM_V91 | V8_PSTN_PCM_MODEM_V90_V92_DIGITAL: | |
| 238 return "V.91 and V.90/V.92 digital available"; | |
| 239 case V8_PSTN_PCM_MODEM_V91 | V8_PSTN_PCM_MODEM_V90_V92_DIGITAL | V8_PSTN_PCM_MODEM_V90_V92_ANALOGUE: | |
| 240 return "V.91 and V.90/V.92 digital/analogue available"; | |
| 241 } | |
| 242 return "???"; | |
| 243 } | |
| 244 /*- End of function --------------------------------------------------------*/ | |
| 245 | |
| 246 SPAN_DECLARE(const char *) v8_t66_to_str(int t66) | |
| 247 { | |
| 248 /* T.66 doesn't really define any V.8 values. The bits are all reserved. */ | |
| 249 switch (t66) | |
| 250 { | |
| 251 case 0: | |
| 252 return "???"; | |
| 253 case 1: | |
| 254 return "Reserved TIA"; | |
| 255 case 2: | |
| 256 return "Reserved"; | |
| 257 case 3: | |
| 258 return "Reserved TIA + others"; | |
| 259 case 4: | |
| 260 return "Reserved"; | |
| 261 case 5: | |
| 262 return "Reserved TIA + others"; | |
| 263 case 6: | |
| 264 return "Reserved"; | |
| 265 case 7: | |
| 266 return "Reserved TIA + others"; | |
| 267 } | |
| 268 return "???"; | |
| 269 } | |
| 270 /*- End of function --------------------------------------------------------*/ | |
| 271 | |
| 272 SPAN_DECLARE(void) v8_log_supported_modulations(v8_state_t *s, int modulation_schemes) | |
| 273 { | |
| 274 const char *comma; | |
| 275 int i; | |
| 276 | |
| 277 comma = ""; | |
| 278 span_log(&s->logging, SPAN_LOG_FLOW, ""); | |
| 279 for (i = 0; i < 32; i++) | |
| 280 { | |
| 281 if ((modulation_schemes & (1 << i))) | |
| 282 { | |
| 283 span_log(&s->logging, SPAN_LOG_FLOW | SPAN_LOG_SUPPRESS_LABELLING, "%s%s", comma, v8_modulation_to_str(modulation_schemes & (1 << i))); | |
| 284 comma = ", "; | |
| 285 } | |
| 286 } | |
| 287 span_log(&s->logging, SPAN_LOG_FLOW | SPAN_LOG_SUPPRESS_LABELLING, " supported\n"); | |
| 288 } | |
| 289 /*- End of function --------------------------------------------------------*/ | |
| 290 | |
| 291 static const uint8_t *process_call_function(v8_state_t *s, const uint8_t *p) | |
| 292 { | |
| 293 s->result.call_function = (*p >> 5) & 0x07; | |
| 294 span_log(&s->logging, SPAN_LOG_FLOW, "%s\n", v8_call_function_to_str(s->result.call_function)); | |
| 295 return ++p; | |
| 296 } | |
| 297 /*- End of function --------------------------------------------------------*/ | |
| 298 | |
| 299 static const uint8_t *process_modulation_mode(v8_state_t *s, const uint8_t *p) | |
| 300 { | |
| 301 unsigned int far_end_modulations; | |
| 302 | |
| 303 /* Modulation mode octet */ | |
| 304 far_end_modulations = 0; | |
| 305 if (*p & 0x80) | |
| 306 far_end_modulations |= V8_MOD_V34HALF; | |
| 307 if (*p & 0x40) | |
| 308 far_end_modulations |= V8_MOD_V34; | |
| 309 if (*p & 0x20) | |
| 310 far_end_modulations |= V8_MOD_V90; | |
| 311 | |
| 312 /* Check for an extension octet */ | |
| 313 if ((*++p & 0x38) == 0x10) | |
| 314 { | |
| 315 if (*p & 0x80) | |
| 316 far_end_modulations |= V8_MOD_V27TER; | |
| 317 if (*p & 0x40) | |
| 318 far_end_modulations |= V8_MOD_V29; | |
| 319 if (*p & 0x04) | |
| 320 far_end_modulations |= V8_MOD_V17; | |
| 321 if (*p & 0x02) | |
| 322 far_end_modulations |= V8_MOD_V22; | |
| 323 if (*p & 0x01) | |
| 324 far_end_modulations |= V8_MOD_V32; | |
| 325 | |
| 326 /* Check for an extension octet */ | |
| 327 if ((*++p & 0x38) == 0x10) | |
| 328 { | |
| 329 if (*p & 0x80) | |
| 330 far_end_modulations |= V8_MOD_V21; | |
| 331 if (*p & 0x40) | |
| 332 far_end_modulations |= V8_MOD_V23HALF; | |
| 333 if (*p & 0x04) | |
| 334 far_end_modulations |= V8_MOD_V23; | |
| 335 if (*p & 0x02) | |
| 336 far_end_modulations |= V8_MOD_V26BIS; | |
| 337 if (*p & 0x01) | |
| 338 far_end_modulations |= V8_MOD_V26TER; | |
| 339 } | |
| 340 } | |
| 341 s->far_end_modulations = | |
| 342 s->result.modulations = far_end_modulations; | |
| 343 v8_log_supported_modulations(s, far_end_modulations); | |
| 344 return ++p; | |
| 345 } | |
| 346 /*- End of function --------------------------------------------------------*/ | |
| 347 | |
| 348 static const uint8_t *process_protocols(v8_state_t *s, const uint8_t *p) | |
| 349 { | |
| 350 s->result.protocol = (*p >> 5) & 0x07; | |
| 351 span_log(&s->logging, SPAN_LOG_FLOW | SPAN_LOG_SUPPRESS_LABELLING, "%s\n", v8_protocol_to_str(s->result.protocol)); | |
| 352 return ++p; | |
| 353 } | |
| 354 /*- End of function --------------------------------------------------------*/ | |
| 355 | |
| 356 static const uint8_t *process_pstn_access(v8_state_t *s, const uint8_t *p) | |
| 357 { | |
| 358 s->result.pstn_access = (*p >> 5) & 0x07; | |
| 359 span_log(&s->logging, SPAN_LOG_FLOW | SPAN_LOG_SUPPRESS_LABELLING, "%s\n", v8_pstn_access_to_str(s->result.pstn_access)); | |
| 360 return ++p; | |
| 361 } | |
| 362 /*- End of function --------------------------------------------------------*/ | |
| 363 | |
| 364 static const uint8_t *process_non_standard_facilities(v8_state_t *s, const uint8_t *p) | |
| 365 { | |
| 366 s->result.nsf = (*p >> 5) & 0x07; | |
| 367 span_log(&s->logging, SPAN_LOG_FLOW | SPAN_LOG_SUPPRESS_LABELLING, "%s\n", v8_nsf_to_str(s->result.nsf)); | |
| 368 return p; | |
| 369 } | |
| 370 /*- End of function --------------------------------------------------------*/ | |
| 371 | |
| 372 static const uint8_t *process_pcm_modem_availability(v8_state_t *s, const uint8_t *p) | |
| 373 { | |
| 374 s->result.pcm_modem_availability = (*p >> 5) & 0x07; | |
| 375 span_log(&s->logging, SPAN_LOG_FLOW | SPAN_LOG_SUPPRESS_LABELLING, "%s\n", v8_pcm_modem_availability_to_str(s->result.pcm_modem_availability)); | |
| 376 return ++p; | |
| 377 } | |
| 378 /*- End of function --------------------------------------------------------*/ | |
| 379 | |
| 380 static const uint8_t *process_t66(v8_state_t *s, const uint8_t *p) | |
| 381 { | |
| 382 s->result.t66 = (*p >> 5) & 0x07; | |
| 383 span_log(&s->logging, SPAN_LOG_FLOW | SPAN_LOG_SUPPRESS_LABELLING, "%s\n", v8_t66_to_str(s->result.t66)); | |
| 384 return ++p; | |
| 385 } | |
| 386 /*- End of function --------------------------------------------------------*/ | |
| 387 | |
| 388 static void ci_decode(v8_state_t *s) | |
| 389 { | |
| 390 if ((s->rx_data[0] & 0x1F) == V8_CALL_FUNCTION_TAG) | |
| 391 process_call_function(s, &s->rx_data[0]); | |
| 392 } | |
| 393 /*- End of function --------------------------------------------------------*/ | |
| 394 | |
| 395 static void cm_jm_decode(v8_state_t *s) | |
| 396 { | |
| 397 const uint8_t *p; | |
| 398 | |
| 399 if (s->got_cm_jm) | |
| 400 return; | |
| 401 | |
| 402 /* We must receive two consecutive identical CM or JM sequences to accept it. */ | |
| 403 if (s->cm_jm_len <= 0 | |
| 404 || | |
| 405 s->cm_jm_len != s->rx_data_ptr | |
| 406 || | |
| 407 memcmp(s->cm_jm_data, s->rx_data, s->rx_data_ptr)) | |
| 408 { | |
| 409 /* Save the current CM or JM sequence */ | |
| 410 s->cm_jm_len = s->rx_data_ptr; | |
| 411 memcpy(s->cm_jm_data, s->rx_data, s->rx_data_ptr); | |
| 412 return; | |
| 413 } | |
| 414 /* We have a matching pair of CMs or JMs, so we are happy this is correct. */ | |
| 415 s->got_cm_jm = TRUE; | |
| 416 | |
| 417 span_log(&s->logging, SPAN_LOG_FLOW, "Decoding\n"); | |
| 418 | |
| 419 /* Zero indicates the end */ | |
| 420 s->cm_jm_data[s->cm_jm_len] = 0; | |
| 421 | |
| 422 s->result.modulations = 0; | |
| 423 p = s->cm_jm_data; | |
| 424 | |
| 425 while (*p) | |
| 426 { | |
| 427 switch (*p & 0x1F) | |
| 428 { | |
| 429 case V8_CALL_FUNCTION_TAG: | |
| 430 p = process_call_function(s, p); | |
| 431 break; | |
| 432 case V8_MODULATION_TAG: | |
| 433 p = process_modulation_mode(s, p); | |
| 434 break; | |
| 435 case V8_PROTOCOLS_TAG: | |
| 436 p = process_protocols(s, p); | |
| 437 break; | |
| 438 case V8_PSTN_ACCESS_TAG: | |
| 439 p = process_pstn_access(s, p); | |
| 440 break; | |
| 441 case V8_NSF_TAG: | |
| 442 p = process_non_standard_facilities(s, p); | |
| 443 break; | |
| 444 case V8_PCM_MODEM_AVAILABILITY_TAG: | |
| 445 p = process_pcm_modem_availability(s, p); | |
| 446 break; | |
| 447 case V8_T66_TAG: | |
| 448 p = process_t66(s, p); | |
| 449 break; | |
| 450 default: | |
| 451 p++; | |
| 452 break; | |
| 453 } | |
| 454 /* Skip any future extensions we do not understand */ | |
| 455 while ((*p & 0x38) == 0x10) | |
| 456 p++; | |
| 457 } | |
| 458 } | |
| 459 /*- End of function --------------------------------------------------------*/ | |
| 460 | |
| 461 static void put_bit(void *user_data, int bit) | |
| 462 { | |
| 463 v8_state_t *s; | |
| 464 int new_preamble_type; | |
| 465 const char *tag; | |
| 466 uint8_t data; | |
| 467 | |
| 468 s = user_data; | |
| 469 if (bit < 0) | |
| 470 { | |
| 471 /* Special conditions */ | |
| 472 switch (bit) | |
| 473 { | |
| 474 case SIG_STATUS_CARRIER_UP: | |
| 475 case SIG_STATUS_CARRIER_DOWN: | |
| 476 case SIG_STATUS_TRAINING_SUCCEEDED: | |
| 477 case SIG_STATUS_TRAINING_FAILED: | |
| 478 break; | |
| 479 default: | |
| 480 break; | |
| 481 } | |
| 482 return; | |
| 483 } | |
| 484 //span_log(&s->logging, SPAN_LOG_FLOW, "Bit %d\n", bit); | |
| 485 /* Wait until we sync. */ | |
| 486 s->bit_stream = (s->bit_stream >> 1) | (bit << 19); | |
| 487 /* CI preamble is 10 ones then a framed 0x00 | |
| 488 CM/JM preamble is 10 ones then a framed 0x07 | |
| 489 V.92 preamble is 10 ones then a framed 0x55 | |
| 490 Should we look at all 10 ones? The first couple might be | |
| 491 settling down. */ | |
| 492 /* The preamble + synchronisation bit sequence should be unique in | |
| 493 any bit stream, so we can rely on seeing this at any time as being | |
| 494 a real sync code. */ | |
| 495 switch (s->bit_stream) | |
| 496 { | |
| 497 case 0x803FF: | |
| 498 new_preamble_type = V8_SYNC_CI; | |
| 499 break; | |
| 500 case 0xF03FF: | |
| 501 new_preamble_type = V8_SYNC_CM_JM; | |
| 502 break; | |
| 503 case 0xAABFF: | |
| 504 new_preamble_type = V8_SYNC_V92; | |
| 505 break; | |
| 506 default: | |
| 507 new_preamble_type = V8_SYNC_UNKNOWN; | |
| 508 break; | |
| 509 } | |
| 510 if (new_preamble_type != V8_SYNC_UNKNOWN) | |
| 511 { | |
| 512 /* We have seen a fresh sync code */ | |
| 513 /* Debug */ | |
| 514 if (span_log_test(&s->logging, SPAN_LOG_FLOW)) | |
| 515 { | |
| 516 if (s->preamble_type != V8_SYNC_UNKNOWN) | |
| 517 { | |
| 518 switch (s->preamble_type) | |
| 519 { | |
| 520 case V8_SYNC_CI: | |
| 521 tag = "CI: "; | |
| 522 break; | |
| 523 case V8_SYNC_CM_JM: | |
| 524 tag = (s->calling_party) ? "JM: " : "CM: "; | |
| 525 break; | |
| 526 case V8_SYNC_V92: | |
| 527 tag = "V92: "; | |
| 528 break; | |
| 529 default: | |
| 530 tag = "??: "; | |
| 531 break; | |
| 532 } | |
| 533 span_log_buf(&s->logging, SPAN_LOG_FLOW, tag, s->rx_data, s->rx_data_ptr); | |
| 534 } | |
| 535 } | |
| 536 /* If we were handling a valid sync code then we should process what has been | |
| 537 received to date. */ | |
| 538 switch (s->preamble_type) | |
| 539 { | |
| 540 case V8_SYNC_CI: | |
| 541 ci_decode(s); | |
| 542 break; | |
| 543 case V8_SYNC_CM_JM: | |
| 544 cm_jm_decode(s); | |
| 545 break; | |
| 546 } | |
| 547 s->preamble_type = new_preamble_type; | |
| 548 s->bit_cnt = 0; | |
| 549 s->rx_data_ptr = 0; | |
| 550 } | |
| 551 | |
| 552 if (s->preamble_type != V8_SYNC_UNKNOWN) | |
| 553 { | |
| 554 /* Parse octets with 1 bit start, 1 bit stop */ | |
| 555 s->bit_cnt++; | |
| 556 /* Start, stop? */ | |
| 557 if ((s->bit_stream & 0x80400) == 0x80000 && s->bit_cnt >= 10) | |
| 558 { | |
| 559 /* Store the available data */ | |
| 560 data = (uint8_t) ((s->bit_stream >> 11) & 0xFF); | |
| 561 /* CJ (3 successive zero octets) detection */ | |
| 562 if (data == 0) | |
| 563 { | |
| 564 if (++s->zero_byte_count == 3) | |
| 565 s->got_cj = TRUE; | |
| 566 } | |
| 567 else | |
| 568 { | |
| 569 s->zero_byte_count = 0; | |
| 570 } | |
| 571 | |
| 572 if (s->rx_data_ptr < (int) (sizeof(s->rx_data) - 1)) | |
| 573 s->rx_data[s->rx_data_ptr++] = data; | |
| 574 s->bit_cnt = 0; | |
| 575 } | |
| 576 } | |
| 577 } | |
| 578 /*- End of function --------------------------------------------------------*/ | |
| 579 | |
| 580 static void v8_decode_init(v8_state_t *s) | |
| 581 { | |
| 582 fsk_rx_init(&s->v21rx, | |
| 583 &preset_fsk_specs[(s->calling_party) ? FSK_V21CH2 : FSK_V21CH1], | |
| 584 FSK_FRAME_MODE_ASYNC, | |
| 585 put_bit, | |
| 586 s); | |
| 587 fsk_rx_signal_cutoff(&s->v21rx, -45.5f); | |
| 588 s->preamble_type = V8_SYNC_UNKNOWN; | |
| 589 s->bit_stream = 0; | |
| 590 s->cm_jm_len = 0; | |
| 591 s->got_cm_jm = FALSE; | |
| 592 s->got_cj = FALSE; | |
| 593 s->zero_byte_count = 0; | |
| 594 s->rx_data_ptr = 0; | |
| 595 } | |
| 596 /*- End of function --------------------------------------------------------*/ | |
| 597 | |
| 598 static int get_bit(void *user_data) | |
| 599 { | |
| 600 v8_state_t *s; | |
| 601 uint8_t bit; | |
| 602 | |
| 603 s = user_data; | |
| 604 if (queue_read(s->tx_queue, &bit, 1) <= 0) | |
| 605 return SIG_STATUS_END_OF_DATA; | |
| 606 return bit; | |
| 607 } | |
| 608 /*- End of function --------------------------------------------------------*/ | |
| 609 | |
| 610 static void v8_put_preamble(v8_state_t *s) | |
| 611 { | |
| 612 static const uint8_t preamble[10] = | |
| 613 { | |
| 614 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 | |
| 615 }; | |
| 616 | |
| 617 queue_write(s->tx_queue, preamble, 10); | |
| 618 } | |
| 619 /*- End of function --------------------------------------------------------*/ | |
| 620 | |
| 621 static void v8_put_byte(v8_state_t *s, int data) | |
| 622 { | |
| 623 int i; | |
| 624 uint8_t bits[10]; | |
| 625 | |
| 626 /* Insert start & stop bits */ | |
| 627 bits[0] = 0; | |
| 628 for (i = 1; i < 9; i++) | |
| 629 { | |
| 630 bits[i] = (uint8_t) (data & 1); | |
| 631 data >>= 1; | |
| 632 } | |
| 633 bits[9] = 1; | |
| 634 queue_write(s->tx_queue, bits, 10); | |
| 635 } | |
| 636 /*- End of function --------------------------------------------------------*/ | |
| 637 | |
| 638 static void send_cm_jm(v8_state_t *s) | |
| 639 { | |
| 640 int val; | |
| 641 unsigned int offered_modulations; | |
| 642 | |
| 643 offered_modulations = s->parms.modulations & s->far_end_modulations; | |
| 644 | |
| 645 /* Send a CM, or a JM as appropriate */ | |
| 646 v8_put_preamble(s); | |
| 647 v8_put_byte(s, V8_CM_JM_SYNC_OCTET); | |
| 648 /* Data call */ | |
| 649 v8_put_byte(s, (s->result.call_function << 5) | V8_CALL_FUNCTION_TAG); | |
| 650 | |
| 651 /* Supported modulations */ | |
| 652 val = 0x05; | |
| 653 if (offered_modulations & V8_MOD_V90) | |
| 654 val |= 0x20; | |
| 655 if (offered_modulations & V8_MOD_V34) | |
| 656 val |= 0x40; | |
| 657 v8_put_byte(s, val); | |
| 658 | |
| 659 val = 0x10; | |
| 660 if (offered_modulations & V8_MOD_V32) | |
| 661 val |= 0x01; | |
| 662 if (offered_modulations & V8_MOD_V22) | |
| 663 val |= 0x02; | |
| 664 if (offered_modulations & V8_MOD_V17) | |
| 665 val |= 0x04; | |
| 666 if (offered_modulations & V8_MOD_V29) | |
| 667 val |= 0x40; | |
| 668 if (offered_modulations & V8_MOD_V27TER) | |
| 669 val |= 0x80; | |
| 670 v8_put_byte(s, val); | |
| 671 | |
| 672 val = 0x10; | |
| 673 if (offered_modulations & V8_MOD_V26TER) | |
| 674 val |= 0x01; | |
| 675 if (offered_modulations & V8_MOD_V26BIS) | |
| 676 val |= 0x02; | |
| 677 if (offered_modulations & V8_MOD_V23) | |
| 678 val |= 0x04; | |
| 679 if (offered_modulations & V8_MOD_V23HALF) | |
| 680 val |= 0x40; | |
| 681 if (offered_modulations & V8_MOD_V21) | |
| 682 val |= 0x80; | |
| 683 v8_put_byte(s, val); | |
| 684 | |
| 685 if (s->parms.protocol) | |
| 686 v8_put_byte(s, (s->parms.protocol << 5) | V8_PROTOCOLS_TAG); | |
| 687 if (s->parms.pcm_modem_availability) | |
| 688 v8_put_byte(s, (s->parms.pcm_modem_availability << 5) | V8_PCM_MODEM_AVAILABILITY_TAG); | |
| 689 if (s->parms.pstn_access) | |
| 690 v8_put_byte(s, (s->parms.pstn_access << 5) | V8_PSTN_ACCESS_TAG); | |
| 691 if (s->parms.t66 >= 0) | |
| 692 v8_put_byte(s, (s->parms.t66 << 5) | V8_T66_TAG); | |
| 693 | |
| 694 /* No NSF */ | |
| 695 //v8_put_byte(s, (0 << 5) | V8_NSF_TAG); | |
| 696 } | |
| 697 /*- End of function --------------------------------------------------------*/ | |
| 698 | |
| 699 SPAN_DECLARE_NONSTD(int) v8_tx(v8_state_t *s, int16_t *amp, int max_len) | |
| 700 { | |
| 701 int len; | |
| 702 | |
| 703 //span_log(&s->logging, SPAN_LOG_FLOW, "v8_tx state %d\n", s->state); | |
| 704 len = 0; | |
| 705 if (s->modem_connect_tone_tx_on) | |
| 706 { | |
| 707 if (s->modem_connect_tone_tx_on > ms_to_samples(75)) | |
| 708 { | |
| 709 /* Send the ANSam tone */ | |
| 710 len = modem_connect_tones_tx(&s->ansam_tx, amp, max_len); | |
| 711 if (len < max_len) | |
| 712 { | |
| 713 span_log(&s->logging, SPAN_LOG_FLOW, "ANSam or ANSam/ ended\n"); | |
| 714 s->modem_connect_tone_tx_on = ms_to_samples(75); | |
| 715 } | |
| 716 } | |
| 717 else | |
| 718 { | |
| 719 /* Send the 75ms of silence after the ANSam tone */ | |
| 720 if (max_len > s->modem_connect_tone_tx_on) | |
| 721 len = s->modem_connect_tone_tx_on; | |
| 722 else | |
| 723 len = max_len; | |
| 724 vec_zeroi16(amp, len); | |
| 725 s->modem_connect_tone_tx_on -= len; | |
| 726 } | |
| 727 } | |
| 728 if (s->fsk_tx_on && len < max_len) | |
| 729 { | |
| 730 max_len -= len; | |
| 731 len = fsk_tx(&s->v21tx, amp + len, max_len); | |
| 732 if (len < max_len) | |
| 733 { | |
| 734 span_log(&s->logging, SPAN_LOG_FLOW, "FSK ends\n"); | |
| 735 s->fsk_tx_on = FALSE; | |
| 736 } | |
| 737 } | |
| 738 return len; | |
| 739 } | |
| 740 /*- End of function --------------------------------------------------------*/ | |
| 741 | |
| 742 static void v8_send_ci(v8_state_t *s) | |
| 743 { | |
| 744 int i; | |
| 745 | |
| 746 /* Send 4 CI packets in a burst (the spec says at least 3) */ | |
| 747 for (i = 0; i < 4; i++) | |
| 748 { | |
| 749 v8_put_preamble(s); | |
| 750 v8_put_byte(s, V8_CI_SYNC_OCTET); | |
| 751 v8_put_byte(s, (s->result.call_function << 5) | V8_CALL_FUNCTION_TAG); | |
| 752 } | |
| 753 } | |
| 754 /*- End of function --------------------------------------------------------*/ | |
| 755 | |
| 756 static void handle_modem_connect_tone(v8_state_t *s, int tone) | |
| 757 { | |
| 758 s->result.modem_connect_tone = tone; | |
| 759 span_log(&s->logging, SPAN_LOG_FLOW, "'%s' recognised\n", modem_connect_tone_to_str(tone)); | |
| 760 if (tone == MODEM_CONNECT_TONES_ANSAM | |
| 761 || | |
| 762 tone == MODEM_CONNECT_TONES_ANSAM_PR) | |
| 763 { | |
| 764 /* Set the Te interval. The spec. says 500ms is the minimum, | |
| 765 but gives reasons why 1 second is a better value. */ | |
| 766 s->state = V8_HEARD_ANSAM; | |
| 767 s->ci_timer = ms_to_samples(1000); | |
| 768 } | |
| 769 else | |
| 770 { | |
| 771 /* If we found a connect tone, and it isn't one of the modulated answer tones, | |
| 772 indicating V.8 startup, we are not going to do V.8 processing. */ | |
| 773 span_log(&s->logging, SPAN_LOG_FLOW, "Non-V.8 modem connect tone detected\n"); | |
| 774 s->state = V8_PARKED; | |
| 775 if (s->result_handler) | |
| 776 s->result_handler(s->result_handler_user_data, &s->result); | |
| 777 } | |
| 778 } | |
| 779 /*- End of function --------------------------------------------------------*/ | |
| 780 | |
| 781 SPAN_DECLARE_NONSTD(int) v8_rx(v8_state_t *s, const int16_t *amp, int len) | |
| 782 { | |
| 783 int i; | |
| 784 int residual_samples; | |
| 785 int tone; | |
| 786 | |
| 787 //span_log(&s->logging, SPAN_LOG_FLOW, "v8_rx state %d\n", s->state); | |
| 788 residual_samples = 0; | |
| 789 switch (s->state) | |
| 790 { | |
| 791 case V8_WAIT_1S: | |
| 792 residual_samples = modem_connect_tones_rx(&s->ansam_rx, amp, len); | |
| 793 /* Wait 1 second before sending the first CI packet */ | |
| 794 if ((s->negotiation_timer -= len) > 0) | |
| 795 break; | |
| 796 fsk_tx_restart(&s->v21tx, &preset_fsk_specs[FSK_V21CH1]); | |
| 797 v8_send_ci(s); | |
| 798 s->state = V8_CI_ON; | |
| 799 s->fsk_tx_on = TRUE; | |
| 800 break; | |
| 801 case V8_CI_ON: | |
| 802 residual_samples = modem_connect_tones_rx(&s->ansam_rx, amp, len); | |
| 803 /* Check if an ANSam or ANSam/ tone has been detected */ | |
| 804 if ((tone = modem_connect_tones_rx_get(&s->ansam_rx)) != MODEM_CONNECT_TONES_NONE) | |
| 805 { | |
| 806 handle_modem_connect_tone(s, tone); | |
| 807 break; | |
| 808 } | |
| 809 if (queue_empty(s->tx_queue)) | |
| 810 { | |
| 811 s->state = V8_CI_OFF; | |
| 812 s->ci_timer = ms_to_samples(500); | |
| 813 break; | |
| 814 } | |
| 815 break; | |
| 816 case V8_CI_OFF: | |
| 817 residual_samples = modem_connect_tones_rx(&s->ansam_rx, amp, len); | |
| 818 /* Check if an ANSam or ANSam/ tone has been detected */ | |
| 819 if ((tone = modem_connect_tones_rx_get(&s->ansam_rx)) != MODEM_CONNECT_TONES_NONE) | |
| 820 { | |
| 821 handle_modem_connect_tone(s, tone); | |
| 822 break; | |
| 823 } | |
| 824 if ((s->ci_timer -= len) <= 0) | |
| 825 { | |
| 826 if (++s->ci_count >= 10) | |
| 827 { | |
| 828 /* The spec says we should give up now. */ | |
| 829 span_log(&s->logging, SPAN_LOG_FLOW, "Timeout waiting for modem connect tone\n"); | |
| 830 s->state = V8_PARKED; | |
| 831 if (s->result_handler) | |
| 832 s->result_handler(s->result_handler_user_data, NULL); | |
| 833 } | |
| 834 else | |
| 835 { | |
| 836 /* Try again */ | |
| 837 fsk_tx_restart(&s->v21tx, &preset_fsk_specs[FSK_V21CH1]); | |
| 838 v8_send_ci(s); | |
| 839 s->state = V8_CI_ON; | |
| 840 s->fsk_tx_on = TRUE; | |
| 841 } | |
| 842 } | |
| 843 break; | |
| 844 case V8_HEARD_ANSAM: | |
| 845 /* We have heard the ANSam or ANSam/ signal, but we still need to wait for the | |
| 846 end of the Te timeout period to comply with the spec. */ | |
| 847 if ((s->ci_timer -= len) <= 0) | |
| 848 { | |
| 849 v8_decode_init(s); | |
| 850 s->negotiation_timer = ms_to_samples(5000); | |
| 851 fsk_tx_restart(&s->v21tx, &preset_fsk_specs[FSK_V21CH1]); | |
| 852 send_cm_jm(s); | |
| 853 s->state = V8_CM_ON; | |
| 854 s->fsk_tx_on = TRUE; | |
| 855 } | |
| 856 break; | |
| 857 case V8_CM_ON: | |
| 858 residual_samples = fsk_rx(&s->v21rx, amp, len); | |
| 859 if (s->got_cm_jm) | |
| 860 { | |
| 861 span_log(&s->logging, SPAN_LOG_FLOW, "JM recognised\n"); | |
| 862 /* Now JM has been detected, we send CJ and wait for 75 ms | |
| 863 before finishing the V.8 analysis. */ | |
| 864 fsk_tx_restart(&s->v21tx, &preset_fsk_specs[FSK_V21CH1]); | |
| 865 for (i = 0; i < 3; i++) | |
| 866 v8_put_byte(s, 0); | |
| 867 s->state = V8_CJ_ON; | |
| 868 s->fsk_tx_on = TRUE; | |
| 869 break; | |
| 870 } | |
| 871 if ((s->negotiation_timer -= len) <= 0) | |
| 872 { | |
| 873 /* Timeout */ | |
| 874 span_log(&s->logging, SPAN_LOG_FLOW, "Timeout waiting for JM\n"); | |
| 875 s->state = V8_PARKED; | |
| 876 if (s->result_handler) | |
| 877 s->result_handler(s->result_handler_user_data, NULL); | |
| 878 } | |
| 879 if (queue_contents(s->tx_queue) < 10) | |
| 880 { | |
| 881 /* Send CM again */ | |
| 882 send_cm_jm(s); | |
| 883 } | |
| 884 break; | |
| 885 case V8_CJ_ON: | |
| 886 residual_samples = fsk_rx(&s->v21rx, amp, len); | |
| 887 if (queue_empty(s->tx_queue)) | |
| 888 { | |
| 889 s->negotiation_timer = ms_to_samples(75); | |
| 890 s->state = V8_SIGC; | |
| 891 } | |
| 892 break; | |
| 893 case V8_SIGC: | |
| 894 if ((s->negotiation_timer -= len) <= 0) | |
| 895 { | |
| 896 /* The V.8 negotiation has succeeded. */ | |
| 897 span_log(&s->logging, SPAN_LOG_FLOW, "Negotiation succeeded\n"); | |
| 898 s->state = V8_PARKED; | |
| 899 if (s->result_handler) | |
| 900 s->result_handler(s->result_handler_user_data, &s->result); | |
| 901 } | |
| 902 break; | |
| 903 case V8_CM_WAIT: | |
| 904 residual_samples = fsk_rx(&s->v21rx, amp, len); | |
| 905 if (s->got_cm_jm) | |
| 906 { | |
| 907 span_log(&s->logging, SPAN_LOG_FLOW, "CM recognised\n"); | |
| 908 | |
| 909 /* TODO: negotiate if the call function is acceptable */ | |
| 910 | |
| 911 /* Stop sending ANSam or ANSam/ and send JM instead */ | |
| 912 fsk_tx_init(&s->v21tx, &preset_fsk_specs[FSK_V21CH2], get_bit, s); | |
| 913 /* Set the timeout for JM */ | |
| 914 s->negotiation_timer = ms_to_samples(5000); | |
| 915 s->state = V8_JM_ON; | |
| 916 send_cm_jm(s); | |
| 917 s->modem_connect_tone_tx_on = ms_to_samples(75); | |
| 918 s->fsk_tx_on = TRUE; | |
| 919 break; | |
| 920 } | |
| 921 if ((s->negotiation_timer -= len) <= 0) | |
| 922 { | |
| 923 /* Timeout */ | |
| 924 span_log(&s->logging, SPAN_LOG_FLOW, "Timeout waiting for CM\n"); | |
| 925 s->state = V8_PARKED; | |
| 926 if (s->result_handler) | |
| 927 s->result_handler(s->result_handler_user_data, NULL); | |
| 928 } | |
| 929 break; | |
| 930 case V8_JM_ON: | |
| 931 residual_samples = fsk_rx(&s->v21rx, amp, len); | |
| 932 if (s->got_cj) | |
| 933 { | |
| 934 span_log(&s->logging, SPAN_LOG_FLOW, "CJ recognised\n"); | |
| 935 /* Stop sending JM, flushing anything left in the buffer, and wait 75 ms */ | |
| 936 queue_flush(s->tx_queue); | |
| 937 s->negotiation_timer = ms_to_samples(75); | |
| 938 s->state = V8_SIGA; | |
| 939 break; | |
| 940 } | |
| 941 if ((s->negotiation_timer -= len) <= 0) | |
| 942 { | |
| 943 /* Timeout */ | |
| 944 span_log(&s->logging, SPAN_LOG_FLOW, "Timeout waiting for CJ\n"); | |
| 945 s->state = V8_PARKED; | |
| 946 if (s->result_handler) | |
| 947 s->result_handler(s->result_handler_user_data, NULL); | |
| 948 break; | |
| 949 } | |
| 950 if (queue_contents(s->tx_queue) < 10) | |
| 951 { | |
| 952 /* Send JM */ | |
| 953 send_cm_jm(s); | |
| 954 } | |
| 955 break; | |
| 956 case V8_SIGA: | |
| 957 if ((s->negotiation_timer -= len) <= 0) | |
| 958 { | |
| 959 /* The V.8 negotiation has succeeded. */ | |
| 960 span_log(&s->logging, SPAN_LOG_FLOW, "Negotiation succeeded\n"); | |
| 961 s->state = V8_PARKED; | |
| 962 if (s->result_handler) | |
| 963 s->result_handler(s->result_handler_user_data, &s->result); | |
| 964 } | |
| 965 break; | |
| 966 case V8_PARKED: | |
| 967 residual_samples = len; | |
| 968 break; | |
| 969 } | |
| 970 return residual_samples; | |
| 971 } | |
| 972 /*- End of function --------------------------------------------------------*/ | |
| 973 | |
| 974 SPAN_DECLARE(logging_state_t *) v8_get_logging_state(v8_state_t *s) | |
| 975 { | |
| 976 return &s->logging; | |
| 977 } | |
| 978 /*- End of function --------------------------------------------------------*/ | |
| 979 | |
| 980 SPAN_DECLARE(int) v8_restart(v8_state_t *s, | |
| 981 int calling_party, | |
| 982 v8_parms_t *parms) | |
| 983 { | |
| 984 memcpy(&s->parms, parms, sizeof(s->parms)); | |
| 985 memset(&s->result, 0, sizeof(s->result)); | |
| 986 | |
| 987 s->result.call_function = s->parms.call_function; | |
| 988 s->result.nsf = -1; | |
| 989 s->result.t66 = -1; | |
| 990 | |
| 991 s->ci_timer = 0; | |
| 992 if (calling_party) | |
| 993 { | |
| 994 s->calling_party = TRUE; | |
| 995 s->state = V8_WAIT_1S; | |
| 996 s->negotiation_timer = ms_to_samples(1000); | |
| 997 s->ci_count = 0; | |
| 998 modem_connect_tones_rx_init(&s->ansam_rx, MODEM_CONNECT_TONES_ANS_PR, NULL, NULL); | |
| 999 fsk_tx_init(&s->v21tx, &preset_fsk_specs[FSK_V21CH1], get_bit, s); | |
| 1000 } | |
| 1001 else | |
| 1002 { | |
| 1003 /* Send the ANSam or ANSam/ tone */ | |
| 1004 s->calling_party = FALSE; | |
| 1005 modem_connect_tones_tx_init(&s->ansam_tx, s->parms.modem_connect_tone); | |
| 1006 | |
| 1007 v8_decode_init(s); | |
| 1008 s->state = V8_CM_WAIT; | |
| 1009 s->negotiation_timer = ms_to_samples(200 + 5000); | |
| 1010 s->modem_connect_tone_tx_on = ms_to_samples(75) + 1; | |
| 1011 } | |
| 1012 s->result.modem_connect_tone = MODEM_CONNECT_TONES_NONE; | |
| 1013 | |
| 1014 if ((s->tx_queue = queue_init(NULL, 1024, 0)) == NULL) | |
| 1015 return -1; | |
| 1016 return 0; | |
| 1017 } | |
| 1018 /*- End of function --------------------------------------------------------*/ | |
| 1019 | |
| 1020 SPAN_DECLARE(v8_state_t *) v8_init(v8_state_t *s, | |
| 1021 int calling_party, | |
| 1022 v8_parms_t *parms, | |
| 1023 v8_result_handler_t *result_handler, | |
| 1024 void *user_data) | |
| 1025 { | |
| 1026 if (s == NULL) | |
| 1027 { | |
| 1028 if ((s = (v8_state_t *) malloc(sizeof(*s))) == NULL) | |
| 1029 return NULL; | |
| 1030 } | |
| 1031 memset(s, 0, sizeof(*s)); | |
| 1032 span_log_init(&s->logging, SPAN_LOG_NONE, NULL); | |
| 1033 span_log_set_protocol(&s->logging, "V.8"); | |
| 1034 s->result_handler = result_handler; | |
| 1035 s->result_handler_user_data = user_data; | |
| 1036 | |
| 1037 v8_restart(s, calling_party, parms); | |
| 1038 | |
| 1039 memcpy(&s->parms, parms, sizeof(s->parms)); | |
| 1040 | |
| 1041 s->result.call_function = s->parms.call_function; | |
| 1042 s->result.nsf = -1; | |
| 1043 s->result.t66 = -1; | |
| 1044 | |
| 1045 s->ci_timer = 0; | |
| 1046 if (calling_party) | |
| 1047 { | |
| 1048 s->calling_party = TRUE; | |
| 1049 s->state = V8_WAIT_1S; | |
| 1050 s->negotiation_timer = ms_to_samples(1000); | |
| 1051 s->ci_count = 0; | |
| 1052 modem_connect_tones_rx_init(&s->ansam_rx, MODEM_CONNECT_TONES_ANS_PR, NULL, NULL); | |
| 1053 fsk_tx_init(&s->v21tx, &preset_fsk_specs[FSK_V21CH1], get_bit, s); | |
| 1054 } | |
| 1055 else | |
| 1056 { | |
| 1057 /* Send the ANSam or ANSam/ tone */ | |
| 1058 s->calling_party = FALSE; | |
| 1059 modem_connect_tones_tx_init(&s->ansam_tx, s->parms.modem_connect_tone); | |
| 1060 | |
| 1061 v8_decode_init(s); | |
| 1062 s->state = V8_CM_WAIT; | |
| 1063 s->negotiation_timer = ms_to_samples(200 + 5000); | |
| 1064 s->modem_connect_tone_tx_on = ms_to_samples(75) + 1; | |
| 1065 } | |
| 1066 s->result.modem_connect_tone = MODEM_CONNECT_TONES_NONE; | |
| 1067 | |
| 1068 if ((s->tx_queue = queue_init(NULL, 1024, 0)) == NULL) | |
| 1069 return NULL; | |
| 1070 return s; | |
| 1071 } | |
| 1072 /*- End of function --------------------------------------------------------*/ | |
| 1073 | |
| 1074 SPAN_DECLARE(int) v8_release(v8_state_t *s) | |
| 1075 { | |
| 1076 return queue_free(s->tx_queue); | |
| 1077 } | |
| 1078 /*- End of function --------------------------------------------------------*/ | |
| 1079 | |
| 1080 SPAN_DECLARE(int) v8_free(v8_state_t *s) | |
| 1081 { | |
| 1082 int ret; | |
| 1083 | |
| 1084 ret = queue_free(s->tx_queue); | |
| 1085 free(s); | |
| 1086 return ret; | |
| 1087 } | |
| 1088 /*- End of function --------------------------------------------------------*/ | |
| 1089 /*- End of file ------------------------------------------------------------*/ |
