3.27_433:实验并验证485发送数据透传至RF433模块,并在外部设备成功接收

- 新增协议识别器状态机,实现指令与透传数据的自动识别
This commit is contained in:
2026-03-27 19:58:20 +08:00
parent 268667e335
commit 0eea5c1424
71 changed files with 6051 additions and 2620 deletions

View File

@ -0,0 +1,269 @@
/**
******************************************************************************
* @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;
}