AP05/uart_utils/uart_utils.c

407 lines
11 KiB
C
Raw Normal View History

2025-04-06 06:41:47 +00:00
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <termios.h>
#include <string.h>
#include <sys/select.h>
#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
}
}
/*************************************************************
*
*
speed240048009600115200
data_bits5678
stop_bits12
check'N''O''E'
flow_ctrl0OFF1ON
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;
}
/*************************************************************
*
*
echo01
*
**************************************************************/
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); /* 设置串口属性 */
}
}
/*************************************************************
*
*
block01
*
**************************************************************/
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时不阻塞
}
}
}
/*************************************************************
*
*
speed240048009600115200
data_bits5678
stop_bits12
check'N''O''E'
flow_ctrl0OFF1ON
*
**************************************************************/
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);
}