Mercurial > hg > audiostuff
comparison spandsp-0.0.6pre17/src/modem_connect_tones.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 * modem_connect_tones.c - Generation and detection of tones | |
| 5 * associated with modems calling and answering calls. | |
| 6 * | |
| 7 * Written by Steve Underwood <steveu@coppice.org> | |
| 8 * | |
| 9 * Copyright (C) 2006 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: modem_connect_tones.c,v 1.41 2009/11/06 19:21:33 steveu Exp $ | |
| 27 */ | |
| 28 | |
| 29 /*! \file */ | |
| 30 | |
| 31 /* CNG is 0.5s+-15% of 1100+-38Hz, 3s+-15% off, repeating. | |
| 32 | |
| 33 CED is 0.2s silence, 3.3+-0.7s of 2100+-15Hz, and 75+-20ms of silence. | |
| 34 | |
| 35 ANS is 3.3+-0.7s of 2100+-15Hz. | |
| 36 | |
| 37 ANS/ is 3.3+-0.7s of 2100+-15Hz, with phase reversals (180+-10 degrees, hopping in <1ms) every 450+-25ms. | |
| 38 | |
| 39 ANSam/ is 2100+-1Hz, with phase reversals (180+-10 degrees, hopping in <1ms) every 450+-25ms, and AM with a sinewave of 15+-0.1Hz. | |
| 40 The modulated envelope ranges in amplitude between (0.8+-0.01) and (1.2+-0.01) times its average | |
| 41 amplitude. It lasts up to 5s, but will be stopped early if the V.8 protocol proceeds. */ | |
| 42 | |
| 43 #if defined(HAVE_CONFIG_H) | |
| 44 #include "config.h" | |
| 45 #endif | |
| 46 | |
| 47 #include <inttypes.h> | |
| 48 #include <stdlib.h> | |
| 49 #include <memory.h> | |
| 50 #if defined(HAVE_TGMATH_H) | |
| 51 #include <tgmath.h> | |
| 52 #endif | |
| 53 #if defined(HAVE_MATH_H) | |
| 54 #include <math.h> | |
| 55 #endif | |
| 56 #include "floating_fudge.h" | |
| 57 #include <stdio.h> | |
| 58 | |
| 59 #include "spandsp/telephony.h" | |
| 60 #include "spandsp/fast_convert.h" | |
| 61 #include "spandsp/logging.h" | |
| 62 #include "spandsp/complex.h" | |
| 63 #include "spandsp/dds.h" | |
| 64 #include "spandsp/tone_detect.h" | |
| 65 #include "spandsp/tone_generate.h" | |
| 66 #include "spandsp/super_tone_rx.h" | |
| 67 #include "spandsp/power_meter.h" | |
| 68 #include "spandsp/async.h" | |
| 69 #include "spandsp/fsk.h" | |
| 70 #include "spandsp/modem_connect_tones.h" | |
| 71 | |
| 72 #include "spandsp/private/fsk.h" | |
| 73 #include "spandsp/private/modem_connect_tones.h" | |
| 74 | |
| 75 #define HDLC_FRAMING_OK_THRESHOLD 5 | |
| 76 | |
| 77 SPAN_DECLARE(const char *) modem_connect_tone_to_str(int tone) | |
| 78 { | |
| 79 switch (tone) | |
| 80 { | |
| 81 case MODEM_CONNECT_TONES_NONE: | |
| 82 return "No tone"; | |
| 83 case MODEM_CONNECT_TONES_FAX_CNG: | |
| 84 return "FAX CNG"; | |
| 85 case MODEM_CONNECT_TONES_ANS: | |
| 86 return "ANS or FAX CED"; | |
| 87 case MODEM_CONNECT_TONES_ANS_PR: | |
| 88 return "ANS/"; | |
| 89 case MODEM_CONNECT_TONES_ANSAM: | |
| 90 return "ANSam"; | |
| 91 case MODEM_CONNECT_TONES_ANSAM_PR: | |
| 92 return "ANSam/"; | |
| 93 case MODEM_CONNECT_TONES_FAX_PREAMBLE: | |
| 94 return "FAX preamble"; | |
| 95 case MODEM_CONNECT_TONES_FAX_CED_OR_PREAMBLE: | |
| 96 return "FAX CED or preamble"; | |
| 97 } | |
| 98 return "???"; | |
| 99 } | |
| 100 /*- End of function --------------------------------------------------------*/ | |
| 101 | |
| 102 SPAN_DECLARE_NONSTD(int) modem_connect_tones_tx(modem_connect_tones_tx_state_t *s, | |
| 103 int16_t amp[], | |
| 104 int len) | |
| 105 { | |
| 106 int16_t mod; | |
| 107 int i; | |
| 108 int xlen; | |
| 109 | |
| 110 i = 0; | |
| 111 switch (s->tone_type) | |
| 112 { | |
| 113 case MODEM_CONNECT_TONES_FAX_CNG: | |
| 114 for ( ; i < len; i++) | |
| 115 { | |
| 116 if (s->duration_timer > ms_to_samples(3000)) | |
| 117 { | |
| 118 if ((xlen = i + s->duration_timer - ms_to_samples(3000)) > len) | |
| 119 xlen = len; | |
| 120 s->duration_timer -= (xlen - i); | |
| 121 for ( ; i < xlen; i++) | |
| 122 amp[i] = dds_mod(&s->tone_phase, s->tone_phase_rate, s->level, 0); | |
| 123 } | |
| 124 if (s->duration_timer > 0) | |
| 125 { | |
| 126 if ((xlen = i + s->duration_timer) > len) | |
| 127 xlen = len; | |
| 128 s->duration_timer -= (xlen - i); | |
| 129 memset(amp + i, 0, sizeof(int16_t)*(xlen - i)); | |
| 130 i = xlen; | |
| 131 } | |
| 132 if (s->duration_timer == 0) | |
| 133 s->duration_timer = ms_to_samples(500 + 3000); | |
| 134 } | |
| 135 break; | |
| 136 case MODEM_CONNECT_TONES_ANS: | |
| 137 if (s->duration_timer < len) | |
| 138 len = s->duration_timer; | |
| 139 if (s->duration_timer > ms_to_samples(2600)) | |
| 140 { | |
| 141 /* There is some initial silence to be generated. */ | |
| 142 if ((i = s->duration_timer - ms_to_samples(2600)) > len) | |
| 143 i = len; | |
| 144 memset(amp, 0, sizeof(int16_t)*i); | |
| 145 } | |
| 146 for ( ; i < len; i++) | |
| 147 amp[i] = dds_mod(&s->tone_phase, s->tone_phase_rate, s->level, 0); | |
| 148 s->duration_timer -= len; | |
| 149 break; | |
| 150 case MODEM_CONNECT_TONES_ANS_PR: | |
| 151 if (s->duration_timer < len) | |
| 152 len = s->duration_timer; | |
| 153 if (s->duration_timer > ms_to_samples(3300)) | |
| 154 { | |
| 155 if ((i = s->duration_timer - ms_to_samples(3300)) > len) | |
| 156 i = len; | |
| 157 memset(amp, 0, sizeof(int16_t)*i); | |
| 158 } | |
| 159 for ( ; i < len; i++) | |
| 160 { | |
| 161 if (--s->hop_timer <= 0) | |
| 162 { | |
| 163 s->hop_timer = ms_to_samples(450); | |
| 164 s->tone_phase += 0x80000000; | |
| 165 } | |
| 166 amp[i] = dds_mod(&s->tone_phase, s->tone_phase_rate, s->level, 0); | |
| 167 } | |
| 168 s->duration_timer -= len; | |
| 169 break; | |
| 170 case MODEM_CONNECT_TONES_ANSAM: | |
| 171 if (s->duration_timer < len) | |
| 172 len = s->duration_timer; | |
| 173 if (s->duration_timer > ms_to_samples(5000)) | |
| 174 { | |
| 175 if ((i = s->duration_timer - ms_to_samples(5000)) > len) | |
| 176 i = len; | |
| 177 memset(amp, 0, sizeof(int16_t)*i); | |
| 178 } | |
| 179 for ( ; i < len; i++) | |
| 180 { | |
| 181 mod = (int16_t) (s->level + dds_mod(&s->mod_phase, s->mod_phase_rate, s->mod_level, 0)); | |
| 182 amp[i] = dds_mod(&s->tone_phase, s->tone_phase_rate, mod, 0); | |
| 183 } | |
| 184 s->duration_timer -= len; | |
| 185 break; | |
| 186 case MODEM_CONNECT_TONES_ANSAM_PR: | |
| 187 if (s->duration_timer < len) | |
| 188 len = s->duration_timer; | |
| 189 if (s->duration_timer > ms_to_samples(5000)) | |
| 190 { | |
| 191 if ((i = s->duration_timer - ms_to_samples(5000)) > len) | |
| 192 i = len; | |
| 193 memset(amp, 0, sizeof(int16_t)*i); | |
| 194 } | |
| 195 for ( ; i < len; i++) | |
| 196 { | |
| 197 if (--s->hop_timer <= 0) | |
| 198 { | |
| 199 s->hop_timer = ms_to_samples(450); | |
| 200 s->tone_phase += 0x80000000; | |
| 201 } | |
| 202 mod = (int16_t) (s->level + dds_mod(&s->mod_phase, s->mod_phase_rate, s->mod_level, 0)); | |
| 203 amp[i] = dds_mod(&s->tone_phase, s->tone_phase_rate, mod, 0); | |
| 204 } | |
| 205 s->duration_timer -= len; | |
| 206 break; | |
| 207 } | |
| 208 return len; | |
| 209 } | |
| 210 /*- End of function --------------------------------------------------------*/ | |
| 211 | |
| 212 SPAN_DECLARE(modem_connect_tones_tx_state_t *) modem_connect_tones_tx_init(modem_connect_tones_tx_state_t *s, | |
| 213 int tone_type) | |
| 214 { | |
| 215 int alloced; | |
| 216 | |
| 217 alloced = FALSE; | |
| 218 if (s == NULL) | |
| 219 { | |
| 220 if ((s = (modem_connect_tones_tx_state_t *) malloc(sizeof(*s))) == NULL) | |
| 221 return NULL; | |
| 222 alloced = TRUE; | |
| 223 } | |
| 224 s->tone_type = tone_type; | |
| 225 switch (s->tone_type) | |
| 226 { | |
| 227 case MODEM_CONNECT_TONES_FAX_CNG: | |
| 228 /* 0.5s of 1100Hz+-38Hz + 3.0s of silence repeating. Timing +-15% */ | |
| 229 s->tone_phase_rate = dds_phase_rate(1100.0); | |
| 230 s->level = dds_scaling_dbm0(-11); | |
| 231 s->duration_timer = ms_to_samples(500 + 3000); | |
| 232 s->mod_phase_rate = 0; | |
| 233 s->tone_phase = 0; | |
| 234 s->mod_phase = 0; | |
| 235 s->mod_level = 0; | |
| 236 s->hop_timer = 0; | |
| 237 break; | |
| 238 case MODEM_CONNECT_TONES_ANS: | |
| 239 case MODEM_CONNECT_TONES_ANSAM: | |
| 240 /* 0.2s of silence, then 2.6s to 4s of 2100Hz+-15Hz tone, then 75ms of silence. */ | |
| 241 s->tone_phase_rate = dds_phase_rate(2100.0); | |
| 242 s->level = dds_scaling_dbm0(-11); | |
| 243 if (s->tone_type == MODEM_CONNECT_TONES_ANSAM) | |
| 244 { | |
| 245 s->mod_phase_rate = dds_phase_rate(15.0); | |
| 246 s->mod_level = s->level/5; | |
| 247 s->duration_timer = ms_to_samples(200 + 5000); | |
| 248 } | |
| 249 else | |
| 250 { | |
| 251 s->mod_phase_rate = 0; | |
| 252 s->mod_level = 0; | |
| 253 s->duration_timer = ms_to_samples(200 + 2600); | |
| 254 } | |
| 255 s->tone_phase = 0; | |
| 256 s->mod_phase = 0; | |
| 257 s->hop_timer = 0; | |
| 258 break; | |
| 259 case MODEM_CONNECT_TONES_ANS_PR: | |
| 260 case MODEM_CONNECT_TONES_ANSAM_PR: | |
| 261 s->tone_phase_rate = dds_phase_rate(2100.0); | |
| 262 s->level = dds_scaling_dbm0(-12); | |
| 263 if (s->tone_type == MODEM_CONNECT_TONES_ANSAM_PR) | |
| 264 { | |
| 265 s->mod_phase_rate = dds_phase_rate(15.0); | |
| 266 s->mod_level = s->level/5; | |
| 267 s->duration_timer = ms_to_samples(200 + 5000); | |
| 268 } | |
| 269 else | |
| 270 { | |
| 271 s->mod_phase_rate = 0; | |
| 272 s->mod_level = 0; | |
| 273 s->duration_timer = ms_to_samples(200 + 3300); | |
| 274 } | |
| 275 s->tone_phase = 0; | |
| 276 s->mod_phase = 0; | |
| 277 s->hop_timer = ms_to_samples(450); | |
| 278 break; | |
| 279 default: | |
| 280 if (alloced) | |
| 281 free(s); | |
| 282 return NULL; | |
| 283 } | |
| 284 return s; | |
| 285 } | |
| 286 /*- End of function --------------------------------------------------------*/ | |
| 287 | |
| 288 SPAN_DECLARE(int) modem_connect_tones_tx_release(modem_connect_tones_tx_state_t *s) | |
| 289 { | |
| 290 return 0; | |
| 291 } | |
| 292 /*- End of function --------------------------------------------------------*/ | |
| 293 | |
| 294 SPAN_DECLARE(int) modem_connect_tones_tx_free(modem_connect_tones_tx_state_t *s) | |
| 295 { | |
| 296 free(s); | |
| 297 return 0; | |
| 298 } | |
| 299 /*- End of function --------------------------------------------------------*/ | |
| 300 | |
| 301 static void report_tone_state(modem_connect_tones_rx_state_t *s, int tone, int level) | |
| 302 { | |
| 303 if (tone != s->tone_present) | |
| 304 { | |
| 305 if (s->tone_callback) | |
| 306 { | |
| 307 s->tone_callback(s->callback_data, tone, level, 0); | |
| 308 } | |
| 309 else | |
| 310 { | |
| 311 if (tone != MODEM_CONNECT_TONES_NONE) | |
| 312 s->hit = tone; | |
| 313 } | |
| 314 s->tone_present = tone; | |
| 315 } | |
| 316 } | |
| 317 /*- End of function --------------------------------------------------------*/ | |
| 318 | |
| 319 static void v21_put_bit(void *user_data, int bit) | |
| 320 { | |
| 321 modem_connect_tones_rx_state_t *s; | |
| 322 | |
| 323 s = (modem_connect_tones_rx_state_t *) user_data; | |
| 324 if (bit < 0) | |
| 325 { | |
| 326 /* Special conditions. */ | |
| 327 switch (bit) | |
| 328 { | |
| 329 case SIG_STATUS_CARRIER_DOWN: | |
| 330 /* Only declare tone off, if we were the one to declare tone on. */ | |
| 331 if (s->tone_present == MODEM_CONNECT_TONES_FAX_PREAMBLE) | |
| 332 report_tone_state(s, MODEM_CONNECT_TONES_NONE, -99); | |
| 333 /* Fall through */ | |
| 334 case SIG_STATUS_CARRIER_UP: | |
| 335 s->raw_bit_stream = 0; | |
| 336 s->num_bits = 0; | |
| 337 s->flags_seen = 0; | |
| 338 s->framing_ok_announced = FALSE; | |
| 339 break; | |
| 340 } | |
| 341 return; | |
| 342 } | |
| 343 /* Look for enough FAX V.21 message preamble (back to back HDLC flag octets) to be sure | |
| 344 we are really seeing preamble, and declare the signal to be present. Any change from | |
| 345 preamble declares the signal to not be present, though it will probably be the body | |
| 346 of the messages following the preamble. */ | |
| 347 s->raw_bit_stream = (s->raw_bit_stream << 1) | ((bit << 8) & 0x100); | |
| 348 s->num_bits++; | |
| 349 if ((s->raw_bit_stream & 0x7F00) == 0x7E00) | |
| 350 { | |
| 351 if ((s->raw_bit_stream & 0x8000)) | |
| 352 { | |
| 353 /* Hit HDLC abort */ | |
| 354 s->flags_seen = 0; | |
| 355 } | |
| 356 else | |
| 357 { | |
| 358 /* Hit HDLC flag */ | |
| 359 if (s->flags_seen < HDLC_FRAMING_OK_THRESHOLD) | |
| 360 { | |
| 361 /* Check the flags are back-to-back when testing for valid preamble. This | |
| 362 greatly reduces the chances of false preamble detection, and anything | |
| 363 which doesn't send them back-to-back is badly broken. */ | |
| 364 if (s->num_bits != 8) | |
| 365 s->flags_seen = 0; | |
| 366 if (++s->flags_seen >= HDLC_FRAMING_OK_THRESHOLD && !s->framing_ok_announced) | |
| 367 { | |
| 368 report_tone_state(s, MODEM_CONNECT_TONES_FAX_PREAMBLE, lfastrintf(fsk_rx_signal_power(&(s->v21rx)))); | |
| 369 s->framing_ok_announced = TRUE; | |
| 370 } | |
| 371 } | |
| 372 } | |
| 373 s->num_bits = 0; | |
| 374 } | |
| 375 else | |
| 376 { | |
| 377 if (s->flags_seen >= HDLC_FRAMING_OK_THRESHOLD) | |
| 378 { | |
| 379 if (s->num_bits == 8) | |
| 380 { | |
| 381 s->framing_ok_announced = FALSE; | |
| 382 s->flags_seen = 0; | |
| 383 } | |
| 384 } | |
| 385 } | |
| 386 } | |
| 387 /*- End of function --------------------------------------------------------*/ | |
| 388 | |
| 389 SPAN_DECLARE_NONSTD(int) modem_connect_tones_rx(modem_connect_tones_rx_state_t *s, | |
| 390 const int16_t amp[], | |
| 391 int len) | |
| 392 { | |
| 393 int i; | |
| 394 int16_t notched; | |
| 395 float v1; | |
| 396 float famp; | |
| 397 float filtered; | |
| 398 | |
| 399 switch (s->tone_type) | |
| 400 { | |
| 401 case MODEM_CONNECT_TONES_FAX_CNG: | |
| 402 for (i = 0; i < len; i++) | |
| 403 { | |
| 404 famp = amp[i]; | |
| 405 /* A Cauer notch at 1100Hz, spread just wide enough to meet our detection bandwidth | |
| 406 criteria. */ | |
| 407 v1 = 0.792928f*famp + 1.0018744927985f*s->znotch_1 - 0.54196833412465f*s->znotch_2; | |
| 408 famp = v1 - 1.2994747954630f*s->znotch_1 + s->znotch_2; | |
| 409 s->znotch_2 = s->znotch_1; | |
| 410 s->znotch_1 = v1; | |
| 411 notched = (int16_t) lfastrintf(famp); | |
| 412 | |
| 413 /* Estimate the overall energy in the channel, and the energy in | |
| 414 the notch (i.e. overall channel energy - tone energy => noise). | |
| 415 Use abs instead of multiply for speed (is it really faster?). */ | |
| 416 s->channel_level += ((abs(amp[i]) - s->channel_level) >> 5); | |
| 417 s->notch_level += ((abs(notched) - s->notch_level) >> 5); | |
| 418 if (s->channel_level > 70 && s->notch_level*6 < s->channel_level) | |
| 419 { | |
| 420 /* There is adequate energy in the channel, and it is mostly at 1100Hz. */ | |
| 421 if (s->tone_present != MODEM_CONNECT_TONES_FAX_CNG) | |
| 422 { | |
| 423 if (++s->tone_cycle_duration >= ms_to_samples(415)) | |
| 424 report_tone_state(s, MODEM_CONNECT_TONES_FAX_CNG, lfastrintf(log10f(s->channel_level/32768.0f)*20.0f + DBM0_MAX_POWER + 0.8f)); | |
| 425 } | |
| 426 } | |
| 427 else | |
| 428 { | |
| 429 /* If the signal looks wrong, even for a moment, we consider this the | |
| 430 end of the tone. */ | |
| 431 if (s->tone_present == MODEM_CONNECT_TONES_FAX_CNG) | |
| 432 report_tone_state(s, MODEM_CONNECT_TONES_NONE, -99); | |
| 433 s->tone_cycle_duration = 0; | |
| 434 } | |
| 435 } | |
| 436 break; | |
| 437 case MODEM_CONNECT_TONES_FAX_PREAMBLE: | |
| 438 /* Ignore any CED tone, and just look for V.21 preamble. */ | |
| 439 fsk_rx(&(s->v21rx), amp, len); | |
| 440 break; | |
| 441 case MODEM_CONNECT_TONES_FAX_CED_OR_PREAMBLE: | |
| 442 /* Also look for V.21 preamble. A lot of machines don't send the 2100Hz burst. It | |
| 443 might also not be seen all the way through the channel, due to switching delays. */ | |
| 444 fsk_rx(&(s->v21rx), amp, len); | |
| 445 /* Now fall through and look for a 2100Hz tone */ | |
| 446 case MODEM_CONNECT_TONES_ANS: | |
| 447 for (i = 0; i < len; i++) | |
| 448 { | |
| 449 famp = amp[i]; | |
| 450 /* A Cauer bandpass at 15Hz, with which we demodulate the AM signal. */ | |
| 451 v1 = fabs(famp) + 1.996667f*s->z15hz_1 - 0.9968004f*s->z15hz_2; | |
| 452 filtered = 0.001599787f*(v1 - s->z15hz_2); | |
| 453 s->z15hz_2 = s->z15hz_1; | |
| 454 s->z15hz_1 = v1; | |
| 455 s->am_level += abs(lfastrintf(filtered)) - (s->am_level >> 8); | |
| 456 //printf("%9.1f %10.4f %9d %9d\n", famp, filtered, s->am_level, s->channel_level); | |
| 457 /* A Cauer notch at 2100Hz, spread just wide enough to meet our detection bandwidth | |
| 458 criteria. */ | |
| 459 /* This is actually centred at 2095Hz, but gets the balance we want, due | |
| 460 to the asymmetric walls of the notch */ | |
| 461 v1 = 0.76000f*famp - 0.1183852f*s->znotch_1 - 0.5104039f*s->znotch_2; | |
| 462 famp = v1 + 0.1567596f*s->znotch_1 + s->znotch_2; | |
| 463 s->znotch_2 = s->znotch_1; | |
| 464 s->znotch_1 = v1; | |
| 465 notched = (int16_t) lfastrintf(famp); | |
| 466 /* Estimate the overall energy in the channel, and the energy in | |
| 467 the notch (i.e. overall channel energy - tone energy => noise). | |
| 468 Use abs instead of multiply for speed (is it really faster?). | |
| 469 Damp the overall energy a little more for a stable result. | |
| 470 Damp the notch energy a little less, so we don't damp out the | |
| 471 blip every time the phase reverses. */ | |
| 472 s->channel_level += ((abs(amp[i]) - s->channel_level) >> 5); | |
| 473 s->notch_level += ((abs(notched) - s->notch_level) >> 4); | |
| 474 /* This should cut off at about -43dBm0 */ | |
| 475 if (s->channel_level <= 70) | |
| 476 { | |
| 477 /* If the energy level is low, even for a moment, we consider this the | |
| 478 end of the tone. */ | |
| 479 if (s->tone_present != MODEM_CONNECT_TONES_NONE) | |
| 480 report_tone_state(s, MODEM_CONNECT_TONES_NONE, -99); | |
| 481 s->tone_cycle_duration = 0; | |
| 482 s->good_cycles = 0; | |
| 483 s->tone_on = FALSE; | |
| 484 continue; | |
| 485 } | |
| 486 /* There is adequate energy in the channel. Is it mostly at 2100Hz? */ | |
| 487 s->tone_cycle_duration++; | |
| 488 if (s->notch_level*6 < s->channel_level) | |
| 489 { | |
| 490 /* The notch test says yes, so we have the tone. */ | |
| 491 /* We should get a kick from the notch filter every 450+-25ms, as the phase reverses, for an | |
| 492 EC disable tone. For a simple answer tone, the tone should persist unbroken for longer. */ | |
| 493 if (!s->tone_on) | |
| 494 { | |
| 495 if (s->tone_cycle_duration >= ms_to_samples(450 - 25)) | |
| 496 { | |
| 497 if (++s->good_cycles == 3) | |
| 498 { | |
| 499 report_tone_state(s, | |
| 500 (s->am_level*15/256 > s->channel_level) ? MODEM_CONNECT_TONES_ANSAM_PR : MODEM_CONNECT_TONES_ANS_PR, | |
| 501 lfastrintf(log10f(s->channel_level/32768.0f)*20.0f + DBM0_MAX_POWER + 0.8f)); | |
| 502 } | |
| 503 } | |
| 504 else | |
| 505 { | |
| 506 s->good_cycles = 0; | |
| 507 } | |
| 508 /* Cycles are timed from rising edge to rising edge */ | |
| 509 s->tone_cycle_duration = 0; | |
| 510 } | |
| 511 else | |
| 512 { | |
| 513 if (s->tone_cycle_duration >= ms_to_samples(450 + 100)) | |
| 514 { | |
| 515 if (s->tone_present == MODEM_CONNECT_TONES_NONE) | |
| 516 { | |
| 517 report_tone_state(s, | |
| 518 (s->am_level*15/256 > s->channel_level) ? MODEM_CONNECT_TONES_ANSAM : MODEM_CONNECT_TONES_ANS, | |
| 519 lfastrintf(log10f(s->channel_level/32768.0f)*20.0f + DBM0_MAX_POWER + 0.8f)); | |
| 520 } | |
| 521 s->good_cycles = 0; | |
| 522 s->tone_cycle_duration = ms_to_samples(450 + 100); | |
| 523 } | |
| 524 } | |
| 525 s->tone_on = TRUE; | |
| 526 } | |
| 527 else if (s->notch_level*5 > s->channel_level) | |
| 528 { | |
| 529 if (s->tone_present == MODEM_CONNECT_TONES_ANS) | |
| 530 { | |
| 531 report_tone_state(s, MODEM_CONNECT_TONES_NONE, -99); | |
| 532 s->good_cycles = 0; | |
| 533 } | |
| 534 else | |
| 535 { | |
| 536 if (s->tone_cycle_duration >= ms_to_samples(450 + 25)) | |
| 537 { | |
| 538 /* The change came too late for a cycle of ANS_PR tone */ | |
| 539 if (s->tone_present == MODEM_CONNECT_TONES_ANS_PR || s->tone_present == MODEM_CONNECT_TONES_ANSAM_PR) | |
| 540 report_tone_state(s, MODEM_CONNECT_TONES_NONE, -99); | |
| 541 s->good_cycles = 0; | |
| 542 } | |
| 543 } | |
| 544 s->tone_on = FALSE; | |
| 545 } | |
| 546 } | |
| 547 break; | |
| 548 } | |
| 549 return 0; | |
| 550 } | |
| 551 /*- End of function --------------------------------------------------------*/ | |
| 552 | |
| 553 SPAN_DECLARE(int) modem_connect_tones_rx_get(modem_connect_tones_rx_state_t *s) | |
| 554 { | |
| 555 int x; | |
| 556 | |
| 557 x = s->hit; | |
| 558 s->hit = MODEM_CONNECT_TONES_NONE; | |
| 559 return x; | |
| 560 } | |
| 561 /*- End of function --------------------------------------------------------*/ | |
| 562 | |
| 563 SPAN_DECLARE(modem_connect_tones_rx_state_t *) modem_connect_tones_rx_init(modem_connect_tones_rx_state_t *s, | |
| 564 int tone_type, | |
| 565 tone_report_func_t tone_callback, | |
| 566 void *user_data) | |
| 567 { | |
| 568 if (s == NULL) | |
| 569 { | |
| 570 if ((s = (modem_connect_tones_rx_state_t *) malloc(sizeof(*s))) == NULL) | |
| 571 return NULL; | |
| 572 } | |
| 573 | |
| 574 s->tone_type = tone_type; | |
| 575 switch (s->tone_type) | |
| 576 { | |
| 577 case MODEM_CONNECT_TONES_FAX_PREAMBLE: | |
| 578 case MODEM_CONNECT_TONES_FAX_CED_OR_PREAMBLE: | |
| 579 fsk_rx_init(&(s->v21rx), &preset_fsk_specs[FSK_V21CH2], FSK_FRAME_MODE_SYNC, v21_put_bit, s); | |
| 580 fsk_rx_signal_cutoff(&(s->v21rx), -45.5f); | |
| 581 break; | |
| 582 case MODEM_CONNECT_TONES_ANS_PR: | |
| 583 case MODEM_CONNECT_TONES_ANSAM: | |
| 584 case MODEM_CONNECT_TONES_ANSAM_PR: | |
| 585 /* Treat these all the same for receive purposes */ | |
| 586 s->tone_type = MODEM_CONNECT_TONES_ANS; | |
| 587 break; | |
| 588 } | |
| 589 s->channel_level = 0; | |
| 590 s->notch_level = 0; | |
| 591 s->am_level = 0; | |
| 592 s->tone_present = MODEM_CONNECT_TONES_NONE; | |
| 593 s->tone_cycle_duration = 0; | |
| 594 s->good_cycles = 0; | |
| 595 s->hit = MODEM_CONNECT_TONES_NONE; | |
| 596 s->tone_on = FALSE; | |
| 597 s->tone_callback = tone_callback; | |
| 598 s->callback_data = user_data; | |
| 599 s->znotch_1 = 0.0f; | |
| 600 s->znotch_2 = 0.0f; | |
| 601 s->z15hz_1 = 0.0f; | |
| 602 s->z15hz_2 = 0.0f; | |
| 603 s->num_bits = 0; | |
| 604 s->flags_seen = 0; | |
| 605 s->framing_ok_announced = FALSE; | |
| 606 s->raw_bit_stream = 0; | |
| 607 return s; | |
| 608 } | |
| 609 /*- End of function --------------------------------------------------------*/ | |
| 610 | |
| 611 SPAN_DECLARE(int) modem_connect_tones_rx_release(modem_connect_tones_rx_state_t *s) | |
| 612 { | |
| 613 return 0; | |
| 614 } | |
| 615 /*- End of function --------------------------------------------------------*/ | |
| 616 | |
| 617 SPAN_DECLARE(int) modem_connect_tones_rx_free(modem_connect_tones_rx_state_t *s) | |
| 618 { | |
| 619 free(s); | |
| 620 return 0; | |
| 621 } | |
| 622 /*- End of function --------------------------------------------------------*/ | |
| 623 /*- End of file ------------------------------------------------------------*/ |
