3.27_433:实验并验证485发送数据透传至RF433模块,并在外部设备成功接收
- 新增协议识别器状态机,实现指令与透传数据的自动识别
This commit is contained in:
269
Core/Src/uart3_passthrough.c
Normal file
269
Core/Src/uart3_passthrough.c
Normal 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;
|
||||
}
|
||||
Reference in New Issue
Block a user