| #include <termios.h> |
| #include <pthread.h> |
| #include <sys/un.h> |
| #include <stdio.h> |
| #include <sys/socket.h> |
| #include <errno.h> |
| #include <stdlib.h> |
| #include <fcntl.h> |
| #include <string.h> |
| #include <sys/epoll.h> |
| #include <netinet/in.h> |
| #include <signal.h> |
| #include <unistd.h> |
| #include <sys/select.h> |
| |
| #include "mbtk_type.h" |
| |
| //#define AT_TYPE_SOCKET |
| #define MBTK_LOG |
| |
| #ifdef MBTK_LOG |
| #include "mbtk_log.h" |
| #else |
| #define LOGE printf |
| #define LOGD printf |
| #define LOGV printf |
| #define LOGI printf |
| #endif |
| |
| #define DATABITS CS8 |
| #define STOPBITS 0 |
| #define PARITYON 0 |
| #define PARITY 0 |
| |
| typedef enum { |
| AT_MODE_SOCK_1 = 0, |
| AT_MODE_SOCK_2, |
| AT_MODE_DEV_1, |
| AT_MODE_DEV_2 |
| } at_mode_enum; |
| |
| static int epoll_fd = -1; |
| static struct epoll_event epoll_events[20]; |
| static int at_fd = -1; |
| static at_mode_enum at_mode = AT_MODE_SOCK_1; |
| |
| static char *at_rsp_complete_tag[] = { |
| "OK", |
| "ERROR", |
| "CONNECT", |
| "+CMS ERROR:", |
| "+CME ERROR:", |
| "NO ANSWER", |
| "NO DIALTONE", |
| NULL}; |
| |
| //#ifdef AT_TYPE_SOCKET |
| #define TEMP_FAILURE_RETRY(exp) ({ \ |
| typeof (exp) _rc; \ |
| do { \ |
| _rc = (exp); \ |
| } while (_rc == -1 && errno == EINTR); \ |
| _rc; }) |
| //#endif |
| |
| static void at_epoll_change(int is_add,int fd) |
| { |
| struct epoll_event ev; |
| memset(&ev,0x0,sizeof(struct epoll_event)); |
| ev.data.fd = fd; |
| ev.events = EPOLLIN | EPOLLET; |
| if(is_add) |
| { |
| epoll_ctl(epoll_fd,EPOLL_CTL_ADD,fd,&ev); |
| } |
| else |
| { |
| epoll_ctl(epoll_fd,EPOLL_CTL_DEL,fd,&ev); |
| } |
| } |
| |
| static int at_set_fd_noblock(int fd) |
| { |
| // Set O_NONBLOCK |
| int flags = fcntl(fd, F_GETFL, 0); |
| if (flags < 0) { |
| LOGE("Get flags error:%s\n", strerror(errno)); |
| return -1; |
| } |
| flags |= O_NONBLOCK; |
| if (fcntl(fd, F_SETFL, flags) < 0) { |
| LOGE("Set flags error:%s\n", strerror(errno)); |
| return -1; |
| } |
| |
| return 0; |
| } |
| |
| //#ifdef AT_TYPE_SOCKET |
| int openSocket(const char* sockname) |
| { |
| int sock = socket(AF_UNIX, SOCK_STREAM, 0); |
| if (sock < 0) { |
| LOGE("Error create socket: %s\n", strerror(errno)); |
| return -1; |
| } |
| struct sockaddr_un addr; |
| memset(&addr, 0, sizeof(addr)); |
| addr.sun_family = AF_UNIX; |
| strncpy(addr.sun_path, sockname, sizeof(addr.sun_path)); |
| while (TEMP_FAILURE_RETRY(connect(sock,(const struct sockaddr*)&addr, sizeof(addr))) != 0) { |
| LOGE("Error connect to socket %s: %s, try again", sockname, strerror(errno)); |
| sleep(1); |
| } |
| |
| #if 0 |
| int sk_flags = fcntl(sock, F_GETFL, 0); |
| fcntl(sock, F_SETFL, sk_flags | O_NONBLOCK); |
| #endif |
| |
| return sock; |
| } |
| |
| //#else |
| |
| static int at_open(char *dev) |
| { |
| // Init USB PC port. |
| struct termios ser_settings; |
| int fd = -1; |
| |
| usb_pc_init: |
| fd = open(dev,O_RDWR); |
| if(fd <= 0) |
| { |
| if(errno == ENODEV) |
| { |
| LOGD("Wait dev[%s] ready...",dev); |
| usleep(500000); |
| goto usb_pc_init; |
| } |
| |
| LOGE("Cannot open USB PC port[%s] - [errno = %d]",dev,errno); |
| return -1; |
| } |
| |
| tcgetattr(fd, &ser_settings); |
| cfmakeraw(&ser_settings); |
| //ser_settings.c_lflag |= (ECHO | ECHONL); |
| //ser_settings.c_lflag &= ~ECHOCTL; |
| tcsetattr(fd, TCSANOW, &ser_settings); |
| |
| #if 0 |
| if(at_set_fd_noblock(at_fd)) |
| { |
| LOGE("at_set_fd_noblock() fail."); |
| return -1; |
| } |
| |
| at_epoll_change(1, at_fd); |
| #endif |
| |
| return fd; |
| } |
| //#endif |
| |
| static int adb_port_open(const char *dev, unsigned int baud) |
| { |
| int fd; |
| |
| while((fd = open(dev, O_RDWR)) < 0) |
| { |
| printf("%s: open %s failed\n", __func__, dev); |
| sleep(1); |
| } |
| |
| /* set newtio */ |
| struct termios newtio; |
| memset(&newtio, 0, sizeof(newtio)); |
| #if 0 |
| (void)fcntl(fd, F_SETFL, 0); |
| newtio.c_cflag = BAUD | DATABITS | STOPBITS | PARITYON | PARITY | CLOCAL | CREAD; |
| newtio.c_iflag = IGNPAR; |
| newtio.c_oflag = 0; |
| newtio.c_lflag = 0; /* disable ECHO, ICANON, etc... */ |
| |
| newtio.c_cc[VERASE] = 0x8; /* del */ |
| newtio.c_cc[VEOF] = 4; /* Ctrl-d */ |
| newtio.c_cc[VMIN] = 1; /* blocking read until 1 character arrives */ |
| newtio.c_cc[VEOL] = 0xD; /* '\0' */ |
| |
| tcflush(fd, TCIFLUSH); |
| tcsetattr(fd, TCSANOW, &newtio); |
| #else |
| if (tcflush(fd, TCIOFLUSH) < 0) { |
| printf("Could not flush uart port\n"); |
| return -1; |
| } |
| |
| newtio.c_cc[VTIME] = 0; /* inter-character timer unused */ |
| newtio.c_cc[VMIN] = 1; /* blocking read until 5 chars received */ |
| newtio.c_cflag |= (CS8 | CLOCAL | CREAD); |
| newtio.c_iflag = IGNPAR; |
| newtio.c_oflag = 0; |
| newtio.c_lflag = 0; |
| |
| int rate = baud; // Default bitrate. |
| switch(rate) |
| { |
| case 300: |
| cfsetospeed(&newtio, B300); |
| cfsetispeed(&newtio, B300); |
| break; |
| case 600: |
| cfsetospeed(&newtio, B600); |
| cfsetispeed(&newtio, B600); |
| break; |
| case 1200: |
| cfsetospeed(&newtio, B1200); |
| cfsetispeed(&newtio, B1200); |
| break; |
| case 2400: |
| cfsetospeed(&newtio, B2400); |
| cfsetispeed(&newtio, B2400); |
| break; |
| case 4800: |
| cfsetospeed(&newtio, B4800); |
| cfsetispeed(&newtio, B4800); |
| break; |
| case 9600: |
| cfsetospeed(&newtio, B9600); |
| cfsetispeed(&newtio, B9600); |
| break; |
| case 19200: |
| cfsetospeed(&newtio, B19200); |
| cfsetispeed(&newtio, B19200); |
| break; |
| case 38400: |
| cfsetospeed(&newtio, B38400); |
| cfsetispeed(&newtio, B38400); |
| break; |
| case 57600: |
| cfsetospeed(&newtio, B57600); |
| cfsetispeed(&newtio, B57600); |
| break; |
| case 115200: |
| cfsetospeed(&newtio, B115200); |
| cfsetispeed(&newtio, B115200); |
| break; |
| case 230400: |
| cfsetospeed(&newtio, B230400); |
| cfsetispeed(&newtio, B230400); |
| break; |
| case 460800: |
| cfsetospeed(&newtio, B460800); |
| cfsetispeed(&newtio, B460800); |
| break; |
| case 921600: |
| cfsetospeed(&newtio, B921600); |
| cfsetispeed(&newtio, B921600); |
| break; |
| case 1500000: |
| cfsetospeed(&newtio, B1500000); |
| cfsetispeed(&newtio, B1500000); |
| break; |
| case 2000000: |
| cfsetospeed(&newtio, B2000000); |
| cfsetispeed(&newtio, B2000000); |
| break; |
| case 3000000: |
| cfsetospeed(&newtio, B3000000); |
| cfsetispeed(&newtio, B3000000); |
| break; |
| case 4000000: |
| cfsetospeed(&newtio, B4000000); |
| cfsetispeed(&newtio, B4000000); |
| break; |
| default: |
| cfsetospeed(&newtio, B115200); |
| cfsetispeed(&newtio, B115200); |
| break; |
| } |
| |
| if (tcsetattr(fd, TCSANOW, &newtio) < 0) { |
| printf("Can't set port setting\n"); |
| return -1; |
| } |
| /* Blocking behavior */ |
| fcntl(fd, F_SETFL, 0); |
| #endif |
| |
| return fd; |
| } |
| |
| |
| static void signal_process(int signal_num) { |
| if(at_fd > 0) { |
| close(at_fd); |
| } |
| #ifdef MBTK_LOG |
| LOGD("Exit by sig - %d\n", signal_num); |
| #endif |
| exit(0); |
| } |
| |
| static void* read_thread_run( void *arg) |
| { |
| //UNUSED(arg); |
| |
| char at_rsp[1024]; |
| char *ptr; |
| int index; |
| int len; |
| while(at_fd > 0) { |
| memset(at_rsp, 0x0, 1024); |
| index = 0; |
| len = 0; |
| while(1) { |
| if((len = read(at_fd, at_rsp + index, 1024)) > 0) { |
| ptr = at_rsp; |
| while(*ptr == '\r' || *ptr == '\n') |
| { |
| ptr++; |
| } |
| if(strlen(ptr) > 0 && ptr[strlen(ptr) - 1] == '\n') { |
| printf("<%s\n", ptr); |
| #ifdef MBTK_LOG |
| LOGV("RSP:%s", ptr); |
| #endif |
| |
| break; |
| } else { |
| index += len; |
| } |
| } else { |
| LOGE("Read error:%d",errno); |
| return NULL; |
| } |
| } |
| } |
| |
| LOGD("read_thread_run() exit.\n"); |
| return NULL; |
| } |
| |
| static int read_thread_start() |
| { |
| pthread_t tid; |
| pthread_attr_t attr; |
| pthread_attr_init (&attr); |
| pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); |
| int ret = pthread_create(&tid, &attr, read_thread_run, &attr); |
| if (ret < 0) |
| { |
| LOGE("pthread_create\n"); |
| return -1; |
| } |
| |
| return 0; |
| } |
| |
| static int at_complete(char *rsp) |
| { |
| #if 0 |
| char *ptr = at_rsp_complete_tag; |
| while(ptr) { |
| LOGD("ptr = %s", ptr); |
| if(strstr(rsp, ptr)) { |
| LOGD("%s , %s", rsp, ptr); |
| return 1; |
| } |
| ptr++; |
| } |
| #else |
| int i = 0; |
| while(at_rsp_complete_tag[i]) { |
| LOGD("ptr = %s", at_rsp_complete_tag[i]); |
| if(strstr(rsp, at_rsp_complete_tag[i])) { |
| LOGD("%s , %s", rsp, at_rsp_complete_tag[i]); |
| return 1; |
| } |
| i++; |
| } |
| |
| #endif |
| return 0; |
| } |
| |
| static void at_rsp_read() |
| { |
| char at_rsp[1024]; |
| int len = 0; |
| while(1) { |
| memset(at_rsp, 0x0, 1024); |
| if((len = read(at_fd, at_rsp, 1024)) > 0) { |
| printf("%s", at_rsp); |
| if(at_complete(at_rsp)) { |
| break; |
| } |
| } else { |
| printf("Read error:%d\n",errno); |
| break; |
| } |
| } |
| } |
| |
| static void help() |
| { |
| printf("at : Enter AT mode(Socket).\n"); |
| printf("at <at_cmd>: Send AT command(Socket).\n"); |
| printf("at <dev>: Enter AT mode(Device).\n"); |
| printf("at <dev> echo: ´®¿ÚÊý¾Ý»ØÏÔ¡£\n"); |
| printf("at <dev> <at_cmd>: Send AT command(Device).\n"); |
| } |
| |
| static void sig_process(int sig) |
| { |
| LOGI("I got signal %d\n", sig); |
| switch(sig) |
| { |
| case SIGINT: // Ctrl + C |
| { |
| LOGI("Exit by SIGINT.\n"); |
| exit(0); |
| } |
| case SIGQUIT: // Ctrl + \ (ÀàËÆ SIGINT £¬µ«Òª²úÉúcoreÎļþ) |
| { |
| LOGI("Exit by SIGQUIT.\n"); |
| exit(0); |
| } |
| case SIGTERM:// ĬÈÏkill (ͬ SIGKILL £¬µ« SIGKILL ²»¿É²¶»ñ) |
| { |
| LOGI("Exit by SIGTERM.\n"); |
| exit(0); |
| } |
| case SIGTSTP:// Ctrl + Z (ͬ SIGSTOP £¬µ« SIGSTOP ²»¿É²¶»ñ) |
| { |
| LOGI("Exit by SIGTSTP.\n"); |
| exit(0); |
| } |
| case SIGSEGV: // Èç¿ÕÖ¸Õë |
| { |
| LOGI("Exit by SIGSEGV.\n"); |
| exit(0); |
| } |
| default: |
| { |
| LOGI("Unknown sig:%d\n",sig); |
| break; |
| } |
| } |
| } |
| |
| int main(int argc, char *argv[]) |
| { |
| //UNUSED(argc); |
| //UNUSED(argv); |
| signal(SIGINT, sig_process); |
| signal(SIGQUIT, sig_process); |
| signal(SIGTERM, sig_process); |
| //signal(SIGTSTP, sig_process); |
| //signal(SIGSEGV, sig_process); |
| |
| #ifdef MBTK_LOG |
| mbtk_log_init("radio", "MBTK_AT"); |
| LOGI("mbtk_at start."); |
| #endif |
| |
| signal(SIGKILL, signal_process); |
| signal(SIGINT, signal_process); |
| signal(SIGQUIT, signal_process); |
| signal(SIGTERM, signal_process); |
| |
| char *at_cmd = NULL; |
| bool echo = FALSE; |
| if(argc == 1) { |
| at_mode = AT_MODE_SOCK_1; |
| } else if(argc == 2) { |
| if(!strncasecmp(argv[1], "at", 2)) { |
| at_mode = AT_MODE_SOCK_2; |
| at_cmd = argv[1]; |
| } else if(!strncasecmp(argv[1], "/dev/", 5)) { |
| at_mode = AT_MODE_DEV_1; |
| } else { |
| help(); |
| return -1; |
| } |
| } else if(argc == 3) { |
| if(!strncasecmp(argv[1], "/dev/", 5) && (!strncasecmp(argv[2], "at", 2) || !strncasecmp(argv[2], "echo", 4))) { |
| at_mode = AT_MODE_DEV_2; |
| if(!strncasecmp(argv[2], "at", 2)) { |
| at_cmd = argv[2]; |
| } else { |
| echo = TRUE; |
| } |
| } else { |
| help(); |
| return -1; |
| } |
| } else { |
| help(); |
| return -1; |
| } |
| #if 0 |
| #ifdef AT_TYPE_SOCKET |
| at_fd = openSocket("/tmp/atcmdmbtk"); |
| #else |
| at_fd = at_open(argv[1]); |
| #endif |
| if(at_fd > 0) { |
| #ifdef AT_TYPE_SOCKET |
| if(argc > 1) { |
| char *at_cmd = argv[1]; |
| #else |
| if(argc > 2) { |
| char *at_cmd = argv[2]; |
| #endif |
| #endif |
| |
| if(at_mode == AT_MODE_SOCK_1 || at_mode == AT_MODE_SOCK_2) { |
| at_fd = openSocket("/tmp/atcmdmbtk"); |
| } else { |
| #if 0 |
| at_fd = at_open(argv[1]); |
| #else |
| if(echo) { |
| at_fd = adb_port_open(argv[1], 115200); |
| } else { |
| at_fd = at_open(argv[1]); |
| } |
| #endif |
| } |
| if(at_fd > 0) { |
| if(at_cmd != NULL) { |
| char *ptr = at_cmd + strlen(at_cmd) - 1; |
| while(ptr >= at_cmd && (*ptr == '\r' || *ptr == '\n')) |
| { |
| *ptr-- = '\0'; |
| } |
| // printf("AT:[%ld]%s\n", strlen(at_cmd), at_cmd); |
| if(!strncasecmp(at_cmd, "at", 2)) |
| { |
| *(++ptr) = '\r'; |
| *(++ptr) = '\n'; |
| if(write(at_fd, at_cmd, strlen(at_cmd)) <= 0) { |
| printf("Write error:%d\n", errno); |
| } else { |
| // Read response. |
| at_rsp_read(); |
| } |
| } else { |
| printf("AT error!\n"); |
| } |
| } else { |
| if(echo) { |
| char read_buff[1024]; |
| char write_buff[1024]; |
| int len; |
| #if 0 |
| fd_set fds; |
| int fdcount, nfds = 0; |
| while(1) { |
| FD_SET(at_fd, &fds); |
| if(at_fd > nfds) |
| nfds = at_fd; |
| |
| fdcount = select(nfds + 1, &fds, NULL, NULL, NULL); |
| if(fdcount < 0) /* error */ |
| { |
| printf("select returned %d, errno %d, continue\r", fdcount, errno); |
| sleep(1); |
| continue; |
| } |
| |
| if(FD_ISSET(at_fd, &fds)) |
| { |
| FD_CLR(at_fd, &fds); |
| memset(read_buff, 0x0, 1024); |
| if((len = read(at_fd, read_buff, 1024)) > 0) { |
| memset(write_buff, 0x0, 1024); |
| printf("%s\n", read_buff); |
| len = snprintf(write_buff, 1024, "%s\n", read_buff); |
| write(at_fd, write_buff, len); |
| } else { |
| printf("Read error:%d\n",errno); |
| return NULL; |
| } |
| } |
| } |
| #else |
| printf("Waitting data!!!\n"); |
| while(1) { |
| memset(read_buff, 0x0, 1024); |
| if((len = read(at_fd, read_buff, 1024)) > 0) { |
| memset(write_buff, 0x0, 1024); |
| printf("%s\n", read_buff); |
| len = snprintf(write_buff, 1024, "%s\n", read_buff); |
| write(at_fd, write_buff, len); |
| } else { |
| printf("Read error:%d\n",errno); |
| return NULL; |
| } |
| } |
| #endif |
| } else { |
| setbuf(stdout, NULL); |
| read_thread_start(); |
| char at_cmd[100]; |
| //printf(">>"); |
| while(1) |
| { |
| memset(at_cmd, 0x0, 100); |
| if(fgets(at_cmd, 100, stdin)) |
| { |
| char *ptr = at_cmd + strlen(at_cmd) - 1; |
| while(ptr >= at_cmd && (*ptr == '\r' || *ptr == '\n')) |
| { |
| *ptr-- = '\0'; |
| } |
| // printf("AT:[%ld]%s\n", strlen(at_cmd), at_cmd); |
| if(!strncasecmp(at_cmd, "at", 2)) |
| { |
| *(++ptr) = '\r'; |
| *(++ptr) = '\n'; |
| if(write(at_fd, at_cmd, strlen(at_cmd)) <= 0) { |
| LOGE("Write error:%d",errno); |
| break; |
| } |
| printf(">%s",at_cmd); |
| #ifdef MBTK_LOG |
| LOGV("AT:%s",at_cmd); |
| #endif |
| } else if(!strcasecmp(at_cmd, "q")) { |
| break; |
| } else { |
| printf("\n"); |
| } |
| } |
| } |
| } |
| } |
| |
| close(at_fd); |
| |
| #ifdef MBTK_LOG |
| LOGD("EXIT"); |
| #endif |
| } |
| |
| return 0; |
| } |