7f393956cc
- 12/14 条建议已落地,按"只保留待办"约定重写本文件 - 保留:S12 断言宏、S1-c 可选单测、A-4 采集链路测试约束 - 保留:A-5 残余(CI 体积门禁盲区) - 保留:错误码通道四要素(设计基线,供后续驱动接入沿用) - 删除:S1-a/S1-b、S2~S11、S13、S14;T-1~T-5;A-1~A-3/A-6/A-7 - 删除:评价表/盘点表、路线图、总结、变更记录 - 同步修正 6 个外部文档对本文件章节的死引用 - 新增"编号约定":S/T/A 编号不随条目删除而回收
10 KiB
10 KiB
模拟器差距清单(PC 模拟器 vs 真机)
用途:把散落在各子系统文档里的"模拟器无法建模 X"汇成单一事实源,回答一个关键问题—— 模拟器回归通过 ≠ 真机通过,那么差在哪?差多少?哪些必须真机补测? 性质:登记册(living document)。新增模拟器后端差异时必须在此登记一行,不得只写在别处。 上游依据:
审查记录/下一步任务规划.md§3.1(N-4 二期门禁)。 相关:UI设计/LVGL模拟器部署与使用说明.md(部署与使用)、simulator/README.md(目录与架构)、测试说明/测试开发标准流程.md(L3 门禁在测试分层中的位置)。
0. 一句话结论
模拟器覆盖的是 「纯逻辑 + 平台抽象之上」的那一层:UI 场景/渲染/导航、配置引擎、日志记录格式、
net_*BSD API 之上的协议状态机。它不覆盖「硬件时序 / 中断 / 真实复位 / CH395F 与 NAND 芯片行为」。 因此 L3(模拟器回归)与 L1/L2(板端套件 /@test闭环)互补而非替代——见 §3 的"什么时候必须回真机"。
1. 模拟器覆盖范围(基线)
| 覆盖 | 说明 |
|---|---|
| UI 场景层 | Drivers/BSP/UI/ui_menu.c 等同一份源码,MCU 与 PC 共用(simulator/README.md §2.3) |
| 渲染链路 | LVGL I1 渲染 → SDL 窗口(MCU 端为帧缓冲 → RemoDispBus) |
| 配置文件引擎 | App/cfg/cfg_file.c 共享核心 + cfg_file_store_sim.c(宿主文件 sim_config.ini) |
net_* BSD API 之上的协议 |
ui_net_sink.c(RemoDispBus 服务端,TCP 7003)与 net_socket_sim.c(Winsock 后端) |
| 日志记录格式 | sys_log 定长记录编解码(sim_syslog.c 写宿主文件) |
不覆盖:CH395F 真实网络栈、GD5F NAND、SD2506 RTC、TPAFE5160 ADC、RS-485、IWDG、中断/时序相关行为。
2. 差距清单
列含义:
模拟器行为/真机行为描述差异本身;影响说明它会让什么 bug 逃过模拟器回归;回归补测给出"模拟器过 ≠ 真机过"时应补的真机手段(@test/ 板端套件 / 目检)。
2.1 网络(net_socket_sim.c vs net_socket.c)
| # | 差距 | 模拟器行为 | 真机行为 | 影响 | 回归补测 |
|---|---|---|---|---|---|
| N-1 | 无 pending 机制 | net_accept/net_send 直接失败或阻塞于宿主 socket;无"挂起队列"概念 |
异步 TCP 状态机,accept/send 可处于 pending,由 net_poll 推进 |
E-06(accept 轮询计时失真)、E-20(lftpd 控制通道 errno 分类)、E-21(timeSync errno 分级)等在模拟器上无法复现 | @test + FTP 套件;N-4 二期专门建模 |
| N-2 | 代次号恒为 0 | net_get_generation() 恒返 0(无"网络重建"概念) |
每次 net_stack_bring_up / 重配置递增,各 TCP 服务据此重建监听 |
"网络重建后服务是否重建监听" 的逻辑在模拟器上恒走同一分支 | @test 网络重配置用例(UI 改 IP 免重启生效) |
| N-3 | net_process_messages / net_recv_to 等缺失 |
未实现(MCU 专属:CH395F 消息队列驱动、带超时接收) | 由 netMsgQueue 串行化 SPI 事务、支持毫秒级超时接收 |
依赖"带超时接收"与"消息泵"的上层逻辑在模拟器上不可编译/不可运行 | 板端 CH395F / NET 套件 |
| N-4 | Socket 失效语义不同 | 以 in_use 判活(net_socket_sim.c 设计要点 4) |
监听 Socket 随客户端一同失效,需 net_relisten 显式重建 |
"客户端断线 → 监听失效 → 重连" 的黏滞状态在模拟器上不出现 | check_remo_sink.py 覆盖重连;真机 @test |
| N-5 | 单连接 backlog | NET_SIM_BACKLOG = 1 |
CH395F 多 socket 并发 | 多客户端并发场景(FTP + 推流 + timeSync 同时)不可在模拟器验证 | 板端 NET 套件 + 台架并发场景 |
| N-6 | 非阻塞语义模拟 | 创建即 FIONBIO,使 DONTWAIT 语义与 MCU 对齐(设计要点 2) |
中断驱动 + 状态机,天然非阻塞 | ——(此项是对齐而非差距,登记以说明"为何模拟器能测非阻塞路径") | —— |
2.2 日志与配置
| # | 差距 | 模拟器行为 | 真机行为 | 影响 | 回归补测 |
|---|---|---|---|---|---|
| L-1 | 控制台单写者无对应实现 | simulator/dbg_log.h 把 DBG_* 映射到 printf;不编译 console_log.c |
单写者环形缓冲 + defaultTask 唯一发送 | console_log 的环形缓冲溢出/丢弃计数逻辑模拟器测不到;共享代码若误调 console_log.h 声明,模拟器链接失败(已被此约束捕获) |
@test + 板端串口观测;docs/子系统设计/控制台单写者日志设计说明.md §219 |
| L-2 | mtime 粒度不同 | 宿主文件 mtime(秒级) | FAT 打包时间(fdate<<16|ftime,分钟级) |
cfg_file_poll 的 (size, mtime) 变更令牌在两端触发时机不同;分钟级粒度下的"同分钟内两次改动"在真机可能被判为无变化 |
板端 STORAGE 套件;配置文件设计说明.md §变更检测 |
| L-3 | 无应用回调(空操作) | 模拟器不注册段回调,cfg_file_poll 重载后回调为空 |
各段回调真正执行(如网络重配置) | "配置变更 → 触发回调 → 副作用"链路在模拟器上只验证到写盘,回调逻辑不覆盖 | @test(配置保存 → UI 生效) |
| L-4 | 堆后端不同 | cfg_store_alloc = 宿主 malloc(堆余量以 MB 计) |
FreeRTOS 堆(configTOTAL_HEAP_SIZE 48 KB,实测最低水位 ~4.8 KB) |
分配失败路径在模拟器上永不触发——P0-1 类"KB 级分配必然返回 NULL"缺陷模拟器照不出来(AGENTS.md 已列为铁律) |
内存预算门禁 + 真机 [HEAP] 水位告警(S11) |
2.3 硬件专属(模拟器完全无对应)
| # | 差距 | 模拟器行为 | 真机行为 | 影响 | 回归补测 |
|---|---|---|---|---|---|
| H-1 | IWDG 硬件行为 | 无 IWDG;sim_port.c 桩(空实现 + 计数器) |
独立看门狗,LSI 时钟驱动,超时真复位 | 真实复位行为、LSI 漂移、RCC_CSR 标志均不可建模;位图/判定逻辑可在模拟器跑(纯 RAM) |
真机 @test(复位原因日志)+ 看门狗单测(L0.5 已覆盖位图逻辑)看门狗设计说明.md §4.9 |
| H-2 | CH395F 芯片 | 无(Winsock 代其 BSD API) | SPI 寄存器/命令/中断、PHY 协商、真实以太网帧 | 寄存器时序、命令回复、中断风暴、PHY 100M 全双工强制 | 板端 CH395F 套件(52 断言点)+ @test |
| H-3 | GD5F NAND | 无 | SPI NAND:BBT 扫描、ECC、坏块管理、dhara FTL | 坏块/ECC/写入失败等路径完全不可测 | 板端 GD5F 套件(76 断言点)+ @test |
| H-4 | SD2506 RTC | 无 | I2C RTC:时间读写、闹钟、温度、电池电压 | 时间源相关(sys_clock_init 降级路径)在模拟器上不可触发 |
板端 RTC 套件(18 断言点)+ sys_clock L0.5(已覆盖算术面) |
| H-5 | TPAFE5160 ADC | 无 | SPI ADC + BUSY EXTI 中断 | 中断驱动采集链路 | 待功能实现(上游 B1) |
| H-6 | RS-485 半双工 | 无 | UART4 + DE 方向控制,DWT 微秒延时 | DE 收发切换时序(特有陷阱) | 待功能实现(上游 B2) |
| H-7 | 启动段硬件初始化 | 只跑纯软件部分 | I2C/SPI 外设初始化、BBT 扫描耗时、FatFS 挂载 | 启动段死机(无看门狗保护窗口)只能在真机复现 | 真机开机日志判读(项目启动顺序管理.md §6.8,S10 落地) |
2.4 哪些差异是"有意的对齐"(非缺陷)
登记以免后人误判为差距:
| 项 | 说明 |
|---|---|
lv_conf.h 独立 |
模拟器 simulator/lv_conf.h 与 MCU Lib/lv_conf.h 相互独立(SDL/主题差异),有意不统一 |
DBG_* → printf |
模拟器 stub 覆盖 MCU 版头(simulator/README.md 文件职责表),有意 |
NET_NO_OS 剥离 FreeRTOS |
net_socket_sim.c 构建时定义,剥离 RTOS 依赖,有意 |
| 无 SDL_PollEvent | LVGL SDL 驱动内部统一轮询,主循环轮询会吞键盘事件(simulator/README.md 已知坑 7) |
3. 什么时候必须回真机(决策规则)
模拟器回归(L3)通过后,满足以下任一条件即必须走真机(@test / 板端套件):
- 改动触及硬件访问层:
Drivers/BSP/下任何驱动的寄存器/时序/中断代码 - 改动触及 §2.3 的 H-1~H-7 任一子系统的初始化或运行时行为
- 改动触及 §2.2 的 L-2/L-3/L-4:变更检测令牌、段回调副作用、内存分配失败路径
- 涉及网络重建 / 多连接并发(N-2、N-5)
- 涉及启动段(
osKernelStart之前)(H-7) - 涉及内存预算:新增任务/缓冲/栈(L-4;模拟器堆不可作依据)
反之,纯 UI 场景/渲染/导航、配置解析算术、日志记录编解码格式的改动,模拟器 + L0.5 可给出足够信心。
4. 登记约定
- 何时登记:新增/修改
simulator/sim/下任何后端、或发现"某逻辑模拟器走了不同分支"时,必须在 §2 加一行。 - 格式:沿用本表列(差距 / 模拟器行为 / 真机行为 / 影响 / 回归补测)。
- 联动:若该差距影响 L3 门禁的可信度,须同步在
UI设计/UI_自动化测试流程.md引用本清单。 - 收敛:当某差距被 N-4 二期之类的工作消除时,不删行——改标
删除线+ 注明消除日期与提交,保留"曾经差在哪"的历史。
5. 变更记录
| 日期 | 变更 |
|---|---|
| 2026-10-02 | 初版(S13):收录 6 条网络差距(N-1net_socket_sim.c 文件头设计要点 + 双端导出函数逐一对比(MCU 有而 sim 缺 9 个)+ 各子系统文档既有记载汇总。§3 给出 6 条"必须回真机"决策规则 |