blob: 950d3e2241ef93253efea5461c5ac74542895941 [file] [log] [blame]
#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;
}