269 lines
7.8 KiB
C
269 lines
7.8 KiB
C
|
|
/**
|
|||
|
|
******************************************************************************
|
|||
|
|
* @file uart3_passthrough.c
|
|||
|
|
* @brief UART3透传引擎模块实现
|
|||
|
|
* @author Application Layer
|
|||
|
|
* @version 1.0
|
|||
|
|
******************************************************************************
|
|||
|
|
* @attention
|
|||
|
|
* 设计依据:UART3智能数据路由与透传功能开发计划 第3.2节
|
|||
|
|
*
|
|||
|
|
* 功能说明:
|
|||
|
|
* 本模块实现透传数据缓冲与发送功能,将UART3接收的透传数据转发至UART1
|
|||
|
|
*
|
|||
|
|
* 工作流程(严格按文档3.2.3节伪代码实现):
|
|||
|
|
* 1. 检查是否有待发送数据
|
|||
|
|
* 2. 检查UART1是否可发送
|
|||
|
|
* 3. 获取当前处理节点
|
|||
|
|
* 4. 发送一个字节
|
|||
|
|
* 5. 更新队列状态和统计
|
|||
|
|
*
|
|||
|
|
* 发送机制:
|
|||
|
|
* - 单字节每次发送,由UART1 TX完成中断驱动连续发送
|
|||
|
|
* - 使用独立环形缓冲区,避免与指令解析争用
|
|||
|
|
******************************************************************************
|
|||
|
|
*/
|
|||
|
|
|
|||
|
|
#include "uart3_passthrough.h"
|
|||
|
|
#include "uart3_smart_router_config.h"
|
|||
|
|
#include "multi_uart_router.h"
|
|||
|
|
#include "uart2_print.h"
|
|||
|
|
#include <string.h>
|
|||
|
|
|
|||
|
|
/*==============================================================================
|
|||
|
|
* 调试宏定义
|
|||
|
|
*============================================================================*/
|
|||
|
|
#if DEBUG_PASSTHROUGH_ENGINE
|
|||
|
|
#define DEBUG_LOG(fmt, ...) UART2_Print_Printf("[PTX] " fmt "\r\n", ##__VA_ARGS__)
|
|||
|
|
#else
|
|||
|
|
#define DEBUG_LOG(fmt, ...)
|
|||
|
|
#endif
|
|||
|
|
|
|||
|
|
/*==============================================================================
|
|||
|
|
* 全局变量定义
|
|||
|
|
* 设计依据:文档第3.2.2节
|
|||
|
|
*============================================================================*/
|
|||
|
|
/**
|
|||
|
|
* @brief 透传引擎全局上下文
|
|||
|
|
* @note 保存透传引擎全部状态信息
|
|||
|
|
*/
|
|||
|
|
passthrough_context_t g_passthrough_ctx;
|
|||
|
|
|
|||
|
|
/*==============================================================================
|
|||
|
|
* 公共函数实现
|
|||
|
|
* 设计依据:文档第3.2.1节模块接口设计
|
|||
|
|
*============================================================================*/
|
|||
|
|
/**
|
|||
|
|
* @brief 透传引擎初始化
|
|||
|
|
* @note 初始化透传队列和统计信息
|
|||
|
|
*/
|
|||
|
|
void Passthrough_Init(void)
|
|||
|
|
{
|
|||
|
|
memset(&g_passthrough_ctx, 0, sizeof(g_passthrough_ctx));
|
|||
|
|
|
|||
|
|
for (uint8_t i = 0; i < PASSTHROUGH_MAX_NODES; i++) {
|
|||
|
|
g_passthrough_ctx.queue.nodes[i].valid = false;
|
|||
|
|
g_passthrough_ctx.queue.nodes[i].length = 0;
|
|||
|
|
g_passthrough_ctx.queue.nodes[i].offset = 0;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
g_passthrough_ctx.queue.write_index = 0;
|
|||
|
|
g_passthrough_ctx.queue.read_index = 0;
|
|||
|
|
g_passthrough_ctx.queue.pending_count = 0;
|
|||
|
|
|
|||
|
|
g_passthrough_ctx.stats.total_bytes_sent = 0;
|
|||
|
|
g_passthrough_ctx.stats.total_packets = 0;
|
|||
|
|
g_passthrough_ctx.stats.overflow_count = 0;
|
|||
|
|
g_passthrough_ctx.stats.busy_count = 0;
|
|||
|
|
|
|||
|
|
g_passthrough_ctx.initialized = true;
|
|||
|
|
|
|||
|
|
DEBUG_LOG("Passthrough engine initialized, buffer size: %d bytes", PASSTHROUGH_TOTAL_BUFFER);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* @brief 压入单字节到透传缓冲区
|
|||
|
|
* @note 将单个字节添加到透传发送队列
|
|||
|
|
* @param byte: 待发送字节
|
|||
|
|
* @retval bool: true=成功,false=缓冲区满
|
|||
|
|
*/
|
|||
|
|
bool Passthrough_PushByte(uint8_t byte)
|
|||
|
|
{
|
|||
|
|
passthrough_context_t *ctx = &g_passthrough_ctx;
|
|||
|
|
|
|||
|
|
if (!ctx->initialized) {
|
|||
|
|
return false;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
uint8_t next_index = (ctx->queue.write_index + 1) % PASSTHROUGH_MAX_NODES;
|
|||
|
|
|
|||
|
|
if (next_index == ctx->queue.read_index && ctx->queue.pending_count > 0) {
|
|||
|
|
ctx->stats.overflow_count++;
|
|||
|
|
DEBUG_LOG("Buffer full, overflow count: %d", ctx->stats.overflow_count);
|
|||
|
|
return false;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
passthrough_node_t *node = &ctx->queue.nodes[ctx->queue.write_index];
|
|||
|
|
|
|||
|
|
if (!node->valid || node->length >= PASSTHROUGH_NODE_SIZE) {
|
|||
|
|
if (node->valid) {
|
|||
|
|
ctx->queue.write_index = next_index;
|
|||
|
|
node = &ctx->queue.nodes[ctx->queue.write_index];
|
|||
|
|
}
|
|||
|
|
node->length = 0;
|
|||
|
|
node->offset = 0;
|
|||
|
|
node->valid = true;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
node->data[node->length++] = byte;
|
|||
|
|
ctx->queue.pending_count++;
|
|||
|
|
|
|||
|
|
return true;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* @brief 压入数据块到透传缓冲区
|
|||
|
|
* @note 将数据块添加到透传发送队列
|
|||
|
|
* @param data: 数据缓冲区指针
|
|||
|
|
* @param length: 数据长度
|
|||
|
|
* @retval uint16_t: 实际写入的字节数
|
|||
|
|
*/
|
|||
|
|
uint16_t Passthrough_PushBuffer(const uint8_t *data, uint16_t length)
|
|||
|
|
{
|
|||
|
|
if (data == NULL || length == 0) {
|
|||
|
|
return 0;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
passthrough_context_t *ctx = &g_passthrough_ctx;
|
|||
|
|
uint16_t written = 0;
|
|||
|
|
|
|||
|
|
for (uint16_t i = 0; i < length; i++) {
|
|||
|
|
uint8_t next_index = (ctx->queue.write_index + 1) % PASSTHROUGH_MAX_NODES;
|
|||
|
|
|
|||
|
|
if (next_index == ctx->queue.read_index && ctx->queue.pending_count > 0) {
|
|||
|
|
ctx->stats.overflow_count++;
|
|||
|
|
DEBUG_LOG("Buffer overflow at byte %d/%d", i, length);
|
|||
|
|
break;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
passthrough_node_t *node = &ctx->queue.nodes[ctx->queue.write_index];
|
|||
|
|
|
|||
|
|
if (!node->valid || node->length >= PASSTHROUGH_NODE_SIZE) {
|
|||
|
|
if (node->valid) {
|
|||
|
|
ctx->queue.write_index = next_index;
|
|||
|
|
node = &ctx->queue.nodes[ctx->queue.write_index];
|
|||
|
|
}
|
|||
|
|
node->length = 0;
|
|||
|
|
node->offset = 0;
|
|||
|
|
node->valid = true;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
node->data[node->length++] = data[i];
|
|||
|
|
ctx->queue.pending_count++;
|
|||
|
|
written++;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (written > 0) {
|
|||
|
|
ctx->stats.total_packets++;
|
|||
|
|
DEBUG_LOG("Pushed %d bytes to buffer, pending: %d", written, ctx->queue.pending_count);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return written;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* @brief 透传引擎任务
|
|||
|
|
* @note 在主循环中周期性调用,每次尝试发送一个字节
|
|||
|
|
* 配合UART1 TX完成中断实现连续发送
|
|||
|
|
*/
|
|||
|
|
void Passthrough_Task(void)
|
|||
|
|
{
|
|||
|
|
passthrough_context_t *ctx = &g_passthrough_ctx;
|
|||
|
|
|
|||
|
|
if (!ctx->initialized) {
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (ctx->queue.pending_count == 0) {
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (!Passthrough_CanSend()) {
|
|||
|
|
ctx->stats.busy_count++;
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
passthrough_node_t *node = &ctx->queue.nodes[ctx->queue.read_index];
|
|||
|
|
|
|||
|
|
if (!node->valid || node->offset >= node->length) {
|
|||
|
|
if (node->valid) {
|
|||
|
|
node->valid = false;
|
|||
|
|
}
|
|||
|
|
ctx->queue.read_index = (ctx->queue.read_index + 1) % PASSTHROUGH_MAX_NODES;
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
uint8_t byte = node->data[node->offset++];
|
|||
|
|
MultiUART_Send(PORT_UART1, &byte, 1);
|
|||
|
|
|
|||
|
|
ctx->queue.pending_count--;
|
|||
|
|
ctx->stats.total_bytes_sent++;
|
|||
|
|
|
|||
|
|
DEBUG_LOG("Sent byte 0x%02X, pending: %d", byte, ctx->queue.pending_count);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* @brief UART1发送完成回调
|
|||
|
|
* @note 应在HAL_UART_TxCpltCallback中调用,触发下一次发送
|
|||
|
|
*/
|
|||
|
|
void Passthrough_OnTxComplete(void)
|
|||
|
|
{
|
|||
|
|
Passthrough_Task();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* @brief 检查UART1是否可发送
|
|||
|
|
* @note 检查UART1发送缓冲区是否有空间
|
|||
|
|
* @retval bool: true=可发送,false=忙
|
|||
|
|
*/
|
|||
|
|
bool Passthrough_CanSend(void)
|
|||
|
|
{
|
|||
|
|
return (MultiUART_GetTxAvailable(PORT_UART1) > 0) &&
|
|||
|
|
(g_passthrough_ctx.queue.pending_count > 0);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* @brief 获取透传统计信息
|
|||
|
|
* @note 获取透传引擎的运行统计
|
|||
|
|
* @param stats: 统计结构指针
|
|||
|
|
*/
|
|||
|
|
void Passthrough_GetStats(passthrough_stats_t *stats)
|
|||
|
|
{
|
|||
|
|
if (stats != NULL) {
|
|||
|
|
memcpy(stats, &g_passthrough_ctx.stats, sizeof(passthrough_stats_t));
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* @brief 重置统计信息
|
|||
|
|
* @note 清零所有统计计数器
|
|||
|
|
*/
|
|||
|
|
void Passthrough_ResetStats(void)
|
|||
|
|
{
|
|||
|
|
passthrough_context_t *ctx = &g_passthrough_ctx;
|
|||
|
|
ctx->stats.total_bytes_sent = 0;
|
|||
|
|
ctx->stats.total_packets = 0;
|
|||
|
|
ctx->stats.overflow_count = 0;
|
|||
|
|
ctx->stats.busy_count = 0;
|
|||
|
|
DEBUG_LOG("Stats reset");
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* @brief 获取待发送字节数
|
|||
|
|
* @note 获取队列中等待发送的字节总数
|
|||
|
|
* @retval uint16_t: 待发送字节数
|
|||
|
|
*/
|
|||
|
|
uint16_t Passthrough_GetPendingCount(void)
|
|||
|
|
{
|
|||
|
|
return g_passthrough_ctx.queue.pending_count;
|
|||
|
|
}
|