comparison spandsp-0.0.3/spandsp-0.0.3/src/v8.c @ 5:f762bf195c4b

import spandsp-0.0.3
author Peter Meerwald <pmeerw@cosy.sbg.ac.at>
date Fri, 25 Jun 2010 16:00:21 +0200
parents
children
comparison
equal deleted inserted replaced
4:26cd8f1ef0b1 5:f762bf195c4b
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 General Public License version 2, as
14 * 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 General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * 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.20 2006/11/30 15:41:47 steveu Exp $
26 */
27
28 /*! \file */
29
30 #ifdef 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
45 #include "spandsp/telephony.h"
46 #include "spandsp/logging.h"
47 #include "spandsp/queue.h"
48 #include "spandsp/async.h"
49 #include "spandsp/dds.h"
50 #include "spandsp/tone_detect.h"
51 #include "spandsp/tone_generate.h"
52 #include "spandsp/super_tone_rx.h"
53 #include "spandsp/modem_connect_tones.h"
54 #include "spandsp/power_meter.h"
55 #include "spandsp/fsk.h"
56 #include "spandsp/v8.h"
57
58 #define ms_to_samples(t) (((t)*SAMPLE_RATE)/1000)
59
60 enum
61 {
62 V8_WAIT_1S,
63 V8_CI,
64 V8_CI_ON,
65 V8_CI_OFF,
66 V8_HEARD_ANSAM,
67 V8_CM_ON,
68 V8_CJ_ON,
69 V8_CM_WAIT,
70
71 V8_SIGC,
72 V8_WAIT_200MS,
73 V8_JM_ON,
74 V8_SIGA,
75
76 V8_PARKED
77 } v8_states_e;
78
79 enum
80 {
81 V8_SYNC_UNKNOWN = 0,
82 V8_SYNC_CI,
83 V8_SYNC_CM_JM,
84 V8_SYNC_V92
85 } v8_sync_types_e;
86
87 const char *v8_call_function_to_str(int call_function)
88 {
89 switch (call_function)
90 {
91 case V8_CALL_TBS:
92 return "TBS";
93 case V8_CALL_H324:
94 return "H.324 PSTN multimedia terminal";
95 case V8_CALL_V18:
96 return "V.18 textphone";
97 case V8_CALL_T101:
98 return "T.101 videotext";
99 case V8_CALL_T30_TX:
100 return "T.30 Tx FAX";
101 case V8_CALL_T30_RX:
102 return "T.30 Rx FAX";
103 case V8_CALL_V_SERIES:
104 return "V series modem data";
105 case V8_CALL_FUNCTION_EXTENSION:
106 return "Call function is in extention octet";
107 }
108 return "???";
109 }
110 /*- End of function --------------------------------------------------------*/
111
112 const char *v8_modulation_to_str(int modulation_scheme)
113 {
114 switch (modulation_scheme)
115 {
116 case V8_MOD_V17:
117 return "V.17 half-duplex";
118 case V8_MOD_V21:
119 return "V.21 duplex";
120 case V8_MOD_V22:
121 return "V.22/V22.bis duplex";
122 case V8_MOD_V23HALF:
123 return "V.23 half-duplex";
124 case V8_MOD_V23:
125 return "V.23 duplex";
126 case V8_MOD_V26BIS:
127 return "V.23 duplex";
128 case V8_MOD_V26TER:
129 return "V.23 duplex";
130 case V8_MOD_V27TER:
131 return "V.23 duplex";
132 case V8_MOD_V29:
133 return "V.29 half-duplex";
134 case V8_MOD_V32:
135 return "V.32/V32.bis duplex";
136 case V8_MOD_V34HALF:
137 return "V.34 half-duplex";
138 case V8_MOD_V34:
139 return "V.34 duplex";
140 case V8_MOD_V90:
141 return "V.90 duplex";
142 case V8_MOD_V92:
143 return "V.92 duplex";
144 case V8_MOD_FAILED:
145 return "negotiation failed";
146 }
147 return "???";
148 }
149 /*- End of function --------------------------------------------------------*/
150
151 const char *v8_protocol_to_str(int protocol)
152 {
153 switch (protocol)
154 {
155 case V8_PROTOCOL_NONE:
156 return "None";
157 case V8_PROTOCOL_LAPM_V42:
158 return "LAPM";
159 case V8_PROTOCOL_EXTENSION:
160 return "Extension";
161 }
162 return "Undefined";
163 }
164 /*- End of function --------------------------------------------------------*/
165
166 const char *v8_pstn_access_to_str(int pstn_access)
167 {
168 return "???";
169 }
170 /*- End of function --------------------------------------------------------*/
171
172 const char *v8_pcm_modem_availability_to_str(int pcm_modem_availability)
173 {
174 return "???";
175 }
176 /*- End of function --------------------------------------------------------*/
177
178 void v8_log_supported_modulations(v8_state_t *s, int modulation_schemes)
179 {
180 const char *comma;
181 int i;
182
183 comma = "";
184 span_log(&s->logging, SPAN_LOG_FLOW, "");
185 for (i = 0; i < 32; i++)
186 {
187 if ((modulation_schemes & (1 << i)))
188 {
189 span_log(&s->logging, SPAN_LOG_FLOW | SPAN_LOG_SUPPRESS_LABELLING, "%s%s", comma, v8_modulation_to_str(modulation_schemes & (1 << i)));
190 comma = ", ";
191 }
192 }
193 span_log(&s->logging, SPAN_LOG_FLOW | SPAN_LOG_SUPPRESS_LABELLING, " supported\n");
194 }
195 /*- End of function --------------------------------------------------------*/
196
197 static const uint8_t *process_call_function(v8_state_t *s, const uint8_t *p)
198 {
199 int call_function;
200
201 call_function = (*p >> 5) & 0x07;
202 span_log(&s->logging, SPAN_LOG_FLOW, "%s\n", v8_call_function_to_str(call_function));
203 s->call_function = call_function;
204 return ++p;
205 }
206 /*- End of function --------------------------------------------------------*/
207
208 static const uint8_t *process_modulation_mode(v8_state_t *s, const uint8_t *p)
209 {
210 int far_end_modulations;
211
212 /* Modulation mode octet */
213 far_end_modulations = 0;
214 if (*p & 0x80)
215 far_end_modulations |= V8_MOD_V34HALF;
216 if (*p & 0x40)
217 far_end_modulations |= V8_MOD_V34;
218 if (*p & 0x20)
219 far_end_modulations |= V8_MOD_V90;
220
221 if ((*++p & 0x38) == 0x10)
222 {
223 if (*p & 0x80)
224 far_end_modulations |= V8_MOD_V27TER;
225 if (*p & 0x40)
226 far_end_modulations |= V8_MOD_V29;
227 if (*p & 0x04)
228 far_end_modulations |= V8_MOD_V17;
229 if (*p & 0x02)
230 far_end_modulations |= V8_MOD_V22;
231 if (*p & 0x01)
232 far_end_modulations |= V8_MOD_V32;
233
234 if ((*++p & 0x38) == 0x10)
235 {
236 if (*p & 0x80)
237 far_end_modulations |= V8_MOD_V21;
238 if (*p & 0x40)
239 far_end_modulations |= V8_MOD_V23HALF;
240 if (*p & 0x04)
241 far_end_modulations |= V8_MOD_V23;
242 if (*p & 0x02)
243 far_end_modulations |= V8_MOD_V26BIS;
244 if (*p & 0x01)
245 far_end_modulations |= V8_MOD_V26TER;
246 /* Skip any future extensions we do not understand */
247 while ((*++p & 0x38) == 0x10)
248 /* dummy loop */;
249 }
250 }
251 s->far_end_modulations = far_end_modulations;
252 v8_log_supported_modulations(s, s->far_end_modulations);
253 return ++p;
254 }
255 /*- End of function --------------------------------------------------------*/
256
257 static const uint8_t *process_protocols(v8_state_t *s, const uint8_t *p)
258 {
259 int protocol;
260
261 protocol = (*p >> 5) & 0x07;
262 span_log(&s->logging, SPAN_LOG_FLOW, "%s\n", v8_protocol_to_str(protocol));
263 s->protocol = protocol;
264 return ++p;
265 }
266 /*- End of function --------------------------------------------------------*/
267
268 static const uint8_t *process_pstn_access(v8_state_t *s, const uint8_t *p)
269 {
270 int pstn_access;
271
272 pstn_access = (*p >> 5) & 0x07;
273 if (pstn_access & V8_PSTN_ACCESS_DCE_ON_DIGTIAL)
274 span_log(&s->logging, SPAN_LOG_FLOW, "DCE on digital network connection\n");
275 else
276 span_log(&s->logging, SPAN_LOG_FLOW, "DCE on analogue network connection\n");
277 if (pstn_access & V8_PSTN_ACCESS_ANSWER_DCE_CELLULAR)
278 span_log(&s->logging, SPAN_LOG_FLOW, "Answer DCE on cellular connection\n");
279 if (pstn_access & V8_PSTN_ACCESS_CALL_DCE_CELLULAR)
280 span_log(&s->logging, SPAN_LOG_FLOW, "Call DCE on cellular connection\n");
281 return ++p;
282 }
283 /*- End of function --------------------------------------------------------*/
284
285 static const uint8_t *process_non_standard_facilities(v8_state_t *s, const uint8_t *p)
286 {
287 ++p;
288 p += *p;
289 return p;
290 }
291 /*- End of function --------------------------------------------------------*/
292
293 static const uint8_t *process_pcm_modem_availability(v8_state_t *s, const uint8_t *p)
294 {
295 int pcm_availability;
296
297 pcm_availability = (*p >> 5) & 0x07;
298 if (pcm_availability & V8_PSTN_PCM_MODEM_V91)
299 span_log(&s->logging, SPAN_LOG_FLOW, "V.91 available\n");
300 if (pcm_availability & V8_PSTN_PCM_MODEM_V90_V92_DIGITAL)
301 span_log(&s->logging, SPAN_LOG_FLOW, "V.90 or V.92 digital modem available\n");
302 if (pcm_availability & V8_PSTN_PCM_MODEM_V90_V92_ANALOGUE)
303 span_log(&s->logging, SPAN_LOG_FLOW, "V.90 or V.92 analogue modem available\n");
304 return ++p;
305 }
306 /*- End of function --------------------------------------------------------*/
307
308 static const uint8_t *process_t66(v8_state_t *s, const uint8_t *p)
309 {
310 return ++p;
311 }
312 /*- End of function --------------------------------------------------------*/
313
314 static void ci_decode(v8_state_t *s)
315 {
316 if ((s->rx_data[0] & 0x1F) == 0x01)
317 process_call_function(s, &s->rx_data[0]);
318 }
319 /*- End of function --------------------------------------------------------*/
320
321 static void cm_jm_decode(v8_state_t *s)
322 {
323 const uint8_t *p;
324
325 if (s->got_cm_jm)
326 return;
327
328 /* We must receive two consecutive identical CM or JM sequences to accept it. */
329 if (s->cm_jm_count <= 0
330 ||
331 s->cm_jm_count != s->rx_data_ptr
332 ||
333 memcmp(s->cm_jm_data, s->rx_data, s->rx_data_ptr))
334 {
335 /* Save the current CM or JM sequence */
336 s->cm_jm_count = s->rx_data_ptr;
337 memcpy(s->cm_jm_data, s->rx_data, s->rx_data_ptr);
338 return;
339 }
340 /* We have a pair of matching CMs or JMs */
341 s->got_cm_jm = TRUE;
342
343 span_log(&s->logging, SPAN_LOG_FLOW, "Decoding\n");
344
345 /* Zero indicates the end */
346 s->cm_jm_data[s->cm_jm_count] = 0;
347
348 s->far_end_modulations = 0;
349 p = s->cm_jm_data;
350
351 while (*p)
352 {
353 switch (*p & 0x1F)
354 {
355 case 0x01:
356 p = process_call_function(s, p);
357 break;
358 case 0x05:
359 p = process_modulation_mode(s, p);
360 break;
361 case 0x0A:
362 p = process_protocols(s, p);
363 break;
364 case 0x0D:
365 p = process_pstn_access(s, p);
366 break;
367 case 0x0F:
368 p = process_non_standard_facilities(s, p);
369 break;
370 case 0x07:
371 p = process_pcm_modem_availability(s, p);
372 break;
373 case 0x0E:
374 p = process_t66(s, p);
375 break;
376 default:
377 p++;
378 break;
379 }
380 }
381 }
382 /*- End of function --------------------------------------------------------*/
383
384 static void put_bit(void *user_data, int bit)
385 {
386 v8_state_t *s;
387 int new_preamble_type;
388 const char *tag;
389 uint8_t data;
390
391 s = user_data;
392 if (bit < 0)
393 {
394 /* Special conditions */
395 switch (bit)
396 {
397 case PUTBIT_CARRIER_UP:
398 case PUTBIT_CARRIER_DOWN:
399 case PUTBIT_TRAINING_SUCCEEDED:
400 case PUTBIT_TRAINING_FAILED:
401 break;
402 default:
403 break;
404 }
405 return;
406 }
407 /* Wait until we sync. */
408 s->bit_stream = (s->bit_stream >> 1) | (bit << 19);
409 if (s->bit_stream == 0x803FF)
410 new_preamble_type = V8_SYNC_CI;
411 else if (s->bit_stream == 0xF03FF)
412 new_preamble_type = V8_SYNC_CM_JM;
413 else if (s->bit_stream == 0xAABFF)
414 new_preamble_type = V8_SYNC_V92;
415 else
416 new_preamble_type = V8_SYNC_UNKNOWN;
417 if (new_preamble_type)
418 {
419 /* Debug */
420 if (span_log_test(&s->logging, SPAN_LOG_FLOW))
421 {
422 if (s->preamble_type == V8_SYNC_CI)
423 {
424 tag = "CI: ";
425 }
426 else if (s->preamble_type == V8_SYNC_CM_JM)
427 {
428 if (s->caller)
429 tag = "JM: ";
430 else
431 tag = "CM: ";
432 }
433 else if (s->preamble_type == V8_SYNC_V92)
434 {
435 tag = "V92: ";
436 }
437 else
438 {
439 tag = "??: ";
440 }
441 span_log_buf(&s->logging, SPAN_LOG_FLOW, tag, s->rx_data, s->rx_data_ptr);
442 }
443 /* Decode previous sequence */
444 switch (s->preamble_type)
445 {
446 case V8_SYNC_CI:
447 ci_decode(s);
448 break;
449 case V8_SYNC_CM_JM:
450 cm_jm_decode(s);
451 break;
452 }
453 s->preamble_type = new_preamble_type;
454 s->bit_cnt = 0;
455 s->rx_data_ptr = 0;
456 }
457
458 /* Parse octets with 1 bit start, 1 bit stop */
459 if (s->preamble_type)
460 {
461 s->bit_cnt++;
462 /* Start, stop? */
463 if ((s->bit_stream & 0x80400) == 0x80000 && s->bit_cnt >= 10)
464 {
465 /* Store the available data */
466 data = (uint8_t) ((s->bit_stream >> 11) & 0xFF);
467 /* CJ detection */
468 if (data == 0)
469 {
470 if (++s->zero_byte_count == 3)
471 s->got_cj = TRUE;
472 }
473 else
474 {
475 s->zero_byte_count = 0;
476 }
477
478 if (s->rx_data_ptr < (int) (sizeof(s->rx_data) - 1))
479 s->rx_data[s->rx_data_ptr++] = data;
480 s->bit_cnt = 0;
481 }
482 }
483 }
484 /*- End of function --------------------------------------------------------*/
485
486 static void v8_decode_init(v8_state_t *s)
487 {
488 if (s->caller)
489 fsk_rx_init(&s->v21rx, &preset_fsk_specs[FSK_V21CH2], FALSE, put_bit, s);
490 else
491 fsk_rx_init(&s->v21rx, &preset_fsk_specs[FSK_V21CH1], FALSE, put_bit, s);
492 s->preamble_type = 0;
493 s->bit_stream = 0;
494 s->cm_jm_count = 0;
495 s->got_cm_jm = FALSE;
496 s->got_cj = FALSE;
497 s->zero_byte_count = 0;
498 s->rx_data_ptr = 0;
499 }
500 /*- End of function --------------------------------------------------------*/
501
502 static int get_bit(void *user_data)
503 {
504 v8_state_t *s;
505 uint8_t bit;
506
507 s = user_data;
508 if (queue_read(&s->tx_queue, &bit, 1) <= 0)
509 bit = 1;
510 return bit;
511 }
512 /*- End of function --------------------------------------------------------*/
513
514 static void v8_put_byte(v8_state_t *s, int data)
515 {
516 int i;
517 uint8_t bits[10];
518
519 /* Insert start & stop bits */
520 bits[0] = 0;
521 for (i = 1; i < 9; i++)
522 {
523 bits[i] = (uint8_t) (data & 1);
524 data >>= 1;
525 }
526 bits[9] = 1;
527 queue_write(&s->tx_queue, bits, 10);
528 }
529 /*- End of function --------------------------------------------------------*/
530
531 static void send_cm_jm(v8_state_t *s, int mod_mask)
532 {
533 int val;
534 static const uint8_t preamble[20] =
535 {
536 /* 10 1's (0x3FF), then 10 bits of CM sync (0x00F) */
537 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1
538 };
539
540 /* Send a CM, or a JM as appropriate */
541 queue_write(&s->tx_queue, preamble, 20);
542
543 /* Data call */
544 v8_put_byte(s, (V8_CALL_V_SERIES << 5) | 0x01);
545
546 /* Supported modulations */
547 val = 0x05;
548 if (mod_mask & V8_MOD_V90)
549 val |= 0x20;
550 if (mod_mask & V8_MOD_V34)
551 val |= 0x40;
552 v8_put_byte(s, val);
553
554 val = 0x10;
555 if (mod_mask & V8_MOD_V32)
556 val |= 0x01;
557 if (mod_mask & V8_MOD_V22)
558 val |= 0x02;
559 if (mod_mask & V8_MOD_V17)
560 val |= 0x04;
561 if (mod_mask & V8_MOD_V29)
562 val |= 0x40;
563 if (mod_mask & V8_MOD_V27TER)
564 val |= 0x80;
565 v8_put_byte(s, val);
566
567 val = 0x10;
568 if (mod_mask & V8_MOD_V26TER)
569 val |= 0x01;
570 if (mod_mask & V8_MOD_V26BIS)
571 val |= 0x02;
572 if (mod_mask & V8_MOD_V23)
573 val |= 0x04;
574 if (mod_mask & V8_MOD_V23HALF)
575 val |= 0x40;
576 if (mod_mask & V8_MOD_V21)
577 val |= 0x80;
578 v8_put_byte(s, val);
579
580 v8_put_byte(s, (0 << 5) | 0x07);
581
582 v8_put_byte(s, (V8_PROTOCOL_LAPM_V42 << 5) | 0x0A);
583
584 /* No cellular right now */
585 v8_put_byte(s, (0 << 5) | 0x0D);
586 }
587 /*- End of function --------------------------------------------------------*/
588
589 static int select_modulation(int mask)
590 {
591 if (mask & V8_MOD_V90)
592 return V8_MOD_V90;
593 if (mask & V8_MOD_V34)
594 return V8_MOD_V34;
595 if (mask & V8_MOD_V32)
596 return V8_MOD_V32;
597 if (mask & V8_MOD_V23)
598 return V8_MOD_V23;
599 if (mask & V8_MOD_V21)
600 return V8_MOD_V21;
601 return V8_MOD_FAILED;
602 }
603 /*- End of function --------------------------------------------------------*/
604
605 int v8_tx(v8_state_t *s, int16_t *amp, int max_len)
606 {
607 int len;
608
609 //span_log(&s->logging, SPAN_LOG_FLOW, "v8_tx state %d\n", s->state);
610 len = 0;
611 switch (s->state)
612 {
613 case V8_CI_ON:
614 case V8_CM_ON:
615 case V8_JM_ON:
616 case V8_CJ_ON:
617 len = fsk_tx(&s->v21tx, amp, max_len);
618 break;
619 case V8_CM_WAIT:
620 /* Send the ANSam tone */
621 len = modem_connect_tones_tx(&s->ec_dis_tx, amp, max_len);
622 break;
623 }
624 return len;
625 }
626 /*- End of function --------------------------------------------------------*/
627
628 int v8_rx(v8_state_t *s, const int16_t *amp, int len)
629 {
630 int i;
631 int residual_samples;
632 v8_result_t result;
633 static const uint8_t preamble[20] =
634 {
635 /* 10 1's (0x3FF), then 10 bits of CI sync (0x001) */
636 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1
637 };
638
639 //span_log(&s->logging, SPAN_LOG_FLOW, "v8_rx state %d\n", s->state);
640 residual_samples = 0;
641 switch (s->state)
642 {
643 case V8_WAIT_1S:
644 /* Wait 1 second before sending the first CI packet */
645 if ((s->negotiation_timer -= len) > 0)
646 break;
647 s->state = V8_CI;
648 s->ci_count = 0;
649 modem_connect_tones_rx_init(&s->ec_dis_rx, MODEM_CONNECT_TONES_EC_DISABLE, NULL, NULL);
650 fsk_tx_init(&s->v21tx, &preset_fsk_specs[FSK_V21CH1], get_bit, s);
651 /* Fall through to the next state */
652 case V8_CI:
653 residual_samples = modem_connect_tones_rx(&s->ec_dis_rx, amp, len);
654 /* Send 4 CI packets in a burst (the spec says at least 3) */
655 for (i = 0; i < 4; i++)
656 {
657 /* 10 1's (0x3FF), then CI sync (0x001) */
658 queue_write(&s->tx_queue, preamble, 20);
659 v8_put_byte(s, (V8_CALL_V_SERIES << 5) | 0x01);
660 }
661 s->state = V8_CI_ON;
662 break;
663 case V8_CI_ON:
664 residual_samples = modem_connect_tones_rx(&s->ec_dis_rx, amp, len);
665 if (queue_empty(&s->tx_queue))
666 {
667 s->state = V8_CI_OFF;
668 s->ci_timer = ms_to_samples(500);
669 }
670 break;
671 case V8_CI_OFF:
672 residual_samples = modem_connect_tones_rx(&s->ec_dis_rx, amp, len);
673 /* Check if an ANSam tone has been detected */
674 if (modem_connect_tones_rx_get(&s->ec_dis_rx))
675 {
676 /* Set the Te interval. The spec. says 500ms is the minimum,
677 but gives reasons why 1 second is a better value. */
678 s->ci_timer = ms_to_samples(1000);
679 s->state = V8_HEARD_ANSAM;
680 break;
681 }
682 if ((s->ci_timer -= len) <= 0)
683 {
684 if (++s->ci_count >= 10)
685 {
686 /* The spec says we should give up now. */
687 s->state = V8_PARKED;
688 if (s->result_handler)
689 s->result_handler(s->result_handler_user_data, NULL);
690 }
691 else
692 {
693 /* Try again */
694 s->state = V8_CI;
695 }
696 }
697 break;
698 case V8_HEARD_ANSAM:
699 /* We have heard the ANSam signal, but we still need to wait for the
700 end of the Te timeout period to comply with the spec. */
701 if ((s->ci_timer -= len) <= 0)
702 {
703 v8_decode_init(s);
704 s->state = V8_CM_ON;
705 s->negotiation_timer = ms_to_samples(5000);
706 send_cm_jm(s, s->available_modulations);
707 }
708 break;
709 case V8_CM_ON:
710 residual_samples = fsk_rx(&s->v21rx, amp, len);
711 if (s->got_cm_jm)
712 {
713 /* Now JM has been detected we send CJ and wait for 75 ms
714 before finishing the V.8 analysis. */
715 s->negotiated_modulation = select_modulation(s->far_end_modulations);
716
717 queue_flush(&s->tx_queue);
718 for (i = 0; i < 9; i++)
719 v8_put_byte(s, 0);
720 s->state = V8_CJ_ON;
721 break;
722 }
723 if ((s->negotiation_timer -= len) <= 0)
724 {
725 /* Timeout */
726 s->state = V8_PARKED;
727 if (s->result_handler)
728 s->result_handler(s->result_handler_user_data, NULL);
729 }
730 if (queue_empty(&s->tx_queue))
731 {
732 /* Send CM again */
733 send_cm_jm(s, s->available_modulations);
734 }
735 break;
736 case V8_CJ_ON:
737 residual_samples = fsk_rx(&s->v21rx, amp, len);
738 if (queue_empty(&s->tx_queue))
739 {
740 s->negotiation_timer = ms_to_samples(75);
741 s->state = V8_SIGC;
742 }
743 break;
744 case V8_SIGC:
745 if ((s->negotiation_timer -= len) <= 0)
746 {
747 /* The V.8 negotiation has succeeded. */
748 s->state = V8_PARKED;
749 if (s->result_handler)
750 {
751 result.call_function = s->call_function;
752 result.available_modulations = s->far_end_modulations;
753 result.negotiated_modulation = s->negotiated_modulation;
754 result.protocol = s->protocol;
755 result.pstn_access = s->pstn_access;
756 result.nsf_seen = s->nsf_seen;
757 result.pcm_modem_availability = s->pcm_modem_availability;
758 result.t66_seen = s->t66_seen;
759 s->result_handler(s->result_handler_user_data, &result);
760 }
761 }
762 break;
763 case V8_WAIT_200MS:
764 if ((s->negotiation_timer -= len) <= 0)
765 {
766 /* Send the ANSam tone */
767 modem_connect_tones_tx_init(&s->ec_dis_tx, MODEM_CONNECT_TONES_EC_DISABLE_MOD);
768
769 v8_decode_init(s);
770 s->state = V8_CM_WAIT;
771 s->negotiation_timer = ms_to_samples(5000);
772 }
773 break;
774 case V8_CM_WAIT:
775 residual_samples = fsk_rx(&s->v21rx, amp, len);
776 if (s->got_cm_jm)
777 {
778 /* Stop sending ANSam and send JM instead */
779 fsk_tx_init(&s->v21tx, &preset_fsk_specs[FSK_V21CH2], get_bit, s);
780 /* Set the timeout for JM */
781 s->negotiation_timer = ms_to_samples(5000);
782 s->state = V8_JM_ON;
783 s->common_modulations = s->available_modulations & s->far_end_modulations;
784 s->negotiated_modulation = select_modulation(s->common_modulations);
785 send_cm_jm(s, s->common_modulations);
786 break;
787 }
788 if ((s->negotiation_timer -= len) <= 0)
789 {
790 /* Timeout */
791 s->state = V8_PARKED;
792 if (s->result_handler)
793 s->result_handler(s->result_handler_user_data, NULL);
794 }
795 break;
796 case V8_JM_ON:
797 residual_samples = fsk_rx(&s->v21rx, amp, len);
798 if (s->got_cj)
799 {
800 /* Stop sending JM, and wait 75 ms */
801 s->negotiation_timer = ms_to_samples(75);
802 s->state = V8_SIGA;
803 break;
804 }
805 if ((s->negotiation_timer -= len) <= 0)
806 {
807 /* Timeout */
808 s->state = V8_PARKED;
809 if (s->result_handler)
810 s->result_handler(s->result_handler_user_data, NULL);
811 break;
812 }
813 if (queue_empty(&s->tx_queue))
814 {
815 /* Send JM */
816 send_cm_jm(s, s->common_modulations);
817 }
818 break;
819 case V8_SIGA:
820 if ((s->negotiation_timer -= len) <= 0)
821 {
822 /* The V.8 negotiation has succeeded. */
823 s->state = V8_PARKED;
824 if (s->result_handler)
825 {
826 result.call_function = s->call_function;
827 result.available_modulations = s->far_end_modulations;
828 result.negotiated_modulation = s->negotiated_modulation;
829 result.protocol = s->protocol;
830 result.pstn_access = s->pstn_access;
831 result.nsf_seen = s->nsf_seen;
832 result.pcm_modem_availability = s->pcm_modem_availability;
833 result.t66_seen = s->t66_seen;
834 s->result_handler(s->result_handler_user_data, &result);
835 }
836 }
837 break;
838 case V8_PARKED:
839 residual_samples = len;
840 break;
841 }
842 return residual_samples;
843 }
844 /*- End of function --------------------------------------------------------*/
845
846 v8_state_t *v8_init(v8_state_t *s,
847 int caller,
848 int available_modulations,
849 v8_result_handler_t *result_handler,
850 void *user_data)
851 {
852 memset(s, 0, sizeof(*s));
853 s->caller = caller;
854 s->available_modulations = available_modulations;
855 s->result_handler = result_handler;
856 s->result_handler_user_data = user_data;
857
858 s->ci_timer = 0;
859 if (s->caller)
860 {
861 s->state = V8_WAIT_1S;
862 s->negotiation_timer = ms_to_samples(1000);
863 }
864 else
865 {
866 s->state = V8_WAIT_200MS;
867 s->negotiation_timer = ms_to_samples(200);
868 }
869 if (queue_create(&s->tx_queue, 1024, 0))
870 return NULL;
871 return s;
872 }
873 /*- End of function --------------------------------------------------------*/
874
875 int v8_release(v8_state_t *s)
876 {
877 return queue_delete(&s->tx_queue);
878 }
879 /*- End of function --------------------------------------------------------*/
880 /*- End of file ------------------------------------------------------------*/

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