Files
433_STM32/docs/UART3智能数据路由与透传功能开发计划.md
zhongxuanzhen 0eea5c1424 3.27_433:实验并验证485发送数据透传至RF433模块,并在外部设备成功接收
- 新增协议识别器状态机,实现指令与透传数据的自动识别
2026-03-27 19:58:20 +08:00

43 KiB
Raw Blame History

UART3智能数据路由与透传功能开发计划

项目名称E32-433TBH-SC UART3智能数据路由与透传扩展 版本V1.0 制定日期2026-03-27 适用范围STM32F103嵌入式系统 基于系统:多通信接口统一指令处理系统 V1.0


1. 需求与目标

1.1 功能需求详述

背景:当前系统已通过multi_uart_routercmd_router模块实现了三端口UART1/UART2/UART3ASCII指令的统一解析与响应路由。

新增功能目标使UART3成为"智能接口",能够根据数据内容自动识别并路由:

数据类型 识别条件 处理路径 响应目标
ASCII指令 符合$CMD,param*CS\r\n格式 现有指令解析流程 返回UART3
透传数据 不符合指令格式 透传引擎转发至UART1 无(单向透传)

具体场景

  1. 场景A - 纯指令流

    • UART3接收$DI*2F\r\n
    • 识别为指令 → CmdParser解析 → 执行DI查询 → 响应返回UART3
  2. 场景B - 纯透传数据

    • UART3接收Hello World\r\n(无$起始符)
    • 识别为透传 → 直接转发至UART1RF433发送
  3. 场景C - 混合交织数据

    • UART3接收$DI*2F\r\nDATA_TO_FWD\r\n
    • 前半段识别为指令,执行后
    • 后半段无$起始识别为透传转发至UART1
  4. 场景D - 透传数据中出现$字符

    • UART3接收Some Data $10 more
    • 由于前面不是$开头,前半部分透传
    • 后续若出现完整指令格式则按指令处理

1.2 非功能性需求

指标 目标值 说明
实时性 - 透传延迟 ≤10ms 从UART3接收到UART1开始发送的延迟
实时性 - 指令响应 ≤50ms 指令解析到响应发送的总时间
可靠性 - 指令识别准确率 ≥99.9% 误判率≤0.1%
吞吐量 - 透传能力 ≥9600 Baud 匹配UART3物理层速率
资源消耗 - Flash增量 ≤4KB 新增代码占用
资源消耗 - RAM增量 ≤1KB 缓冲区及状态机占用
CPU占用率 ≤15% 峰值情况

1.3 与现有系统的关系

┌─────────────────────────────────────────────────────────────────────┐
│                        现有系统架构                                  │
├─────────────────────────────────────────────────────────────────────┤
│                                                                     │
│  ┌──────────────┐                                                   │
│  │ UART3中断    │ ◄── RS485接收字节                                  │
│  └──────┬───────┘                                                   │
│         │                                                           │
│         ▼                                                           │
│  ┌──────────────┐                                                   │
│  │MultiUART    │                                                    │
│  │FeedByte()   │ ◄── 写入环形缓冲区                                  │
│  └──────┬───────┘                                                   │
│         │                                                           │
│         ▼                                                           │
│  ┌──────────────┐                                                   │
│  │CmdRouter    │                                                    │
│  │Task()       │ ◄── 轮询读取缓冲区                                   │
│  └──────┬───────┘                                                   │
│         │                                                           │
│         ▼                                                           │
│  ┌──────────────┐                                                   │
│  │CmdParser    │                                                    │
│  │FeedByte()   │ ◄── 所有数据统一解析                                 │
│  └──────────────┘                                                   │
│                                                                     │
└─────────────────────────────────────────────────────────────────────┘

                          ▼ 增量设计 ▼

┌─────────────────────────────────────────────────────────────────────┐
│                        新增功能架构                                  │
├─────────────────────────────────────────────────────────────────────┤
│                                                                     │
│  ┌──────────────┐                                                   │
│  │ UART3中断    │                                                   │
│  └──────┬───────┘                                                   │
│         │                                                           │
│         ▼                                                           │
│  ┌──────────────┐                                                   │
│  │MultiUART    │                                                    │
│  │FeedByte()   │                                                    │
│  └──────┬───────┘                                                   │
│         │                                                           │
│         ▼                                                           │
│  ┌──────────────────────────────────────────────────────┐           │
│  │          UART3协议识别器 (Protocol Discriminator)       │           │
│  │  ┌─────────────────────────────────────────────────┐  │           │
│  │  │ 状态机: INIT → SCAN → CMD_MODE / PASSTHROUGH    │  │           │
│  │  │ 识别结果: 指令 or 透传                            │  │           │
│  │  └─────────────────────────────────────────────────┘  │           │
│  └────────────────────────┬──────────────────────────────┘           │
│                           │                                          │
│           ┌───────────────┴───────────────┐                          │
│           ▼                               ▼                          │
│  ┌──────────────────┐        ┌──────────────────────┐                │
│  │   CMD_MODE       │        │   PASSTHROUGH_MODE   │                │
│  │                  │        │                      │                │
│  │ CmdParser       │        │ 透传引擎             │                │
│  │ FeedByte()      │        │ Passthrough_Task()   │                │
│  │      ↓          │        │      ↓              │                │
│  │ 执行指令        │        │ MultiUART_Send()    │                │
│  │      ↓          │        │ (UART1)            │                │
│  │ 响应→UART3      │        │                    │                │
│  └──────────────────┘        └──────────────────────┘                │
│                                                                     │
└─────────────────────────────────────────────────────────────────────┘

2. 系统架构设计

2.1 当前UART3数据处理流程分析

基于代码分析当前UART3数据处理流程如下

// main.c 中的中断回调(假设已实现)
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
    if (huart->Instance == USART3) {
        MultiUART_FeedByte(PORT_UART3, uart3_rx_byte);
        HAL_UART_Receive_IT(&huart3, &uart3_rx_byte, 1);
    }
}

// cmd_router.c - CmdRouter_Task()
void CmdRouter_Task(void)
{
    // ... UART1/UART3处理 ...

    for (port_id_t port_id = 0; port_id < PORT_COUNT; port_id++) {
        if (port_id == PORT_UART2) continue;  // UART2单独处理

        uint8_t byte;
        while (MultiUART_ReadByte(port_id, &byte) > 0) {
            CmdParser_FeedByte(byte, HAL_GetTick());  // 统一喂给解析器
        }
    }

    CmdParser_Task();  // 处理已解析完成的指令
}

问题分析

  1. 无区分机制所有UART3数据统一喂给CmdParser,无法处理透传数据
  2. 解析器污染:非指令数据进入解析器会触发错误计数
  3. 缺乏透发转发即使识别出透传数据也没有转发至UART1的机制

2.2 目标架构与数据流图

2.2.1 整体数据流图

                           UART2 (调试日志)
                                  ▲
                                  │ DEBUG_LOG()
                                  │
┌─────────────────────────────────┴─────────────────────────────────┐
│                        UART3智能数据路由                            │
│                                                                   │
│  ┌─────────────────────────────────────────────────────────────┐ │
│  │                    UART3 ISR (每字节)                          │ │
│  └──────────────────────────┬────────────────────────────────────┘ │
│                             │ byte                                 │
│                             ▼                                      │
│  ┌─────────────────────────────────────────────────────────────┐ │
│  │                   协议识别器 (Protocol Discriminator)           │ │
│  │                                                              │ │
│  │  ┌──────────┐   byte   ┌──────────┐   识别结果              │ │
│  │  │  INIT    │ ──────► │  SCAN    │ ──────►                 │ │
│  │  └──────────┘         └────┬─────┘                           │ │
│  │                             │                                  │ │
│  │         ┌───────────────────┼───────────────────┐             │ │
│  │         │                   │                   │             │ │
│  │    遇到'$'              超时(50ms)         遇到'\n'           │ │
│  │         │                   │                   │             │ │
│  │         ▼                   ▼                   ▼             │ │
│  │  ┌───────────┐      ┌────────────┐      ┌───────────┐      │ │
│  │  │ CMD_MODE  │      │PASSTHROUGH  │      │ CMD_MODE  │      │ │
│  │  │ (指令解析) │      │ (透传转发)  │      │ (已完整帧) │      │ │
│  │  └─────┬─────┘      └──────┬──────┘      └─────┬─────┘      │ │
│  │        │                   │                   │             │ │
│  └────────┼───────────────────┼───────────────────┼─────────────┘ │
│           │                   │                   │                │
│           ▼                   │                   ▼                │
│  ┌──────────────────┐         │         ┌──────────────────┐       │
│  │ CmdParser       │         │         │ 缓存已接收字节    │       │
│  │ FeedByte()      │         │         │ 等待透传引擎处理  │       │
│  └────────┬────────┘         │         └────────┬─────────┘       │
│           │                  │                  │                  │
│           ▼                  │                  ▼                  │
│  ┌──────────────────┐        │         ┌──────────────────┐       │
│  │ 指令执行         │        │         │ Passthrough_Task │       │
│  │ + 响应→UART3    │        │         │ 转发至UART1      │       │
│  └──────────────────┘        │         └──────────────────┘       │
│                               │                                    │
└───────────────────────────────┼────────────────────────────────────┘
                                │
                                ▼
                    ┌──────────────────────┐
                    │ UART1 (RF433)        │
                    │ 透明传输至远端       │
                    └──────────────────────┘

2.2.2 模块划分与职责

模块 职责 文件位置
Protocol Discriminator UART3协议识别与模式切换 uart3_router.[c/h](新增)
Passthrough Engine 透传数据缓冲与发送 uart3_passthrough.[c/h](新增)
CmdRouter 修改:集成协议识别器 修改现有

2.3 关键设计决策

2.3.1 协议识别策略

方案:基于启发式规则的早期判断

策略 描述 优势 劣势
起始符检测 $开头视为指令候选 简单直接 透传数据中包含$会误判
字符集分析 指令字符集受限A-Z,0-9,,* 可区分乱码 需要一定积累
超时触发 一定时间无$则判定为透传 防止长数据堆积 增加延迟
帧间隔检测 \n后重新判断 符合协议特性 依赖协议格式

选定方案:起始符 + 超时触发的混合模式

状态机逻辑:
1. 初始状态 INIT
2. 接收到'$' → 进入CMD_MODE开始指令解析
3. 接收到非'$'字节 → 启动50ms超时计时器进入SCAN状态
4. SCAN状态下
   - 遇到'$' → 清空已接收数据进入CMD_MODE
   - 超时(50ms) → 已接收数据判定为透传进入PASSTHROUGH_MODE
   - 遇到'\n' → 已接收数据判定为透传进入PASSTHROUGH_MODE
5. CMD_MODE下遇到完整帧(\r\n) → 执行指令然后返回SCAN状态

为什么是50ms

  • UART3@9600bps1字节 ≈ 1.04ms
  • 50ms ≈ 48字节数据的传输时间
  • 足够接收一个短指令的开销

2.3.2 路由切换机制

场景分析:指令解析过程中发现格式错误

接收序列: $ABC,XYZ*12\r\n

正常流程:
  '$' → CMD_MODE
  'A','B','C' → 解析命令
  ',' → 解析参数
  ... 完整帧 → 执行

异常流程(指令不存在):
  '$' → CMD_MODE
  ... 解析完成 → 执行 → 发现CMD未知
  → 返回错误响应 → 但数据已完全接收

错误切换场景:
  接收序列: $INVALID_DATA\r\n

  '$' → CMD_MODE
  ... 解析命令 'INVALID'
  遇到 '\r' → 校验和验证失败
  → 判定为"错误指令帧"
  → 不切换为透传而是返回ERR响应

决策:指令解析失败不切换为透传

  • 解析失败(校验和错误、未知命令等)仍按指令处理,返回错误响应
  • 只有在未开始解析的情况下SCAN状态超时才判定为透传
  • 这样可以处理$开头但格式错误的数据

已缓存错误数据的处理

// 场景: SCAN状态下已接收10字节 "RAW_DATA$"
// 此时用户发送的不是完整指令

处理策略:
1.  '$' 后续数据在100ms内未形成完整帧
2. 则将 '$' 及其之前的数据作为透传发送
3. '$' 及其后的数据重新进入SCAN状态判断

2.3.3 缓冲区设计

方案:独立环形缓冲区

方案 优势 劣势 决策
复用UART3 RX环形缓冲区 节省内存 逻辑复杂,需要读写位置管理
独立透传缓冲区 逻辑清晰,隔离性好 额外内存开销

缓冲区容量计算

场景: UART3@9600bps 连续接收大数据
最大传输速率: 960 bytes/sec (9600/10)
透传目标: UART1@9600bps 发送

若UART1发送速度 < UART3接收速度需要缓冲

设计考虑:
- 环形缓冲区大小: 256字节 (2x UART3_RING_SIZE)
- 理由: 透传数据通常是连续数据流,需要足够缓冲应对速度差
- 最坏情况: UART3全速接收UART1正在发送历史数据

透传数据包节点设计

#define PASSTHROUGH_NODE_SIZE  128   // 每个透传节点大小
#define PASSTHROUGH_NODE_COUNT  4     // 节点数量

typedef struct {
    uint8_t data[PASSTHROUGH_NODE_SIZE];
    uint16_t length;          // 有效数据长度
    uint16_t offset;          // 已发送偏移
    bool in_use;              // 是否被占用
} passthrough_node_t;

typedef struct {
    passthrough_node_t nodes[PASSTHROUGH_NODE_COUNT];
    uint8_t write_index;     // 写入位置
    uint8_t read_index;       // 读取位置
    volatile uint16_t total_pending;  // 待发送总字节数
} passthrough_queue_t;

2.3.4 发送流控策略

问题UART3接收速率(9600Baud) > UART1发送速率(可能受RF433限制)

方案:背压反馈 + 缓冲区管理

// 透传引擎发送逻辑
void Passthrough_Task(void)
{
    // 检查UART1是否可发送
    if (!UART1_IsTxReady()) {
        return;  // UART1忙等待下次调度
    }

    // 检查是否有待发送数据
    if (g_passthrough_queue.total_pending == 0) {
        return;
    }

    // 获取下一个待发送节点
    passthrough_node_t *node = &g_passthrough_queue.nodes[g_passthrough_queue.read_index];

    if (node->offset < node->length) {
        // 发送一个字节
        uint8_t byte = node->data[node->offset++];
        MultiUART_Send(PORT_UART1, &byte, 1);
    }

    // 检查节点是否发送完成
    if (node->offset >= node->length) {
        node->in_use = false;
        g_passthrough_queue.read_index = (g_passthrough_queue.read_index + 1) % PASSTHROUGH_NODE_COUNT;
        g_passthrough_queue.total_pending -= node->length;
    }
}

背压策略

  • 当透传缓冲区接近满时(total_pending > 200),记录警告日志
  • 当缓冲区满时新数据覆盖最旧数据Lossy机制
  • 始终保证透传通道可用不阻塞UART3中断

3. 模块详细设计

3.1 协议识别器模块

3.1.1 状态机设计

                    ┌─────────────────────────────────────────────────┐
                    │                                                 │
                    │                 状态转换图                       │
                    │                                                 │
                    └─────────────────────────────────────────────────┘

    ┌───────────────────────────────────────────────────────────────────────┐
    │                                                                        │
    │                         ┌─────────────┐                               │
    │                         │    INIT    │  初始状态                      │
    │                         └──────┬──────┘                               │
    │                                │                                       │
    │                    byte != '$' │ byte == '$'                          │
    │                                │                                       │
    │                                ▼                                       │
    │                         ┌─────────────┐                               │
    ├────────────────────────►│    SCAN     │◄──────┐                       │
    │                         └──────┬──────┘       │                       │
    │                                │               │                       │
    │          byte == '$'           │               │                       │
    │           (新起始符)            │ 超时/'\n'     │ '\r'                  │
    │                                │               │                       │
    │                                ▼               │                       │
    │                         ┌─────────────┐       │                       │
    │                         │ CMD_MODE    │───────┘                       │
    │                         └──────┬──────┘    '\n'                       │
    │                                │               │                       │
    │                    帧解析完成  │ 解析失败      │                       │
    │                                │               │                       │
    │                                ▼               │                       │
    │                         ┌─────────────┐       │                       │
    │                         │   EXEC     │───────┘                       │
    │                         │   执行指令  │   (返回SCAN)                  │
    │                         └─────────────┘                               │
    │                                                                        │
    │    PASSTHROUGH_MODE:                                                 │
    │    ┌─────────────┐                                                   │
    │    │  PASSTHROUGH│ ←── (SCAN超时/'\n') ─────────────────────────┐   │
    │    └──────┬──────┘                                                │   │
    │           │                                                        │   │
    │           │ 所有缓存透传数据                                         │   │
    │           │ 发送完成                                                │   │
    │           │                                                        │   │
    │           └────────────────────────────────────────────────────────┘   │
    │                                                                        │
    └───────────────────────────────────────────────────────────────────────┘

状态说明:
- INIT:      系统启动/复位状态,等待第一个字节
- SCAN:      扫描模式,等待指令起始符'$'或透传判定
- CMD_MODE:  指令解析模式数据喂给CmdParser
- EXEC:      指令执行模式
- PASSTHROUGH: 透传模式数据转发至UART1

转换条件:
1. INIT → SCAN:    收到任何字节(非'$')
2. SCAN → CMD_MODE: 收到'$'
3. SCAN → PASSTHROUGH: 超时(50ms) 且有数据 或 收到'\n'
4. CMD_MODE → EXEC:  收到'\n' 且帧解析完成
5. CMD_MODE → SCAN:  收到'\r'
6. EXEC → SCAN:      指令执行完成
7. PASSTHROUGH → SCAN: 透传数据全部发送完成

3.1.2 伪代码实现

/**
 * UART3协议识别器上下文
 */
typedef struct {
    enum {
        STATE_INIT = 0,
        STATE_SCAN,
        STATE_CMD_MODE,
        STATE_EXEC,
        STATE_PASSTHROUGH
    } state;

    uint32_t last_byte_tick;      // 上次收到字节的时间
    uint32_t scan_start_tick;      // SCAN状态开始时间
    uint8_t scan_buffer[128];      // SCAN状态缓存
    uint16_t scan_length;          // SCAN缓存长度
    bool pending_cmd;             // CMD_MODE是否有待处理帧
    uint32_t passthrough_bytes;   // 透传字节计数
} uart3_protocol_context_t;

// 超时阈值
#define SCAN_TIMEOUT_MS    50     // SCAN状态超时时间
#define CMD_COMPLETE_TIMEOUT_MS  200  // 指令帧完整接收超时

/**
 * @brief  协议识别器字节输入
 * @note   由UART3中断调用判断字节应该走指令路径还是透传路径
 * @param  byte: 接收字节
 * @param  current_tick: 当前系统时间
 * @retval uint8_t: 识别结果 (ROUTE_CMD / ROUTE_PASSTHROUGH / ROUTE_NONE)
 */
uint8_t UART3_ProtocolDiscriminator(uint8_t byte, uint32_t current_tick)
{
    uart3_protocol_context_t *ctx = &g_uart3_proto_ctx;

    switch (ctx->state) {
        case STATE_INIT:
            ctx->last_byte_tick = current_tick;
            if (byte == '$') {
                ctx->state = STATE_CMD_MODE;
                ctx->scan_length = 0;
                return ROUTE_CMD;  // '$'交给CmdParser
            } else {
                // 非'$'开始SCAN
                ctx->state = STATE_SCAN;
                ctx->scan_start_tick = current_tick;
                ctx->scan_buffer[0] = byte;
                ctx->scan_length = 1;
                return ROUTE_NONE;  // 暂时缓存
            }

        case STATE_SCAN:
            ctx->last_byte_tick = current_tick;

            if (byte == '$') {
                // 发现新指令起始符
                if (ctx->scan_length > 0) {
                    // 之前的数据判定为透传
                    ctx->state = STATE_PASSTHROUGH;
                    return ROUTE_PASSTHROUGH;  // 触发透传
                } else {
                    // 空扫描直接进入CMD_MODE
                    ctx->state = STATE_CMD_MODE;
                    return ROUTE_CMD;
                }
            } else if (byte == '\n') {
                // 帧结束,判定为透传
                ctx->state = STATE_PASSTHROUGH;
                return ROUTE_PASSTHROUGH;
            } else {
                // 其他字符加入SCAN缓存
                if (ctx->scan_length < sizeof(ctx->scan_buffer)) {
                    ctx->scan_buffer[ctx->scan_length++] = byte;
                }
                return ROUTE_NONE;
            }

        case STATE_CMD_MODE:
            ctx->last_byte_tick = current_tick;
            // 所有数据都交给CmdParser
            return ROUTE_CMD;

        case STATE_PASSTHROUGH:
            // 透传模式下,新数据继续加入透传缓存
            // 注意:此时透传引擎应该正在发送已缓存数据
            return ROUTE_PASSTHROUGH;

        default:
            ctx->state = STATE_INIT;
            return ROUTE_NONE;
    }
}

/**
 * @brief  协议识别器状态检查(定时调用)
 * @note   检查SCAN状态是否超时
 * @retval bool: true=触发了透传false=继续等待
 */
bool UART3_ProtocolDiscriminator_CheckTimeout(uint32_t current_tick)
{
    uart3_protocol_context_t *ctx = &g_uart3_proto_ctx;

    if (ctx->state == STATE_SCAN && ctx->scan_length > 0) {
        if (current_tick - ctx->scan_start_tick >= SCAN_TIMEOUT_MS) {
            ctx->state = STATE_PASSTHROUGH;
            return true;
        }
    }

    return false;
}

/**
 * @brief  获取透传模式下的缓存数据
 * @param  buffer: 输出缓冲区
 * @param  length: 数据长度
 * @retval bool: true=有数据false=无数据
 */
bool UART3_GetPassthroughData(uint8_t *buffer, uint16_t *length)
{
    uart3_protocol_context_t *ctx = &g_uart3_proto_ctx;

    if (ctx->state == STATE_PASSTHROUGH && ctx->scan_length > 0) {
        memcpy(buffer, ctx->scan_buffer, ctx->scan_length);
        *length = ctx->scan_length;
        ctx->scan_length = 0;
        ctx->state = STATE_INIT;  // 重置状态
        return true;
    }

    return false;
}

3.1.3 输入/输出接口

// uart3_protocol_discriminator.h

#ifndef __UART3_PROTOCOL_DISCRIMINATOR_H
#define __UART3_PROTOCOL_DISCRIMINATOR_H

#include <stdint.h>
#include <stdbool.h>

// 路由结果枚举
typedef enum {
    ROUTE_NONE = 0,        // 暂时缓存,不路由
    ROUTE_CMD,             // 路由至指令解析器
    ROUTE_PASSTHROUGH      // 路由至透传引擎
} route_result_t;

// 初始化
void UART3_Protocol_Init(void);

// 字节输入
route_result_t UART3_Protocol_FeedByte(uint8_t byte, uint32_t current_tick);

// 超时检查(定时调用)
bool UART3_Protocol_CheckTimeout(uint32_t current_tick);

// 获取透传数据
bool UART3_Protocol_GetPassthroughData(uint8_t *buffer, uint16_t *length);

// 获取当前状态(调试用)
uint8_t UART3_Protocol_GetState(void);

#endif

3.1.4 与CmdParser的交互关系

关键设计

  • 协议识别器位于CmdRouter_Task之前,先判断数据类型
  • 只有识别为CMD的数据才喂给CmdParser
  • 透传数据写入独立缓冲区,由透传引擎处理
// 修改后的 CmdRouter_Task() 逻辑

void CmdRouter_Task_UART3_Enhanced(void)
{
    uint32_t current_tick = HAL_GetTick();

    // 1. 读取UART3接收缓冲区
    uint8_t byte;
    while (MultiUART_ReadByte(PORT_UART3, &byte) > 0) {

        // 2. 协议识别
        route_result_t route = UART3_Protocol_FeedByte(byte, current_tick);

        switch (route) {
            case ROUTE_CMD:
                // 指令路径喂给CmdParser
                CmdParser_FeedByte(byte, current_tick);
                LOG_DEBUG("UART3 CMD: 0x%02X", byte);
                break;

            case ROUTE_PASSTHROUGH:
                // 透传路径:写入透传缓冲区
                Passthrough_PushByte(byte);
                LOG_DEBUG("UART3 PTX: 0x%02X", byte);
                break;

            case ROUTE_NONE:
                // 暂时缓存,不处理
                break;
        }
    }

    // 3. 检查SCAN超时
    if (UART3_Protocol_CheckTimeout(current_tick)) {
        // 超时触发透传
        uint8_t buffer[128];
        uint16_t length;
        if (UART3_Protocol_GetPassthroughData(buffer, &length)) {
            Passthrough_PushBuffer(buffer, length);
            LOG_INFO("UART3 PASSTHROUGH triggered: %d bytes", length);
        }
    }

    // 4. 透传引擎任务
    Passthrough_Task();

    // 5. 指令解析任务
    if (CmdParser_HasCompleteFrame(NULL)) {
        // 指令解析完成,等待执行
    }
    CmdParser_Task();
}

3.2 透传引擎模块

3.2.1 模块接口设计

// uart3_passthrough.h

#ifndef __UART3_PASSTHROUGH_H
#define __UART3_PASSTHROUGH_H

#include <stdint.h>
#include <stdbool.h>

// 透传引擎配置
#define PASSTHROUGH_TX_BUFFER_SIZE   256   // 发送缓冲区大小
#define PASSTHROUGH_MAX_QUEUE_SIZE   4     // 最大队列节点数
#define PASSTHROUGH_NODE_SIZE        128    // 每个节点大小

// 透传统计结构
typedef struct {
    uint32_t total_bytes_sent;      // 累计发送字节数
    uint32_t total_packets;         // 累计发送数据包数
    uint32_t overflow_count;         // 缓冲区溢出次数
    uint32_t busy_count;             // UART1忙等待次数
} passthrough_stats_t;

/**
 * @brief  透传引擎初始化
 */
void Passthrough_Init(void);

/**
 * @brief  压入单字节到透传缓冲区
 * @param  byte: 待发送字节
 * @retval bool: true=成功false=缓冲区满
 */
bool Passthrough_PushByte(uint8_t byte);

/**
 * @brief  压入数据块到透传缓冲区
 * @param  data: 数据缓冲区
 * @param  length: 数据长度
 * @retval uint16_t: 实际写入的字节数
 */
uint16_t Passthrough_PushBuffer(const uint8_t *data, uint16_t length);

/**
 * @brief  透传引擎任务(应周期性调用)
 * @note   每次调用尝试发送一个字节
 */
void Passthrough_Task(void);

/**
 * @brief  检查UART1是否就绪
 * @retval bool: true=可发送false=忙
 */
bool Passthrough_CanSend(void);

/**
 * @brief  获取透传统计信息
 * @param  stats: 统计结构指针
 */
void Passthrough_GetStats(passthrough_stats_t *stats);

/**
 * @brief  重置统计信息
 */
void Passthrough_ResetStats(void);

#endif

3.2.2 核心数据结构

// 透传数据节点
typedef struct {
    uint8_t data[PASSTHROUGH_NODE_SIZE];
    uint16_t length;           // 有效数据长度
    uint16_t offset;           // 已发送偏移
    bool valid;                // 节点是否有效
} passthrough_node_t;

// 透传队列
typedef struct {
    passthrough_node_t nodes[PASSTHROUGH_MAX_QUEUE_SIZE];
    uint8_t write_index;                       // 写入位置
    uint8_t read_index;                        // 读取位置
    volatile uint16_t pending_count;           // 待发送字节总数
    uint8_t current_node;                      // 当前处理节点
} passthrough_queue_t;

// 透传引擎上下文
typedef struct {
    passthrough_queue_t queue;
    passthrough_stats_t stats;
    bool initialized;
} passthrough_context_t;

static passthrough_context_t g_passthrough_ctx;

3.2.3 发送任务工作流程

/**
 * @brief  透传引擎任务
 * @note   在主循环中周期性调用,每次尝试发送一个字节
 *         配合UART1 TX完成中断实现连续发送
 */
void Passthrough_Task(void)
{
    passthrough_context_t *ctx = &g_passthrough_ctx;

    // 检查是否有待发送数据
    if (ctx->queue.pending_count == 0) {
        return;
    }

    // 检查UART1是否可发送
    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) {
        // 节点数据已发送完毕,移动到下一个
        node->valid = false;
        ctx->queue.read_index = (ctx->queue.read_index + 1) % PASSTHROUGH_MAX_QUEUE_SIZE;
        ctx->queue.current_node++;
        return;
    }

    // 发送一个字节
    uint8_t byte = node->data[node->offset++];
    MultiUART_Send(PORT_UART1, &byte, 1);

    ctx->queue.pending_count--;
    ctx->stats.total_bytes_sent++;
}

/**
 * @brief  UART1发送完成回调
 * @note   应在HAL_UART_TxCpltCallback中调用
 */
void Passthrough_OnTxComplete(void)
{
    // 触发下一次发送
    Passthrough_Task();
}

/**
 * @brief  压入数据块
 */
uint16_t Passthrough_PushBuffer(const uint8_t *data, uint16_t length)
{
    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_QUEUE_SIZE;
        if (next_index == ctx->queue.read_index && ctx->queue.pending_count > 0) {
            // 队列满,溢出处理
            ctx->stats.overflow_count++;
            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++;
    }

    ctx->stats.total_packets++;
    return written;
}

bool Passthrough_CanSend(void)
{
    // 检查UART1 TX是否忙
    return (MultiUART_GetTxAvailable(PORT_UART1) > 0) &&
           (g_passthrough_ctx.queue.pending_count > 0);
}

3.3 与现有模块的集成

3.3.1 修改CmdRouter_Task

// cmd_router.c - 新增UART3专用处理

// UART3是否启用智能路由模式
#ifndef UART3_SMART_ROUTING_ENABLED
#define UART3_SMART_ROUTING_ENABLED  1
#endif

void CmdRouter_Task(void)
{
    uint32_t current_tick = HAL_GetTick();

    // 1. 处理UART1 (RF433)
    // ... 保持现有逻辑 ...

    // 2. 处理UART3 - 智能路由模式
    #if UART3_SMART_ROUTING_ENABLED
    if (UART3_SMART_ROUTING_ENABLED) {
        UART3_SmartRouter_Task(current_tick);
    }
    #else
    // 原有逻辑所有数据喂给CmdParser
    uint8_t byte;
    while (MultiUART_ReadByte(PORT_UART3, &byte) > 0) {
        CmdParser_SetSourcePort(PORT_UART3);
        CmdParser_FeedByte(byte, current_tick);
    }
    #endif

    // 3. 处理UART2 (调试串口)
    // ... 保持现有逻辑 ...

    // 4. 执行已解析的指令
    CmdParser_Task();
}

/**
 * @brief  UART3智能路由任务
 */
static void UART3_SmartRouter_Task(uint32_t current_tick)
{
    uint8_t byte;

    // 读取所有待处理的字节
    while (MultiUART_ReadByte(PORT_UART3, &byte) > 0) {
        // 协议识别
        route_result_t route = UART3_Protocol_FeedByte(byte, current_tick);

        switch (route) {
            case ROUTE_CMD:
                // 指令路径
                CmdParser_SetSourcePort(PORT_UART3);
                CmdParser_FeedByte(byte, current_tick);
                LOG_DEBUG("[UART3] CMD byte: 0x%02X", byte);
                break;

            case ROUTE_PASSTHROUGH:
                // 透传路径
                Passthrough_PushByte(byte);
                LOG_DEBUG("[UART3] PTX byte: 0x%02X", byte);
                break;

            case ROUTE_NONE:
                // 缓存中,不处理
                break;
        }
    }

    // 检查SCAN超时
    if (UART3_Protocol_CheckTimeout(current_tick)) {
        uint8_t buffer[128];
        uint16_t length;
        if (UART3_Protocol_GetPassthroughData(buffer, &length)) {
            Passthrough_PushBuffer(buffer, length);
            LOG_INFO("[UART3] PASSTHROUGH: %d bytes queued", length);
        }
    }

    // 执行透传引擎任务
    Passthrough_Task();
}

3.3.2 透传引擎发送接口

// 复用现有的 MultiUART_Send(PORT_UART1, data, len)
// 透传引擎将数据写入UART1的发送缓冲区
// 由MultiUART_TxCpltCallback驱动后续发送

附录A关键数据结构定义

// 协议识别器上下文
typedef struct {
    uint8_t state;                     // 当前状态
    uint32_t last_byte_tick;           // 上次收到字节时间
    uint32_t scan_start_tick;           // SCAN状态开始时间
    uint8_t scan_buffer[128];           // SCAN状态缓存
    uint16_t scan_length;               // SCAN缓存长度
    uint32_t cmd_frame_count;           // 指令帧计数
    uint32_t passthrough_bytes;         // 透传字节计数
    uint32_t mode_switch_count;         // 模式切换次数
} uart3_protocol_context_t;

// 透传节点
typedef struct {
    uint8_t data[128];
    uint16_t length;
    uint16_t offset;
    bool valid;
} passthrough_node_t;

// 透传队列
typedef struct {
    passthrough_node_t nodes[4];
    uint8_t write_index;
    uint8_t read_index;
    volatile uint16_t pending_count;
} passthrough_queue_t;

// 透传引擎上下文
typedef struct {
    passthrough_queue_t queue;
    uint32_t total_bytes_sent;
    uint32_t total_packets;
    uint32_t overflow_count;
    uint32_t busy_count;
    bool initialized;
} passthrough_context_t;

附录D配置参数

// uart3_smart_router_config.h

#ifndef __UART3_SMART_ROUTER_CONFIG_H
#define __UART3_SMART_ROUTER_CONFIG_H

// 协议识别器配置
#define SCAN_TIMEOUT_MS              50      // SCAN状态超时时间
#define SCAN_BUFFER_SIZE             128     // SCAN缓存大小
#define CMD_COMPLETE_TIMEOUT_MS       200     // 指令帧完整接收超时

// 透传引擎配置
#define PASSTHROUGH_NODE_SIZE         128     // 每个透传节点大小
#define PASSTHROUGH_MAX_NODES         4       // 最大节点数
#define PASSTHROUGH_TOTAL_BUFFER      (PASSTHROUGH_NODE_SIZE * PASSTHROUGH_MAX_NODES)  // 512 bytes

// 功能开关
#define UART3_SMART_ROUTING_ENABLED   1       // 1=启用智能路由 0=原有逻辑
#define PASSTHROUGH_LOG_ENABLED       1       // 1=启用透传日志

// 调试配置
#define DEBUG_PROTOCOL_DISCRIMINATOR  1       // 协议识别器调试
#define DEBUG_PASSTHROUGH_ENGINE     1       // 透传引擎调试

#endif