📄 gprs.c
字号:
/* * $Id$ * EAX-400 linux实验指导书配套实验代码 * 实验3.3 GPRS通信 * Copyright (c) 2006 Beijing EFLAG Technology Co.,LTD * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */#ifndef _POSIX_SOURCE #define _POSIX_SOURCE#endif #include <stdio.h>#include <stdlib.h>#include <string.h>#include <unistd.h>#include <pthread.h>#include <fcntl.h>#include <errno.h>#include <signal.h>#include <sys/ioctl.h>#include <linux/limits.h>#include <termios.h> #include "gprs.h"#include "eax400lab_error.h"#define DEF_BBAUD B9600 /* SIM100-S默认的波特率 */#define DEF_GPRS_DEV "/dev/ttyS4"#define GPRS_SEND_BUF_SZ 4096#define GPRS_RECV_BUF_SZ 4096#define QBUF_READ_SZ 1024#define QBUF_WRITE_SZ 1024#define DEF_TIMEOUT_SEC 100#define DEF_CMD NULL static struct gprs_stat gprs = { name: "SIM100-S GPRS Module", fds: -1,};static unsigned int msg_over; /* 短消息发送结束标志 *//* 显示帮助信息 */static void usage(char *prog){ fprintf(stdout, "usage:\n\t%s: -d <dev> [-b <baud>]\n", prog); }static int to_Bbaud(unsigned int baud) { int Bbaud; switch (baud) { case 0: /* default */ Bbaud = DEF_BBAUD; break; case 300: Bbaud = B300; break; case 1200: Bbaud = B1200; break; case 2400: Bbaud = B2400; break; case 4800: Bbaud = B4800; break; case 9600: Bbaud = B9600; break; case 19200: Bbaud = B19200; break; case 38400: Bbaud = B38400; break; case 57600: Bbaud = B57600; break; case 115200: Bbaud = B115200; break; default: pr_error("Invalid baud setting %d.\n", baud); return -1; } return Bbaud;} /* * 初始化串口 */static int init_serial(char *dev, unsigned int baud, struct termios *oldsterm){ int fds; long vdisable; struct termios sterm; speed_t Bbaud; if (!oldsterm) { pr_error("Invalid termios."); return -1; } /* 将输入的波特率转换为BXXX宏,同时进行参数检查 */ Bbaud = to_Bbaud(baud); if (Bbaud < 0) return -1; fds = open(dev, O_RDWR | O_NOCTTY); if (fds < 0) { pr_error("open serial device %s error occured", dev); return -1; } if ((vdisable = fpathconf(fds, _PC_VDISABLE)) < 0) { close(fds); pr_error("fpathconf() for serial device %s error", dev); return -1; } if (!isatty(fds)) { close(fds); pr_error("device %s is not a tty device", dev); return -1; } if (!isatty(STDIN_FILENO)) { close(fds); pr_error("stdin is not a tty device"); return -1; } if (!isatty(STDOUT_FILENO)) { close(fds); pr_error("stdout is not a tty device"); return -1; } /* 获得终端属性 */ if (tcgetattr(fds, oldsterm)) { close(fds); pr_error("Can't get serial device %s tc attribute", dev); return -1; } #if 1 bzero(&sterm, sizeof(sterm)); sterm.c_cc[VERASE] = vdisable; sterm.c_cc[VKILL] = vdisable; sterm.c_cc[VEOF] = vdisable; sterm.c_cc[VEOL] = vdisable; sterm.c_cc[VEOL2] = vdisable; sterm.c_cc[VREPRINT] = vdisable; sterm.c_cc[VWERASE] = vdisable; sterm.c_cc[VLNEXT] = vdisable; sterm.c_cc[VSUSP] = vdisable; /* 为发送短信而保留^z */ sterm.c_cflag = (Bbaud | CS8 | CLOCAL | CREAD); sterm.c_iflag = (IGNPAR | IGNBRK); sterm.c_oflag = (OPOST | ONLCR); /* 向GPRS发出的AT命令应该以\r\n结尾(0xd 0xa) */ sterm.c_lflag = (ICANON); /* 应用新的终端设置 */ if (tcsetattr(fds, TCSAFLUSH, &sterm)) { tcsetattr(fds, TCSANOW, oldsterm); close(fds); pr_error("Can't set serial device %s tc attribute", dev); return -1; }#endif //tcflush(fds, TCIOFLUSH); gprs.fds = fds; return fds;}/* 恢复串口的默认设置 */static int reset_serial(void){ int fds; fds = gprs.fds; gprs.fds = -1; tcsetattr(fds, TCSANOW, &gprs.oldsterm); close(fds);}/* * 这个函数对串口也进行了初始化。 */int init_gprs(char *dev, unsigned int baud){ int fds; fds = init_serial(dev, baud, &gprs.oldsterm); if (fds < 0) return -1; gprs.sbuf = malloc(GPRS_SEND_BUF_SZ); if (!gprs.sbuf) { reset_serial(); pr_error("allocate send buffer failed"); return -1; } gprs.rbuf = malloc(GPRS_RECV_BUF_SZ); if (!gprs.rbuf) { reset_serial(); free(gprs.sbuf); pr_error("allocate receive buffer failed"); return -1; } gprs.serialdev = dev; gprs.baudspeed = baud; gprs.timeout = DEF_TIMEOUT_SEC; //gprs.cmd = DEF_CMD; //sc_syncmode(fds, "0"); //sc_autostart(fds, CT_SETPARM, "0"); //sc_testgprs(fds); //sc_stop(fds); //sc_start(fds); return 0;}void kill_gprs(void){ } int main(int argc, char *argv[]){ int optch; char *dev = DEF_GPRS_DEV; const char optstring[] = "d:b:"; unsigned int baud = 0; pthread_t tidrr, tidrs; /* 参数检查 */ while ((optch = getopt(argc, argv, optstring)) != -1) switch (optch) { case 'd': dev = optarg; break; case 'b': baud = atoi(optarg); break; default: printf("unknown option -%c.\n", optch); usage(argv[0]); return -1; } if (init_gprs(dev, baud) < 0) return -1; fprintf(stdout, "%s initilizing ...\n", gprs.name); if (pthread_create(&tidrs, NULL, (void *(*)(void *))write_to_serial, &gprs) < 0) { reset_serial(); free(gprs.rbuf); free(gprs.sbuf); pr_error("Can't create send thread."); return -1; } if (pthread_create(&tidrr, NULL, (void *(*)(void *))read_from_serial, &gprs) < 0) { // TODO: kill send thread reset_serial(); free(gprs.rbuf); free(gprs.sbuf); pr_error("Can't create send thread."); return -1; } pthread_join(tidrr, NULL); fprintf(stdout, "%s exiting ...\n", gprs.name); return 0;}/* * * 从串口读数据到gprs->bufs中. * 注意:该函数会调用parse_msg()和parse_cmd()来解析数据。目前仅对???$GPGGA, $GPGSA, $GPGSV, $GPRMC 这4种消息 * 进行解析。 * * 返回值: * 大于0:成功从串口读取的字节数 * -1: 出错 * */int read_from_serial(struct gprs_stat *gprs){ ssize_t nr; int fds = gprs->fds; char *rbuf = gprs->rbuf;// unsigned int k; static unsigned int read_serial_seq = 0; while (1) { if ((nr = read(fds, rbuf, GPRS_RECV_BUF_SZ)) > 0) { read_serial_seq++; if (nr == GPRS_RECV_BUF_SZ) rbuf[nr - 1] = '\0'; else rbuf[nr] = '\0'; fprintf(stdout, "%s\n", rbuf); //pr_debug("[%d gprs ack %d bytes]\n%s\n", read_serial_seq, // nr, rbuf); //pr_debug("[%d dump gprs ack]\n", read_serial_seq); //for (k = 0; k < nr; k++) // pr_debug("%02x ", rbuf[k]); //pr_debug("\n"); } if (nr < 0) { pr_error("read from serial error occuren"); break; } if (!nr) pr_error("read serial EOF!"); }; //gprs->nread = nr; return nr;}static void gprs_menu(void){ fprintf(stdout, "[0] give a call\n"); fprintf(stdout, "[1] respond a call\n"); fprintf(stdout, "[2] hold a call\n"); fprintf(stdout, "[3] send a msg\n"); fprintf(stdout, "[4] recv a msg\n"); }static void gprs_shell(void){ fprintf(stdout, "gprs control shell > "); fflush(stdout); }static void gprs_at_shell(void){ fprintf(stdout, "gprs AT shell > "); fflush(stdout); }#define GPRS_CMD_SZ 128static inline ssize_t get_line(char *cmd){ return read(STDIN_FILENO, cmd, GPRS_CMD_SZ);} static void gprs_call(char *number, int num){ number[num - 1] = '\0'; sprintf(gprs.sbuf, "atd%s;\n", number); write(gprs.fds, gprs.sbuf, strlen(gprs.sbuf));}static void gprs_hold_call(void){ sprintf(gprs.sbuf, "ath\n"); write(gprs.fds, gprs.sbuf, strlen(gprs.sbuf)); }static void gprs_accept_call(void){ sprintf(gprs.sbuf, "ata\n"); write(gprs.fds, gprs.sbuf, strlen(gprs.sbuf)); }static void sigtstp_handler(int signum){ fprintf(stdout, "write message over...\n"); msg_over = 1; }static void gprs_send_message(void){ char buf[GPRS_CMD_SZ]; ssize_t num; if (signal(SIGTSTP, SIG_IGN) != SIG_IGN) { if (signal(SIGTSTP, sigtstp_handler) == SIG_ERR) { perror("signal(SIGTSTP)"); return; } } sprintf(gprs.sbuf, "at+cmgf=1\n"); write(gprs.fds, gprs.sbuf, strlen(gprs.sbuf)); fprintf(stdout, "Please input number: "); fflush(stdout); get_line(buf); num = strlen(buf); buf[num - 1] = '\0'; sprintf(gprs.sbuf, "at+cmgs=%s\n", buf); write(gprs.fds, gprs.sbuf, strlen(gprs.sbuf)); //msg_over = 0; while ((num = read(STDIN_FILENO, buf, GPRS_CMD_SZ)) > 0) { write(gprs.fds, gprs.sbuf, num); if (msg_over) { char stp = 0x1a; /* ^z */ write(gprs.fds, &stp, 1); msg_over = 0; break; } } signal(SIGTSTP, SIG_DFL); } /* * * 向串口写数据。 * * 返回值: * 大于0:成功写入串口的字节数 * -1: 出错 * */int write_to_serial(struct gprs_stat *gprs){ int fds = gprs->fds; char *sbuf = gprs->sbuf; //unsigned int k; static unsigned int input_seq = 0; char cmd[GPRS_CMD_SZ]; //tcflush(STDIN_FILENO, TCIOFLUSH); while (1) { gprs_menu(); gprs_shell(); get_line(cmd); if (!strncmp("0", cmd, 1)) { fprintf(stdout, "\nplease input number: "); fflush(stdout); get_line(cmd); gprs_call(cmd, strlen(cmd)); fprintf(stdout, "calling... wait for a moment\n"); fflush(stdout); sleep(3); } else if (!strncmp("1", cmd, 1)) { fprintf(stdout, "accept the call...\n"); gprs_accept_call(); } else if (!strncmp("2", cmd, 1)) { fprintf(stdout, "hold the call...\n"); fflush(stdout); gprs_hold_call(); } else if (!strncmp("3", cmd, 1)) { fprintf(stdout, "send a message...\n"); fflush(stdout); gprs_send_message(); } else if (!strncmp("4", cmd, 1)) { fprintf(stdout, "recv a message...\n"); fflush(stdout); } else { /* 原始AT命令模式 */ ssize_t nr; gprs_at_shell(); if ((nr = read(STDIN_FILENO, sbuf, GPRS_SEND_BUF_SZ)) > 0) { input_seq++; //pr_debug("[%d input %dbytes]\n\"%s\"\n", input_seq, nr, sbuf); //pr_debug("[%d dump input]\n", input_seq); //for (k = 0; k < nr; k++) // pr_debug("%02x ", sbuf[k]); //pr_debug("\n"); write(fds, sbuf, nr); } if (nr == -1) { perror("read() from stdin error"); break; } if (!nr) perror("stdin tty dev is EOF\n"); } } return -1;}/* * * 当程序运行结束时应该调用这个函数,恢复串口的原始设置 * * 返回值: * 0: 成功 * -1: 出错 * */int recover_serial(struct gprs_stat *gprs) // 线程交互时需要这个函数{ if (tcsetattr(gprs->fds, TCSAFLUSH, &gprs->oldsterm) == -1) { pr_error("set old serial tc attribute error"); return -1; } return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -