281 lines
7.2 KiB
C
281 lines
7.2 KiB
C
/******************************************************************************
|
|
* @file jb_uart.c
|
|
* @brief USART3 协议串口驱动实现
|
|
* @author cyWu <1917507415@qq.com>
|
|
* @date 2026.08.10
|
|
* @version V1.0.0
|
|
* @history
|
|
* - V1.0.0, 2026.08.10, cyWu, 首次发布
|
|
******************************************************************************/
|
|
|
|
#include "jb_uart.h"
|
|
#include "log.h"
|
|
|
|
#include <string.h>
|
|
|
|
/*============================================================================*/
|
|
/* 私有宏 */
|
|
/*============================================================================*/
|
|
|
|
#define UART_DBG_BUF_SIZE (256U)
|
|
#define UART_DBG_IDLE_MS (30U)
|
|
/* 协议 MAX_PACKAGE_LEN(128) + 前置 0x00 */
|
|
#define JB_UART_TX_MAX_LEN (129U)
|
|
|
|
/*============================================================================*/
|
|
/* 私有变量 */
|
|
/*============================================================================*/
|
|
|
|
UART_HandleTypeDef g_jb_uart_handle;
|
|
|
|
static uint8_t s_initialized;
|
|
static uint8_t s_uart_rx_byte;
|
|
static JbUartRxCallback_t s_rx_cb;
|
|
|
|
static uint8_t s_dbg_buf[UART_DBG_BUF_SIZE];
|
|
static volatile uint16_t s_dbg_head;
|
|
static volatile uint16_t s_dbg_tail;
|
|
static volatile uint32_t s_dbg_last_rx_ms;
|
|
static volatile uint32_t s_rx_total;
|
|
static volatile uint32_t s_err_code;
|
|
static volatile uint8_t s_err_pending;
|
|
|
|
/*============================================================================*/
|
|
/* 私有函数 */
|
|
/*============================================================================*/
|
|
|
|
/**
|
|
* @brief ISR 安全:调试缓冲写入 1 字节
|
|
* @param byte 数据
|
|
*/
|
|
static void uart_dbg_push(uint8_t byte)
|
|
{
|
|
uint16_t next = (uint16_t)((s_dbg_head + 1U) % UART_DBG_BUF_SIZE);
|
|
|
|
if (next == s_dbg_tail)
|
|
{
|
|
s_dbg_tail = (uint16_t)((s_dbg_tail + 1U) % UART_DBG_BUF_SIZE);
|
|
}
|
|
s_dbg_buf[s_dbg_head] = byte;
|
|
s_dbg_head = next;
|
|
s_dbg_last_rx_ms = HAL_GetTick();
|
|
s_rx_total++;
|
|
}
|
|
|
|
/**
|
|
* @brief 打印十六进制
|
|
* @param tag 标签
|
|
* @param buf 数据
|
|
* @param len 长度
|
|
*/
|
|
static void uart_dbg_print_hex(const char *tag, const uint8_t *buf, uint32_t len)
|
|
{
|
|
uint32_t i;
|
|
|
|
printf("UART %s %lu bytes:", tag, (unsigned long)len);
|
|
for (i = 0; i < len; i++)
|
|
{
|
|
printf(" %02X", buf[i]);
|
|
}
|
|
printf("\r\n");
|
|
}
|
|
|
|
/**
|
|
* @brief 刷出 RX 调试与错误日志
|
|
*/
|
|
static void uart_dbg_flush(void)
|
|
{
|
|
uint8_t dump[UART_DBG_BUF_SIZE];
|
|
uint16_t dump_len = 0;
|
|
uint16_t tail;
|
|
uint16_t head;
|
|
|
|
if (s_err_pending)
|
|
{
|
|
s_err_pending = 0;
|
|
printf("UART RX error: 0x%08lX, total_rx=%lu\r\n",
|
|
(unsigned long)s_err_code,
|
|
(unsigned long)s_rx_total);
|
|
}
|
|
|
|
head = s_dbg_head;
|
|
tail = s_dbg_tail;
|
|
if (head == tail)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if ((HAL_GetTick() - s_dbg_last_rx_ms) < UART_DBG_IDLE_MS)
|
|
{
|
|
return;
|
|
}
|
|
|
|
while ((tail != head) && (dump_len < UART_DBG_BUF_SIZE))
|
|
{
|
|
dump[dump_len++] = s_dbg_buf[tail];
|
|
tail = (uint16_t)((tail + 1U) % UART_DBG_BUF_SIZE);
|
|
}
|
|
s_dbg_tail = tail;
|
|
|
|
uart_dbg_print_hex("RX", dump, dump_len);
|
|
printf("UART RX total=%lu\r\n", (unsigned long)s_rx_total);
|
|
}
|
|
|
|
/*============================================================================*/
|
|
/* 公有接口 */
|
|
/*============================================================================*/
|
|
|
|
/**
|
|
* @brief 注册 RX 回调
|
|
* @param cb 回调
|
|
*/
|
|
void jb_uart_set_rx_callback(JbUartRxCallback_t cb)
|
|
{
|
|
s_rx_cb = cb;
|
|
}
|
|
|
|
/**
|
|
* @brief 初始化 USART3
|
|
* @return JbUart_Ret_t
|
|
*/
|
|
JbUart_Ret_t jb_uart_init(void)
|
|
{
|
|
if (s_initialized)
|
|
{
|
|
return JB_UART_OK;
|
|
}
|
|
|
|
g_jb_uart_handle.Instance = JB_USART;
|
|
g_jb_uart_handle.Init.BaudRate = JB_UART_BAUDRATE;
|
|
g_jb_uart_handle.Init.WordLength = UART_WORDLENGTH_8B;
|
|
g_jb_uart_handle.Init.StopBits = UART_STOPBITS_1;
|
|
g_jb_uart_handle.Init.Parity = UART_PARITY_NONE;
|
|
g_jb_uart_handle.Init.HwFlowCtl = UART_HWCONTROL_NONE;
|
|
g_jb_uart_handle.Init.Mode = UART_MODE_TX_RX;
|
|
g_jb_uart_handle.Init.OverSampling = UART_OVERSAMPLING_16;
|
|
g_jb_uart_handle.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;
|
|
|
|
if (HAL_UART_Init(&g_jb_uart_handle) != HAL_OK)
|
|
{
|
|
return JB_UART_ERR_HAL;
|
|
}
|
|
|
|
if (HAL_UART_Receive_IT(&g_jb_uart_handle, &s_uart_rx_byte, 1U) != HAL_OK)
|
|
{
|
|
return JB_UART_ERR_HAL;
|
|
}
|
|
|
|
s_initialized = 1U;
|
|
printf("USART3 ready: PB10=TX PB11=RX baud=%lu 8N1, waiting RX...\r\n",
|
|
(unsigned long)JB_UART_BAUDRATE);
|
|
return JB_UART_OK;
|
|
}
|
|
|
|
/**
|
|
* @brief 主循环周期处理
|
|
*/
|
|
void jb_uart_run(void)
|
|
{
|
|
if (!s_initialized)
|
|
{
|
|
return;
|
|
}
|
|
uart_dbg_flush();
|
|
}
|
|
|
|
/**
|
|
* @brief 阻塞发送
|
|
* @param buf 数据
|
|
* @param len 长度
|
|
* @return 成功返回 len,失败 -1
|
|
*/
|
|
int32_t jb_uart_write(uint8_t *buf, uint32_t len)
|
|
{
|
|
static uint8_t s_tx_buf[JB_UART_TX_MAX_LEN];
|
|
uint32_t tx_len;
|
|
|
|
if (!buf)
|
|
{
|
|
return -1;
|
|
}
|
|
if (len == 0U)
|
|
{
|
|
return 0;
|
|
}
|
|
if (!s_initialized)
|
|
{
|
|
return -1;
|
|
}
|
|
if ((len + 1U) > JB_UART_TX_MAX_LEN)
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
/* 协议帧前加 0x00 后连续发送,避免越界读与帧间空隙 */
|
|
s_tx_buf[0] = 0x00U;
|
|
s_tx_buf[1] = 0x00U;
|
|
memcpy(&s_tx_buf[2], buf, len);
|
|
tx_len = len + 2U;
|
|
|
|
uart_dbg_print_hex("TX", s_tx_buf, tx_len);
|
|
|
|
if (HAL_UART_Transmit(&g_jb_uart_handle, s_tx_buf, (uint16_t)tx_len, 1000U) != HAL_OK)
|
|
{
|
|
printf("UART TX failed, len=%lu\r\n", (unsigned long)tx_len);
|
|
return -1;
|
|
}
|
|
return (int32_t)len;
|
|
}
|
|
|
|
/**
|
|
* @brief 获取初始化状态
|
|
* @return JbUart_Ret_t
|
|
*/
|
|
JbUart_Ret_t jb_uart_get_status(void)
|
|
{
|
|
if (!s_initialized)
|
|
{
|
|
return JB_UART_ERR_NOT_INIT;
|
|
}
|
|
return JB_UART_OK;
|
|
}
|
|
|
|
/*============================================================================*/
|
|
/* HAL 回调 */
|
|
/*============================================================================*/
|
|
|
|
/**
|
|
* @brief UART RX 完成回调
|
|
* @param huart 句柄
|
|
*/
|
|
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
|
|
{
|
|
if (huart->Instance == JB_USART)
|
|
{
|
|
uart_dbg_push(s_uart_rx_byte);
|
|
if (s_rx_cb != NULL)
|
|
{
|
|
s_rx_cb(s_uart_rx_byte);
|
|
}
|
|
(void)HAL_UART_Receive_IT(&g_jb_uart_handle, &s_uart_rx_byte, 1U);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @brief UART 错误回调
|
|
* @param huart 句柄
|
|
*/
|
|
void HAL_UART_ErrorCallback(UART_HandleTypeDef *huart)
|
|
{
|
|
if (huart->Instance == JB_USART)
|
|
{
|
|
s_err_code = HAL_UART_GetError(huart);
|
|
s_err_pending = 1U;
|
|
__HAL_UART_CLEAR_PEFLAG(huart);
|
|
__HAL_UART_CLEAR_FEFLAG(huart);
|
|
__HAL_UART_CLEAR_NEFLAG(huart);
|
|
__HAL_UART_CLEAR_OREFLAG(huart);
|
|
(void)HAL_UART_Receive_IT(&g_jb_uart_handle, &s_uart_rx_byte, 1U);
|
|
}
|
|
}
|