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

Repositories maintained by Peter Meerwald, pmeerw@pmeerw.net.