Files
STM32F4-Base/test/host/sb_link/run_unit_test.py
T
wandering1 7c8669e52a feat(屏板): USART1 700 kbaud + 收中断传输层 sb_link(1-2/1-3)
批 1 的 1-2 / 1-3:把屏板(DTU-LCD)发来的 6 B 帧 A 在 USART1 上稳定收下来。

1-2 波特率:.ioc 不保存任何 UART 的波特率(只有
USART1.IPParameters=VirtualMode),GUI 里改也不落盘,所以只能在
Src/usart.c 的 USER CODE BEGIN USART1_Init 2 区覆盖 huart1.Init.BaudRate
后重调一次 HAL_UART_Init(第二次调用时 gState 已非 RESET,HAL 只重算
BRR、不再跑 MspInit,GPIO/DMA/NVIC 不会被重配)。开机日志实测
BRR=0x0078,与理论值 84 MHz/(16x700 kHz)=7.5 逐位相符,误差 0%。

1-3 收中断:新建 Drivers/BSP/ScreenLink/sb_link.c/h——16 B 缓冲 + IDLE
中断断帧、帧 A 校验、错误中断里按 RM0090 清 ORE/NE/FE/PE、周期统计上报。
HAL_UARTEx_RxEventCallback / HAL_UART_ErrorCallback 是全局单例(唯一实现
在 rs485.c),故只在那里各加一行转发,按句柄过滤放在 sb_link 内。

台架实测(PC + USB 转 TTL 顶替屏板,COM6@700000)撞出两个真问题:
- 错误回调里无条件重挂 -> 出现 err=160 / rearm=160 同步增长,看着像每帧
  都重挂失败。真因是 HAL 把 NE/FE/PE 归为非阻塞型(接收照跑、RxState 仍是
  BUSY_RX),此时 ReceiveToIdle_IT 只会返回 HAL_BUSY。改为仅当
  RxState == HAL_UART_STATE_READY(ORE 那类阻塞型)时才重挂。
- 日志字面量里带中文 -> ARMCC #870-D invalid multibyte character
  sequence。字面量一律纯 ASCII,中文只写注释。

验证:主机单测 81/81 PASSED(test/host/sb_link/,其中按 RM0090 的清除语义
把"必须 SR->DR 顺序才清得掉 ORE"钉成断言);Keil 0 错误 0 警告;台架
rx == 发送帧数、ok == rx、crc=0、len=0、size=6、keys 随按键帧递增;先用
错波特率灌 64 B 垃圾(len=31、bits=0x06)后自动恢复且 rearm=0。
新增 test/host/screenlink_bench.py 作为可复跑的屏板激励(--key / --glitch-baud)。
2026-10-29 20:13:18 +08:00

60 lines
2.9 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""屏板链路传输层(sb_link)的主机侧单元测试运行器(纯标准库)。
做什么:
用本机 MSVC 编译 test/host/sb_link/sb_link_test.c(它以 #include 纳入**生产源文件**
Drivers/BSP/ScreenLink/sb_link.c 与 sb_proto.c),在 PC 上离线验证 USART1 接收这一层:
挂接收 / IDLE 事件分派 / 坏帧分类 / **错误中断里清 ORE 并重挂** / 重挂失败的码映射 /
周期统计上报(含时基回绕)。零硬件、零烧录、毫秒级。
工具链探测 / INCLUDE-LIB 拼接 / 编译运行 / 退出码判定全部委托给通用 harness
`test/host/common/unit_test_harness.py`(本文件只做声明)。
为什么必须主机侧测(而不是只用台架):
这一层最要命的两条在台架上都"看不见":
① **漏一次重挂 = 链路永久静默**,现象与"屏板没上电 / 线接反"完全同形,没有报错;
② **ORE 没清干净 = 一次噪声永久打死接收**,台架上要拔插 TX 线才复现,且复现后
只能靠断电重来。主机侧用桩把 RM0090 的清除语义(先读 SR 再读 DR)实现出来,
于是"顺序写反"会直接让下一次挂接收失败、用例立刻红。
桩目录(`stub/`,必须排在 include 路径最前,覆盖真实头):
main.h 假 USART 寄存器(读序列可记账、ORE 可注入)+ 假 ReceiveToIdle_IT(返回值可脚本)
dbg_log.h 日志换成行缓冲,于是能断言"打了几行、说了什么"
用法(仓库根目录):
python test/host/sb_link/run_unit_test.py
或统一用 .venv: & '.venv\\Scripts\\python.exe' test/host/sb_link/run_unit_test.py
退出码:0=PASS / 1=测试失败 / 2=环境错误(找不到编译器 / 编译失败 / 无汇总行)。
设计依据:docs/任务规划/屏板链路.md §3 批 1(1-3 的判据)、§1.3(接收只要 16 B);
docs/产品需求/产品需求设计文档.md §5.16.2(帧 A 结构)。
创建日期:2026-10-29
"""
import os
import sys
HERE = os.path.dirname(os.path.abspath(__file__))
ROOT = os.path.dirname(os.path.dirname(os.path.dirname(HERE)))
# harness 位于 test/host/common/
sys.path.insert(0, os.path.join(ROOT, "test", "host", "common"))
from unit_test_harness import TestBuild, run_host_unit_test # noqa: E402
# 桩目录必须排在最前:它覆盖 main.h(真实那份会拉进 core_cm4.h)与 dbg_log.h(会拉进 App 层)
BUILD = TestBuild(
name="ScreenLink Link Tests",
src=os.path.join(HERE, "sb_link_test.c"),
include_dirs=[
os.path.join(HERE, "stub"),
os.path.join(ROOT, "Drivers", "BSP", "ScreenLink"),
os.path.join(ROOT, "Drivers", "BSP"),
HERE,
],
summary_marker="=== ScreenLink Link Tests:",
)
if __name__ == "__main__":
sys.exit(run_host_unit_test(BUILD))