#include #include #include #include #include #include #include #include #include #include "read_utils.h" #include "uart_utils.h" #define PRINT_TIME_TAG #define DBG_TAG "uart_utils" #define DBG_LVL DBG_INFO #include "debug_print.h" #define STRING(x) #x #define TO_STRING(x) STRING(x) #define S(x) X(x,B##x,TO_STRING(x)) #define VALID_TERMINAL_SPEED_TABLE \ S(0)\ S(50)\ S(75)\ S(110)\ S(134)\ S(150)\ S(200)\ S(300)\ S(600)\ S(1200)\ S(1800)\ S(2400)\ S(4800)\ S(9600)\ S(19200)\ S(38400)\ S(57600)\ S(115200)\ S(230400)\ S(460800)\ S(500000)\ S(576000)\ S(921600)\ S(1000000)\ S(1152000)\ S(1500000)\ S(2000000)\ S(2500000)\ S(3000000)\ S(3500000)\ S(4000000) /************************************************************* * 功能: 打开串口设备文件 * 参数: 串口设备文件名 * 返回值: 串口设备文件描述符 **************************************************************/ int uart_open(uart_utils_t *uart, char *dev_name) { int uart_fd; uart_fd = open(dev_name, O_RDWR|O_NOCTTY); if(uart_fd < 0) { LOG_I("uart_open FATAL\n"); } if(uart != NULL) { uart->uart_fd = uart_fd; uart->saved = 0; } return uart_fd; } void uart_print_attr(struct termios *options) { int i; LOG_I("c_iflag = 0%o\n", options->c_iflag); LOG_I("c_oflag = 0%o\n", options->c_oflag); LOG_I("c_cflag = 0%o\n", options->c_cflag); LOG_I("c_lflag = 0%o\n", options->c_lflag); for(i=VINTR;i<=VEOL2;i++) { LOG_I("c_cc[%d] = %d\n", i, options->c_cc[i]); } } /************************************************************* * 功能: 串口默认属性 * 参数: 无 * 返回值: 无 **************************************************************/ static struct termios *uart_default_attr(void) { struct termios *options = NULL; options = (struct termios *)calloc(1, sizeof(struct termios)); if(options == NULL) { LOG_I("uart_default_attr calloc\n"); goto exit; } /* cfmakeraw() sets the terminal to something like the "raw" mode of the old Version 7 terminal driver: input is available character by character, echoing is disabled, and all special processing of terminal input and output characters is disabled. The terminal attributes are set as follows: */ cfmakeraw(options); /* Ignore break characters */ options->c_iflag = IGNBRK; /* Enable receiver. */ options->c_cflag |= CREAD; /* Ignore modem status lines. */ options->c_cflag |= CLOCAL; /* Number of bits per byte (mask). */ options->c_cflag &= ~CSIZE; /* Minimum number of bytes read at once [!ICANON]. */ options->c_cc[VMIN] = 1; /* Time-out value (tenths of a second) [!ICANON]. */ options->c_cc[VTIME] = 0; exit: return options; } static inline const char* valid_terminal_speeds(void) { #define X(x,y,z) "\n\t " z return VALID_TERMINAL_SPEED_TABLE; #undef X } static inline speed_t check_speed_parameter(int requested_speed) { switch(requested_speed) { #define X(x,y,z) case x: return y; VALID_TERMINAL_SPEED_TABLE default: LOG_I("invalid speed parameters, valid values are %s\n", valid_terminal_speeds()); return B9600; #undef X } } /************************************************************* * 功能: 设置串口属性结构体 * 参数: speed:串口波特率(可选2400、4800、9600、115200。可自己酌情修改程序添加支持) data_bits:数据位宽(可选5、6、7、8) stop_bits:停止位(可选1、2) check:奇偶校验位(可选'N'、'O'、'E';分别应着无奇偶校验、奇校验、偶校验) flow_ctrl:硬件流控制(0为OFF,1为ON) options:串口属结构体, * 返回值: 串口属性结构体 **************************************************************/ struct termios *uart_set_attr( int speed, int data_bits, int stop_bits, int check, int flow_ctrl, struct termios *options) { speed_t baud_rate = 0; if(options == NULL) { options = uart_default_attr(); } switch(data_bits) { case 5: options->c_cflag |= CS5; break; case 6: options->c_cflag |= CS6; break; case 7: options->c_cflag |= CS7; break; case 8: options->c_cflag |= CS8; break; default: options->c_cflag |= CS8; break; } /****************校验位选择****************/ switch(check) { case 'O': options->c_cflag |= PARENB;//允许输出产生奇偶信息以及输入的奇偶校验 options->c_cflag |= PARODD;//奇校验 options->c_iflag |= (INPCK|ISTRIP);//INPCK:启用输入奇偶检测;ISTRIP:去掉第八位(传输时只传7位) break; case 'E': options->c_cflag |= PARENB;//允许输出产生奇偶信息以及输入的奇偶校验 options->c_cflag &= ~PARODD;//输入和输出是偶校验(ECC) options->c_iflag |= (INPCK|ISTRIP); break; case 'N': options->c_cflag &= ~PARENB;//无奇偶校验位 } /****************硬件流控制****************/ switch (flow_ctrl) { case '0'://OFF options->c_cflag &= ~CRTSCTS; options->c_iflag &= ~(IXON|IXOFF|IXANY); break; case '1'://ON options->c_cflag |= CRTSCTS; options->c_iflag |= IXON|IXOFF|IXANY; break; default://OFF options->c_cflag &= ~CRTSCTS; options->c_iflag &= ~(IXON|IXOFF|IXANY); break; } /****************停止位选择****************/ if(stop_bits == 1) { options->c_cflag &= ~CSTOPB; } else if(stop_bits ==2) { options->c_cflag |= CSTOPB; } else { options->c_cflag &= ~CSTOPB; } /****************波特率选择****************/ baud_rate = check_speed_parameter(speed); cfsetispeed(options, baud_rate); cfsetospeed(options, baud_rate); return options; } /************************************************************* * 功能: 设置回显 * 参数: 串口设备文件名 echo:回显(0为关,1为开) * 返回值: 无 **************************************************************/ void uart_set_echo(uart_utils_t *uart, int echo) { struct termios options; if (uart != NULL) { tcgetattr(uart->uart_fd, &options); /* 获取串口属性 */ if(echo == 0) { options.c_lflag &= ~ECHO; /* 关回显 */ } else if(echo == 1) { options.c_lflag |= ECHO; /* 开回显 */ } else { options.c_lflag &= ~ECHO; /* 关回显 */ } tcsetattr(uart->uart_fd, TCSANOW, &options); /* 设置串口属性 */ } } /************************************************************* * 功能: 设置阻塞 * 参数: 串口设备文件名 block:阻塞(0为不阻塞,1为阻塞) * 返回值: 无 **************************************************************/ void uart_set_block(uart_utils_t *uart, int block) { if (uart != NULL) { if(block == 0) { fcntl(uart->uart_fd, F_SETFL, O_NONBLOCK); //read时不阻塞 } else if(block == 1) { fcntl(uart->uart_fd, F_SETFL, 0); //read时阻塞 } else { fcntl(uart->uart_fd, F_SETFL, O_NONBLOCK); //read时不阻塞 } } } /************************************************************* * 功能: 串口初始化程序 * 参数: 串口设备文件名 speed:串口波特率(可选2400、4800、9600、115200。可自己酌情修改程序添加支持) data_bits:数据位宽(可选5、6、7、8) stop_bits:停止位(可选1、2) check:奇偶校验位(可选'N'、'O'、'E';分别应着无奇偶校验、奇校验、偶校验) flow_ctrl:硬件流控制(0为OFF,1为ON) * 返回值: 串口设备文件描述符 **************************************************************/ int uart_init(uart_utils_t *uart, int speed, int data_bits, int stop_bits, int check, int flow_ctrl) { struct termios *options; if(uart == NULL) { goto exit; } if(uart->saved == 0) { uart->saved = 1; tcgetattr(uart->uart_fd, &uart->option_back); //保存串口属性 } //uart_print_attr(&uart->option_back); options = uart_set_attr(speed, data_bits, stop_bits, check, flow_ctrl, NULL); tcflush(uart->uart_fd, TCIFLUSH); //uart_print_attr(options); tcsetattr(uart->uart_fd, TCSANOW, options); /* 设置串口属性 */ if(options != &uart->option_back){ free(options); } return uart->uart_fd; exit: return -1; } /************************************************************* * 功能: 串口反初始化程序 * 参数: 串口设备文件描述符 * 返回值: 无 **************************************************************/ void uart_uninit(uart_utils_t *uart) { if(uart == NULL) { return; } if(uart->saved == 1) { uart->saved = 0; tcgetattr(uart->uart_fd, &uart->option_back); //保存串口属性 } /*关闭串口*/ close(uart->uart_fd); } /************************************************************* * 功能: 串口发送字符串 * 参数: uart_fd:串口设备文件描述符 str:待发送的字符 * 返回值: 无 **************************************************************/ void uart_send_str(int uart_fd, char *str) { int ret; ret = write(uart_fd, str, strlen(str)); if(ret < 0) { LOG_I("uart write"); } } /************************************************************* * 功能: 读一串至截止字符的字符串,在设定的时间内读不到数据则函数返回 * 参数: uart_fd:串口设备文件描述符 buffer:存放数据的内存的首地址 len:存放数据的内存空间的大小 until:截止字符 timeout_ms:超时时间(单位:ms) * 返回值: 成功:实际读到的字符数 失败:-1 **************************************************************/ int uart_read_until_char(int uart_fd, char *buffer, int len, unsigned char until, int timeout_ms) { return read_data_until_char(uart_fd, buffer, len, until, timeout_ms, timeout_ms); } /************************************************************* * 功能: 设定的时间内读取数据 * 参数: uart_fd:串口设备文件描述符 buffer:存放数据的内存的首地址 len:存放数据的内存空间的大小 timeout_ms:超时时间(单位:ms) * 返回值: 成功:实际读到的字符数 失败:-1 **************************************************************/ int uart_read_until_time(int uart_fd, char *buffer, int len, int timeout_first, int timeout_interval) { return read_data_until_time(uart_fd, buffer, len, timeout_first, timeout_interval); }