Skip to content

serial组件中的超时事件RT_SERIAL_EVENT_RX_TIMEOUT 仅做了定义 但是为什么不给实现呢 #8143

Open

Description

@meng-plus

Activity

  1. cc-caixf commented on Oct 18, 2023

    @cc-caixf
    Contributor

    我对SERIAL_V2框架的问题:

    假如驱动实现 INT TX 的RT_SERIAL_TX_BLOCKING_NO_BUFFER, 也就是TX用_serial_fifo_tx_blocking_nbuf(),
    那么SERIAL_V2框架里都没有初始化rb, 这里又调用rt_ringbuffer_data_len(), 明显不对.

    (意思就是 驱动 实现TX 中断模式 下用RT_SERIAL_TX_BLOCKING_NO_BUFFER模式, SERIAL_V2框架会出现错误)

  2. Yunlk commented on Oct 20, 2026

    @Yunlk
    Contributor

    盘点结论:宏已定义,但框架两条实现都没接线,驱动 emit 了也是空操作

    一、框架侧现状

    宏定义在 components/drivers/include/drivers/dev_serial.h:168(顺带说明:这个文件原来就是 issue 里链接的 serial.h,后来拆分改名,原链接已失效):

    #define RT_SERIAL_EVENT_RX_TIMEOUT      0x05    /* Rx timeout    */

    v1 —— components/drivers/serial/dev_serial.c

    rt_hw_serial_isr() 的 switch(1536-1695 行)只处理 0x01~0x04:

    case RT_SERIAL_EVENT_RX_IND:      1540
    case RT_SERIAL_EVENT_TX_DONE:     1619
    case RT_SERIAL_EVENT_TX_DMADONE:  1628
    case RT_SERIAL_EVENT_RX_DMADONE:  1656
    

    没有 0x05 的分支,而且整个 switch 没有 default。所以在 v1 下调用 rt_hw_serial_isr(serial, RT_SERIAL_EVENT_RX_TIMEOUT) 完全不做任何事。

    v2 —— components/drivers/serial/dev_serial_v2.c

    rt_hw_serial_isr()(2174-2370 行)同样是那四个 case,末尾是:

        default:
            break;

    0x05 落进 default 被直接丢弃。

    二、为什么两条线都没实现——超时语义本身不同

    这不是「漏写一个 case」,而是这个事件在现有框架里没有落点:

    • v1 根本没有「超时」这个概念。 中断模式收到数据就发 RX_IND,不存在「半帧」状态。要支持这个事件,得先引入定时器 + 半帧状态机,属于新增功能,不是补一个 case。v1 也没有任何超时相关控制命令——RT_SERIAL_CTRL_SET_RX_TIMEOUT 只定义在 dev_serial_v2.h(206 行),v1 侧没有。

    • v2 的超时是「读侧 deadline」,不是「事件」。 v2 提供了 RT_SERIAL_CTRL_SET_RX_TIMEOUT / GET_RX_TIMEOUT(dev_serial_v2.c:195、1641、1684),实现在阻塞读路径里:

    rt_completion_wait(&rx_fifo->rx_cpt, rx_timeout_left);   // 672 行
    ...
    if (delta_tick >= base_rx_timeout) { ... }               // 676 行

    超时表现为 read() 到点返回已经收到的部分数据,由读侧自己兜住,不需要 ISR 再发一个事件。所以 v2 是「用另一套机制解决了同一个问题」。

    三、真正受影响的驱动:2 个,且它们现在都在调空操作

    全仓搜索这个宏只有 4 处出现(1 处定义、2 处调用、1 处已注释):

    文件 行 状态
    components/drivers/include/drivers/dev_serial.h 168 定义
    bsp/wch/arm/ch579m/board/drv_uart.c 335 调用(硬件 UART_II_RECV_TOUT 中断)
    bsp/synwit/libraries/SWM341_drivers/drv_uart.c 287 调用(硬件 UART_IT_RX_TOUT 中断)
    bsp/wch/risc-v/libraries/ch56x_drivers/ch56x_uart.c 293 已注释掉

    两个驱动的用法一致,都是靠芯片自带的接收超时中断来切分数据帧。ch579m 的注释写得很直接:

    case UART_II_RECV_TOUT:         // 接收超时,暂时一帧数据接收完成
        rt_hw_serial_isr(serial, RT_SERIAL_EVENT_RX_TIMEOUT);
        break;

    它们的意图是「超时即一帧收完」。但框架把 0x05 丢掉了,这个「帧结束」信号永远到不了应用层——两个驱动只能靠 RX_IND 按 FIFO 水位上报,帧边界实际上丢了。换句话说,这两处调用目前是看起来生效、实际无效。

    四、建议

    要给一个可实现的方案,得先回答:半帧超时之后,通知谁、带什么信息?三个方向:

    • 方案 A(推荐):让它等价于一次 RX_IND,即 serial->parent.rx_indicate(&serial->parent, <当前 FIFO 中可读长度>)。只补一个 case,不动结构体和 ABI,两个现有驱动的原意立刻能兑现。
    • 方案 B:新增独立回调(如 rx_timeout_cb),语义更清晰,但要改 rt_serial_device 结构,涉及 ABI。
    • 方案 C:明确不支持,删掉这个宏,同时把 ch579m / SWM341 两处调用一并改掉,避免留下「定义了但没实现」的误导。

    我倾向方案 A:改动最小、不破坏兼容性、现有两个驱动直接受益。

    如果需要我做方案 A 的 PR(补 case,并在两个 BSP 上验证),或者先补一份 utest 用例,可以告诉我。

  3. Yunlk commented on Oct 20, 2026

    @Yunlk
    Contributor

    /claim

  4. github-actions commented on Oct 20, 2026

    @github-actions

    @Yunlk has claimed this issue.

  5. Yunlk commented on Oct 20, 2026

    @Yunlk
    Contributor

    更正上一条盘点里的一处说法

    上一条我写「v2 的 rt_hw_serial_isr 同样只有那四个 case,0x05 落进 default: break 被丢弃」。这句话是错的,编译验证时才发现:

    components/drivers/include/drivers/dev_serial_v2.h 只定义了 0x01~0x04,根本没有 RT_SERIAL_EVENT_RX_TIMEOUT:

    #define RT_SERIAL_EVENT_RX_IND          0x01
    #define RT_SERIAL_EVENT_TX_DONE         0x02
    #define RT_SERIAL_EVENT_RX_DMADONE      0x03
    #define RT_SERIAL_EVENT_TX_DMADONE      0x04

    我在 v2 的 isr 里试着加 case RT_SERIAL_EVENT_RX_TIMEOUT:,直接编译失败:

    dev_serial_v2.c:2186:10: error: 'RT_SERIAL_EVENT_RX_TIMEOUT' undeclared
    

    所以准确的说法是:V2 下这个事件不存在,驱动无法引用(会编译不过),不存在"丢进 default"这回事。这个坑只存在于 V1——宏定义了,但 rt_hw_serial_isr 没有对应 case,且 switch 没有 default。

    顺带确认了受影响范围:发出该事件的两个驱动所在的 BSP(bsp/wch/arm/ch579m、bsp/synwit/swm341-mini)都使用 V1 框架,所以确实会命中这个静默丢弃。

    已按方案 A 提了草稿 PR:#11909

    改动只有 V1 的一行 case(把超时并入 RX_IND 分支),V2 不动。附带说明:这个事件由芯片的接收空闲超时中断触发,QEMU 的 pl011 没有该中断,我也没有 ch579m / SWM341 硬件,所以目前只做到编译级验证,没有行为验证。如果认可这个语义方向,我可以补一个不依赖硬件的 utest(直接调 rt_hw_serial_isr,用伪 serial 设备校验 rx_indicate 的次数与长度)。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions