2 * Asterisk -- A telephony toolkit for Linux.
4 * BestData 56SX-92 Voice Modem Driver (Conexant)
6 * Copyright (C) 1999, Mark Spencer and 2001 Jim Dixon
8 * Mark Spencer <markster@linux-support.net>
9 * Jim Dixon <jim@lambdatel.com>
11 * This program is free software, distributed under the terms of
12 * the GNU General Public License
21 #include <asterisk/lock.h>
22 #include <asterisk/vmodem.h>
23 #include <asterisk/module.h>
24 #include <asterisk/frame.h>
25 #include <asterisk/logger.h>
26 #include <asterisk/options.h>
28 #define STATE_COMMAND 0
30 #define STATE_VOICEPLAY 2
32 #define VRA "40" /* Number of 100ms of non-ring after a ring cadence after which we consider the lien to be answered */
33 #define VRN "25" /* Number of 100ms of non-ring with no cadence after which we assume an answer */
37 static char *breakcmd = "\020!";
39 static char *desc = "BestData (Conexant V.90 Chipset) VoiceModem Driver";
42 AST_MUTEX_DEFINE_STATIC(usecnt_lock);
44 static char *bestdata_idents[] = {
45 /* Identify BestData Modem */
46 "ACF3_V1.010-V90_P21_FSH",
50 static int bestdata_break(struct ast_modem_pvt *p);
52 static int bestdata_startrec(struct ast_modem_pvt *p)
54 if (p->ministate != STATE_COMMAND) bestdata_break(p);
55 if (ast_modem_send(p, "AT+VRX", 0) ||
56 ast_modem_expect(p, "CONNECT", 5)) {
57 ast_log(LOG_WARNING, "Unable to start recording\n");
60 p->ministate = STATE_VOICE;
64 static int bestdata_startplay(struct ast_modem_pvt *p)
66 if (p->ministate != STATE_COMMAND) bestdata_break(p);
67 if (ast_modem_send(p, "AT+VTX", 0) ||
68 ast_modem_expect(p, "CONNECT", 5)) {
69 ast_log(LOG_WARNING, "Unable to start recording\n");
72 p->ministate = STATE_VOICEPLAY;
76 static int bestdata_break(struct ast_modem_pvt *p)
78 if (ast_modem_send(p, breakcmd, 2)) {
79 ast_log(LOG_WARNING, "Failed to break\n");
82 p->ministate = STATE_COMMAND;
84 /* Read any outstanding junk */
85 while(!ast_modem_read_response(p, 1));
86 if (ast_modem_send(p, "AT", 0)) {
87 /* Modem might be stuck in some weird mode, try to get it out */
88 ast_modem_send(p, "+++", 3);
89 if (ast_modem_expect(p, "OK", 10)) {
90 ast_log(LOG_WARNING, "Modem is not responding\n");
93 if (ast_modem_send(p, "AT", 0)) {
94 ast_log(LOG_WARNING, "Modem is not responding\n");
98 if (ast_modem_expect(p, "OK", 5)) {
99 ast_log(LOG_WARNING, "Modem did not respond properly\n");
105 static int bestdata_init(struct ast_modem_pvt *p)
108 ast_log(LOG_DEBUG, "bestdata_init()\n");
109 if (bestdata_break(p))
111 /* Force into command mode */
112 p->ministate = STATE_COMMAND;
113 if (ast_modem_send(p, "AT+FCLASS=8", 0) ||
114 ast_modem_expect(p, "OK", 5)) {
115 ast_log(LOG_WARNING, "Unable to set to voice mode\n");
118 if (ast_modem_send(p, "AT+VSM=1,8000,0,0", 0) ||
119 ast_modem_expect(p, "OK", 5)) {
120 ast_log(LOG_WARNING, "Unable to set to 8000 Hz sampling\n");
123 if (ast_modem_send(p, "AT+VLS=0", 0) ||
124 ast_modem_expect(p, "OK", 5)) {
125 ast_log(LOG_WARNING, "Unable to set to telco interface\n");
128 if (ast_modem_send(p, "AT+VRA=" VRA, 0) ||
129 ast_modem_expect(p, "OK", 5)) {
130 ast_log(LOG_WARNING, "Unable to set to 'ringback goes away' timer\n");
133 if (ast_modem_send(p, "AT+VRN=" VRN, 0) ||
134 ast_modem_expect(p, "OK", 5)) {
135 ast_log(LOG_WARNING, "Unable to set to 'ringback never came timer'\n");
138 if (ast_modem_send(p, "AT+VTD=63", 0) ||
139 ast_modem_expect(p, "OK", 5)) {
140 ast_log(LOG_WARNING, "Unable to set to tone detection\n");
143 if (ast_modem_send(p, "AT+VCID=1", 0) ||
144 ast_modem_expect(p, "OK", 5)) {
145 ast_log(LOG_WARNING, "Unable to enable Caller*ID\n");
151 static struct ast_frame *bestdata_handle_escape(struct ast_modem_pvt *p, char esc)
153 char name[30]="",nmbr[30]="";
156 /* Handle escaped characters -- but sometimes we call it directly as
157 a quick way to cause known responses */
158 p->fr.frametype = AST_FRAME_NULL;
165 p->fr.delivery.tv_sec = 0;
166 p->fr.delivery.tv_usec = 0;
168 ast_log(LOG_DEBUG, "Escaped character '%c'\n", esc);
171 case 'R': /* Pseudo ring */
173 if (now > (p->lastring + (RINGT / 1000)))
174 { /* if stale, treat as new */
179 p->fr.frametype = AST_FRAME_CONTROL;
180 p->fr.subclass = AST_CONTROL_RING;
185 case 'X': /* Caller-ID Spill */
186 if (p->gotclid) return &p->fr;
187 name[0] = nmbr[0] = 0;
192 if (ast_modem_read_response(p, 5)) break;
193 strncpy(res, p->response, sizeof(res)-1);
195 if (!strncmp(res,"\020.",2)) break;
196 if (!strncmp(res,"NAME",4)) strncpy(name,res + 7, sizeof(name) - 1);
197 if (!strncmp(res,"NMBR",4)) strncpy(nmbr,res + 7, sizeof(nmbr) - 1);
200 if ((!strcmp(name,"O")) || (!strcmp(name,"P"))) name[0] = 0;
201 if ((!strcmp(nmbr,"O")) || (!strcmp(nmbr,"P"))) nmbr[0] = 0;
203 strncpy(p->cid_name, name, sizeof(p->cid_name) - 1);
205 strncpy(p->cid_num, nmbr, sizeof(p->cid_num) - 1);
207 p->owner->cid.cid_num = strdup(p->cid_num);
208 p->owner->cid.cid_name = strdup(p->cid_name);
211 case '@': /* response from "OK" in command mode */
213 ast_setstate(p->owner, AST_STATE_UP);
214 if (bestdata_startrec(p)) return NULL;
215 p->fr.frametype = AST_FRAME_CONTROL;
216 p->fr.subclass = AST_CONTROL_RING;
218 case 'b': /* Busy signal */
219 p->fr.frametype = AST_FRAME_CONTROL;
220 p->fr.subclass = AST_CONTROL_BUSY;
222 case 'o': /* Overrun */
223 ast_log(LOG_WARNING, "Overflow on modem, flushing buffers\n");
224 if (ast_modem_send(p, "\0x10E", 2))
225 ast_log(LOG_WARNING, "Unable to flush buffers\n");
227 case '0': /* All the DTMF characters */
243 p->dtmfrx = esc; /* save this for when its done */
245 case '/': /* Start of DTMF tone shielding */
248 case '~': /* DTMF transition to off */
251 p->fr.frametype = AST_FRAME_DTMF;
252 p->fr.subclass = p->dtmfrx;
256 case 'u': /* Underrun */
257 ast_log(LOG_WARNING, "Data underrun\n");
259 case CHAR_ETX: /* End Transmission */
260 case 'd': /* Dialtone */
261 case 'c': /* Calling Tone */
262 case 'e': /* European version */
263 case 'a': /* Answer Tone */
264 case 'f': /* Bell Answer Tone */
265 case 'T': /* Timing mark */
266 case 't': /* Handset off hook */
267 case 'h': /* Handset hungup */
268 case 0: /* Pseudo signal */
272 ast_log(LOG_DEBUG, "Unknown Escaped character '%c' (%d)\n", esc, esc);
277 static struct ast_frame *bestdata_read(struct ast_modem_pvt *p)
281 struct ast_frame *f=NULL;
285 if (p->ministate == STATE_COMMAND) {
286 /* Read the first two bytes, first, in case it's a control message */
287 fread(result, 1, 2, p->f);
288 if (result[0] == CHAR_DLE) {
289 return bestdata_handle_escape(p, result[1]);
291 if (p->ringt) /* if ring timeout specified */
294 res = ast_waitfor_n_fd(&x, 1, &p->ringt, NULL);
299 if ((result[0] == '\n') || (result[0] == '\r'))
300 return bestdata_handle_escape(p, 0);
301 /* Read the rest of the line */
302 fgets(result + 2, sizeof(result) - 2, p->f);
303 ast_modem_trim(result);
304 if (!strcasecmp(result, "OK")) {
305 /* If we're in immediate mode, reply now */
306 if (p->mode == MODEM_MODE_IMMEDIATE)
307 return bestdata_handle_escape(p, '@');
309 if (!strcasecmp(result, "BUSY")) {
310 /* Same as a busy signal */
311 return bestdata_handle_escape(p, 'b');
313 if (!strcasecmp(result, "RING")) {
314 return bestdata_handle_escape(p, 'R');
316 if (!strcasecmp(result, "NO DIALTONE")) {
317 /* There's no dialtone, so the line isn't working */
318 ast_log(LOG_WARNING, "Device '%s' lacking dialtone\n", p->dev);
321 ast_log(LOG_DEBUG, "Modem said '%s'\n", result);
322 return bestdata_handle_escape(p, 0);
325 /* if playing, start recording instead */
326 if (p->ministate == STATE_VOICEPLAY)
328 if (bestdata_startrec(p)) return NULL;
330 /* We have to be more efficient in voice mode */
331 b = (short *)(p->obuf + p->obuflen);
332 while (p->obuflen/2 < 240) {
333 /* Read ahead the full amount */
334 res = fread(result, 1, 240 - p->obuflen/2, p->f);
336 /* If there's nothing there, just continue on */
338 return bestdata_handle_escape(p, 0);
339 ast_log(LOG_WARNING, "Read failed: %s\n", strerror(errno));
341 for (x=0;x<res;x++) {
342 /* Process all the bytes that we've read */
343 if (result[x] == CHAR_DLE) {
344 /* We assume there is no more than one signal frame among our
346 if (f) ast_log(LOG_WARNING, "Warning: Dropped a signal frame\n");
347 /* if not a DLE in the data */
348 if (result[++x] != CHAR_DLE)
350 /* If bestdata_handle_escape says NULL, say it now, doesn't matter
351 what else is there, the connection is dead. */
352 f = bestdata_handle_escape(p, result[x]);
353 if (p->dtmfrx) continue;
357 /* Generate a 16-bit signed linear value from our
358 unsigned 8-bit value */
359 *(b++) = (((short)result[x]) - 127) * 0xff;
364 /* If we have a control frame, return it now */
366 /* If we get here, we have a complete voice frame */
367 p->fr.frametype = AST_FRAME_VOICE;
368 p->fr.subclass = AST_FORMAT_SLINEAR;
370 p->fr.data = p->obuf;
371 p->fr.datalen = p->obuflen;
373 p->fr.delivery.tv_sec = 0;
374 p->fr.delivery.tv_usec = 0;
375 p->fr.offset = AST_FRIENDLY_OFFSET;
376 p->fr.src = __FUNCTION__;
378 ast_log(LOG_DEBUG, "bestdata_read(voice frame)\n");
385 static int bestdata_write(struct ast_modem_pvt *p, struct ast_frame *f)
387 unsigned char c,buf[32768]; /* I hope we dont have frames larger then 16K */
393 if (p->owner && (p->owner->_state == AST_STATE_UP) &&
394 (p->ministate != STATE_VOICEPLAY) && bestdata_startplay(p)) return -1;
395 sp = (short *) f->data;
396 /* stick DLE's in ahead of anything else */
397 for(i = 0,j = 0; i < f->datalen / 2; i++)
402 if (c == DLE) buf[j++] = DLE;
405 do i = fwrite(buf,1,j,p->f);
406 while ((i == -1) && (errno == EWOULDBLOCK));
409 ast_log(LOG_WARNING,"modem short write!!\n");
414 ast_log(LOG_DEBUG, "bestdata_write()\n");
418 static char *bestdata_identify(struct ast_modem_pvt *p)
424 ast_modem_send(p, "AT+FMM", 0);
425 ast_modem_read_response(p, 5);
426 strncpy(mdl, p->response, sizeof(mdl)-1);
428 ast_modem_expect(p, "OK", 5);
429 ast_modem_send(p, "AT+FMI", 0);
430 ast_modem_read_response(p, 5);
431 strncpy(mfr, p->response, sizeof(mfr)-1);
433 ast_modem_expect(p, "OK", 5);
434 ast_modem_send(p, "AT+FMR", 0);
435 ast_modem_read_response(p, 5);
436 strncpy(rev, p->response, sizeof(rev)-1);
438 ast_modem_expect(p, "OK", 5);
439 snprintf(identity, sizeof(identity), "%s Model %s Revision %s", mfr, mdl, rev);
440 return strdup(identity);
443 static void bestdata_incusecnt(void)
445 ast_mutex_lock(&usecnt_lock);
447 ast_mutex_unlock(&usecnt_lock);
448 ast_update_use_count();
451 static void bestdata_decusecnt(void)
453 ast_mutex_lock(&usecnt_lock);
455 ast_mutex_unlock(&usecnt_lock);
456 ast_update_use_count();
459 static int bestdata_answer(struct ast_modem_pvt *p)
463 if (ast_modem_send(p, "AT+VLS=1", 0) ||
464 ast_modem_expect(p, "OK", 10)) {
465 ast_log(LOG_WARNING, "Unable to answer: %s", p->response);
471 static int bestdata_dialdigit(struct ast_modem_pvt *p, char digit)
475 if (p->ministate != STATE_COMMAND) bestdata_break(p);
476 snprintf(cmd, sizeof(cmd), "AT+VTS=%c", digit);
477 if (ast_modem_send(p, cmd, 0) ||
478 ast_modem_expect(p, "OK", 10)) {
479 ast_log(LOG_WARNING, "Unable to answer: %s", p->response);
485 static int bestdata_dial(struct ast_modem_pvt *p, char *stuff)
487 char cmd[800] = "",a[20]="";
490 if (p->ministate != STATE_COMMAND)
493 strncpy(cmd, "AT+VTS=", sizeof(cmd) - 1);
495 for(i = 0; stuff[i]; i++)
504 strncpy(a, "[,,100]", sizeof(a) - 1);
507 snprintf(a, sizeof(a), "{%c,7}", stuff[i]);
509 if (stuff[i + 1]) strncat(a, ",", sizeof(a) - strlen(a) - 1);
510 strncpy(cmd + j, a, sizeof(cmd) - j - 1);
516 snprintf(cmd, sizeof(cmd), "ATD%c %s", p->dialtype,stuff);
518 if (ast_modem_send(p, cmd, 0)) {
519 ast_log(LOG_WARNING, "Unable to dial\n");
525 static int bestdata_hangup(struct ast_modem_pvt *p)
527 if (bestdata_break(p))
529 /* Hangup by switching to data, then back to voice */
530 if (ast_modem_send(p, "ATH", 0) ||
531 ast_modem_expect(p, "OK", 8)) {
532 ast_log(LOG_WARNING, "Unable to set to data mode\n");
535 if (ast_modem_send(p, "AT+FCLASS=8", 0) ||
536 ast_modem_expect(p, "OK", 5)) {
537 ast_log(LOG_WARNING, "Unable to set to voice mode\n");
547 static struct ast_modem_driver bestdata_driver =
552 0, /* Not full duplex */
553 bestdata_incusecnt, /* incusecnt */
554 bestdata_decusecnt, /* decusecnt */
555 bestdata_identify, /* identify */
556 bestdata_init, /* init */
560 bestdata_dial, /* dial */
561 bestdata_answer, /* answer */
562 bestdata_hangup, /* hangup */
563 bestdata_startrec, /* start record */
564 NULL, /* stop record */
565 bestdata_startplay, /* start playback */
566 NULL, /* stop playback */
567 NULL, /* set silence supression */
568 bestdata_dialdigit, /* dialdigit */
576 ast_mutex_lock(&usecnt_lock);
578 ast_mutex_unlock(&usecnt_lock);
582 int load_module(void)
584 return ast_register_modem_driver(&bestdata_driver);
587 int unload_module(void)
589 return ast_unregister_modem_driver(&bestdata_driver);
599 return ASTERISK_GPL_KEY;