Mon Sep 18 09:13:00 2006

Asterisk developer's documentation


chan_modem_bestdata.c

Go to the documentation of this file.
00001 /*
00002  * Asterisk -- An open source telephony toolkit.
00003  *
00004  * Copyright (C) 1999, Mark Spencer and 2001 Jim Dixon
00005  *
00006  * Mark Spencer <markster@linux-support.net>
00007  * Jim Dixon <jim@lambdatel.com>
00008  *
00009  * See http://www.asterisk.org for more information about
00010  * the Asterisk project. Please do not directly contact
00011  * any of the maintainers of this project for assistance;
00012  * the project provides a web site, mailing lists and IRC
00013  * channels for your use.
00014  *
00015  * This program is free software, distributed under the terms of
00016  * the GNU General Public License Version 2. See the LICENSE file
00017  * at the top of the source tree.
00018  */
00019 
00020 /*
00021  *
00022  * BestData 56SX-92 Voice Modem Driver (Conexant)
00023  * 
00024  * \ingroup channel_drivers
00025  */
00026 
00027 #include <stdio.h>
00028 
00029 #include <string.h>
00030 #include <stdlib.h>
00031 #include <errno.h>
00032 #include <unistd.h>
00033 
00034 #include "asterisk.h"
00035 
00036 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 7221 $")
00037 
00038 #include "asterisk/lock.h"
00039 #include "asterisk/vmodem.h"
00040 #include "asterisk/module.h"
00041 #include "asterisk/frame.h"
00042 #include "asterisk/logger.h"
00043 #include "asterisk/options.h"
00044 
00045 #define STATE_COMMAND   0
00046 #define STATE_VOICE  1
00047 #define  STATE_VOICEPLAY   2
00048 
00049 #define VRA "40"        /* Number of 100ms of non-ring after a ring cadence after which we consider the lien to be answered */
00050 #define VRN "25"        /* Number of 100ms of non-ring with no cadence after which we assume an answer */
00051 
00052 #define  RINGT 7000
00053 
00054 static char *breakcmd = "\020!";
00055 
00056 static char *desc = "BestData (Conexant V.90 Chipset) VoiceModem Driver";
00057 
00058 static int usecnt;
00059 AST_MUTEX_DEFINE_STATIC(usecnt_lock);
00060 
00061 static char *bestdata_idents[] = {
00062    /* Identify BestData Modem */
00063    "ACF3_V1.010-V90_P21_FSH",
00064    NULL
00065 };
00066 
00067 static int bestdata_break(struct ast_modem_pvt *p);
00068 
00069 static int bestdata_startrec(struct ast_modem_pvt *p)
00070 {
00071    if (p->ministate != STATE_COMMAND) bestdata_break(p);
00072    if (ast_modem_send(p, "AT+VRX", 0) ||
00073         ast_modem_expect(p, "CONNECT", 5)) {
00074       ast_log(LOG_WARNING, "Unable to start recording\n");
00075       return -1;
00076    }
00077    p->ministate = STATE_VOICE;
00078    return 0;
00079 }
00080 
00081 static int bestdata_startplay(struct ast_modem_pvt *p)
00082 {
00083    if (p->ministate != STATE_COMMAND) bestdata_break(p);
00084    if (ast_modem_send(p, "AT+VTX", 0) ||
00085         ast_modem_expect(p, "CONNECT", 5)) {
00086       ast_log(LOG_WARNING, "Unable to start recording\n");
00087       return -1;
00088    }
00089    p->ministate = STATE_VOICEPLAY;
00090    return 0;
00091 }
00092 
00093 static int bestdata_break(struct ast_modem_pvt *p)
00094 {
00095    if (ast_modem_send(p, breakcmd, 2)) {
00096       ast_log(LOG_WARNING, "Failed to break\n");
00097       return -1;
00098    }
00099    p->ministate = STATE_COMMAND;
00100    usleep(10000);
00101    /* Read any outstanding junk */
00102    while(!ast_modem_read_response(p, 1));
00103    if (ast_modem_send(p, "AT", 0)) {
00104       /* Modem might be stuck in some weird mode, try to get it out */
00105       ast_modem_send(p, "+++", 3);
00106       if (ast_modem_expect(p, "OK", 10)) {
00107          ast_log(LOG_WARNING, "Modem is not responding\n");
00108          return -1;
00109       }
00110       if (ast_modem_send(p, "AT", 0)) {
00111          ast_log(LOG_WARNING, "Modem is not responding\n");
00112          return -1;
00113       }
00114    }
00115    if (ast_modem_expect(p, "OK", 5)) {
00116       ast_log(LOG_WARNING, "Modem did not respond properly\n");
00117       return -1;
00118    }
00119    return 0;
00120 }
00121 
00122 static int bestdata_init(struct ast_modem_pvt *p)
00123 {
00124    if (option_debug)
00125       ast_log(LOG_DEBUG, "bestdata_init()\n");
00126    if (bestdata_break(p))
00127       return -1;
00128    /* Force into command mode */
00129    p->ministate = STATE_COMMAND;
00130    if (ast_modem_send(p, "AT+FCLASS=8", 0) ||
00131         ast_modem_expect(p, "OK", 5)) {
00132       ast_log(LOG_WARNING, "Unable to set to voice mode\n");
00133       return -1;
00134    }
00135    if (ast_modem_send(p, "AT+VSM=1,8000,0,0", 0) ||
00136         ast_modem_expect(p, "OK", 5)) {
00137       ast_log(LOG_WARNING, "Unable to set to 8000 Hz sampling\n");
00138       return -1;
00139    }
00140    if (ast_modem_send(p, "AT+VLS=0", 0) ||
00141         ast_modem_expect(p, "OK", 5)) {
00142       ast_log(LOG_WARNING, "Unable to set to telco interface\n");
00143       return -1;
00144    }
00145    if (ast_modem_send(p, "AT+VRA=" VRA, 0) ||
00146         ast_modem_expect(p, "OK", 5)) {
00147       ast_log(LOG_WARNING, "Unable to set to 'ringback goes away' timer\n");
00148       return -1;
00149    }
00150    if (ast_modem_send(p, "AT+VRN=" VRN, 0) ||
00151         ast_modem_expect(p, "OK", 5)) {
00152       ast_log(LOG_WARNING, "Unable to set to 'ringback never came timer'\n");
00153       return -1;
00154    }
00155    if (ast_modem_send(p, "AT+VTD=63", 0) ||
00156         ast_modem_expect(p, "OK", 5)) {
00157       ast_log(LOG_WARNING, "Unable to set to tone detection\n");
00158       return -1;
00159    }
00160    if (ast_modem_send(p, "AT+VCID=1", 0) ||
00161         ast_modem_expect(p, "OK", 5)) {
00162       ast_log(LOG_WARNING, "Unable to enable Caller*ID\n");
00163       return -1;
00164    }
00165    return 0;
00166 }
00167 
00168 static struct ast_frame *bestdata_handle_escape(struct ast_modem_pvt *p, char esc)
00169 {
00170    char name[30]="",nmbr[30]="";
00171    time_t   now;
00172 
00173    /* Handle escaped characters -- but sometimes we call it directly as 
00174       a quick way to cause known responses */
00175    p->fr.frametype = AST_FRAME_NULL;
00176    p->fr.subclass = 0;
00177    p->fr.data = NULL;
00178    p->fr.datalen = 0;
00179    p->fr.samples = 0;
00180    p->fr.offset = 0;
00181    p->fr.mallocd = 0;
00182    p->fr.delivery.tv_sec = 0;
00183    p->fr.delivery.tv_usec = 0;
00184    if (esc)
00185       ast_log(LOG_DEBUG, "Escaped character '%c'\n", esc);
00186    
00187    switch(esc) {
00188    case 'R': /* Pseudo ring */
00189       time(&now);
00190       if (now > (p->lastring + (RINGT / 1000)))
00191          { /* if stale, treat as new */
00192          p->gotclid = 0;
00193          }
00194       if (p->gotclid)
00195          {
00196          p->fr.frametype = AST_FRAME_CONTROL;
00197          p->fr.subclass = AST_CONTROL_RING;
00198          }
00199       p->ringt = RINGT;
00200       time(&p->lastring);
00201       return &p->fr;
00202    case 'X': /* Caller-ID Spill */
00203       if (p->gotclid) return &p->fr;
00204       name[0] = nmbr[0] = 0;
00205       for(;;)
00206          {
00207          char res[1000]="";
00208 
00209          if (ast_modem_read_response(p, 5)) break;
00210          strncpy(res, p->response, sizeof(res)-1);
00211          ast_modem_trim(res);
00212          if (!strncmp(res,"\020.",2)) break;
00213          if (!strncmp(res,"NAME",4)) strncpy(name,res + 7, sizeof(name) - 1);
00214          if (!strncmp(res,"NMBR",4)) strncpy(nmbr,res + 7, sizeof(nmbr) - 1);
00215          }
00216       p->gotclid = 1;
00217       if ((!strcmp(name,"O")) || (!strcmp(name,"P"))) name[0] = 0;
00218       if ((!strcmp(nmbr,"O")) || (!strcmp(nmbr,"P"))) nmbr[0] = 0;
00219       if (name[0])
00220          strncpy(p->cid_name, name, sizeof(p->cid_name) - 1);
00221       if (nmbr[0])
00222          strncpy(p->cid_num, nmbr, sizeof(p->cid_num) - 1);
00223       if (p->owner) {
00224          p->owner->cid.cid_num = strdup(p->cid_num);
00225          p->owner->cid.cid_name = strdup(p->cid_name);
00226       }
00227       return &p->fr;
00228    case '@': /* response from "OK" in command mode */
00229       if (p->owner)
00230          ast_setstate(p->owner, AST_STATE_UP);
00231       if (bestdata_startrec(p)) return NULL;
00232       p->fr.frametype = AST_FRAME_CONTROL;
00233       p->fr.subclass = AST_CONTROL_RING;
00234       return &p->fr;
00235    case 'b': /* Busy signal */
00236       p->fr.frametype = AST_FRAME_CONTROL;
00237       p->fr.subclass = AST_CONTROL_BUSY;
00238       return &p->fr;
00239    case 'o': /* Overrun */
00240       ast_log(LOG_WARNING, "Overflow on modem, flushing buffers\n");
00241       if (ast_modem_send(p, "\0x10E", 2)) 
00242          ast_log(LOG_WARNING, "Unable to flush buffers\n");
00243       return &p->fr; 
00244    case '0':  /* All the DTMF characters */
00245    case '1':
00246    case '2':
00247    case '3':
00248    case '4':
00249    case '5':
00250    case '6':
00251    case '7':
00252    case '8':
00253    case '9':
00254    case '*':
00255    case '#':
00256    case 'A':
00257    case 'B':
00258    case 'C':
00259    case 'D':
00260       p->dtmfrx = esc;  /* save this for when its done */
00261       return &p->fr; 
00262    case '/': /* Start of DTMF tone shielding */
00263       p->dtmfrx = ' ';
00264       return &p->fr; 
00265    case '~': /* DTMF transition to off */
00266       if (p->dtmfrx > ' ')
00267          {
00268          p->fr.frametype = AST_FRAME_DTMF;
00269          p->fr.subclass = p->dtmfrx;
00270          }
00271       p->dtmfrx = 0;
00272       return &p->fr; 
00273    case 'u': /* Underrun */
00274       ast_log(LOG_WARNING, "Data underrun\n");
00275       /* Fall Through */
00276    case CHAR_ETX: /* End Transmission */
00277    case 'd': /* Dialtone */
00278    case 'c': /* Calling Tone */
00279    case 'e': /* European version */
00280    case 'a': /* Answer Tone */
00281    case 'f': /* Bell Answer Tone */
00282    case 'T': /* Timing mark */
00283    case 't': /* Handset off hook */
00284    case 'h': /* Handset hungup */
00285    case 0: /* Pseudo signal */
00286       /* Ignore */
00287       return &p->fr; 
00288    default:
00289       ast_log(LOG_DEBUG, "Unknown Escaped character '%c' (%d)\n", esc, esc);
00290    }
00291    return &p->fr;
00292 }
00293 
00294 static struct ast_frame *bestdata_read(struct ast_modem_pvt *p)
00295 {
00296    char result[256];
00297    short *b;
00298    struct ast_frame *f=NULL;
00299    int res;
00300    int x;
00301 
00302    if (p->ministate == STATE_COMMAND) {
00303       /* Read the first two bytes, first, in case it's a control message */
00304       fread(result, 1, 2, p->f);
00305       if (result[0] == CHAR_DLE) {
00306          return bestdata_handle_escape(p, result[1]);
00307       } else {
00308          if (p->ringt) /* if ring timeout specified */
00309             {
00310             x = fileno(p->f);
00311             res = ast_waitfor_n_fd(&x, 1, &p->ringt, NULL);
00312             if (res < 0) {
00313                return NULL;
00314             }
00315             }
00316          if ((result[0] == '\n') || (result[0] == '\r'))
00317             return bestdata_handle_escape(p, 0);
00318          /* Read the rest of the line */
00319          fgets(result + 2, sizeof(result) - 2, p->f);
00320          ast_modem_trim(result);
00321          if (!strcasecmp(result, "OK")) {
00322             /* If we're in immediate mode, reply now */
00323             if (p->mode == MODEM_MODE_IMMEDIATE)
00324                return bestdata_handle_escape(p, '@');
00325          } else
00326          if (!strcasecmp(result, "BUSY")) {
00327             /* Same as a busy signal */
00328             return bestdata_handle_escape(p, 'b');
00329          } else
00330          if (!strcasecmp(result, "RING")) {
00331             return bestdata_handle_escape(p, 'R');
00332          } else
00333          if (!strcasecmp(result, "NO DIALTONE")) {
00334             /* There's no dialtone, so the line isn't working */
00335             ast_log(LOG_WARNING, "Device '%s' lacking dialtone\n", p->dev);
00336             return NULL;
00337          }
00338          ast_log(LOG_DEBUG, "Modem said '%s'\n", result);
00339          return bestdata_handle_escape(p, 0);
00340       }
00341    } else {
00342         /* if playing, start recording instead */
00343       if (p->ministate == STATE_VOICEPLAY)
00344          {
00345          if (bestdata_startrec(p)) return NULL;
00346          }
00347       /* We have to be more efficient in voice mode */
00348       b = (short *)(p->obuf + p->obuflen);
00349       while (p->obuflen/2 < 240) {
00350          /* Read ahead the full amount */
00351          res = fread(result, 1, 240 - p->obuflen/2, p->f);
00352          if (res < 1) {
00353             /* If there's nothing there, just continue on */
00354             if (errno == EAGAIN)
00355                return bestdata_handle_escape(p, 0);
00356             ast_log(LOG_WARNING, "Read failed: %s\n", strerror(errno));
00357          }
00358          for (x=0;x<res;x++) {
00359             /* Process all the bytes that we've read */
00360             if (result[x] == CHAR_DLE) {
00361                /* We assume there is no more than one signal frame among our
00362                   data.  */
00363                if (f) ast_log(LOG_WARNING, "Warning: Dropped a signal frame\n");
00364                  /* if not a DLE in the data */
00365                if (result[++x] != CHAR_DLE)
00366                   {
00367                   /* If bestdata_handle_escape says NULL, say it now, doesn't matter
00368                      what else is there, the connection is dead. */
00369                   f = bestdata_handle_escape(p, result[x]);
00370                   if (p->dtmfrx) continue;
00371                   return(f);
00372                   }
00373             }
00374             /* Generate a 16-bit signed linear value from our 
00375                unsigned 8-bit value */
00376             *(b++) = (((short)result[x]) - 127) * 0xff;
00377             p->obuflen += 2;
00378          }
00379          if (f) break;
00380       }
00381       /* If we have a control frame, return it now */
00382       if (f) return f;
00383       /* If we get here, we have a complete voice frame */
00384       p->fr.frametype = AST_FRAME_VOICE;
00385       p->fr.subclass = AST_FORMAT_SLINEAR;
00386       p->fr.samples = 240;
00387       p->fr.data = p->obuf;
00388       p->fr.datalen = p->obuflen;
00389       p->fr.mallocd = 0;
00390       p->fr.delivery.tv_sec = 0;
00391       p->fr.delivery.tv_usec = 0;
00392       p->fr.offset = AST_FRIENDLY_OFFSET;
00393       p->fr.src = __FUNCTION__;
00394       if (option_debug)
00395          ast_log(LOG_DEBUG, "bestdata_read(voice frame)\n");
00396       p->obuflen = 0;
00397       return &p->fr;
00398    }
00399    return NULL;
00400 }
00401 
00402 static int bestdata_write(struct ast_modem_pvt *p, struct ast_frame *f)
00403 {
00404 unsigned char  c,buf[32768]; /* I hope we dont have frames larger then 16K */
00405 int   i,j;
00406 short *sp;
00407 unsigned long u;
00408 #define  DLE   16
00409 
00410    if (p->owner && (p->owner->_state == AST_STATE_UP) && 
00411       (p->ministate != STATE_VOICEPLAY) && bestdata_startplay(p)) return -1;
00412    sp = (short *) f->data;
00413      /* stick DLE's in ahead of anything else */
00414    for(i = 0,j = 0; i < f->datalen / 2; i++)
00415       {
00416       *sp *= 3;
00417       u = *sp++ + 32768;
00418       c = u >> 8;
00419       if (c == DLE) buf[j++] = DLE;
00420       buf[j++] = c;
00421       }
00422    do i = fwrite(buf,1,j,p->f);
00423    while ((i == -1) && (errno == EWOULDBLOCK));
00424    if (i != j)
00425       {
00426       ast_log(LOG_WARNING,"modem short write!!\n");
00427       return -1;
00428       }
00429    fflush(p->f);
00430    if (option_debug)
00431       ast_log(LOG_DEBUG, "bestdata_write()\n");
00432    return 0;
00433 }
00434 
00435 static char *bestdata_identify(struct ast_modem_pvt *p)
00436 {
00437    char identity[256];
00438    char mfr[80];
00439    char mdl[80];
00440    char rev[80];
00441    ast_modem_send(p, "AT+FMM", 0);
00442    ast_modem_read_response(p, 5);
00443    strncpy(mdl, p->response, sizeof(mdl)-1);
00444    ast_modem_trim(mdl);
00445    ast_modem_expect(p, "OK", 5);
00446    ast_modem_send(p, "AT+FMI", 0);
00447    ast_modem_read_response(p, 5);
00448    strncpy(mfr, p->response, sizeof(mfr)-1);
00449    ast_modem_trim(mfr);
00450    ast_modem_expect(p, "OK", 5);
00451    ast_modem_send(p, "AT+FMR", 0);
00452    ast_modem_read_response(p, 5);
00453    strncpy(rev, p->response, sizeof(rev)-1);
00454    ast_modem_trim(rev);
00455    ast_modem_expect(p, "OK", 5);
00456    snprintf(identity, sizeof(identity), "%s Model %s Revision %s", mfr, mdl, rev);
00457    return strdup(identity);
00458 }
00459 
00460 static void bestdata_incusecnt(void)
00461 {
00462    ast_mutex_lock(&usecnt_lock);
00463    usecnt++;
00464    ast_mutex_unlock(&usecnt_lock);
00465    ast_update_use_count();
00466 }
00467 
00468 static void bestdata_decusecnt(void)
00469 {
00470    ast_mutex_lock(&usecnt_lock);
00471    usecnt++;
00472    ast_mutex_unlock(&usecnt_lock);
00473    ast_update_use_count();
00474 }
00475 
00476 static int bestdata_answer(struct ast_modem_pvt *p)
00477 {
00478    p->ringt = 0;
00479    p->lastring = 0;
00480    if (ast_modem_send(p, "AT+VLS=1", 0) ||
00481         ast_modem_expect(p, "OK", 10)) {
00482       ast_log(LOG_WARNING, "Unable to answer: %s", p->response);
00483       return -1;
00484    }
00485    return 0;
00486 }
00487 
00488 static int bestdata_dialdigit(struct ast_modem_pvt *p, char digit)
00489 {
00490    char cmd[80];
00491 
00492    if (p->ministate != STATE_COMMAND) bestdata_break(p);
00493    snprintf(cmd, sizeof(cmd), "AT+VTS=%c", digit);
00494    if (ast_modem_send(p, cmd, 0) ||
00495         ast_modem_expect(p, "OK", 10)) {
00496       ast_log(LOG_WARNING, "Unable to answer: %s", p->response);
00497       return -1;
00498    }
00499    return 0;
00500 }
00501 
00502 static int bestdata_dial(struct ast_modem_pvt *p, char *stuff)
00503 {
00504    char cmd[800] = "",a[20]="";
00505    int i,j;
00506 
00507    if (p->ministate != STATE_COMMAND)
00508       {
00509       bestdata_break(p);
00510       strncpy(cmd, "AT+VTS=", sizeof(cmd) - 1);
00511       j = strlen(cmd);
00512       for(i = 0; stuff[i]; i++)
00513          {
00514          switch(stuff[i])
00515             {
00516              case '!' :
00517             a[0] = stuff[i];
00518             a[1] = 0;
00519             break;
00520              case ',':
00521             strncpy(a, "[,,100]", sizeof(a) - 1);
00522             break;
00523              default:
00524             snprintf(a, sizeof(a), "{%c,7}", stuff[i]);
00525             }
00526          if (stuff[i + 1]) strncat(a, ",", sizeof(a) - strlen(a) - 1);
00527          strncpy(cmd + j, a, sizeof(cmd) - j - 1);
00528          j += strlen(a);
00529          }
00530       }
00531    else
00532       {
00533       snprintf(cmd, sizeof(cmd), "ATD%c %s", p->dialtype,stuff);
00534       }
00535    if (ast_modem_send(p, cmd, 0)) {
00536       ast_log(LOG_WARNING, "Unable to dial\n");
00537       return -1;
00538    }
00539    return 0;
00540 }
00541 
00542 static int bestdata_hangup(struct ast_modem_pvt *p)
00543 {
00544    if (bestdata_break(p))
00545       return -1;
00546    /* Hangup by switching to data, then back to voice */
00547    if (ast_modem_send(p, "ATH", 0) ||
00548         ast_modem_expect(p, "OK", 8)) {
00549       ast_log(LOG_WARNING, "Unable to set to data mode\n");
00550       return -1;
00551    }
00552    if (ast_modem_send(p, "AT+FCLASS=8", 0) ||
00553         ast_modem_expect(p, "OK", 5)) {
00554       ast_log(LOG_WARNING, "Unable to set to voice mode\n");
00555       return -1;
00556    }
00557    p->gotclid = 0;
00558    p->ringt = 0;
00559    p->lastring = 0;
00560    p->dtmfrx = 0;
00561    return 0;
00562 }
00563 
00564 static struct ast_modem_driver bestdata_driver =
00565 {
00566    "BestData",
00567    bestdata_idents,
00568    AST_FORMAT_SLINEAR,
00569    0,    /* Not full duplex */
00570    bestdata_incusecnt,  /* incusecnt */
00571    bestdata_decusecnt,  /* decusecnt */
00572    bestdata_identify,   /* identify */
00573    bestdata_init, /* init */
00574    NULL, /* setdev */
00575    bestdata_read,
00576    bestdata_write,
00577    bestdata_dial, /* dial */
00578    bestdata_answer,  /* answer */
00579    bestdata_hangup,  /* hangup */
00580    bestdata_startrec,   /* start record */
00581    NULL, /* stop record */
00582    bestdata_startplay,  /* start playback */
00583    NULL, /* stop playback */
00584    NULL, /* set silence supression */
00585    bestdata_dialdigit,  /* dialdigit */
00586 };
00587 
00588 
00589 
00590 int usecount(void)
00591 {
00592    return usecnt;
00593 }
00594 
00595 int load_module(void)
00596 {
00597    return ast_register_modem_driver(&bestdata_driver);
00598 }
00599 
00600 int unload_module(void)
00601 {
00602    return ast_unregister_modem_driver(&bestdata_driver);
00603 }
00604 
00605 char *description()
00606 {
00607    return desc;
00608 }
00609 
00610 char *key()
00611 {
00612    return ASTERISK_GPL_KEY;
00613 }

Generated on Mon Sep 18 09:13:00 2006 for Asterisk - the Open Source PBX by  doxygen 1.4.7