Files
STM32F4-Base/Drivers/BSP/UI/ui_menu_tab.h
T
wandering1 cc2966319a docs(S-5): 补齐 16 条返回值约定,bsp-err 基线 19 → 1,并修门禁自身误判
A(还债)先行,B(GD5F 的 SPI 失败被吞成成功)另波处理。本笔不改行为:@build 的
Program Size 与上一笔逐字段相同(Code 213,648、RO 18,860、RW 1,188、ZI 131,500)。

**补齐 16 条「返回值:」约定,bsp-err 存量基线 19 → 1**:
· gd5f2gq5ue.h 九个 SPI 原语(wait_busy / write_enable / read_status / page_read /
  read_from_cache / program_load / program_exec / block_erase / check_ecc)
  写全规范五要素,
  并把**每个函数能返回哪些码**写死:哪一个是"可重试"的 GD5F_WAIT_EXPIRED、哪一个才是
  器件自认坏块的 P_FAIL/E_FAIL、失败时出参为什么不可信(E-42 同族)。
· nand_ftl.h 从零散三行补成带模块头,并明写 **nand_ftl_init() 的 −1 抹掉了失败类**:
  分类目前只在失败点进日志,要按类分支需要 C4 快照(现无消费者故未做);同时警告"不得
  把 −1 解读成卷坏了可以重格式化"(E-31 的教训正在这条上)。
· ui_menu_tab.h 五个表查询 API 由行尾短注释升级为完整块(含"越界返回 false 是保守取
  只读"、"宁可按一张错表导航失败也不要按错表导航成功"这类判断依据)。

**修掉门禁自己的一条误判口径**(本笔最该记的):R3 原本要求紧邻注释块里出现字面"返回值",
而规范 V1.0 允许列对齐写法「返 回 值:」。后果有两层:① 合规写法被判违规;② 反向更糟——
gd5f_write_enable / gd5f_read_status 两条**早就"通过"了**,原因竟是它们的**函数说明**里顺口
写了"返回值"三个字,而不是真有一行返回值说明。**一条会因为散文里出现关键词而放行的规则,
等于在奖励运气**。修法是在块内忽略空格后再匹配关键词(排版选择不是违规),并在注释里写明
为什么不许把"必须写成不空格的形式"写进规则。

剩余 1 条刻意保留:bool ui_content_page_open()。它与"补注释"不是一档事——要改签名、要处理
3 个调用点(ui_menu.c:138/192/196 **今天三处全部丢弃返回值**,即"按 ENTER 开页失败是静默的"
这件事现在没人知道)、且 UI 源码双端编译(模拟器同一份),验证面是"重建模拟器 + 像素回归 +
真机逐页进菜单"。这不是还债,是独立一波改动,留档待决策。UI 三个文件带 BOM,Edit 会静默
剥掉 → 已按原样补回 3 字节(AGENTS 铁律:丢 BOM 后 ARMCC 按 CP936 解码,中文报 #870-D)。

**更正我自己写进文档的一条错话**:S-5 各条里我把 GD5F_SPI_TIMEOUT 100 记成"自旋圈数(改
分频时长会变)"。这次逐行核它 12 处用法,**全部是 HAL_* 超时参数或 HAL_GetTick() 差值 →
它也是毫秒**。真问题降级为"单位没写进名字(缺 _MS 后缀),读代码必须回实现里查单位"。
osWaitForever 与 HAL_MAX_DELAY 同为 0xFFFFFFFFU、以及 *_BUSY_TIMEOUT = -2 其实是返回码这两条
仍然成立(后者已改)。现状类条目(报告 §0.4、bsp_err.h、pre-commit使用说明.md §2.27、脚本
文件头)已全部改准;**已提交的变更记录行仍写着旧说法——按 §8.1 冻结历史不回改,以本笔新增
的更正行为准**。

验证:@build 0 错 0 警告(尺寸同上,故**不跑 @test**——无指令变化,跑它没有新信息);受影响
文件的 17 个钩子全 Passed(含 ui-golden 像素回归、cppcheck、编码规范、bsp-err 1/1/0 且
--prune 干净);check_doc_links --all --sections-strict 147 篇 0 问题;id-check
  --strict 通过;
9 个文件字节卫生 0 异常(UI 头 BOM 仍在、无 CR、无 U+FFFD、无行尾空格、均有尾换行)。
口径同步:AGENTS.md、.pre-commit-config.yaml、pre-commit使用说明.md §2.27 的基线计数 19 → 1;
报告 §0.4 / §9 / 附录 A 与变更记录两条(还债一条、更正一条)。
2026-10-23 08:25:58 +08:00

89 lines
4.2 KiB
C
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.
/*
* 模块名称:UI 菜单节点表头文件(自动生成)
* 模块功能:菜单节点结构、表规模护栏与表查询 API 声明
* 适用平台:STM32F407ZGTx / PC 模拟器(共用源码)
* 作者:王建锋
* 创建日期:2026-09-07
* 修改记录:
* 2026-09-13 王建锋 工程约定规范化(文件头),内容由生成器自动更新
* 自动生成:本文件由 tools/menu_gen/gen_menu.py 从 ui_menu_tree.txt 自动生成,请勿手改。
* 修改菜单:编辑 ui_menu_tree.txt 后重跑 `python tools/menu_gen/gen_menu.py`。
*/
#ifndef UI_MENU_TAB_H
#define UI_MENU_TAB_H
#include <stdint.h>
#include <stdbool.h>
#define MENU_ROOT 0xFFu /* 根哨兵:仅根节点(主界面)的 parent 取此值;8 位,上限 255 项 */
/* 菜单节点:子项 = parent 等于本下标的所有行(按表序);有子项=菜单,无=叶子 */
/* 字段序 parent/pwd 在前:32 位下两项 8 位合并 + 4 位指针 = 8 B/项 */
typedef struct {
uint8_t parent; /* 父节点下标(0..254);根为 MENU_ROOT(0xFF) */
uint8_t pwd; /* 1 = 需密码(密码页按所输密码授权);0 = 直接进(只读) */
const char *name; /* 显示文本(字面量,存 Flash) */
} ui_menu_node_t;
#define UI_MENU_TAB_COUNT 42
/* 护栏:8 位索引上限 255 项(哨兵 0xFF 占用 255);超界则编译失败(C99 写法,兼容 ARMCC v5) */
typedef char menu_tab_count_check[(UI_MENU_TAB_COUNT <= 255) ? 1 : -1];
extern const ui_menu_node_t g_menu_tab[];
/*
* 表查询 API(导航逻辑层 ui_menu.c 与显示层 ui_menu_view.c 共用):
* 实现随表生成,改菜单(ui_menu_tree.txt)调用方零代码改动。
*/
/*
* 函数功能:取某节点的直接子项(按表序)
* 入口参数:node - 节点下标 uint8_t 0 - 表长-1
* out - 子项下标输出 uint8_t[] 长度 >= max,可为 NULL(只数个数时)
* max - 最多写出个数 uint8_t >= 1
* 返回值:实际写出的子项个数 uint8_t 0 - max(0 = 叶子节点)
* 限定条件:node 越界时返回 0,不写 out(与"叶子"同形,调用方需要区分就先用 has_children)
* 函数说明:不分配内存、不递归,只查一层。
*/
uint8_t ui_menu_tab_children(uint8_t node, uint8_t out[], uint8_t max);
/*
* 函数功能:判断节点是否为菜单节点(有子项)
* 入口参数:node - 节点下标 uint8_t 0 - 表长-1
* 返回值:true - 有子项(显示为菜单,带 ▶);false - 无子项(叶子,可进内容页)
* 限定条件:纯查询,无副作用;node 越界返回 false
* 函数说明:这是**谓词**(bool 合法),不是成败码——S-5 R1 的白名单形态。
*/
bool ui_menu_tab_has_children(uint8_t node);
/*
* 函数功能:取节点的显示名
* 入口参数:node - 节点下标 uint8_t 0 - 表长-1
* 返回值:显示名字符串指针 const char* 指向表内静态存储,**不为 NULL**(越界返回空串)
* 限定条件:返回的是静态存储地址,调用方不得写、不得 free
* 函数说明:编码随表来源(ui_menu_tree.txt),显示层直接喂 LVGL。
*/
const char *ui_menu_tab_name(uint8_t node);
/*
* 函数功能:判断该叶子是否需要密码
* 入口参数:node - 节点下标 uint8_t 0 - 表长-1
* 返回值:true - 需密码(先进密码页,按所输密码授权);false - 直接进(只读)
* 限定条件:纯查询;node 越界返回 false(保守取"只读",不放开写权限)
* 函数说明:授权强度由密码页所输密码决定,本函数只回答"要不要过这一关"。
*/
bool ui_menu_tab_has_pwd(uint8_t node);
/*
* 函数功能:菜单表启动自检(表与生成器是否自洽)
* 入口参数:无
* 返回值:true - 表自洽(非根节点的 parent 下标均有效、pwd 只取 0/1);
* false - 表被手工改坏,调用方应拒绝进入菜单而不是继续用
* 限定条件:ui_menu_init() 阶段调用一次
* 函数说明:宁可拒绝显示,也不要按一张错表导航——错表可能把只读叶子指到写页面上。
*/
bool ui_menu_tab_valid(void);
#endif