forked from gary/ems
2
0
Fork 0
sun_ems/ems_c/driver/drv_uart.c

345 lines
11 KiB
C
Raw Normal View History

2025-05-13 17:49:49 +08:00
/*****************************************************************************
* @copyright 2024-2024, . POWER SUPPLY CO., LTD.
* @file drv_uart.c
* @brief
* @author Gary
* @date 2024/09/02
* @remark
*****************************************************************************/
#define _GNU_SOURCE
#include <stdio.h>
#include <fcntl.h>
#include <termios.h>
#include <string.h>
#include <errno.h>
#include <sys/time.h>
#include "kit_log.h"
#include "drv_uart.h"
/*****************************************************************************
* @brief
* @param[in] p_uart:
* @return 0- 1-
*****************************************************************************/
int32_t drvUartOpen(uart_lib_t* p_uart)
{
// 定义串口时序控制
struct termios options;
p_uart->fd = open((const char *)p_uart->address,O_RDWR | O_NOCTTY | O_NDELAY | O_EXCL);
if (p_uart->fd == -1) {
//p_uart->lastError = SERIAL_PORT_ERROR_OPEN_FAILED;
return 1;
}
// 获取当前串口配置
if (tcgetattr(p_uart->fd, &options) != 0)
{
KITLOG(LOG_DRIVER_EN, ERROR_EN, "tcgetattr failed");
close(p_uart->fd);
return 1;
}
// 设置等待时间和最小接受字符
options.c_cc[VTIME] = p_uart->timeout / 100; // 设置等待时间(单位:十分之一秒)
options.c_cc[VMIN] = 1; // 最小接受字符
//options.c_cflag |= (CREAD | CLOCAL);
options.c_cflag &= ~CRTSCTS; // 不进行流控制
//options.c_cflag &= CRTSCTS; // 进行流控制
// 设置波特率
switch (p_uart->baud)
{
case kUart_Baud_115200:
cfsetospeed(&options, B115200);
cfsetispeed(&options, B115200);
break;
case kUart_Baud_57600:
cfsetospeed(&options, B57600);
cfsetispeed(&options, B57600);
break;
case kUart_Baud_38400:
cfsetospeed(&options, B38400);
cfsetispeed(&options, B38400);
break;
case kUart_Baud_19200:
cfsetospeed(&options, B19200);
cfsetispeed(&options, B19200);
break;
case kUart_Baud_9600:
cfsetospeed(&options, B9600);
cfsetispeed(&options, B9600);
break;
case kUart_Baud_4800:
cfsetospeed(&options, B4800);
cfsetispeed(&options, B4800);
break;
case kUart_Baud_2400:
cfsetospeed(&options, B2400);
cfsetispeed(&options, B2400);
break;
case kUart_Baud_1800:
cfsetospeed(&options, B1800);
cfsetispeed(&options, B1800);
break;
case kUart_Baud_1200:
cfsetospeed(&options, B1200);
cfsetispeed(&options, B1200);
break;
case kUart_Baud_600:
cfsetospeed(&options, B600);
cfsetispeed(&options, B600);
break;
case kUart_Baud_300:
cfsetospeed(&options, B300);
cfsetispeed(&options, B300);
break;
case kUart_Baud_200:
cfsetospeed(&options, B200);
cfsetispeed(&options, B200);
break;
case kUart_Baud_150:
cfsetospeed(&options, B150);
cfsetispeed(&options, B150);
break;
default:
//sprintf(log, "未知波特率:%d", p_uart->baud);
return 1;
}
options.c_cflag |= (CREAD | CLOCAL);
/* Set data bits (5/6/7/8) */
options.c_cflag &= ~CSIZE;
switch (p_uart->data)
{
case kUart_Data_5:
options.c_cflag |= CS5;
break;
case kUart_Data_6:
options.c_cflag |= CS6;
break;
case kUart_Data_7:
options.c_cflag |= CS7;
break;
case kUart_Data_8:
options.c_cflag |= CS8;
break;
default:
//sprintf(log, "未知数据位:%d", p_uart->data);
return 1;
}
// 设置停止位
switch (p_uart->stop)
{
case kUart_Stop_1:
options.c_cflag &= ~CSTOPB; // 一位停止位
break;
case kUart_Stop_2:
options.c_cflag |= CSTOPB; // 两位停止位
break;
default:
//sprintf(log, "未知停止位:%d", p_uart->stop);
return 1;
}
// 禁用输出处理
options.c_oflag &= ~OPOST;
// 禁用规范模式
options.c_lflag &= ~(ICANON | ECHO | ECHONL | ISIG | ECHOE);
// 启用接收器并忽略调制解调器状态行
options.c_cflag |= CREAD | CLOCAL;
// 禁用换行符转换
options.c_oflag &= ~ONLCR;
//禁用软件流特殊控制
options.c_iflag &= ~(IXON | IXOFF | IXANY | ICRNL);
// 禁用特殊输入处理
options.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL);
// 清空串口的输入输出缓冲区
tcflush(p_uart->fd, TCIOFLUSH);
// 激活配置,将配置的参数应用到串口
if (tcsetattr(p_uart->fd, TCSANOW, &options) < 0)
{
KITLOG(LOG_DRIVER_EN, ERROR_EN, "tcsetattr failed");
close(p_uart->fd);
p_uart->fd = -1;
//p_uart->lastError = SERIAL_PORT_ERROR_INVALID_ARGUMENT;
return 1;
}
return 0;
}
/*****************************************************************************
* @brief
* @param[in] p_uart:
* @return 0- 1-
*****************************************************************************/
int32_t drvUartClose(uart_lib_t* p_uart)
{
if (p_uart->fd > 0)
{
close(p_uart->fd);
p_uart->fd = 0;
p_uart->status = CONN_OFFLINE;
}
else
{
KITLOG(LOG_DRIVER_EN, ERROR_EN, "关闭失败!");
return 1;
}
return 0;
}
void uartPrintLog(const char *str, uint8_t *data, uint16_t len, uint8_t order)
{
uint8_t sdata[256 * 2 * 2] = {0};
int pos = 0;
if ((uint8_t)getRtdbPointValue(rtdbType, kDev_Type_EMS, 0, kEms_UartLog_Enable) == 1)
{
if (len > 0)
{
for (int i = 0; i < len; i++)
{
pos += sprintf((char*)(sdata + pos), "%02x ", data[i]);
}
sprintf((char*)(sdata + pos), "\n");
}
KITPTF(LOG_DRIVER_EN, INFO_EN, "串口:%d,%s:%s", order, str, sdata);
KITLOG(LOG_DRIVER_EN, INFO_EN, "串口:%d,%s:%s", order, str, sdata);
}
}
/*****************************************************************************
* @brief
* @param[in] p_uart:
* @return 0- 1-
*****************************************************************************/
int32_t drvUartSend(uart_lib_t* p_uart)
{
// 连接状态
int ret = 0;
#if 0
if (p_uart->status == CONN_OFFLINE)
{
KITLOG(LOG_DRIVER_EN, ERROR_EN, "串口(%s) 离线\n", p_uart->address);
return 1;
}
fd_set set;
FD_ZERO(&set);
FD_SET(p_uart->fd, &set);
struct timeval time_out = {1, 0};
//int ret = select(p_uart->fd + 1, NULL,&set, NULL, &time_out);
if (0 == ret)
{
printf("串口select 超时 !!! fd:%d\r\n",p_uart->fd);
//return -128;
}
else if (ret < 0)
{
printf("串口select 失败 为负值 !!! fd:%d\r\n",p_uart->fd);
//return -1;
}
#endif
ssize_t rett = 0;
///tcflush(p_uart->fd, TCIOFLUSH);
while (rett < p_uart->send_len)
{
ssize_t rc = write(p_uart->fd, p_uart->send_buf + rett, p_uart->send_len - rett);
if (rc > 0)
{
rett += rc;
}
else
{
// 发生错误
KITLOG(LOG_DRIVER_EN, ERROR_EN, "串口(%s) 发送错误! ret: %ld, errno: %s(%d)\n",
p_uart->address, ret, strerror(errno), errno);
return 1;
}
}
uartPrintLog("串口发送:", p_uart->send_buf, p_uart->send_len, p_uart->uartId);
//tcdrain(p_uart->fd); // 确保数据实际发送出去
return 0;
}
/*****************************************************************************
* @brief
* @param[in] p_uart:
* @return 0- 1-
*****************************************************************************/
int32_t drvUartRecv(uart_lib_t* p_uart)
{
fd_set set;
FD_ZERO(&set);
FD_SET(p_uart->fd, &set);
struct timeval time_out = {1, 0};
static uint8_t retries = 0;
uint8_t expectedLength = p_uart->recv_len;
//expectedLength = 67;
// expectedLength = 65;
p_uart->recv_len = 0;
//同一帧最多接收p_uart->error_cnt收不到全量报文强行退出
while (p_uart->recv_len < expectedLength)
{
int ret = select(p_uart->fd + 1, &set, NULL, NULL, &time_out); // 改为读集合
if (0 == ret)
{
// tcflush(p_uart->fd, TCIOFLUSH);
uartPrintLog("-128串口接收", p_uart->recv_buf, p_uart->recv_len, p_uart->uartId);
return -128;
}
else if (ret < 0)
{
// tcflush(p_uart->fd, TCIOFLUSH);
uartPrintLog("-1串口接收", p_uart->recv_buf, p_uart->recv_len, p_uart->uartId);
return -1;
}
ssize_t len = read(p_uart->fd, p_uart->recv_buf + p_uart->recv_len, expectedLength - p_uart->recv_len);
if (len > 0)
{
p_uart->recv_len += len;
// 检查是否接收到完整的帧
if (p_uart->recv_len >= expectedLength)
{
retries = 0;
tcflush(p_uart->fd, TCIOFLUSH);
uartPrintLog("串口接收:", p_uart->recv_buf, p_uart->recv_len, p_uart->uartId);
return 0;
}
}
else if (len < 0)
{
KITLOG(LOG_DRIVER_EN, ERROR_EN, "串口(%d) 接收数据失败! ret: %zd, errno: %s(%d)\n",
p_uart->uartId, len, strerror(errno), errno);
return 1; // 接收失败
}
// 如果未达到期望长度,可以考虑重试接收
if (p_uart->recv_len < expectedLength)
{
retries++;
if(retries >= 3)
{
KITLOG(LOG_DRIVER_EN, ERROR_EN, "串口(%d) 全量数据接收失败! 期望长度: %d, 实际接收长度:%d",p_uart->uartId, expectedLength, p_uart->recv_len);
// 清空串口接收缓冲区
tcflush(p_uart->fd, TCIFLUSH);
return -1;
}
usleep(100000); // 等待一段时间后重试
}
}
return 0;
}