📄 libsms_modem.c
字号:
/*SMS Server ToolsCopyright (C) 2000 Stefan FringsThis program is free software unless you got it under another license directlyfrom the author. You can redistribute it and/or modify it under the terms ofthe GNU General Public License as published by the Free Software Foundation.Either version 2 of the License, or (at your option) any later version.http://www.isis.de/members/~s.fringsmailto:s.frings@mail.isis.de */#include <sys/types.h>#include <sys/stat.h>#include <fcntl.h>#include <string.h>#include <strings.h>#include <errno.h>#include <termios.h>#include <stdio.h>#include <unistd.h>#include <syslog.h>#include <sys/ioctl.h>#ifdef __sun#include <sys/filio.h>#endif#include "libsms_modem.h"#include "../../dprint.h"#define MAX_BUF 2048#define CDS_HDR "\r\n+CDS:"#define CDS_HDR_LEN (strlen(CDS_HDR))#define optz(_n,_l) (buf+buf_len-(((_n)+(_l)>buf_len)?buf_len:(_n)+(_l)))/* global variables */int sms_report_type;cds_report cds_report_func;int put_command( struct modem *mdm, char* cmd, int cmd_len, char* answer, int max, int timeout,char* exp_end){ static char buf[MAX_BUF]; static int buf_len = 0; char* pos; char* foo; char* ptr; char* to_move; char* answer_s; char* answer_e; int timeoutcounter; int available; int status; int exp_end_len; int n; /* check if fd is "clean" for reading */ timeoutcounter = 0; ioctl(mdm->fd,TIOCMGET,&status); while (!(status & TIOCM_CTS)) { usleep( READ_SLEEP ); timeoutcounter++; ioctl(mdm->fd,TIOCMGET,&status); if (timeoutcounter>=timeout) { LOG(L_INFO,"INFO:put_command: Modem is not clear to send\n"); return 0; } }#ifdef SHOW_SMS_MODEM_COMMAND DBG("DEBUG: put_command: -<%d>-->[%.*s] \n",cmd_len,cmd_len,cmd);#endif /* send the command to the modem */ write(mdm->fd,cmd,cmd_len); tcdrain(mdm->fd); /* read from the modem */ exp_end_len = exp_end?strlen(exp_end):0; answer_s = buf; answer_e = 0; to_move = 0; do { /* try to read some bytes */ ioctl(mdm->fd,FIONREAD,&available); /* how many bytes are available to read? */ if (available<1) /* if 0 then wait a little bit and retry */ { usleep( READ_SLEEP ); timeoutcounter++; ioctl(mdm->fd,FIONREAD,&available); } if (available>0) { /* How many bytes do I want to read maximum? Not more than buffer size. And how many bytes are available? */ n = (available>MAX_BUF-buf_len-1)?MAX_BUF-buf_len-1:available; /* read data */ n = read( mdm->fd, buf+buf_len, n); if (n<0) { LOG(L_ERR,"ERROR:put_command: error reading from modem: %s\n", strerror(errno)); goto error; } if (n) { buf_len += n; buf[buf_len] = 0; //DBG("DEBUG:put_commnad: read = [%s]\n",buf+buf_len-n); foo = pos = 0; if ( (!exp_end && ((pos=strstr(optz(n,4),"OK\r\n")) || (foo=strstr(optz(n,5),"ERROR")))) || (exp_end && (pos=strstr(optz(n,exp_end_len),exp_end)) )) { /* we found the end */ //DBG("DEBUG:put_commnad: end found = %s\n", // (foo?"ERROR":(exp_end?exp_end:"OK"))); /* for ERROR we still have to read EOL */ if (!foo || (foo=strstr(foo+5,"\r\n"))) { answer_e = foo?foo+2:(pos+(exp_end?exp_end_len:4)); timeoutcounter = timeout; } } } } /* repeat until timout */ }while (timeoutcounter<timeout); if (!answer_e) answer_e = buf+buf_len; /* CDS report is activ? */ if (sms_report_type==CDS_REPORT) { to_move = 0; ptr = buf; /* do we have a CDS reply inside? */ while ( (pos=strstr(ptr,CDS_HDR)) ) { if (pos!=ptr) { /* here we have the command response */ answer_s = ptr; } /* look for the end of CDS response */ ptr = pos+CDS_HDR_LEN; for( n=0 ; n<2&&(foo=strstr(ptr,"\r\n")) ; ptr=foo+2,n++ ); if (n<2) { /* we haven't read the entire CDS response */ DBG("DEBUG:put_command: CDS end not found!\n"); to_move = pos; ptr = buf + buf_len; }else{ /* process the CDS */ DBG("DEBUG:put_command:CDS=[%.*s]\n",(int)(ptr-pos),pos); cds_report_func(mdm,pos,ptr-pos); } } if ((*ptr)) { answer_s = ptr; ptr = answer_e; } if (ptr!=buf+buf_len) to_move = ptr; } /* copy the response in answer buffer - as much as fits */ if (answer && max) { n = max-1<answer_e-answer_s?max-1:answer_e-answer_s; memcpy(answer,answer_s,n); answer[n] = 0; } /* shift left the remaining data into the buffer - if needs */ if (sms_report_type==CDS_REPORT && to_move) { buf_len = buf_len - (to_move-buf); memcpy(buf,to_move,buf_len); buf[buf_len] = 0; DBG("DEBUG:put_commnad: buffer shifted left=[%d][%s]\n",buf_len,buf); } else { buf_len = 0; }#ifdef SHOW_SMS_MODEM_COMMAND DBG("DEBUG:put_command: <-[%s] \n",answer);#endif return answer_e-answer_s;error: return 0;}/* setup serial port */int setmodemparams( struct modem *mdm ){ struct termios newtio; bzero(&newtio, sizeof(newtio)); newtio.c_cflag = mdm->baudrate | CRTSCTS | CS8 | CLOCAL | CREAD | O_NDELAY; //uncomment next line to disable hardware handshake //newtio.c_cflag &= ~CRTSCTS; newtio.c_iflag = IGNPAR; newtio.c_oflag = 0; newtio.c_lflag = 0; newtio.c_cc[VTIME] = 1; newtio.c_cc[VMIN] = 0; tcflush(mdm->fd, TCIOFLUSH); tcsetattr(mdm->fd,TCSANOW,&newtio); return 0;}int initmodem(struct modem *mdm, cds_report cds_report_f){ char command[100]; char answer[100]; int retries=0; int success=0; int clen=0; int n; LOG(L_INFO,"INFO:initmodem: init modem %s on %s.\n",mdm->name,mdm->device); if (mdm->pin[0]) { /* Checking if modem needs PIN */ put_command(mdm,"AT+CPIN?\r",9,answer,sizeof(answer),50,0); if (strstr(answer,"+CPIN: SIM PIN")) { LOG(L_INFO,"INFO:initmodem: Modem needs PIN, entering PIN...\n"); clen=sprintf(command,"AT+CPIN=\"%s\"\r",mdm->pin); put_command(mdm,command,clen,answer,sizeof(answer),100,0); put_command(mdm,"AT+CPIN?\r",9,answer,sizeof(answer),50,0); if (!strstr(answer,"+CPIN: READY")) { if (strstr(answer,"+CPIN: SIM PIN")) { LOG(L_ERR,"ERROR:initmodem: Modem did not accept" " this PIN\n"); goto error; } else if (strstr(answer,"+CPIN: SIM PUK")) { LOG(L_ERR,"ERROR:initmodem: YourPIN is locked!" " Unlock it manually!\n"); goto error; } else { goto error; } } LOG(L_INFO,"INFO:initmodem: PIN Ready!\n"); sleep(5); } } if (mdm->mode==MODE_DIGICOM) success=1; else { LOG(L_INFO,"INFO:initmodem: Checking if Modem is registered to" " the network\n"); success=0; retries=0; do { retries++; put_command(mdm,"AT+CREG?\r",9,answer,sizeof(answer),100,0); if (strchr(answer,'1') ) { LOG(L_INFO,"INFO:initmodem: Modem is registered to the" " network\n"); success=1; } else if (strchr(answer,'2')) { // added by bogdan LOG(L_WARN,"WARNING:initmodem: Modems seems to try to " "reach the network! Let's wait a little bit\n"); retries--; sleep(2); } else if (strchr(answer,'5')) { // added by Thomas Stoeckel LOG(L_INFO,"INFO:initmodem: Modem is registered to a" " roaming partner network\n"); success=1; } else if (strstr(answer,"ERROR")) { LOG(L_WARN,"WARNING:initmodem: Ignoring that modem does" " not support +CREG command.\n"); success=1; } else { LOG(L_NOTICE,"NOTICE:initmodem: Waiting 2 sec. before" " retrying\n"); sleep(2); } }while ((success==0)&&(retries<20)); } if (success==0) { LOG(L_ERR,"ERROR:initmodem: Modem is not registered to the network\n"); goto error; } for( n=0 ; n<2+2*(sms_report_type==CDS_REPORT) ; n++) { /* build the command */ switch (n) { case 0: strcpy(command,"AT+CMGF=0\r"); command[8]+=(mdm->mode==MODE_ASCII || mdm->mode==MODE_DIGICOM); clen = 10; break; case 1: strcpy(command,"AT S7=45 S0=0 L1 V1 X4 &c1 E1 Q0\r"); clen = 33; break; case 2: strcpy(command,"AT+CSMP=49,167,0,241\r"); clen = 21; break; case 3: strcpy(command,"AT+CNMI=1,1,0,1,0\r"); clen = 18; break; } /* send it to modem */ retries=0; success=0; do { retries++; /*querying the modem*/ put_command(mdm,command,clen,answer,sizeof(answer),100,0); /*dealing with the answer*/ if (strstr(answer,"ERROR")) { LOG(L_NOTICE,"NOTICE:initmodem: Waiting 1 sec. before to" " retrying\n"); sleep(1); } else success=1; }while ((success==0)&&(retries<3)); /* have we succeeded? */ if (success==0) { LOG(L_ERR,"ERROR:initmodem: cmd [%.*s] returned ERROR\n", clen-1,command); goto error; } } /* end for */ if ( sms_report_type==CDS_REPORT && !cds_report_f) { LOG(L_ERR,"ERROR:initmodem:no CDS_REPORT function given\n"); goto error; } cds_report_func = cds_report_f; if (mdm->smsc[0]) { LOG(L_INFO,"INFO:initmodem: Changing SMSC to \"%s\"\n",mdm->smsc); setsmsc(mdm,mdm->smsc); } return 0;error: return -1;}int checkmodem(struct modem *mdm){ char answer[500]; /* Checking if modem needs PIN */ put_command(mdm,"AT+CPIN?\r",9,answer,sizeof(answer),50,0); if (!strstr(answer,"+CPIN: READY")) { LOG(L_WARN,"WARNING:sms_checkmodem: modem wants the PIN again!\n"); goto reinit; } if (mdm->mode!=MODE_DIGICOM) { put_command(mdm,"AT+CREG?\r",9,answer,sizeof(answer),100,0); if (!strchr(answer,'1') ) { LOG(L_WARN,"WARNING:sms_checkmodem: Modem is not registered to the" " network\n"); goto reinit; } } return 1;reinit: LOG(L_WARN,"WARNING:sms_checkmodem: re -init the modem!!\n"); initmodem(mdm,cds_report_func); return -1;}int setsmsc(struct modem *mdm, char *smsc){ char command[100]; char answer[50]; int clen; if (smsc && smsc[0]) { clen=sprintf(command,"AT+CSCA=\"+%s\"\r",smsc); put_command(mdm,command,clen,answer,sizeof(answer),50,0); } return 0;}int openmodem( struct modem *mdm){ mdm->fd = open(mdm->device, O_RDWR | O_NOCTTY ); if (mdm->fd <0) return -1; tcgetattr(mdm->fd,&(mdm->oldtio)); return 0;}int closemodem(struct modem *mdm){ tcsetattr(mdm->fd,TCSANOW,&(mdm->oldtio)); close(mdm->fd); return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -