00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
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"
00050 #define VRN "25"
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
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
00102 while(!ast_modem_read_response(p, 1));
00103 if (ast_modem_send(p, "AT", 0)) {
00104
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
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
00174
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':
00189 time(&now);
00190 if (now > (p->lastring + (RINGT / 1000)))
00191 {
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':
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 '@':
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':
00236 p->fr.frametype = AST_FRAME_CONTROL;
00237 p->fr.subclass = AST_CONTROL_BUSY;
00238 return &p->fr;
00239 case 'o':
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':
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;
00261 return &p->fr;
00262 case '/':
00263 p->dtmfrx = ' ';
00264 return &p->fr;
00265 case '~':
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':
00274 ast_log(LOG_WARNING, "Data underrun\n");
00275
00276 case CHAR_ETX:
00277 case 'd':
00278 case 'c':
00279 case 'e':
00280 case 'a':
00281 case 'f':
00282 case 'T':
00283 case 't':
00284 case 'h':
00285 case 0:
00286
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
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)
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
00319 fgets(result + 2, sizeof(result) - 2, p->f);
00320 ast_modem_trim(result);
00321 if (!strcasecmp(result, "OK")) {
00322
00323 if (p->mode == MODEM_MODE_IMMEDIATE)
00324 return bestdata_handle_escape(p, '@');
00325 } else
00326 if (!strcasecmp(result, "BUSY")) {
00327
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
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
00343 if (p->ministate == STATE_VOICEPLAY)
00344 {
00345 if (bestdata_startrec(p)) return NULL;
00346 }
00347
00348 b = (short *)(p->obuf + p->obuflen);
00349 while (p->obuflen/2 < 240) {
00350
00351 res = fread(result, 1, 240 - p->obuflen/2, p->f);
00352 if (res < 1) {
00353
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
00360 if (result[x] == CHAR_DLE) {
00361
00362
00363 if (f) ast_log(LOG_WARNING, "Warning: Dropped a signal frame\n");
00364
00365 if (result[++x] != CHAR_DLE)
00366 {
00367
00368
00369 f = bestdata_handle_escape(p, result[x]);
00370 if (p->dtmfrx) continue;
00371 return(f);
00372 }
00373 }
00374
00375
00376 *(b++) = (((short)result[x]) - 127) * 0xff;
00377 p->obuflen += 2;
00378 }
00379 if (f) break;
00380 }
00381
00382 if (f) return f;
00383
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];
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
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
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,
00570 bestdata_incusecnt,
00571 bestdata_decusecnt,
00572 bestdata_identify,
00573 bestdata_init,
00574 NULL,
00575 bestdata_read,
00576 bestdata_write,
00577 bestdata_dial,
00578 bestdata_answer,
00579 bestdata_hangup,
00580 bestdata_startrec,
00581 NULL,
00582 bestdata_startplay,
00583 NULL,
00584 NULL,
00585 bestdata_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 }