/*
** Soft:Daocaoren Name:马上有房 qq:168620188
*/
#ifndef _UART_H_
#define _UART_H_
#include <stdio.h>
#include <assert.h> 
#include <sys/time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <termios.h>
#include <string.h>
#include <unistd.h>
#include <stdarg.h>
#include <sys/select.h>
#include <ctype.h>
#include <time.h>
#include <errno.h>
#include <getopt.h>
#include <signal.h>
#include <stdlib.h>
// #include "pdu.h"


#define MAX_PORTS	4
/*this array hold information about each port we have opened */
struct PortInfo {
    char name[16];
    int  port_fd;
};
int serial_init(int port, int spd, int databits, int parity, \
						int stopbits, int RTSCTS, int need_line_input);
int serial_write(int fd, void *src, int len);
int serial_read(int fd, char *buf, int len);
int serial_recv(int fd,char *rbuf,int rbuf_len, int timeout);
//串口常用初始化接口
#define serial_com_init(port, spd, databits, parity, stopbits)\
		serial_init(port, spd, databits, parity, stopbits, 0, 0)
//串口默认初始化接口
#define serial_def_init(port, spd) serial_init(port, spd, 8, 'n', 1, 0, 1)
#endif



/*
** File: uart.c
**
** Description:
** Provides an RS-232 interface that is very similar to the CVI provided
** interface library
*/
/*this array hold information about each port we have opened */
struct PortInfo ports[13] = 
{
	{"/dev/ttyUSB0", 0},
	{"/dev/ttyUSB1", 0},
	{"/dev/ttyUSB2", 0}, 
	{"/dev/ttyUSB3", 0},
	{"/dev/ttyUSB4", 0},
	{"/dev/ttyUSB5", 0},
	{"/dev/ttyUSB6", 0},
	{"/dev/ttyUSB7", 0},
	{"/dev/ttyUSB8", 0},
	{"/dev/ttyUSB9", 0},
	{"/dev/ttyUSB10", 0},
	{"/dev/ttyUSB11", 0},
	{"/dev/ttyUSB12", 0},
};
FILE*  pf;
FILE*  pfi;
int spd_arr[] = {B2000000, B1500000, B576000, B500000, B460800, B230400, B115200, B57600, B38400, B19200, B9600, B4800, B2400};
int name_arr[] = { 2000000, 1500000,  576000,  500000,  460800,  230400,  115200,  57600,  38400,  19200,  9600,  4800,  2400 };
/**
*@brief  设置串口通信速率
*@param  fd    类型 int 打开串口的文件句柄
*@param  speed 类型 int 串口速度
*@return  void
*/
int set_speed(int fd, int speed)
{
	int   i; 
	int   status; 
	struct termios Opt;
	tcgetattr(fd, &Opt); 
	for ( i= 0;  i < sizeof(spd_arr) / sizeof(int);  i++) { 
		if(speed == name_arr[i]) {
			tcflush(fd, TCIOFLUSH);     
			cfsetispeed(&Opt, spd_arr[i]);  
			cfsetospeed(&Opt, spd_arr[i]);   
			status = tcsetattr(fd, TCSANOW, &Opt);  
			if  (status != 0) {        
				printf("tcsetattr failed");  
				return 1;     
			}
			tcflush(fd,TCIOFLUSH);   
		}
	}
	// printf("set_speed\n");
	return 0;
}

/**
*@brief  设置串口数据位，停止位和效验位
*@param  fd       类型  int 打开的串口文件句柄
*@param  databits 类型  int 数据位   取值为 7 或者8
*@param  stopbits 类型  int 停止位   取值为 1 或者2
*@param  parity   类型  int 效验类型 取值为N,E,O,,S
*/
int set_Parity(int fd, int databits, int parity, int stopbits, int RTSCTS)
{ 
	struct termios options; 
	if  ( tcgetattr( fd,&options)  !=  0) { 
		perror("SetupSerial 1");     
		return -1;  
	}
	options.c_cflag &= ~CSIZE; 
	switch (databits) /*设置数据位数*/
	{   
	case 7:		
		options.c_cflag |= CS7; 
		break;
	case 8:     
		options.c_cflag |= CS8;
		break;   
	default:    
		fprintf(stderr,"Unsupported data size\n"); 
        return -1;  
	}

    options.c_iflag |= INPCK;
    cfmakeraw(&options);
    //options.c_lflag |= (ICANON | ECHO | ECHOE);
    //options.c_lflag &= ~(ICANON | ECHO | ECHOE);
    //options.c_iflag &= ~(IXON | IXOFF);
	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':     
			options.c_cflag |= (PARODD | PARENB); /* 设置为奇效验*/  
			break;  
		case 'e':  
		case 'E':   
			options.c_cflag |= PARENB;     /* Enable parity */    
			options.c_cflag &= ~PARODD;   /* 转换为偶效验*/     
			break;
		case 'S': 
		case 's':  /*as no parity*/   
		    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 rts/cts */ 
	if (RTSCTS)
	{
	    printf("Set rts/cts");
		options.c_cflag |= CRTSCTS;
	}

	tcflush(fd,TCIFLUSH);
	options.c_cc[VTIME] = 150; /* 设置超时15 seconds*/   
	options.c_cc[VMIN] = 0; /* Update the options and do it NOW */
	if (tcsetattr(fd,TCSANOW,&options) != 0)   
	{ 
		printf("SetupSerial failed");   
		return -1;  
	} 
	// printf("set_Parity\n");
	return 0;  
}

//接收消息结尾加换行符
int serial_set_line_input(int fd)
{ 
	struct termios options; 
	if  ( tcgetattr( fd,&options)  !=  0) { 
		perror("SetupSerial 1");     
		return -1;  
	}

    options.c_lflag |= ICANON;

    tcflush(fd,TCIFLUSH);
    options.c_cc[VTIME] = 150; /* 设置超时15 seconds*/   
    options.c_cc[VMIN] = 0; /* Update the options and do it NOW */
    if (tcsetattr(fd,TCSANOW,&options) != 0)   
    { 
    	perror("SetupSerial 3");   
    	return -1;  
    } 
    return 0;  
}

/**
*@brief  
*@param  port 串口端口号
*@param  spd  串口速度
*@param  databits,parity,stopbits,RTSCTS,分别为数据位,校验位,停止位,rtscts位
*@param  need_line_input接收数据结尾是否加换行符?
*/
int serial_init(int port, int spd, int databits, int parity, int stopbits, int RTSCTS, int need_line_input)
{
    int fd;
	if(port < 13)
	{
   		// printf("open port:%d\n", port);
	}
	else {
		printf("error: port:%d > MAX_PORTS\n", port);
		return -1;
	}
												 //	   	                	
    fd = open(ports[port].name, O_RDWR|O_NOCTTY);//O_NONBLOCK 非阻塞, O_WRONLY 只读写, O_RDONLY 只读, O_RDWR 读写,O_NOCTTY 阻塞

	if (-1 == fd) { 
        printf("init %s failed\n", ports[port].name);
        return -1;
    }
	pf = fdopen(port, "w");
	pfi = fdopen(port, "r");
	if (!pf || ! pfi)
		fprintf(stderr,"open port failed\n");



    set_speed(fd, spd);
	
    set_Parity(fd, databits, parity, stopbits, RTSCTS);
	
    if (need_line_input) {
		serial_set_line_input(fd);
    }

	ports[port].port_fd = fd;
	
    return fd;
}

/**
*@brief  
*@param  fd   串口端口号文件描述符
*@param  src  需要通过串口发送的数据
*@param  len  需要发送的数据长度
*@param  成功返回0, 否则返回-1
*/
int serial_write(int fd, void *src, int len)
{
    int ret = write(fd, src, len);
    if (len != ret) {
		perror("oh, write serial failed!");
		return -1;
    }
    return 0;
}

/**
*@brief  
*@param  fd   串口端口号文件描述符
*@param  src  串口接收数据的指针
*@param  len  需要接收的数据长度
*@param  成功返回0, 否则返回-1
*/
int serial_read(int fd, char *buf, int len)
{
    int ret = read(fd, buf, len-1);
    if (-1 == ret) {
		perror("oh, read serial failed!");
		return -1;
    }
    buf[ret] = '\0';
    return ret;
}

int serial_recv(int fd,char *rbuf,int rbuf_len, int timeout)
{      
    int retval;
    fd_set  rset;
    struct timeval time_out;
    if(!rbuf || rbuf_len <= 0)
    {  
        // printf("serial_recv Invalid parameter.\n");
        return -1;
    }  
    if(timeout) //指定延时等待
    {    
        time_out.tv_sec = (time_t)(timeout / 1000);
        time_out.tv_usec = 0;
        FD_ZERO(&rset);
        FD_SET(fd,&rset);

        retval = select(fd,&rset,NULL,NULL,&time_out);
        if(retval < 0)
        {
            // printf("%s,Select failed:%s\n",strerror(errno));
            return -2;
        }
        else if(0 == retval)
        {
            // printf("Time Out.\n");
            return 0;
        }

    }
    // usleep(1000);
    retval = read(fd, rbuf, rbuf_len);
    if( retval <= 0)
    {
        // printf("Read failed:%s\n",strerror(errno));
        return -3;
    }
    return retval;

} 


static void timeout()
{
	fprintf(stderr,"No response from modem.\n");
	exit(2);
}
/*字符包含判断*/
static int starts_with(const char* prefix, const char* str)
{
	while(*prefix)
	{
		if (*prefix++ != *str++)
		{
			return 0;
		}
	}
	return 1;
}
/*判断是否存在*/
int FileExist(const char* filename)
{
    if (filename && access(filename, F_OK) == 0) {
        return 1;
    }
    return 0;
}
/*字符转小写*/
char* str_tolower(const char* str)
{
	size_t len = strlen(str);
    char *lower = calloc(len+1, sizeof(char));
    for (size_t i = 0; i < len; ++i) {
        lower[i] = tolower((unsigned char)str[i]);
    }
	/*free(upper);*/
	return lower;
}
/*字符转大写*/
char* str_toupper(const char* str)
{
	size_t len = strlen(str);
    char *upper = calloc(len+1, sizeof(char));
    for (size_t i = 0; i < len; ++i) {
        upper[i] = toupper((unsigned char)str[i]);
    }
	/*free(upper);*/
	return upper;
}
/*char*转char[]*/
char strx_tostrarr(const char* str)
{
	return 0;
}


int main(int argc, char **argv)
{
	if(argc<3)
	{
		printf("ERROR demo: sendat 2 'ATI'\n");	
		exit(1);
		return 0;
	}
	int debug = 1;
	int port= 0;
	sscanf(argv[1], "%d", &port);
	if(FileExist(ports[port].name)==0)
	{
		printf("AT ERROR absent.\n");
   		return 0;
	}
	char *message= argv[2];
	char *nty= "\r\n";
	char buff[1024];
	signal(SIGALRM,timeout);
	alarm(2);
	/*信号超时3秒自动退出*/
	int fd = serial_def_init(port, 1500000);
	if(fd < 0) return 0;
	char *send= strcat(message,nty);
	serial_write(fd,send, strlen(send));
	while(1) {
		int read = serial_read(fd, buff, sizeof(buff));
		if(starts_with("OK", buff)) {
			if (debug == 1)
				printf("%s", buff);
			close(fd);//关闭串口
			exit(0);
		}
		if(starts_with("ERROR", buff)) {
			if (debug == 1)
				printf("%s", buff);
			close(fd);//关闭串口
			exit(1);
		}
		if(starts_with("COMMAND NOT SUPPORT", buff)) {
			if (debug == 1)
				printf("%s", buff);
			close(fd);//关闭串口
			exit(1);
		}
		if(starts_with("+CME ERROR", buff)) {
			if (debug == 1)
				printf("%s", buff);
			close(fd);//关闭串口
			exit(1);
		}
		printf("%s", buff);
	}

	exit(1);
	return 0;
}
