7ec76aa5ecddf71d4c40558778b4e655cfdab94f
[asterisk/asterisk.git] / channels / chan_modem_bestdata.c
1 /*
2  * Asterisk -- A telephony toolkit for Linux.
3  *
4  * BestData 56SX-92 Voice Modem Driver (Conexant)
5  * 
6  * Copyright (C) 1999, Mark Spencer and 2001 Jim Dixon
7  *
8  * Mark Spencer <markster@linux-support.net>
9  * Jim Dixon <jim@lambdatel.com>
10  *
11  * This program is free software, distributed under the terms of
12  * the GNU General Public License
13  */
14
15 #include <stdio.h>
16
17 #include <string.h>
18 #include <stdlib.h>
19 #include <errno.h>
20 #include <asterisk/lock.h>
21 #include <asterisk/vmodem.h>
22 #include <asterisk/module.h>
23 #include <asterisk/frame.h>
24 #include <asterisk/logger.h>
25 #include <asterisk/options.h>
26
27 #define STATE_COMMAND   0
28 #define STATE_VOICE     1
29 #define STATE_VOICEPLAY 2
30
31 #define VRA "40"                        /* Number of 100ms of non-ring after a ring cadence after which we consider the lien to be answered */
32 #define VRN "25"                        /* Number of 100ms of non-ring with no cadence after which we assume an answer */
33
34 #define RINGT   7000
35
36 static char *breakcmd = "\020!";
37
38 static char *desc = "BestData (Conexant V.90 Chipset) VoiceModem Driver";
39
40 int usecnt;
41 pthread_mutex_t usecnt_lock = AST_MUTEX_INITIALIZER;
42
43 static char *bestdata_idents[] = {
44         /* Identify BestData Modem */
45         "ACF3_V1.010-V90_P21_FSH",
46         NULL
47 };
48
49 static int bestdata_startrec(struct ast_modem_pvt *p)
50 {
51 static int bestdata_break(struct ast_modem_pvt *p);
52
53         if (p->ministate != STATE_COMMAND) bestdata_break(p);
54         if (ast_modem_send(p, "AT+VRX", 0) ||
55              ast_modem_expect(p, "CONNECT", 5)) {
56                 ast_log(LOG_WARNING, "Unable to start recording\n");
57                 return -1;
58         }
59         p->ministate = STATE_VOICE;
60         return 0;
61 }
62
63 static int bestdata_startplay(struct ast_modem_pvt *p)
64 {
65 static int bestdata_break(struct ast_modem_pvt *p);
66
67         if (p->ministate != STATE_COMMAND) bestdata_break(p);
68         if (ast_modem_send(p, "AT+VTX", 0) ||
69              ast_modem_expect(p, "CONNECT", 5)) {
70                 ast_log(LOG_WARNING, "Unable to start recording\n");
71                 return -1;
72         }
73         p->ministate = STATE_VOICEPLAY;
74         return 0;
75 }
76
77 static int bestdata_break(struct ast_modem_pvt *p)
78 {
79         if (ast_modem_send(p, breakcmd, 2)) {
80                 ast_log(LOG_WARNING, "Failed to break\n");
81                 return -1;
82         }
83         p->ministate = STATE_COMMAND;
84         usleep(10000);
85         /* Read any outstanding junk */
86         while(!ast_modem_read_response(p, 1));
87         if (ast_modem_send(p, "AT", 0)) {
88                 /* Modem might be stuck in some weird mode, try to get it out */
89                 ast_modem_send(p, "+++", 3);
90                 if (ast_modem_expect(p, "OK", 10)) {
91                         ast_log(LOG_WARNING, "Modem is not responding\n");
92                         return -1;
93                 }
94                 if (ast_modem_send(p, "AT", 0)) {
95                         ast_log(LOG_WARNING, "Modem is not responding\n");
96                         return -1;
97                 }
98         }
99         if (ast_modem_expect(p, "OK", 5)) {
100                 ast_log(LOG_WARNING, "Modem did not respond properly\n");
101                 return -1;
102         }
103         return 0;
104 }
105
106 static int bestdata_init(struct ast_modem_pvt *p)
107 {
108         if (option_debug)
109                 ast_log(LOG_DEBUG, "bestdata_init()\n");
110         if (bestdata_break(p))
111                 return -1;
112         /* Force into command mode */
113         p->ministate = STATE_COMMAND;
114         if (ast_modem_send(p, "AT+FCLASS=8", 0) ||
115              ast_modem_expect(p, "OK", 5)) {
116                 ast_log(LOG_WARNING, "Unable to set to voice mode\n");
117                 return -1;
118         }
119         if (ast_modem_send(p, "AT+VSM=1,8000,0,0", 0) ||
120              ast_modem_expect(p, "OK", 5)) {
121                 ast_log(LOG_WARNING, "Unable to set to 8000 Hz sampling\n");
122                 return -1;
123         }
124         if (ast_modem_send(p, "AT+VLS=0", 0) ||
125              ast_modem_expect(p, "OK", 5)) {
126                 ast_log(LOG_WARNING, "Unable to set to telco interface\n");
127                 return -1;
128         }
129         if (ast_modem_send(p, "AT+VRA=" VRA, 0) ||
130              ast_modem_expect(p, "OK", 5)) {
131                 ast_log(LOG_WARNING, "Unable to set to 'ringback goes away' timer\n");
132                 return -1;
133         }
134         if (ast_modem_send(p, "AT+VRN=" VRN, 0) ||
135              ast_modem_expect(p, "OK", 5)) {
136                 ast_log(LOG_WARNING, "Unable to set to 'ringback never came timer'\n");
137                 return -1;
138         }
139         if (ast_modem_send(p, "AT+VTD=63", 0) ||
140              ast_modem_expect(p, "OK", 5)) {
141                 ast_log(LOG_WARNING, "Unable to set to tone detection\n");
142                 return -1;
143         }
144         if (ast_modem_send(p, "AT+VCID=1", 0) ||
145              ast_modem_expect(p, "OK", 5)) {
146                 ast_log(LOG_WARNING, "Unable to enable Caller*ID\n");
147                 return -1;
148         }
149         return 0;
150 }
151
152 static struct ast_frame *bestdata_handle_escape(struct ast_modem_pvt *p, char esc)
153 {
154         char name[30],nmbr[30];
155         time_t  now;
156
157         /* Handle escaped characters -- but sometimes we call it directly as 
158            a quick way to cause known responses */
159         p->fr.frametype = AST_FRAME_NULL;
160         p->fr.subclass = 0;
161         p->fr.data = NULL;
162         p->fr.datalen = 0;
163         p->fr.samples = 0;
164         p->fr.offset = 0;
165         p->fr.mallocd = 0;
166         if (esc)
167                 ast_log(LOG_DEBUG, "Escaped character '%c'\n", esc);
168         
169         switch(esc) {
170         case 'R': /* Pseudo ring */
171                 time(&now);
172                 if (now > (p->lastring + (RINGT / 1000)))
173                    { /* if stale, treat as new */
174                         p->gotclid = 0;
175                    }
176                 if (p->gotclid)
177                    {
178                         p->fr.frametype = AST_FRAME_CONTROL;
179                         p->fr.subclass = AST_CONTROL_RING;
180                    }
181                 p->ringt = RINGT;
182                 time(&p->lastring);
183                 return &p->fr;
184         case 'X': /* Caller-ID Spill */
185                 if (p->gotclid) return &p->fr;
186                 name[0] = nmbr[0] = 0;
187                 for(;;)
188                    {
189                         char res[1000];
190
191                         if (ast_modem_read_response(p, 5)) break;
192                         strncpy(res, p->response, sizeof(res)-1);
193                         ast_modem_trim(res);
194                         if (!strncmp(res,"\020.",2)) break;
195                         if (!strncmp(res,"NAME",4)) strcpy(name,res + 7);
196                         if (!strncmp(res,"NMBR",4)) strcpy(nmbr,res + 7);
197                    }
198                 p->gotclid = 1;
199                 if ((!strcmp(name,"O")) || (!strcmp(name,"P"))) name[0] = 0;
200                 if ((!strcmp(nmbr,"O")) || (!strcmp(nmbr,"P"))) nmbr[0] = 0;
201                 if ((name[0]) && (nmbr[0])) snprintf(p->cid,sizeof(p->cid),
202                         "\"%s\" <%s>",name,nmbr);
203                 else if (name[0]) snprintf(p->cid,sizeof(p->cid),
204                         "\"%s\"",name);
205                 else if (nmbr[0]) snprintf(p->cid,sizeof(p->cid),
206                         "%s",nmbr);
207                 if (p->owner) p->owner->callerid = strdup(p->cid);
208                 return &p->fr;
209         case '@': /* response from "OK" in command mode */
210                 if (p->owner)
211                         ast_setstate(p->owner, AST_STATE_UP);
212                 if (bestdata_startrec(p)) return NULL;
213                 p->fr.frametype = AST_FRAME_CONTROL;
214                 p->fr.subclass = AST_CONTROL_RING;
215                 return &p->fr;
216         case 'b': /* Busy signal */
217                 p->fr.frametype = AST_FRAME_CONTROL;
218                 p->fr.subclass = AST_CONTROL_BUSY;
219                 return &p->fr;
220         case 'o': /* Overrun */
221                 ast_log(LOG_WARNING, "Overflow on modem, flushing buffers\n");
222                 if (ast_modem_send(p, "\0x10E", 2)) 
223                         ast_log(LOG_WARNING, "Unable to flush buffers\n");
224                 return &p->fr;  
225         case '0':  /* All the DTMF characters */
226         case '1':
227         case '2':
228         case '3':
229         case '4':
230         case '5':
231         case '6':
232         case '7':
233         case '8':
234         case '9':
235         case '*':
236         case '#':
237         case 'A':
238         case 'B':
239         case 'C':
240         case 'D':
241                 p->dtmfrx = esc;  /* save this for when its done */
242                 return &p->fr;  
243         case '/': /* Start of DTMF tone shielding */
244                 p->dtmfrx = ' ';
245                 return &p->fr;  
246         case '~': /* DTMF transition to off */
247                 if (p->dtmfrx > ' ')
248                    {
249                         p->fr.frametype = AST_FRAME_DTMF;
250                         p->fr.subclass = p->dtmfrx;
251                    }
252                 p->dtmfrx = 0;
253                 return &p->fr;  
254         case 'u': /* Underrun */
255                 ast_log(LOG_WARNING, "Data underrun\n");
256                 /* Fall Through */
257         case CHAR_ETX: /* End Transmission */
258         case 'd': /* Dialtone */
259         case 'c': /* Calling Tone */
260         case 'e': /* European version */
261         case 'a': /* Answer Tone */
262         case 'f': /* Bell Answer Tone */
263         case 'T': /* Timing mark */
264         case 't': /* Handset off hook */
265         case 'h': /* Handset hungup */
266         case 0: /* Pseudo signal */
267                 /* Ignore */
268                 return &p->fr;  
269         default:
270                 ast_log(LOG_DEBUG, "Unknown Escaped character '%c' (%d)\n", esc, esc);
271         }
272         return &p->fr;
273 }
274
275 static struct ast_frame *bestdata_read(struct ast_modem_pvt *p)
276 {
277         char result[256];
278         short *b;
279         struct ast_frame *f=NULL;
280         int res;
281         int x;
282
283         if (p->ministate == STATE_COMMAND) {
284                 /* Read the first two bytes, first, in case it's a control message */
285                 fread(result, 1, 2, p->f);
286                 if (result[0] == CHAR_DLE) {
287                         return bestdata_handle_escape(p, result[1]);
288                 } else {
289                         if (p->ringt) /* if ring timeout specified */
290                            {
291                                 x = fileno(p->f);
292                                 res = ast_waitfor_n_fd(&x, 1, &p->ringt, NULL);
293                                 if (res < 0) {
294                                         return NULL;
295                                 }
296                            }
297                         if ((result[0] == '\n') || (result[0] == '\r'))
298                                 return bestdata_handle_escape(p, 0);
299                         /* Read the rest of the line */
300                         fgets(result + 2, sizeof(result) - 2, p->f);
301                         ast_modem_trim(result);
302                         if (!strcasecmp(result, "OK")) {
303                                 /* If we're in immediate mode, reply now */
304                                 if (p->mode == MODEM_MODE_IMMEDIATE)
305                                         return bestdata_handle_escape(p, '@');
306                         } else
307                         if (!strcasecmp(result, "BUSY")) {
308                                 /* Same as a busy signal */
309                                 return bestdata_handle_escape(p, 'b');
310                         } else
311                         if (!strcasecmp(result, "RING")) {
312                                 return bestdata_handle_escape(p, 'R');
313                         } else
314                         if (!strcasecmp(result, "NO DIALTONE")) {
315                                 /* There's no dialtone, so the line isn't working */
316                                 ast_log(LOG_WARNING, "Device '%s' lacking dialtone\n", p->dev);
317                                 return NULL;
318                         }
319                         ast_log(LOG_DEBUG, "Modem said '%s'\n", result);
320                         return bestdata_handle_escape(p, 0);
321                 }
322         } else {
323                   /* if playing, start recording instead */
324                 if (p->ministate == STATE_VOICEPLAY)
325                    {
326                         if (bestdata_startrec(p)) return NULL;
327                    }
328                 /* We have to be more efficient in voice mode */
329                 b = (short *)(p->obuf + p->obuflen);
330                 while (p->obuflen/2 < 240) {
331                         /* Read ahead the full amount */
332                         res = fread(result, 1, 240 - p->obuflen/2, p->f);
333                         if (res < 1) {
334                                 /* If there's nothing there, just continue on */
335                                 if (errno == EAGAIN)
336                                         return bestdata_handle_escape(p, 0);
337                                 ast_log(LOG_WARNING, "Read failed: %s\n", strerror(errno));
338                         }
339                         for (x=0;x<res;x++) {
340                                 /* Process all the bytes that we've read */
341                                 if (result[x] == CHAR_DLE) {
342                                         /* We assume there is no more than one signal frame among our
343                                            data.  */
344                                         if (f) ast_log(LOG_WARNING, "Warning: Dropped a signal frame\n");
345                                           /* if not a DLE in the data */
346                                         if (result[++x] != CHAR_DLE)
347                                            {
348                                                 /* If bestdata_handle_escape says NULL, say it now, doesn't matter
349                                                    what else is there, the connection is dead. */
350                                                 f = bestdata_handle_escape(p, result[x]);
351                                                 if (p->dtmfrx) continue;
352                                                 return(f);
353                                            }
354                                 }
355                                 /* Generate a 16-bit signed linear value from our 
356                                    unsigned 8-bit value */
357                                 *(b++) = (((short)result[x]) - 127) * 0xff;
358                                 p->obuflen += 2;
359                         }
360                         if (f) break;
361                 }
362                 /* If we have a control frame, return it now */
363                 if (f) return f;
364                 /* If we get here, we have a complete voice frame */
365                 p->fr.frametype = AST_FRAME_VOICE;
366                 p->fr.subclass = AST_FORMAT_SLINEAR;
367                 p->fr.samples = 240;
368                 p->fr.data = p->obuf;
369                 p->fr.datalen = p->obuflen;
370                 p->fr.mallocd = 0;
371                 p->fr.offset = AST_FRIENDLY_OFFSET;
372                 p->fr.src = __FUNCTION__;
373                 if (option_debug)
374                         ast_log(LOG_DEBUG, "bestdata_read(voice frame)\n");
375                 p->obuflen = 0;
376                 return &p->fr;
377         }
378         return NULL;
379 }
380
381 static int bestdata_write(struct ast_modem_pvt *p, struct ast_frame *f)
382 {
383 unsigned char   c,buf[32768]; /* I hope we dont have frames larger then 16K */
384 int     i,j;
385 short   *sp;
386 unsigned long u;
387 #define DLE     16
388
389         if (p->owner && (p->owner->_state == AST_STATE_UP) && 
390                 (p->ministate != STATE_VOICEPLAY) && bestdata_startplay(p)) return -1;
391         sp = (short *) f->data;
392           /* stick DLE's in ahead of anything else */
393         for(i = 0,j = 0; i < f->datalen / 2; i++)
394            {
395                 *sp *= 3;
396                 u = *sp++ + 32768;
397                 c = u >> 8;
398                 if (c == DLE) buf[j++] = DLE;
399                 buf[j++] = c;
400            }
401         do i = fwrite(buf,1,j,p->f);
402         while ((i == -1) && (errno == EWOULDBLOCK));
403         if (i != j)
404            {
405                 ast_log(LOG_WARNING,"modem short write!!\n");
406                 return -1;
407            }
408         fflush(p->f);
409         if (option_debug)
410                 ast_log(LOG_DEBUG, "bestdata_write()\n");
411         return 0;
412 }
413
414 static char *bestdata_identify(struct ast_modem_pvt *p)
415 {
416         char identity[256];
417         char mfr[80];
418         char mdl[80];
419         char rev[80];
420         ast_modem_send(p, "AT+FMM", 0);
421         ast_modem_read_response(p, 5);
422         strncpy(mdl, p->response, sizeof(mdl)-1);
423         ast_modem_trim(mdl);
424         ast_modem_expect(p, "OK", 5);
425         ast_modem_send(p, "AT+FMI", 0);
426         ast_modem_read_response(p, 5);
427         strncpy(mfr, p->response, sizeof(mfr)-1);
428         ast_modem_trim(mfr);
429         ast_modem_expect(p, "OK", 5);
430         ast_modem_send(p, "AT+FMR", 0);
431         ast_modem_read_response(p, 5);
432         strncpy(rev, p->response, sizeof(rev)-1);
433         ast_modem_trim(rev);
434         ast_modem_expect(p, "OK", 5);
435         snprintf(identity, sizeof(identity), "%s Model %s Revision %s", mfr, mdl, rev);
436         return strdup(identity);
437 }
438
439 static void bestdata_incusecnt()
440 {
441         ast_pthread_mutex_lock(&usecnt_lock);
442         usecnt++;
443         ast_pthread_mutex_unlock(&usecnt_lock);
444         ast_update_use_count();
445 }
446
447 static void bestdata_decusecnt()
448 {
449         ast_pthread_mutex_lock(&usecnt_lock);
450         usecnt++;
451         ast_pthread_mutex_unlock(&usecnt_lock);
452         ast_update_use_count();
453 }
454
455 static int bestdata_answer(struct ast_modem_pvt *p)
456 {
457         p->ringt = 0;
458         p->lastring = 0;
459         if (ast_modem_send(p, "AT+VLS=1", 0) ||
460              ast_modem_expect(p, "OK", 10)) {
461                 ast_log(LOG_WARNING, "Unable to answer: %s", p->response);
462                 return -1;
463         }
464         return 0;
465 }
466
467 static int bestdata_dialdigit(struct ast_modem_pvt *p, char digit)
468 {
469         char cmd[80];
470
471         if (p->ministate != STATE_COMMAND) bestdata_break(p);
472         snprintf(cmd, sizeof(cmd), "AT+VTS=%c", digit);
473         if (ast_modem_send(p, cmd, 0) ||
474              ast_modem_expect(p, "OK", 10)) {
475                 ast_log(LOG_WARNING, "Unable to answer: %s", p->response);
476                 return -1;
477         }
478         return 0;
479 }
480
481 static int bestdata_dial(struct ast_modem_pvt *p, char *stuff)
482 {
483         char cmd[800],a[20];
484         int i,j;
485
486         if (p->ministate != STATE_COMMAND)
487            {
488                 bestdata_break(p);
489                 strcpy(cmd,"AT+VTS=");
490                 j = strlen(cmd);
491                 for(i = 0; stuff[i]; i++)
492                    {
493                         switch(stuff[i])
494                            {
495                             case '!' :
496                                 a[0] = stuff[i];
497                                 a[1] = 0;
498                                 break;
499                             case ',':
500                                 strcpy(a,"[,,100]");
501                                 break;
502                             default:
503                                 sprintf(a,"{%c,7}",stuff[i]);
504                            }
505                         if (stuff[i + 1]) strcat(a,",");
506                         strcpy(cmd + j,a);
507                         j += strlen(a);
508                    }
509            }
510         else
511            {
512                 snprintf(cmd, sizeof(cmd), "ATD%c %s", p->dialtype,stuff);
513            }
514         if (ast_modem_send(p, cmd, 0)) {
515                 ast_log(LOG_WARNING, "Unable to dial\n");
516                 return -1;
517         }
518         return 0;
519 }
520
521 static int bestdata_hangup(struct ast_modem_pvt *p)
522 {
523         if (bestdata_break(p))
524                 return -1;
525         /* Hangup by switching to data, then back to voice */
526         if (ast_modem_send(p, "ATH", 0) ||
527              ast_modem_expect(p, "OK", 8)) {
528                 ast_log(LOG_WARNING, "Unable to set to data mode\n");
529                 return -1;
530         }
531         if (ast_modem_send(p, "AT+FCLASS=8", 0) ||
532              ast_modem_expect(p, "OK", 5)) {
533                 ast_log(LOG_WARNING, "Unable to set to voice mode\n");
534                 return -1;
535         }
536         p->gotclid = 0;
537         p->ringt = 0;
538         p->lastring = 0;
539         p->dtmfrx = 0;
540         return 0;
541 }
542
543 static struct ast_modem_driver bestdata_driver =
544 {
545         "BestData",
546         bestdata_idents,
547         AST_FORMAT_SLINEAR,
548         0,              /* Not full duplex */
549         bestdata_incusecnt,     /* incusecnt */
550         bestdata_decusecnt,     /* decusecnt */
551         bestdata_identify,      /* identify */
552         bestdata_init,  /* init */
553         NULL,   /* setdev */
554         bestdata_read,
555         bestdata_write,
556         bestdata_dial,  /* dial */
557         bestdata_answer,        /* answer */
558         bestdata_hangup,        /* hangup */
559         bestdata_startrec,      /* start record */
560         NULL,   /* stop record */
561         bestdata_startplay,     /* start playback */
562         NULL,   /* stop playback */
563         NULL,   /* set silence supression */
564         bestdata_dialdigit,     /* dialdigit */
565 };
566
567
568
569 int usecount(void)
570 {
571         int res;
572         ast_pthread_mutex_lock(&usecnt_lock);
573         res = usecnt;
574         ast_pthread_mutex_unlock(&usecnt_lock);
575         return res;
576 }
577
578 int load_module(void)
579 {
580         return ast_register_modem_driver(&bestdata_driver);
581 }
582
583 int unload_module(void)
584 {
585         return ast_unregister_modem_driver(&bestdata_driver);
586 }
587
588 char *description()
589 {
590         return desc;
591 }
592
593 char *key()
594 {
595         return ASTERISK_GPL_KEY;
596 }