Linux下短信功能的实现
Linux版本Linux-3.2.0,无线模块是华为909SE,使用USB转串口模式,短信接口为/dev/ttyUSB4。
1 驱动
USB转串口驱动自行下载合适的版本,安装后无线模块会自动转化为8个串口,ttyUSB0~ttyUSB7,其中ttyUSB0用于网络数据的传输,ttyUSB4用于短信发送与接收。转化后可作为串口直接使用。
2 初始化
串口初始化:串口的初始化与一般一般串口相同,请自行参考串口初始化配置。
下面是串口配置的主要代码:
usbfd = open(Interface_USB4, O_RDWR); // 选择串口句柄
set_speed(usbfd , 115200); //设置串口速度函数
set_other_attribute(usbfd, 8, 1, 0, 0); //设置串口其他参数的函数
static int speed_arr[] = {B230400, B115200, B57600, B38400, B19200, B9600, B4800, B2400, B1800, B1200, B600, B300};
static int name_arr[] = {230400, 115200, 57600, 38400, 19200, 9600, 4800, 2400, 1800, 1200, 600, 300};
int set_speed(int fd, int speed)
{
int i, status;
struct termios Opt;
tcgetattr(fd, &Opt);
for ( i= 0; i < sizeof(speed_arr) / sizeof(int); i++) {
if (speed == name_arr[i]) {
tcflush(fd, TCIOFLUSH);
cfsetispeed(&Opt, speed_arr[i]);
cfsetospeed(&Opt, speed_arr[i]);
status = tcsetattr(fd, TCSANOW, &Opt);
if (status != 0) {
printf("tcsetattr failed\n");
return -1;
}
tcflush(fd,TCIOFLUSH);
return 0;
}
}
return -1;
}
int set_other_attribute(int fd, int databits, int stopbits, int parity, int mode)
{
struct termios options;
if (tcgetattr(fd, &options) != 0) {
printf("tcgetattr failed\n");
return -1;
}
options.c_cflag &= ~CSIZE;
switch (databits) /*¨¦?¨º?Y?¨º*/
{
case 7:
options.c_cflag |= CS7;
break;
case 8:
options.c_cflag |= CS8;
break;
default:
fprintf(stderr,"Unsupported data size\n");
return -1;
}
switch (parity)
{
case 'n':
case 'N':
options.c_cflag &= ~PARENB; /* Clear parity enable */
options.c_iflag &= ~INPCK; /* Enable parity checking */
break;
case 'o':
case 'O':
case 1:
options.c_cflag |= (PARODD | PARENB); /* ¨¦???§¹?*/
options.c_iflag |= INPCK; /* Disnable parity checking */
break;
case 'e':
case 'E':
case 2:
options.c_cflag |= PARENB; /* Enable parity */
options.c_cflag &= ~PARODD; /* ?????§¹?*/
options.c_iflag |= INPCK; /* Disnable parity checking */
break;
case 'S':
case 's': /*as no parity*/
case 0:
options.c_cflag &= ~PARENB;
options.c_cflag &= ~CSTOPB;
break;
default:
fprintf(stderr,"Unsupported parity\n");
return -1;
}
/* ¨¦???¦Ë*/
switch (stopbits)
{
case 1:
options.c_cflag &= ~CSTOPB;
break;
case 2:
options.c_cflag |= CSTOPB;
break;
default:
fprintf(stderr,"Unsupported stop bits\n");
return -1;
}
/* Set input parity option */
if (parity != 'n')
options.c_iflag |= INPCK;
tcflush(fd,TCIFLUSH);
options.c_iflag = 0;
options.c_oflag = 0;
options.c_lflag = 0;
options.c_cc[VTIME] = 50; /* ¨¦?3??15 seconds*/
options.c_cc[VMIN] = 1; /* Update the options and do it NOW */
// options.c_oflag 0;
switch(mode)
{
/*case 1://rs485
options.c_cflag |= RS485;
printf("Enable RS485 !\n");
break;
case 2://HWHD
options.c_cflag |= HWHD;
printf("Enable HWHD !\n");
break;
case 3://Modem
options.c_cflag |= Modem;
printf("Enable Modem !\n");
break;
case 4://ISO7816T0
options.c_cflag |= ISO7816T0;
printf("Enable ISO7816 T=0 \n");
break;
case 5://ISO7816T1
options.c_cflag |= ISO7816T1;
printf("Enable ISO7816 T=1 \n");
break;
case 6://IrDA
options.c_cflag |= IrDA;
printf("Enable IrDA \n");
break;*/
default:
break;
}
if (tcsetattr(fd,TCSANOW,&options) != 0)
{
perror("SetupSerial 3");
return -1;
}
#if 0
tcgetattr(fd, &options);
printf("c_iflag: %x\rc_oflag: %x\n", options.c_iflag, options.c_oflag);
printf("c_cflag: %x\nc_lflag: %x\n", options.c_cflag, options.c_lflag);
printf("c_line: %x\nc_cc[VTIME]: %d\nc_cc[VMIN]: %d\n", options.c_line, options.c_cc[VTIME], options.c_cc[VMIN]);
#endif
return 0;
}
模块初始化:根据使用的模块,进行配置。包括短信模式、字符模式、新消息到来提醒、短信存储位置、清除已读短信等配置。
MsgInit;//模块初始化函数
int MsgInit(void)
{
int rec;
rec = ATCMDSend("AT+IPR=0\r\n", strlen("AT+IPR=0\r\n") , "OK", 3);
if (rec != 0)
{
printf("波特率自适应设置失败\n");
return -1;
}
rec = ATCMDSend("AT+CMGF=1\r\n", strlen("AT+CMGF=1\r\n") , "OK", 3);
if (rec != 0)
{
printf(短信模式配置失败\n");
return -1;
}
rec = SetGSMMode();
if (rec != 0)
{
printf("字符格式设置失败\n");
return -1;
}
rec = ATCMDSend("AT+CNMI=2,1,0,0,0\r\n", strlen("AT+CNMI=2,1,0,0,0\r\n") , "OK", 3);
if(rec != 0)
{
printf("新消息提示设置失败\n");
return -1;
}
rec = SetFlashMode();
if (rec != 0)
{
printf("短信存储器选择失败\n");
return -1;
}
rec = ATCMDSend("AT+CMGD=1,4\r\n", strlen("AT+CMGD=1,4\r\n") , "OK", 5);
if (rec != 0)
{
printf("清空短消息失败\n");
return -1;
}
printf("=====message initial done!\n");
return 0;
}
3 短信读取与发送:短信接收与发送分别使用不同的线程独立完成,在接收过程中提取接收的短信号码,留作发送时使用。
短信接收线程:
void SMS_RECV(int arg)
{
int readlen ;
int timeout=0;
int ct=0;
char ATrxbuf[COMPORT_BUFSIZE]={0};
if(fcntl(usbfd, F_SETFL, FNDELAY) < 0)
{
printf("[%s:%d]>>>>error\n\n\n", __FILE__, __LINE__);
}
while(1)
{
readlen = read(usbfd, ATrxbuf+ct, COMPORT_BUFSIZE);
if(readlen > 0)
{
//printf("Thread_SMS_RECV message<<<<<<<<\n %s \n>>>>>>>>>\n", ATrxbuf);
timeout=0;
if(readlen + ct < COMPORT_BUFSIZE)
{
ct += readlen;
}
else
{
ct = 0;
bzero(ATrxbuf, COMPORT_BUFSIZE);
}
}
else
{
if((ct>0)&&(timeout > 5))//50ms once
{
//printf("ct= %d \n", ct);
//printf("readlen= %d \n", readlen);
//printf("<<<<<<ATrxbuf[]>>>>>>\n",ATrxbuf);
printf("%s \n", ATrxbuf);
//printf("<<<<<<<<END>>>>>>>>>>\n",ATrxbuf);
Msg_CheckAndSend(ATrxbuf, ct);
//AckDataAnalyse(ATrxbuf, ct);
timeout = 0;
ct = 0;
bzero(ATrxbuf, COMPORT_BUFSIZE);
}
}
timeout++;
usleep(10000);//10ms
}
}
int Msg_CheckAndSend(char *Msgdata,int len)
{
char *p1=NULL,*p2=NULL, *p3=NULL,*p4=NULL,*p5=NULL;
char Msgbuf[COMPORT_BUFSIZE]={0};
int rec=0, i=3;
unsigned int lenOfsms;
bzero(Msgbuf, COMPORT_BUFSIZE);
memcpy(Msgbuf, Msgdata, len-2);/*except "\r\n"*/
memcpy(Msgdata, Msgbuf, len-2);/*except "\r\n"*/
if ((p4 = strstr(Msgdata, "CMTI")) != NULL)
{
printf("--------------------------------------\n");
p5 = strstr(p4, ",");
if (p5 != NULL)
{
Msgindex = atoi(p5+1);
printf("MsgindexOfNewSMS>>>>>>> %d <<<<<<\n", Msgindex);
Msgflag = 1;/*means get new message*/
}
printf("--------------------------------------\n");
}
if ((p1 = strstr(Msgdata, "+CMGR:")) != NULL)
{
printf("++++++++++++++++++++++++++++++++++++++\n");
p2 = strstr(p1, "+86");
if (p2 != NULL)
{
memcpy(phonenumber, p2+3, 11);
//printf("\n p2:<<<<<<<<\n %s \n>>>>>>>>>\n", p2);//for debug
}
else
{
printf("骚扰短信或通信公司短信,不处理");
}
p3 = strstr(p1, "\n");
if (p3 != NULL)
{
bzero(Msgbuf, COMPORT_BUFSIZE);
lenOfsms = strlen(p3)-9;
memcpy(Msgbuf, p3+1, lenOfsms);//store SMS into Msgbuf
//printf("\n p3:<<<<<<<<\n %s \n>>>>>>>>>\n", p3);//for debug
#if 1 /*debug print*/
printf("PhoneNO:<<<<<<<< %s >>>>>>>>>\n", phonenumber);
printf("lenOfsms:<<<<<<<< %d >>>>>>>>>\n", lenOfsms);
printf("SMS_Detail: <<<<<<<<\n%s\n>>>>>>>>>\n", Msgbuf);
#endif
printf("######################################\n");
Msg_FixParam(Msgbuf, lenOfsms);//短信解析线程
}
}
}
短信发送线程:
void Thread_SendATcmd(int arg)
{
int rec=1;
unsigned int i=2;/*×î´ó³¢ÊÔ·¢Ë͵ĴÎÊý*/
char tempbuf[5]={0}, ATSendbuf[30]={0};
/*----------------------------------*/
// test read message
/*----------------------------------*/
while(1)
{
if (Msgflag == 1)//means recv new SMS
{
while(i--) //
{
rec = ATcmd_ReadMsg();
if (rec == 0)
break;
}
Msgflag = 0;
i = 3;
}
usleep(10*1000);//10ms
}
}
发送读取短信命令的函数:
int ATcmd_ReadMsg(void)
{
int rec;
char tempbuf[100]={0};
strcpy(tempbuf, "AT+CMGR=");
sprintf(&tempbuf[strlen(tempbuf)],"%d", Msgindex);
strcat(tempbuf, "\r\n");
//printf("send-AT-read-SMS-cmd: %s\n", tempbuf);
rec = ATCMDSend(tempbuf, strlen(tempbuf), "OK", 3);
if (rec == 0)
{
ATCMDSend("AT+CMGD=1,3\r\n", strlen("AT+CMGD=1,3\r\n") , NULL, 0);
//删除已读短信
}
return rec;
}
实现过程中参考的参考的主要代码:(功能较单一,代码简洁)
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <fcntl.h> // open() close()
#include <unistd.h> // read() write()
#include <termios.h> // set baud rate
#include <fcntl.h>
#include <sys/select.h>
#include <sys/time.h>
#include <sys/types.h>
#define FUNC_RUN 0
#define FUNC_NOT_RUN 1
#define SIMPLE_TEST 1
#define READ_SIM_CARD_ID 2
#define SHORT_MESSAGE 3
#define FUNC_QUIT 4
#define SEND_SHORT_MESSAGE 1
#define READ_SHORT_MESSAGE 2
#define CONFIG_SHORT_MESSAGE_ENV 3
#define QUIT_SHORT_MESSAGE 4
#define DEVICE_TTYS "/dev/ttyUSB4" //(有些人的文件是”/dev/ttyS0,看看你是用那个串口”自己对号入座啦!)
#define MAX_LEN_OF_SHORT_MESSAGE 140
#define RECEIVE_BUF_WAIT_1S 1
#define RECEIVE_BUF_WAIT_2S 2
#define RECEIVE_BUF_WAIT_3S 3
#define RECEIVE_BUF_WAIT_4S 4
#define RECEIVE_BUF_WAIT_5S 5
//------------------------------------- read datas from GSM/GPRS ---------------------------
// succese return 1
// error return 0
int read_GSM_GPRS_datas(int fd, char *rcv_buf,int rcv_wait)
{
int retval;
fd_set rfds;
struct timeval tv;
int ret,pos;
tv.tv_sec = rcv_wait; // wait 2.5s
tv.tv_usec = 0;
pos = 0; // point to rceeive buf
while (1)
{
FD_ZERO(&rfds);
FD_SET(fd, &rfds);
retval = select(fd+1 , &rfds, NULL, NULL, &tv);
if (retval == -1)
{
perror("select()");
break;
}
else if (retval)
{ // pan duan shi fou hai you shu ju
ret = read(fd, rcv_buf+pos, 2048);
pos += ret;
if (rcv_buf[pos-2] == '\r' && rcv_buf[pos-1] == '\n')
{
FD_ZERO(&rfds);
FD_SET(fd, &rfds);
retval = select(fd+1 , &rfds, NULL, NULL, &tv);
if (!retval) break;// no datas, break
}
}
else
{
printf("No data\n");
break;
}
}
return 1;
} // end read_GSM_GPRS_datas
//------------------------------------- send cmd ------------------------------------------// succese return 1
// error return 0
int send_GSM_GPRS_cmd(int fd, char *send_buf)
{
ssize_t ret;
ret = write(fd,send_buf,strlen(send_buf));
if (ret == -1)
{
printf ("write device %s error\n", DEVICE_TTYS);
return -1;
}
return 1;
} // end send_GSM_GPRS_cmd
//------------------------------------- send cmd and read back result ----------------------
void GSM_GPRS_send_cmd_read_result(int fd, char *send_buf, int rcv_wait)
{
char rcv_buf[2048];
if((send_buf==NULL) || (send_GSM_GPRS_cmd(fd,send_buf)))
{ // send success , then read
bzero(rcv_buf,sizeof(rcv_buf));
if (read_GSM_GPRS_datas(fd,rcv_buf,rcv_wait))
{
printf ("%s\n",rcv_buf);
}
else
{
printf ("read error\n");
}
}
else
{
printf("write error\n");
}
} // end GSM_GPRS_send_cmd_read_result
//------------------------------------- send cmd : "at" to GSM/GPRS MODEM ------------------
void GSM_simple_test(int fd)
{
char *send_buf="AT\r";
GSM_GPRS_send_cmd_read_result(fd,send_buf,RECEIVE_BUF_WAIT_1S);
} // end GSM_simple_test
//------------------------------------- send cmd : "at+ccid" to GSM/GPRS MODEM -------------
void GSM_read_sim_card_id(int fd)
{
char *send_buf="AT+CMGD=1,4\r";
GSM_GPRS_send_cmd_read_result(fd,send_buf,RECEIVE_BUF_WAIT_1S);
} // end GSM_read_sim_card_id
//------------------------------------- GSM/GPRS send short message ------------------------
void GSM_Send_Message(int fd)
{
char cmd_buf[23];
char *sendtxt_buf="AT+CMGF=1\r";
char short_message_buf[MAX_LEN_OF_SHORT_MESSAGE];
int i;
char rcv_buf;
bzero(cmd_buf,sizeof(cmd_buf));
bzero(short_message_buf,sizeof(short_message_buf));
printf ("send short message:\n");
GSM_GPRS_send_cmd_read_result(fd,sendtxt_buf,RECEIVE_BUF_WAIT_1S);
cmd_buf[0]='A';
cmd_buf[1]='T';
cmd_buf[2]='+';
cmd_buf[3]='C';
cmd_buf[4]='M';
cmd_buf[5]='G';
cmd_buf[6]='S';
cmd_buf[7]='=';
cmd_buf[8]='"';
printf ("please input telephone number:");
i = 9;
while (1)
{
cmd_buf[i]=getchar();
if (cmd_buf[i]=='\n') break;
i++;
}
cmd_buf[i]='"';
cmd_buf[i+1]='\r';
cmd_buf[i+2]='\0';
// send cmd : at+cmgs="(telephone number)"
GSM_GPRS_send_cmd_read_result(fd,cmd_buf,RECEIVE_BUF_WAIT_1S);
// input short message
printf("please input short message:");
i = 0;
while(i < MAX_LEN_OF_SHORT_MESSAGE-2)
{
short_message_buf[i] = getchar();
if (short_message_buf[i]=='\n') break;
i++;
}
short_message_buf[i] = 0x1A;
short_message_buf[i+1] = '\r';
short_message_buf[i+2] = '\0';
// send short message
GSM_GPRS_send_cmd_read_result(fd, short_message_buf,RECEIVE_BUF_WAIT_4S);
printf("\nend send short message\n");
} // end GSM_Send_Message
//------------------------------------- GSM/GPRS read all short message --------------------
void GSM_Read_Message(int fd)
{
char *send_buf="AT+CMGR=1\r"; //\"ALL\"\r";
char rcv_buf[2048];
GSM_GPRS_send_cmd_read_result(fd,send_buf,RECEIVE_BUF_WAIT_3S);
printf("end read first short message\n");
} // end GSM_Read_Message
//------------------------------------- GSM/GPRS Config short message env ------------------
void GSM_Conf_Message(int fd)
{
char *send_buf="AT+CMGF=1\r";
char *send_center_buf="AT+CSCA=\"+8613800210500\"\r";
GSM_GPRS_send_cmd_read_result(fd,send_buf,RECEIVE_BUF_WAIT_1S);
//char *sedd_buf="AT+CPMS=\"SM\"\r";
//GSM_GPRS_send_cmd_read_result(fd,send_buf,RECEIVE_BUF_WAIT_1S);
//printf("message storage in SM.");
// set short message center number
GSM_GPRS_send_cmd_read_result(fd,send_center_buf,RECEIVE_BUF_WAIT_1S);
printf("end config short message env\n");
} // end GSM_Conf_Message
//------------------------------------- GSM/GPRS short message -----------------------------
void GSM_short_mesg(int fd)
{
int flag_sm_run, flag_sm_select;
flag_sm_run = FUNC_RUN;
while (flag_sm_run == FUNC_RUN)
{
printf ("\n Select:\n");
printf ("1 : Send short message \n");
printf ("2 : Read first short message \n");
printf ("3 : Config short message env\n");
printf ("4 : quit\n");
printf (">");
scanf("%d",&flag_sm_select);
getchar();
// temp
// printf ("input select:%d\n",flag_sm_select);
// end temp
switch (flag_sm_select)
{
case SEND_SHORT_MESSAGE : { GSM_Send_Message(fd);}
case READ_SHORT_MESSAGE : { GSM_Read_Message(fd);}
case CONFIG_SHORT_MESSAGE_ENV : { GSM_Conf_Message(fd);}
case QUIT_SHORT_MESSAGE : { flag_sm_run = FUNC_NOT_RUN;}
default :
{
printf("please input your select use 1 to 3\n");
}
}
}
printf ("\n");
} // end GSM_send_mesg
//------------------------------------- print ----------------------------------------------
void print_prompt(void)
{
printf ("Select what you want to do:\n");
printf ("1 : Simple Test\n");
printf ("2 : Del all msg\n");
printf ("3 : Short message\n");
printf ("4 : Quit\n");
printf (">");
} // end print_prompt
//------------------------------------- Control GSM/GPRS MODULE ----------------------------
void func_GSM(int fd)
{
int flag_func_run;
int flag_select_func;
ssize_t ret;
flag_func_run = FUNC_RUN;
while (flag_func_run == FUNC_RUN)
{
print_prompt(); // print select functions
scanf("%d",&flag_select_func); // user input select
getchar();
switch(flag_select_func)
{
case SIMPLE_TEST : {GSM_simple_test(fd); break;}
case READ_SIM_CARD_ID : {GSM_read_sim_card_id(fd); break;}
//case MAKE_A_CALL : {GSM_call(fd); break;}
//case WAIT_A_CALL : {GSM_wait_call(fd); break;}
case SHORT_MESSAGE : {GSM_short_mesg(fd); break;}
case FUNC_QUIT :
{
flag_func_run = FUNC_NOT_RUN;
printf("Quit GSM/GPRS function. byeb");
break;
}
default :
{
printf("please input your select use 1 to 7\n");
}
}
}
}// end func_GPRS
//------------------------------------- init seriel port ----------------------------------
void init_ttyS(int fd)
{
struct termios options;
bzero(&options, sizeof(options)); // clear options
cfsetispeed(&options,B9600); // setup baud rate
cfsetospeed(&options,B9600);
options.c_cflag |= (CRTSCTS | CS8 | CLOCAL | CREAD);
options.c_iflag = IGNPAR;
tcflush(fd, TCIFLUSH);
tcsetattr(fd, TCSANOW, &options);
}//end init_ttyS
//------------------------------------- main -----------------------------------------------
int main(void)
{
int fd;
printf("\nGSM/GPRS TESTS\n\n");
// open seriel port
fd = open(DEVICE_TTYS, O_RDWR);
if (fd == -1)
{
printf("open device %s error\n",DEVICE_TTYS);
}
else
{
init_ttyS(fd); // init device
func_GSM(fd); // GSM/GPRS functions
// close ttyS0
if (close(fd)!=0) printf("close device %s error",DEVICE_TTYS);
}
return 0;
}// end main