Sat Sep 16 07:28:14 2006

Asterisk developer's documentation


chan_modem_i4l.c File Reference

ISDN4Linux TTY Driver. More...

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include "asterisk.h"
#include "asterisk/lock.h"
#include "asterisk/vmodem.h"
#include "asterisk/module.h"
#include "asterisk/frame.h"
#include "asterisk/logger.h"
#include "asterisk/options.h"
#include "asterisk/dsp.h"
#include "asterisk/callerid.h"
#include "asterisk/ulaw.h"
#include "asterisk/pbx.h"
#include "asterisk/utils.h"

Go to the source code of this file.

Defines

#define MAX_WRITE_SIZE   2048
#define STATE_COMMAND   0
#define STATE_VOICE   1

Functions

 AST_MUTEX_DEFINE_STATIC (usecnt_lock)
char * description ()
 Provides a description of the module.
static int i4l_answer (struct ast_modem_pvt *p)
static int i4l_break (struct ast_modem_pvt *p)
static void i4l_decusecnt (void)
static int i4l_dial (struct ast_modem_pvt *p, char *stuff)
static int i4l_dialdigit (struct ast_modem_pvt *p, char digit)
static struct ast_framei4l_handle_escape (struct ast_modem_pvt *p, char esc)
static int i4l_hangup (struct ast_modem_pvt *p)
static char * i4l_identify (struct ast_modem_pvt *p)
static void i4l_incusecnt (void)
static int i4l_init (struct ast_modem_pvt *p)
static struct ast_framei4l_read (struct ast_modem_pvt *p)
static int i4l_setdev (struct ast_modem_pvt *p, int dev)
static int i4l_startrec (struct ast_modem_pvt *p)
static int i4l_write (struct ast_modem_pvt *p, struct ast_frame *f)
char * key ()
 Returns the ASTERISK_GPL_KEY.
int load_module (void)
 Initialize the module.
int unload_module (void)
 Cleanup all module structures, sockets, etc.
int usecount (void)
 Provides a usecount.

Variables

static char * breakcmd = "\0x10\0x14\0x10\0x3"
static char * desc = "ISDN4Linux Emulated Modem Driver"
static struct ast_modem_driver i4l_driver
static char * i4l_idents []
static int usecnt


Detailed Description

ISDN4Linux TTY Driver.

Definition in file chan_modem_i4l.c.


Define Documentation

#define MAX_WRITE_SIZE   2048

Referenced by i4l_write().

#define STATE_COMMAND   0

Definition at line 50 of file chan_modem_i4l.c.

#define STATE_VOICE   1

Definition at line 51 of file chan_modem_i4l.c.


Function Documentation

AST_MUTEX_DEFINE_STATIC ( usecnt_lock   ) 

char* description ( void   ) 

Provides a description of the module.

Returns:
a short description of your module

Definition at line 735 of file chan_modem_i4l.c.

00736 {
00737    return desc;
00738 }

static int i4l_answer ( struct ast_modem_pvt p  )  [static]

Definition at line 571 of file chan_modem_i4l.c.

References ast_dsp_digitmode(), ast_dsp_new(), ast_dsp_set_features(), ast_log(), ast_modem_expect(), ast_modem_send(), ast_modem_pvt::dev, ast_modem_pvt::dsp, DSP_DIGITMODE_DTMF, DSP_FEATURE_DTMF_DETECT, DSP_FEATURE_FAX_DETECT, ast_modem_pvt::dtmfmode, LOG_DEBUG, LOG_WARNING, ast_modem_pvt::ministate, MODEM_DTMF_AST, ast_modem_pvt::response, and STATE_VOICE.

00572 {
00573    if (ast_modem_send(p, "ATA\r", 4) ||
00574         ast_modem_expect(p, "VCON", 10)) {
00575       ast_log(LOG_WARNING, "Unable to answer: %s", p->response);
00576       return -1;
00577    }
00578 #if 1
00579    if (ast_modem_send(p, "AT+VDD=0,8", 0) ||
00580         ast_modem_expect(p, "OK", 5)) {
00581       ast_log(LOG_WARNING, "Unable to set to phone line interface\n");
00582       return -1;
00583    }
00584 #endif
00585    if (ast_modem_send(p, "AT+VTX+VRX", 0) ||
00586         ast_modem_expect(p, "CONNECT", 10)) {
00587       ast_log(LOG_WARNING, "Unable to answer: %s", p->response);
00588       return -1;
00589    }
00590    p->ministate = STATE_VOICE;
00591 
00592    /*  let ast dsp detect dtmf */
00593    if (p->dtmfmode & MODEM_DTMF_AST) {
00594       if (p->dsp) {
00595          ast_log(LOG_DEBUG, "Already have a dsp on %s?\n", p->dev);
00596       } else {
00597          p->dsp = ast_dsp_new();
00598          if (p->dsp) {
00599             ast_log(LOG_DEBUG, "Detecting DTMF inband with sw DSP on %s\n",p->dev);
00600             ast_dsp_set_features(p->dsp, DSP_FEATURE_DTMF_DETECT|DSP_FEATURE_FAX_DETECT);
00601             ast_dsp_digitmode(p->dsp, DSP_DIGITMODE_DTMF | 0);
00602          }
00603       }
00604    }
00605 
00606    return 0;
00607 }

static int i4l_break ( struct ast_modem_pvt p  )  [static]

Definition at line 136 of file chan_modem_i4l.c.

References ast_log(), ast_modem_expect(), ast_modem_read_response(), ast_modem_send(), and LOG_WARNING.

Referenced by i4l_init().

00137 {
00138    if (ast_modem_send(p, breakcmd, 2)) {
00139       ast_log(LOG_WARNING, "Failed to break\n");
00140       return -1;
00141    }
00142    if (ast_modem_send(p, "\r\n", 2)) {
00143       ast_log(LOG_WARNING, "Failed to send enter?\n");
00144       return -1;
00145    }
00146 #if 0
00147    /* Read any outstanding junk */
00148    while(!ast_modem_read_response(p, 1));
00149 #endif
00150    if (ast_modem_send(p, "AT", 0)) {
00151       /* Modem might be stuck in some weird mode, try to get it out */
00152       ast_modem_send(p, "+++", 3);
00153       if (ast_modem_expect(p, "OK", 10)) {
00154          ast_log(LOG_WARNING, "Modem is not responding\n");
00155          return -1;
00156       }
00157       if (ast_modem_send(p, "AT", 0)) {
00158          ast_log(LOG_WARNING, "Modem is not responding\n");
00159          return -1;
00160       }
00161    }
00162    if (ast_modem_expect(p, "OK", 5)) {
00163       ast_log(LOG_WARNING, "Modem did not respond properly\n");
00164       return -1;
00165    }
00166    return 0;
00167 }

static void i4l_decusecnt ( void   )  [static]

Definition at line 563 of file chan_modem_i4l.c.

References ast_mutex_lock(), ast_mutex_unlock(), ast_update_use_count(), and usecnt_lock.

00564 {
00565    ast_mutex_lock(&usecnt_lock);
00566    usecnt++;
00567    ast_mutex_unlock(&usecnt_lock);
00568    ast_update_use_count();
00569 }

static int i4l_dial ( struct ast_modem_pvt p,
char *  stuff 
) [static]

Definition at line 628 of file chan_modem_i4l.c.

References ast_log(), ast_modem_send(), ast_strlen_zero(), ast_channel::cid, ast_callerid::cid_num, ast_callerid::cid_pres, ast_modem_pvt::dialtype, LOG_WARNING, ast_modem_pvt::outgoingmsn, and ast_modem_pvt::owner.

00629 {
00630    char cmd[80];
00631    char tmpmsn[255];
00632    struct ast_channel *c = p->owner;
00633 
00634    /* Find callerid number first, to set the correct A number */
00635    if (c && c->cid.cid_num && !(c->cid.cid_pres & 0x20)) {
00636        snprintf(tmpmsn, sizeof(tmpmsn), ",%s,", c->cid.cid_num);
00637        if(!ast_strlen_zero(p->outgoingmsn) && strstr(p->outgoingmsn,tmpmsn) != NULL) {
00638          /* Tell ISDN4Linux to use this as A number */
00639          snprintf(cmd, sizeof(cmd), "AT&E%s\n", c->cid.cid_num);
00640          if (ast_modem_send(p, cmd, strlen(cmd))) {
00641       ast_log(LOG_WARNING, "Unable to set A number to %s\n", c->cid.cid_num);
00642          }
00643 
00644        } else {
00645          ast_log(LOG_WARNING, "Outgoing MSN %s not allowed (see outgoingmsn=%s in modem.conf)\n",c->cid.cid_num,p->outgoingmsn);
00646        }
00647    }
00648 
00649    snprintf(cmd, sizeof(cmd), "ATD%c %s\n", p->dialtype,stuff);
00650    if (ast_modem_send(p, cmd, strlen(cmd))) {
00651       ast_log(LOG_WARNING, "Unable to dial\n");
00652       return -1;
00653    }
00654    return 0;
00655 }

static int i4l_dialdigit ( struct ast_modem_pvt p,
char  digit 
) [static]

Definition at line 609 of file chan_modem_i4l.c.

References ast_log(), CHAR_DLE, ast_modem_pvt::dev, ast_modem_pvt::dtmfmodegen, ast_modem_pvt::fd, LOG_DEBUG, ast_modem_pvt::ministate, MODEM_DTMF_AST, MODEM_DTMF_I4L, and STATE_VOICE.

00610 {
00611    char c[2];
00612    if (p->ministate == STATE_VOICE) {
00613       if (p->dtmfmodegen & MODEM_DTMF_I4L) {
00614       c[0] = CHAR_DLE;
00615       c[1] = digit;
00616       write(p->fd, c, 2);
00617          ast_log(LOG_DEBUG, "Send ISDN out-of-band DTMF %c\n",digit);
00618       }
00619       if(p->dtmfmodegen & MODEM_DTMF_AST) {
00620          ast_log(LOG_DEBUG, "Generating inband DTMF\n");
00621          return -1;
00622       }
00623    } else
00624       ast_log(LOG_DEBUG, "Asked to send digit but call not up on %s\n", p->dev);
00625    return 0;
00626 }

static struct ast_frame* i4l_handle_escape ( struct ast_modem_pvt p,
char  esc 
) [static]

Definition at line 247 of file chan_modem_i4l.c.

References AST_CONTROL_ANSWER, AST_CONTROL_BUSY, AST_CONTROL_RING, AST_CONTROL_RINGING, AST_FRAME_CONTROL, AST_FRAME_DTMF, AST_FRAME_NULL, ast_log(), ast_modem_send(), ast_setstate(), AST_STATE_UP, CHAR_ETX, ast_frame::data, ast_frame::datalen, ast_frame::delivery, ast_modem_pvt::fr, ast_frame::frametype, i4l_startrec(), LOG_DEBUG, LOG_WARNING, ast_frame::mallocd, ast_frame::offset, option_debug, ast_modem_pvt::owner, ast_frame::samples, and ast_frame::subclass.

Referenced by i4l_read().

00248 {
00249    /* Handle escaped characters -- but sometimes we call it directly as 
00250       a quick way to cause known responses */
00251    p->fr.frametype = AST_FRAME_NULL;
00252    p->fr.subclass = 0;
00253    p->fr.data = NULL;
00254    p->fr.datalen = 0;
00255    p->fr.samples = 0;
00256    p->fr.offset = 0;
00257    p->fr.mallocd = 0;
00258    p->fr.delivery.tv_sec = 0;
00259    p->fr.delivery.tv_usec = 0;
00260    if (esc && option_debug)
00261       ast_log(LOG_DEBUG, "Escaped character '%c'\n", esc);
00262    
00263    switch(esc) {
00264    case 'R': /* Pseudo ring */
00265       p->fr.frametype = AST_FRAME_CONTROL;
00266       p->fr.subclass = AST_CONTROL_RING;
00267       return &p->fr;
00268    case 'I': /* Pseudo ringing */
00269       p->fr.frametype = AST_FRAME_CONTROL;
00270       p->fr.subclass =  AST_CONTROL_RINGING;
00271       return &p->fr;
00272    case 'X': /* Pseudo connect */
00273       p->fr.frametype = AST_FRAME_CONTROL;
00274       p->fr.subclass = AST_CONTROL_ANSWER;
00275       if (p->owner)
00276          ast_setstate(p->owner, AST_STATE_UP);
00277       if (i4l_startrec(p))
00278          return   NULL;
00279       return &p->fr;
00280    case 'b': /* Busy signal */
00281       p->fr.frametype = AST_FRAME_CONTROL;
00282       p->fr.subclass = AST_CONTROL_BUSY;
00283       return &p->fr;
00284    case 'o': /* Overrun */
00285       ast_log(LOG_WARNING, "Overflow on modem, flushing buffers\n");
00286       if (ast_modem_send(p, "\0x10E", 2)) 
00287          ast_log(LOG_WARNING, "Unable to flush buffers\n");
00288       return &p->fr; 
00289    case CHAR_ETX: /* End Transmission */
00290       return NULL;
00291    case 'u': /* Underrun */
00292       ast_log(LOG_WARNING, "Data underrun\n");
00293       /* Fall Through */
00294    case 'd': /* Dialtone */
00295    case 'c': /* Calling Tone */
00296    case 'e': /* European version */
00297    case 'a': /* Answer Tone */
00298    case 'f': /* Bell Answer Tone */
00299    case 'T': /* Timing mark */
00300    case 't': /* Handset off hook */
00301    case 'h': /* Handset hungup */
00302       /* Ignore */
00303       if (option_debug)
00304          ast_log(LOG_DEBUG, "Ignoring Escaped character '%c' (%d)\n", esc, esc);
00305       return &p->fr;
00306    case '0':
00307    case '1':
00308    case '2':
00309    case '3':
00310    case '4':
00311    case '5':
00312    case '6':
00313    case '7':
00314    case '8':
00315    case '9':
00316    case '*':
00317    case '#':
00318       ast_log(LOG_DEBUG, "Detected outband DTMF digit: '%c' (%d)\n", esc, esc);
00319       p->fr.frametype=AST_FRAME_DTMF;
00320       p->fr.subclass=esc;
00321       return &p->fr;
00322    case 0: /* Pseudo signal */
00323       return &p->fr;
00324    default:
00325       ast_log(LOG_DEBUG, "Unknown Escaped character '%c' (%d)\n", esc, esc);
00326    }
00327    return &p->fr;
00328 }

static int i4l_hangup ( struct ast_modem_pvt p  )  [static]

Definition at line 657 of file chan_modem_i4l.c.

References ast_dsp_free(), ast_log(), ast_modem_expect(), ast_modem_send(), ast_modem_pvt::dsp, ast_modem_pvt::fd, and LOG_WARNING.

00658 {
00659    char dummy[50];
00660    int dtr = TIOCM_DTR;
00661 
00662    /* free the memory used by the DSP */
00663    if (p->dsp) {
00664       ast_dsp_free(p->dsp);
00665       p->dsp = NULL;
00666    }
00667 
00668    /* down DTR to hangup modem */
00669    ioctl(p->fd, TIOCMBIC, &dtr);
00670    /* Read anything outstanding */
00671    while(read(p->fd, dummy, sizeof(dummy)) > 0);
00672 
00673    /* rise DTR to re-enable line */
00674    ioctl(p->fd, TIOCMBIS, &dtr);
00675    
00676    /* Read anything outstanding */
00677    while(read(p->fd, dummy, sizeof(dummy)) > 0);
00678 
00679    /* basically we're done, just to be sure */
00680    write(p->fd, "\n\n", 2);
00681    read(p->fd, dummy, sizeof(dummy));
00682    if (ast_modem_send(p, "ATH", 0)) {
00683       ast_log(LOG_WARNING, "Unable to hang up\n");
00684       return -1;
00685    }
00686    if (ast_modem_expect(p, "OK", 5)) {
00687       ast_log(LOG_WARNING, "Final 'OK' not received\n");
00688       return -1;
00689    }
00690 
00691    return 0;
00692 }

static char* i4l_identify ( struct ast_modem_pvt p  )  [static]

Definition at line 550 of file chan_modem_i4l.c.

References strdup.

00551 {
00552    return strdup("Linux ISDN");
00553 }

static void i4l_incusecnt ( void   )  [static]

Definition at line 555 of file chan_modem_i4l.c.

References ast_mutex_lock(), ast_mutex_unlock(), ast_update_use_count(), and usecnt_lock.

00556 {
00557    ast_mutex_lock(&usecnt_lock);
00558    usecnt++;
00559    ast_mutex_unlock(&usecnt_lock);
00560    ast_update_use_count();
00561 }

static int i4l_init ( struct ast_modem_pvt p  )  [static]

Definition at line 169 of file chan_modem_i4l.c.

References ast_log(), ast_modem_expect(), ast_modem_send(), ast_strlen_zero(), ast_modem_pvt::escape, i4l_break(), ast_modem_pvt::incomingmsn, LOG_DEBUG, LOG_WARNING, ast_modem_pvt::ministate, ast_modem_pvt::msn, option_debug, and STATE_COMMAND.

00170 {
00171    char cmd[256];
00172    if (option_debug)
00173       ast_log(LOG_DEBUG, "i4l_init()\n");
00174    if (i4l_break(p))
00175       return -1;
00176    /* Force into command mode */
00177    p->ministate = STATE_COMMAND;
00178    if (ast_modem_send(p, "AT+FCLASS=8", 0) ||
00179         ast_modem_expect(p, "OK", 5)) {
00180       ast_log(LOG_WARNING, "Unable to set to voice mode\n");
00181       return -1;
00182    }
00183    if (!ast_strlen_zero(p->msn)) {
00184       snprintf(cmd, sizeof(cmd), "AT&E%s", p->msn);
00185       if (ast_modem_send(p, cmd, 0) ||
00186           ast_modem_expect(p, "OK", 5)) {
00187          ast_log(LOG_WARNING, "Unable to set MSN to %s\n", p->msn);
00188          return -1;
00189       }
00190    }
00191    if (!ast_strlen_zero(p->incomingmsn)) {
00192       char *q;
00193       snprintf(cmd, sizeof(cmd), "AT&L%s", p->incomingmsn);
00194       /* translate , into ; since that is the seperator I4L uses, but can't be directly */
00195       /* put in the config file because it will interpret the rest of the line as comment. */
00196       q = cmd+4;
00197       while (*q) {
00198          if (*q == ',') *q = ';';
00199          ++q;
00200       }
00201       if (ast_modem_send(p, cmd, 0) ||
00202           ast_modem_expect(p, "OK", 5)) {
00203          ast_log(LOG_WARNING, "Unable to set Listen to %s\n", p->msn);
00204          return -1;
00205       }
00206    }
00207    if (ast_modem_send(p, "AT&D2", 0) ||
00208         ast_modem_expect(p, "OK", 5)) {
00209       ast_log(LOG_WARNING, "Unable to set to DTR disconnect mode\n");
00210       return -1;
00211    }
00212    if (ast_modem_send(p, "ATS18=1", 0) ||
00213         ast_modem_expect(p, "OK", 5)) {
00214       ast_log(LOG_WARNING, "Unable to set to audio only mode\n");
00215       return -1;
00216    }
00217    if (ast_modem_send(p, "ATS13.6=1", 0) ||
00218         ast_modem_expect(p, "OK", 5)) {
00219       ast_log(LOG_WARNING, "Unable to set to RUNG indication\n");
00220       return -1;
00221    }
00222    if (ast_modem_send(p, "ATS14=4", 0) ||
00223         ast_modem_expect(p, "OK", 5)) {
00224       ast_log(LOG_WARNING, "Unable to set to transparent mode\n");
00225       return -1;
00226    }
00227    if (ast_modem_send(p, "ATS23=9", 0) ||
00228         ast_modem_expect(p, "OK", 5)) {
00229       ast_log(LOG_WARNING, "Unable to set to transparent/ringing mode\n");
00230       return -1;
00231    }
00232 
00233    if (ast_modem_send(p, "AT+VSM=6", 0) ||
00234         ast_modem_expect(p, "OK", 5)) {
00235       ast_log(LOG_WARNING, "Unable to set to muLAW mode\n");
00236       return -1;
00237    }
00238    if (ast_modem_send(p, "AT+VLS=2", 0) ||
00239         ast_modem_expect(p, "OK", 5)) {
00240       ast_log(LOG_WARNING, "Unable to set to phone line interface\n");
00241       return -1;
00242    }
00243    p->escape = 0;
00244    return 0;
00245 }

static struct ast_frame* i4l_read ( struct ast_modem_pvt p  )  [static]

Definition at line 330 of file chan_modem_i4l.c.

References ast_log(), ast_modem_trim(), AST_MULAW, ast_verbose(), CHAR_DLE, ast_modem_pvt::cid_num, ast_modem_pvt::dev, ast_modem_pvt::dnid, ast_modem_pvt::escape, ast_modem_pvt::f, ast_modem_pvt::fd, i4l_handle_escape(), LOG_DEBUG, LOG_WARNING, ast_modem_pvt::ministate, ast_modem_pvt::obuf, ast_modem_pvt::obuflen, option_debug, option_verbose, result, STATE_COMMAND, and VERBOSE_PREFIX_3.

00331 {
00332    unsigned char result[256];
00333    short *b;
00334    struct ast_frame *f=NULL;
00335    int res;
00336    int x;
00337    if (p->ministate == STATE_COMMAND) {
00338       /* Read the first two bytes, first, in case it's a control message */
00339       res = read(p->fd, result, 2);
00340       if (res < 2) {
00341          /* short read, means there was a hangup? */
00342          /* (or is this also possible without hangup?) */
00343          /* Anyway, reading from unitialized buffers is a bad idea anytime. */
00344          if (errno == EAGAIN)
00345             return i4l_handle_escape(p, 0);
00346          return NULL;
00347       }
00348       if (result[0] == CHAR_DLE) {
00349          return i4l_handle_escape(p, result[1]);
00350          
00351       } else {
00352          if ((result[0] == '\n') || (result[0] == '\r'))
00353             return i4l_handle_escape(p, 0);
00354          /* Read the rest of the line */
00355          fgets(result + 2, sizeof(result) - 2, p->f);
00356          ast_modem_trim(result);
00357          if (!strcasecmp(result, "VCON")) {
00358             /* If we're in immediate mode, reply now */
00359 /*          if (p->mode == MODEM_MODE_IMMEDIATE) */
00360                return i4l_handle_escape(p, 'X');
00361          } else
00362          if (!strcasecmp(result, "BUSY")) {
00363             /* Same as a busy signal */
00364             return i4l_handle_escape(p, 'b');
00365          } else
00366          if (!strncasecmp(result, "CALLER NUMBER: ", 15 )) {
00367             strncpy(p->cid_num, result + 15, sizeof(p->cid_num)-1);
00368             return i4l_handle_escape(p, 0);
00369          } else
00370          if (!strcasecmp(result, "RINGING")) {
00371             if (option_verbose > 2)
00372                ast_verbose(VERBOSE_PREFIX_3 "%s is ringing...\n", p->dev);
00373             return i4l_handle_escape(p, 'I');
00374          } else
00375          if (!strncasecmp(result, "RUNG", 4)) {
00376             /* PM2002: the line was hung up before we picked it up, bye bye */
00377             if (option_verbose > 2) 
00378                ast_verbose(VERBOSE_PREFIX_3 "%s was hung up on before we answered\n", p->dev);
00379             return NULL;
00380          } else
00381          if (!strncasecmp(result, "RING", 4)) {
00382             if (result[4]=='/') 
00383                strncpy(p->dnid, result + 5, sizeof(p->dnid)-1);
00384             return i4l_handle_escape(p, 'R');
00385          } else
00386          if (!strcasecmp(result, "NO CARRIER")) {
00387             if (option_verbose > 2) 
00388                ast_verbose(VERBOSE_PREFIX_3 "%s hung up on\n", p->dev);
00389             return NULL;
00390          } else
00391          if (!strcasecmp(result, "NO DIALTONE")) {
00392             /* There's no dialtone, so the line isn't working */
00393             ast_log(LOG_WARNING, "Device '%s' lacking dialtone\n", p->dev);
00394             return NULL;
00395          }
00396          if (option_debug)
00397             ast_log(LOG_DEBUG, "Modem said '%s'\n", result);
00398          return i4l_handle_escape(p, 0);
00399       }
00400    } else {
00401       /* We have to be more efficient in voice mode */
00402       b = (short *)(p->obuf + p->obuflen);
00403       while (p->obuflen/2 < 240) {
00404          /* Read ahead the full amount */
00405          res = read(p->fd, result, 240 - p->obuflen/2);
00406          if (res < 1) {
00407             /* If there's nothing there, just continue on */
00408             if (errno == EAGAIN)
00409                return i4l_handle_escape(p, 0);
00410             ast_log(LOG_WARNING, "Read failed: %s\n", strerror(errno));
00411             return NULL;
00412          }
00413          
00414          for (x=0;x<res;x++) {
00415             /* Process all the bytes that we've read */
00416             switch(result[x]) {
00417             case CHAR_DLE:
00418 #if 0
00419                ast_log(LOG_DEBUG, "Ooh, an escape at %d...\n", x);
00420 #endif
00421                if (!p->escape) {
00422                   /* Note that next value is
00423                      an escape, and continue. */
00424                   p->escape++;
00425                   break;
00426                } else {
00427                   /* Send as is -- fallthrough */
00428                   p->escape = 0;
00429                }
00430             default:
00431                if (p->escape) {
00432                   ast_log(LOG_DEBUG, "Value of escape is %c (%d)...\n", result[x] < 32 ? '^' : result[x], result[x]);
00433                   p->escape = 0;
00434                   if (f) 
00435                      ast_log(LOG_WARNING, "Warning: Dropped a signal frame\n");
00436                   f = i4l_handle_escape(p, result[x]);
00437                   /* If i4l_handle_escape says NULL, say it now, doesn't matter
00438                   what else is there, the connection is dead. */
00439                   if (!f)
00440                      return NULL;
00441                } else {
00442                   *(b++) = AST_MULAW((int)result[x]);
00443                   p->obuflen += 2;
00444                }
00445             }
00446          }
00447          if (f)
00448             break;
00449       }
00450       if (f) {
00451          if( ! (!(p->dtmfmode & MODEM_DTMF_I4L) && f->frametype == AST_FRAME_DTMF))
00452          return f;
00453       }
00454 
00455       /* If we get here, we have a complete voice frame */
00456       p->fr.frametype = AST_FRAME_VOICE;
00457       p->fr.subclass = AST_FORMAT_SLINEAR;
00458       p->fr.samples = 240;
00459       p->fr.data = p->obuf;
00460       p->fr.datalen = p->obuflen;
00461       p->fr.mallocd = 0;
00462       p->fr.delivery.tv_sec = 0;
00463       p->fr.delivery.tv_usec = 0;
00464       p->fr.offset = AST_FRIENDLY_OFFSET;
00465       p->fr.src = __FUNCTION__;
00466       p->obuflen = 0;
00467 
00468       /* process with dsp */
00469       if (p->dsp) {
00470          f = ast_dsp_process(p->owner, p->dsp, &p->fr);
00471          if (f && (f->frametype == AST_FRAME_DTMF)) {
00472             ast_log(LOG_DEBUG, "Detected inband DTMF digit: %c on %s\n", f->subclass, p->dev);
00473             if (f->subclass == 'f') {
00474                /* Fax tone -- Handle and return NULL */
00475                struct ast_channel *ast = p->owner;
00476                if (!p->faxhandled) {
00477                   p->faxhandled++;
00478                   if (strcmp(ast->exten, "fax")) {
00479                      const char *target_context = ast_strlen_zero(ast->macrocontext) ? ast->context : ast->macrocontext;
00480                      
00481                      if (ast_exists_extension(ast, target_context, "fax", 1, ast->cid.cid_num)) {
00482                         if (option_verbose > 2)
00483                            ast_verbose(VERBOSE_PREFIX_3 "Redirecting %s to fax extension\n", ast->name);
00484                         /* Save the DID/DNIS when we transfer the fax call to a "fax" extension */
00485                         pbx_builtin_setvar_helper(ast, "FAXEXTEN", ast->exten);
00486                         if (ast_async_goto(ast, target_context, "fax", 1))
00487                            ast_log(LOG_WARNING, "Failed to async goto '%s' into fax of '%s'\n", ast->name, target_context);
00488                      } else
00489                         ast_log(LOG_NOTICE, "Fax detected, but no fax extension\n");
00490                   } else
00491                      ast_log(LOG_DEBUG, "Already in a fax extension, not redirecting\n");
00492                } else
00493                   ast_log(LOG_DEBUG, "Fax already handled\n");
00494                p->fr.frametype = AST_FRAME_NULL;
00495                p->fr.subclass = 0;
00496                f = &p->fr;
00497             }
00498             return f;
00499          }
00500       }
00501       
00502       return &p->fr;
00503    }
00504    return NULL;
00505 }

static int i4l_setdev ( struct ast_modem_pvt p,
int  dev 
) [static]

Definition at line 66 of file chan_modem_i4l.c.

References ast_log(), ast_modem_expect(), ast_modem_read_response(), ast_modem_send(), ast_modem_trim(), LOG_WARNING, MODEM_DEV_TELCO, MODEM_DEV_TELCO_SPK, and ast_modem_pvt::response.

00067 {
00068    char cmd[80];
00069    if ((dev != MODEM_DEV_TELCO) && (dev != MODEM_DEV_TELCO_SPK)) {
00070       ast_log(LOG_WARNING, "ISDN4Linux only supports telco device, not %d.\n", dev);
00071       return -1;
00072    } else   /* Convert DEV to our understanding of it */
00073       dev = 2;
00074    if (ast_modem_send(p, "AT+VLS?", 0)) {
00075       ast_log(LOG_WARNING, "Unable to select current mode %d\n", dev);
00076       return -1;
00077    }
00078    if (ast_modem_read_response(p, 5)) {
00079       ast_log(LOG_WARNING, "Unable to select device %d\n", dev);
00080       return -1;
00081    }
00082    ast_modem_trim(p->response);
00083    strncpy(cmd, p->response, sizeof(cmd)-1);
00084    if (ast_modem_expect(p, "OK", 5)) {
00085       ast_log(LOG_WARNING, "Modem did not respond properly\n");
00086       return -1;
00087    }
00088    if (dev == atoi(cmd)) {
00089       /* We're already in the right mode, don't bother changing for fear of
00090          hanging up */
00091       return 0;
00092    }
00093    snprintf(cmd, sizeof(cmd), "AT+VLS=%d", dev);
00094    if (ast_modem_send(p, cmd, 0))  {
00095       ast_log(LOG_WARNING, "Unable to select device %d\n", dev);
00096       return -1;
00097    }
00098    if (ast_modem_read_response(p, 5)) {
00099       ast_log(LOG_WARNING, "Unable to select device %d\n", dev);
00100       return -1;
00101    }
00102    ast_modem_trim(p->response);
00103    if (strcasecmp(p->response, "VCON") && strcasecmp(p->response, "OK")) {
00104       ast_log(LOG_WARNING, "Unexpected reply: %s\n", p->response);
00105       return -1;
00106    }
00107    return 0;
00108 }

static int i4l_startrec ( struct ast_modem_pvt p  )  [static]

Definition at line 110 of file chan_modem_i4l.c.

References ast_dsp_digitmode(), ast_dsp_new(), ast_dsp_set_features(), ast_log(), ast_modem_expect(), ast_modem_send(), ast_modem_pvt::dev, ast_modem_pvt::dsp, DSP_DIGITMODE_DTMF, DSP_FEATURE_DTMF_DETECT, DSP_FEATURE_FAX_DETECT, ast_modem_pvt::dtmfmode, LOG_DEBUG, LOG_WARNING, ast_modem_pvt::ministate, MODEM_DTMF_AST, and STATE_VOICE.

Referenced by i4l_handle_escape().

00111 {
00112    if (ast_modem_send(p, "AT+VRX+VTX", 0) ||
00113         ast_modem_expect(p, "CONNECT", 5)) {
00114       ast_log(LOG_WARNING, "Unable to start recording\n");
00115       return -1;
00116    }
00117    p->ministate = STATE_VOICE;
00118    
00119    /*  let ast dsp detect dtmf */
00120    if (p->dtmfmode & MODEM_DTMF_AST) {
00121       if (p->dsp) {
00122          ast_log(LOG_DEBUG, "Already have a dsp on %s?\n", p->dev);
00123       } else {
00124          p->dsp = ast_dsp_new();
00125          if (p->dsp) {
00126             ast_log(LOG_DEBUG, "Detecting DTMF inband with sw DSP on %s\n",p->dev);
00127             ast_dsp_set_features(p->dsp, DSP_FEATURE_DTMF_DETECT|DSP_FEATURE_FAX_DETECT);
00128             ast_dsp_digitmode(p->dsp, DSP_DIGITMODE_DTMF | 0);
00129          }
00130       }
00131    }
00132 
00133    return 0;
00134 }

static int i4l_write ( struct ast_modem_pvt p,
struct ast_frame f 
) [static]

Definition at line 507 of file chan_modem_i4l.c.

References AST_FORMAT_SLINEAR, AST_FRAME_VOICE, AST_LIN2MU, ast_log(), CHAR_DLE, ast_frame::data, ast_frame::datalen, ast_modem_pvt::f, ast_modem_pvt::fd, ast_frame::frametype, LOG_WARNING, MAX_WRITE_SIZE, result, and ast_frame::subclass.

00508 {
00509 #define MAX_WRITE_SIZE 2048
00510    unsigned char result[MAX_WRITE_SIZE << 1];
00511    unsigned char b;
00512    int bpos=0, x;
00513    int res;
00514    if (f->datalen > MAX_WRITE_SIZE) {
00515       ast_log(LOG_WARNING, "Discarding too big frame of size %d\n", f->datalen);
00516       return -1;
00517    }
00518    if (f->frametype != AST_FRAME_VOICE) {
00519       ast_log(LOG_WARNING, "Don't know how to handle %d type frames\n", f->frametype);
00520       return -1;
00521    }
00522    if (f->subclass != AST_FORMAT_SLINEAR) {
00523       ast_log(LOG_WARNING, "Don't know how to handle anything but signed linear frames\n");
00524       return -1;
00525    }
00526    for (x=0;x<f->datalen/2;x++) {
00527       b = AST_LIN2MU(((short *)f->data)[x]);
00528       result[bpos++] = b;
00529       if (b == CHAR_DLE)
00530          result[bpos++]=b;
00531    }
00532 #if 0
00533    res = fwrite(result, bpos, 1, p->f);
00534    res *= bpos;
00535 #else
00536    res = write(p->fd, result, bpos);
00537 #endif
00538    if (res < 1) {
00539       if (errno != EAGAIN) {
00540          ast_log(LOG_WARNING, "Failed to write buffer\n");
00541          return -1;
00542       }
00543    }
00544 #if 0
00545    printf("Result of write is %d\n", res);
00546 #endif
00547    return 0;
00548 }

char* key ( void   ) 

Returns the ASTERISK_GPL_KEY.

This returns the ASTERISK_GPL_KEY, signifiying that you agree to the terms of the GPL stated in the ASTERISK_GPL_KEY. Your module will not load if it does not return the EXACT message:

 char *key(void) {
         return ASTERISK_GPL_KEY;
 }

Returns:
ASTERISK_GPL_KEY

Definition at line 740 of file chan_modem_i4l.c.

References ASTERISK_GPL_KEY.

00741 {
00742    return ASTERISK_GPL_KEY;
00743 }

int load_module ( void   ) 

Initialize the module.

Initialize the Agents module. This function is being called by Asterisk when loading the module. Among other thing it registers applications, cli commands and reads the cofiguration file.

Returns:
int Always 0.

Definition at line 725 of file chan_modem_i4l.c.

References ast_register_modem_driver(), and i4l_driver.

00726 {
00727    return ast_register_modem_driver(&i4l_driver);
00728 }

int unload_module ( void   ) 

Cleanup all module structures, sockets, etc.

This is called at exit. Any registrations and memory allocations need to be unregistered and free'd here. Nothing else will do these for you (until exit).

Returns:
Zero on success, or non-zero on error.

Definition at line 730 of file chan_modem_i4l.c.

References ast_unregister_modem_driver(), and i4l_driver.

00731 {
00732    return ast_unregister_modem_driver(&i4l_driver);
00733 }

int usecount ( void   ) 

Provides a usecount.

This function will be called by various parts of asterisk. Basically, all it has to do is to return a usecount when called. You will need to maintain your usecount within the module somewhere. The usecount should be how many channels provided by this module are in use.

Returns:
The module's usecount.

Definition at line 720 of file chan_modem_i4l.c.

00721 {
00722    return usecnt;
00723 }


Variable Documentation

char* breakcmd = "\0x10\0x14\0x10\0x3" [static]

Definition at line 53 of file chan_modem_i4l.c.

char* desc = "ISDN4Linux Emulated Modem Driver" [static]

Definition at line 55 of file chan_modem_i4l.c.

struct ast_modem_driver i4l_driver [static]

Definition at line 694 of file chan_modem_i4l.c.

Referenced by load_module(), and unload_module().

char* i4l_idents[] [static]

Initial value:

 {
   
   "Linux ISDN",
   NULL
}

Definition at line 60 of file chan_modem_i4l.c.

int usecnt [static]

Definition at line 57 of file chan_modem_i4l.c.


Generated on Sat Sep 16 07:28:14 2006 for Asterisk - the Open Source PBX by  doxygen 1.4.7