libsms_modem.c

Go to the documentation of this file.
00001 /*
00002 SMS Server Tools
00003 Copyright (C) 2000 Stefan Frings
00004 
00005 This program is free software unless you got it under another license directly
00006 from the author. You can redistribute it and/or modify it under the terms of
00007 the GNU General Public License as published by the Free Software Foundation.
00008 Either version 2 of the License, or (at your option) any later version.
00009 
00010 http://www.isis.de/members/~s.frings
00011 mailto:s.frings@mail.isis.de
00012  */
00013 
00014 
00015 #include <sys/types.h>
00016 #include <sys/stat.h>
00017 #include <fcntl.h>
00018 #include <string.h>
00019 #include <strings.h>
00020 #include <errno.h>
00021 #include <termios.h>
00022 #include <stdio.h>
00023 #include <unistd.h>
00024 #include <syslog.h>
00025 #include <sys/ioctl.h>
00026 #ifdef __sun
00027 #include <sys/filio.h>
00028 #endif
00029 #include "libsms_modem.h"
00030 #include "../../dprint.h"
00031 
00032 #define  MAX_BUF        2048
00033 #define  CDS_HDR        "\r\n+CDS:"
00034 #define  CDS_HDR_LEN    (strlen(CDS_HDR))
00035 #define optz(_n,_l)     (buf+buf_len-(((_n)+(_l)>buf_len)?buf_len:(_n)+(_l)))
00036 
00037 /* global variables */
00038 int         sms_report_type;
00039 cds_report  cds_report_func;
00040 
00041 
00042 
00043 int put_command( struct modem *mdm, char* cmd, int cmd_len, char* answer,
00044                                  int max, int timeout,char* exp_end)
00045 {
00046    static char buf[MAX_BUF];
00047    static int  buf_len = 0;
00048    char* pos;
00049    char* foo;
00050    char* ptr;
00051    char* to_move;
00052    char* answer_s;
00053    char* answer_e;
00054    int   timeoutcounter;
00055    int   available;
00056    int   status;
00057    int   exp_end_len;
00058    int   n;
00059 
00060    /* check if fd is "clean" for reading */
00061    timeoutcounter = 0;
00062    ioctl(mdm->fd,TIOCMGET,&status);
00063    while (!(status & TIOCM_CTS))
00064    {
00065       usleep( READ_SLEEP );
00066       timeoutcounter++;
00067       ioctl(mdm->fd,TIOCMGET,&status);
00068       if (timeoutcounter>=timeout) {
00069          LM_INFO("Modem is not clear to send\n");
00070          return 0;
00071       }
00072    }
00073 #ifdef SHOW_SMS_MODEM_COMMAND
00074    LM_DBG("<--<%d>-->[%.*s] \n",cmd_len,cmd_len,cmd);
00075 #endif
00076    /* send the command to the modem */
00077    write(mdm->fd,cmd,cmd_len);
00078    tcdrain(mdm->fd);
00079 
00080    /* read from the modem */
00081    exp_end_len = exp_end?strlen(exp_end):0;
00082    answer_s = buf;
00083    answer_e = 0;
00084    to_move = 0;
00085    do
00086    {
00087       /* try to read some bytes */
00088       ioctl(mdm->fd,FIONREAD,&available);
00089       /* how many bytes are available to read? */
00090       if (available<1)  /* if 0 then wait a little bit and retry */
00091       {
00092          usleep( READ_SLEEP );
00093          timeoutcounter++;
00094          ioctl(mdm->fd,FIONREAD,&available);
00095       }
00096       if (available>0)
00097       {
00098          /* How many bytes do I want to read maximum?
00099          Not more than buffer size. And how many bytes are available? */
00100          n = (available>MAX_BUF-buf_len-1)?MAX_BUF-buf_len-1:available;
00101          /* read data */
00102          n = read( mdm->fd, buf+buf_len, n);
00103          if (n<0) {
00104             LM_ERR("error reading from modem: %s\n",
00105                strerror(errno));
00106             goto error;
00107          }
00108          if (n) {
00109             buf_len += n;
00110             buf[buf_len] = 0;
00111             //LM_DBG("read = [%s]\n",buf+buf_len-n);
00112             foo = pos = 0;
00113             if ( (!exp_end && ((pos=strstr(optz(n,4),"OK\r\n"))
00114             || (foo=strstr(optz(n,5),"ERROR"))))
00115             || (exp_end && (pos=strstr(optz(n,exp_end_len),exp_end)) )) {
00116                /* we found the end */
00117                //LM_DBG("end found = %s\n",
00118                // (foo?"ERROR":(exp_end?exp_end:"OK")));
00119                /* for ERROR we still have to read EOL */
00120                if (!foo || (foo=strstr(foo+5,"\r\n"))) {
00121                   answer_e = foo?foo+2:(pos+(exp_end?exp_end_len:4));
00122                   timeoutcounter = timeout;
00123                }
00124             }
00125          }
00126       }
00127    /* repeat until timout */
00128    }while (timeoutcounter<timeout);
00129 
00130    if (!answer_e)
00131       answer_e = buf+buf_len;
00132 
00133    /* CDS report is activ? */
00134    if (sms_report_type==CDS_REPORT) {
00135       to_move = 0;
00136       ptr = buf;
00137       /* do we have a CDS reply inside? */
00138       while ( (pos=strstr(ptr,CDS_HDR)) ) {
00139          if (pos!=ptr) {  /* here we have the command response */
00140             answer_s = ptr;
00141          }
00142          /* look for the end of CDS response */
00143          ptr = pos+CDS_HDR_LEN;
00144          for( n=0 ; n<2&&(foo=strstr(ptr,"\r\n")) ; ptr=foo+2,n++ );
00145          if (n<2) { /* we haven't read the entire CDS response */
00146             LM_DBG("CDS end not found!\n");
00147             to_move = pos;
00148             ptr = buf + buf_len;
00149          }else{
00150             /* process the CDS */
00151             LM_DBG("CDS=[%.*s]\n",(int)(ptr-pos),pos);
00152             cds_report_func(mdm,pos,ptr-pos);
00153          }
00154       }
00155       if ((*ptr)) {
00156          answer_s = ptr;
00157          ptr = answer_e;
00158       }
00159       if (ptr!=buf+buf_len)
00160          to_move = ptr;
00161    }
00162 
00163    /* copy the response in answer buffer - as much as fits */
00164    if (answer && max) {
00165       n = max-1<answer_e-answer_s?max-1:answer_e-answer_s;
00166       memcpy(answer,answer_s,n);
00167       answer[n] = 0;
00168    }
00169    /* shift left the remaining data into the buffer - if needs */
00170    if (sms_report_type==CDS_REPORT && to_move) {
00171       buf_len = buf_len - (to_move-buf);
00172       memcpy(buf,to_move,buf_len);
00173       buf[buf_len] = 0;
00174       LM_DBG("buffer shifted left=[%d][%s]\n",buf_len,buf);
00175    } else {
00176       buf_len = 0;
00177    }
00178 
00179 #ifdef SHOW_SMS_MODEM_COMMAND
00180    LM_DBG("<-[%s] \n",answer);
00181 #endif
00182    return answer_e-answer_s;
00183 
00184 error:
00185    return 0;
00186 }
00187 
00188 
00189 
00190 
00191 /* setup serial port */
00192 int setmodemparams( struct modem *mdm )
00193 {
00194    struct termios newtio;
00195 
00196    bzero(&newtio, sizeof(newtio));
00197    newtio.c_cflag = mdm->baudrate | CRTSCTS | CS8 | CLOCAL | CREAD | O_NDELAY;
00198    //uncomment next line to disable hardware handshake
00199    //newtio.c_cflag &= ~CRTSCTS;
00200    newtio.c_iflag = IGNPAR;
00201    newtio.c_oflag = 0;
00202    newtio.c_lflag = 0;
00203    newtio.c_cc[VTIME]    = 1;
00204    newtio.c_cc[VMIN]     = 0;
00205    tcflush(mdm->fd, TCIOFLUSH);
00206    tcsetattr(mdm->fd,TCSANOW,&newtio);
00207    return 0;
00208 }
00209 
00210 
00211 
00212 
00213 int initmodem(struct modem *mdm, cds_report cds_report_f)
00214 {
00215    char command[100];
00216    char answer[100];
00217    int retries=0;
00218    int success=0;
00219    int clen=0;
00220    int n;
00221 
00222    LM_INFO("init modem %s on %s.\n",mdm->name,mdm->device);
00223 
00224    if (mdm->pin[0]) {
00225       /* Checking if modem needs PIN */
00226       put_command(mdm,"AT+CPIN?\r",9,answer,sizeof(answer),50,0);
00227       if (strstr(answer,"+CPIN: SIM PIN")) {
00228          LM_INFO("Modem needs PIN, entering PIN...\n");
00229          clen=sprintf(command,"AT+CPIN=\"%s\"\r",mdm->pin);
00230          put_command(mdm,command,clen,answer,sizeof(answer),100,0);
00231          put_command(mdm,"AT+CPIN?\r",9,answer,sizeof(answer),50,0);
00232          if (!strstr(answer,"+CPIN: READY")) {
00233             if (strstr(answer,"+CPIN: SIM PIN")) {
00234                LM_ERR("Modem did not accept this PIN\n");
00235                goto error;
00236             } else if (strstr(answer,"+CPIN: SIM PUK")) {
00237                LM_ERR("YourPIN is locked! Unlock it manually!\n");
00238                goto error;
00239             } else {
00240                goto error;
00241             }
00242          }
00243          LM_INFO("INFO:initmodem: PIN Ready!\n");
00244          sleep(5);
00245       }
00246    }
00247 
00248    if (mdm->mode==MODE_DIGICOM)
00249       success=1;
00250    else {
00251       LM_INFO("INFO:initmodem: Checking if Modem is registered to"
00252          " the network\n");
00253       success=0;
00254       retries=0;
00255       do
00256       {
00257          retries++;
00258          put_command(mdm,"AT+CREG?\r",9,answer,sizeof(answer),100,0);
00259          if (strchr(answer,'1') )
00260          {
00261             LM_INFO("INFO:initmodem: Modem is registered to the"
00262                " network\n");
00263             success=1;
00264          } else if (strchr(answer,'2')) {
00265             // added by bogdan
00266             LM_WARN("Modems seems to try to reach the network!"
00267                   " Let's wait a little bit\n");
00268             retries--;
00269             sleep(2);
00270          } else if (strchr(answer,'5')) {
00271             // added by Thomas Stoeckel
00272             LM_INFO("Modem is registered to a roaming partner network\n");
00273             success=1;
00274          } else if (strstr(answer,"ERROR")) {
00275             LM_WARN("Ignoring that modem does not support +CREG command\n");
00276             success=1;
00277          } else {
00278             LM_NOTICE("NOTICE:initmodem: Waiting 2 sec. before retrying\n");
00279             sleep(2);
00280          }
00281       }while ((success==0)&&(retries<20));
00282    }
00283 
00284    if (success==0) {
00285       LM_ERR("Modem is not registered to the network\n");
00286       goto error;
00287    }
00288 
00289    for( n=0 ; n<2+2*(sms_report_type==CDS_REPORT) ; n++) {
00290       /* build the command */
00291       switch (n) {
00292          case 0:
00293             strcpy(command,"AT+CMGF=0\r");
00294             command[8]+=(mdm->mode==MODE_ASCII || mdm->mode==MODE_DIGICOM);
00295             clen = 10;
00296             break;
00297          case 1:
00298             strcpy(command,"AT S7=45 S0=0 L1 V1 X4 &c1 E1 Q0\r");
00299             clen = 33;
00300             break;
00301          case 2:
00302             strcpy(command,"AT+CSMP=49,167,0,241\r");
00303             clen = 21;
00304             break;
00305          case 3:
00306             strcpy(command,"AT+CNMI=1,1,0,1,0\r");
00307             clen = 18;
00308             break;
00309       }
00310       /* send it to modem */
00311       retries=0;
00312       success=0;
00313       do {
00314          retries++;
00315          /*querying the modem*/
00316          put_command(mdm,command,clen,answer,sizeof(answer),100,0);
00317          /*dealing with the answer*/
00318          if (strstr(answer,"ERROR")) {
00319             LM_NOTICE("Waiting 1 sec. before to retrying\n");
00320             sleep(1);
00321          } else
00322             success=1;
00323       }while ((success==0)&&(retries<3));
00324       /* have we succeeded? */
00325       if (success==0) {
00326          LM_ERR("cmd [%.*s] returned ERROR\n", clen-1,command);
00327          goto error;
00328       }
00329    } /* end for */
00330 
00331    if ( sms_report_type==CDS_REPORT && !cds_report_f) {
00332       LM_ERR("no CDS_REPORT function given\n");
00333       goto error;
00334    }
00335    cds_report_func = cds_report_f;
00336 
00337    if (mdm->smsc[0]) {
00338       LM_INFO("Changing SMSC to \"%s\"\n",mdm->smsc);
00339       setsmsc(mdm,mdm->smsc);
00340    }
00341 
00342 
00343 
00344    return 0;
00345 error:
00346    return -1;
00347 }
00348 
00349 
00350 
00351 
00352 int checkmodem(struct modem *mdm)
00353 {
00354    char answer[500];
00355 
00356    /* Checking if modem needs PIN */
00357    put_command(mdm,"AT+CPIN?\r",9,answer,sizeof(answer),50,0);
00358    if (!strstr(answer,"+CPIN: READY")) {
00359       LM_WARN("modem wants the PIN again!\n");
00360       goto reinit;
00361    }
00362 
00363    if (mdm->mode!=MODE_DIGICOM) {
00364       put_command(mdm,"AT+CREG?\r",9,answer,sizeof(answer),100,0);
00365       if (!strchr(answer,'1') ) {
00366          LM_WARN("Modem is not registered to the"
00367                " network\n");
00368          goto reinit;
00369       }
00370    }
00371 
00372    return 1;
00373 reinit:
00374    LM_WARN("re -init the modem!!\n");
00375    initmodem(mdm,cds_report_func);
00376    return -1;
00377 }
00378 
00379 
00380 
00381 
00382 int setsmsc(struct modem *mdm, char *smsc)
00383 {
00384    char command[100];
00385    char answer[50];
00386    int  clen;
00387 
00388    if (smsc && smsc[0]) {
00389       clen=sprintf(command,"AT+CSCA=\"+%s\"\r",smsc);
00390       put_command(mdm,command,clen,answer,sizeof(answer),50,0);
00391    }
00392    return 0;
00393 }
00394 
00395 
00396 
00397 
00398 int openmodem( struct modem *mdm)
00399 {
00400    mdm->fd = open(mdm->device, O_RDWR | O_NOCTTY );
00401    if (mdm->fd <0)
00402       return -1;
00403 
00404    tcgetattr(mdm->fd,&(mdm->oldtio));
00405    return 0;
00406 }
00407 
00408 
00409 
00410 
00411 int closemodem(struct modem *mdm)
00412 {
00413    tcsetattr(mdm->fd,TCSANOW,&(mdm->oldtio));
00414    close(mdm->fd);
00415    return 0;
00416 }
00417 

Generated on Wed May 23 18:00:28 2012 for Kamailio - The Open Source SIP Server by  doxygen 1.5.6