AP05/uart_utils/uart_utils.c
2025-04-06 14:41:47 +08:00

407 lines
11 KiB
C
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#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
}
}
/*************************************************************
* 功能: 设置串口属性结构体
* 参数:
speed串口波特率可选2400、4800、9600、115200。可自己酌情修改程序添加支持
data_bits数据位宽可选5、6、7、8
stop_bits停止位可选1、2
check奇偶校验位可选'N'、'O'、'E';分别应着无奇偶校验、奇校验、偶校验)
flow_ctrl硬件流控制0为OFF1为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为OFF1为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);
}