feat(S-5): 收编 SD2506/TPAFE 并给 dhara 失败分类,门禁基线 19→17
前一笔立契约与门禁(`Drivers/BSP/bsp_err.h` + `bsp-err` 钩子 + RS485 试点);这一笔按用户
指定顺序 C3 → C1 → C2 把三个模块真正收编,并让存储失败第一次变得可读、可分类。
**C3 · SD2506 整模块(11 个公共 API + 6 个内部 helper)**:三枚私有宏 `SD2506_OK`/
`SD2506_ERROR`/`SD2506_I2C_ERROR` **删除而不是留别名**——留别名等于新代码还能用旧形状,
把迁移洗掉;编译器替我们找全所有调用点。新增 `sd2506_err_from_hal()`,**把 I2C 超时从
"和没人应答共用一个 −2"里拆出来归成 `BSP_ERR_TIMEOUT`(可重试)**——SD2506 是启动链第一站、
I2C1 上电时序敏感,这是本波唯一真正的语义改善,不是改名。`sd2506_init` 的 charge 寄存器
**回读校验不符**原返参数类错误,改归 `BSP_ERR_IO`(那不是调用方的错)。
**C1 · 同形两义**:`GD5F_BUSY_TIMEOUT` → `GD5F_WAIT_EXPIRED`(**值 −2 不变**,纯消"名字叫
TIMEOUT 其实是返回码")。**GD5F 私有码集整体收编刻意没做**:169 处引用里 48 处在板级套件、
还要动 Trap 记录用词,属另一波带真机+套件回归的工作,不夹带。TPAFE5160 收编 23 处:
`BUSY_TIMEOUT → BSP_ERR_TIMEOUT`、`ERROR → BSP_ERR_PARAM`(**同值 −1,行为零变化**)、
`FRSTDATA_ERR → BSP_ERR_NO_DEVICE`(E-44 的本义就是"芯片没驱动 DB 总线",归到器件无响应比
私有 −3 有用,且避开与 `BSP_ERR_TIMEOUT` 撞值)。实测 `tpafe5160.o`/`gd5f2gq5ue.o` 的 Code
增量为 **0**——改名不产生一条指令。
⚠ **`tpafe5160_snapshot()` 刻意不套成败码**:它是 1=有新帧 / 0=无新帧 / −1=参数错 的三态
**状态**返回,0 不是错误而是"这一拍没有新数据",强行收编会把慢消费者的正常路径变成失败。
顺带订正我上一版在 `bsp_err.h` 的断言——"本层只有 `net_*` 把数量与错误挤同一返回值"是错的,
`snapshot`/`adc_input_poll` 就是第二族;两族现都已写明并各注保留理由。
**C2 · FTL 坍缩点分类**:`ftl_flush_cache`/`ftl_read_page` 不再把 dhara 失败压成
`GD5F_ERROR`,
按**处置差异**分三类,并在最早同时知道 LPN 与原始码的位置就地打印:`ECC`/`TOO_BAD` →
`BSP_ERR_CRC`(页级,重试或换页,不代表卷坏);`JOURNAL_FULL`/`MAP_FULL` →
`BSP_ERR_NO_SPACE`(介质健康但块池/日志见底,此时重格式化只是把问题推回去);
`BAD_BLOCK`/`RECOVER`/`CORRUPT_MAP`/越界 → `BSP_ERR_IO`(完整性故障,保卷 + 上报,不许自愈
重格式化)。这与 **E-31** 是同一条纪律的两端。可读名用自建短表:**本仓 dhara 没有编
`error.c`,用 `dhara_strerror()` 会直接链接失败**。`disk_read`/`disk_write` 仍回
`RES_ERROR`
(FatFs 契约);要让 defaultTask 卷健康探针按类分支还差跨调用存活的快照 → C4 待还。
**两次靠核实拦住的自我错误**:① 我一度认定 `DBG_ERROR("... err=%d", err)` 是把结构体塞进
varargs 的格式 bug——核 `Lib/dhara/error.h` 后确认 `dhara_error_t` 是 `enum`(标量),那行日志
本来合法,改了反而是引入错误;② `bsp-err` 一次 `replace_all` 越界把 8 处 **GD5F 码空间**的
判据改成 `!= BSP_OK`(数值同为 0、无行为变化),但那正是"把两个码空间混起来",已逐一还原。
`cppcheck` 亦抓到 `cls` 声明作用域过宽,已收进失败分支。
**验证**:`@build` 0 错 0 警告(`Code` 213,648、RO 18,860、`ER_IROM1` 232,508 B /
22.2%、
`ROM 合计` 233,696;**RAM 三项零增量**);`@test` PASS(692 ms,烧入戳 `Oct 23 01:35:32`)
且逐条读到被改模块的锚点:`SD2506 init: OK (ret=0)` 与 ID/时间/温度/电池四条读回正常、
`ADC init: OK`、`NAND init: OK`、`Map resumed: 14094/97504`、`adc=` 帧计数持续递增(证明
snapshot 三态未被改坏)、`[ERR]`/Fault/FAIL 0 条。主机单测:系统时钟 100/100、dhara NAND
移植层 149/149(两者都因本次改动需补 `Drivers/BSP` include 路径,补后在钩子内实跑 Passed)。
`pre-commit run` 全量 RC=0(20 个实跑钩子 Passed);`bsp-err` 基线 **19 → 17**(还掉两个
`*_BUSY_TIMEOUT = -2`)、`--prune` 干净;`doc-links --all --sections-strict` 147 篇
0 问题;
`id-check --strict`、`layer-deps`、`mem-numbers`、`mem-budget`、`ui-golden` 全过;33
个文件
字节卫生 0 异常(无 CR / 无 U+FFFD / 无行尾空格 / 均有尾换行)。
**口径与数字联动**:新增 `docs/架构设计/STM32F4-Base存储架构说明.md` §10.4(三类码与处置
理由);`pre-commit使用说明.md` §2.27 与 `AGENTS.md` 基线计数 19 → 17;TPAFE README、
GD5F 测试指南与 Trap 记录均**保留旧名留痕**以便对旧日志;配图桶按 .map 对象级增量重算
(`dhara/FTL` 10,931 → 11,222,+291 全部落在 `nand_ftl.o`;应用代码/UI +36 落在
`app_main.o`;其余散量入"其他"7,557;桶和 = Code+RO 断言通过、文本溢出 0);
`ram_baseline --update/--write`、`ram_report_20261023.md` 快照、报告 §1.3/§5.1/§5.4
与
部署文档 §3.3 数字全部同步;报告 §0.4/§9 的 S-5 状态改为 🟡 主体已落地。
This commit is contained in:
@@ -0,0 +1,173 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
"""BSP 错误码与超时命名约定检查(报告 S-5 的机械检查那一半)。
|
||||
|
||||
为什么要有这个脚本:约定写在 docs 里不会自己生效。同一层的驱动今天并存六套返回约定,
|
||||
而"能不能重试"只写在个别注释里;同形两义的 *_TIMEOUT 已经出现三类(毫秒 / 自旋圈数 /
|
||||
其实是返回码)。没有机械检查,新代码只会继续按各自旧习惯长。
|
||||
|
||||
三条规则(只看 Drivers/BSP 下的公开头文件 = 对外 API 面;lftpd 按第三方排除):
|
||||
R1 公开 API 不得返回 HAL_StatusTypeDef / bool
|
||||
bool 把"为什么失败"整条丢掉;HAL 枚举把 HAL 焊进调用方的 include 链。
|
||||
R2 *_TIMEOUT 宏不得取负值
|
||||
名字叫 TIMEOUT 却是返回码,读代码的人会当成时长;超时应返回 BSP_ERR_TIMEOUT。
|
||||
R3 非 void 的公开 API 必须在紧邻注释块里写「返回值:」
|
||||
约定要能被读到才算约定,也才谈得上审查。
|
||||
|
||||
增量拦截(与 layer-deps / id-check 同构):BASELINE 钉住存量,只减不增,没有 --write。
|
||||
修完一条跑 --prune,它会点名"这条已消失,请从 BASELINE 删除"。
|
||||
|
||||
退出码:0 = 通过;1 = 有新增违规;2 = 用法或扫描错误。
|
||||
"""
|
||||
|
||||
import argparse
|
||||
import re
|
||||
import subprocess
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
ROOT = Path(__file__).resolve().parent.parent
|
||||
EXCLUDE = ("lftpd/",)
|
||||
|
||||
# 存量基线(2026-10-23 清点):"文件|规则|名字"。修掉一条删一行,不要往里加。
|
||||
BASELINE = frozenset(
|
||||
line.strip() for line in """
|
||||
Drivers/BSP/GD5F2GQ5UE/gd5f2gq5ue.h|R3|gd5f_block_erase
|
||||
Drivers/BSP/GD5F2GQ5UE/gd5f2gq5ue.h|R3|gd5f_check_ecc
|
||||
Drivers/BSP/GD5F2GQ5UE/gd5f2gq5ue.h|R3|gd5f_page_read
|
||||
Drivers/BSP/GD5F2GQ5UE/gd5f2gq5ue.h|R3|gd5f_program_exec
|
||||
Drivers/BSP/GD5F2GQ5UE/gd5f2gq5ue.h|R3|gd5f_program_load
|
||||
Drivers/BSP/GD5F2GQ5UE/gd5f2gq5ue.h|R3|gd5f_read_from_cache
|
||||
Drivers/BSP/GD5F2GQ5UE/gd5f2gq5ue.h|R3|gd5f_read_status
|
||||
Drivers/BSP/GD5F2GQ5UE/gd5f2gq5ue.h|R3|gd5f_wait_busy
|
||||
Drivers/BSP/GD5F2GQ5UE/gd5f2gq5ue.h|R3|gd5f_write_enable
|
||||
Drivers/BSP/GD5F2GQ5UE/nand_ftl.h|R3|nand_ftl_format
|
||||
Drivers/BSP/GD5F2GQ5UE/nand_ftl.h|R3|nand_ftl_init
|
||||
Drivers/BSP/UI/ui_content_page.h|R1|ui_content_page_open
|
||||
Drivers/BSP/UI/ui_menu_tab.h|R3|ui_menu_tab_children
|
||||
Drivers/BSP/UI/ui_menu_tab.h|R3|ui_menu_tab_has_children
|
||||
Drivers/BSP/UI/ui_menu_tab.h|R3|ui_menu_tab_has_pwd
|
||||
Drivers/BSP/UI/ui_menu_tab.h|R3|ui_menu_tab_name
|
||||
Drivers/BSP/UI/ui_menu_tab.h|R3|ui_menu_tab_valid
|
||||
""".splitlines() if line.strip()
|
||||
)
|
||||
|
||||
DEFINE_RE = re.compile(r"^\s*#define\s+([A-Z][A-Z_0-9]*TIMEOUT[A-Z_0-9]*)\s+(-[0-9]+)",
|
||||
re.MULTILINE);
|
||||
# bool 用在"提问"上是合法的(is_editable / has_children / is_active…);只有拿 bool 当
|
||||
# **错误通道**才是问题。用名字形状区分,避免把 7 个正当谓词误判成违规、再拿基线去洗规则。
|
||||
PREDICATE_RE = re.compile(r"(^|_)(is|has|can|should|need|valid|active|open|empty)_|" +
|
||||
r"_(is|has|can|valid)$")
|
||||
DECL_RE = re.compile(r"^\s*(?:extern\s+)?([A-Za-z_][A-Za-z_0-9_ ]*[ ]+\**)"
|
||||
r"([a-z_][a-z_0-9]*)\s*\([^;{]*\)\s*;", re.MULTILINE);
|
||||
|
||||
|
||||
def tracked_headers():
|
||||
"""git 跟踪的 BSP 公开头文件(排除第三方 lftpd)。"""
|
||||
out = subprocess.run(["git", "ls-files", "--", "Drivers/BSP"],
|
||||
cwd=str(ROOT), capture_output=True, text=True)
|
||||
if out.returncode != 0:
|
||||
print("git ls-files 失败:", out.stderr.strip())
|
||||
raise SystemExit(2)
|
||||
files = []
|
||||
for rel in out.stdout.split():
|
||||
rel = rel.replace("\\", "/")
|
||||
if not rel.endswith(".h"):
|
||||
continue
|
||||
if any(part in rel for part in EXCLUDE):
|
||||
continue
|
||||
files.append(rel)
|
||||
return sorted(files)
|
||||
|
||||
|
||||
def doc_block_before(lines, idx):
|
||||
"""取声明上方紧邻的注释块文本(向上直到 /* 或空行为止)。"""
|
||||
buf = []
|
||||
j = idx - 1
|
||||
while j >= 0:
|
||||
t = lines[j].strip()
|
||||
if t.endswith("*/") or t.startswith("*") or t.startswith("/*"):
|
||||
buf.append(t)
|
||||
if t.startswith("/*"):
|
||||
break
|
||||
j -= 1
|
||||
continue
|
||||
break
|
||||
return "\n".join(buf)
|
||||
|
||||
|
||||
def scan():
|
||||
hits = []
|
||||
for rel in tracked_headers():
|
||||
try:
|
||||
text = (ROOT / rel).read_text(encoding="utf-8")
|
||||
except (OSError, UnicodeDecodeError) as exc:
|
||||
print("读不了", rel, exc)
|
||||
raise SystemExit(2)
|
||||
lines = text.splitlines()
|
||||
for m in DEFINE_RE.finditer(text):
|
||||
hits.append((rel, "R2", m.group(1)))
|
||||
for m in DECL_RE.finditer(text):
|
||||
ret = m.group(1).replace("const", "").strip()
|
||||
name = m.group(2)
|
||||
flat = ret.replace(" ", "");
|
||||
if name in ("void", "return", "if", "while", "sizeof", "typedef", "static"):
|
||||
continue
|
||||
is_bool = flat.endswith("bool") or flat.endswith("_Bool")
|
||||
if flat.endswith("HAL_StatusTypeDef") or (is_bool and not PREDICATE_RE.search(name)):
|
||||
hits.append((rel, "R1", name))
|
||||
if flat == "void":
|
||||
continue
|
||||
idx = text[:m.start()].count("\n")
|
||||
if "返回值" not in doc_block_before(lines, idx):
|
||||
hits.append((rel, "R3", name))
|
||||
return hits
|
||||
|
||||
|
||||
def main():
|
||||
ap = argparse.ArgumentParser(description="BSP 错误码/超时命名约定(增量拦截)")
|
||||
ap.add_argument("--verbose", action="store_true", help="列出全部命中与归类")
|
||||
ap.add_argument("--prune", action="store_true", help="只报已消失、可从 BASELINE 删除的条目")
|
||||
ap.add_argument("--emit-baseline", action="store_true",
|
||||
help="打印当前全部命中的键(建基线用)")
|
||||
args = ap.parse_args()
|
||||
|
||||
keys = {"%s|%s|%s" % h for h in scan()}
|
||||
|
||||
if args.emit_baseline:
|
||||
for key in sorted(keys):
|
||||
print(key)
|
||||
print("# 共 %d 条" % len(keys))
|
||||
return 0
|
||||
|
||||
gone = sorted(set(BASELINE) - keys)
|
||||
fresh = sorted(keys - set(BASELINE))
|
||||
|
||||
if args.prune:
|
||||
if not gone:
|
||||
print("[prune] 基线 %d 条全部仍在" % len(BASELINE))
|
||||
for key in gone:
|
||||
print("[prune] 这条已消失,请从 BASELINE 删除:", key)
|
||||
return 0
|
||||
|
||||
if args.verbose:
|
||||
for key in sorted(keys):
|
||||
print(" [%s] %s" % ("基线" if key in BASELINE else "新增", key))
|
||||
|
||||
print("BSP 约定:命中 %d(在册 %d / 新增 %d),基线共 %d"
|
||||
% (len(keys), len(keys & set(BASELINE)), len(fresh), len(BASELINE)))
|
||||
if fresh:
|
||||
print("[FAIL] 新增违反 BSP 约定的条目:")
|
||||
for key in fresh:
|
||||
print(" -", key)
|
||||
print(' 出路:① 返回 bsp_err_t(Drivers/BSP/bsp_err.h,0=成功、负值=失败,')
|
||||
print(' 可重试判定用 BSP_ERR_CAN_RETRY);② 时长宏一律 *_MS 且必须是时间,')
|
||||
print(' 自旋圈数改名 *_LOOP 并注释写明非时间量;③ 返回码不许叫 *_TIMEOUT。')
|
||||
return 1
|
||||
if gone:
|
||||
print("[提醒] 有 %d 条基线已还清,请用 --prune 列出并从 BASELINE 删除" % len(gone))
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
@@ -5,3 +5,4 @@ date code ro rw zi er_irom1 er_pct iram1 iram1_pct ccm ccm_pct top_rwzi
|
||||
2026-10-15 213540 18740 1136 131520 232280 22.2 75232 57.4 57376 87.9 heap_4.o=57376;lv_mem_core_builtin.o=16384;lftpd.o=7884;ui_net_sink.o=6766;ui_port.o=6420;nand_ftl.o=6216;ch395f.o=4162;console_log.o=4120;sys_log_mcu.o=3588;default_task.o=2736
|
||||
2026-10-20 213356 18580 1184 131480 231936 22.1 75240 57.4 57376 87.9 heap_4.o=57376;lv_mem_core_builtin.o=16384;lftpd.o=7884;ui_net_sink.o=6766;ui_port.o=6420;nand_ftl.o=6216;ch395f.o=4162;console_log.o=4120;sys_log_mcu.o=3588;default_task.o=2736
|
||||
2026-10-22 213436 18652 1188 131500 232088 22.1 75264 57.4 57376 87.9 heap_4.o=57376;lv_mem_core_builtin.o=16384;lftpd.o=7884;ui_net_sink.o=6766;ui_port.o=6420;nand_ftl.o=6216;ch395f.o=4162;console_log.o=4120;sys_log_mcu.o=3588;default_task.o=2736
|
||||
2026-10-23 213648 18860 1188 131500 232508 22.2 75264 57.4 57376 87.9 heap_4.o=57376;lv_mem_core_builtin.o=16384;lftpd.o=7884;ui_net_sink.o=6766;ui_port.o=6420;nand_ftl.o=6216;ch395f.o=4162;console_log.o=4120;sys_log_mcu.o=3588;default_task.o=2736
|
||||
|
||||
|
Reference in New Issue
Block a user