Asterisk.org: Developer Documentation (28 Oct 2009)

Wed Oct 28 15:48:33 2009

## 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"`

Include dependency graph for chan_modem_i4l.c:

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_frame * | i4l_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_frame * | i4l_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, read]`

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, read]`

Definition at line 330 of file chan_modem_i4l.c.

References ast_async_goto(), ast_dsp_process(), ast_exists_extension(), AST_FORMAT_SLINEAR, AST_FRAME_DTMF, AST_FRAME_NULL, AST_FRAME_VOICE, AST_FRIENDLY_OFFSET, ast_log(), ast_modem_trim(), AST_MULAW, ast_strlen_zero(), ast_verbose(), CHAR_DLE, ast_channel::cid, ast_callerid::cid_num, ast_modem_pvt::cid_num, ast_channel::context, ast_frame::data, ast_frame::datalen, ast_frame::delivery, ast_modem_pvt::dev, ast_modem_pvt::dnid, ast_modem_pvt::dsp, ast_modem_pvt::dtmfmode, ast_modem_pvt::escape, ast_channel::exten, ast_modem_pvt::f, ast_modem_pvt::faxhandled, ast_modem_pvt::fd, ast_modem_pvt::fr, ast_frame::frametype, i4l_handle_escape(), LOG_DEBUG, LOG_NOTICE, LOG_WARNING, ast_channel::macrocontext, ast_frame::mallocd, ast_modem_pvt::ministate, MODEM_DTMF_I4L, ast_channel::name, ast_modem_pvt::obuf, ast_modem_pvt::obuflen, ast_frame::offset, option_debug, option_verbose, ast_modem_pvt::owner, pbx_builtin_setvar_helper(), result, ast_frame::samples, ast_frame::src, STATE_COMMAND, ast_frame::subclass, 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.

This function is called at module load time. Put all code in here that needs to set up your module's hardware, software, registrations, etc.

Returns:
  This function should return 0 on success and non-zero on failure. If the module is not loaded successfully, Asterisk will call its unload_module() function.

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.

TE STUFF END

Definition at line 725 of file chan_modem_i4l.c.

References ast_register_modem_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().

    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.

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.