Files
433_STM32/Core/Src/multi_uart_router.c

663 lines
18 KiB
C
Raw Permalink Normal View History

/**
******************************************************************************
* @file multi_uart_router.c
* @brief UART统一路由核心模块实现
* @author Application Layer
* @version 1.0
******************************************************************************
* @attention
* UART端口的统一管理
* 3.13.33.5A
*
*
* 1. +
* 2.
* 3.
* 4.
*
*
* - PORT_UART1: RF433无线模块(线)
* - PORT_UART2: ()
* - PORT_UART3:
******************************************************************************
*/
#include "multi_uart_router.h"
#include "uart2_print.h"
#include <string.h>
#include <stdarg.h>
#include <stdio.h>
/*==============================================================================
*
*============================================================================*/
/* DEBUG_MULTI_UART: 多UART路由调试日志开关 */
#define DEBUG_MULTI_UART 1
#if DEBUG_MULTI_UART
/* 多UART模块日志宏带前缀"[MUART]" */
#define DEBUG_LOG(fmt, ...) UART2_Print_Printf("[MUART] " fmt "\r\n", ##__VA_ARGS__)
#else
#define DEBUG_LOG(fmt, ...)
#endif
/*==============================================================================
*
*============================================================================*/
/**
* @brief UART端口上下文表
* @note
* /UART句柄
*/
static uart_port_context_t g_port_ctx[PORT_COUNT];
/**
* @brief UART端口与HAL句柄映射表
* @note ID索引HAL_UART_HandleTypeDef指针
* 使
*/
static UART_HandleTypeDef *const g_port_uart_map[PORT_COUNT] = {
[PORT_UART1] = &huart1, /**< RF433无线模块 */
[PORT_UART2] = &huart2, /**< 调试串口 */
[PORT_UART3] = &huart3, /**< 预留扩展 */
};
/**
* @brief UART端口名称映射表
* @note
*/
static const char *const g_port_name_map[PORT_COUNT] = {
[PORT_UART1] = "UART1", /**< RF433无线模块 */
[PORT_UART2] = "UART2", /**< 调试串口 */
[PORT_UART3] = "UART3", /**< 预留扩展 */
};
/*==============================================================================
*
*============================================================================*/
/**
* @brief
* @note
*
* @param ring: (/)
* @return
*/
static void rx_ring_init(uart_rx_ring_t *ring)
{
ring->head = 0;
ring->tail = 0;
ring->count = 0;
ring->overflow_count = 0;
}
/**
* @brief
* @note
*
* @param ring: (/)
* @return
*/
static void tx_ring_init(uart_tx_ring_t *ring)
{
ring->head = 0;
ring->tail = 0;
ring->count = 0;
ring->is_sending = false;
ring->overflow_count = 0;
}
/**
* @brief ()
* @note
*
* @param ring: (/)
* @param byte: ()
* @return bool: true=false=
*
* 线
* - 使__disable_irq/__enable_irq保护临界区
* - count和写入buffer之间不被中断打断
*
*
* -
* - overflow_count计数供诊断使用
*/
static bool rx_ring_push(uart_rx_ring_t *ring, uint8_t byte)
{
bool success = true;
__disable_irq();
if (ring->count >= UART_RX_BUFFER_SIZE) {
ring->overflow_count++;
success = false;
} else {
ring->buffer[ring->head] = byte;
ring->head = (ring->head + 1) % UART_RX_BUFFER_SIZE;
ring->count++;
}
__enable_irq();
return success;
}
/**
* @brief ()
* @note
*
* @param ring: ()
* @param byte: ()
* @return uint16_t: (01)
*
* 线
* - 使__disable_irq/__enable_irq保护临界区
*
*
* - 0
* - tail指针FIFO
*/
static uint16_t rx_ring_pop(uart_rx_ring_t *ring, uint8_t *byte)
{
uint16_t result = 0;
__disable_irq();
if (ring->count > 0) {
*byte = ring->buffer[ring->tail];
ring->tail = (ring->tail + 1) % UART_RX_BUFFER_SIZE;
ring->count--;
result = 1;
}
__enable_irq();
return result;
}
/**
* @brief ()
* @note
*
* @param ring: (/)
* @param data: ()
* @param len: ()
* @return uint16_t:
*
* 线
* - 使__disable_irq/__enable_irq保护临界区
*
*
* - ()
* - written值
*/
static uint16_t tx_ring_push(uart_tx_ring_t *ring, const uint8_t *data, uint16_t len)
{
uint16_t written = 0;
__disable_irq();
for (uint16_t i = 0; i < len; i++) {
if (ring->count >= UART_TX_BUFFER_SIZE) {
ring->overflow_count++;
break;
}
ring->buffer[ring->head] = data[i];
ring->head = (ring->head + 1) % UART_TX_BUFFER_SIZE;
ring->count++;
written++;
}
__enable_irq();
return written;
}
/**
* @brief UART发送(Kickoff)
* @note UART空闲
*
* @param port_id: ID()
* @return
*
*
* - (count > 0)
* - UART当前处于空闲状态(is_sending == false)
*
*
* - 使__disable_irq/__enable_irq保护临界区
*
*
* - TxCpltCallback驱动
* - "kickoff"
*/
static void tx_kickoff(port_id_t port_id)
{
uart_port_context_t *ctx = &g_port_ctx[port_id];
uart_tx_ring_t *ring = &ctx->tx_ring;
uint8_t byte;
bool has_data = false;
__disable_irq();
if (!ring->is_sending && ring->count > 0) {
/* 取出下一个待发送字节 */
byte = ring->buffer[ring->tail];
ring->tail = (ring->tail + 1) % UART_TX_BUFFER_SIZE;
ring->count--;
ring->is_sending = true;
has_data = true;
}
__enable_irq();
/* 启动UART中断发送 */
if (has_data) {
HAL_UART_Transmit_IT(ctx->huart, &byte, 1);
}
}
/*==============================================================================
*
*============================================================================*/
/**
* @brief UART路由模块初始化
* @note
*
* @param
* @return
*
*
* 1.
* 2. HAL句柄的关联
* 3.
* 4.
*
*
* HAL_UART_Init()使
*/
void MultiUART_Init(void)
{
for (port_id_t i = 0; i < PORT_COUNT; i++) {
uart_port_context_t *ctx = &g_port_ctx[i];
/* 建立端口与HAL句柄的关联 */
ctx->huart = g_port_uart_map[i];
ctx->name = g_port_name_map[i];
/* 初始化收发环形缓冲区 */
rx_ring_init(&ctx->rx_ring);
tx_ring_init(&ctx->tx_ring);
/* 重置统计计数器和临时变量 */
ctx->rx_tmp = 0;
ctx->rx_count = 0;
ctx->tx_count = 0;
ctx->error_count = 0;
ctx->initialized = true;
}
DEBUG_LOG("Init OK, %d ports configured", PORT_COUNT);
}
/**
* @brief
* @note UART接收中断中调用
*
* @param port_id: ID()
* @param byte: ()
* @return
*
*
* 1.
* 2.
* 3.
* 4.
*
*
* error_count计数
*/
void MultiUART_FeedByte(port_id_t port_id, uint8_t byte)
{
/* 参数合法性检查 */
if (port_id >= PORT_COUNT) {
return;
}
uart_port_context_t *ctx = &g_port_ctx[port_id];
/* 检查端口是否已初始化 */
if (!ctx->initialized) {
return;
}
/* 写入接收缓冲区,失败时增加错误计数 */
if (!rx_ring_push(&ctx->rx_ring, byte)) {
ctx->error_count++;
DEBUG_LOG("%s RX overflow", ctx->name);
}
ctx->rx_count++;
}
/**
* @brief UART路由任务函数
* @note
*
* @param
* @return
*
*
* tx_kickoff启动待发的数据
* (MultiUART_FeedByte)
*
*
* - PORT_UART2()UART2_Print模块独立处理
*
*
* (10ms定时)
*/
void MultiUART_Task(void)
{
for (port_id_t i = 0; i < PORT_COUNT; i++) {
uart_port_context_t *ctx = &g_port_ctx[i];
/* 检查端口是否已初始化 */
if (!ctx->initialized) {
continue;
}
/* 跳过调试串口(UART2) */
if (i == PORT_UART2) {
continue;
}
/* 尝试启动发送 */
tx_kickoff(i);
}
}
/**
* @brief
* @note
*
* @param port_id: ID()
* @param data: ()
* @param len: ()
* @return
*
*
* - PORT_UART2直接调用UART2_Print_Send
* - 使
*
*
* 1.
* 2. tx_kickoff启动首次发送()
*
*
* - tx_ring_push内部使用临界区保护
*/
void MultiUART_Send(port_id_t port_id, const uint8_t *data, uint16_t len)
{
/* 参数合法性检查 */
if (port_id >= PORT_COUNT || data == NULL || len == 0) {
return;
}
/*----------------------------------------------------------
* (UART2)
*
*----------------------------------------------------------*/
if (port_id == PORT_UART2) {
UART2_Print_Send(data, len);
return;
}
uart_port_context_t *ctx = &g_port_ctx[port_id];
/* 检查端口是否已初始化 */
if (!ctx->initialized) {
return;
}
/* 写入发送缓冲区并更新计数 */
uint16_t written = tx_ring_push(&ctx->tx_ring, data, len);
if (written > 0) {
ctx->tx_count += written;
tx_kickoff(port_id);
}
}
/**
* @brief
* @note MultiUART_Send
*
* @param port_id: ID()
* @param str: '\0'()
* @return
*
* 使
* str必须为有效指针且以'\0'
* strlen计算长度时不包括终止符
*/
void MultiUART_SendString(port_id_t port_id, const char *str)
{
if (str == NULL) {
return;
}
MultiUART_Send(port_id, (const uint8_t *)str, strlen(str));
}
/**
* @brief
* @note 仿printf风格
*
* @param port_id: ID()
* @param fmt: ()
* @param ...: ()
* @return
*
*
* 1. 使va_list/va_start/va_end处理可变参数
* 2. vsnprintf将格式化参数写入临时缓冲区(128)
* 3. MultiUART_Send发送
*
*
* 127(128-1)
*/
void MultiUART_SendFmt(port_id_t port_id, const char *fmt, ...)
{
if (fmt == NULL) {
return;
}
char buffer[128];
va_list args;
va_start(args, fmt);
int len = vsnprintf(buffer, sizeof(buffer), fmt, args);
va_end(args);
if (len > 0) {
if (len >= (int)sizeof(buffer)) {
len = sizeof(buffer) - 1;
}
MultiUART_Send(port_id, (const uint8_t *)buffer, len);
}
}
/**
* @brief UART发送完成回调函数
* @note UART TX完成中断中调用
*
* @param port_id: ID()
* @return
*
*
* - PORT_UART2调用UART2_Print_TxCpltCallback处理
*
*
* 1. is_sending标志
* 2.
* 3.
*
*
* - 使__disable_irq/__enable_irq保护临界区
*/
void MultiUART_TxCpltCallback(port_id_t port_id)
{
if (port_id >= PORT_COUNT) {
return;
}
/* 调试串口(UART2)特殊处理 */
if (port_id == PORT_UART2) {
UART2_Print_TxCpltCallback();
return;
}
uart_port_context_t *ctx = &g_port_ctx[port_id];
uart_tx_ring_t *ring = &ctx->tx_ring;
uint8_t byte;
bool has_more = false;
__disable_irq();
ring->is_sending = false;
if (ring->count > 0) {
byte = ring->buffer[ring->tail];
ring->tail = (ring->tail + 1) % UART_TX_BUFFER_SIZE;
ring->count--;
ring->is_sending = true;
has_more = true;
}
__enable_irq();
if (has_more) {
HAL_UART_Transmit_IT(ctx->huart, &byte, 1);
}
}
/**
* @brief
* @note
*
* @param port_id: ID()
* @return const char*:
*
*
* ID无效时返回"UNKNOWN"
*/
const char *MultiUART_GetPortName(port_id_t port_id)
{
if (port_id >= PORT_COUNT) {
return "UNKNOWN";
}
return g_port_name_map[port_id];
}
/**
* @brief
* @note
*
* @param port_id: ID()
* @return uint16_t: 0
*
*
* - 使count
*
* 使
* -
* -
*/
uint16_t MultiUART_GetRxCount(port_id_t port_id)
{
if (port_id >= PORT_COUNT) {
return 0;
}
uint16_t count;
__disable_irq();
count = g_port_ctx[port_id].rx_ring.count;
__enable_irq();
return count;
}
/**
* @brief
* @note ()
*
* @param port_id: ID()
* @param byte: ()
* @return uint16_t: (01)
*
*
* - 使
*
* 使
*
*/
uint16_t MultiUART_ReadByte(port_id_t port_id, uint8_t *byte)
{
if (port_id >= PORT_COUNT || byte == NULL) {
return 0;
}
uart_rx_ring_t *ring = &g_port_ctx[port_id].rx_ring;
__disable_irq();
if (ring->count == 0) {
__enable_irq();
return 0;
}
*byte = ring->buffer[ring->tail];
ring->tail = (ring->tail + 1) % UART_RX_BUFFER_SIZE;
ring->count--;
__enable_irq();
return 1;
}
/**
* @brief
* @note
*
* @param port_id: ID()
* @return uint16_t: 0
*
* available = buffer_size - count
*
*
* - 使
*/
uint16_t MultiUART_GetTxAvailable(port_id_t port_id)
{
if (port_id >= PORT_COUNT) {
return 0;
}
uint16_t available;
__disable_irq();
available = UART_TX_BUFFER_SIZE - g_port_ctx[port_id].tx_ring.count;
__enable_irq();
return available;
}
/**
* @brief
* @note
*
* @param port_id: ID()
* @return uint32_t: 0
*
*
* = rx_ring.overflow_count + tx_ring.overflow_count
*
* 使
* -
* -
*/
uint32_t MultiUART_GetOverflowCount(port_id_t port_id)
{
if (port_id >= PORT_COUNT) {
return 0;
}
return g_port_ctx[port_id].rx_ring.overflow_count +
g_port_ctx[port_id].tx_ring.overflow_count;
}