docs: 错误码传播审计收口并删除该文档(E-xx 转历史编号族)
本次会话先后销项与关闭: - E-61 SD2506 清 INTAF:原实现只读取 CTR1,而按手册 ARST=0 时读操作 不清标志,属空操作;改为读-改-写 CTR1,并按手册订正 CTR1 位宏 (INTAF/INTDF/BLF 位置,ARST 归 CTR3) - E-16 cfg_file:新增 CFG_FILE_MAX_NAME_LEN(段名/键名 ≤15),注册时 拒绝超长键名;s_gen_document 两处 snprintf 改检查式;补 TC-CFG-024 用例(主机单测 149→151 PASSED) - E-23 TC704:PHASE7_MULTI_COUNT 8→5(并发上限 = 8 − 3 个常驻监听), accept 失败分支加网络代次检查(网络重建即重建监听) - E-26(UDP)按“保留 API + 文档定案”关闭;E-30 评估为不必要后关闭; N-4(ACCEPT 决定不实施)关闭 审计文档剩余 5 项 P2 + 2 项监督,经用户裁定“都不重要”后整体删除: - 删除 docs/问题记录/错误码传播审计.md(634 行) - 九类缺陷模式表迁入 docs/编号规范.md §4.2.1(PAT-01~09) - E-xx 转为纯历史编号族:编号规范 §4.1 属主改“无(原属主已删除)”, §4.3 保持冻结;全仓 26 处引用按“保留编号、去悬空文档名”处理 - 顺带修正 N-4 收口遗留:排期详述 C1 才是 E-25/E-27/E-28 的承载处 (审计 §4 曾误写为登记簿);README 两处 C1 旧名改回“net 层跨上下文收口” 一并提交此前遗留的体系层评审报告 2026-10-14 复核 WIP(六维评分复核、 未闭环 Top 5→3、三区水位实测刷新)。 校验:Keil 构建 0 错误 0 警告(Code=212344);check_doc_links --sections-strict 与 --all(142 文档)通过;内存双台账刷新后均 PASS。
This commit is contained in:
+19
-5
@@ -12,7 +12,7 @@
|
||||
* 移除对 C 库 malloc 的全部依赖(MicroLIB C 堆仅 512B,
|
||||
* 原 4 处 KB 级 malloc 真机必然失败);增编译期堆峰值预算
|
||||
* 校验 + 失败上报自检记录
|
||||
* v1.2 2026-09-21 王建锋 E-01(错误码传播审计 P0):超长文件守卫根治——poll 判定
|
||||
* v1.2 2026-09-21 王建锋 E-01(历史审计 P0,属主文档已删除):超长文件守卫根治——poll 判定
|
||||
* 前置到 cfg_store_stat 真实 st.size(旧检查位于截断后的
|
||||
* len 上恒假=死码,超长文件被截断当有效解析 → 界外静默
|
||||
* 回工厂默认 → 基线粘住 → 用户配置销毁链);save 输出上限
|
||||
@@ -21,6 +21,10 @@
|
||||
* v1.3 2026-10-04 王建锋 P2-1:受管键行超 CFG_LINE_TEST_MAX 时拒绝保存——
|
||||
* 原实现 Pass1 静默跳过超长行,Pass2 遂在段头补写新 KV 且
|
||||
* 原文超长行原样保留 → 同一键出现两行(旧值残留、静默截断)
|
||||
* v1.4 2026-10-15 王建锋 E-16(历史审计 P2,属主文档已删除):生成文档边界余量收口——
|
||||
* s_gen_document 两处 `off += snprintf(...)` 改检查式(截断即
|
||||
* 返回 -1,不再跳过缓冲末尾);注册拒超长键名(≤ 15 字符),
|
||||
* 使每行 112 字节余量成为可编译期验证的前提
|
||||
* 函数说明:引擎状态非重入——调用方须收敛同一任务(defaultTask:poll/save,见 P1-3;
|
||||
* 启动期 load 先于任务竞争);FS 卷并发由 FatFS REENTRANT 卷锁保证
|
||||
* (见《配置文件设计说明》D15 A+ 方案)
|
||||
@@ -63,7 +67,7 @@ static const char s_doc_header[] =
|
||||
#define CFG_OUT_MAX 5120u /* 保存输出缓冲上限(经 cfg_store_alloc 取,见下方堆峰值预算) */
|
||||
#define CFG_LINE_TEST_MAX 127u /* 受管键行匹配的行长上限(超长必非受管键行) */
|
||||
#define CFG_SNAP_MAX 64u /* 变更检测段快照缓冲(挂回调段 data_size 须 ≤ 此值) */
|
||||
#define CFG_NAME_MAX 16u /* 段名缓冲(15 字符 + NUL) */
|
||||
#define CFG_NAME_MAX (CFG_FILE_MAX_NAME_LEN + 1u) /* 段名/键名缓冲(15 字符 + NUL) */
|
||||
#define CFG_HEAP_BUDGET 10240u /* 暂态堆峰值预算:读缓冲(1B NUL) + 输出缓冲之和上限 */
|
||||
|
||||
/* 编译期钉死暂态堆峰值:放大 CFG_FILE_MAX_LEN / CFG_OUT_MAX 会先在此编译失败,强制
|
||||
@@ -457,6 +461,7 @@ static int s_decode(const cfg_key_def_t *p_key, uint8_t *p_dst, const char *p_va
|
||||
*/
|
||||
static int s_gen_document(char *p_buf, size_t cap, size_t *p_len) {
|
||||
size_t off;
|
||||
int n;
|
||||
int i;
|
||||
int k;
|
||||
size_t hlen;
|
||||
@@ -480,7 +485,11 @@ static int s_gen_document(char *p_buf, size_t cap, size_t *p_len) {
|
||||
if (cap < off + 112u) {
|
||||
return -1;
|
||||
}
|
||||
off += (size_t)snprintf(p_buf + off, cap - off, "\r\n[%s]\r\n", p_sec->name);
|
||||
n = snprintf(p_buf + off, cap - off, "\r\n[%s]\r\n", p_sec->name);
|
||||
if (n < 0 || (size_t)n >= cap - off) {
|
||||
return -1;
|
||||
}
|
||||
off += (size_t)n;
|
||||
|
||||
for (k = 0; k < (int)p_sec->key_count; k++) {
|
||||
const cfg_key_def_t *p_key = &p_sec->p_keys[k];
|
||||
@@ -492,7 +501,11 @@ static int s_gen_document(char *p_buf, size_t cap, size_t *p_len) {
|
||||
if (cap < off + 112u) {
|
||||
return -1;
|
||||
}
|
||||
off += (size_t)snprintf(p_buf + off, cap - off, "%s=%s\r\n", p_key->name, v);
|
||||
n = snprintf(p_buf + off, cap - off, "%s=%s\r\n", p_key->name, v);
|
||||
if (n < 0 || (size_t)n >= cap - off) {
|
||||
return -1;
|
||||
}
|
||||
off += (size_t)n;
|
||||
}
|
||||
}
|
||||
*p_len = off;
|
||||
@@ -1004,7 +1017,8 @@ int cfg_file_register(const cfg_section_reg_t *p_reg) {
|
||||
for (k = 0; k < (int)p_reg->key_count; k++) {
|
||||
const cfg_key_def_t *p_key = &p_reg->p_keys[k];
|
||||
|
||||
if (p_key->name == NULL || p_key->len == 0u) {
|
||||
if (p_key->name == NULL || p_key->len == 0u ||
|
||||
strlen(p_key->name) >= CFG_NAME_MAX) {
|
||||
return -1;
|
||||
}
|
||||
if (p_key->type == CFG_VAL_UINT &&
|
||||
|
||||
+9
-3
@@ -9,10 +9,12 @@
|
||||
* 修改记录:
|
||||
* v1.0 2026-09-14 王建锋 创建初始版本(P3:段键表引擎 + net_cfg 集成)
|
||||
* v1.1 2026-09-15 王建锋 属主任务由 netTask 改为 defaultTask(配置引擎单一属主,P1-3)
|
||||
* v1.2 2026-09-21 王建锋 E-01(错误码传播审计 P0):超长守卫契约同步——poll 沉降
|
||||
* v1.2 2026-09-21 王建锋 E-01(历史审计 P0,属主文档已删除):超长守卫契约同步——poll 沉降
|
||||
* 后先按真实 st.size 判超长(旧实现查截断后读长恒假)、
|
||||
* save 输出上限收紧至 CFG_FILE_MAX_LEN、写盘唯一闸口拒写
|
||||
* 超长;超长处置补自检留痕
|
||||
* v1.3 2026-10-15 王建锋 E-16(历史审计 P2,属主文档已删除):新增公开常量
|
||||
* CFG_FILE_MAX_NAME_LEN(段名/键名上限 15 字符)
|
||||
*/
|
||||
|
||||
#ifndef CFG_FILE_H
|
||||
@@ -33,6 +35,10 @@ extern "C" {
|
||||
/* 引擎可注册段数上限 */
|
||||
#define CFG_FILE_MAX_SECTIONS 8u
|
||||
|
||||
/* 段名 / 键名最大字符数(不含结尾 NUL);超长的注册描述符被 cfg_file_register 拒绝。
|
||||
* 该上限是生成文档每行余量(112 字节)可编译期验证的前提,勿放宽 */
|
||||
#define CFG_FILE_MAX_NAME_LEN 15u
|
||||
|
||||
/* 单段键数上限 */
|
||||
#define CFG_FILE_MAX_KEYS 16u
|
||||
|
||||
@@ -55,7 +61,7 @@ typedef enum {
|
||||
|
||||
/* 键定义(offset/len 均相对段 RAM 副本起始) */
|
||||
typedef struct {
|
||||
const char *name; /* 键名(小写) */
|
||||
const char *name; /* 键名(小写,≤ CFG_FILE_MAX_NAME_LEN 字符) */
|
||||
cfg_val_type_t type; /* 值类型 */
|
||||
size_t offset; /* 字段偏移 */
|
||||
size_t len; /* 字段长度 */
|
||||
@@ -63,7 +69,7 @@ typedef struct {
|
||||
|
||||
/* 段注册描述符 */
|
||||
typedef struct {
|
||||
const char *name; /* 段名(≤ 15 字符) */
|
||||
const char *name; /* 段名(≤ CFG_FILE_MAX_NAME_LEN 字符) */
|
||||
void *p_data; /* 段 RAM 副本(模块自有静态区,引擎原地更新) */
|
||||
const void *p_defaults; /* 工厂默认值(与 p_data 同布局;load 先复位再解析) */
|
||||
size_t data_size; /* RAM 副本字节数 */
|
||||
|
||||
@@ -36,7 +36,7 @@
|
||||
* E-02 头阻塞修复 + L3 pending 化(timeSync 侧;lftpd 侧见 lftpd_inet.c):
|
||||
* 旧实现用单次 30s 阻塞 net_recv(默认 NET_RECV_TIMEOUT_MS)等时间包——等待期间
|
||||
* netTask(全部 socket 操作的唯一执行者)被独占,其余任务的网络操作(远端显示 /
|
||||
* FTP)整体停摆(docs/问题记录/错误码传播审计.md E-02)。
|
||||
* FTP)整体停摆(历史审计 E-02,属主文档已删除)。
|
||||
* 2026-09-22 先落地分片有界读(5ms 片),同日 L3 pending 化后改为"挂起请求":
|
||||
* 每次等待 = 一次挂起登记(netTask 零占用,完成按主循环节拍检查),调用方
|
||||
* 单次超时 = 剩余总预算(总等待 ≤ TIME_SYNC_TOTAL_BUDGET_MS,语义与旧 30s
|
||||
|
||||
+1
-1
@@ -13,7 +13,7 @@
|
||||
> 两模块**零调用者**且未编入任何构建——CRC 从未被链接使用:名义上的关联点 `net_cfg_legacy.c`
|
||||
> (旧档 `/cfg/netcfg.bin` 迁移,**该文件亦已于 2026-10-10 删除**)自带静态 `s_crc16_modbus()`,
|
||||
> 从不调用本模块;环形缓冲由 `App/log/console_log.c` 内联实现(`s_con_ring`)。
|
||||
> 保留只会造成"有统一实现"的误导,故整体移除(详见 `docs/任务规划/排期详述.md` E-15(C5))。
|
||||
> 保留只会造成"有统一实现"的误导,故整体移除。
|
||||
|
||||
## 设计要点
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
- **recv 挂起(pending)已落地**:`net_recv` 阻塞不占 netTask——登记挂起请求 + 每轮 tick 唤醒
|
||||
- **send 挂起已落地**:`net_send` 快路径有界自旋(`NET_SEND_SPIN_MS` = 2ms),超预算登记
|
||||
挂起 send,由 `net_send_pending_tick` 按主循环节拍分块推进;netTask 最坏停滞由 1s 压到 2ms
|
||||
- **ACCEPT 尚未挂起化**(调用方轮询问题,不是队头阻塞)→ `docs/任务规划/登记簿.md` N-4
|
||||
- **ACCEPT 决定不挂起化(2026-10-15)**(调用方轮询问题,不是队头阻塞;pending 化收益仅 RPC 开销与抖动)
|
||||
- 架构细节:`docs/网络/Net层阻塞模型架构设计.md`
|
||||
|
||||
### 周期对账自愈(TRAP-NET-17 修复;对账与监听重建合一)
|
||||
|
||||
@@ -496,22 +496,32 @@ int sd2506_set_alarm(const sd2506_time_t *p_time, uint8_t mask) {
|
||||
* 函数功能:清除闹钟中断标志
|
||||
* 入口参数:无
|
||||
* 返回值:0-成功,-2=I2C 错误 int
|
||||
* 限定条件:sd2506_init() 已调用成功;ARST=1 时自动清除 INTAF
|
||||
* 函数说明:读取 CTR1 即可清除 INTAF 标志
|
||||
* 限定条件:sd2506_init() 已调用成功
|
||||
* 函数说明:ARST 位于 CTR3(11H) bit7,本驱动从未写 CTR3 → ARST=0,
|
||||
* 故读 CTR1 不会自动清 INTAF(手册 L519/L523),须手动写 CTR1 将 INTAF 置 0;
|
||||
* 写 0FH 须在写允许窗口内且保持 WRTC2/WRTC3=1(手册 L521),
|
||||
* 故写入值取写允许态 0xFF 清 INTAF 位后的 0xDF。
|
||||
* return: 0=OK, -2=I2C error
|
||||
* note: reading CTR1 clears INTAF
|
||||
*/
|
||||
int sd2506_clear_alarm(void) {
|
||||
int ret = 0;
|
||||
uint8_t val = 0;
|
||||
int ret_off = 0;
|
||||
|
||||
/* 读取 CTR1, ARST=1 时自动清除 INTAF */
|
||||
ret = sd2506_read_reg(SD2506_REG_CTR1, &val);
|
||||
/* 写 0FH 须在写允许窗口内(手册 L519),且 WRTC2/WRTC3 必须保持 1(L521) */
|
||||
ret = sd2506_write_enable();
|
||||
if (ret != SD2506_OK) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
return SD2506_OK;
|
||||
ret = sd2506_write_reg(SD2506_REG_CTR1,
|
||||
(uint8_t)(SD2506_CTR1_WRITE_ON & (uint8_t)~SD2506_CTR1_INTAF));
|
||||
|
||||
ret_off = sd2506_write_disable();
|
||||
if (ret == SD2506_OK) {
|
||||
ret = ret_off;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -85,11 +85,14 @@ extern "C" {
|
||||
|
||||
/* ======================== 控制位定义 ======================== */
|
||||
|
||||
/* 控制寄存器 1 (0FH) */
|
||||
#define SD2506_CTR1_ARST (1U << 5) /* 自动复位使能 */
|
||||
#define SD2506_CTR1_INTAF (1U << 3) /* 报警中断标志 */
|
||||
#define SD2506_CTR1_INTDF (1U << 2) /* 倒计时中断标志 */
|
||||
#define SD2506_CTR1_BLF (1U << 0) /* 电池欠压标志 */
|
||||
/* 控制寄存器 1 (0FH):bit7=WRTC3 bit6=OSF bit5=INTAF bit4=INTDF bit3=BLF
|
||||
* bit2=WRTC2 bit1=PMF bit0=RTCF(手册寄存器总表) */
|
||||
#define SD2506_CTR1_INTAF (1U << 5) /* 报警中断标志 */
|
||||
#define SD2506_CTR1_INTDF (1U << 4) /* 倒计时中断标志 */
|
||||
#define SD2506_CTR1_BLF (1U << 3) /* 电池欠压标志 */
|
||||
|
||||
/* 控制寄存器 3 (11H) */
|
||||
#define SD2506_CTR3_ARST (1U << 7) /* 自动复位使能(ARST=1 时读 CTR1 自动清 INTAF/INTDF/BLF) */
|
||||
|
||||
/* 控制寄存器 2 (10H) */
|
||||
#define SD2506_CTR2_INTAE (1U << 5) /* 报警中断允许 */
|
||||
@@ -267,11 +270,12 @@ int sd2506_write_sram(uint8_t addr, const uint8_t *p_buf, uint8_t len);
|
||||
int sd2506_set_alarm(const sd2506_time_t *p_time, uint8_t mask);
|
||||
|
||||
/*
|
||||
* 函数功能:清除报警中断标志
|
||||
* 函数功能:清除报警中断标志 INTAF
|
||||
* 入口参数:无
|
||||
* 返回值:0 - 成功,-2 - I2C 通信错误
|
||||
* 限定条件:sd2506_init() 已调用
|
||||
* 函数说明:读取 CTR1 自动清除 INTAF (ARST=1 时)
|
||||
* 函数说明:ARST(CTR3 bit7) 未启用,读 CTR1 不清 INTAF;本函数经写允许窗口
|
||||
* 手动写 CTR1 将 INTAF 置 0
|
||||
*/
|
||||
int sd2506_clear_alarm(void);
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
* 2026-07-17 王建锋 创建初始版本,参考 AD7606 并行驱动及 TPAFE5160 手册
|
||||
* 2026-07-17 王建锋 增加 EXTI 中断读取模式
|
||||
* 2026-09-20 王建锋 V0.1 引脚适配(引脚值随 main.h 宏,驱动逻辑不变)
|
||||
* 2026-10-10 王建锋 消费者接入前置修复(错误码传播审计 E-44 / E-45 / E-58):
|
||||
* 2026-10-10 王建锋 消费者接入前置修复(历史审计 E-44 / E-45 / E-58,属主文档已删除):
|
||||
* FRSTDATA 数据有效性校验 + 帧序号取代就绪电平标志 +
|
||||
* 原子快照 API;移除会撕裂的 get_buf/data_ready/clear_ready
|
||||
*/
|
||||
|
||||
+2
-3
@@ -189,7 +189,6 @@ docs/
|
||||
| [`CH395F_Trap_Records.md`](问题记录/CH395F_Trap_Records.md) | CH395F 以太网控制器陷阱台账 |
|
||||
| [`GD5F2GQ5UE_Trap_Records.md`](问题记录/GD5F2GQ5UE_Trap_Records.md) | GD5F2GQ5UE SPI NAND 陷阱台账 |
|
||||
| [`SD2506_Trap_Records.md`](问题记录/SD2506_Trap_Records.md) | SD2506 RTC 陷阱台账 |
|
||||
| [`错误码传播审计.md`](问题记录/错误码传播审计.md) | 错误码传播缺陷审计(9 类模式 × 子系统) |
|
||||
|
||||
---
|
||||
|
||||
@@ -258,13 +257,13 @@ docs/
|
||||
|
||||
| 问题 | 位置 | 说明 |
|
||||
|---|---|---|
|
||||
| 指向未实现工具 | `UI_界面制作流程.md`、`UI_自动化测试流程.md` → `tools/ui_mock/` | 该目录**始终不存在**;golden 回归实际落在 `simulator/tests/`(四脚本)。引用待改指,见 `docs/问题记录/项目审查与优化建议报告.md` §6.1 |
|
||||
| ~~指向未实现工具~~ | ~~`UI_界面制作流程.md`、`UI_自动化测试流程.md` → `tools/ui_mock/`~~ | ✅ 已改指(2026-10-14 核实):两份 UI 文档正文已无该路径(仅存变更记录里的历史提及);golden 回归落在 `simulator/tests/`(四脚本) |
|
||||
| ~~产物缺失~~ | ~~`内存管理/RAM使用分析与优化方案.md` → `scripts/ram_baseline.tsv`~~ | ✅ 已建(2026-10-12,N-27 前半):`ram_baseline.py` + `ram_baseline.tsv` + [`RAM预算台账.md`](内存管理/RAM预算台账.md) + `mem-budget` 钩子 |
|
||||
| ~~目录名含空格~~ | ~~`UI 设计/`~~ | ✅ 已修复(2026-09-25,D-6):改名为 `UI设计/`,全仓库 67 处引用同步;命名约定见 [`文档规范.md`](文档规范.md) §1 |
|
||||
| ~~缺一致性门禁~~ | — | ✅ 已落地(2026-09-25/26,D-7 三档齐):`scripts/check_doc_links.py`(存在性)+ `scripts/gen_task_table.py`(数值)+ `scripts/check_mem_numbers.py`(体积),接入 pre-commit `doc-links` / `task-table` / `mem-numbers` 钩子 |
|
||||
| ~~`docs/文档规范.md` 未创建~~ | — | ✅ 已创建(2026-09-25):[`文档规范.md`](文档规范.md) |
|
||||
|
||||
> 未闭环的文档类问题见 [`问题记录/项目审查与优化建议报告.md`](问题记录/项目审查与优化建议报告.md) §3.1(体量与 D-1)与 §3.4(复核后仅剩三条:D-1、语义断链、元信息漂移)。
|
||||
> 未闭环的文档类问题见 [`问题记录/项目审查与优化建议报告.md`](问题记录/项目审查与优化建议报告.md) §3.1(体量)与 §3.3/§3.4(**仅剩 D-1 仓库膨胀**,登记簿 N-29 已决策暂不处理)。
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -252,7 +252,7 @@ if (n > 0) {
|
||||
> "把推流搬出 uiTask(独立任务 + 帧 seqlock)"已完整评估并**决定不做**:实测刷新最坏周期
|
||||
> (`uip` ≈61 ms)是 **LVGL 帧周期地板**、与网络无关,搬任务不会让刷新变快;成本却含
|
||||
> **必改 `.ioc`** 的重生成与全套回归,收益只剩极端并发下的观感隔离。若日后它成为实际问题,
|
||||
> 正确方向是先治 netTask 排队公平性(登记簿 N-4 二期),不是把 UI 搬走。
|
||||
> 正确方向是先治 netTask 排队公平性(见 `../网络/Net层阻塞模型架构设计.md`),不是把 UI 搬走。
|
||||
> 观测手段:`[PROF]` 的 `uis`(往返最坏)与 `uisn`(此刻仍在推流段内多久)——
|
||||
> **`uisn` 持续非 0 就是这一格真发生的铁证**;字段语义与判读见
|
||||
> [`../子系统设计/看门狗设计说明.md`](../子系统设计/看门狗设计说明.md) §11.4。
|
||||
|
||||
@@ -865,7 +865,6 @@ cfg-file-unit-test、test-suite-switch、gitlint。
|
||||
| 硬件网表 | [`docs/硬件平台/V0.1_网表详细分析报告.md`](../../docs/硬件平台/V0.1_网表详细分析报告.md) |
|
||||
| 待办登记簿 | [`docs/任务规划/README.md`](../任务规划/README.md) |
|
||||
| 体系层评审报告 | [`docs/问题记录/项目审查与优化建议报告.md`](../../docs/问题记录/项目审查与优化建议报告.md) |
|
||||
| 错误码审计 | [`docs/问题记录/错误码传播审计.md`](../../docs/问题记录/错误码传播审计.md) |
|
||||
| 实机测试指南 | [`docs/测试说明/实机测试实施指南.md`](../../docs/测试说明/实机测试实施指南.md) |
|
||||
| 测试标准流程 | [`docs/测试说明/测试开发标准流程.md`](../../docs/测试说明/测试开发标准流程.md) |
|
||||
| RAM 预算与优化 | [`docs/内存管理/RAM使用分析与优化方案.md`](../../docs/内存管理/RAM使用分析与优化方案.md) |
|
||||
|
||||
@@ -382,7 +382,7 @@ cppcheck 是开源 C/C++ 静态分析工具,**不运行代码**,通过语法
|
||||
| **检查逻辑** | 解析 `.map` 执行区占比 → 超阈值即 FAIL 并附 **Top-10 RW+ZI 对象表**(定位增量元凶);同时校验 `docs/内存管理/RAM预算台账.md` 受管区与 `.map` 一致(漂移 → 提示 `--write`) |
|
||||
| **软提醒**(不拦) | tsv 末行落后于 `.map`(忘跑 `--update`);`.map` 早于最新源码(忘 `@build`) |
|
||||
| **配套三件套** | `scripts/ram_baseline.py`(门禁/趋势/受管区生成)+ `scripts/ram_baseline.tsv`(每次 `@build` 后 `--update` 追加的趋势基线,`--trend` 高亮 RW+ZI 增长 >1 KB 的对象)+ `docs/内存管理/RAM预算台账.md`(子系统配额 + CCM 台账 + 超配额流程) |
|
||||
| **为什么需要** | `docs/问题记录/项目审查与优化建议报告.md` §5.5 第 1 条"超阈值即失败 + Top-10 附表"此前**无任何机械检查**——`mem-numbers` 只防"文档数字漂移"不防"占用超阈值";B4/B5 要新建任务与缓冲,红线必须先机械化(登记簿 N-27 前半 / W1-0) |
|
||||
| **为什么需要** | 2026-09 体系评审提出的"超阈值即失败 + Top-10 附表"(现沉淀在 `docs/问题记录/项目审查与优化建议报告.md` §5.5 闭环说明)此前**无任何机械检查**——`mem-numbers` 只防"文档数字漂移"不防"占用超阈值";B4/B5 要新建任务与缓冲,红线必须先机械化(登记簿 N-27 前半 / W1-0) |
|
||||
| **运行器** | `scripts/ram_baseline.py --gate`(纯标准库,复用 `ram_report.py` 的 `.map` 解析口径;退出码 0=通过/跳过 / 1=超阈值或漂移 / 2=解析失败) |
|
||||
|
||||
### 2.20 iec104-unit-test — IEC 60870-5-104 协议栈主机侧单测(2026-10-12 加,B4)
|
||||
|
||||
+19
-17
@@ -22,8 +22,8 @@
|
||||
> 已闭环项的**结论与证据沉淀进对应模块文档/问题记录**,本文件夹不再重复。
|
||||
> **消化即销项**:事项修复/关闭后,直接删除对应条目,并同步清理其它文档对本编号的引用。
|
||||
>
|
||||
> **不在本文件夹范围**:`../问题记录/错误码传播审计.md`(E-xx,审计报告,非待办池)、
|
||||
> `../问题记录/项目审查与优化建议报告.md`(体系层评审报告)、`../测试说明/实机测试实施指南.md`(执行流程)。
|
||||
> **不在本文件夹范围**:`../问题记录/项目审查与优化建议报告.md`(体系层评审报告)、
|
||||
> `../测试说明/实机测试实施指南.md`(执行流程)。
|
||||
>
|
||||
> **修订**:2026-10-04 四档合并;2026-10-11 统一排序 + 审查报告并轨;
|
||||
> **2026-10-12 按用户决定 RS-485(B2)整簇暂缓,波次重排为 W1~W7,清除已销项残留**;
|
||||
@@ -43,7 +43,7 @@
|
||||
| `P0-x`~`P3-x` | 审计缺陷/改进项(2026-09-15/09-21 审计) | P0=功能 bug、P1=疑似 bug/健壮性、P2=改进、P3=卫生 |
|
||||
| `N-x` / `S-x` / `T-x` | 台架/审计观察登记项 / 存储·日志管线 / 测试与工具链 | **存量冻结沿用、不再新增**(新条目见上一行);`N-x` 含硬件改版项(需下一版硬件,固件侧只记口径,如 N-18) |
|
||||
| `S1~S14` / `A-1~A-7` | 2026-10-02 复审的测试充分性与架构专项 | 编号**不回收** |
|
||||
| `E-xx` | 错误码传播审计发现 | 独立维护于 `错误码传播审计.md`,**不并入本文件夹**,只交叉引用 |
|
||||
| `E-xx` | 错误码传播审计发现(**历史族**) | 属主文档已于 2026-10-15 删除;编号冻结(`docs/编号规范.md` §4.1 / §4.3),存量引用仅作历史指称,新发现一律 `DEF` |
|
||||
| `B`/`C`/`D` 前缀 | §2 排序条目编号:B=功能主线、C=结构债、D=验证窗口 | 编号不回收,见 §2 |
|
||||
| 报告 `N-x`/`R-x`/`F-x`/`S-x`/`U-x`/`D-x` | `项目审查与优化建议报告.md` **自有编号** | ⚠ **与本登记簿同名不同义**(报告 N-16 = 日志逐条开关,登记簿 N-16 = A2/A4 负向台架)→ **引用一律带文档名**。其未闭环项 2026-10-11 并入本登记簿(新编 `N-19`~`N-29` + U 簇,出处列保留报告编号) |
|
||||
|
||||
@@ -64,19 +64,21 @@
|
||||
| 类别 | 数量 | 条目 |
|
||||
|---|---|---|
|
||||
| P1 收尾 | 1 | P1-10 测试固件构建实测(`测试与架构专项.md` §1) |
|
||||
| 网络 | 5 | N-2(49s 日志静默,**低风险观察项**)· N-3(L5 基线重验)· N-4(ACCEPT pending 化)· N-16(A2/A4 负向台架)· N-17(探针窗口心跳缺口) |
|
||||
| 网络 | 4 | N-2(49s 日志静默,**低风险观察项**)· N-3(L5 基线重验)· N-16(A2/A4 负向台架)· N-17(探针窗口心跳缺口) |
|
||||
| 存储 / 日志 | 3 | **S-3(USART1 TX-only 根治)** · S-4(dhara 重试自旋)· S-5(可选全序列卷锁) |
|
||||
| 数据正确性 | 1 | **N-21(dhara `is_free`/`copy`,全簿最高风险)** |
|
||||
| 结构 / 健壮性 | 9 | N-20(Error_Handler 死循环)· N-22(写回 flush)· N-23(注册校验残余白名单)· N-24(日志逐条开关)· N-25(性能/语义簇)· N-26(NAND DMA 断言)· N-27(内存优化簇,三件套 ✅ 前半落地)· N-28(Flash 死代码簇)· **N-33(栈余量收口,W1)** |
|
||||
| 仓库 | 1 | N-29(`.git` 149 MB,**已决策暂不处理、登记观察**) |
|
||||
| 结构 / 健壮性 | 7 | N-22(写回 flush)· N-23(注册校验残余白名单)· N-24(日志逐条开关)· N-25(性能/语义簇)· N-27(内存优化簇,三件套 ✅ 前半落地)· N-28(Flash 死代码簇)· **N-33(栈余量收口,W1)** |
|
||||
| 仓库 | 1 | N-29(`.git` **235 MB**,**已决策暂不处理、登记观察**) |
|
||||
| 硬件 | 1 | N-18(V0.2 改版项) |
|
||||
| 测试 / 基础设施 | 6 | T-7(CI runner + 推送闭环 + 第二机交叉验证)· S12(断言宏)· S1-c(可选单测)· A-4(采集链路测试约束,RS485 侧随 B2 暂缓)· A-5 残余(CI 体积门禁盲区)· D7(串口助手 A6/A7 待 CH340) |
|
||||
| UI | 1 簇 | U 簇(27 页标准化,**本轮不排期**) |
|
||||
| **暂缓** | 1 簇 | **B2 RS-485 整簇(2026-10-12 用户决定,`暂缓-RS485.md`)** |
|
||||
|
||||
> **网络侧另有 E-xx 未闭环项**(E-12/15/16/23/24/25/26/27/28/30/47/48/49/50/58/59/61,共 17 项)
|
||||
> 与 1 项回归监督(E-62),详见 `../问题记录/错误码传播审计.md` §3——其中 **E-49/E-50 随 RS-485 暂缓**。
|
||||
> 本文件夹不重复登记。UI 标准化簇与覆盖率缺口(lftpd/dhara 移植层无主机测试)为整簇排期项,见 §2 W6 / N-21。
|
||||
> **网络侧 E-xx 存量项**(历史编号族,属主文档已于 2026-10-15 删除,编号冻结见
|
||||
> `docs/编号规范.md` §4.3):E-25 / E-27 / E-28 挂 C1(net 层跨上下文收口,见 `排期详述.md` §1);
|
||||
> E-47 待 CH395F 驱动侧定案;E-12 为 `FF_FS_LOCK` / 单写者纪律记录项;E-31 后续与 E-62
|
||||
> 为回归监督项(纪律已固化于 `AGENTS.md`,无需改动)。
|
||||
> UI 标准化簇与覆盖率缺口(lftpd/dhara 移植层无主机测试)为整簇排期项,见 §2 W6 / N-21。
|
||||
|
||||
### 1.1 结构性判断(排序依据)
|
||||
|
||||
@@ -100,11 +102,11 @@
|
||||
|---|---|---|
|
||||
| **W1 采集+保护收尾** | **里程碑制 + 并行道**:M1 台架闭环 ✅ 达成(B6 ✅→N-33 ✅)∥ M2 功能面(代码道 B7 ✅→{B8∥B9})→ M3 送检(B10,Fixed Date)——任务卡/判据/写范围见 `W1-采集保护收尾.md` | **用户决定(2026-10-12):先把 ADC 采集、保护等相关功能完成**。B4/B5 代码已落地但未台架闭环、功能面不完整(定值不落盘 / 无频率保护 / 无动作记录 / 栈两处 FAIL)——本波收口到"可用 + 可验收";真约束只有**台架**与**送检窗口**两个稀缺资源,其余任务按写范围切分并行 |
|
||||
| **W2 数据正确性** | **N-21** dhara `is_free`/`copy`(报告 N-12/13) | 低概率、后果重(数据丢失);修复须配主机侧移植层测试,一并补报告"覆盖率"缺口 |
|
||||
| **W3 预算与内存** | **N-27 后半**:R-9 池 40→16 KB → R-2 后半(54 KB→CCM)→ R-3~R-6 逐项评估 | 依赖 W1 三件套产出的台账数据;**B5 堆扩容后 CCM 只剩 ≈8 KB**(56 KB 堆),R-2 后半更被堵死(解锁链见 `docs/内存管理/RAM预算台账.md` §3) |
|
||||
| **W4 结构债** | **N-20 → C6(S-3)→ C3(N-2+N-24)→ C1 ACCEPT pending 化 → C5(含 N-23 残余)→ N-22/N-25/N-26/N-28**(详表 `排期详述.md` §1) | 无紧急,按性价比排:C6 灭 IWDG 误复位机制根源;C1 体量大、验证重,放后(N-23 钩子已落地 2026-10-12,残余并入 C5) |
|
||||
| **W3 预算与内存** | **N-27 后半**:R-9 池 40→16 KB → R-2 后半(54 KB→CCM)→ R-3/R-4/R-6 逐项评估(**R-5 已判定不可行**,见 `登记簿.md`) | 依赖 W1 三件套产出的台账数据;**B5 堆扩容后 CCM 只剩 7,904 B**(56 KB 堆),R-2 后半更被堵死(解锁链见 `docs/内存管理/RAM预算台账.md` §3) |
|
||||
| **W4 结构债** | **C6(S-3)→ C3(N-2+N-24)→ C1 net 层跨上下文收口 → C5(含 N-23 残余)→ N-22/N-25/N-28**(详表 `排期详述.md` §1) | 无紧急,按性价比排:C6 灭 IWDG 误复位机制根源;C1 消化 E-25/E-27/E-28(原 ACCEPT+SEND pending 化已收口),体量大、验证重,放后(N-23 钩子已落地 2026-10-12,残余并入 C5) |
|
||||
| **W5 验证常态** | P1-10 收尾 · T-7 CI · D2 N-3 · D5 N-16 · D6 N-17 · D7 串口助手 · S12 · S1-c · A-5(详表 `排期详述.md` §2) | 窗口性,逢机顺带,不单独排期 |
|
||||
| **W6 UI 扩展** | U4 残余(golden + 字符集差集挂门禁)→ U1 令牌层 → U2/U3 → **27 页**落地 | 产品驱动、体量大,需单独立项(顺序按 `docs/问题记录/项目审查与优化建议报告.md` §6.5);**本轮不排期(2026-10-11 已确认)** |
|
||||
| **W7 仓库决策** | **N-29** `.git` 149 MB + 图片 36.3 MB | **已决策(2026-10-11):暂不处理、登记观察**——推送/协作前重评(`git filter-repo` 历史重写影响未推送提交与协作者) |
|
||||
| **W7 仓库决策** | **N-29** `.git` **235 MB** + 图片 36.3 MB | **已决策(2026-10-11):暂不处理、登记观察**——推送/协作前重评(`git filter-repo` 历史重写影响未推送提交与协作者) |
|
||||
| **暂缓** | **B2 RS-485 整簇**(`暂缓-RS485.md`) | **用户决定(2026-10-12):当前不处理 RS-485** |
|
||||
| **硬件改版** | N-18 8 路电气量全接 TPAFE(V0.2) | 下一版硬件;固件侧已用语义映射隔离,改版只动映射表 |
|
||||
|
||||
@@ -116,9 +118,9 @@ W1 收尾 台架道: B6✅→N-33✅(M1 ✅ 2026-10-12) ∥ 代码道: B7✅
|
||||
↓
|
||||
W2 数据 N-21 dhara is_free/copy(配主机侧移植层测试)
|
||||
↓
|
||||
W3 预算 R-9 池瘦身 → R-2 后半(54KB→CCM)→ R-3~R-6 评估
|
||||
W3 预算 R-9 池瘦身 → R-2 后半(54KB→CCM)→ R-3/R-4/R-6 评估
|
||||
↓
|
||||
W4 结构 N-20 → C6(S-3) → C3(N-2/N-24) → C1 ACCEPT pending 化 → C5(含 N-23 残余) → N-22/25/26/28
|
||||
W4 结构 C6(S-3) → C3(N-2/N-24) → C1 net 层跨上下文收口 → C5(含 N-23 残余) → N-22/25/28
|
||||
↓
|
||||
W5 验证 P1-10 · T-7 CI · D2/D5/D6/D7 · S12 · S1-c · A-5
|
||||
↓
|
||||
@@ -139,11 +141,11 @@ W7 仓库 N-29 .git 149MB(已决策暂不处理) 硬件:N-18 V0.2
|
||||
**不再新增字母+数字编号**(规则见 `docs/任务规划/README.md` §0 表首行);存量编号
|
||||
(P-x / N-x / S-x / T-x / S1x / A-x / B·C·D 前缀)**冻结沿用**,而**已随销项消失的号永久作废**、
|
||||
不得作为新条目候选——"不回收"在只写规则、不留痕迹的情况下不可执行(撞号实测见
|
||||
`docs/任务规划/README.md` §0 注);`错误码传播审计.md` 的 E-xx 独立维护。
|
||||
`docs/任务规划/README.md` §0 注);E-xx(历史编号族)冻结于 `docs/编号规范.md` §4.3。
|
||||
- **引用审查报告编号一律带文档名**(报告 N-16 ≠ 登记簿 N-16、报告 S-3 ≠ 登记簿 S-3);
|
||||
报告并轨项用本登记簿新编号(N-19~N-29 + U 簇),出处列保留报告编号。
|
||||
- **§2 是全项目唯一的推进顺序权威**:`产品需求设计文档.md` 等文档中的路线图只留指针,顺序变更只改 §2.0(详表文件跟着挪,不改顺序)。
|
||||
- **暂缓块(`暂缓-RS485.md`)不是销项**:条目仍在簿,只是不占波次;重启或关闭时更新该文件与 §1/§2.0。
|
||||
- 新增发现按既有惯例分流:能立即修的进 §2 波次(W4 C5);需排期的进 `登记簿.md` / `测试与架构专项.md` 对应编号空间;跨版本观察的进 `登记簿.md`。
|
||||
- 上游引用关系:`问题记录/项目审查与优化建议报告.md`(体系层评审)、`问题记录/错误码传播审计.md`(E-xx)、
|
||||
`测试说明/实机测试实施指南.md`(执行流程)——三者均不在本文件夹合并范围。
|
||||
- 上游引用关系:`问题记录/项目审查与优化建议报告.md`(体系层评审)、
|
||||
`测试说明/实机测试实施指南.md`(执行流程)——两者均不在本文件夹合并范围。
|
||||
|
||||
+12
-35
@@ -11,46 +11,23 @@
|
||||
|
||||
## 2. 设计基线(供后续接入参考)
|
||||
|
||||
### 2.1 ACCEPT pending 化设计基线(recv/send 挂起已落地)
|
||||
### 2.1 net 层阻塞模型 pending 化(状态)
|
||||
|
||||
> **来源**:recv/send 架构现状见 `docs/网络/Net层阻塞模型架构设计.md`(演进史查 git 历史);
|
||||
> 本节仅保留 **ACCEPT pending 化仍要用的设计基线**。
|
||||
> **来源**:`docs/网络/Net层阻塞模型架构设计.md`(现状架构;演进史查 git 历史)。
|
||||
|
||||
**已验证的机制骨架**(ACCEPT 沿用,勿重新发明):独立静态 pending 表 + `net_pending_tick`
|
||||
主循环按节拍结束挂起(recv 五路:数据/到点/断连/同 fd 串行/重建取消必通知)+ 登记守卫(每 fd 至多一个、
|
||||
不覆盖、拒绝 netTask 自等待)+ 挂起超时留痕探针(tripwire,只留痕不伪造返回值)。
|
||||
|
||||
**扩展点**:
|
||||
|
||||
| 项 | 目标 | 对应缺陷 | 状态 |
|
||||
|---|---|---|---|
|
||||
| **SEND pending** | 发送续传改为"登记 → send_ready 完成",消除 1s/分片 stall 对队列的冻结 | E-02 残余(SEND 位置) | ✅ **2026-10-14 已落地**(`net_send_pending_tick` + 有界自旋 `NET_SEND_SPIN_MS`;架构见 `docs/网络/Net层阻塞模型架构设计.md` §4.5/§5.5/§7) |
|
||||
| **ACCEPT pending** | accept 等待改为"登记 → CONNECT 事件完成",退役 100ms/200ms 轮询循环 | E-06(accept 轮询计时失真) | ⬜ 待做 |
|
||||
|
||||
**ACCEPT 门禁**(在已落地机制的门禁基础上加强):
|
||||
|
||||
1. CH395F NET 层全套件(含此前未跑的 Phase 7 / Phase 10,视 RAM 预算);
|
||||
2. 延迟探针 L3/L5 基线重锁(recv 挂起落地时已重锁 M3,ACCEPT 落地须再锁);
|
||||
3. `e02_probe.py` **探针族扩充**:close / reconfig / EOF / disconnect-during-pending 四专项;
|
||||
4. `ftp_regression.py`(D20)+ E-06 假 425 场景**独立重跑**(recv 挂起那轮是借 M3 压力档覆盖的);
|
||||
5. UI 远端推流压力 + timeSync 三场景;
|
||||
6. 产品 `@test` 闭环 + ST-LINK 全片回读;
|
||||
7. `ram_report.py` / `stack_report.py` 前后对比(铁律);
|
||||
8. 看门狗接 selftest 留痕 + 模拟器差距清单 +1(`net_socket_sim.c` 无法建模 pending)。
|
||||
|
||||
**已知代价(延续,需文档化)**:pending 完成判定随主循环节拍运行,被长操作占用时超时
|
||||
顺延(~1ms 级);**SEND 已 pending 化(2026-10-14)**,该顺延面已收窄——发送停滞不再顺延整层;
|
||||
剩余 ACCEPT 化不改变此结论。
|
||||
|
||||
**改动量估算**:SEND 实际落地约 300 行(`net_pending.c` +287 行、`net_socket.c` 10 处集成点、
|
||||
`net_config.h` 新增 `NET_SEND_SPIN_MS`);公开 API 不变。风险评级**中**(执行器核心 + D 系列前科)
|
||||
——**大的是验证,不是代码**。SEND 已完成构建门禁(0 错误 0 警告)与静态核对,**台架复测待做**
|
||||
(netTask 栈峰值须重测)。剩余 ACCEPT 预计再 ~100-200 行。
|
||||
- **recv 挂起 / send 挂起已落地**:`net_recv` 阻塞不占 netTask(登记 + 每轮 tick 唤醒);
|
||||
`net_send` 快路径有界自旋(`NET_SEND_SPIN_MS` = 2 ms),超预算登记挂起、由 `net_send_pending_tick`
|
||||
按主循环节拍分块推进(2026-10-14 落地)。
|
||||
- **ACCEPT pending 化决定不实施(2026-10-15)**:ACCEPT 是**调用方轮询**问题、执行者零占用
|
||||
(`net_accept_locked` 单次 `net_poll` 即返回,0 停滞)——pending 化只换 RPC 开销与延迟抖动,
|
||||
不解队头阻塞;判据见 `docs/网络/Net层阻塞模型架构设计.md` §10。
|
||||
- 原 ACCEPT 设计基线(扩展点 / 门禁清单 / 改动量估算)随该决策作废,不再保留。
|
||||
|
||||
### 2.2 错误码通道四要素(CH395F 范式)
|
||||
|
||||
> **来源**:`../问题记录/错误码传播审计.md`。GD5F 错误通道统一(E-10 / E-42 / E-53 / E-54 / E-56 / E-57)
|
||||
> 即按此骨架落地(2026-10-03,套件回归 16/16 PASS)。**后续任何驱动 / 子系统建立错误通道时应沿用。**
|
||||
> **来源**:错误码通道四要素方法论(2026-09 错误码传播审计确立,属主文档已于 2026-10-15 删除)。
|
||||
> GD5F 错误通道统一即按此骨架落地
|
||||
> (2026-10-03,套件回归 16/16 PASS,见 `../问题记录/GD5F2GQ5UE_Trap_Records.md`)。**后续任何驱动 / 子系统建立错误通道时应沿用。**
|
||||
|
||||
```
|
||||
① 分类:区分「超时 / 真故障 / 参数错」——不得混为一个返回码
|
||||
|
||||
+3
-4
@@ -9,12 +9,11 @@
|
||||
|
||||
| 序 | 任务 | 说明 | 出处 |
|
||||
|---|---|---|---|
|
||||
| **N-20** | **`Error_Handler` 统一降级** | 一处初始化失败 = 整机挂死(只剩 IWDG 兜底)→ 记自检 + 禁用该子系统 + 其余照常。详见 `登记簿.md` | 报告 N-03c |
|
||||
| **C6** | **USART1 TX-only 结构根治(S-3)** | 灭 ORE 僵尸机制根源(2026-10-02 台架 IWDG 误复位的机制根源):改 `.ioc` 令 USART1 不使能 RX / PA10 不复用为 `USART1_RX` → CubeMX 重生成 → 跑 `check_cubemx_survival.py`。结构性改动,需单开一轮 + 复跑台架闭环 | S-3 |
|
||||
| **C3** | **存储侧日志管线(N-2 + N-24)** | 丢弃可观测性**代码已具备**(`console_log.c` `s_con_drop`+`[ERR] CONSOLE dropped`、`sys_log_mcu.c` 队列满 `DBG_ERROR`、TX 僵尸通道自愈);V5 30 min 日志**未复现 49s 静默**(运行期 >10s 静默全为 ~28s、均在 `e02_probe` 窗口内=N-17)。剩余:与 S8(非阻塞日志)合并评估 + 日志逐条 `f_open/f_write/f_close` 改造评估(N-24) | N-2 / N-24 |
|
||||
| **C1** | **ACCEPT + SEND 阻塞路径 pending 化** | 沿用已落地的 recv 挂起机制扩展;同期消化 E-25(net_select 语义)、E-24/E-27/E-28(跨上下文收口);基线重锁 + 探针族扩充 + 看门狗接 selftest。**设计基线见 `基线与待确认.md` §2.1** | N-4 |
|
||||
| **C5** | 一档剩余 | E-15(ringbuf 定去留——**已确认零调用者,倾向删除**)、E-61(SD2506 注释订正)、E-16(cfg_file 段名长度)、E-26(UDP 定案,倾向移除)、E-23、E-30;**N-23 残余**(`KNOWN_GAPS` 白名单清理 + `app_cfg.h` 未接线开关,见 `登记簿.md`)。**E-49(RS485 DE 收尾)已移入 `暂缓-RS485.md`** | 一档/二档 |
|
||||
| **N-22/25/26/28** | 评估簇 | 写回 flush / 性能与语义一致性 / NAND DMA 断言 / Flash 死代码——逐项见 `登记簿.md` 对应行,随窗口评估 | 报告各条 |
|
||||
| **C1** | **net 层跨上下文收口** | 消化 E-25(`net_select` 语义)、E-27/E-28(裸指针收口为状态查询 API)。原 ACCEPT + SEND pending 化已收口:SEND 2026-10-14 落地、ACCEPT 决定不实施(2026-10-15) | E-25 / E-27 / E-28 |
|
||||
| **C5** | 一档剩余 | **N-23 残余**(`KNOWN_GAPS` 白名单清理 + `app_cfg.h` 未接线开关,见 `登记簿.md`)。**RS-485 DE 收尾已移入 `暂缓-RS485.md`** | 一档/二档 |
|
||||
| **N-22/25/28** | 评估簇 | 写回 flush / 性能与语义一致性 / Flash 死代码——逐项见 `登记簿.md` 对应行,随窗口评估 | 报告各条 |
|
||||
|
||||
## 2. W5 验证常态详述
|
||||
|
||||
|
||||
@@ -75,11 +75,11 @@
|
||||
1. **协议解析必须与硬件 I/O 分离**——`App/protocol/` 的解析函数应接受
|
||||
`(const uint8_t *buf, size_t len)` 并返回解析结果,使其成为 L0.5 的**天然适格对象**
|
||||
(参考 `cfg_file` 的"核心 + 后端"模式);
|
||||
2. **采集缓冲必须双缓冲 + 序号**(上游 E-49 / E-50)——否则消费者读到撕裂数据,
|
||||
2. **采集缓冲必须双缓冲 + 序号**——否则消费者读到撕裂数据,
|
||||
且**撕裂在单测里测不出来**(时序相关),必须在设计上消除;
|
||||
3. **DE 收尾必须有超时路径覆盖**(RS485 半双工特有陷阱)。
|
||||
|
||||
**完成判据**:B2 设计文档体现上述三条;协议解析函数有对应 L0.5 单测。(B1 侧:ADC 无协议解析面,其"同一时刻性"由 E-58 原子快照保证、已闭环。)
|
||||
**完成判据**:B2 设计文档体现上述三条;协议解析函数有对应 L0.5 单测。(B1 侧:ADC 无协议解析面,其"同一时刻性"由原子快照保证、已闭环。)
|
||||
|
||||
### 2.4 A-5 残余:CI 体积门禁盲区 ⬜
|
||||
|
||||
|
||||
+5
-8
@@ -11,9 +11,8 @@
|
||||
|
||||
| # | 事项 | 发现 | 证据与现状 | 出处 |
|
||||
|---|---|---|---|---|
|
||||
| N-2 | **49s 全系统日志静默(defaultTask/NAND syslog 排空停滞)**——串口日志 49s 无行,期间 net 栈照常处理外部连接 → 日志管线停滞,队列满后各任务日志行被丢;系统功能不受损 | 2026-09-22(L3 台架 F2,gen 181) | **A/B 归因:既有存储侧现象**。**2026-10-03 降级为低风险观察项**:① 丢弃可观测性**代码已具备**(`console_log.c` `s_con_drop` + `[ERR] CONSOLE dropped`;`sys_log_mcu.c` 队列满 `DBG_ERROR`;UART TX 僵尸通道自愈);② V5 30 min **未复现 49s**(>10s 静默全为 ~28s、均在 `e02_probe` 窗口内=N-17)。**残余待办**:与 S8(非阻塞日志)合并评估(C3) | `错误码传播审计.md` E-02 阶段二 |
|
||||
| N-2 | **49s 全系统日志静默(defaultTask/NAND syslog 排空停滞)**——串口日志 49s 无行,期间 net 栈照常处理外部连接 → 日志管线停滞,队列满后各任务日志行被丢;系统功能不受损 | 2026-09-22(L3 台架 F2,gen 181) | **A/B 归因:既有存储侧现象**。**2026-10-03 降级为低风险观察项**:① 丢弃可观测性**代码已具备**(`console_log.c` `s_con_drop` + `[ERR] CONSOLE dropped`;`sys_log_mcu.c` 队列满 `DBG_ERROR`;UART TX 僵尸通道自愈);② V5 30 min **未复现 49s**(>10s 静默全为 ~28s、均在 `e02_probe` 窗口内=N-17)。**残余待办**:与 S8(非阻塞日志)合并评估(C3) | `../网络/Net层阻塞模型架构设计.md`(原审计队头阻塞阶段二) |
|
||||
| N-3 | **L5 队列往返基线(1223/988µs)的 L3 后重验**——L5 测 DONTWAIT 队列全程;L3 对该路径逐位不变 → 机制上无影响,但基线数值属分片时代,严格重锁需跑一轮 Phase 13(需 PC peer) | 2026-09-22(L3 收尾留档) | 低风险:10ms/100ms 阈值余量 >8×;下次 Phase 13 窗口顺带重锁即可 | `链路延迟测试说明.md` §6.4 L5 注¹ |
|
||||
| N-4 | **ACCEPT 阻塞路径 pending 化**(recv/send 挂起机制已落地,扩展到 accept)——E-06、E-20、E-21 剩余分量共用该机制扩展;届时延迟探针 L3/L5 基线再重锁、探针族扩充、看门狗接 selftest 留痕、模拟器差距清单 +1 | — | **recv 挂起已落地**;**send 挂起已于 2026-10-14 落地**(构建门禁过、台架复测待做),**ACCEPT 仍待做**(收益性质不同,优先级低——见 `Net层阻塞模型架构设计.md` §10 判据)。架构现状见 `Net层阻塞模型架构设计.md`,ACCEPT 设计基线见 `基线与待确认.md` §2.1 | `错误码传播审计.md` 第二档 #2 |
|
||||
| N-16 | **A2/A4 专项场景台架验证待办**(正常路径已实测零回归):① PHY 拔线负向测试——断链需断 **DTU 侧**线缆或关**受管交换机端口**;② A2 芯片级 `net_init` 失败分支(需 SPI 故障注入);③ A4 短写压测(需远显客户端 + UI 推流压力) | 2026-10-03(台架拓扑 = CH395↔交换机,拔线操作受限) | 待专项台架窗口 | `实机测试实施指南.md` §10 |
|
||||
| N-17 | **`time_sync` 30s 挂起客户端掉线 + 监听重建期间,网络任务心跳缺口达 800ms~1s(声明 stall 但未复位)。**待办**:定位监听重建为何阻塞 NET/FTP/UI;评估缩短重建重试(5×2s)或让掉线路径不阻塞其它任务 | 2026-10-03(V5 台架) | V5 长跑 44 次 `task stall: mask=0x00000001`,**100% 与 `e02_probe` 的 30s 挂起客户端触发 `time_sync: no TIME packet in 30s, drop conn` → 监听重建(约 4s)重合**;隔离实验(仅 FTP,120s)**0 次 stall** → 探针场景专属。缺口(~1s)< IWDG 最坏超时(1701ms),余量仅 ~0.7s。 | `实机测试实施指南.md` §4;`../子系统设计/看门狗设计说明.md` |
|
||||
| N-30 | **relisten 沉降段统一到驱动 `sock_reset` 原语受阻**——"去重复实现"的收口已实测回退:原语版 `ftp_abort_probe` RST **0/10**、FIN **0/5**(中止后首笔复连仍被截断到 ≤2048B),另新增 `sock_reset_sync timeout (600ms)` 与 `close: sock_reset not done` 两条 `[ERR]`;同场 net 层自建序列 **10/10 + 5/5** | 2026-10-14(同一块板 A/B,判据 `test/host/ftp_abort_probe.py`;快复连 50/50、背靠背 30/30 两版都过 → 失效面精确落在"中止后首笔复连") | **现状 = `net_listener.c` 保留自建排渣序列**(排空 + CLOSE + 排事件 + 等 CLOSED,30 ms 重试轮持续清)。重开前置三条语义:① 隔离窗内**持续**排空/关闭(残渣在 CLOSE 之后才落进 RX,一次排空接不住)② **复用让位**(复位机不得拆上层刚在同一芯片 Socket 上重建的监听)③ `net_sock_reset_sync` 改"已在运行 = 加入等待"(`begin` 返 -1 ≠ 失败) | `../网络/网络自愈架构设计.md` §8 延后项 1、§5.2 E16;`../问题记录/CH395F_Trap_Records.md` TRAP-NET-18 |
|
||||
@@ -42,14 +41,12 @@
|
||||
|
||||
| # | 事项 | 影响 / 现状 | 处置方向 | 波次 | 出处 |
|
||||
|---|---|---|---|---|---|
|
||||
| N-20 | `Error_Handler` 仍 `__disable_irq(); while(1){}`(`Src/main.c:274-282`) | 一处初始化失败 = 整机挂死(只剩 IWDG 兜底),无自检日志 | 统一降级策略:记自检 + 禁用该子系统 + 其余照常 | W4 | 报告 N-03c |
|
||||
| N-21 | **dhara 两处**:`dhara_nand_is_free()` 只查页首 64 B;`dhara_nand_copy()` 不处理 `DHARA_NO_PAGE` 哨兵 | 映射恢复误判 → **数据丢失风险**(低概率、后果重);哨兵页号被当真实页 → 未定义行为;至今只能靠人工读代码发现 | 整页(或首/中/尾)扫描 + 返回 `DHARA_E_UNSUPPORTED`;**必须配主机侧移植层单测**(一并补报告"覆盖率"缺口) | **W2** | 报告 N-12/N-13 + §7 |
|
||||
| N-22 | 写回缓存无空闲/掉电强制 flush(整页写与换页已 flush) | 写回窗口内掉电丢最近日志/配置写 | defaultTask 空闲 N ms flush | W4 | 报告 N-14 |
|
||||
| N-23 残余 | **钩子已落地**(2026-10-12 `registration-check` 挂 pre-commit,存量缺口走 `KNOWN_GAPS` 白名单只 WARN);**残余** = 白名单清理:`rs485_task.c`(随 B2 暂缓一并处置:删除或注册)、`lftpd_log.c`;`app_cfg.h` 未接线开关(C5) | 白名单不清 = "写了不编译"盲区仍在 | 逐项清白名单(`--strict` 供审计复跑);开关随 C5 处置 | W4(C5) | 报告 N-06 残余 + 报告 S-3 |
|
||||
| N-23 残余 | **钩子已落地**(2026-10-12 `registration-check` 挂 pre-commit,存量缺口走 `KNOWN_GAPS` 白名单只 WARN);**残余** = 白名单只剩 `rs485_task.c` 一条**刻意**缺口(E-59 门禁下随 B2 暂缓,见 `暂缓-RS485.md`);`app_cfg.h` 未接线开关(C5)。⚠ `lftpd_log.c` 已随 N-19 删除并入 `lftpd_auth.c`(2026-10-11),不再是缺口 | 白名单不清 = "写了不编译"盲区仍在 | 随 B2 一并出白名单(`--strict` 供审计复跑);开关随 C5 处置 | W4(C5) | 报告 N-06 残余 + 报告 S-3 |
|
||||
| N-24 | 日志每条 `f_open+f_write+f_close`(`sys_log_mcu.c:123-140`) | 每条日志 2–4 次 NAND 页读写;UI 翻记录逐条 open/seek/close | 与 C3 日志管线合并评估(现仅 `FIL` static 化省 528 B 栈) | W4 | 报告 N-16(**≠ 本登记簿 N-16**) |
|
||||
| N-25 | 性能/资源建议簇:PASV 每次新建监听;`NET_RECV_TIMEOUT_MS 30000`;PHY 强制 100M 无自协商回退;`NET_MAX_SOCKETS 8` 与单连接语义不符;`HAL_Delay(1)` 阻塞 DE(**DE 项随 B2 暂缓,见 `暂缓-RS485.md`**) | 次级性能/语义一致性 | 逐项见 `../问题记录/项目审查与优化建议报告.md` §4.2/§4.5/§4.7,随窗口评估 | W4 | 报告 N-09/P2-8/PHY/P3-x/rs485 |
|
||||
| N-26 | NAND 直 DMA 调用方缓冲(已加运行时守卫,阈值 1024) | CCM 缓冲被 DMA = 静默传错(与 ADC DMA 不可达 CCM 同类坑) | 补编译期/启动期地址断言 + **新铁律:堆缓冲不可被 DMA 直接寻址** | W4 | 报告 N-11 |
|
||||
| N-27 | **内存优化簇**:LVGL 池 + UI 两份缓冲 54,146 B 仍在 SRAM1,CCM 只剩 ≈8,160 B(2026-10-12 B5 堆扩容 48→56 KB 后) | R-2 后半段(迁 CCM)被堵死 → 后续功能预算看不清 | **三件套 ✅ 2026-10-12 落地**(`ram_baseline.py` 四模式 + `ram_baseline.tsv` 趋势 + `docs/内存管理/RAM预算台账.md` + `mem-budget` 钩子 92% 门禁)→ **W3** 再做 R-9(`LV_MEM_SIZE` 40→16 KB,池水位门禁数据已具备)→ R-2 后半;R-3/R-4/R-5/R-6 逐项评估(R-6 前置已满足) | **W3** | 报告 R-2 剩余/R-3~R-6/R-9/§5.5 |
|
||||
| N-25 | 性能/资源建议簇:PASV 每次新建监听;PHY 强制 100M 无自协商回退;`NET_MAX_SOCKETS 8` 与单连接语义不符;`HAL_Delay(1)` 阻塞 DE(**DE 项随 B2 暂缓,见 `暂缓-RS485.md`**)。⚠ 原列的 `NET_RECV_TIMEOUT_MS 30000` 已随 2026-10-13「recv 语义主流化」删除(挂起 recv 模型),不再是待办 | 次级性能/语义一致性 | 逐项见 `../问题记录/项目审查与优化建议报告.md` §4.2/§4.7,随窗口评估 | W4 | 报告 N-09/PHY/P3-x/rs485 |
|
||||
| N-27 | **内存优化簇**:LVGL 池 + UI 两份缓冲 54,146 B 仍在 SRAM1,CCM 只剩 **7,904 B**(`RW_CCM` 上限 65,280 − 57,376;2026-10-12 B5 堆扩容 48→56 KB 后) | R-2 后半段(迁 CCM)被堵死 → 后续功能预算看不清 | **三件套 ✅ 2026-10-12 落地**(`ram_baseline.py` 四模式 + `ram_baseline.tsv` 趋势 + `docs/内存管理/RAM预算台账.md` + `mem-budget` 钩子 92% 门禁)→ **W3** 再做 R-9(`LV_MEM_SIZE` 40→16 KB,池水位门禁数据已具备)→ R-2 后半;R-3/R-4/R-6 逐项评估(R-6 前置已满足)。⚠ **R-5 已判定不可行、从本簇剔除**:CMSIS-RTOS2 `freertos_os2.h` 有 `#if (configMAX_PRIORITIES != 56) #error`,改小直接编译失败(为 480 B 改第三方包装层不划算) | **W3** | 报告 R-2 剩余/R-3/R-4/R-6/R-9/§5.5 |
|
||||
| N-28 | Flash 死代码评估簇:剩余 ≈10 KB(`box_shadow` 3,246 / `draw_sw_img` 2,960 / `bin_decoder` 1,972 / `image_decoder` 952 / `triangle` 930)+ 双精度 `dadd` 等 ≈1 KB;uvprojx 仍挂 201 个空 LVGL TU(F-1/F-2/F-3 已闭环,省的是编译时长) | 编译时长 + 文档噪音 | 逐项实测再关;⚠ `mask`/`mask_rect`/`grad` 是文字与矩形绘制必经路径,**不可盲关** | W4 | 报告 F-4/F-5/F-6 |
|
||||
| N-29 | **仓库膨胀**:`.git` 149 MB + 图片 36.3 MB | clone/备份慢,且持续恶化 | 降采样 / 拆 submodule / LFS 三选一 **+ 一次 `git filter-repo` 历史重写**。**已决策(2026-10-11):暂不处理、登记观察**——推送/协作前重评(届时未推送提交更少、重写代价最低) | **W7** | 报告 D-1 |
|
||||
| N-29 | **仓库膨胀**:`.git` **235.3 MB**(2026-10-14 实测;本行建档时记 149 MB)+ 手册图片 36.3 MB(受控文件合计仅 79.3 MB,`.git` 已是它的 3 倍) | clone/备份慢,且持续恶化 | 降采样 / 拆 submodule / LFS 三选一 **+ 一次 `git filter-repo` 历史重写**(三项都不解决历史膨胀)。**已决策(2026-10-11):暂不处理、登记观察**——推送/协作前重评(届时未推送提交更少、重写代价最低) | **W7** | 报告 D-1 |
|
||||
| U 簇 | UI 标准化:无令牌层/组件库/页注册表(手写 `case` 仍在),**27 页**未落地;golden 未挂 pre-commit、字符集差集检查仍是约定 | 新增一页成本仍是 8 处手工改动 | 按 `../问题记录/项目审查与优化建议报告.md` §6.5:U4 残余(两脚本入门禁,可逢窗口顺带)→ U1 令牌层 → U2/U3 → 页面落地;U4 golden 可直接当 U1 验收工具。**已确认(2026-10-11):本轮不排期**,等功能主线出结果后按产品需求启动 | W6 | 报告 U1~U5 |
|
||||
|
||||
@@ -36,10 +36,10 @@
|
||||
<!-- MEM_SNAPSHOT:BEGIN generated by scripts/check_mem_numbers.py -->
|
||||
| 区域 | 用量 | 容量 | 占比 |
|
||||
|---|---|---|---|
|
||||
| ER_IROM1 | 231,036 B (225.62 KB) | 1,048,576 B (1024 KB) | 22.0% |
|
||||
| ER_IROM1 | 231,084 B (225.67 KB) | 1,048,576 B (1024 KB) | 22.0% |
|
||||
| RW_IRAM1 | 98,144 B (95.84 KB) | 131,072 B (128 KB) | 74.9% |
|
||||
| RW_CCM | 57,376 B (56.03 KB) | 65,280 B (64 KB) | 87.9% |
|
||||
| **Flash (ROM 合计)** | **232,148 B (226.7 KB)** | 1,048,576 B (1024 KB) | **22.1%** |
|
||||
| **Flash (ROM 合计)** | **232,196 B (226.8 KB)** | 1,048,576 B (1024 KB) | **22.1%** |
|
||||
<!-- MEM_SNAPSHOT:END -->
|
||||
|
||||
各区的容量与常量来源:
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
>
|
||||
> **数字不手抄**:下方受管区由 `scripts/ram_baseline.py --write` 从 `.map` 生成,
|
||||
> pre-commit `mem-budget` 钩子校验一致性(同 `mem-numbers` 的"事实源唯一"思路)。
|
||||
> 配额是**规划值**(`docs/问题记录/项目审查与优化建议报告.md` §5.5),改动 = 先登记本文件 §6 变更记录,再改 `ram_baseline.py` 的 `QUOTAS`。
|
||||
> 配额是**规划值**,**本文件 §2 是配额与阈值的唯一权威**(2026-09 体系评审提出、2026-10-12 落地后报告侧条目已销项),改动 = 先登记本文件 §6 变更记录,再改 `ram_baseline.py` 的 `QUOTAS`。
|
||||
> 区域放置与 DMA 可达性规则 → `内存内容分配策略.md`(本文件不重复)。
|
||||
|
||||
## 1. 区域预算与门禁(受管区)
|
||||
@@ -15,7 +15,7 @@
|
||||
<!-- MEM_BUDGET:BEGIN generated by scripts/ram_baseline.py -->
|
||||
| 区域 | 用量 | 容量 | 占比 | 门禁(≤92%) |
|
||||
|---|---|---|---|---|
|
||||
| ER_IROM1 (Flash) | 231,036 B | 1,048,576 B | 22.0% | 参考 |
|
||||
| ER_IROM1 (Flash) | 231,084 B | 1,048,576 B | 22.0% | 参考 |
|
||||
| RW_CCM | 57,376 B | 65,280 B | 87.9% | PASS |
|
||||
| UNINIT_CCM | 48 B | 256 B | 18.8% | 参考 |
|
||||
| RW_IRAM1 | 98,144 B | 131,072 B | 74.9% | PASS |
|
||||
@@ -33,7 +33,7 @@
|
||||
- **门禁**:pre-commit `mem-budget` 钩子(`scripts/ram_baseline.py --gate`)——
|
||||
RW_IRAM1 / RW_CCM 任一 >92% 即拦提交,并打印 Top-10 RW+ZI 对象定位增量;
|
||||
无 `.map` 时自适应跳过(CI 盲区登记在 `docs/任务规划/测试与架构专项.md` A-5 残余)。
|
||||
- **阈值依据**:92% = `docs/问题记录/项目审查与优化建议报告.md` §5.5 第 1 条——留 ~8% 给突发缓冲与栈抬升,
|
||||
- **阈值依据**:92% 由 2026-09 体系评审提出、2026-10-12 落地为门禁(提出时的报告条目已随销项删除,闭环说明见 `docs/问题记录/项目审查与优化建议报告.md` §5.5)——留 ~8% 给突发缓冲与栈抬升,
|
||||
触线即触发排期,而不是静默逼近溢出。
|
||||
- **软提醒**(不拦提交):tsv 末行落后于 `.map`(忘跑 `--update`)、`.map` 早于最新源码(忘 `@build`)。
|
||||
- **子系统归集为参考值**:按对象名前缀归集(口径见 §2),合计与区域总量可差几十字节
|
||||
@@ -41,7 +41,7 @@
|
||||
|
||||
## 2. 子系统配额口径
|
||||
|
||||
配额值(`ram_baseline.py` 的 `QUOTAS`,与 `docs/问题记录/项目审查与优化建议报告.md` §5.5 第 3 条一致;
|
||||
配额值(`ram_baseline.py` 的 `QUOTAS`,**本文件即唯一权威**;
|
||||
RTOS 堆 2026-10-12 B5 扩容 48→56 KB 见 §6):**网络 12 KB / 存储 12 KB /
|
||||
UI 16 KB / RTOS 堆 56 KB / 应用 8 KB**。归集口径(按 `.map` 对象名,首匹配):
|
||||
|
||||
|
||||
@@ -39,11 +39,13 @@
|
||||
## 4. 内容分配规则
|
||||
|
||||
- **R1(CCM 驻留)**:CCM 只放"**CPU-only 且损坏即致命、无自愈**"的内存。当前唯一驻留者 = **FreeRTOS 堆**(`heap_4.o`,56KB——2026-10-12 B5 由 48KB 扩容,`.ioc` L1 参数 `configTOTAL_HEAP_SIZE=57344`;全部任务栈/队列/定时器)。scatter 的 RW_CCM 节**不得**再列其他对象;任何新增必须经 §5 式裁决并走 §7 完整验证阶梯。
|
||||
- **R2(DMA 缓冲)**:只允许文件作用域静态缓冲,必须落 SRAM。两条防线缺一不可:
|
||||
- **R2(DMA 缓冲)**:只允许文件作用域静态缓冲,必须落 SRAM。**三层防线缺一不可**:
|
||||
- **窗口防线(编译期)**:DMA 白名单窗口 `GD5F_DMA_RAM_BASE/END`(0x20000000~0x20020000,须与 scatter `RW_IRAM1` 一致)与 CCM 窗口**永不得重叠**,另锁死阈值契约 `132 ≤ GD5F_DMA_THRESHOLD < GD5F_PAGE_SIZE`——两条都用项目惯用的**负数组 typedef 断言**(AC5 不支持 C11 `_Static_assert`),有人改窗口常量或阈值当场编译失败(`gd5f2gq5ue.h`)。
|
||||
- **尺寸防线**:GD5F DMA 阈值 `GD5F_DMA_THRESHOLD=1024`(>1024B 才走 DMA;阈值以下一律 CPU 轮询)。取值须 ≥ 存储路径上可能出现在任务栈的最大缓冲(dhara meta 132B、`dhara_nand_is_free` 64B)、且 < 页大小(2048,保住页级热路径的 DMA)。
|
||||
- **地址防线(2026-09-21 加固)**:`gd5f_dma_buf_ok()` 运行时校验**整段**缓冲是否落在 SRAM 区间(0x20000000~0x2001FFFF),越界者拒走 DMA、回落 CPU 轮询,并打印 `[ERR][NAND] RX/TX DMA buffer not DMA-reachable (p=… size=…) fallback poll`。
|
||||
- **地址防线(运行时 + 启动期)**:`gd5f_dma_buf_ok()` 运行时校验**整段**缓冲是否落在 SRAM 区间(0x20000000~0x2001FFFF),越界者拒走 DMA、回落 CPU 轮询,并打印 `[ERR][NAND] RX/TX DMA buffer not DMA-reachable (p=… size=…) fallback poll`;`nand_ftl.c` 在 init 期对三块静态页缓冲**预先过同一守卫**,把"scatter 被改动导致静态缓冲落进 CCM"变成开机即报,而不是静默传错。
|
||||
|
||||
阈值只挡得住"当前已知的小栈缓冲",挡不住"将来新加的 >1024B 非 SRAM 缓冲";地址守卫把 R2/R3 从**约定**升级为**运行时强制**。守卫负路径已由 TC-GD5F-704/705 在台架实证(读/写两方向各一,探针缓冲取自 CCM 堆,数据仍正确落位)。
|
||||
⚠ **缓冲自身地址无法编译期断言**:`.bss` 地址链接期才确定,AC5 的常量表达式取不到(`__builtin_*` 系在 MicroLIB 下亦不可用,实证见 `Src/main.c` `Error_Handler` 注释)→ 静态缓冲落位靠 **scatter + 启动期自检**双层保证,别再试图"加个 `_Static_assert`"。
|
||||
- **R3(堆/栈隔离)**:禁止以 `pvPortMalloc` 所得内存或任务栈为 DMA 源/目的(09-21 事故类:DMA 静默不落地 = 静默数据损坏,比报错更难查)。该约束在 GD5F 驱动内已由 `gd5f_dma_buf_ok()` 运行时强制(违反即回落轮询 + `[ERR]` 日志),并有 TC-GD5F-704/705 覆盖读、写两个方向。
|
||||
- **R4(UI/LVGL 留 SRAM)**:LVGL 池 + 帧缓冲为**自愈型**内容(每帧由 widget 树全量重渲染,脏帧下一帧即消失),不需要保护区;且留 SRAM 保留 DMA 门(将来帧推送若要 DMA 加速必须 SRAM 可达);其越界风险已由 32B 保护带 + canary + 溢出钩子兜住(见 §5.3)。
|
||||
- **R5(新内容放置判定表)**:
|
||||
@@ -138,7 +140,9 @@ LVGL 集合明细(均在 SRAM):LVGL 池 40,960B(`lv_mem_core_builtin.o`
|
||||
|---|---|
|
||||
| CCM 布局(仅 heap_4.o) | `MDK-ARM/STM32F407-Demo/STM32F407-Demo.sct` |
|
||||
| DMA 阈值 1024B | `Drivers/BSP/GD5F2GQ5UE/gd5f2gq5ue.h`(`GD5F_DMA_THRESHOLD`,公开供测试对齐上下界) |
|
||||
| DMA 窗口/阈值**编译期**断言 | `Drivers/BSP/GD5F2GQ5UE/gd5f2gq5ue.h`(`gd5f_dma_window_no_ccm_check_t` 窗口不重叠 + `gd5f_dma_threshold_contract_check_t` 阈值契约,负数组 typedef) |
|
||||
| DMA 可达性运行时守卫 | `Drivers/BSP/GD5F2GQ5UE/gd5f2gq5ue.c`(`gd5f_dma_buf_ok`,`gd5f_read_from_cache`/`gd5f_program_load` 两处接入) |
|
||||
| 静态缓冲落位**启动期**自检 | `Drivers/BSP/GD5F2GQ5UE/nand_ftl.c`(init 期对三块 2KB 页缓冲过 `gd5f_dma_buf_ok`) |
|
||||
| 守卫负路径用例(读/写) | `test/board/gd5f_test_task.c`(TC-GD5F-704/705) |
|
||||
| 错误级日志纳入自动闭环 | `.dsh/skills/serial-boot-test/scripts/verify_log.py` + `.dsh/skills/serial-boot-test/scripts/run_boot_test.py`(默认 Forbidden 含 `[ERR]`,`[FAIL]` 仍拦截断言失败) |
|
||||
| LVGL 越界保护带 32B | `Drivers/BSP/UI/ui_port.c`(`UI_DRAW_BUF_GUARD`) |
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
> 版本 v1.1 日期 2026-09-21 作者 AI 辅助调研
|
||||
> 数据来源:`data/ram_report_20260921.md`(.map 静态占用)+ 逐行代码核验(`nand_ftl.c` / `gd5f2gq5ue.c` / `Lib/dhara` / `Lib/FatFs/ffconf.h` / `lftpd*`)
|
||||
> 定位:`RAM使用分析与优化方案.md` 的存储专项补充;优化项编号 P0/P1/P2,与 `docs/内存管理/RAM使用分析与优化方案.md` §6 的 S 序号在"规划"一节对齐
|
||||
> v1.1 清理(2026-09-21 同日):移除已落地的 P0-1 BBT 页缓冲收缩(−1,776B,commit `be1a30a`)与编程回读校验整体移除的实施记录(详见 GD5F TRAP-GD5F-05 / 错误码传播审计),以及过期逐模块基线表;仅保留未实施项与回归要求
|
||||
> v1.1 清理(2026-09-21 同日):移除已落地的 P0-1 BBT 页缓冲收缩(−1,776B,commit `be1a30a`)与编程回读校验整体移除的实施记录(详见 GD5F TRAP-GD5F-05),以及过期逐模块基线表;仅保留未实施项与回归要求
|
||||
|
||||
## 1. 现状约束(不变,是下述全部方案的依据)
|
||||
|
||||
|
||||
+12
-3
@@ -6,7 +6,7 @@
|
||||
> **日期**:2026-09-29 创建;**2026-10-10 按当前代码重写正文**(旧正文含大量立项前的
|
||||
> 描述,已清理;实施史与逐次决策见 §10 与文末变更记录,未删)。
|
||||
> **相关文档**:
|
||||
> [`../任务规划/README.md`](../任务规划/README.md)(登记簿未办项 N-17 / S-3 / N-4,见 `../任务规划/登记簿.md`)、
|
||||
> [`../任务规划/README.md`](../任务规划/README.md)(登记簿未办项 N-17 / S-3,见 `../任务规划/登记簿.md`)、
|
||||
> [`运行与自检记录设计说明.md`](运行与自检记录设计说明.md)(复位记录与 `selftest.log`)、
|
||||
> [`../测试说明/看门狗单元测试说明.md`](../测试说明/看门狗单元测试说明.md)(L0.5 判定状态机单测)、
|
||||
> [`../测试说明/实机测试实施指南.md`](../测试说明/实机测试实施指南.md)(故障注入台架流程)、
|
||||
@@ -243,6 +243,16 @@ static HAL_StatusTypeDef iwdg_deferred_start(const IWDG_HandleTypeDef *a_h) { (v
|
||||
|
||||
4 个 Fault(Hard/Mem/Bus/Usage)的采集与使能(`fault_handler_enable()` 使能后三者,否则被升级成 HardFault 看不出根因)见 §10.2 与 `AGENTS.md`「平台约束」。
|
||||
|
||||
**`Error_Handler()` 统一降级(2026-10-12)**:CubeMX 弱定义的这个入口旧形态是 `__disable_irq(); while(1){}`——**单处外设初始化失败即整机挂死**,只剩 IWDG 兜底且不留任何自检日志。现改为打 1 条自检 + `NVIC_SystemReset()`,与 4 个 Fault 处理同款自恢复(IWDG 退回"最后兜底"而非唯一出路;复位归因 `SFTRSTF` → 开机日志 `software (NVIC_SystemReset)`,§4.5)。三条实现约束:
|
||||
|
||||
| 约束 | 原因 |
|
||||
|---|---|
|
||||
| **不得 `__disable_irq()`** | 日志必须能走串口,关中断 = 现场彻底消失 |
|
||||
| **`__builtin_return_address(0)` 不可用** | AC5 前端接受但编成库函数调用,MicroLIB 无该符号 → `L6218E`(2026-10-12 台架实证,勿再尝试);ARMCC `__asm` 只有整函数形态且取不到 C 符号(§10.4)。→ **失败点靠"最后一条成功日志"与 `main()` 的 `MX_*_Init` 顺序之间定位**(GPIO→DMA→USART1→SPI2→SPI1→I2C1→UART4→UART5→USART2→USART3→IWDG→ADC1→TIM3→`app_main_init`) |
|
||||
| **日志路径必须内核前安全** | 调用点全在 `osKernelStart` 之前:控制台写者未注册 → `con_append` 走 `dbg_console_write_raw`(DWT/计数有界轮询,`huart1` 未就绪即返回),`sys_clock_get_str` 未初始化打占位串——全程无内核 API(§4.7 与 `AGENTS.md`「平台约束」同源) |
|
||||
|
||||
成本 = 仅这 1 条日志(≈90 B Flash,见 `AGENTS.md` 日志成本)。重生成存活:函数体在 `USER CODE Error_Handler_Debug` 区(L2,`KeepUserCode` 逐字保留)+ `check_cubemx_survival.py` 审计项兜底(L3)。
|
||||
|
||||
### 4.5 复位原因锁存与优先级
|
||||
|
||||
`RCC_CSR` 的复位标志只由 POR 清除、读后不自动清 → 必须读并锁存后 `SET_BIT(RCC->CSR, RCC_CSR_RMVF)`,否则下次软复位会读回上次残留。
|
||||
@@ -464,7 +474,6 @@ snapshot == required → miss_streak=0、证据门闩复位、喂狗
|
||||
|---|---|---|
|
||||
| **N-17** | `time_sync` 30 s 挂起客户端掉线 + 监听重建期间 NET/FTP/UI 心跳缺口 800 ms~1 s(声明 stall 但未复位),**余量仅 ~0.7 s** | 待定位监听重建为何阻塞其它任务;必要时缩短重试 |
|
||||
| **S-3** | USART1 TX-only 结构根治(灭 ORE 僵尸机制) | 是 R3 节奏饥饿的机制根源 |
|
||||
| **N-4 / C1** | 网络 pending 二期时"看门狗接 `selftest` 留痕" | 二期一并做 |
|
||||
| O1 | 是否需要复位计数与"连续 N 次看门狗复位后进入安全模式" | 当前不做;若现场出现复位风暴再评估 |
|
||||
| O2 | 细粒度复位原因是否上 `run.log`/UI | 倾向不上(避免中文字符集重生成),只保留串口 + `selftest.log` |
|
||||
|
||||
@@ -617,7 +626,7 @@ enter/exit 段还能读出"此刻仍在段内已多久"——**永久阻塞的
|
||||
|---|---|
|
||||
| **提高 uiTask 优先级** | 会**掩盖**"心跳依赖他任务"与"忙等"两个真实缺陷;而且它根本不解决"UI 在等 netTask"。缺陷已修完后,提优先级才成为可讨论项 |
|
||||
| 给 `net_*` 加"有界等待"版 | 回执通道是"每任务一个 32 位通知值",超时后**迟到的回执会被下一次调用的零等待拾取当成新结果**(`net_wait_result` 注释里 L7 挂死/整段错位的同款根因)。要做对必须引入请求序号,代价高于搬家 |
|
||||
| 把推流搬出 uiTask(独立 `uiSinkTask`) | 实测 `uis`=1 µs 而 `uip` 仍 60.9 ms = **LVGL 帧周期地板** → 搬走推流**不会让刷新变快**;收益只剩极端并发下的观感隔离,成本含**必改 `.ioc`** 的重生成与全套回归。若日后成问题,正确方向是先治 netTask 排队公平性(登记簿 N-4 二期),不是搬 UI |
|
||||
| 把推流搬出 uiTask(独立 `uiSinkTask`) | 实测 `uis`=1 µs 而 `uip` 仍 60.9 ms = **LVGL 帧周期地板** → 搬走推流**不会让刷新变快**;收益只剩极端并发下的观感隔离,成本含**必改 `.ioc`** 的重生成与全套回归。若日后成问题,正确方向是先治 netTask 排队公平性(见 `../网络/Net层阻塞模型架构设计.md`),不是搬 UI |
|
||||
| 把推流塞进 netTask | 零往返零新增 RAM,但共享源码要走 backend 端口(双端同改)、netTask 这个唯一执行者更胖、一个 UI 侧 bug 直接变成整机复位 |
|
||||
|
||||
---
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
> [`相量层单元测试说明.md`](相量层单元测试说明.md)(同批落地的 L2 姊妹篇)、
|
||||
> [`../硬件平台/ADC通道映射说明.md`](../硬件平台/ADC通道映射说明.md)(**语义映射权威口径**)、
|
||||
> [`../算法/继电保护功能复现规划.md`](../算法/继电保护功能复现规划.md)(L1-3 / L1-4 设计依据)、
|
||||
> [`../问题记录/错误码传播审计.md`](../问题记录/错误码传播审计.md)(E-44 / E-58 快照语义)
|
||||
> 历史审计 E-44 / E-58(快照语义约定;属主文档已于 2026-10-15 删除,编号仅作指称)
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -42,7 +42,7 @@
|
||||
| 6 | 36 | 4 | 2KB | 40 | 2 | 1KB |
|
||||
| 7 | 42 | 4 | 2KB | 46 | 2 | 1KB |
|
||||
|
||||
UDP 路径 `net_socket()` 中对 Socket 4~7 的兜底重设使用同一布局。该分配已通过 **Phase 7 TC704(8 Socket 并发回显,40/40 PASS)** 验证。
|
||||
UDP 路径 `net_socket()` 中对 Socket 4~7 的兜底重设使用同一布局。该分配已通过 **Phase 7 TC704(5 Socket 并发回显)** 验证。
|
||||
|
||||
### 大文件传输(20KB+)策略
|
||||
|
||||
@@ -853,31 +853,31 @@ sequenceDiagram
|
||||
|
||||
> **实现说明**:TC-NET-703 与 TC-NET-701/702 的 PC 环境互斥(前者要求 PC 服务关闭、后两者要求开启),故固件中 TC-NET-703 由子开关 `PHASE7_TEST_TIMEOUT` 单独启用——默认 `ENABLE_PHASE7_TESTS` 仅跑 701/702;单独开启 `PHASE7_TEST_TIMEOUT` 并关闭 PC 服务后重编,方可执行 703。
|
||||
|
||||
### TC-NET-704: 8-Socket 并发 TCP Client(多 Socket 模式验证)
|
||||
### TC-NET-704: 5-Socket 并发 TCP Client(多 Socket 模式验证)
|
||||
|
||||
| 字段 | 值 |
|
||||
|------|-----|
|
||||
| **ID** | TC-NET-704 |
|
||||
| **优先级** | P0 |
|
||||
| **类型** | 功能测试 / 并发测试(NET 层) |
|
||||
| **标题** | 同时打开 8 个 Socket 连接 PC Server,各自 64B 收发 |
|
||||
| **前置条件** | 1. PC: `python ./test/host/ch395f_socket_test.py tcp_server --port 8081 --max-conn 8`(并发回显,`--max-conn` 为并发计数)<br>2. `net_init()` 已置 `FUN_PARA=0x08`,8 个 Socket 缓冲按「CH395F 缓冲架构」分配(每 Socket 接收 2KB + 发送 1KB,MSS=1024)——**缓冲显式分配是本用例的前提**(Socket 可用性不依赖 FUN_PARA)<br>3. `ENABLE_PHASE7_TESTS` 已定义 |
|
||||
| **标题** | 同时打开 5 个 Socket 连接 PC Server,各自 64B 收发 |
|
||||
| **前置条件** | 1. PC: `python ./test/host/ch395f_socket_test.py tcp_server --port 8081 --max-conn 5`(并发回显,`--max-conn` 为并发计数)<br>2. `net_init()` 已置 `FUN_PARA=0x08`,Socket 缓冲按「CH395F 缓冲架构」分配(每 Socket 接收 2KB + 发送 1KB,MSS=1024)——**缓冲显式分配是本用例的前提**(Socket 可用性不依赖 FUN_PARA)<br>3. `ENABLE_PHASE7_TESTS` 已定义<br>4. `PHASE7_MULTI_COUNT=5`(并发上限 = `NET_MAX_SOCKETS`(8) − 3 常驻监听;2026-10-15 由 8 降至此) |
|
||||
|
||||
**测试步骤与判定标准**:
|
||||
|
||||
| 步 | 操作 | 成功标准 | 失败标准 |
|
||||
|----|------|----------|----------|
|
||||
| 1 | 循环 i=0..7:`net_socket()` 创建 8 个 TCP socket(本地端口 51000+i),`net_connect(192.168.1.2:8081)` | 8 个 `net_connect` 均返回 `0` | 任一返回 `-1` |
|
||||
| 2 | netTask `net_poll()` 推进下,`net_select` 等待全部 8 路可写 | 8 路均在 10s 内 ESTABLISHED | 任一超时未建立 |
|
||||
| 3 | 每路 `net_send(sockfd, 64B)` → `net_recv(sockfd, 64B)` 校验 | 8 路收发各 64B、字节级比对 + 累加和 `TEST_CHECK` 通过 | 任一收发失败 / 数据不符 / `TEST_CHECK` 失败 |
|
||||
| 1 | 循环 i=0..4:`net_socket()` 创建 5 个 TCP socket(本地端口 51000+i),`net_connect(192.168.1.2:8081)` | 5 个 `net_connect` 均返回 `0` | 任一返回 `-1` |
|
||||
| 2 | netTask `net_poll()` 推进下,`net_select` 等待全部 5 路可写 | 5 路均在 10s 内 ESTABLISHED | 任一超时未建立 |
|
||||
| 3 | 每路 `net_send(sockfd, 64B)` → `net_recv(sockfd, 64B)` 校验 | 5 路收发各 64B、字节级比对 + 累加和 `TEST_CHECK` 通过 | 任一收发失败 / 数据不符 / `TEST_CHECK` 失败 |
|
||||
|
||||
**通过标准**:8/8 路全部通过,0 失败。任一失败 → 标记 FAIL
|
||||
**通过标准**:5/5 路全部通过,0 失败。任一失败 → 标记 FAIL
|
||||
|
||||
**覆盖原则**:DP-01(多 Socket 并发主路径)、缓冲架构(8×6 块分配,MSS=1024)
|
||||
|
||||
> **注**:PC 端 `--max-conn` 须为**并发**计数(连接关闭即减),否则 Phase 7 全量(701+702+704 共 12 连接)会按累计计数超限而拒掉 4~7。该用例已随 Phase 7 实测通过(并发回显落在 sock2/4/5/6/7,见 TRAP-NET-15 末)。
|
||||
>
|
||||
> **2026-10-11 复跑(N-31,`FUN_PARA=0x08`)**:**Phase 7 34/34 全通过**,5 路并发 ESTABLISHED + 64 B 回显字节级比对 OK,芯片 Socket 实测落在 **sock2/4/5/6/7**(0/1/3 被 FTP/对时/远显三个监听占用)→ 证明 Socket 可用性不依赖 FUN_PARA。两条**前置排雷**(否则会得到全量假 FAIL):① PC 适配器落在 **Public** 防火墙配置文件会静默丢入站 8081,症状是 TC701/702/704 全部 `CONNECT TIMEOUT`;② 残留的旧 `tcp_server` 进程占着 8081,新服务器绑不上端口不报错。另:`PHASE7_MULTI_COUNT` 须 ≤5(E-23 未修,`NET_MAX_SOCKETS=8` 减去三个常驻监听)。证据链见 `问题记录/CH395F_Trap_Records.md` TRAP-NET-15。
|
||||
> **2026-10-11 复跑(N-31,`FUN_PARA=0x08`)**:**Phase 7 34/34 全通过**,5 路并发 ESTABLISHED + 64 B 回显字节级比对 OK,芯片 Socket 实测落在 **sock2/4/5/6/7**(0/1/3 被 FTP/对时/远显三个监听占用)→ 证明 Socket 可用性不依赖 FUN_PARA。两条**前置排雷**(否则会得到全量假 FAIL):① PC 适配器落在 **Public** 防火墙配置文件会静默丢入站 8081,症状是 TC701/702/704 全部 `CONNECT TIMEOUT`;② 残留的旧 `tcp_server` 进程占着 8081,新服务器绑不上端口不报错。另:`PHASE7_MULTI_COUNT=5`(2026-10-15 由 8 降至此;`NET_MAX_SOCKETS=8` 减去三个常驻监听)。证据链见 `问题记录/CH395F_Trap_Records.md` TRAP-NET-15。
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
> **已完成事项**(S7、A1~A4)的实施细节与证据**不在本文**,见对应模块文档(§10 状态与去向)。
|
||||
> **前置铁律**:本文所有步骤**均在接上 MCU / 串口 / ST-LINK 之后**执行;
|
||||
> 无实机时**只读本文,不执行任何烧录**。
|
||||
> **上游**:`错误码传播审计.md`(E-xx)· `docs/任务规划/README.md`(统一登记簿:P-x / N·S·T-x /
|
||||
> **上游**:`docs/任务规划/README.md`(统一登记簿:P-x / N·S·T-x /
|
||||
> S1x·A-x / 阶段排序 / 诊断基线)·
|
||||
> `子系统设计/看门狗设计说明.md`(§7 验证记录)。
|
||||
> **约定**:本文事项完成后**先销上游登记**,再在文末变更记录留一行;
|
||||
@@ -186,11 +186,11 @@ $cli = if ($env:DTU_STLINK_CLI) { $env:DTU_STLINK_CLI } else { (Get-Command ST-L
|
||||
|
||||
## 6. 步骤 5:GD5F 错误通道统一(P2-A,S9 = 上游 C2) · ✅ 已闭环
|
||||
|
||||
> **2026-10-03 台架结论**:四要素(分类/透传/分级/留痕)+ 返回类型统一 `int32_t` 已落地(E-10/E-42/E-53/E-54/E-56/E-57 全部销项,见 `错误码传播审计.md`)。
|
||||
> **2026-10-03 台架结论**:四要素(分类/透传/分级/留痕)+ 返回类型统一 `int32_t` 已落地(E-10/E-42/E-53/E-54/E-56/E-57 全部销项;历史编号,属主文档已删除)。
|
||||
> 套件回归:`test/run_all_suites.py --suites gd5f` → **`=== GD5F2GQ5UE Tests: 16/16 PASSED (failed=0) ===`**(只读模式,4 个破坏性用例按设计跳过);编排器 `[GD5F] -> PASS`。
|
||||
> **顺带修复(编排器缺陷,非本次代码引入)**:`run_all_suites.py` 原对所有套件统一 `--forbidden "HardFault;assert;[ERR]"`,而 GD5F 的 `TC-GD5F-704`(CCM 非 DMA 可达缓冲)会**预期**打出 `[ERR][NAND] RX DMA buffer not DMA-reachable ... fallback poll`(用例 PASS)→ GD5F 套件**永远被判 FAIL**(自 `2055de0` 起)。按 `verify_log.py` 的说明改为**按套件覆盖 `--forbidden`**(GD5F = `HardFault;assert`),修复后 PASS。
|
||||
|
||||
> **来源**:`错误码传播审计.md` 第二档 #1(E-10/E-42/E-53/E-54/E-56/E-57);
|
||||
> **来源**:第二档 #1(E-10/E-42/E-53/E-54/E-56/E-57,历史编号);
|
||||
> `docs/任务规划/基线与待确认.md` §2.2 四要素骨架(设计基线)。
|
||||
|
||||
**现状证据**:`ch395f.c`(1330 行) 与 `gd5f2gq5ue.c`(1496 行) 是同代驱动,但**只有 CH395F**
|
||||
@@ -419,8 +419,8 @@ CH395F / STORAGE / GD5F,未含 RTC;怀疑 RTC 构建下 `testTask` 不被创
|
||||
| **S7** 自检结果判定 | ✅ 已落地并投用 | `测试说明/自动化测试流程.md`;提交 `4a4cd29` |
|
||||
| **A1** P0-1 `cfg_file` 堆分配改造 | ✅ 已闭环(含真机持久化) | `子系统设计/配置文件设计说明.md`(实施 v1.11 + 2026-10-03 真机验证记录 + 2026-10-04 独立复跑记录) |
|
||||
| **A2** P1-8 网络重建失败恢复 | ✅ 已闭环(正常路径零回归;故障分支见 N-16) | `网络/Net层阻塞模型架构设计.md` |
|
||||
| **A3** E-34 CH395F 字节命令超时 | ✅ 已闭环(正常路径零回归;故障分支待专项窗口) | `问题记录/错误码传播审计.md` E-34 |
|
||||
| **A4** E-04 `remo_send` 返回值 | ✅ 已闭环(正常路径零回归;推流压测待专项窗口) | `问题记录/错误码传播审计.md` E-04 |
|
||||
| **A3** E-34 CH395F 字节命令超时 | ✅ 已闭环(正常路径零回归;故障分支待专项窗口) | —(历史编号,属主文档已于 2026-10-15 删除) |
|
||||
| **A4** E-04 `remo_send` 返回值 | ✅ 已闭环(正常路径零回归;推流压测待专项窗口) | —(历史编号,属主文档已于 2026-10-15 删除) |
|
||||
| 2026-10-02 台架取证链(IWDG PR/RLR 错配 / dhara resume 回滚 / ORE 僵尸通道) | ✅ 已修 | `子系统设计/看门狗设计说明.md` 2026-10-02 变更记录 · `架构设计/STM32F4-Base存储架构说明.md` §5.4.1 · `子系统设计/控制台单写者日志设计说明.md` §12;提交 `930215f` |
|
||||
|
||||
> **真机判定汇总**(2026-10-03,本机 MCU,新固件全闭环 `@test` PASS 7/7):A1 ✅ PASS(含配置持久化);
|
||||
@@ -435,8 +435,8 @@ CH395F / STORAGE / GD5F,未含 RTC;怀疑 RTC 构建下 `testTask` 不被创
|
||||
| S7 自检判定 | —(原复审项,已闭环 2026-10-02) | `测试说明/自动化测试流程.md`(参数已落地,`4a4cd29`) |
|
||||
| V2/V4/V5 | `子系统设计/看门狗设计说明.md` §7 验证记录 | `子系统设计/看门狗设计说明.md` 变更记录(2026-10-03) |
|
||||
| S11 堆告警 | —(原复审项,已闭环 2026-10-03) | `内存管理/RAM使用分析与优化方案.md`(基线更新) |
|
||||
| S9 GD5F | `问题记录/错误码传播审计.md` 第二档 #1 | `问题记录/GD5F2GQ5UE_Trap_Records.md`、`测试说明/GD5F2GQ5UE_Test_Guide.md` |
|
||||
| N-2 日志静默 | `docs/任务规划/登记簿.md` N-2 | `问题记录/错误码传播审计.md` E-02 |
|
||||
| S9 GD5F | —(第二档 #1:历史编号 E-10/E-42/E-53/E-54/E-56/E-57,属主文档已删除) | `问题记录/GD5F2GQ5UE_Trap_Records.md`、`测试说明/GD5F2GQ5UE_Test_Guide.md` |
|
||||
| N-2 日志静默 | `docs/任务规划/登记簿.md` N-2 | `网络/Net层阻塞模型架构设计.md`(E-02 头阻塞,历史编号) |
|
||||
| P1-8 网络重建 | —(原台账项,已闭环 2026-10-02) | `网络/Net层阻塞模型架构设计.md` |
|
||||
| S5/S4 | —(原复审项,已闭环 2026-10-03) | `测试说明/测试开发标准流程.md` |
|
||||
| 模拟器差距 | `测试说明/模拟器差距清单.md` §3 决策规则 | 本文为"需回真机"项的执行面 |
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
> [`卷锁单元测试说明.md`](卷锁单元测试说明.md)(同批落地的姊妹篇)、
|
||||
> [`../子系统设计/看门狗设计说明.md`](../子系统设计/看门狗设计说明.md)(`required_mask` / 抽样窗 / 长耗时白名单)、
|
||||
> [`../任务规划/README.md`](../任务规划/README.md)(**N-17** 登记条目)、
|
||||
> [`../问题记录/错误码传播审计.md`](../问题记录/错误码传播审计.md)(**E-02** 头阻塞)
|
||||
> 历史审计 **E-02**(netTask 头阻塞;属主文档已于 2026-10-15 删除,现状见 [`../网络/Net层阻塞模型架构设计.md`](../网络/Net层阻塞模型架构设计.md))
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
> **用途**:把散落在各子系统文档里的"模拟器无法建模 X"汇成**单一事实源**,回答一个关键问题——
|
||||
> **模拟器回归通过 ≠ 真机通过,那么差在哪?差多少?哪些必须真机补测?**
|
||||
> **性质**:**登记册**(living document)。新增模拟器后端差异时必须在此登记一行,不得只写在别处。
|
||||
> **上游依据**:`docs/任务规划/基线与待确认.md` §2.1(N-4 门禁)。
|
||||
> **上游依据**:`docs/任务规划/基线与待确认.md` §2.1(net 层 pending 化状态)。
|
||||
> **相关**:`UI设计/LVGL模拟器部署与使用说明.md`(部署与使用)、`simulator/README.md`(目录与架构)、
|
||||
> `测试说明/测试开发标准流程.md`(L3 门禁在测试分层中的位置)。
|
||||
|
||||
@@ -40,7 +40,7 @@
|
||||
|
||||
| # | 差距 | 模拟器行为 | 真机行为 | 影响 | 回归补测 |
|
||||
|---|---|---|---|---|---|
|
||||
| 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(ACCEPT pending 化)专门建模 |
|
||||
| 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 套件;ACCEPT 决定不 pending 化(2026-10-15),不再专门建模 |
|
||||
| N-2 | **代次号恒为 0** | `net_get_generation()` 恒返 0(无"网络重建"概念) | 每次 `net_stack_bring_up` / 重配置递增,各 TCP 服务据此重建监听 | "网络重建后服务是否重建监听" 的逻辑**在模拟器上恒走同一分支** | `@test` 网络重配置用例(UI 改 IP 免重启生效) |
|
||||
| N-3 | ~~`net_recv_to` 缺失~~(**已消除**:sim 以 `GetTickCount64` + `Sleep(1)` 轮询兑现预算,含 -2 返回码与 `timeout_ms=0` 拒 INVAL);`net_process_messages` 仍缺失 | `net_recv_to` 已实现(包装层模拟);消息泵未实现(MCU 专属:CH395F 消息队列驱动) | 由 `netMsgQueue` 串行化 SPI 事务、支持毫秒级超时接收 | 依赖"消息泵"的上层逻辑在模拟器上**不可编译/不可运行**;带超时接收的**外部语义**已可双端共测,但预算兑现精度为 Sleep(1) 粒度 | 板端 CH395F / NET 套件 |
|
||||
| N-4 | **Socket 失效语义不同** | 以 `in_use` 判活(`net_socket_sim.c` 设计要点 4) | 监听 Socket 随客户端一同失效,由 net 层 `auto_relisten` + 对账形态③④自动重建(无手动 `net_relisten`) | "客户端断线 → 监听失效 → 重连" 的黏滞状态在模拟器上不出现 | `check_remo_sink.py` 覆盖重连;真机 `@test` |
|
||||
@@ -101,7 +101,7 @@
|
||||
- **何时登记**:新增/修改 `simulator/sim/` 下任何后端、或发现"某逻辑模拟器走了不同分支"时,**必须**在 §2 加一行。
|
||||
- **格式**:沿用本表列(差距 / 模拟器行为 / 真机行为 / 影响 / 回归补测)。
|
||||
- **联动**:若该差距影响 L3 门禁的可信度,须同步在 `UI设计/UI_自动化测试流程.md` 引用本清单。
|
||||
- **收敛**:当某差距被 N-4 之类的工作**消除**时,不删行——改标 ~~删除线~~ + 注明消除日期与提交,保留"曾经差在哪"的历史。
|
||||
- **收敛**:当某差距被后续工作**消除**时,不删行——改标 ~~删除线~~ + 注明消除日期与提交,保留"曾经差在哪"的历史。
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -625,7 +625,7 @@ sock4 auto-relisten ok / relisten retry ok ← 监听器随后自行恢复
|
||||
维护注意:队列中长 SEND/CLOSE 消息处理期间,pending 完成顺延至下轮 tick(~1ms 级;长 SEND
|
||||
stall 期间最多顺延相应时长)——已知代价,勿"优化"回执行器内等待。
|
||||
|
||||
### 8.4 相关既有缺陷(会掩盖/放大延迟,见 `docs/问题记录/错误码传播审计.md`)
|
||||
### 8.4 相关既有缺陷(会掩盖/放大延迟;编号为历史审计编号,属主文档已删除,仅作指称)
|
||||
|
||||
| 编号 | 位置 | 与延迟的关系 |
|
||||
|---|---|---|
|
||||
@@ -766,7 +766,6 @@ sock4 auto-relisten ok / relisten retry ok ← 监听器随后自行恢复
|
||||
| UI 设计架构(离屏渲染 + 推流) | `docs/UI设计/UI_设计架构.md` |
|
||||
| BSD Socket API 与双端后端 | `docs/网络/BSD_Socket_API_使用指南.md` |
|
||||
| CH395F 陷阱史(TRAP-NET-09/-16 等) | `docs/问题记录/CH395F_Trap_Records.md` |
|
||||
| 错误码传播审计(E-02 / E-04 / E-33 / E-34) | `docs/问题记录/错误码传播审计.md` |
|
||||
| CH395F 测试套件(吞吐 Phase 8 等) | `docs/测试说明/CH395F_Test_Guide.md` |
|
||||
| RAM 预算(`ui_net_sink` 6.4KB 常驻) | `docs/内存管理/RAM使用分析与优化方案.md` |
|
||||
| 串口助手(抓日志排查) | `docs/测试说明/串口助手使用指南.md` |
|
||||
|
||||
+20
-3
@@ -53,7 +53,7 @@
|
||||
| **P-2** | **编号不携带语义**:严重度、状态、日期、负责人、波次一律是表格列 | 降级只改列,编号永不变、引用永不断(`P1-x` 的历史教训) |
|
||||
| **P-3** | **一个前缀只有一个属主登记处**;前缀一经分配**永不复用给别类**,号段用尽即扩位(`N-99`→`N-100`),绝不换字母 | 保证"看到前缀就知道去哪张表查" |
|
||||
| **P-4** | **形态唯一**:`<前缀>-<序号>`;前缀 1~3 位大写字母;序号位数按类别固定并左补零;子项只允许一级 `-<小写字母>`。**禁止**裸形(`S3`)、空格形(`Trap 07`)、中文形(`陷阱 1`)、圈号(`①②③④`) | 连字符与补零不得承载语义;字面唯一才能被机器判定 |
|
||||
| **P-5** | **只增不复用**;每个类别有「下一个可用号」游标(`[计划] scripts/id_registry.json`),新增先取游标 | 并行任务与多文档同时新增时防撞号(`docs/问题记录/项目审查与优化建议报告.md` 变更记录自述"并轨时未做全局唯一性检查"就是没有游标) |
|
||||
| **P-5** | **只增不复用**;每个类别有「下一个可用号」游标(`[计划] scripts/id_registry.json`),新增先取游标 | 并行任务与多文档同时新增时防撞号(《项目审查与优化建议报告》与登记簿并轨时 `N-16` 撞过号,就是没有游标——见 `docs/任务规划/README.md` §0) |
|
||||
| **P-6** | **引用必须机器可判定**:跨文档引用用行内代码,首次出现紧邻属主文档名;文档内编号**必须**带文档名 | 与 `§N.M` 同一条路:能校验的约定才算存在 |
|
||||
| **P-7** | **编号不语义,引用必语义**:编号本体保持无语义并冻结(同 P-2);但**正文引用必须带语义括注**——`TRAP-NET-18(异常释放后排空 RX 残渣)`、`docs/网络/网络自愈架构设计.md` §4.6(应用主动拆会话保监听);**禁止裸 ID 单独承担信息**。语义放括注,事实变了只改括注、编号不变 | 读者不该为看懂一句话去跳三篇文档。可读性由**引用方式**解决,不由**编号命名**解决——命名带语义会重蹈 `P1-x` 覆辙(§1.2)。落地见 §5.6 |
|
||||
|
||||
@@ -92,7 +92,7 @@
|
||||
| `FR-[A-Z0-9]+-\d{2}` | 功能需求 | `docs/产品需求/产品需求设计文档.md` §5 | 各域独立递增;**新增域写进该文 §1.2 术语与缩写** |
|
||||
| `NFR-[A-Z0-9]+-\d{2}` | 非功能需求(**新建**,现 §7 全是散文无号) | `docs/产品需求/产品需求设计文档.md` §7 | 从 `NFR-<域>-01` 起 |
|
||||
| `N-\d{2}` | **登记簿条目**(技术债 / 长期观察 / 硬件改版项;含义由"网络项"重定义) | `docs/任务规划/登记簿.md` | **曾用**最大 `N-33`(`N-30`~`N-33` 均已销项、登记簿行已删,**现存至 `N-29`**)→ 游标 `N-34`(号不回收);原 `S-x`/`T-x` 并入本族(§7.1) |
|
||||
| `E-\d{2}` | 错误码/返回值传播审计发现 | `docs/问题记录/错误码传播审计.md` | **冻结**:`E-63` 为最大号,**不再新增**;新发现一律 `DEF` |
|
||||
| `E-\d{2}` | 错误码/返回值传播审计发现 | 无(原属主 `docs/问题记录/错误码传播审计.md` 已于 2026-10-15 删除) | **冻结**:`E-63` 为最大号,**不再新增**;新发现一律 `DEF`;现存引用仅作历史指称(§4.3) |
|
||||
| `E\d+` | **自愈实验编号**(N34 台架实验,**无连字符**) | `docs/网络/网络自愈架构设计.md` §5.2 | **已封闭**:`E0`~`E15`,**不再新增**;原始实验记录已归档(该文档 §12)。⚠ 与上一行靠**连字符**区分:带连字符 = 审计发现 |
|
||||
| `TC-[A-Z]{1,4}-\d{3,4}` | 测试用例 | 各测试文档 | 3 位起;分阶段套件序号 = 阶段号×100 + 项号(阶段 ≥10 自然进位 4 位,`TC-NET-1001` 合规);后缀只允许 `-<小写字母>` |
|
||||
| `TM-[A-Z]{1,4}-\d{2}` | 测试阶段 | 各测试文档 | 模块码取 §6 统一表(`TM-PHY-01` → `TM-NET-01`) |
|
||||
@@ -118,12 +118,29 @@
|
||||
| `RUN-<yyyymmdd>-<n>` | 台架轮次 | `round 1~9` | `docs/测试说明/实机测试实施指南.md` | 日期制 |
|
||||
| `MS-<nn>` | 里程碑 | `M1~M3` | 波次文件 | `MS-01` |
|
||||
| `RC-<nn>` | net 周期对账类型 | `①②③④⑤`(唯一被代码逻辑引用的圈号链) | `docs/网络/网络自愈架构设计.md` | `RC-01`~`RC-05` |
|
||||
| `PAT-<nn>` | 缺陷模式(九类) | `docs/问题记录/错误码传播审计.md` §1.1 的 `P1~P9` | 同文 | `PAT-01`~`PAT-09` |
|
||||
| `PAT-<nn>` | 缺陷模式(九类) | 原 `docs/问题记录/错误码传播审计.md` §1.1 的 `P1~P9`(该文档已删除,定义迁至本文档 §4.2.1) | 本文档 §4.2.1 | `PAT-01`~`PAT-09` |
|
||||
| `ST-<n>` | 专项内部实施阶段(**文档内编号**) | 保护规划 §7.1 的 `P0~P5`、方案阶段 `P0~P3` | 各专项文档 | 各文档自 `ST-0` |
|
||||
| `UL-<n>` | UI 标准化四层(**文档内编号**) | 报告 UI 四层 `L0~L3` | `docs/UI设计/UI_设计架构.md` | `UL-0` |
|
||||
| `LAT-<nn>` | 链路延迟分段(**文档内编号**) | `docs/测试说明/链路延迟测试说明.md` 的 `L1~L11` | 同文 | `LAT-01` |
|
||||
| `CS-<n>` | CubeMX 定制存活三层 | `AGENTS.md` 的 `L1 写进 .ioc → L2 USER CODE → L3 审计` | `docs/子系统设计/看门狗设计说明.md` §10 | `CS-1`~`CS-3` |
|
||||
|
||||
#### 4.2.1 缺陷模式定义(`PAT-01`~`PAT-09`)
|
||||
|
||||
2026-10-15 由已删除的 `docs/问题记录/错误码传播审计.md` §1.1 迁入(原编号 `P1`~`P9`,与发现编号 `E-xx` 区分)。
|
||||
新发现归入 `DEF-<nnn>` 时,"缺陷模式"列仍按本表取值:
|
||||
|
||||
| 模式 | 名字 | 一句话 | 典型症状 |
|
||||
|---|---|---|---|
|
||||
| **PAT-01** | 值拷贝队列陷阱 | 消息体按值拷进队列,netTask 修改的是**副本**,调用方看不到 | 回传字段恒为初始值 |
|
||||
| **PAT-02** | 共享全局错误变量竞态 | 全局 `errno` 被多任务交错覆写 | 报出别人的错误码 |
|
||||
| **PAT-03** | 返回值与错误码混同 | "0 = 成功"其实是"命令已发出";成功路径不清 errno | 失败被当成功 |
|
||||
| **PAT-04** | 返回值未检查 | `HAL_*` / 库函数返回被丢弃 | 失败静默继续 |
|
||||
| **PAT-05** | 事件标志语义 | 状态位被当作命令位消费掉 | 等待者永不唤醒 |
|
||||
| **PAT-06** | 通知值宽度与符号 | 32 位通知值装不下 / 符号位被当成数据 | 大长度变负数 |
|
||||
| **PAT-07** | ISR 与跨上下文共享状态 | ISR 写、任务读,无同步 | 读到半包 / 撕裂 |
|
||||
| **PAT-08** | 外设 / 库特定约定 | 该外设 / 该移植版特有的规则 | 照抄上游示例即错 |
|
||||
| **PAT-09** | 超时与错误混同 | 超时用同一个码表达,调用方无法区分 | 无法复位 / 无法重试 |
|
||||
|
||||
### 4.3 冻结前缀(历史快照,正文不回改)
|
||||
|
||||
| 冻结对象 | 处置 |
|
||||
|
||||
@@ -440,6 +440,9 @@ void tcp_client(void)
|
||||
|
||||
## 6. UDP 编程
|
||||
|
||||
> **本项目不使用 UDP(2026-10-15 定案)**:UDP API 保留为 BSD socket 完整性,仅**单任务独占期**可用
|
||||
> (`net_sendto` / `net_recvfrom` 直碰 SPI、不经队列,见 §2 三例外);本平台无 UDP 消费者。
|
||||
|
||||
### 6.1 UDP Client
|
||||
|
||||
```c
|
||||
|
||||
@@ -449,7 +449,6 @@ sequenceDiagram
|
||||
- `docs/网络/网络自愈架构设计.md` —— **监听生命周期权威设计**(边沿→电平、单一所有者重建 = `net_reconcile_tick` 形态③④、`net_listener.c` / `net_events.c` 模块化边界 §11)
|
||||
- `docs/问题记录/CH395F_Trap_Records.md` —— TRAP-NET-01~23 机制细节(本文引用处)
|
||||
- `docs/网络/Net层阻塞模型架构设计.md` —— 阻塞等待模型的现状架构设计(pending 请求模型 / 五路完成语义)
|
||||
- `docs/问题记录/错误码传播审计.md` —— E-02 头阻塞与错误码回传全审计
|
||||
- `docs/测试说明/链路延迟测试说明.md` —— 芯片 / 队列 / 挂起 recv 等分段时延基线与自愈路径的台架证据
|
||||
- `docs/子系统设计/网络配置说明.md` §4 —— 代次号与网络重建时序
|
||||
- `docs/测试说明/CH395F_Test_Guide.md` —— 单连接模型测试规则(TC-NET-6xx)
|
||||
|
||||
@@ -10,7 +10,6 @@
|
||||
> `docs/网络/BSD_Socket_API_函数调用关系.md`(调用链与执行域)、
|
||||
> `docs/网络/网络自愈架构设计.md`(周期对账与监听生命周期——与本模型的分工见 §2.4;模块化边界见该文档 §11)、
|
||||
> `docs/测试说明/链路延迟测试说明.md`(延迟基线与故障对照)、
|
||||
> `docs/问题记录/错误码传播审计.md`(E-02 队头阻塞审计)、
|
||||
> `docs/任务规划/基线与待确认.md` §2.1(ACCEPT 挂起化设计基线)
|
||||
|
||||
## 目录
|
||||
@@ -53,7 +52,7 @@ netTask 是**全部 socket 操作的唯一执行者**——CH395F 的 SPI 总线
|
||||
| B 有界分片轮询(`net_recv_to` 分片) | ≤ `timeout_ms` | 分片间隙可用 | ⚠️ 止血:仍周期性占用,调用方须自管总预算 |
|
||||
| C **挂起登记(本模型)** | 微秒级(登记一次) | 照常服务整个队列 | ✅ 结构性消灭 |
|
||||
|
||||
三条路线的量化对照见 `docs/问题记录/错误码传播审计.md` E-02。本模型选 C;路线 B 的入口
|
||||
三条路线的量化对照见历史审计 E-02(头阻塞;属主文档已于 2026-10-15 删除,编号仅作指称)。本模型选 C;路线 B 的入口
|
||||
`net_recv_to` **仍在 API 面上**,定位是**调用方显式预算**(§6.2、§8),与挂起登记互补。
|
||||
|
||||
> **send 是同一问题的第二个面**:`net_send` 写入 CH395F 发送 FIFO 后要等 `send_ready`
|
||||
@@ -636,9 +635,9 @@ net_pending_capture_owner() ← 捕获执行者
|
||||
| 项 | 现状 | 说明 |
|
||||
|---|---|---|
|
||||
| **SEND 路径**(执行者占用问题)✅ **已纳入本模型** | `net_send_locked` 快路径有界自旋 ≤ `NET_SEND_SPIN_MS`(2 ms);超预算登记挂起 send,由 `net_send_pending_tick` 按主循环节拍分块推进(`NET_SEND_CHUNK_MAX` = 1 KB/块),调用方在自己上下文睡 | 停滞期 netTask **不再冻结**:挂起 send 每轮至多写一块,`net_pending_tick` 与消息队列照常推进。健康链路块间等待 med 219 µs ≪ 2 ms,快路径行为不变。`NET_SEND_TIMEOUT_MS` 是**无进展**超时(每次成功写块刷新,见 §5.5) |
|
||||
| **ACCEPT 路径未纳入**(调用方轮询问题) | `net_accept_locked` 单次 `net_poll` 后**立即**返回 `ESTABLISHED` 或 `WOULDBLOCK`——**不占用 netTask**(0 停滞) | 代价不在执行者,而在**调用方轮询**:没有"阻塞到有连接"的入口,各服务(`ui_net_sink` / `iec104_serv` 100 ms / `time_sync` / `lftpd`)各自手写轮询循环,每轮一次完整 RPC 往返(入队 + 通知 + 唤醒),并带来一个轮询周期级的 accept 延迟抖动。pending 化的收益是**消除轮询 churn 与抖动**,不是解队头阻塞 |
|
||||
| **ACCEPT 路径决定不纳入**(调用方轮询问题;2026-10-15 决策) | `net_accept_locked` 单次 `net_poll` 后**立即**返回 `ESTABLISHED` 或 `WOULDBLOCK`——**不占用 netTask**(0 停滞) | 代价不在执行者,而在**调用方轮询**:没有"阻塞到有连接"的入口,各服务(`ui_net_sink` / `iec104_serv` 100 ms / `time_sync` / `lftpd`)各自手写轮询循环,每轮一次完整 RPC 往返(入队 + 通知 + 唤醒),并带来一个轮询周期级的 accept 延迟抖动。pending 化的收益是**消除轮询 churn 与抖动**,不是解队头阻塞 |
|
||||
| **超时精度** | 随主循环节拍(~1ms),被长操作占用时顺延 | 文档化、不修;发送停滞不再顺延整层(send 已在模型内),顺延面只剩单次长操作本身 |
|
||||
| **挂起超时留痕探针** | 编译期选项 `NET_PENDING_TRIPWIRE` 默认关(排查挂死时开);未接自检 selftest | 待办见 `docs/任务规划/登记簿.md` N-4 |
|
||||
| **挂起超时留痕探针** | 编译期选项 `NET_PENDING_TRIPWIRE` 默认关(排查挂死时开);未接自检 selftest | 可选改进,随窗口(无排期) |
|
||||
| **模拟器不可建模** | `net_socket_sim.c` 单线程 Winsock 无法复现**挂起模型内部机制**(外部语义已由包装层按 blocking 属性/预算模拟) | 挂起表 / tick / 通知路径在模拟器上零覆盖,只能硬件验证(§7.4) |
|
||||
| **单 fd 单挂起** | 每 fd 至多一个挂起 recv,第二个被 `BUSY` 拒绝 | 由登记守卫保证;同 fd 并发 recv 本就无意义(per-fd 串行语义) |
|
||||
|
||||
@@ -648,8 +647,7 @@ net_pending_capture_owner() ← 捕获执行者
|
||||
> (§5.5、§7.1 send 组);
|
||||
> - ACCEPT 是**调用方轮询**问题:执行者本就零占用,"accept 慢"来自调用方轮询周期,
|
||||
> 不是 netTask 卡住——pending 化换的是 RPC 开销与延迟抖动,**不解决任何队头阻塞**。
|
||||
> 故 ACCEPT 优先级低于 SEND,**尚未落地**(登记项见 `docs/任务规划/登记簿.md` N-4,
|
||||
> 设计基线见 `docs/任务规划/基线与待确认.md` §2.1)。
|
||||
> 故 ACCEPT 优先级低于 SEND,**决定不挂起化(2026-10-15)**——保留调用方轮询。
|
||||
|
||||
---
|
||||
|
||||
|
||||
+5
-4
@@ -29,9 +29,10 @@
|
||||
|
||||
> ⚠ **字母 `E` 有两套编号,靠连字符区分**:
|
||||
> - `E0`~`E19`(**无**连字符)= 本文的**自愈实验**编号,逐条见 §5.2;
|
||||
> - `E-02`(**带**连字符)= `docs/问题记录/错误码传播审计.md` 的**审计发现**编号——
|
||||
> - `E-02`(**带**连字符)= **历史审计发现**编号(属主文档已于 2026-10-15 删除,
|
||||
> 编号冻结于 `docs/编号规范.md` §4.3)——
|
||||
> §5.2 末行引用它是为了记录该发现的**收口台架**,**不是**实验编号
|
||||
> (证据:`test/host/e02_probe.py` 文档串自述"错误码传播审计.md E-02 的 timeSync 触发形态");
|
||||
> (证据:`test/host/e02_probe.py` 文档串自述"历史审计 E-02 的 timeSync 触发形态");
|
||||
> - 该审计编号族冻结于 `E-63`,不再新增。
|
||||
|
||||
## 1. 为什么是这个架构
|
||||
@@ -585,8 +586,8 @@ DISCONNECT 会被 `(void)` 丢掉。但 RECV_OK 是条件位(下轮补回)
|
||||
> ⚠ **这些编号是冻结标识**:`net_socket.c` / `net_events.c` / `net_listener.c` 注释、
|
||||
> `test/host/e02_probe.py`、`test/host/e6_soak.py`、`docs/问题记录/CH395F_Trap_Records.md`
|
||||
> 都直接引用它们,**重排或改名会断链**。
|
||||
> ⚠ 末行 `E-02` **不是实验编号**——它是 `docs/问题记录/错误码传播审计.md` 的**审计发现**编号
|
||||
> (`E-<nn>` 族,冻结于 `E-63`),列在此处只为记录该发现的**收口台架**。
|
||||
> ⚠ 末行 `E-02` **不是实验编号**——它是**历史审计发现**编号
|
||||
> (`E-<nn>` 族,属主文档已于 2026-10-15 删除,冻结于 `E-63`),列在此处只为记录该发现的**收口台架**。
|
||||
> 区分规则:**带连字符 = 审计发现,无连字符 = 自愈实验**。
|
||||
|
||||
| 编号 | 验证了什么(方法) | 结论(现状口径) | 落点 |
|
||||
|
||||
@@ -285,7 +285,7 @@ CH395F 以太网驱动与 NET 层的实证陷阱:现象、定案根因、修
|
||||
- **能真正掐断链路的手段**:`Disable-NetAdapter`(链路真 down)。⚠ 该 cmdlet **只有 `-Name`/`-InterfaceDescription`**,没有 `-InterfaceIndex`;网卡名是中文,用 `(Get-NetAdapter -InterfaceIndex N).Name` 取值再传入;禁用/恢复必须写在 `try/finally` 里。
|
||||
- **仍未覆盖的场景**:"链路仍在、对端静默"(NAT 会话过期、中间节点黑洞)没有安全注入手段(静态 ARP 黑洞被交换机泛洪兜底、删 IP 连带拆掉本机连接)——E11 用禁用网卡的近似注入完成定案。
|
||||
- **主机侧回显服务器收不到入站连接 → 全量 `CONNECT TIMEOUT`**:本机对 `C:\programdata\anaconda3\python.exe` 有 Public 入站 Block 规则(`C:\python314\python.exe` 才是 Allow),而 `.venv\Scripts\python.exe` 的基座解释器正是 Anaconda python。Windows 防火墙**块规则优先于放行规则** → 中途加 Allow 规则**完全无效**,只有 `Set-NetFirewallProfile -Name Public -Enabled False` 才通。症状极具误导性:芯片 ~1.6s `CONNECT TIMEOUT`、`net_connect` 仍返 0、`[CONN] openOK` 照常打印,看着像芯片故障,实为主机防火墙。固定跑法:`try { 关 Public → 复跑 } finally { 开 Public }`。
|
||||
- **Phase 7 两条既有失败与改动无关,别追**:① TC704 `socket create #5` FAIL = E-23(`NET_MAX_SOCKETS=8` 减 3 常驻监听 → 并发上限 5,而 `PHASE7_MULTI_COUNT` 仍是 8);② TC703 要求 PC 服务器**离线**,与 701/702/704 环境互斥,同轮连跑必有一侧失真。
|
||||
- **Phase 7 两条既有失败与改动无关,别追**:① TC704 `socket create #5` FAIL = 并发上限 5(`NET_MAX_SOCKETS=8` 减 3 常驻监听)而 `PHASE7_MULTI_COUNT` 曾是 8(该配置已于 2026-10-15 降为 5);② TC703 要求 PC 服务器**离线**,与 701/702/704 环境互斥,同轮连跑必有一侧失真。
|
||||
- **对照组必须从干净态起测**:上一腿若**没死透**就重启下一腿,对照组失真。每个样本前 `stlink_flash.py reset` + 等 12s 干净启动,并取多样本再比均值。
|
||||
- **`[PROF]`/`[PROF2]` 字段不是计数器,别拿来判"任务卡死"**:`netp` = `net_poll` 段最长耗时(µs)、`netn` = 采样瞬间在段内时长(`App/util/task_prof.c`)→ 数值恒定只说明"没刷新最大值"。真正的停摆信号是 `[ERR][WD] task stall`;其 `miss=` 打印的是**累计**数(连续数封顶在容忍值 8),容忍 = 8 轮×100ms = 连续 800ms 有任务缺席即停喂、IWDG 2.5s 溢出(`App/util/task_watchdog.c`)。缺席位图解码:`req=0x77` 为 DEFAULT/NET/FTP/UI/TIMESYNC/ADC,`mask=0x41` → 缺席 NET+FTP+UI+TIMESYNC = "netTask 卡住、所有做 `net_*` 的任务阻塞在队列+通知后面"的指纹。
|
||||
- **静默黑洞用临时探针抓状态,测完即删**:B10 的孤儿态在日志里毫无痕迹,靠对账跳过分支加一条 `TEMP orphan …` 才直接看到;同一轮还顺手用探针**否掉了自己的第一假设**。假设写盘前先测,比推理便宜。
|
||||
|
||||
@@ -1,634 +0,0 @@
|
||||
# 错误码传播审计报告(全项目)
|
||||
|
||||
> **模块名称**:全项目错误码 / 返回值 / 状态传播审计
|
||||
> **文档目的**:以 2026-09-21 网络错误码事故(errno 被并发覆写 → 远端显示误判断连)为起点,
|
||||
> 普查全项目的"错误信息传递"链路:哪些机制会把**成功**报给调用方而实际已失败、哪些通道会让
|
||||
> 错误码**丢失 / 串扰 / 永远到不了**,并按 P0/P1/P2 排出修复优先级。
|
||||
> **本文档只读审计,不修改任何代码。**
|
||||
>
|
||||
> **首版**:2026-09-21(发现 59 项)
|
||||
> **本版**:2026-09-25 重写 —— ① 已闭环项从正文移除,只在 §2 留一行索引;② 全部未闭环项
|
||||
> **逐项回到当前代码复核**;③ 新增本轮复核发现。
|
||||
> **代码基线**:`v2-on-ui` @ `9a8255f`(2026-09-24),复核日期 2026-09-25
|
||||
> **配套文档**:`docs/任务规划/README.md`(N-2/N-4 登记项)、`docs/网络/Net层阻塞模型架构设计.md`(E-02 架构现状)、
|
||||
> `docs/问题记录/*_Trap_Records.md`(模块陷阱史)、`AGENTS.md`(已固化铁律)
|
||||
|
||||
---
|
||||
|
||||
## 0. 结论速览
|
||||
|
||||
**当前未闭环 16 项:P1×1、P2×15。无 P0。**
|
||||
|
||||
> **2026-10-10 追记(E-59 门禁的 TPAFE 前置项全部闭环)**:**E-44 / E-45 / E-58** 已修复并经真机验证
|
||||
> (`tpafe5160` 驱动:FRSTDATA 数据有效性校验 + 帧序号取代就绪电平标志 + 原子快照 API;
|
||||
> 旧的 `get_buf`/`data_ready`/`clear_ready` **删除**,全仓库零调用者)。未闭环 17 → **16**(P1 2→1),
|
||||
> 已闭环索引 41 → **44**(§2.2)。门禁本身已固化进 `AGENTS.md`;**E-59 仍未闭环**(消费者仍是空桩,
|
||||
> 且 RS485 侧 E-50 / E-49 未修、两任务栈预算未做)。
|
||||
|
||||
> **2026-10-04 订正(计数同步)**:2026-10-03 的 **E-34 / E-04**(第一档)与
|
||||
> **GD5F 错误通道统一(E-10 / E-42 / E-53 / E-56 / E-57,第二档 #1)** 已修复并台架验证,
|
||||
> 加上 **E-60**(2026-09-21 订正),未闭环数由 25 降为 **17**(P1 5→2、P2 20→15);
|
||||
> 已闭环索引同步为 **41** 项(§2)。本次只订正计数与索引,审计结论未变。
|
||||
|
||||
> **2026-10-02 追记(L0.5 单测新发现,已修复)**:**E-63(P0)** ——
|
||||
> `App/cfg/cfg_file.c` 外科手术保存的 3 处 `s_encode(...) == 0` 判定恒假
|
||||
> (该函数成功返回**文本长度**而非 0)→ **受管值改写路径沦为死码**:
|
||||
> 对已存在的 `/config.ini` 保存时受管键**从不被改写**(静默不落盘),
|
||||
> 而 `net_cfg_save()` 仍返回 0 并打 `save: OK`。由本日新增的 `cfg_file`
|
||||
> 主机侧单测(S1-b)首跑抓出,已修复并通过 `@build` 0/0。**已闭环**,
|
||||
> 明细见 §2.1。
|
||||
|
||||
首版 59 项中 **44 项已闭环**(索引见 §2),其中 **4 项 P0 全部修复并在位**;**16 项未闭环**
|
||||
(见 §3),另 **1 项回归监督**(E-62,无需改动、仅防后人误改)。剩余问题分三类:
|
||||
|
||||
| 类别 | 数量 | 性质 | 处置 |
|
||||
|---|---|---|---|
|
||||
| **A. 待处理的实质缺陷** | 4 | 有明确后果,需改代码 | §3.1,第一 / 二档 |
|
||||
| **B. 契约缺口(随消费者接入触发)** | 7 | 当前调用者"恰好不会踩",但契约没写死 | §3.2,接消费者前必修 |
|
||||
| **C. 一致性 / 可维护性** | 5 | 无功能影响或影响极小 | §3.3,第三档 |
|
||||
|
||||
**最值得先动的两件事**(2026-10-10 更新——原列的 **E-58 已闭环**,**E-34 / E-04 已闭环**,见 §2.2):
|
||||
|
||||
1. **E-59(P1,元发现)**——`rs485_task` 仍为空桩(`adc_task` 已实现,B1 2026-10-10)。TPAFE 侧契约缺陷
|
||||
(**E-44 / E-45 / E-58**)已于 2026-10-10 **全部修复**,RS485 侧 **E-50 / E-49 仍未修**;
|
||||
门禁已固化进 `AGENTS.md`,接消费者前仍欠"栈预算 + RS485 双缓冲/序号"。
|
||||
2. **E-50(P2)**——RS485 单缓冲无 ISR/任务同步 → 读出跨两帧拼接的数据;与 E-59 同族,
|
||||
属"接 RS485 消费者前必修"(§5 第三档前置条件)。
|
||||
|
||||
> **2026-09-25 变更**:**E-03 已修复**(错误码改按任务隔离,见 §3.1)。
|
||||
> 它是本次审计中唯一"并发条件下会说谎"的通道,且 N-4(SEND/ACCEPT pending 化)不覆盖它,故独立小修先行。
|
||||
>
|
||||
> **2026-10-03 变更**:**E-34 / E-04 已修复并通过真机验证**(CH395F 字节命令有限超时 + `remo_send` 返回值校验;见 §5 第一档)。
|
||||
> **2026-10-03 变更②**:**GD5F 错误通道统一(E-10 / E-42 / E-53 / E-54 / E-56 / E-57)已修复并通过台架套件回归**(`=== GD5F2GQ5UE Tests: 16/16 PASSED (failed=0) ===`,只读模式;见 §5 第二档 #1)。
|
||||
> 真机全闭环 `@test` PASS 7/7;执行判据见 `docs/测试说明/实机测试实施指南.md` §3 / §10。
|
||||
|
||||
---
|
||||
|
||||
## 1. 审计方法与口径
|
||||
|
||||
### 1.1 九类缺陷模式
|
||||
|
||||
所有发现按这九类归类,编号 P1~P9(与发现编号 E-xx 区分):
|
||||
|
||||
| 模式 | 名字 | 一句话 | 典型症状 |
|
||||
|---|---|---|---|
|
||||
| **P1** | 值拷贝队列陷阱 | 消息体按值拷进队列,netTask 修改的是**副本**,调用方看不到 | 回传字段恒为初始值 |
|
||||
| **P2** | 共享全局错误变量竞态 | 全局 `errno` 被多任务交错覆写 | 报出别人的错误码 |
|
||||
| **P3** | 返回值与错误码混同 | "0 = 成功"其实是"命令已发出";成功路径不清 errno | 失败被当成功 |
|
||||
| **P4** | 返回值未检查 | `HAL_*` / 库函数返回被丢弃 | 失败静默继续 |
|
||||
| **P5** | 事件标志语义 | 状态位被当作命令位消费掉 | 等待者永不唤醒 |
|
||||
| **P6** | 通知值宽度与符号 | 32 位通知值装不下 / 符号位被当成数据 | 大长度变负数 |
|
||||
| **P7** | ISR 与跨上下文共享状态 | ISR 写、任务读,无同步 | 读到半包 / 撕裂 |
|
||||
| **P8** | 外设 / 库特定约定 | 该外设 / 该移植版特有的规则 | 照抄上游示例即错 |
|
||||
| **P9** | 超时与错误混同 | 超时用同一个码表达,调用方无法区分 | 无法复位 / 无法重试 |
|
||||
|
||||
### 1.2 严重度定义
|
||||
|
||||
| 级别 | 含义 | 判据 |
|
||||
|---|---|---|
|
||||
| **P0** | 生产可触发的**静默数据丢失** | 无需特殊工况,正常运行即出错,且无任何告警 |
|
||||
| **P1** | 故障条件下的潜在陷阱 | 触发需特定时序 / 工况 / 参数,一旦触达后果重(死锁、数据损坏、整机不可用) |
|
||||
| **P2** | 健壮性 / 一致性 / 可维护性 | 当前路径无实际后果,或仅影响排障与后续维护 |
|
||||
|
||||
### 1.3 静态代码 ≠ 可触发缺陷
|
||||
|
||||
本项目的硬口径:**只有"生产路径 + 可复现"才算 P0/P1**。多条首版 P0/P1 在本轮复核中被降级,
|
||||
原因就是"静态上确实存在,但当前没有任何调用者能走到":
|
||||
|
||||
- 共享全局 errno 竞态 → 唯一的错误消费者(`ui_net_sink`)**不读 errno、直接看返回值**,
|
||||
只会在 UI 任务与 PC 轮询叠加时偶发(P1 保留)
|
||||
- `cfg_file` 的 `snprintf` 返回值全丢弃 → 但文件解析器**根本不接受转义序列**,
|
||||
溢出所需的字符永远进不来(P2)
|
||||
- `nand_ftl` 的 `dhara_nand_is_free` 把垃圾 `0xFF` 当已用页 → 偏差方向是**保守**的,
|
||||
最多浪费一个页(P2 降级)
|
||||
|
||||
也就是说:**降级不是"不重要",而是"触发不了",触发条件一出现就必须立刻重估**(见 §3.2)。
|
||||
|
||||
### 1.4 本轮复核范围
|
||||
|
||||
- 复核对象:首版 59 项中**未标注已闭环**的全部条目
|
||||
- 方法:逐项回到当前源码查实际代码(`grep` + 精读调用链),不看注释、不信文档既有结论
|
||||
- 已闭环项(§2):仅确认提交存在与机制在位,不重复逐行审
|
||||
- 未覆盖:`Lib/FatFs` 移植层内部、`Lib/dhara` 内核、lftpd 字符串 / IO 辅助模块、
|
||||
`Middlewares/` 内部(同首版边界)
|
||||
- 模拟器保真度差异见 §6
|
||||
|
||||
---
|
||||
|
||||
## 2. 已闭环总览(44 项)
|
||||
|
||||
只列索引与闭环依据,明细不再展开(首版明细可从 git 历史取回)。
|
||||
|
||||
### 2.1 P0 四项(全部已修复并台架验证)
|
||||
|
||||
| 编号 | 位置 | 危害 | 闭环 |
|
||||
|---|---|---|---|
|
||||
| **E-01** | `App/cfg/cfg_file.c` | `cfg_file_poll` 的"超长=损坏"检查是**死代码**(读长被钉死在阈值)→ >4096B 配置被截断当有效解析 → 界外内容静默回工厂默认 → 基线粘住错误状态 → 下次开机 load 守卫判"损坏" → **用户配置文件整体销毁** | `d030cb0` + 关联 `70f1cc8`(`f_rename` 不覆盖既有目标) |
|
||||
| **E-31** | `nand_ftl.c` / `journal.c` | 扫描读失败被**覆盖为 `TOO_BAD`** → 非空白卷在 I/O 故障下被误判"全新"→ 直接 `clear` → 映射表整体丢失 | `da1a6e8` |
|
||||
| **E-02** | `net_socket.c` / `lftpd` / `time_sync` | 一条空闲 FTP 控制连接把 netTask 独占 30s → **全体消费者队列停摆**(实测冻结远端显示 17.7s) | `f8d6e90`+`4a1605b`(分片)→ `a45c0cb`(挂起 recv 化,结构性消灭) |
|
||||
| **E-63** | `App/cfg/cfg_file.c` | 外科手术保存 3 处 `s_encode(...) == 0` 判定恒假(函数成功返回**文本长度**)→ 受管值改写为**死码**:对已存在 `/config.ini` 保存时受管键从不改写(**静默不落盘**,`net_cfg_save` 仍报 OK) | **2026-10-02**(L0.5 `cfg_file` 单测首跑抓出)——判据由 `== 0` 改 `>= 0`;见 [`../测试说明/配置文件单元测试说明.md`](../测试说明/配置文件单元测试说明.md) §5 |
|
||||
|
||||
### 2.2 P1 二十一项
|
||||
|
||||
E-05(net 建链 API 队列化)、E-06 / E-20 / E-21 的**主要分量**(随 E-02 pending 化落地)、
|
||||
E-09(UI 页面局部副本 + 显式提交)、E-17(RECONFIG 原子消费)、
|
||||
E-32(SD2506 充电器寄存器回读校验)、E-33(CH395F DMA 错误通道)、
|
||||
E-36 / E-37(RS485 契约与 init 返回码)、E-38(SD2506 负温度解码)、
|
||||
E-39 / E-51(SD2506 写允许窗口 / `set_alarm` 读-改-写)、E-40(FTL erase/prog 错误分类)、
|
||||
E-43(GD5F erase 容量边界)、**E-03(错误码按任务隔离,2026-09-25)**、
|
||||
**E-34(CH395F 字节命令有限超时,2026-10-03)**、**E-04(`remo_send` 返回值校验,2026-10-03)**、
|
||||
**E-44(TPAFE `read_all` 无数据有效性校验:FRSTDATA 宏有定义、代码零引用,芯片死亡时返回 OK + 常量垃圾;
|
||||
现 `read_channels` 要求"一帧内 FRSTDATA 必须跳变"、`init()` 首帧自检返 `-3`,2026-10-10)**、
|
||||
**E-45(TPAFE `s_ready` 三写者、重触发即清掉未消费帧;改帧序号 `frame_seq()` 只增不清,2026-10-10)**、
|
||||
**E-58(TPAFE `get_buf` 取指针 + 任务侧拷贝被 ISR 抢占 → 两帧混合;删 `get_buf`/`data_ready`/`clear_ready`,
|
||||
改临界区原子快照 `snapshot()`,2026-10-10)**。
|
||||
|
||||
> 注:**E-44 / E-45 在 2026-09-25 重写时只留在首版 P1 速览表、未展开正文条目**(正文只余 E-59 的引用),
|
||||
> 本次闭环直接进索引;实现口径与陷阱见 `AGENTS.md`「ADC 取数只用 `tpafe5160_snapshot()`」条与
|
||||
> `Drivers/BSP/TPAFE5160/README.md`。
|
||||
|
||||
> 注:E-05 已闭环(建链 API 并入队列),但**同族的 `net_getsockname` 残留通道**
|
||||
> 在 §3.1-E-24 重新入册。
|
||||
|
||||
### 2.3 P2 十九项
|
||||
|
||||
E-07(`f_close` 返回值检查 ×5)、E-08(preboot 分支并轨)、E-11(`cfg_file` 读路径返回值)、
|
||||
E-14(net init/重建失败补自检留痕)、E-18(ftpTask 等待超时)、E-19(死事件位清理)、
|
||||
E-22 的**主要分量**、E-29(`ui_net_sink` `FD_CLR` 合法性)、E-35(测试常量对齐)、
|
||||
E-46(`0xECH` 非法字面量)、E-52(开机诊断检查 `get_*` 返回值)、
|
||||
E-53(GD5F 轮询路径 HAL 返回值)、E-54(ECC 使能回读)、E-55(`dhara_nand_read` 返回值)、
|
||||
E-57(`int` / `int32_t` 混用)、**E-10 / E-42 / E-56(GD5F init / BBT / raw 契约,2026-10-03)**、
|
||||
**E-60(SD2506 `SD2506_CHARGE_5K` 宏位订正,2026-09-21)**。
|
||||
|
||||
---
|
||||
|
||||
## 3. 未闭环发现(16 项)
|
||||
|
||||
每项字段统一为:**位置 → 机制 → 后果 → 当前状态 → 建议**。
|
||||
"当前状态"是本轮(2026-09-25)回到代码实测的结论;**2026-10-03 已修复的条目
|
||||
(E-04 / E-10 / E-42 / E-53 / E-56)与 2026-09-25 的 E-03 保留为留档**(标 ✅),不计入未闭环数。
|
||||
|
||||
### 3.1 A 类:待处理的实质缺陷(未闭环 4 项)
|
||||
|
||||
> **本类已闭环留档**:E-03(2026-09-25)、E-04 / E-10 / E-42 / E-53 / E-56(2026-10-03)——
|
||||
> 见下方各条目的 ✅ 标记与 §2 索引;此处保留详细条目仅作背景留档。
|
||||
|
||||
---
|
||||
|
||||
#### ~~E-03 `s_net_errno` 跨任务覆写竞态~~ — **已修复(2026-09-25)** | 模式 P2
|
||||
|
||||
- **位置**:`Drivers/BSP/NET/net_socket.c`(定义处 + 全部写入点 + `net_get_errno`)
|
||||
- **机制**:netTask 在 `net_process_messages` 结束处把精确错误码写进全局 `s_net_errno`,
|
||||
随后调用方包装器在**自己的上下文**里再写一次。两条写路径分属不同任务,无任何互斥。
|
||||
- **后果**:netTask 刚为 A 任务置好码,B 任务的通知处理抢先覆盖 → A 读到 B 的码。
|
||||
任何基于 `net_get_errno()` 做分支的逻辑都可能走错路径(错判"可重试"为"连接已死",或反过来)。
|
||||
- **修复(2026-09-25)——取"按任务隔离"路线**:
|
||||
1. 删除全局 `s_net_errno`,改为 `s_net_errno_slots[8]`(每槽 `{owner 任务句柄, err}`)
|
||||
2. `net_errno_slot()`:无锁快路径命中自己的槽(**只读不写**,并发读者看不到半成品槽位);
|
||||
首次占用在 `taskENTER_CRITICAL` 内复查后写入;槽位用尽**不新增共享槽**(那会把竞态带回来),
|
||||
统一回退 [0] 槽 → 语义退化为共享,仅影响排障可读性
|
||||
3. `net_set_errno(err)` 取代全部 107 处 `s_net_errno = X` 赋值;
|
||||
新增 `NET_ERR_RETURN_1(err)` 宏合并"记码 + `return -1`",共替代 82 处
|
||||
4. `net_get_errno()` 改读**本任务**槽位,对外语义不变(成功不清零,向后兼容)
|
||||
5. 被修路径的**真实收益**:三个既有消费者(`ui_net_sink.c:476`、`net_test_task.c:231/382`)
|
||||
都是"同任务 `net_recv` 后立即 `net_get_errno()`"——这正是竞态窗口内的模式,
|
||||
修复后该判定不再可能读到别的任务的码
|
||||
- **验证**:构建 0 错误 0 警告;cppcheck(warning/performance/portability)无告警;
|
||||
`git diff --check` 无空白问题;编码无 `U+FFFD` 且 BOM 状态与原文一致
|
||||
- **代码代价**:BSS +64 B(8×(4+4))
|
||||
- **登记**:`docs/任务规划/README.md` N-5(✅ 已销项,2026-09-26 清理)
|
||||
- **残留**:`net_recv_to` 继续用返回码 `-2` 表达超时(不依赖 errno),保持既有正确做法
|
||||
|
||||
---
|
||||
|
||||
#### E-04 `remo_send` 丢弃 `net_send` 返回值 — **P1** | 模式 P3
|
||||
|
||||
- **位置**:`Drivers/BSP/UI/ui_net_sink.c:101-120`(`:119` 调用点)
|
||||
- **机制**:`net_send(g_client, p, (int)(4 + len + 1), 0)` 的返回值直接丢弃。
|
||||
`net_send` 在弱网 / 对端停滞时的合法返回是**短写**(已发字节数 < 请求),不是 -1。
|
||||
- **后果**:应答帧静默截断 → 客户端 CRC 校验失败 → 断开重连 → 用户观感是
|
||||
"画面卡住然后黑屏 / 一直卡"。这是**最难定位的一类故障**:设备侧一切日志正常。
|
||||
- **当前状态**:✅ **已修复并通过真机验证(2026-10-03)**——`remo_send` 改返回 `int` + 校验 `ret == total` + 短写告警 / 连续失败阻断推送;真机无误报基线。以下为**修复前**复核记录(保留作背景):`ui_net_sink.c` 全文件无 `net_send` 返回值检查,
|
||||
且 `remo_send` 的整帧(3204B)**远超过**单次可发送上限
|
||||
`NET_SEND_CHUNK_MAX`(= 芯片发送缓冲 1KB,`net_socket.c:1394`),
|
||||
所以"单次调用的返回值即全量"这一假设**在整帧路径上必然不成立**;
|
||||
当前能工作只是因为 `net_send_locked` 内部做了分块循环 + 内部重试。
|
||||
一旦对端读取变慢,内部分块重试会耗尽预算并**合法地短写返回**,此时上层无任何感知。
|
||||
- **建议**:`remo_send` 改为返回 `int`,校验 `ret == len`;短写 → `DBG_ERROR` + 计入统计;
|
||||
连续失败 → `net_close(g_client)` 强制重连补帧(与 `lftpd_inet_write` 的处理方式对齐)。
|
||||
- **关联**:`docs/测试说明/链路延迟测试说明.md:632` 已把 E-04 列为"会掩盖延迟"的既有缺陷。
|
||||
|
||||
---
|
||||
|
||||
#### E-24 `net_getsockname` 直读 `s_local_ip`,绕过 netTask 串行化 — **P2** | 模式 P7
|
||||
|
||||
- **位置**:`Drivers/BSP/NET/net_socket.c:3637-3641`(读 `s_local_ip`);
|
||||
写点 `:201`(netTask 在 `net_init` 内 `memcpy`)
|
||||
- **机制**:`s_local_ip` 是 4 字节静态数组,netTask 写、任意任务读,无同步。
|
||||
- **后果**:`net_getsockname` 可能拼出**新旧混合**的 IP。
|
||||
- **当前状态(复核)**:**仍然存在,但本轮确认影响面比首版预估的更窄——仍应记录。**
|
||||
写入只发生在 `net_init` 内部**一次**(`:201`),此后 IP 不再变化
|
||||
(DHCP → `0.0.0.0` 也在同一次写入内)。所以"撕裂"需要恰好在 `net_init` 执行期间调用
|
||||
`net_getsockname`,而所有调用方(`lftpd.c:407` PASV、`lftpd.c:673` 连接日志、
|
||||
`lftpd_inet.c:64`)都在 **NET_READY 屏障之后**才可能执行 → 当前不可达。
|
||||
- **建议**:维持 P2。`net_getsockname` 改为经队列请求(或至少把 4 字节打包成单次 32 位读
|
||||
+ netTask 侧序贯穿),使契约与其余 socket API 一致;不作为独立修复项排期,
|
||||
随 N-4 顺带处理。
|
||||
|
||||
---
|
||||
|
||||
#### E-10 GD5F init 内多处 HAL 返回值未检查 — **P2** | 模式 P4
|
||||
|
||||
- **位置**:`Drivers/BSP/GD5F2GQ5UE/gd5f2gq5ue.c:606` 起(init 步骤 3~6 的 setup 序列)、
|
||||
各直接调用的 `HAL_SPI_Transmit` / `gd5f_set_feature` / `gd5f_wait_busy`
|
||||
- **机制**:扫坏块、使能 ECC、解除块保护、定位保留池等步骤大量调用点忽略返回值。
|
||||
- **后果**:init 返回 `GD5F_OK` 但实际配置未生效(例如 ECC 未真正打开),
|
||||
存储栈在**无 ECC 保护**下运行 → 数据完整性底线静默降级。
|
||||
- **当前状态**:✅ **已修复(2026-10-03)**——init 全链路检查返回值(见 §5 第二档 #1)。修复前复核:**当时仍然存在**。`gd5f_wait_busy` 自身有 `int` 返回值
|
||||
(`gd5f2gq5ue.c:147`,超时返 `GD5F_BUSY_TIMEOUT`),但 init 与 BBT rebuild 里
|
||||
至少 5 处(`:548` / `:552` / `:643` / `:647` / `:1000`)直接丢弃返回值;
|
||||
`gd5f_bbt_scan()` 内部的 `gd5f_page_read` / `gd5f_read_from_cache`(`:505-506`)同样未检查。
|
||||
- **建议**:init 全链路失败即返回错误码(`App/task/default_task.c:64` 已有
|
||||
`int ret = gd5f2gq5ue_init()` 的检查位,只是慢路径没把错误传上来);init 重试 1~2 次;
|
||||
让 `default_task` 能对"扫坏块失败 / ECC 未使能"做出差异化反应(而非静默继续)。
|
||||
- **关联**:与 E-42 / E-53 / E-54 同一族,建议合并为一次"GD5F 错误通道统一"改造(§5 第二档 #1)。
|
||||
|
||||
---
|
||||
|
||||
#### E-42 `gd5f_bbt_scan` 丢弃读返回值 — **P2** | 模式 P4
|
||||
|
||||
- **位置**:`Drivers/BSP/GD5F2GQ5UE/gd5f2gq5ue.c:505-506`
|
||||
- **机制**:`gd5f_page_read(page)` 与 `gd5f_read_from_cache(...)` 的返回值均未接收;
|
||||
`bbt_scan` 对外恒返回 `GD5F_OK`(`:518`)。
|
||||
- **后果**:SPI 读失败时局部 8 字节 `spare[8]` 保持**上一轮的陈旧内容**,
|
||||
按 `spare[0] != 0xFF` 判定 → 把好块判成坏块(保守,可接受)或反之。
|
||||
更严重的是**整片扫描全失败时也返回成功**,上层以为坏块表可用。
|
||||
- **当前状态**:✅ **已修复(2026-10-03)**——`bbt_scan` 检查读返回值 + 每轮 `spare` 清零 + 读失败中止,`bbt_rebuild` 扫描失败**放弃持久化**(见 §5 第二档 #1)。修复前复核:**当时仍然存在**。调用点 `:548`(BBT rebuild)与 `:639`(init)
|
||||
都直接忽略返回,rebuild 路径随后照常 `gd5f_bbt_save()` → 可能把**错表**持久化覆盖正确副本。
|
||||
- **建议**:扫描中任一读失败即中止并返回错误;`bbt_scan` 增加 `spare[8]` 每轮清零;
|
||||
`gd5f2gq5ue_bbt_rebuild` 在扫描失败时必须**放弃持久化**(保留既有好副本)。
|
||||
第二项(失败时不动持久区)是比"检查返回值"更关键的语义修正。
|
||||
|
||||
---
|
||||
|
||||
#### E-53 GD5F 轮询路径 HAL 返回值系统性未检查 — **P2** | 模式 P4
|
||||
|
||||
- **位置**:`Drivers/BSP/GD5F2GQ5UE/gd5f2gq5ue.c:155-168`(`gd5f_wait_busy` 内 3 次 HAL 调用)、
|
||||
`:239` / `:403` / `:476` / `:545` / `:552` / `:643` / `:647` / `:1000`(`wait_busy` 调用点)
|
||||
- **机制**:`gd5f_wait_busy` 里 `HAL_SPI_Transmit` / `HAL_SPI_Receive` 的返回值全部丢弃,
|
||||
失败时 `status` 保持初值 `0` → `(status & GD5F_STATUS_OIP) == 0` 立即可满足 →
|
||||
**"操作完成"被伪造出来**。
|
||||
- **后果**:SPI 故障 → 状态字节读到垃圾 → 误判操作完成 → 后续命令在未就绪的芯片上执行,
|
||||
最终表现为"静默报成功但数据没落盘"。
|
||||
- **当前状态**:✅ **已修复(2026-10-03)**——`gd5f_wait_busy` 内检查三次 HAL 调用,失败即返回 `GD5F_ERROR`(与 `GD5F_BUSY_TIMEOUT` 区分;见 §5 第二档 #1)。修复前复核:**当时仍然存在**。`wait_busy` 的返回值形式上是"看起来被检查了"
|
||||
(很多调用点确实写了 `ret = gd5f_wait_busy(...)`),但**函数内部不区分"超时"与"HAL 失败"**,
|
||||
且 HAL 失败造成的伪完成会**优先于**超时返回 `GD5F_OK`。
|
||||
- **建议**:`gd5f_wait_busy` 内检查三次 HAL 调用,失败即返回独立错误码(`GD5F_ERROR`);
|
||||
调用点区分 `GD5F_BUSY_TIMEOUT`(可重试)与 `GD5F_ERROR`(真故障,须上报自检)。
|
||||
- **关联**:与 E-10 / E-42 / E-54 合并改造(§5 第二档 #1)。
|
||||
|
||||
---
|
||||
|
||||
#### E-56 公开 `gd5f2gq5ue_read` 对不可纠正页仍返回 0 — **P2** | 模式 P3
|
||||
|
||||
- **位置**:`Drivers/BSP/GD5F2GQ5UE/gd5f2gq5ue.c:703-737`(read 主体)、
|
||||
`:239`(`gd5f_read_from_cache` 内)
|
||||
- **机制**:`gd5f_read_from_cache` 的返回值语义是"**SPI 传输完成**",不是"**数据正确**"。
|
||||
ECC 不可纠正页(ECCS 非零)在 SPI 层是正常完成的,因此函数返回 `0`(成功)。
|
||||
- **后果**:raw API 使用者会拿到**带有未纠正位翻转**的数据并被告知成功。
|
||||
- **当前状态**:✅ **已修复(2026-10-03)**——按建议 ② 在 `gd5f2gq5ue.h` 的 `read` 声明处**显式文档化 raw 契约**("0 = SPI 传输完成,正确性由 ECC 层保证";见 §5 第二档 #1)。修复前复核:**当时仍然存在,缺口范围本轮已精确确认。**
|
||||
生产主路径是 **dhara glue 层**(`nand_ftl.c`),它自己有 ECC 检查保护,所以是安全的;
|
||||
缺口只存在于**直接调用公开 raw API 的场景**。真正的消费者目前只有 `test/` 测试套件与诊断路径。
|
||||
- **建议**:两条路选一条——① `gd5f2gq5ue_read` 增加 ECCS 回读并在不可纠正时返回错误码;
|
||||
② 在 `gd5f2gq5ue.h` 的 `read` 声明处**显式文档化**"0 = SPI 传输完成,
|
||||
数据正确性由 ECC 层保证"。因涉及公开 API 语义,倾向 ② + 在
|
||||
`docs/问题记录/GD5F2GQ5UE_Trap_Records.md` 补一条契约说明。
|
||||
|
||||
---
|
||||
|
||||
#### E-49 RS485 TX 超时立即拉低 DE — **P2** | 模式 P9
|
||||
|
||||
- **位置**:`Drivers/BSP/RS485/rs485.c:70-93`
|
||||
- **机制**:发送超时路径直接拉低 DE 引脚,此时**末尾字节可能仍在移位寄存器中**。
|
||||
- **后果**:对端收到被截断的最后一帧(半字节)。
|
||||
- **当前状态(复核)**:**仍然存在,但仅在超时路径生效**。正常路径靠 TC 标志正常收尾,
|
||||
所以影响局限于"发送本身已经失败"的场景——属于"失败之后再补一刀"型缺陷。
|
||||
- **建议**:超时路径改为"等 TC 或短延时后再拉低 DE"(给移位器一个明确的排空窗口),
|
||||
代价是超时路径多等 ≤1 字符时间。
|
||||
|
||||
---
|
||||
|
||||
#### E-50 RS485 单缓冲无 ISR/任务同步 → 包撕裂 — **P2** | 模式 P7
|
||||
|
||||
- **位置**:`Drivers/BSP/RS485/rs485.c:37-39`(`rx_buf` / `rx_size`)
|
||||
- **机制**:ISR 写 `rx_size`、任务侧读并 `memcpy`,无同步;115200bps 下
|
||||
256B 帧仅约 22ms 窗口,任务一旦晚于窗口完成拷贝,新帧就会覆盖旧帧。
|
||||
- **后果**:读出**跨两帧**拼接的数据(长度字段与内容不匹配)。
|
||||
- **当前状态(复核)**:**仍然存在,休眠缺陷**。当前 `rs485_task.c:37-43` 是空桩,
|
||||
无消费者。与 E-36 / E-44 / E-45 / E-58 同一族。
|
||||
- **建议**:双缓冲 + 序号(或"任务处理窗口内关 IDLE 中断"的简化约定)。
|
||||
属"接消费者前必修"(§5 第三档前置条件)。
|
||||
|
||||
---
|
||||
|
||||
#### E-59 消费者任务均为空桩,驱动层多项 P1 全部休眠 — **P1(元发现)** | 模式 ——
|
||||
|
||||
- **位置**:`App/task/adc_task.c:37-43`、`App/task/rs485_task.c:37-43`
|
||||
- **机制**:两个任务的函数体都是 `osDelay` 空循环,谁都不调驱动层的 `get_buf` / `on_rx`。
|
||||
- **后果**:**首版列出的多项驱动层 P1(E-36 / E-44 / E-45 / E-58)当前全部不可触发。**
|
||||
这意味着"审计通过"是假的——一旦接入真实消费者,这些缺陷会同时上线。
|
||||
- **当前状态(复核 2026-10-10)**:**仍然存在**(消费者仍未接入),但**闸门已经半开**:
|
||||
① 前置清单里 TPAFE 三项 **E-44 / E-45 / E-58 已修复**(原子快照 API + 帧序号取代
|
||||
就绪标志 + FRSTDATA 数据有效性校验,索引见 §2.2);RS485 侧 **E-36 / E-37 早已闭环**,
|
||||
但 **E-50(单缓冲无同步)与 E-49(超时路径拉 DE)仍未修** → RS485 消费者仍被挡住。
|
||||
② 门禁本身已固化进 `AGENTS.md`(与"改栈前跑 `stack_report.py`"同级)。
|
||||
③ 栈预算**仍未做**:两任务尚未纳入 `Src/freertos.c` 栈表。
|
||||
- **建议**:接 **ADC** 消费者现在只欠"栈预算 + 产品定义(采样率 / 数据出口)";
|
||||
接 **RS485** 消费者前还必须先修 E-50 / E-49。
|
||||
|
||||
---
|
||||
|
||||
### 3.2 B 类:契约缺口(随消费者接入触发,未闭环 7 项)
|
||||
|
||||
这一类的共同特征:**静态缺陷真实存在,但当前没有调用者能走到**。它们现在不产生故障,
|
||||
但契约没写死,属于"埋着的雷"。**触发条件一旦出现(新消费者、参数变更、库配置变更),立即升 P1。**
|
||||
|
||||
---
|
||||
|
||||
#### E-16 `cfg_file` 生成文档的边界余量绑死 `snprintf` 返回语义 — **P2** | 模式 P4
|
||||
|
||||
- **位置**:`App/cfg/cfg_file.c:469` / `:481`(`s_gen_document`)、
|
||||
同族丢弃点 `:252` / `:256` / `:261`(`s_encode`)、`:642` / `:663` / `:683`(行生成)
|
||||
- **机制**:`off += (size_t)snprintf(...)` —— 直接丢弃返回值。`snprintf` 返回**本应写入的长度**,
|
||||
截断时该值 **> 剩余容量**,`off` 会**跳过缓冲末尾**(越界),而不是停在边界;
|
||||
现有的 `if (cap < off + 112u) return -1;` 前置守卫在 `off` 已经越界后也救不回来。
|
||||
- **后果**:极端情况下写越界 / 输出被静默截断。
|
||||
- **当前状态(复核)**:**仍然存在,但本轮确认当前不可达。**
|
||||
触发本缺陷需要一个**超过 104 字符**的段名或键名,而配置文件的**解析器根本不接受转义序列**
|
||||
——含引号 / 反斜杠的键名无法通过解析进入内存,长度上限也受解析缓冲约束。
|
||||
换句话说:**防线是"上游解析器"而不是"本函数的守卫",而这条防线没有写进文档。**
|
||||
- **建议**:① 把 `snprintf` 返回值改为检查式
|
||||
(`int n = snprintf(...); if (n < 0 || (size_t)n >= cap - off) return -1;`);
|
||||
② 更根本的做法是在 `cfg_file.h` 中**显式定义段名 / 键名的最大长度**,并让注册 API 拒绝超长名字
|
||||
——这样余量才是**编译期可验证**的,而不是依赖"解析器恰好不接受转义"。②优先级高于①。
|
||||
|
||||
---
|
||||
|
||||
#### E-25 `net_select` LISTENING 恒可读 + 参数错误不置 errno — **P2** | 模式 P3
|
||||
|
||||
- **位置**:`Drivers/BSP/NET/net_socket.c`(`net_select` 实现)
|
||||
- **机制**:① 监听态 fd 在 `select` 语义下永远"可读"(有连接待 accept 时可读,
|
||||
无连接时按 BSD 也应可读),调用方若用 `select` 做"有数据可读"判断会误判;
|
||||
② 参数错误时直接返回而**不设置 errno**,调用方拿到 `-1` 却查不到原因。
|
||||
- **后果**:无法区分"监听器上有新连接"与"有数据";参数错误无从定位。
|
||||
- **当前状态(复核)**:**仍然存在,休眠缺陷**。当前无 `net_select` 调用者
|
||||
(各服务都是 `accept` 轮询 / pending 模式)。
|
||||
- **建议**:随 N-4 或首个 `select` 消费者落地时一并订正;
|
||||
同时在头文件把"LISTENING 恒可读"作为**契约**写出来。
|
||||
|
||||
---
|
||||
|
||||
#### E-26 UDP 路径未并入队列 — **P2** | 模式 P8
|
||||
|
||||
- **位置**:`Drivers/BSP/NET/net_socket.c:2647`(`net_sendto`)、`:2776`(`net_recvfrom`)
|
||||
- **机制**:UDP 的 `sendto` / `recvfrom` 走**直调芯片**路径,不在 `netMsgQueue` 上,
|
||||
与 netTask 串行语义冲突(SPI 事务可能与其他 socket 操作交错)。
|
||||
- **后果**:UDP 与 TCP 并发时 SPI 事务交错 → 芯片状态机混乱。
|
||||
- **当前状态(复核)**:**仍然存在,休眠缺陷**。当前无任何 UDP 用户
|
||||
(`net_init` 的 UDP 分支无调用者)。
|
||||
- **建议**:三选一并在文档中定案——① 并入队列(新增 `NET_MSG_SENDTO` / `NET_MSG_RECVFROM`);
|
||||
② 直接移除 UDP API(无用户,最干净);③ 保留但在头文件明确"仅单任务独占期可用"。
|
||||
倾向 ② 或 ③,避免为无用户的路径增加队列类型与 RAM。
|
||||
|
||||
---
|
||||
|
||||
#### E-27 / E-28 socket 表裸指针跨上下文读 — **P2** | 模式 P2 / P7
|
||||
|
||||
- **位置**:`Drivers/BSP/NET/net_socket.c`(`net_get_sock()` 返回裸指针)、
|
||||
`App/sync/time_sync.c` / `Drivers/BSP/NET/lftpd/lftpd.c`(代次号读取)
|
||||
- **机制**:`net_get_sock()` 把 socket 控制块**裸指针**交给调用方,调用方随后读
|
||||
`p_sock->state`;netTask 可能在同一时刻改写该结构。
|
||||
- **后果**:读到中间态的 `state`(例如"刚 `CLOSED` 但字段未清")。
|
||||
- **当前状态(复核)**:**仍然存在,休眠缺陷**(本轮从 E-05 族拆分并重新入册)。
|
||||
当前唯一代表性读点是 `lftpd_inet_accept_timeout`
|
||||
(`Drivers/BSP/NET/lftpd/lftpd_inet.c:100-104`)读 `p_sock->state != LISTENING`;
|
||||
该路径受 `timeout_ms` 约束、且 netTask 对 `state` 的写是**单次 32 位写**(无撕裂),
|
||||
实际风险低。已用 pending 模型重写的路径(`net_recv_to`)不再有此类读。
|
||||
- **建议**:长期方向是"状态查询 API 化"(`net_get_state(fd)` 走队列或返回快照值),
|
||||
与 E-24 / E-26 同属"消除跨上下文裸指针"的一组,可合并处理。
|
||||
|
||||
---
|
||||
|
||||
#### E-31 后续:卷自愈的误判边界 — **P2** | 模式 P3
|
||||
|
||||
- **位置**:`App/task/default_task.c:311`(`storage_bring_up`)及卷健康探针
|
||||
- **机制**:E-31 主体已修(错误分类 + 有界重试),但**自愈触发集**仍需一条纪律:
|
||||
只有"真卷损坏"才允许走重格式化,**名字 / 参数类错误码必须排除在外**。
|
||||
- **后果**:若把 `FR_INVALID_NAME` 之类的**纯 RAM 判定错误**归入损坏触发集,
|
||||
会触发**不可逆的整卷重格式化**。
|
||||
- **当前状态(复核)**:**机制在位,纪律已固化为 `AGENTS.md` 铁律**
|
||||
("自愈类逻辑严禁把名字/参数类错误码归入卷损坏触发集")。
|
||||
本项保留为**回归监督项**:后续任何自愈逻辑改动都要回头核对这条纪律。
|
||||
- **建议**:不需要改动。在 `storage_bring_up` 的错误分类 switch 旁补一条注释
|
||||
指向该铁律,降低后人误改概率。
|
||||
|
||||
---
|
||||
|
||||
#### E-47 / E-48 驱动侧边界项 — **P2** | 模式 P8 / P9
|
||||
|
||||
| 编号 | 位置 | 机制与后果 | 当前状态(复核) | 建议 |
|
||||
|---|---|---|---|---|
|
||||
| **E-47** | `Drivers/BSP/CH395F/ch395f.c:606-622` | 轮询超时与"芯片忙"共用 `0x10` 码;且 `CMD_STATUS` 读即清 → 下条命令可能先读到上条的完成态 | **仍然存在**,现边界已统一按"可重试"处理,实际影响有限 | 引入独立超时码或轮次序,使调用方能区分"忙"与"超时" |
|
||||
| **E-48** | `Drivers/BSP/RS485/rs485.c:173` | `ErrorCallback` 的修复者返回值被丢弃 | **仍然存在,实为良性**:ORE 路径 HAL 会先复位 `RxState=READY`;非阻塞错误路径原本就存活自愈 | 非 `HAL_OK` 时补一条 `WARN` 便于排障即可 |
|
||||
|
||||
---
|
||||
|
||||
### 3.3 C 类:一致性 / 可维护性(未闭环 5 项)
|
||||
|
||||
无功能影响或影响极小,排在第三档批量处理。
|
||||
**本类已闭环留档**:E-57(2026-10-03)、E-60(2026-09-21);**监督项**:E-62(无需改动)。
|
||||
|
||||
| 编号 | 位置 | 问题 | 当前状态(复核) | 建议 |
|
||||
|---|---|---|---|---|
|
||||
| **E-12** | `Lib/FatFs/ffconf.h:39` | `FF_FS_LOCK 0` —— 无文件级互斥,同一文件可被两任务同时打开 | **仍然存在**。当前 `defaultTask` 是 syslog 与配置引擎的**唯一写者**(单写者收敛策略),故无实际冲突 | 开 `FF_FS_LOCK`(代价:每文件 ~几十字节 RAM);或固化"单写者纪律"。**当前选择后者,本项仅为记录** |
|
||||
| **E-15** | `App/util/ringbuf.c` | ringbuf 实现存在但**全项目零调用者**(本轮 `grep` 确认除自身外无引用) | **仍然存在** | 修复后启用,或直接删除。**保留一个零调用者的工具模块是负债**,建议本轮就定去留 |
|
||||
| **E-23** | `test/` | 测试套件缺代次检查(accept 失败分支);TC704 并发度偏高 | **仍然存在** | 加代次断言;TC704 降并发或在测试构建抑制服务任务 |
|
||||
| **E-30** | `simulator/sim/net_socket_sim.c` | sim 后端 errno 语义与 MCU 不对齐(成功即清 errno,MCU 不清) | **仍然存在**(语义差异在 §6 表中仍成立) | 对齐语义;并在缺陷记录中标明"sim 复现盲区" |
|
||||
| **E-57** | `Drivers/BSP/GD5F2GQ5UE/gd5f2gq5ue.h:119/140/189/222-253` | 公开 API 返回类型 `int` / `int32_t` 混用(码值均为小负数,无功能影响) | ✅ **已修复(2026-10-03)**:公开 API 全部统一为 `int32_t` | 见 §5 第二档 #1 |
|
||||
| **E-60** | `Drivers/BSP/SD2506/sd2506.c/h` | `SD2506_CHARGE_5K` 宏位与 `docs/芯片手册/SD2506API-G.md` §4.8 不符的风险 | **已订正**(2026-09-21,`41e111b`):宏位已改为 `bit1`,18H 回读校验在位 | 无需改动,仅作为"手册总表 vs 专用表不一致"的案例保留 |
|
||||
| **E-61** | `Drivers/BSP/SD2506/sd2506.c:482` | `sd2506_clear_int` 注释称"ARST=1 时自动清除 INTAF",实际 ARST 在 **CTR3**(11H)而代码从未写过 CTR3 | **仍然存在(纯注释错误)** | 修注释:明确"ARST 未启用,INTAF 靠读 CTR1 清除" |
|
||||
| **E-62** | `Lib/FatFs/ffconf.h` | `FF_USE_LFN=0` → 严格 8.3 短名;自愈逻辑若把 `FR_INVALID_NAME` 归入损坏触发集 → 不可逆重格式化(`.fschk` 无限重格式化事故根因) | **铁律已固化**(`AGENTS.md`);`ff.c` `create_short` 全部拒绝点已加 DEBUG 打印 | 无需改动,回归监督项(与 §3.2-E-31 后续同族) |
|
||||
|
||||
---
|
||||
|
||||
## 4. 模式 × 子系统矩阵(仅未闭环项)
|
||||
|
||||
> 单元格内容 = 发现编号;`✓` = 本轮检查无问题;`—` = 不适用
|
||||
|
||||
| 模式 | net 层 | 事件标志 | 配置引擎 | syslog | CH395F | RS485 | SD2506 | GD5F/FTL | TPAFE | lftpd | timeSync | ui_sink | test | sim |
|
||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
||||
| P1 值拷贝 | ✓ | — | ✓ | ✓ | — | — | — | — | — | — | — | — | — | — |
|
||||
| P2 共享全局 | ✓ | ✓ | ✓ | ✓ | — | — | — | — | — | **E-27/E-28** | **E-27/E-28** | ✓ | ✓ | E-30 |
|
||||
| P3 混同 | **E-25** | — | ✓ | — | E-47 | ✓ | ✓ | **E-31后续** | — | ✓ | ✓ | ✓ | ✓ | E-30 |
|
||||
| P4 未检查 | ✓ | ✓ | **E-16** | ✓ | ✓ | E-48 | ✓ | ✓ | — | ✓ | ✓ | ✓ | ✓ | — |
|
||||
| P5 事件语义 | ✓ | ✓ | ✓ | — | — | — | — | — | — | ✓ | ✓ | ✓ | ✓ | — |
|
||||
| P6 符号/宽度 | — | — | — | — | — | — | — | — | — | — | — | — | — | — |
|
||||
| P7 跨上下文 | **E-24** | — | ✓ | ✓ | — | **E-50** | — | — | **E-58** | E-27/E-28 | ✓ | ✓ | — | — |
|
||||
| P8 外设/库 | **E-26** | — | ✓ | ✓ | E-47 | — | E-61 | ✓ | — | — | — | — | — | — |
|
||||
| P9 超时/错误 | ✓ | — | — | — | E-47 | **E-49** | — | ✓ | ✓ | ✓ | ✓ | — | — | — |
|
||||
|
||||
**读法提示**:三处"空白带"(事件标志、syslog、配置引擎的大部分行)不是没审,
|
||||
而是首版查出的问题已闭环。**GD5F 列的项已于 2026-10-03 全部闭环**(矩阵该列已清空),
|
||||
当前未闭环项集中在 **RS485 驱动(E-49 / E-50)、net 层全局状态
|
||||
(E-24 / E-25 / E-26 / E-27 / E-28)、配置引擎(E-16)与测试基础设施(E-23 / E-30)。**
|
||||
|
||||
---
|
||||
|
||||
## 5. 修复计划
|
||||
|
||||
### 第一档:立即(改动小、价值高、风险低,无架构变更)
|
||||
|
||||
| # | 项 | 内容 | 级别 |
|
||||
|---|---|---|---|
|
||||
| 1 | ~~**E-34**~~ | **已修复并通过真机验证(2026-10-03)**:CH395F 3 处字节级 SPI 调用 `HAL_MAX_DELAY` → 有限超时 100ms + 返回值检查 + 故障锁存 `ch395f_spi_byte_fault()`(仅首条故障记日志,防刷屏)——SPI 异常不再挂死 netTask;真机正常路径零回归 | ✅ |
|
||||
| 2 | ~~**E-04**~~ | **已修复并通过真机验证(2026-10-03)**:`remo_send` 改返回 `int` 校验 `ret == total`;短写 → `DBG_ERROR` + 连续失败计数;连续 3 次 → 阻断推送(客户端无帧自行重连,芯片侧 DISCONNECT/TIMEOUT 自动重开监听;MCU 单连接模型不 `net_close` 数据 fd),新连接/网络重建解除;真机无误报基线 | ✅ |
|
||||
| 3 | ~~**E-03 / N-5**~~ | **已修复(2026-09-25)**:错误码改按任务隔离,删除全局 `s_net_errno`(见 §3.1) | ✅ |
|
||||
| 4 | **E-49** | RS485 TX 超时路径:等 TC / 短延时后再拉低 DE | P2 |
|
||||
| 5 | **E-15** | `ringbuf` 定去留:修复后启用,或删除(零调用者模块不值得维护) | P2 |
|
||||
| 6 | **E-61** | SD2506 `clear_int` 注释订正(ARST 在 CTR3,代码从未启用) | P2 |
|
||||
|
||||
### 第二档:下一迭代(结构性改造)
|
||||
|
||||
| # | 项 | 内容 |
|
||||
|---|---|---|
|
||||
| 1 | ~~**GD5F 错误通道统一**(E-10 / E-42 / E-53 / E-54 / E-56 / E-57)~~ | **已修复并通过台架套件回归(2026-10-03)**:`gd5f_wait_busy` 内检查三次 HAL 调用并区分"超时"(`GD5F_BUSY_TIMEOUT`,可重试)与"真故障"(`GD5F_ERROR`);`gd5f_bbt_scan` 检查读返回值 + 每轮 `spare` 清零 + 读失败中止,`bbt_rebuild` 扫描失败时**放弃持久化**(保留好副本);init 全链路检查返回值;init 后**回读 B0h 校验 ECC 使能(bit4)**;`gd5f2gq5ue_read` 的 raw 契约文档化(E-56);返回类型统一 `int32_t`(E-57);`nand_ftl.c` 2 处未检查的 `gd5f_read_from_cache` 补检查。套件回归 `=== GD5F2GQ5UE Tests: 16/16 PASSED (failed=0) ===` ✅ |
|
||||
| 2 | **N-4:ACCEPT + SEND 阻塞路径 pending 化** | 沿用 recv 挂起机制扩展;同期消化 **E-25**(`net_select` 语义)、**E-24 / E-27 / E-28**(跨上下文裸指针收口为状态查询 API)。基线重锁 + 探针族扩充 + 看门狗接 selftest 留痕 |
|
||||
| 3 | **E-16** | 在 `cfg_file.h` 显式定义段名 / 键名最大长度,注册 API 拒绝超长名字(把余量变成编译期可验证);`snprintf` 返回值改检查式 |
|
||||
| 4 | **E-26** | UDP 路径定案:并入队列 / 移除 / 文档化"单任务独占"。倾向 **移除**(无用户) |
|
||||
| 5 | **E-30** | sim 后端 errno 语义对齐 + 缺陷记录标注 sim 复现盲区 |
|
||||
| 6 | **E-23** | 测试套件加代次断言;TC704 降并发或测试构建抑制服务任务 |
|
||||
|
||||
### 第三档:长期 / 前置门禁
|
||||
|
||||
- **E-59 门禁**(**已固化进 `AGENTS.md`,2026-10-10**):`adc_task` / `rs485_task` 接入消费者
|
||||
**之前**必须先完成驱动契约修复 + 栈预算核算(两任务尚未纳入 `Src/freertos.c` 栈表),
|
||||
与"改栈前跑 `stack_report.py`"同级。清单现状:**E-36 / E-37 ✅(早前)**、
|
||||
**E-44 / E-45 / E-58 ✅(2026-10-10)**、**E-50 / E-49 ❌(RS485 未修)**
|
||||
→ **ADC 侧只欠"栈预算 + 产品定义",RS485 侧仍被挡住**
|
||||
- **E-50**:RS485 双缓冲 + 序号(随 E-59 门禁,**接 RS485 消费者前必修**)
|
||||
- **E-12**:`FF_FS_LOCK` 或固化"单写者纪律"(`AGENTS.md`)
|
||||
- **E-31 后续 / E-62**:卷自愈触发集的回归监督(纪律已固化,需防后人误改)
|
||||
- **E-47 / E-48**:驱动健壮性长尾(独立超时码 / WARN 留痕)
|
||||
|
||||
---
|
||||
|
||||
## 6. 模拟器保真度差异
|
||||
|
||||
核心结论:**09-21 类 errno 缺陷在模拟器结构性不可复现**(单线程 + 成功即清 errno 双重掩盖),
|
||||
该类修复**只能硬件闭环验证**。
|
||||
|
||||
| # | 项目 | MCU 后端 | 模拟器后端 | 影响 |
|
||||
|---|---|---|---|---|
|
||||
| 1 | accept fd 模型 | 返回监听 fd 自身(单连接) | 返回独立新 fd,监听 fd 常驻 | 依赖"fd 生命周期"的写法移植即泄漏 |
|
||||
| 2 | EOF 后行为 | `auto_relisten`:fd 回 LISTEN、保持 `in_use` | 无:fd 仍 `in_use` 但 Winsock 已关 | "EOF 后 fd 仍活"的写法在 sim 失真 |
|
||||
| 3 | recv 阻塞模式 | flags=0 阻塞 / pending | 恒非阻塞,`(void)flags` | **生产阻塞路径在 sim 零覆盖** |
|
||||
| 4 | send 停滞契约 | 分块阻塞;1s/chunk 停滞 → 返回已发字节 + TIMEDOUT | 单次非阻塞;部分发送 → 部分值 + **NET_OK(静默截断无告警)** | 同一条件双端 errno 不同 |
|
||||
| 5 | 零长度 send | -1 / INVAL | 0 / OK | 零长用例 sim 必假 FAIL |
|
||||
| 6 | 零长度 recv | -1 / INVAL | 0 = 对端关闭 | 边界契约不一致 |
|
||||
| 7 | `net_connect` 语义 | 异步:0 = issued,net_poll 推进状态机 | 进行中 = -1 / WOULDBLOCK;state 永不推进 | TC701 假 FAIL / TC703 负向用例**假 PASS** |
|
||||
| 8 | 错误码粒度 | 12 种精确码(附录 A) | 仅 BADF / INVAL / WOULDBLOCK + 通用 NET_ERR | 依赖精确码的分类逻辑在 sim 失真 |
|
||||
| 9 | 成功后 errno | **不清除**(stale 滞留) | **清零** | **本类缺陷在 sim 结构性不可复现** |
|
||||
| 10 | `net_listen` 前置 | 须 BOUND / CREATED | 仅查 `in_use` | sim 更宽松 |
|
||||
| 11 | `getsockname` 数据源 | `s_local_ip` 缓存 | Winsock `getsockname` | PASV 响应 IP 双端不同 |
|
||||
| 12 | 代次号 | reconfig 递增 | 恒 0 | 重建 / 重监听路径 sim 零覆盖 |
|
||||
| 13 | 事件回调 | net_poll 内 `fire_event` | 只存储不触发 | 回调驱动逻辑 sim 全死 |
|
||||
| 14 | 并发模型 | 队列 + netTask 串行 SPI | 单主线程直调 Winsock | 跨任务竞态 sim 不可复现 |
|
||||
| 15 | UDP bind | `open_socket` + SPI | 无对应步骤 | 与 E-26 相关,当前无用户 |
|
||||
| 16 | `net_init` | 芯片全量初始化 | 仅 `WSAStartup` | 设计对齐 |
|
||||
|
||||
---
|
||||
|
||||
## 7. 审计边界与未覆盖项
|
||||
|
||||
- **未逐行审计**:`Lib/FatFs` 移植层内部(已知陷阱已在 `AGENTS.md` 固化)、
|
||||
`Lib/dhara` 内核(仅审 glue 映射层与错误分类)、lftpd 的字符串 / IO 辅助模块(边界抽查)、
|
||||
`Middlewares/` CMSIS / HAL 内部(错误路径抽查)
|
||||
- **模拟器**:16 项差异见 §6;09-21 类 errno 缺陷**只能硬件验证**
|
||||
- **休眠缺陷的性质**:RS485 / TPAFE 侧 **E-50 / E-58** 因消费者为空桩而暂不可触发,
|
||||
接入消费者前必须先修(E-59 门禁)
|
||||
- **基线**:本报告基于 2026-09-24 `v2-on-ui` @ `9a8255f`;后续代码变更需增量复核
|
||||
- **文档一致性提醒**:本轮复核发现首版存在若干"**文档内闭环比代码先行**"的情况
|
||||
(例如 E-26 / E-27 / E-28 在首版矩阵中已被标为 `✓`,但代码实际未改)。
|
||||
**建议后续复核一律以当前源码为准,不以既有矩阵为准。**
|
||||
|
||||
---
|
||||
|
||||
## 附录 A:NET_ERR 错误码表(`Drivers/BSP/NET/net_types.h:98-109`)
|
||||
|
||||
| 码 | 值 | 含义 | 通知值语义 |
|
||||
|---|---|---|---|
|
||||
| `NET_ERR_OK` | 0 | 成功 | 成功:通知值 = 字节数 / fd(≥0) |
|
||||
| `NET_ERR` | -1 | 通用错误 | 失败:通知值 = 负的精确错误码 |
|
||||
| `NET_ERR_BADF` | -2 | 无效 fd(含代次失效) | |
|
||||
| `NET_ERR_INVAL` | -3 | 参数无效 | |
|
||||
| `NET_ERR_NOMEM` | -4 | fd 池 / 缓冲耗尽 | |
|
||||
| `NET_ERR_NOTCONN` | -5 | 未连接 | |
|
||||
| `NET_ERR_ISCONN` | -6 | 已连接 | |
|
||||
| `NET_ERR_WOULDBLOCK` | -7 | 无数据 / 不可写(**正常轮询态,非错误**) | |
|
||||
| `NET_ERR_CONNRESET` | -8 | 对端复位 | |
|
||||
| `NET_ERR_TIMEDOUT` | -9 | 超时(recv / send chunk / listen 重开) | |
|
||||
| `NET_ERR_NOSPACE` | -10 | 芯片缓冲满 | |
|
||||
| `NET_ERR_BUSY` | -11 | 芯片忙(含 listen 端口占用) | |
|
||||
|
||||
超时参数(`net_config.h`):`NET_SEND_TIMEOUT_MS=1000`、`NET_RECV_TIMEOUT_MS=30000`。
|
||||
|
||||
## 附录 B:事件位表(`App/app/sys_events.h`)
|
||||
|
||||
| 位 | 名称 | 语义 | 置位者 | 消费者 |
|
||||
|---|---|---|---|---|
|
||||
| bit0 | `NET_READY` | 状态位 | netTask(组网成功) | ftp / ui / timeSync(`WaitAny\|NoClear` ✓) |
|
||||
| bit1 | `STORAGE_READY` | 状态位 | defaultTask(挂载 + 配置加载完成) | 同上 |
|
||||
| bit2 | `FTP_READY` | 状态位(已改为可达) | ftpTask(`lftpd_start` 之后) | 预留给依赖 FTP 的功能 |
|
||||
| bit3 | `TIMESYNC_READY` | **未置位**(仍无置位者) | 无 | 无(timeSync 实际等 NET / STORAGE) |
|
||||
| bit4 | `NET_RECONFIG` | 命令位(可消费) | defaultTask(UI 保存网口配置) | netTask(已改原子消费 ✓) |
|
||||
| bit5 | `CFG_SAVE` | 命令位(可消费) | uiTask | defaultTask(`WaitAny` 500ms + pending 锁存 ✓) |
|
||||
|
||||
> **bit3 说明**:`TIMESYNC_READY` 仍未置位,属 E-19 的残留项。因当前无消费者,
|
||||
> 影响为零;建议在 N-4 一并处置(置位或删除,不要长期留一个"假位")。
|
||||
|
||||
## 附录 C:队列清单与回传机制
|
||||
|
||||
| 队列 | 定义处 | 深度 | 条目形态 | 回传机制 | 风险 |
|
||||
|---|---|---|---|---|---|
|
||||
| `netMsgQueue` | `Src/freertos.c:166` | 8 | `net_msg_t` **按值** | 任务通知值(精确错误码 / 字节数)+ 指针字段回写 | 头阻塞已由 挂起 recv 化解;errno 竞态已由 E-03 修复(按任务隔离) |
|
||||
| syslog 队列 | `App/log/sys_log_mcu.c:218-223`(惰性创建) | 64 | 输入型(id + 静态串指针) | 无(fire-and-forget) | 结构免疫 P1;preboot 窗口已并轨 |
|
||||
| `cfgSaveQueue` | `Src/freertos.c` | 8 | 输入型(路径指针) | `s_save_pending` 锁存 + `s_save_result` 状态机 | 协议无损 ✓ |
|
||||
|
||||
---
|
||||
|
||||
*报告完。2026-09-25 重写(**重写时点**:已闭环 33 项移入 §2 索引,未闭环 26 项全部回到
|
||||
`v2-on-ui` 当前代码逐项复核,新增 **E-24 / E-26 / E-27 / E-28 / E-61 / E-62** 及
|
||||
**E-59 门禁条**)。审计阶段未修改任何代码、未执行构建。*
|
||||
|
||||
*2026-09-25 同日后续:依 §5 第一档 #3 完成 **E-03 修复**(错误码改按任务隔离,删除全局
|
||||
`s_net_errno` → `s_net_errno_slots[8]` + `net_set_errno()` + `NET_ERR_RETURN_1()` 宏,
|
||||
共替代 82 处赋值-返回对;`net_get_errno()` 对外语义不变)。构建 0 错误 0 警告、
|
||||
cppcheck 无告警、`git diff --check` 干净、编码无 `U+FFFD` 且 BOM 状态一致;BSS +64 B。
|
||||
未闭环数量 26 → **25**(P1 6 → 5)。**台架硬件闭环未执行**——本机 COM6 未枚举
|
||||
(ST-Link 虚拟串口不在,`run_boot_test.py` 报 `open failed`)→ E-03 待补台架回归
|
||||
(建议复用既有 FTP/UI 推流路径 + `net_test_task` Phase 7 的 errno 判定分支)。*
|
||||
|
||||
*2026-10-04 订正:同步 2026-10-03 的 **E-34 / E-04 / GD5F 族(E-10 / E-42 / E-53 / E-56 / E-57)**
|
||||
与 **E-60** 闭环结果——**§0 未闭环 25 → 17**(P1 5→2、P2 20→15),**§2 已闭环 33 → 41**
|
||||
(P0 3→4、P1 15→18、P2 15→19),§3 各类计数(A 10→5、C 8→5)与 §4 矩阵(清空 GD5F 列)
|
||||
同步更新。本次订正**仅改计数与索引,未改动任何审计结论**。*
|
||||
|
||||
*2026-10-10 闭环(E-59 门禁的 TPAFE 前置三项,`Drivers/BSP/TPAFE5160/`):**E-44**——
|
||||
`read_channels()` 要求"一帧读下来 FRSTDATA 必须发生跳变"(板上 R24 4.7k 上拉,芯片死亡则钉死为高),
|
||||
`tpafe5160_init()` 增**首帧自检**,不满足即返回 `-3` + `[ERR]`;**E-45**——`s_ready` 电平标志改
|
||||
`s_frame_seq` 帧序号(只增不清),`start_conv_irq` 不再清标志;**E-58**——删 `get_buf` / `data_ready` /
|
||||
`clear_ready`(删除前确认全仓库**零调用者**),新增临界区原子快照 `tpafe5160_snapshot()` 与
|
||||
`tpafe5160_frstdata_err()`。`@build` 0 错误 0 警告;真机 `@test` PASS + 烧录回读 `No difference found`;
|
||||
开机日志 `[ADC] Init OK` 现只在自检帧通过后才打印 → 证明 FRSTDATA 在本板确实跳变、判据不是空转。
|
||||
**§0 未闭环 17 → 16**(P1 2→1)、**§2 已闭环 41 → 44**(P1 18→21)、§3.1 A 类 5→4、§4 矩阵去掉 E-58。
|
||||
门禁本身已写入 `AGENTS.md`(与"改栈前跑 `stack_report.py`"同级)。*
|
||||
+274
-353
@@ -2,83 +2,73 @@
|
||||
|
||||
| 项目 | 内容 |
|
||||
|------|------|
|
||||
| 审查日期 | 2026-09-18 |
|
||||
| 代码基线 | `HEAD = 2d0ec35`(工作树干净,98+ 提交) |
|
||||
| 固件基线 | `MDK-ARM/STM32F407-Demo/STM32F407-Demo.map`,构建于 2026-09-16 12:33,0 Error / 0 Warning |
|
||||
| **现状复核** | **2026-10-11**,复核基线 `HEAD = 54d6d2d`(分支领先 `origin/v2-on-ui`,未推送);固件基线换为 2026-10-11 00:38 链接的 `.map`。⚠ 复核期间分支又前进(ADC L2 相量层 / L1-6 有效性校验 / `adcTask` 抬栈),其数字影响已在 §5.1"基线口径说明"逐项量化,**不改变任何结论** |
|
||||
| **销项状态** | 本报告采用**修复即销项**:已修复项的正文与表格行已删除(**874 → 733 行**,114 KB → 84 KB),去处清单见文末**变更记录**;未闭环清单见 **§0.2 / §0.4** |
|
||||
| 审查范围 | 仓库全量(2,013 个受版本控制文件);重点为自研代码 24,353 行(108 文件)与构建产物内存画像 |
|
||||
| 审查日期 | 2026-09-18(初版) |
|
||||
| **最近复核** | **2026-10-14**,基线 `HEAD = 803f771`(分支 `v2-on-ui`,工作树干净);固件基线 = 2026-10-14 22:55 链接的 `MDK-ARM/STM32F407-Demo/STM32F407-Demo.map`(0 Error / 0 Warning)。⚠ 2026-10-15 06:41 该 `.map` 被**含未提交改动**的一次重链接覆盖(Code +48 B),本报告数字**不追那次构建**——复跑 `ram_report.py` 会看到小差异,属正常 |
|
||||
| **销项状态** | 本报告采用**修复即销项**:已修复项的正文与表格行已删除,去处见文末**已销项条目的记录去处**;未闭环清单见 **§0.2 / §0.4** |
|
||||
| 审查范围 | 仓库全量(2,466 个受版本控制文件 / 79.3 MB);重点为自研代码 50,874 行(191 文件)与构建产物内存画像 |
|
||||
| 审查方式 | 静态审查 + 链接图(.map)量化分析 + 构建脚本/门禁核对;**未做上机动态验证**(除特别标注外) |
|
||||
| 目标 | 结构合理性、文档分布合理性、模块设计合理性、改进路线图、内存优化、UI 标准化 |
|
||||
|
||||
> **与既有文档的关系**:本报告不重复 `docs/任务规划/README.md`(逐条缺陷台账)与 `docs/内存管理/RAM使用分析与优化方案.md`(内存专项方案),而是做**体系层评审 + 量化补强 + 新增发现**。新增发现统一编号 `N-xx`,已在台账中的条目按 `P1-x/P2-x/P3-x` 引用。
|
||||
> **与既有文档的关系**:本报告不重复 [`../任务规划/README.md`](../任务规划/README.md)(逐条缺陷台账 + **推进顺序唯一权威**)与 `../内存管理/RAM使用分析与优化方案.md`(内存专项方案),而是做**体系层评审 + 量化补强 + 新增发现**。
|
||||
>
|
||||
> **销项约定(2026-10-11 起)**:本报告采用与登记簿相同的**「修复即销项」**——问题修复后其分析正文与表格行**从本报告删除**,完整记录沉淀到对应模块文档(去处清单见文末**变更记录**)。因此本报告**只呈现未闭环问题**,不再随时间膨胀。
|
||||
> **编号口径**:本报告自有编号 `N-xx / D-x / S-x / R-x / F-x / U1~U5`,⚠ **与登记簿同名不同义**(报告 N-16 = 日志逐条开关,登记簿 N-16 = A2/A4 负向台架;报告 S-3 = 注册反向校验,登记簿 S-3 = USART1 TX-only 根治)→ **引用一律带文档名**。未闭环项已于 2026-10-11 并轨进登记簿(新编 `N-19`~`N-29` + U 簇,出处列保留本报告编号);**本报告编号本身不回改、不重排**(`../编号规范.md`)。
|
||||
>
|
||||
> **销项约定**:问题修复后其分析正文与表格行**从本报告删除**,完整记录沉淀到对应模块文档。因此本报告**只呈现未闭环问题**,不随时间膨胀。
|
||||
|
||||
---
|
||||
|
||||
## 0. 执行摘要
|
||||
|
||||
### 0.1 六维评分(2026-09-18 评级 + 2026-10-11 复核)
|
||||
### 0.1 六维评分(2026-10-14 复核)
|
||||
|
||||
| 维度 | 评分 | 一句话结论 | **2026-10-11 复核** |
|
||||
|------|------|-----------|---------------------|
|
||||
| 项目结构 | **B+** | 六层分层真实可执行、命名一致、门禁到位;主要问题是 **BSP 层承载业务模块**、**双构建清单漂移**、**5 个源文件两边都不编译** | **A−**:反向依赖 4→3 处、`net_cfg_legacy` 删除、CI + 22 钩子成型、`App/algo/` 分层补齐;❌ 但"存在但未注册"的**反向校验仍缺**(`check_registration.py` 未建),`rs485_task.c` / `lftpd_log.c` 仍两边不编 |
|
||||
| 文档分布 | **B-** | 工程文档密度与深度高于同级嵌入式项目;主要问题是 **文档占仓库 60% 体积(其中芯片手册图片 40.5 MB)**、**README 任务表 4× 过期**、**约 18 条断链**、**文档承诺了不存在的工具/台账** | **A−**:工程文档 **28,895 行**(翻倍)、`docs/README.md` 索引 + `docs/文档规范.md` + 三档一致性门禁全部落地,`check_doc_links --all` = **129 文档 0 失效**;⚠ 新风险:AGENTS.md 自身数字开始落后实测("18 钩子"实为 22、"清单 23 项"实为 29) |
|
||||
| 模块设计 | **B** | 配置引擎、网络串行化、就绪屏障、FatFs 互斥等设计成熟;主要问题是 **失败路径普遍"死循环/静默降级"**、**无看门狗**、**FTP 无鉴权**、**cfg_file 依赖注定失败的 malloc** | **B+**:看门狗(IWDG + 心跳位图 + 4 个 Fault 现场 + `.noinit`)、ADC 全链(TIM3 事件驱动 + DMA 乒乓)、卷锁、墙钟均已落地;❌ **FTP 仍无鉴权**、RS485 仍无协议栈(E-50/E-49 未修)、`Error_Handler` 仍 `while(1)` |
|
||||
| 内存使用 | **C** | SRAM1 已用 96.6%(余 4,488 B),**64 KB CCM 完全空转**,FreeRTOS 堆被 6 条任务栈吃掉 2/3,**栈/堆水位零观测** | **B**:堆 49,184 B 迁 CCM → SRAM1 降到 **69.8%(余 39,584 B)**、CCM 用 75.1%;栈/堆三面观测常开(`[STACK]` + `stack_report.py` + `configCHECK_FOR_STACK_OVERFLOW=2`);🟡 LVGL 池 40,960 B 未迁也未下调;⚠ 新硬约束:**从堆分配的缓冲不可被 DMA 直接寻址** |
|
||||
| Flash 使用 | **B+** | 仅用 23.4%;但 **≈50 KB(20% 镜像)是可证明的死代码**(LVGL 配置漂移所致) | **A−**:2026-10-11 落地 F-1/F-2/F-3(两份 `lv_conf.h` 对齐、只留 I1 绘制核、零控件、无 flex/grid)→ **省 64,576 B**,占用降到 **20.1%(211,024 B)**;剩余 F-4/F-5/F-6 ≈10 KB 待逐项实测 |
|
||||
| UI 标准化 | **B-** | 已有"声明源→生成器→表驱动"的正确骨架;缺**设计令牌层**、**页面原型库**、**注册自动化**、**golden 回归**,42 个菜单叶子仅 7 个有内容页 | **B**:**golden 回归已落地**(`simulator/tests/` 4 脚本:菜单 8 状态全像素 + 内容页逐字节黄金参考 + 协议 e2e);❌ 令牌层 / 组件库 / 页注册表未动,现口径为 **33 叶子 / 6 个有内容页** |
|
||||
| 维度 | 评分 | 一句话结论 | 仍开放的主要缺口 |
|
||||
|------|------|-----------|-----------------|
|
||||
| 项目结构 | **A−** | 六层分层真实可执行、命名一致、门禁到位;反向依赖控制在 4 处 | `NETCFG`/`UI` 语义层错位(S-1)、4 处裸 `extern`(S-2)、`rs485_task.c` 仍在注册白名单里等 B2 |
|
||||
| 文档分布 | **A−** | 工程文档 **88 篇 / 31,416 行**,`docs/README.md` 索引 + `docs/文档规范.md` + 三档一致性门禁全部落地,`check_doc_links --all` = 0 失效 | **D-1**:`docs/` 占仓库 **71.8%**、手册图片 **36.3 MB**、`.git` 已 **235 MB**(已决策暂不处理,登记观察) |
|
||||
| 模块设计 | **A−** | 看门狗(IWDG + 心跳位图 + 4 个 Fault 现场 + `.noinit`)、就绪屏障、卷锁、FTP 鉴权、`Error_Handler` 自恢复、ADC 全链均已落地 | **N-12/N-13** dhara 移植两处缺陷(数据丢失风险)、**N-16** 日志逐条开关、驱动层无统一错误码约定(S-5)、RS485 无协议栈(随 B2 暂缓) |
|
||||
| 内存使用 | **B** | 堆迁 CCM + 栈/堆三面观测常开 + `mem-budget` 92% 门禁;SRAM1 **74.9%** | **LVGL 池 + UI 两份缓冲 54,146 B 仍在 SRAM1**,而 CCM 只剩 **7,904 B** → R-2 后半被堵死,须先 R-9(§5.3) |
|
||||
| Flash 使用 | **A−** | F-1/F-2/F-3 落地省 64,576 B → 占用 **22.0%(231,036 B)** | F-4/F-5/F-6 ≈10 KB + 编译时长(§5.4) |
|
||||
| UI 标准化 | **B** | golden 回归已建(`simulator/tests/` 四脚本,含池水位门禁) | 无令牌层 / 无组件库 / 无页注册表(手写 `case` 仍在)、**27 页**未落地、golden 与字符集差集未挂门禁(§6) |
|
||||
|
||||
### 0.2 未闭环问题(Top 5,2026-10-11)
|
||||
|
||||
> 已修复/已消解的条目按「修复即销项」从本报告删除,完整记录见对应模块文档(去处清单见文末**变更记录**)。
|
||||
### 0.2 未闭环问题(Top 3,2026-10-14)
|
||||
|
||||
| # | 编号 | 问题 | 影响 | 现状 |
|
||||
|---|------|------|------|------|
|
||||
| 1 | **N-02** | `lftpd.c cmd_pass` 对任意口令无条件回 `230`(现 `:375-379`;`cmd_user :553-557` 同) | 局域网内任意主机可读写 `/config.ini`(含 IP/MAC/网关)→ 可远程断网;单连接 CH395F 上还可挤掉 UI/对时服务 | ❌ 一行未改;⚠ 且**不在 `../任务规划/README.md` 登记簿内** → 建议补登 |
|
||||
| 2 | **N-04 / R-2 剩余** | LVGL 池 `work_mem_int` 40,960 B + UI 帧/绘制 `ui_port.o` 6,420 + UI 发送 `ui_net_sink.o` 6,766 = **54,146 B 仍在 SRAM1** | 堆迁 CCM 后 **CCM 只剩 16,304 B**,这 54 KB 装不下 → R-2 后半段被堵死 | 🟡 必须先做 R-9(`LV_MEM_SIZE` 40 KB→16 KB)或 R-4(帧副本 4→2)腾出空间 |
|
||||
| 3 | **N-12 / N-13** | `dhara_nand_is_free()` 只查页首 64 B;`dhara_nand_copy()` 不处理 `DHARA_NO_PAGE` 哨兵 | 映射恢复误判 → **数据丢失风险**(低概率、后果重);哨兵页号被当真实页 → 未定义行为 | ❌ 两处原样;⚠ 也不在登记簿 |
|
||||
| 4 | **N-06 残余** | `rs485_task.c`、`lftpd_log.c` 既不在 uvprojx 也不在 simulator | "写了不编译"= 死代码 + 误导 | ❌ 未处理;❌ `check_registration.py`(S-3)仍未建 |
|
||||
| 5 | **N-16** | 日志每条记录一次 `f_open + f_write + f_close`(`sys_log_mcu.c:123-140`) | 每条日志 2–4 次 NAND 页读写;UI 翻记录逐条 open/seek/close | ❌ 未办(仅 `FIL` static 化省 528 B 栈) |
|
||||
| 1 | **N-12 / N-13**(登记簿 **N-21**,W2) | `dhara_nand_is_free()` 只查页首 64 B(`nand_ftl.c:152-179`);`dhara_nand_copy()` 不处理 `DHARA_NO_PAGE` 哨兵(`:204-216`) | 映射恢复误判 → **数据丢失风险**(低概率、后果重);哨兵页号被当真实页 → 未定义行为 | ❌ 两处原样;至今只能靠人工读代码发现(主机侧无 dhara 移植层测试) |
|
||||
| 2 | **R-2 剩余 / R-9**(登记簿 **N-27**,W3) | LVGL 池 `work_mem_int` 40,960 B + `ui_port.o` 6,420 + `ui_net_sink.o` 6,766 = **54,146 B 仍在 SRAM1** | 堆 56 KB 占掉 CCM 后 **CCM 只剩 7,904 B**,这 54 KB 装不下 → R-2 后半段堵死 | 🟡 必须先 R-9(`LV_MEM_SIZE` 40→16 KB)+ 缩堆腾 CCM,解锁链 → `../内存管理/RAM预算台账.md` §3 |
|
||||
| 3 | **N-16**(登记簿 **N-24**,W4) | 日志每条记录一次 `f_open + f_write + f_close`(`sys_log_mcu.c:124-141`) | 每条日志 2–4 次 NAND 页读写;UI 翻记录逐条 open/seek/close | ❌ 未办(仅 `FIL` static 化省 528 B 栈) |
|
||||
|
||||
⚠ 另有两条**不在上表但需排期**:`Error_Handler` 仍 `__disable_irq(); while(1){}`(N-03c,§4.1)、`.git` 已膨胀到 **149 MB**(D-1,§3.1)。
|
||||
⚠ 另有两条**不在上表但需知晓**:`.git` 已膨胀到 **235 MB**(D-1,§3.1,2026-10-11 决策"暂不处理、登记观察");`rs485_task.c` 仍不在两端构建清单里——**这是 E-59 门禁下的刻意缺口**(随 B2 暂缓),已登记在 `check_registration.py` 的 `KNOWN_GAPS`,不是漏注册。
|
||||
|
||||
### 0.3 三条主线建议
|
||||
### 0.3 两条主线建议
|
||||
|
||||
1. **把内存从"卡死"变"富裕"**:启用 CCM 承载 LVGL 池与 UI 帧缓冲(≈54 KB),同时补齐栈/堆水位自检,作为后续功能的预算来源(§5.3)。
|
||||
2. **把失败路径从"死循环"变"可恢复"**:IWDG + 任务心跳位图 + 统一的"降级但活着"策略(§4.1)。
|
||||
3. **把 UI 从"每页手写"变"声明 + 原型库"**:令牌层 → 原型库 → 生成器补全注册 → golden 回归,使新增一页的成本从 8 处手工改动降到 1 处声明(§6)。
|
||||
> **推进顺序的唯一权威是 [`../任务规划/README.md`](../任务规划/README.md) §2**;本节只是体系评审视角的两条结构性建议,不另立顺序。
|
||||
|
||||
1. **把内存从"卡死"变"富裕"**:先按 R-9 下调 LVGL 池、再缩堆腾出 CCM,把 LVGL 池与 UI 帧缓冲(≈54 KB)搬进 CCM,作为后续功能的预算来源(§5.3)。
|
||||
2. **把 UI 从"每页手写"变"声明 + 原型库"**:令牌层 → 原型库 → 生成器补全注册 → golden 入门禁,使新增一页的成本从 8 处手工改动降到 1 处声明(§6)。
|
||||
|
||||
---
|
||||
|
||||
## 0.4 未闭环清单(2026-10-11 复核)
|
||||
## 0.4 未闭环清单(2026-10-14 复核)
|
||||
|
||||
> 只列**未办 / 半办**项;已修项已按「修复即销项」删除(去处见变更记录)。图例:❌ 未办 / 🟡 半办。
|
||||
> **统一排序与推进**:本表各项已于 2026-10-11 并入 [`../任务规划/README.md`](../任务规划/README.md) §2 与 [`../任务规划/登记簿.md`](../任务规划/登记簿.md)
|
||||
> (新编号 N-19~N-29 + U 簇,出处列保留本报告编号);**顺序权威在 `docs/任务规划/README.md` §2,本表为评审快照**。
|
||||
> ⚠ 本报告编号与登记簿同名不同义(报告 N-16 = 日志逐条开关,登记簿 N-16 = A2/A4 负向台架)→ 引用带文档名。
|
||||
> 只列**未办 / 半办**项;已修项按「修复即销项」删除(去处见文末)。图例:❌ 未办 / 🟡 半办。
|
||||
> **顺序权威在 [`../任务规划/README.md`](../任务规划/README.md) §2,本表为评审快照**;登记簿编号在括号内。
|
||||
|
||||
| 类别 | 编号 | 未闭环内容 | 下一步 |
|
||||
|------|------|-----------|--------|
|
||||
| **安全** | **N-02** ❌ | FTP 无条件 `230`,任意主机可读写 `/config.ini` | 补登登记簿 + `[ftp] user/pwd_hash` 定长比较 + 失败计数锁定 + 生产默认只读 |
|
||||
| 安全 | N-03c ❌ | `Error_Handler` 仍 `__disable_irq(); while(1){}`(`Src/main.c:274-282`) | 统一降级策略:记自检 + 禁用该子系统 + 其余照常 |
|
||||
| **数据正确性** | **N-12 / N-13** ❌ | `is_free` 只查页首 64 B;`copy` 不处理 `DHARA_NO_PAGE` | 补登登记簿 + 整页(或首/中/尾)扫描 + 返回 `DHARA_E_UNSUPPORTED` |
|
||||
| 数据正确性 | N-14 🟡 | 写回缓存无空闲/掉电强制 flush(整页写与换页已 flush) | 空闲 N ms 由 defaultTask flush |
|
||||
| **内存 RAM** | **R-2 剩余** 🟡 | LVGL 池 + UI 两份缓冲 54,146 B 仍在 SRAM1;CCM 只剩 16,304 B | 先做 R-9 或 R-4 腾 CCM,再迁 |
|
||||
| 内存 RAM | R-3 / R-4 / R-5 / R-6 / R-9 ❌ | 页缓冲未合并 / UI 帧 4 副本 / `configMAX_PRIORITIES` 仍 56 / 栈仍动态 / `LV_MEM_SIZE` 仍 40 KB | R-9 最省力(池水位门禁数据已具备);R-6 前置条件已满足 |
|
||||
| 内存 RAM | N-11 🟡 | NAND 仍直 DMA 调用方缓冲(已加运行时守卫、阈值 1024) | 补编译期/启动期地址断言 + **新铁律:堆缓冲不可被 DMA 直接寻址** |
|
||||
| 内存 RAM | §5.5 ✅ | 三件套已建(2026-10-12):`scripts/ram_baseline.tsv` + `docs/内存管理/RAM预算台账.md` + `mem-budget` 钩子(92% + Top-10 附表) | 已闭环;R-9/R-2 排期解锁见登记簿 N-27(W3) |
|
||||
| **Flash** | **F-4 / F-5 / F-6** ❌ | 剩余可评估 ≈10 KB(`box_shadow` 3,246 / `draw_sw_img` 2,960 / `bin_decoder` 1,972 / `image_decoder` 952 / `triangle` 930)+ 双精度 `dadd` 等 ≈1 KB;uvprojx 仍挂 201 个 LVGL `.c`(F-2 后均为空 TU,省的是编译时长) | 逐项实测再关;⚠ `mask`/`mask_rect`/`grad` 是文字与矩形绘制的必经路径,**不可盲关** |
|
||||
| **性能/资源** | N-09 / N-16 / P2-8 / PHY / P3-x / rs485 ❌ | PASV 每次新建监听;日志每条 open/write/close;`NET_RECV_TIMEOUT_MS 30000`;PHY 强制 100M 无自协商回退;`NET_MAX_SOCKETS 8` 与单连接语义不符;`HAL_Delay(1)` 阻塞 DE | 见 §4.2 / §4.5 / §4.7 各行建议 |
|
||||
| **结构** | S-1 / S-2 / S-3 / S-4 / N-06 残余 ❌ | `NETCFG`/`UI` 语义层错位;4 处裸 `extern`;**无注册反向校验**;`app_cfg.h` 开关未接线未删;`rs485_task.c`/`lftpd_log.c` 两边不编 | `check_registration.py` 是其中唯一"1 小时工作量"的一条 |
|
||||
| **文档/仓库** | D-1 ❌ | 图片 36.3 MB 仍在仓;**`.git` 已 149 MB** | 降采样 / 拆 submodule / LFS 三选一 **+ 一次 `git filter-repo` 历史重写** |
|
||||
| 文档/仓库 | 语义断链 ❌ | 两份 UI 文档仍指 `tools/ui_mock/`(不存在,实为 `simulator/tests/`) | 改指 + 挂进 `ui-verify` |
|
||||
| 文档/仓库 | 元信息漂移 ⚠ | AGENTS.md 写"18 钩子"(实 22)、"清单 23 项"(实 29) | 纳入生成/校验(同任务表做法) |
|
||||
| **UI** | U1 / U2 / U3 / U5 ❌ | 无令牌层、无组件库、无页注册表(手写 `case` 仍在);**27 页**未落地 | 按 §6.5 顺序,U4 的 golden 已可当 U1 的验收工具 |
|
||||
| UI | U4 残余 🟡 | golden 已建但未挂 pre-commit;字符集差集检查仍是约定 | 两个脚本入门禁 |
|
||||
| **测试** | P1-10 🟡 / 覆盖率 ❌ | CH395F 套件收尾两步;无覆盖率概念;主机侧对 `lftpd`/`dhara` 移植层无测试 | N-12/N-13 这类缺陷至今只能靠人工读代码发现 |
|
||||
| **台账** | ⚠ | N-02、N-12/N-13 **漏登**;报告 N-18 与登记簿 N-18 **同号不同义** | 补登 + 引用一律带文档名 |
|
||||
| **数据正确性** | **N-12 / N-13** ❌(N-21,W2) | `is_free` 只查页首 64 B;`copy` 不处理 `DHARA_NO_PAGE` | 整页(或首/中/尾)扫描 + 返回 `DHARA_E_UNSUPPORTED` + **必须配主机侧移植层单测** |
|
||||
| **内存 RAM** | **R-2 剩余** 🟡(N-27,W3) | LVGL 池 + UI 两份缓冲 54,146 B 仍在 SRAM1;CCM 只剩 7,904 B | 先 R-9 + 缩堆腾 CCM,再迁(解锁链 → `../内存管理/RAM预算台账.md` §3) |
|
||||
| 内存 RAM | R-3 / R-4 / R-6 / R-9 ❌(N-27,W3) | 页缓冲未合并 / UI 帧 4 副本 / 栈仍动态 / `LV_MEM_SIZE` 仍 40 KB | R-9 最省力(池水位门禁数据已具备);R-6 前置条件已满足。**R-5 已判定不可行**(§5.3) |
|
||||
| 内存 RAM | N-14 🟡(N-22,W4) | 写回缓存无空闲/掉电强制 flush(整页写与换页已 flush) | 空闲 N ms 由 defaultTask flush |
|
||||
| **Flash** | **F-4 / F-5 / F-6** ❌(N-28,W4) | 剩余可评估 ≈10 KB(`box_shadow` 3,246 / `draw_sw_img` 2,960 / `bin_decoder` 1,972 / `image_decoder` 952 / `triangle` 930)+ 双精度 `dadd` 等 ≈1 KB;uvprojx 仍挂 201 个 LVGL `.c`(F-2 后均为空 TU,省的是编译时长) | 逐项实测再关;⚠ `mask`/`mask_rect`/`grad` 是文字与矩形绘制的必经路径,**不可盲关** |
|
||||
| **性能/资源** | N-09 / PHY / P3-x / rs485 DE ❌(N-25,W4) | PASV 每次新建监听;PHY 强制 100M 无自协商回退;`NET_MAX_SOCKETS 8` 与单连接语义不符;`HAL_Delay(1)` 阻塞 DE(DE 项随 B2 暂缓) | 见 §4.2 / §4.7 各行建议 |
|
||||
| **结构** | S-1 / S-2 / S-4 ❌ | `NETCFG`/`UI` 语义层错位;4 处裸 `extern`;`app_cfg.h` 开关未接线未删 | 随登记簿 C5 处置;`rs485_task.c` 随 B2 一并出白名单 |
|
||||
| **存储/日志** | N-15 🟡 / P2-10 ❌ | `nand_ftl` 三块 2 KB 页缓冲未合并(BBT 缓冲已收紧);容量轮转 `f_unlink` 与 UI 读并发未纳入卷锁 | R-3 评估;卷锁覆盖面 → 登记簿 S-5 |
|
||||
| **驱动规范** | S-5 ❌ | 无统一"错误码 + 超时 + 重试 + 自检上报"约定(`GD5F_OK` / `0` / `bool` 混用) | 定义 `bsp_err_t` + `bsp_retry()` 写入 `docs/代码规范/` |
|
||||
| **仓库** | D-1 ❌(N-29,W7) | 图片 36.3 MB 仍在仓;**`.git` 已 235 MB** | 降采样 / 拆 submodule / LFS 三选一 **+ 一次 `git filter-repo` 历史重写**;**已决策暂不处理、登记观察** |
|
||||
| **UI** | U1 / U2 / U3 / U5 ❌(U 簇,W6) | 无令牌层、无组件库、无页注册表(手写 `case` 仍在);**27 页**未落地 | 按 §6.5 顺序,U4 的 golden 已可当 U1 的验收工具;**本轮不排期** |
|
||||
| UI | U4 残余 🟡(U 簇,W6) | golden 已建但未挂 pre-commit;字符集差集检查仍是约定 | 两个脚本入门禁 |
|
||||
| **测试** | P1-10 🟡 / 覆盖率 ❌ | CH395F 套件收尾两步(构建实测链接 + `@test` 闭环);无覆盖率概念;主机侧对 `dhara` 移植层无测试 | N-12/N-13 这类缺陷至今只能靠人工读代码发现 |
|
||||
|
||||
---
|
||||
|
||||
@@ -88,22 +78,23 @@
|
||||
|
||||
| 数据 | 来源 | 可信度 |
|
||||
|------|------|--------|
|
||||
| 内存/Flash 占用 | `.map` 的 component 表(214 个含码对象,列序 `Code incData RO RW ZI Debug Name`) | 高(构建产物,权威) |
|
||||
| 总量 | map 尾部 `Total RO / Total RW / Total ROM` + `Program Size` | 高 |
|
||||
| 内存/Flash 占用 | `.map` 的 component 表(237 个含码对象,列序 `Code incData RO RW ZI Debug Name`) | 高(构建产物,权威) |
|
||||
| 总量 | map 尾部 `Total RO / Total RW / Total ROM` + `Execution Region` 表 | 高 |
|
||||
| 依赖方向 | 逐文件 `#include` 扫描 + map 的 `refers to` 交叉表 | 高 |
|
||||
| 构建注册 | `MDK-ARM/STM32F407-Demo.uvprojx` + `simulator/CMakeLists.txt` + git 文件清单三方对齐 | 高 |
|
||||
| 文档链接 | 全量 md 链接解析(剔除设备路径 `PB12`/通配/占位后 706 → 94 未解析 → 人工分诊) | 中高(人工分诊) |
|
||||
| 构建注册 | `MDK-ARM/STM32F407-Demo.uvprojx` + `simulator/CMakeLists.txt` + git 文件清单三方对齐(已机械化:`scripts/check_registration.py`) | 高 |
|
||||
| 文档链接 | `scripts/check_doc_links.py --all`(含 `--sections-strict`) | 高(门禁) |
|
||||
|
||||
### 1.2 复现命令(本报告所有数字可重跑)
|
||||
|
||||
```powershell
|
||||
# 1) 构建体量
|
||||
Select-String -Path 'MDK-ARM\STM32F407-Demo\STM32F407-Demo.map' -Pattern 'Total RO Size|Total RW Size|Total ROM Size'
|
||||
# 1) 构建体量(三区水位 + Top-10 RW+ZI)
|
||||
& '.venv\Scripts\python.exe' scripts/ram_report.py
|
||||
& '.venv\Scripts\python.exe' scripts/ram_baseline.py --trend
|
||||
# 2) MicroLIB C 堆真实大小(应为 0x200 = 512 B)
|
||||
Select-String -Path 'MDK-ARM\STM32F407-Demo\STM32F407-Demo.map' -Pattern '__heap_base|__heap_limit|HEAP'
|
||||
# 3) 对象级 RW+ZI 排行(本报告脚本:obj_sizes2.py,注意 map 组件表是 6 个数值列)
|
||||
# 4) 三方文件注册对齐(uvprojx / CMakeLists / git)
|
||||
# 5) 仓库体量:git ls-files -z | 逐个统计字节(必须用 -z,否则中文名会被控制台代码页破坏)
|
||||
# 3) 三方文件注册对齐(uvprojx / CMakeLists / git)
|
||||
& '.venv\Scripts\python.exe' scripts/check_registration.py --strict
|
||||
# 4) 仓库体量:git ls-files -z | 逐个统计字节(必须用 -z,否则中文名会被控制台代码页破坏)
|
||||
```
|
||||
|
||||
> ⚠️ **踩坑记录**(供后续审查复用):
|
||||
@@ -116,132 +107,123 @@ Select-String -Path 'MDK-ARM\STM32F407-Demo\STM32F407-Demo.map' -Pattern '__heap
|
||||
| 术语 | 定义 |
|
||||
|------|------|
|
||||
| 自研代码 | `App/`、`Drivers/BSP/`(不含 `Lib/`、`Middlewares/`、HAL/CMSIS)、`test/`;不含 CubeMX 生成的 `Src/`、`Inc/` |
|
||||
| Flash 占用 | `Code + RO-data`(基线 245,384 B → **2026-10-11 复核 273,860 B**);`ROM` 再加 `RW-data` 初始化表(246,016 → **274,060 B**) |
|
||||
| RAM 占用 | `RW-data + ZI-data`(基线 126,584 B,全部压在 SRAM1)。**2026-10-11 复核:140,720 B,已跨两个区域** = SRAM1 `RW_IRAM1` 91,488 / 131,072(**69.8%**)+ CCM `RW_CCM` 49,184 / 65,280(**75.3%**)+ `UNINIT_CCM` 48 B(`.noinit` 崩溃现场保留区)。⚠ 口径变化:原报告"CCM 不在 scatter 内计 0"已不成立 |
|
||||
| Flash 占用 | `Code + RO-data` = `ER_IROM1` **231,036 B(22.0% of 1 MB)**;`ROM` 再加 `RW-data` 初始化表 = 231,324 B |
|
||||
| RAM 占用 | `RW-data + ZI-data`,**跨两个区域** = SRAM1 `RW_IRAM1` **98,144 / 131,072(74.9%)** + CCM `RW_CCM` **57,376 / 65,280(87.9%)** + `UNINIT_CCM` 48 B(`.noinit` 崩溃现场保留区)。⚠ 原报告"CCM 不在 scatter 内计 0"的口径已不成立 |
|
||||
| "死代码" | 该对象在镜像中有码,但其功能被工程配置(如 `LV_COLOR_DEPTH 1`)或调用点扫描(零调用者)证明不可达 |
|
||||
|
||||
> **内存数字的权威源**:区域水位与子系统配额由 `../内存管理/RAM预算台账.md`(受管区,`ram_baseline.py --write` 生成)持有,趋势在 `scripts/ram_baseline.tsv`。本报告只在支撑结论处引用,不与之竞争事实源。
|
||||
|
||||
---
|
||||
|
||||
## 2. 项目结构合理性
|
||||
|
||||
### 2.1 规模与分布(实测)
|
||||
### 2.1 规模与分布(2026-10-14 实测)
|
||||
|
||||
| 分类 | 文件 | 行数 | 说明 |
|
||||
|------|------|------|------|
|
||||
| `App/`(自研应用) | 38 | 8,516 | 配置引擎、墙钟、日志、任务薄壳;**新增 `App/algo/`(L1 采集 + L2 相量,6 文件 1,090 行)** |
|
||||
| `Drivers/BSP/`(自研驱动/子系统) | 67 | 19,104 | 其中 **UI 子系统 6,036 行**(含 `ui_font_cn_12.c` 1,211)、NET 6,302、CH395F 2,144、GD5F 1,978、SD2506 835、TPAFE 680、NETCFG 578、RS485 310 |
|
||||
| `test/`(自研测试) | 41 | 10,855 | **`test/host/` 主机侧单测 25 文件 / 4,505 行**(2026-09-18 时不存在)+ `test/board/` 板级套件 16 文件 / 6,350 行 |
|
||||
| **自研合计** | **146** | **38,475** | 2026-09-18 基线为 **108 / 24,353** → **+38 文件 / +14,122 行** |
|
||||
| CubeMX `Src/`+`Inc/` | 26 | 5,459 | 受 USER CODE 标记保护 |
|
||||
| `simulator/` | 10 | 2,462 | PC SDL2 宿主 |
|
||||
| 第三方 `Lib/` | 958 | 529,916 | LVGL 9.3(423 个 `.c` / 421,546 行)、FreeRTOS、FatFs、dhara、lftpd |
|
||||
| `App/`(自研应用) | 64 | 13,841 | 配置引擎、墙钟、日志、任务编排;**`App/algo/`(L1~L3 + 测频 + 定值/SOE)14 文件 / 2,855 行** |
|
||||
| `Drivers/BSP/`(自研驱动/子系统) | 76 | 21,845 | NET 8,264、UI 6,073(含 `ui_font_cn_12.c`)、CH395F 2,641、GD5F 2,035、SD2506 835、NETCFG 766、TPAFE 680、RS485 310 |
|
||||
| `test/`(自研测试) | 51 | 15,188 | **`test/host/` 主机侧单测 33 文件 / 7,634 行** + `test/board/` 板级套件 18 文件 / 7,554 行 |
|
||||
| **自研合计** | **191** | **50,874** | 2026-09-18 基线为 108 / 24,353 |
|
||||
| CubeMX `Src/`+`Inc/` | 26 | 5,528 | 受 USER CODE 标记保护 |
|
||||
| `simulator/`(自研部分,不含 SDL2 SDK) | 10 | 2,665 | PC SDL2 宿主 |
|
||||
| 第三方 `Lib/` | 958 | 529,983 | LVGL 9.3、FreeRTOS、FatFs、dhara、lftpd |
|
||||
|
||||
**评价**:自研体量与第三方体量比约 **1:14**(原 1:20,自研涨了一倍半),仍属典型的"薄自研 + 厚中间件"。这决定了**结构审查的重点不在自研代码内部,而在"自研如何约束第三方"**——§5.4 曾量化这层约束(`lv_conf.h`)失守的代价:**64,576 B 死代码**(2026-10-11 已修)。
|
||||
**评价**:自研体量与第三方体量比约 **1:10.4**(基线 1:20),仍属"薄自研 + 厚中间件"。这决定了**结构审查的重点不在自研代码内部,而在"自研如何约束第三方"**——§5.4 量化的 `lv_conf.h` 约束失守代价(64,576 B 死代码)已修,但**两份 `lv_conf.h` 必须同一特性子集**这条硬约束如今靠 `lv-conf-sync` 钩子守住,属"约束被机械化"的正例。
|
||||
|
||||
### 2.2 分层与依赖方向
|
||||
|
||||
实测自研层间的**全部反向依赖**(BSP → App)——2026-10-11 复核为 **3 处**(原 4 处,`net_cfg_legacy.c` 已随旧档迁移路径整体删除,见 §2.4):
|
||||
实测自研层间的**全部反向依赖**(BSP → App)——2026-10-14 复核为 **4 处**:
|
||||
|
||||
| 位置 | 反向 include | 判定 |
|
||||
|------|-------------|------|
|
||||
| `Drivers/BSP/NETCFG/net_cfg.c:31` | `cfg_file.h` | 可接受但需说明:NETCFG 实为"业务配置模块",放在 BSP 层是历史命名 |
|
||||
| `Drivers/BSP/NETCFG/ftp_cfg.c:17` | `cfg_file.h` | 同上(FTP 鉴权配置随 `net_cfg` 落在同一目录) |
|
||||
| `Drivers/BSP/UI/ui_page_runlog.c:19` | `sys_log.h` | UI 读日志属正常消费者,但 `sys_log` 在 App 层 → 层次倒置 |
|
||||
| `Drivers/BSP/UI/ui_page_selftest.c:19` | `sys_log.h` | 同上 |
|
||||
| `Lib/FatFs/ffsystem.c:19` | `sys_clock.h`(App/util) | 中间件→应用;已在文件内注释声明为"④中间件层"有意为之 |
|
||||
|
||||
**评价:良好**。在 38k 行规模上把反向依赖控制在 3 处,说明分层不是墙上的图。但存在**语义层错位**:
|
||||
**评价:良好**。在 50k 行规模上把反向依赖控制在 4 处,说明分层不是墙上的图。但存在**语义层错位**:
|
||||
|
||||
- `Drivers/BSP/NETCFG/`、`Drivers/BSP/UI/` 名字是"板级支持包",内容是**业务**(网络配置语义、菜单/页面/权限/内容页框架)。后果:`sys_log`(App)与 `net_cfg`(BSP)互相引用,层次图自相矛盾。
|
||||
- **建议(S-1)**:把 `NETCFG`、`UI` 在概念上重新定性为 `App/` 或新增 `Service/` 层,`Drivers/BSP/` 只留下与引脚/芯片强绑定的 `ch395f`、`gd5f2gq5ue`、`sd2506`、`tpafe5160`、`rs485`、`dbg_*`。迁移成本最低的做法:**先改文档与分层图(零风险),目录迁移留到有 CI 兜底之后**(避免与 §2.3 的注册问题叠加)。
|
||||
- `Drivers/BSP/NETCFG/`、`Drivers/BSP/UI/` 名字是"板级支持包",内容是**业务**(网络/FTP 配置语义、菜单/页面/权限/内容页框架)。后果:`sys_log`(App)与 `net_cfg`(BSP)互相引用,层次图自相矛盾。
|
||||
- **建议(S-1)**:把 `NETCFG`、`UI` 在概念上重新定性为 `App/` 或新增 `Service/` 层,`Drivers/BSP/` 只留下与引脚/芯片强绑定的 `ch395f`、`gd5f2gq5ue`、`sd2506`、`tpafe5160`、`rs485`、`dbg_*`。迁移成本最低的做法:**先改文档与分层图(零风险),目录迁移留到有 CI 兜底之后**。
|
||||
|
||||
依赖方向裸引用(绕过头文件契约的 `extern`)实测 4 处——**2026-10-11 复核:4 处全部仍在**(仅行号漂移),S-2 未办:
|
||||
依赖方向裸引用(绕过头文件契约的 `extern`)实测 4 处——**2026-10-14 复核:4 处全部仍在**,S-2 未办:
|
||||
|
||||
| 位置 | 裸 extern |
|
||||
|------|-----------|
|
||||
| `Drivers/BSP/CH395F/ch395f.c:178` | `extern volatile uint8_t g_spi1_dma_done;`(实为 GD5F 在 `gd5f2gq5ue.c:50` 定义的变量,跨模块反向且**未进任何头文件**) |
|
||||
| `Drivers/BSP/GD5F2GQ5UE/gd5f2gq5ue.c:47` | `extern SPI_HandleTypeDef hspi1;`(`Inc/spi.h:35` 已导出,局部重复) |
|
||||
| `Drivers/BSP/NET/net_socket.c:56` | `extern osMessageQueueId_t netMsgQueueHandle;` |
|
||||
| `Drivers/BSP/SD2506/sd2506.c:20` | `extern I2C_HandleTypeDef hi2c1;`(`Inc/i2c.h:35` 已导出,局部重复) |
|
||||
| `Drivers/BSP/CH395F/ch395f.c:177` | `extern volatile uint8_t g_spi1_dma_done;`(实为 GD5F 在 `gd5f2gq5ue.c:50` 定义的变量,跨模块反向且**未进任何头文件**) |
|
||||
| `Drivers/BSP/GD5F2GQ5UE/gd5f2gq5ue.c:47` | `extern SPI_HandleTypeDef hspi1;`(`Inc/spi.h` 已导出,局部重复) |
|
||||
| `Drivers/BSP/NET/net_socket.c:77` | `extern osMessageQueueId_t netMsgQueueHandle;` |
|
||||
| `Drivers/BSP/SD2506/sd2506.c:20` | `extern I2C_HandleTypeDef hi2c1;`(`Inc/i2c.h` 已导出,局部重复) |
|
||||
|
||||
**建议(S-2)**:CubeMX 句柄类(`hspi1`/`hi2c1`)统一由 `main.h` 导出并 include,删除局部 extern;`g_spi1_dma_done` 应由 GD5F 模块自己定义并在头文件 `extern` 声明(当前跨模块裸 extern 是真正的耦合隐患);`netMsgQueueHandle` 改为 net_socket 内部持有 + 提供投递 API。
|
||||
|
||||
### 2.3 双构建清单漂移(结构性风险最高的一条)
|
||||
### 2.3 双构建清单漂移
|
||||
|
||||
把 **git 文件清单 × uvprojx × simulator/CMakeLists** 三方对齐后:
|
||||
|
||||
| 类别 | 文件 | 后果 |
|
||||
|------|------|------|
|
||||
| **两边都不注册** | 基线 5 个:`App/task/adc_task.c`、`App/util/crc.c`、`App/util/ringbuf.c`、`Drivers/BSP/NET/lftpd/lftpd_log.c`、`App/task/rs485_task.c` | **2026-10-11 复核:剩 2 个**——`crc.c`/`ringbuf.c` 已整体删除(`fac9d1c4`,2026-10-02,全库无调用者);`adc_task.c` 已挂 uvprojx(**仅 MCU**,模拟器不编,符合"任务层不入模拟器"的既有做法);❌ **`rs485_task.c`(等 E-50/E-49 修复)与 `lftpd_log.c`(与 `lftpd_log.h` 的 DBG 宏语义重复)仍两边不编** |
|
||||
| **两边都不注册** | 基线 5 个 → 现剩 **1 个**:`App/task/rs485_task.c`(E-59 门禁下的**刻意**缺口,随 B2 暂缓,已登记 `KNOWN_GAPS`) | `crc.c`/`ringbuf.c` 已整体删除(全库无调用者)、`lftpd_log.c` 已删除并入 `lftpd_auth.c`、`adc_task.c` 已挂 uvprojx(仅 MCU,符合"任务层不入模拟器")——**"写了不编译"的盲区已消** |
|
||||
| **仅 simulator 注册** | `cfg_file_store_sim.c`、`net_socket_sim.c`、`sim_port.c`、`sim_syslog.c`、`ui_net_sink_backend_sim.c` | 正常(后端适配层模式) |
|
||||
| **uvprojx** | 306 个 `.c`(含 201 个 LVGL)(基线 290) | LVGL 全量编译 → 编译时长;死代码问题被"全编"放大(见 §5.4) |
|
||||
| **uvprojx** | 323 个 `.c`(含 201 个 LVGL) | LVGL 全量编译 → 编译时长;F-2 落地后未用控件类 TU 均为空目标文件(见 §5.4 F-5) |
|
||||
|
||||
**评价**:AGENTS.md 已把"新文件必须注册两处"写成铁律并有 `new-source-file` skill,但**缺少反向校验**("存在但未注册")。这是纯粹的机械检查缺口——**2026-10-11 复核:该缺口未补**(`scripts/` 现有 11 个脚本,无 `check_registration.py`)。
|
||||
|
||||
**建议(S-3,1 小时工作量)**:新增 `[计划] scripts/check_registration.py`,规则:
|
||||
1. `App/**.c`、`Drivers/BSP/**.c`(排除 `*_sim.c`、`*_mcu.c` 之外的模式白名单)必须同时出现在 uvprojx 与 CMakeLists;
|
||||
2. 例外必须写进 `[计划] scripts/registration_allowlist.txt` 并注明原因(如"待 RS485 协议启用");
|
||||
3. 挂入 pre-commit 的 `local` hooks(与 `no-mojibake` 同列)。
|
||||
这样 §2.3 的 5 个文件会立刻变成"要么注册、要么显式豁免"。
|
||||
**评价**:AGENTS.md 的"新文件必须注册两处"铁律如今**两端都有机械保障**——正向由 `new-source-file` skill 约束,反向由 `scripts/check_registration.py`(pre-commit `registration-check` 钩子,2026-10-12)校验"存在但未注册",并反向查"注册了但文件不存在"的幽灵注册。**残余只有一条刻意缺口**:`rs485_task.c` 在 `KNOWN_GAPS` 里等 B2 立项,随该簇一并处置即可(清完后把 `--strict` 设为默认)。
|
||||
|
||||
### 2.4 目录组织与根目录卫生
|
||||
|
||||
| 观察 | 证据 | 判定 |
|
||||
|------|------|------|
|
||||
| 根目录散置工作文件 | `ui_menu_tree.txt`、`ui_cn_chars.txt` | 菜单树/字符集是**生成器输入**,放根目录合理且已在 `docs/` 有权威说明(原点名的根目录 `待处理内容.md` 已并入 `docs/任务规划/README.md` 统一登记簿) |
|
||||
| `Lib/` 命名 | `Lib/` 下混放 `lvgl/`、`lv_conf.h`、`FatFs/`、`dhara/` | `lv_conf.h` 是**工程配置**不是库文件;建议移到 `Config/lv_conf.h` 并同步 include 路径(低风险、提升可读性) |
|
||||
| 功能开关名存实亡 | `App/app/app_cfg.h` 的 `APP_NET_ENABLE/APP_ADC_ENABLE/APP_RS485_ENABLE` **全库零引用** | 与台账 **P2-12** 同源。开关不生效比没有开关更糟——评审者会误信"ADC 可裁剪"。**2026-10-11 复核:🟡 已订正表述但未接线**——文件头 v1.1(2026-10-04)已如实标注"预留占位、不门控任何代码",`APP_CCM_ENABLE`/`APP_UI_NET_SINK` 已删除,三个 `APP_*_ENABLE` 仍在且仍零引用 |
|
||||
| 根目录散置工作文件 | `ui_menu_tree.txt`、`ui_cn_chars.txt` | 菜单树/字符集是**生成器输入**,放根目录合理且已在 `docs/` 有权威说明 |
|
||||
| `Lib/` 命名 | `Lib/` 下混放 `lvgl/`、`lv_conf.h`、`FatFs/`、`dhara/` | `lv_conf.h` 是**工程配置**不是库文件;建议移到 `Config/lv_conf.h` 并同步 include 路径(低风险;⚠ 须一并处理 `simulator/lv_conf.h`,两份必须同一特性子集) |
|
||||
| 功能开关名存实亡 | `App/app/app_cfg.h` 的 `APP_NET_ENABLE/APP_ADC_ENABLE/APP_RS485_ENABLE` **全库零引用** | 开关不生效比没有开关更糟——评审者会误信"ADC 可裁剪"。文件头 v1.1 已如实标注"预留占位、不门控任何代码",但**仍未接线也未删**(S-4) |
|
||||
|
||||
### 2.5 结构结论
|
||||
|
||||
**总体判断:结构合理,无需重构**。要做的是四类**低成本纠偏**:S-1 层次定性、S-2 消裸 extern、S-3 注册反向校验、S-4 让 `app_cfg.h` 开关真正生效或删除(并把 `APP_CCM_ENABLE`/`APP_UI_NET_SINK` 纳入同一处)。
|
||||
**总体判断:结构合理,无需重构**。要做的是三类**低成本纠偏**:S-1 层次定性、S-2 消裸 extern、S-4 让 `app_cfg.h` 开关真正生效或删除。
|
||||
|
||||
---
|
||||
|
||||
## 3. 文档分布合理性
|
||||
|
||||
### 3.1 体量画像(实测,工作树;2026-10-11 复核,括号内为 2026-09-18 基线)
|
||||
### 3.1 体量画像(2026-10-14 实测,工作树)
|
||||
|
||||
| 对象 | 文件数 | 体积 | 占仓库 |
|
||||
|------|--------|------|--------|
|
||||
| 仓库受控文件总计 | 2,363(2,013) | **77.7 MB**(78.3 MB) | 100% |
|
||||
| `docs/` 合计 | 849(652) | **44.4 MB**(47.19 MB) | **57.1%**(60.3%) |
|
||||
| └ `docs/芯片手册/` 图片 | 703 张(564 张) | **36.3 MB**(40.5 MB) | **46.7%**(51.7%) |
|
||||
| └ `docs/images/引用关系图.json` | 1 | 1,072 KB(1,052 KB) | 1.3% |
|
||||
| └ `docs/UI设计/mockups` | 15 | 1,110 KB(1,110 KB) | 1.4% |
|
||||
| `.git` 目录 | 1,027 | **149.3 MB**(46.6 MB pack) | — |
|
||||
| 工程文档(Markdown,自研) | 77 篇 / **28,895 行**(40 篇 / 14,124 行) | — | — |
|
||||
| 外部资料(Markdown,datasheet 转录) | 14 篇 / 58,244 行(16 篇 / 59,142 行) | — | — |
|
||||
| 仓库受控文件总计 | 2,466 | **79.3 MB** | 100% |
|
||||
| `docs/` 合计 | — | **56.9 MB** | **71.8%** |
|
||||
| └ `docs/芯片手册/` 图片 | 703 张 | **36.3 MB** | **45.8%** |
|
||||
| `.git` 目录 | — | **235.3 MB** | — |
|
||||
| 工程文档(Markdown,自研) | 88 篇 / **31,416 行** | — | — |
|
||||
| 外部资料(Markdown,datasheet 转录) | 14 篇 / 58,244 行 | — | — |
|
||||
|
||||
**关键失衡(复核后仍在,但已缓解)**:工程文档行数从 14,124 涨到 **28,895**(翻倍),外部资料行数基本不变 → 比例从 1:4.2 改善到 **1:2.0**;但**图片体量(36.3 MB)仍是全部 Markdown 的 4 倍**,`git clone` 的净耗时依旧几乎全花在扫描手册图片上。⚠ 新增事实:`.git` 已膨胀到 **149 MB**(受控文件才 77.7 MB),说明历史里存过多版图片/产物——**D-1 的优先级因此上升**(拆仓或 LFS 之外,还需 `git filter-repo` 类历史清理才能见效)。
|
||||
**关键失衡**:工程文档与外部资料的行数比已从 1:4.2 改善到 **1:1.9**,但**全部 Markdown 只有 5.4 MB,图片体量(36.3 MB)是它的 6.7 倍、占仓库近一半**,`git clone` 的净耗时几乎全花在扫描手册图片上。⚠ `.git` 已达 **235 MB**(受控文件才 79.3 MB),说明历史里存过多版图片/产物——**D-1 单靠拆仓或 LFS 不足以解决 clone 耗时,还需一次历史重写**。
|
||||
|
||||
### 3.2 做得好的(应保留并显式制度化)
|
||||
|
||||
1. **文档密度与可执行性**:每篇都带"步骤 + 判据"(如 UI 制作流程有 P0→P4 Gate);测试说明按模块拆分并给出预期串口标记,可直接接 `@test`。
|
||||
2. **陷阱台账**:`docs/问题记录/*_Trap_Records.md` + `docs/任务规划/README.md`(P1-1..P3-13,带 ✅ 状态与日期)——这是本工程最有价值的资产,多数嵌入式项目没有。
|
||||
2. **陷阱台账**:`docs/问题记录/*_Trap_Records.md` + `docs/任务规划/`(带状态与日期)——这是本工程最有价值的资产,多数嵌入式项目没有。
|
||||
3. **图与脚本同提交**:`tools/arch_diagram/`、`tools/refgraph/` 生成器 + 产物入库,图可再生而非手绘。
|
||||
4. **UI 设计资产链完整**:原始参考图 → 说明 md → 代码,可追溯。
|
||||
5. **文档一致性已机械化**:`doc-links`(含 `--sections-strict`)、`task-table`、`mem-numbers`、`lv-conf-sync`、`cubemx-survival` 等只读钩子守住"文档说的 == 代码做的"。
|
||||
|
||||
### 3.3 问题清单
|
||||
|
||||
#### D-1(P1)外部资料与工程文档同仓同树
|
||||
|
||||
**影响**:clone 慢、备份慢、code review 时 diff 噪音大;`docs/芯片手册/` 的 564 张图属于**只读输入资料**,与代码演进无关。
|
||||
**影响**:clone 慢、备份慢、code review 时 diff 噪音大;`docs/芯片手册/` 的 703 张图属于**只读输入资料**,与代码演进无关。
|
||||
|
||||
**建议**(三选一,按代价递增):
|
||||
1. **最省**:把 564 张 JPG 降采样到长边 1,200 px(40.5 MB → 约 8 MB),一次性提交并在 `[计划] docs/文档规范.md` 写入"入库图片上限 200 KB/张";
|
||||
1. **最省**:把手册 JPG 降采样到长边 1,200 px(约 36 MB → 8 MB),一次性提交并在 `../文档规范.md` 写入"入库图片上限 200 KB/张";
|
||||
2. **推荐**:`docs/芯片手册/` 拆为独立仓库 `dtu-datasheets`,用 `git submodule` 挂回原路径(现有全部链接不需改写);
|
||||
3. **最正**:Git LFS(需要托管端支持)。
|
||||
|
||||
> **2026-10-11 复核:未办,且问题变大**。图片增至 **703 张 / 36.3 MB**(受控文件总量 77.7 MB,图片仍占 46.7%);⚠ 新事实:`.git` 目录已达 **149.3 MB**(1,027 个对象文件),远大于工作树受控内容 → 历史里存了多版图片/日志/产物。**只做 1/2/3 中任一项都不足以解决 clone 耗时,还需一次历史重写(`git filter-repo`)**;重写属破坏性操作(所有克隆需重取),须单独排期并先备份裸仓。
|
||||
> ⚠ 三项都不解决历史膨胀:`.git` 235 MB 需一次 `git filter-repo` 历史重写(破坏性操作,所有克隆需重取)。**2026-10-11 已决策:暂不处理、登记观察**(登记簿 N-29),推送/协作前重评——届时未推送提交更少、重写代价最低。
|
||||
|
||||
### 3.4 文档结论
|
||||
|
||||
**内容质量高、分布形态差**。按 D-1..D-7 处理后可从 B- 提升到 A-:工程量约 1 人日(不含拆仓),收益是 clone 时间与"文档可信度"。
|
||||
|
||||
> **2026-10-11 复核**:**内容质量侧已到位**(评级 A−,见 §0.1;D-2..D-7 已销项),**分布形态侧未动**——未闭环的文档类问题只剩三条:
|
||||
> - **D-1 ❌**:`docs/` 仍占仓库 **57.1%**、图片仍 **36.3 MB**,且 `.git` 已膨胀到 **149 MB** → 已从"P1 优化"变成影响日常 clone/备份的实际痛点;单靠拆仓或 LFS 不够,**还需一次历史重写**。
|
||||
> - **语义断链 ❌**:两份 UI 文档仍指向 `tools/ui_mock/`(该目录从未存在,实现落在 `simulator/tests/`)——路径检查抓不到,属语义层。
|
||||
> - **元信息漂移 ⚠**:门禁与文档越多,自身数字也会过期——AGENTS.md 现写"18 个钩子"(实测 `.pre-commit-config.yaml` **22** 个)、"清单 23 项"(实测 `check_cubemx_survival.py` **29** 项)。建议把这类计数也纳入生成/校验,否则报告与规范各说一套。
|
||||
**内容质量高(A−)、分布形态差**。D-1 处理后可到 A:工程量约 1 人日(不含拆仓与历史重写),收益是 clone 时间与"文档可信度"。
|
||||
|
||||
---
|
||||
|
||||
@@ -251,237 +233,195 @@ Select-String -Path 'MDK-ARM\STM32F407-Demo\STM32F407-Demo.map' -Pattern '__heap
|
||||
|
||||
**设计良好**:
|
||||
- `app_main_init` 顺序有因(墙钟优先,使后续日志带时间戳);
|
||||
- **Event Flags 就绪屏障**(`NET_READY/STORAGE_READY/FTP_READY/TIMESYNC_READY/CFG_SAVE/NET_RECONFIG`)取代魔法延时,是本项目最漂亮的设计之一;
|
||||
- 配置引擎属主收敛到 defaultTask 单任务(P1-3 已修),消除了跨任务竞态。
|
||||
- **Event Flags 就绪屏障**(`NET_READY/STORAGE_READY/FTP_READY/TIMESYNC_READY`)取代魔法延时,是本项目最漂亮的设计之一;
|
||||
- 配置引擎属主收敛到 defaultTask 单任务,消除了跨任务竞态;
|
||||
- 初始化失败路径已收口:`Error_Handler` 打 1 条自检日志 + `NVIC_SystemReset()`(不再 `__disable_irq(); while(1)`)。
|
||||
|
||||
**问题**:
|
||||
|
||||
| 编号 | 问题 | 证据 | 影响/建议 |
|
||||
|------|------|------|-----------|
|
||||
| **N-03c** | 多处初始化失败即挂死(`Error_Handler()` at `main.c:221`;net/ui 初始化失败路径) | | 建议统一降级策略:**外设失败 → 记自检日志 + 该子系统禁用 + 其余照常**(LED/屏上给出降级标识)。**❌ 2026-10-11 复核仍在**:`Src/main.c:274-282` 仍 `__disable_irq(); while(1){}`(IWDG 独立于中断,最终仍会被硬复位,但无降级、无定位信息) |
|
||||
| P2-12 | `App/app/app_cfg.h` 三个 `APP_*_ENABLE` 零引用 | | 开关要么生效要么删 → **🟡 部分处理**:已如实标注"预留占位、不门控任何代码"(v1.1),未接线也未删 |
|
||||
| 编号 | 问题 | 影响/建议 |
|
||||
|------|------|-----------|
|
||||
| S-4 | `App/app/app_cfg.h` 三个 `APP_*_ENABLE` 零引用(文件头已标注"预留占位") | 开关要么生效要么删;产品定义(登记簿 B0)落定前至少别让评审者误信"可裁剪" |
|
||||
|
||||
### 4.2 网络子系统(CH395F + BSD 抽象层)
|
||||
|
||||
**设计良好**:
|
||||
- 所有 `net_*` 经 `netMsgQueue`(深 8,`Src/freertos.c:154`)串行到 netTask 执行 → 单线程语义清晰;
|
||||
- 所有 `net_*` 经 `netMsgQueue` 串行到 netTask 执行 → 单线程语义清晰;
|
||||
- 全部 CH395F 中断集中在 `net_poll()` 内 `GET_GLOB_INT_STATUS` 排空(AGENTS 铁律,已落实);
|
||||
- 网络代次号机制使"改 IP 免重启"能重建各监听。
|
||||
- 网络代次号机制使"改 IP 免重启"能重建各监听;
|
||||
- **挂起 recv/send 模型**(`net_pending.c/h`)取代"强加 30 s 默认预算",recv 语义已主流化。
|
||||
|
||||
**问题**:
|
||||
|
||||
| 编号 | 问题 | 证据 | 建议 |
|
||||
|------|------|------|------|
|
||||
| **N-02** | **FTP 无鉴权**:`cmd_pass` 无条件 `send_simple_response(socket, 230, STATUS_230)` | `lftpd.c:367-371`(`cmd_user :539` 亦不校验) | 最小可用方案:`config.ini` 增 `[ftp] user/pwd_hash`,`cmd_pass` 用**定长比较 + 失败计数锁定**;生产固件默认关闭 FTP 写权限(`FF_FS_READONLY` 式的只读模式)。**❌ 2026-10-11 复核:一行未改**(现 `lftpd.c:375-379` / `:553-557`,全文件无 password/auth/attempt/read_only);⚠ 且**未登记进 `docs/任务规划/登记簿.md`** → 建议补登为 P0/P1 |
|
||||
| N-09 | `cmd_pasv` 每次新建监听 `lftpd_inet_listen(0)`(随机端口) | `lftpd.c:373` | 在**单连接 socket** 上与 UI `:7003`、对时 `:8888` 争用同一物理 socket;建议限定监听资源池 + 显式"FTP 会话独占"策略,并在文档写明"一次只允许一个 TCP 服务活动"。**❌ 复核仍在**(现 `lftpd.c:392`,3 次重试 + 200 ms 间隔) |
|
||||
| P2-8 | `net_recv` 阻塞超时 30 s | 台账 | 缩短并让上层可取消。**❌ 复核仍在**:`net_config.h:39` `NET_RECV_TIMEOUT_MS 30000` |
|
||||
| — | PHY 强制 100M 全双工,忽略自协商 | AGENTS/architecture | 与某些交换机会联不通;至少加"链路 up 失败 3 次后回退自协商"。**❌ 复核仍在**:`net_task.c:110` 无条件 `ch395f_set_phy(CH395F_PHY_100M_FULL)`,仅 3 s 链路等待 + DISCONN 时上报 `comms fault` 自检 |
|
||||
| P3-x | `NET_MAX_SOCKETS 8`(`net_config.h:24-25`)是**软件表**,与硬件单连接语义不符 | | 文档已说明,但 API 层看不到限制 → 建议在 `net_socket.c` 断言"同时 LISTEN 数 ≤ N"。**❌ 复核仍在**(现 `net_config.h:27`,值仍 8) |
|
||||
| N-09 | `cmd_pasv` 每次新建监听 `lftpd_inet_listen(0)`(随机端口) | `lftpd.c:472` | 在**单连接 socket** 上与 UI `:7003`、对时 `:8888` 争用同一物理 socket;建议限定监听资源池 + 显式"FTP 会话独占"策略,并在文档写明"一次只允许一个 TCP 服务活动" |
|
||||
| — | PHY 强制 100M 全双工,忽略自协商 | `App/task/net_task.c:110` 无条件 `ch395f_set_phy(CH395F_PHY_100M_FULL)` | 与某些交换机会联不通;至少加"链路 up 失败 3 次后回退自协商" |
|
||||
| P3-x | `NET_MAX_SOCKETS 8`(`net_config.h:33`)是**软件表**,与硬件单连接语义不符 | | 文档已说明,但 API 层看不到限制 → 建议在 `net_socket.c` 断言"同时 LISTEN 数 ≤ N" |
|
||||
|
||||
### 4.3 存储子系统(GD5F2GQ5UE + dhara + FatFs)
|
||||
|
||||
**设计良好**:
|
||||
- 分层正确:`gd5f2gq5ue`(芯片)→ `nand_ftl`(dhara map/journal + 页缓存)→ FatFs R0.14 → 应用;
|
||||
- `Lib/FatFs/ffsystem.c` 用真实 `osMutexNew` 实现 `FF_FS_REENTRANT=1` 的卷锁(多数移植是空实现)——**这是本工程移植质量的一个亮点**;`get_fattime()` 接系统墙钟,使 FAT 时间戳有意义;
|
||||
- BBT 保留块池(`gd5f2gq5ue.c:28-40`)把坏块表存储区从 dhara 可见空间中排除,避免被 FTL 擦写。
|
||||
- BBT 保留块池把坏块表存储区从 dhara 可见空间中排除,避免被 FTL 擦写;
|
||||
- **DMA 可达性三层防线**(原 N-11 的处置,2026-10-11):编译期窗口断言(`gd5f2gq5ue.h:96-107` 负数组 typedef,DMA 白名单窗口与 CCM 永不得重叠 + 阈值契约)→ 启动期自检(`nand_ftl.c:241-243` 三块静态页缓冲逐一过守卫)→ 运行时强制(`gd5f_dma_buf_ok()` 不可达即回落轮询 + `[ERR]`);规则本身(**R2 DMA 缓冲只允许 SRAM 静态**、**R3 堆/栈禁为 DMA 源/目的**)已写进 `../内存管理/内存内容分配策略.md` §4,并有 TC-GD5F-704/705 负路径用例实证。**缓冲自身地址无法编译期断言**(`.bss` 地址链接期才定,AC5 取不到)——这条边界在头文件注释里写明,别再试图"加个 `_Static_assert`"。
|
||||
|
||||
**问题**:
|
||||
|
||||
| 编号 | 问题 | 证据 | 影响/建议 |
|
||||
|------|------|------|-----------|
|
||||
| **N-11** | NAND 驱动**直接对调用方缓冲做 DMA**:`HAL_SPI_Receive_DMA(&hspi1, p_buf, size)`(`:200`)、`HAL_SPI_Transmit_DMA(&hspi1, (uint8_t*)p_buf, size)`(`:258`),阈值仅 32 B | `gd5f2gq5ue.c:185-217,246-270` | **这是 CCM 迁移的硬边界**:所有走 NAND 的缓冲区(含 `FIL`、FatFs window、任务栈上的临时缓冲)**必须留在 SRAM1**。必须在 `docs/内存管理/` 写成铁律,否则一旦把某任务栈搬进 CCM 就会静默 DMA 失败。**2026-10-11 复核:🟡 模式未变但已加固**——阈值改为 `GD5F_DMA_THRESHOLD 1024`(`gd5f2gq5ue.h:78`),并新增**运行时 DMA 可达性守卫**(`:110-136`,不可达自动回落轮询)。⚠ 复核新发现:堆已迁 CCM(`ucHeap @0x10000020`)→ **"从 FreeRTOS 堆分配的缓冲不可被任何 DMA 直接寻址"成为全局铁律**,比原结论更硬 |
|
||||
| **N-12** | `dhara_nand_is_free()` 只检查页首 64 B | `nand_ftl.c:137-154` | dhara 依赖该判定做映射恢复;页首 64 B 全 FF 但后半页有数据时会误判为空闲 → 数据丢失风险(低概率但后果重)。建议整页扫描或至少首/中/尾三处采样。**❌ 复核仍在**(现 `nand_ftl.c:152-179`,仍 `uint8_t buf[64]`) |
|
||||
| **N-13** | `dhara_nand_copy()` 未处理 `DHARA_NO_PAGE` 语义(dst 为哨兵值时仍执行"读+编程") | `nand_ftl.c:174-186` | dhara map 在回收/擦除路径会用 `DHARA_NO_PAGE` 试探;当前实现会把它当作真实页号 → 未定义行为。建议:`if (dst == DHARA_NO_PAGE) { dhara_set_error(err, DHARA_E_UNSUPPORTED); return -1; }`(返回不支持是安全语义)。**❌ 复核仍在**(现 `:204-216`,read→prog 直传) |
|
||||
| N-14 | 写回缓存 `s_cache_buf/s_cache_dirty` 无掉电保护策略:`CTRL_SYNC` 已实现(`:343-353`)但**没有周期性或掉电前的强制 flush** | `nand_ftl.c:291-353` | 掉电窗口 = 最后一次未跨页的写。建议:空闲 N ms 由 defaultTask flush + 掉电检测(若硬件支持)或至少"日志落盘后立即 fsync"。**🟡 复核:部分改善**——整页写立即 flush(`:377-381`)、换页时 flush(`:365-368`)、`CTRL_SYNC` 走 flush + `dhara_map_sync`(`:400-406`);仍无空闲定时 flush |
|
||||
| P2-3/P2-4 | 部分返回值丢失 | 台账 | 逐条修 |
|
||||
| N-15 | 页缓冲重复:`nand_ftl` 3×2,048(`:s_page_buf/s_cache_buf/s_copy_buf`)+ `gd5f` 的 `s_bbt_page_buf[2048]`(仅 init 期使用) | 对象 ZI:nand_ftl 6,216 + gd5f 2,596 | BBT 页缓冲可与 `s_copy_buf` 复用或 init 后归还(§5.3 R-3,省 2–4 KB)。**🟡 复核:已省一半**——`s_bbt_page_buf` 由 2,048 B 收紧为 **272 B**(2026-09-21);`nand_ftl` 三块 2 KB 未合并(对象 ZI 仍 6,216) |
|
||||
| — | `disk_ioctl GET_BLOCK_SIZE = 1` | `nand_ftl.c` | FatFs 的擦除块提示失效(FAT32 对齐优化拿不到信息);建议返回 64 页(=1 物理块)。**❌ 复核仍在** |
|
||||
| **N-12** | `dhara_nand_is_free()` 只检查页首 64 B | `nand_ftl.c:152-179`(仍 `uint8_t buf[64]`) | dhara 依赖该判定做映射恢复;页首 64 B 全 FF 但后半页有数据时会误判为空闲 → 数据丢失风险(低概率但后果重)。建议整页扫描或至少首/中/尾三处采样 |
|
||||
| **N-13** | `dhara_nand_copy()` 未处理 `DHARA_NO_PAGE` 语义(dst 为哨兵值时仍执行"读+编程") | `nand_ftl.c:204-216`(read→prog 直传) | dhara map 在回收/擦除路径会用 `DHARA_NO_PAGE` 试探;当前实现会把它当作真实页号 → 未定义行为。建议:`if (dst == DHARA_NO_PAGE) { dhara_set_error(err, DHARA_E_UNSUPPORTED); return -1; }` |
|
||||
| N-14 | 写回缓存 `s_cache_buf/s_cache_dirty` 无掉电保护策略:`CTRL_SYNC` 已实现但**没有空闲时强制 flush** | `nand_ftl.c:418` | 掉电窗口 = 最后一次未跨页的写。已改善:整页写立即 flush、换页时 flush、`CTRL_SYNC` 走 flush + `dhara_map_sync`;仍无空闲定时 flush → 建议 defaultTask 空闲 N ms flush |
|
||||
| N-15 | 页缓冲重复:`nand_ftl` 3×2,048(`s_page_buf/s_cache_buf/s_copy_buf`) | 对象 ZI:nand_ftl 6,216 | 与 `s_copy_buf` 复用可省 2 KB(§5.3 R-3)。🟡 `gd5f` 的 `s_bbt_page_buf` 已由 2,048 B 收紧为 272 B |
|
||||
| — | `disk_ioctl GET_BLOCK_SIZE = 1` | `nand_ftl.c:442-444` | FatFs 的擦除块提示失效(FAT32 对齐优化拿不到信息);建议返回 64 页(=1 物理块) |
|
||||
|
||||
### 4.4 配置引擎(`App/cfg/cfg_file.c`,1,190 行)
|
||||
### 4.4 配置引擎(`App/cfg/cfg_file.c`,1,343 行)
|
||||
|
||||
**设计良好**:描述符 + 段注册表、外科式(surgical)保存、模板生成、2 s 轮询(`cfg_file_poll`)响应 `SYS_EVT_CFG_SAVE`,属主单任务化。这是全项目设计最完整的一个模块。(原"首启旧档迁移"已于 2026-10-10 删除——该一次性路径把整条配置写链挂进启动期调用图,defaultTask 静态最坏链 +600 B。)
|
||||
**设计良好**:描述符 + 段注册表、外科式(surgical)保存、模板生成、2 s 轮询(`cfg_file_poll`)响应 `SYS_EVT_CFG_SAVE`,属主单任务化。这是全项目设计最完整的一个模块。销毁用户文件的路径(超长/损坏)已补自检留痕(`cfg load oversized` / `cfg load read fail` → `SYSLOG_SELFTEST`),现场无调试器时可追溯。
|
||||
|
||||
**问题**:
|
||||
|
||||
| 编号 | 问题 | 建议 |
|
||||
|------|------|------|
|
||||
| P2-1 | 超长键行处理 | 台账 |
|
||||
| — | 失败即静默回落工厂默认(`:955-988`:缺文件→模板→return -1;超长→模板→return -1;读失败→"factory defaults kept") | 语义本身合理(不阻塞组网),但**用户改了 IP 重启就丢且无告警**——建议回落时必写一条自检记录并在 UI 装置信息页给出"当前为出厂配置"标识 |
|
||||
| — | 读失败仍静默回落工厂默认(`:1071-1102`),语义合理(不阻塞组网),但**用户改了 IP 重启就丢,串口之外无提示** | 装置信息页给出"当前为出厂配置"标识(自检记录已有,UI 侧未接) |
|
||||
|
||||
### 4.5 日志子系统(`App/log/sys_log_mcu.c`)
|
||||
|
||||
**设计良好**:定长 64 B 记录(`SYSLOG_REC_SIZE`)、单写者(defaultTask)、RAM 队列 + `syslog_drain`、容量满时删除重建、`/log` 目录惰性创建。
|
||||
|
||||
> **2026-10-11 复核:日志侧新增了两个基线没有的东西,值得记一笔。**
|
||||
> ① **控制台单写者日志**(`App/log/console_log.c`,对象 ZI 4,120 B)——把"多任务直接 `printf` 到 USART1"收敛为单写者队列,配套 `DBG_*` 宏;代价已量化进 AGENTS.md(**每条日志约 90 B Flash + 216 B 栈**,深调用链模块另以 `#define DBG_LINE_BUF_MAX 128U` 收紧)。⚠ 这条代价模型正是 defaultTask 静态最坏链从 5,312 → 2,776 B 的主要杠杆,**属本报告"内存"章节应当吸收的新事实**。
|
||||
> ② **自检记录可查**:`selftest.log` + 开机 `selftest: no fault record` 标记 + Fault 现场 `.noinit` 跨复位 → 现场故障从"不可知"变成"可回读"。
|
||||
**设计良好**:定长 64 B 记录(`SYSLOG_REC_SIZE`)、单写者(defaultTask)、RAM 队列 + `syslog_drain`、容量满时删除重建、`/log` 目录惰性创建(`mkdir` 失败保持未就绪 + 幂等重试 + 上报);`/log/selftest.log` + 开机自检锚点 + Fault 现场 `.noinit` 跨复位 → 现场故障从"不可知"变成"可回读"。控制台侧另有**单写者队列**(`App/log/console_log.c`,对象 ZI 4,120 B)把"多任务直接 `printf` 到 USART1"收敛为一条流;代价已量化进 AGENTS.md(**每条日志约 90 B Flash + 216 B 栈**,深调用链模块另以 `#define DBG_LINE_BUF_MAX 128U` 收紧)。
|
||||
|
||||
**问题**:
|
||||
|
||||
| 编号 | 问题 | 证据 | 建议 |
|
||||
|------|------|------|------|
|
||||
| **N-16** | **每条记录一次 `f_open + f_write + f_close`**(`:89-95`),读侧同样每条 `f_open/f_lseek/f_close`(`:118-126`) | 每条日志触发 FatFs 目录项读写 → 2–4 次 NAND 页读写;UI 翻记录时逐条 open/seek/close | 写侧:常驻 `FIL`(仅 defaultTask 持有)+ 批量 flush;读侧:打开一次 + 缓存目录偏移(UI 已有 `s_cache_valid/s_last_rec` 雏形,可升级为页缓存)。**❌ 2026-10-11 复核仍在**:`sys_log_mcu.c:123-140` 每条仍 open/write/close(失败重建重试一次),`wdev.log` 同模式(`:481-484`);🟡 唯一改善 = `FIL` 已 static 化(`:70`,省 528 B 栈),**无常驻打开句柄、无批量 flush** |
|
||||
| P2-9 | `mkdir` 失败后不再重试(`s_fs_ready` 逻辑,`:158-165`) | 台账 | 失败时保持未就绪 + 定期重试 + 上报自检 |
|
||||
| P2-10 | 容量轮转 `f_unlink`(`:64`)与 UI 读并发 | 台账 | 轮转只在写者、读者持版本号 |
|
||||
| **N-16** | **每条记录一次 `f_open + f_write + f_close`**,读侧同样每条 `f_open/f_lseek/f_close` | `sys_log_mcu.c:124-141`(失败重建重试一次)、`wdev.log` 同模式 `:486-489` | 写侧:常驻 `FIL`(仅 defaultTask 持有)+ 批量 flush;读侧:打开一次 + 缓存目录偏移(UI 已有 `s_cache_valid/s_last_rec` 雏形,可升级为页缓存)。🟡 唯一改善 = `FIL` 已 static 化(省 528 B 栈) |
|
||||
| P2-10 | 容量轮转 `f_unlink` 与 UI 读并发 | | 轮转只在写者、读者持版本号;卷锁覆盖面评估 → 登记簿 S-5 |
|
||||
|
||||
### 4.6 UI 子系统
|
||||
|
||||
见 §6 专题(同时是"标准化"章节)。此处仅记设计层结论:三层拆分(数据 `ui_menu_tab` / 视图 `ui_menu_view` / 控制器 `ui_menu`)+ 内容页描述符框架**方向正确**,但**框架未收敛到"新页面零框架改动"**,且 4 份 3,200 B 帧副本占 12.8 KB RAM(§5)。
|
||||
|
||||
> **2026-10-11 复核:两条结论均未变化。** 框架仍要求"改 `ui_menu.c` 的手写 `case` + 加实例文件 + 双端注册"才能新增一页(§6.2 的 8 步一字未减);帧副本仍 4 份(`ui_port.o` ZI 6,420 + `ui_net_sink.o` 6,766 = 13,186 B,R-4 未办)。✅ 唯一实质改善在**验证侧**:golden 回归已建(§6.1),UI 改动从此有逐像素/逐字节基线可依赖。
|
||||
见 §6 专题(同时是"标准化"章节)。此处仅记设计层结论:三层拆分(数据 `ui_menu_tab` / 视图 `ui_menu_view` / 控制器 `ui_menu`)+ 内容页描述符框架**方向正确**,但**框架未收敛到"新页面零框架改动"**(`menu_content_page_for()` 仍是手写 `case`,`ui_menu.c:118-128`),且 4 份 3,200 B 帧副本占 12.8 KB RAM(§5)。✅ 验证侧已到位:golden 回归已建(§6.1),UI 改动从此有逐像素/逐字节基线可依赖。
|
||||
|
||||
### 4.7 外设驱动
|
||||
|
||||
| 模块 | 评价 | 问题 |
|
||||
|------|------|------|
|
||||
| `sd2506`(RTC) | I2C 超时齐备,降级策略明确(RTC 故障→默认时基 + 自检上报),**良好** | P2-5(负温度解析)、P2-6(WRTC 解锁) |
|
||||
| `tpafe5160`(并行 ADC) | BUSY 超时、EXTI 读取路径齐备;取数已收口为 `tpafe5160_snapshot()` 原子快照(帧序号只增不清 + FRSTDATA 自检) | ⚠ **V0.1 硬件缺陷(登记簿 N-18,V0.2 改版项;注意与本报告 N-18 同号不同义)**:8 路电气量被分给两片转换器 → 主板侧**禁止**跨转换器做相位/功率/功率因数运算;并行总线无批量采样框架,16 位端口读依赖 `gpio.c` 初值 |
|
||||
| `rs485` | 结构简单 | DE 时序用 `HAL_Delay(1)` **阻塞 1 ms**(在调用任务里);`crc.c`/`ringbuf.c` 未注册 → 无帧校验、无接收环。**❌ 复核:`HAL_Delay(1)` 仍在(`rs485.c:91`)**;`crc.c`/`ringbuf.c` 已删除(2026-10-02)→ 帧校验/接收环**从零重做**;`rs485_task.c` 仍未注册,消费者被 E-50(包撕裂)/E-49(TX 超时拉 DE)挡住 |
|
||||
| `ch395f` | 事务包裹 `begin/end`、SPI 分频 8 为 PCB 约束(已文档化,勿动) | 静态 DMA 缓冲 2×2,052 B(obj ZI 4,105),必须留 SRAM1 |
|
||||
| 模块 | 评价 | 未闭环问题 |
|
||||
|------|------|-----------|
|
||||
| `sd2506`(RTC) | I2C 超时齐备,降级策略明确(RTC 故障→默认时基 + 自检上报),WRTC 解锁顺序按手册、负温度符号扩展已处理 | — |
|
||||
| `tpafe5160`(并行 ADC) | BUSY 超时、EXTI 读取路径齐备;取数已收口为 `tpafe5160_snapshot()` 原子快照(帧序号只增不清 + FRSTDATA 自检) | ⚠ **V0.1 硬件缺陷(登记簿 N-18,V0.2 改版项)**:8 路电气量被分给两片转换器 → 主板侧**禁止**跨转换器做相位/功率/功率因数运算;并行总线无批量采样框架,16 位端口读依赖 `gpio.c` 初值 |
|
||||
| `rs485` | 结构简单 | DE 时序用 `HAL_Delay(1)` **阻塞 1 ms**(在调用任务里,`rs485.c`);无帧校验、无接收环(`crc.c`/`ringbuf.c` 已删除 → **需从零重做**);`rs485_task.c` 仍未注册,消费者被 E-50(包撕裂)/E-49(TX 超时拉 DE)挡住(随 B2 暂缓) |
|
||||
| `ch395f` | 事务包裹 `begin/end`、SPI 分频 8 为 PCB 约束(已文档化,勿动) | 静态 DMA 缓冲 2×2,052 B(obj ZI 4,162),必须留 SRAM1 |
|
||||
|
||||
**驱动共性缺口**:没有统一的"错误码 + 超时 + 重试 + 自检上报"约定,各模块自定返回码(`GD5F_OK` / `0` / `bool` 混用)。**建议(S-5)**:定义 `bsp_err_t` 统一错误码 + `bsp_retry()` 辅助 + 所有失败必须走 `syslog(SYS_SELFTEST,...)`,作为驱动编写规范写入 `docs/代码规范/`。
|
||||
**驱动共性缺口**:没有统一的"错误码 + 超时 + 重试 + 自检上报"约定,各模块自定返回码(`GD5F_OK` / `0` / `bool` 混用)。**建议(S-5)**:定义 `bsp_err_t` 统一错误码 + `bsp_retry()` 辅助 + 所有失败必须走自检记录,作为驱动编写规范写入 `docs/代码规范/`。
|
||||
|
||||
### 4.8 测试体系
|
||||
|
||||
**设计良好**:`test/board/test_config.h` 的 `TEST_SUITE_*` 互斥(`#error` 保护)、CH395F 硬件层/NET 层 Phase 互斥、`@test` 一键闭环(烧录→wait-idle→标记校验)、模拟器 `--cfgtest/--logtest`。
|
||||
**设计良好**:`test/board/test_config.h` 的 `TEST_SUITE_*` 互斥(`#error` 保护)、CH395F 硬件层/NET 层 Phase 互斥、`@test` 一键闭环(烧录→wait-idle→标记校验)、模拟器 `--cfgtest/--logtest`、主机侧单测 15 个钩子(含 `sha256` / `ftp_auth` / `vol_lock` / 采集算法族)。
|
||||
|
||||
> ⚠ 仍缺:**覆盖率概念**(原建议未办)、**注册检查**(`check_registration.py`)、**主机侧对 `lftpd`/`dhara` 移植层的测试**(N-12/N-13 这类缺陷至今只能靠人工读代码发现)。
|
||||
> ⚠ 仍缺:**覆盖率概念**、**主机侧对 `dhara` 移植层的测试**(N-12/N-13 这类缺陷至今只能靠人工读代码发现)。
|
||||
|
||||
**问题**:
|
||||
|
||||
| 编号 | 问题 | 建议 |
|
||||
|------|------|------|
|
||||
| P1-10 | CH395F 硬件测试套件 RAM 溢出(`L6406E`):HW 套 +8.7 KB、NET 层固件 +28 KB(`s_rx_buf` 32 KB) | 测试缓冲改为**分 Phase 复用同一块静态缓冲**(union 或分阶段 `memset`);`docs/任务规划/测试与架构专项.md` 的这条待办应升级为正式任务。**🟡 2026-10-11 复核:已升级为登记簿唯一 P 类收尾项**(RAM 侧因堆迁 CCM 大幅缓解,剩"CH395F 套件构建实测链接确认 + `@test` 闭环"两步) |
|
||||
| P1-10 | CH395F 硬件测试套件静态 RAM 预算(`L6406E` 历史:HW 套 +8.7 KB、NET 层固件 +28 KB) | 基线已重建、测试缓冲已瘦身、RAM 侧因堆迁 CCM 大幅缓解;**剩"套件构建实测链接确认 + `@test` 闭环"两步**(登记簿唯一 P 类收尾项,W5) |
|
||||
|
||||
---
|
||||
|
||||
## 5. 内存优化(量化)
|
||||
|
||||
### 5.1 实测基线(map)
|
||||
### 5.1 实测基线(2026-10-14 `.map`)
|
||||
|
||||
| 指标 | 2026-09-16(审查基线) | **2026-10-11 复核** | 上限 | 复核占用 |
|
||||
|------|----------------------|--------------------|------|---------|
|
||||
| `Code + RO-data` | 245,384 B(239.6 KB) | **273,860 B**(267.4 KB) | 1 MB Flash | **26.1%** |
|
||||
| `ROM`(含 RW 初始化表) | 246,016 B | **274,060 B** | 1 MB | 26.1% |
|
||||
| `RW-data` | 632 B | 824 B | — | — |
|
||||
| `ZI-data` | 125,952 B | **139,896 B** | — | — |
|
||||
| **SRAM1(0x20000000,128 KB)** | **126,584 B / 96.6%(余 4,488 B)** | **91,488 B** | 131,072 B | **69.8%(余 39,584 B)** |
|
||||
| **CCM(0x10000000,64 KB)** | **0 B / 0%** | **49,232 B**(`RW_CCM` 49,184 + `UNINIT_CCM` 48) | 65,536 B | **75.1%(余 16,304 B)** |
|
||||
| `Total RW (RW+ZI)` | 126,584 B | **140,720 B** | — | — |
|
||||
| 指标 | 数值 | 上限 | 占用 |
|
||||
|------|------|------|------|
|
||||
| `Code + RO-data`(`ER_IROM1`) | 231,036 B | 1 MB Flash | **22.0%** |
|
||||
| `ROM`(`Code + RO + RW` 初始化表) | 232,148 B | 1 MB | 22.1% |
|
||||
| **SRAM1(0x20000000,128 KB)** `RW_IRAM1` | **98,144 B** | 131,072 B | **74.9%(余 32,928 B)** |
|
||||
| **CCM(0x10000000,64 KB)** `RW_CCM` | **57,376 B** | 65,280 B | **87.9%(余 7,904 B)** |
|
||||
| `UNINIT_CCM`(`.noinit` 崩溃现场) | 48 B | 256 B | 18.8% |
|
||||
|
||||
> **2026-10-11 二次实测(LVGL 死代码裁剪后,F-1/F-2/F-3 已落地)**:`Code=194,276 / RO=15,872 / RW=876 / ZI=139,892` → `ER_IROM1` **210,148 B(20.0%)**、`ROM 合计` **211,024 B(20.1%)**;`RW_IRAM1` 91,536 B(69.8%)与 `RW_CCM` 49,184 B(75.3%)**不变**(本次只动 Flash)。§5.4 的口径以此为准。
|
||||
> **权威源**:区域水位与子系统配额 → `../内存管理/RAM预算台账.md`(受管区);趋势 → `scripts/ram_baseline.tsv`(`ram_baseline.py --trend` 高亮 RW+ZI 增长 >1 KB 的对象)。本节只列支撑结论所需的数。
|
||||
|
||||
**复核结论:R-2(启用 CCM)已部分落地**——`.sct` 现为手工 scatter,除 `ER_IROM1` + `RW_IRAM1 0x20000000 0x00020000` 外新增 `RW_CCM 0x10000000 0x0000FF00`(**只收 `heap_4.o (+RW +ZI)`**)与 `UNINIT_CCM 0x1000FF00 UNINIT 0x00000100`(`*(.noinit)`,崩溃现场跨复位保留区)。→ **FreeRTOS 堆 `ucHeap` 49,152 B 已迁 CCM**(.map `ucHeap 0x10000020`),任务栈从此不占 SRAM1,SRAM1 因此从 96.6% 降到 **69.8%**。⚠ **未迁的部分仍在 SRAM1**:LVGL 池 `work_mem_int` 40,960 B(`0x20008d00`)、UI 帧/绘制缓冲 `ui_port.o` 6,420 B、UI 网络发送 `ui_net_sink.o` 6,766 B——即 R-2 的"−54,122 B"只兑现了 49,184 B(堆),**LVGL 池与 UI 缓冲这 54 KB 里还剩 54,146 B 在 SRAM1**(见 §5.3 R-2 状态)。
|
||||
|
||||
> **基线口径说明**:上表取 **2026-10-11 00:38 链接的 `.map`(HEAD `54d6d2d`,干净树)**。复核期间工作区另有**未提交**改动(`adcTask` 栈 512→**640 words**、新增 `App/algo/adc_health.c/h` + 主机侧套件),其 01:12 重链接结果为 `Code=258,520 / RO=16,208 / RW=880 / ZI=139,896` → `Code+RO` **274,728 B(26.2%)**、`RW_IRAM1` **91,544 B(69.8%)**、`RW_CCM` 49,184 B(75.3%)。差异仅 +868 B Code / +56 B SRAM1,**不影响本节任何结论**;栈迁 CCM 后任务栈大小变化只影响堆内占用,不改 `ZI` 总量。
|
||||
|
||||
**RW+ZI 主要对象(2026-10-11 复核,`scripts/ram_report.py` 排行;括号内为 2026-09-16 基线)**
|
||||
**RW+ZI 主要对象(`ram_baseline.tsv` 末行 Top-10)**
|
||||
|
||||
| 对象 / 符号 | 字节 | 所在区域 | 归属 | DMA 可达性 |
|
||||
|-------------|------|---------|------|-----------|
|
||||
| `ucHeap`(`heap_4.o`) | 49,184(49,184) | **CCM**(`0x10000020`) | FreeRTOS 堆 | **DMA 不可达**——凡从堆里分配且被 DMA 直接寻址的缓冲都会失效(N-11 由此升级为**结构性约束**,见下) |
|
||||
| `work_mem_int`(`lv_mem_core_builtin.o`,= `LV_MEM_SIZE 40*1024`) | 40,960(40,960) | **SRAM1**(`0x20008d00`) | LVGL 池 | 纯 CPU,**可迁 CCM(R-2 未完成项)** |
|
||||
| `ui_net_sink.o`(`g_tx` + `g_lcdmem_data` + `g_rx`) | 6,766(6,762) | SRAM1 | UI 网络发送 | 可迁 CCM(CH395F 侧 memcpy 到自有 SRAM1 缓冲) |
|
||||
| `ui_port.o`(`g_ui_fbuf` + `g_ui_draw_buf`) | 6,420(6,412) | SRAM1 | UI 帧/绘制缓冲 | 可迁 CCM |
|
||||
| `nand_ftl.o`(3×2,048 页缓冲 + 控制块) | 6,216(6,216) | SRAM1 | 存储 | **必须 SRAM1**(N-11) |
|
||||
| `lftpd.o` | 4,768 | SRAM1 | FTP | 任意 |
|
||||
| `ucHeap`(`heap_4.o`) | 57,376 | **CCM**(`0x10000020`) | FreeRTOS 堆(`configTOTAL_HEAP_SIZE` 56 KB + 元数据) | **DMA 不可达**——规则 R3「堆/栈禁为 DMA 源/目的」已写进 `../内存管理/内存内容分配策略.md` §4,并由 `gd5f_dma_buf_ok()` 运行时强制 |
|
||||
| `work_mem_int`(`lv_mem_core_builtin.o`,= `LV_MEM_SIZE 40*1024`) | 40,960 | **SRAM1** | LVGL 池 | 纯 CPU,**可迁 CCM(R-2 未完成项)** |
|
||||
| `lftpd.o` | 7,884 | SRAM1 | FTP(含鉴权) | 任意 |
|
||||
| `ui_net_sink.o`(`g_tx` + `g_lcdmem_data` + `g_rx`) | 6,766 | SRAM1 | UI 网络发送 | 可迁 CCM(CH395F 侧 memcpy 到自有 SRAM1 缓冲) |
|
||||
| `ui_port.o`(`g_ui_fbuf` + `g_ui_draw_buf`) | 6,420 | SRAM1 | UI 帧/绘制缓冲 | 可迁 CCM |
|
||||
| `nand_ftl.o`(3×2,048 页缓冲 + 控制块) | 6,216 | SRAM1 | 存储 | **必须 SRAM1**(规则 R2/R3) |
|
||||
| `ch395f.o`(`s_spi2_dma_tx/rx[2052]`) | 4,162 | SRAM1 | 网络 | **必须 SRAM1** |
|
||||
| `console_log.o`(行环形缓冲) | 4,120 | SRAM1 | 日志 | 任意(TX 走 DMA → 实际必须 SRAM1) |
|
||||
| `ch395f.o`(`s_spi2_dma_tx/rx[2052]`) | 4,106(4,105) | SRAM1 | 网络 | **必须 SRAM1** |
|
||||
| `default_task.o` | 2,728 | SRAM1 | 任务薄壳 | — |
|
||||
| `gd5f2gq5ue.o`(`s_bbt_page_buf[2048]` + BBT 表) | ≈2,596(2,596) | SRAM1 | 存储 | **必须 SRAM1** |
|
||||
| `default_task.o` | 2,736 | SRAM1 | 任务薄壳 | — |
|
||||
| `sys_log_mcu.o` | 1,924 | SRAM1 | 日志 | 任意 |
|
||||
| `cmsis_os2.o` | 1,724(1,724) | SRAM1 | RTOS 胶水 | 任意 |
|
||||
| `sample_ring.o`(L2 输入 2 周波环缓冲,**新增**) | 1,448 | SRAM1 | 算法 | 任意 |
|
||||
| `startup_...o`:`STACK 0x400`(`HEAP 0x200` 已被链接器移除) | 1,024(1,536) | SRAM1 | MSP + MicroLIB 堆 | 任意 |
|
||||
| `tasks.o`(含 `pxReadyTasksLists[56]` = 1,120) | 1,280(1,280) | SRAM1 | RTOS | 任意(`configMAX_PRIORITIES` 仍 56 → **R-5 未办**) |
|
||||
|
||||
**两个静态池(49,184 + 40,960 = 90,144 B)仍是 RAM 问题的核心**,但**已分居两区**:堆在 CCM(占 CCM 的 75.3%)、LVGL 池在 SRAM1(占 SRAM1 的 45%)。→ 下一步收益点在**把 LVGL 池 + UI 两份缓冲(54,146 B)也搬进 CCM**,或按 R-9 先实测下调 `LV_MEM_SIZE`。⚠ 堆进 CCM 带来一条新铁律:**从 FreeRTOS 堆分配的缓冲不可被 DMA 直接寻址**(DMA2 不可达 `0x10000000`)——本仓已实测到同款约束(ADC1 DMA 目的缓冲必须在 `RW_IRAM1`),应写入 `docs/内存管理/`。
|
||||
**两个静态池(57,376 + 40,960 = 98,336 B)仍是 RAM 问题的核心**,且**分居两区**:堆在 CCM(占 CCM 的 87.9%)、LVGL 池在 SRAM1(占 SRAM1 的 42%)。→ 下一步收益点在**把 LVGL 池 + UI 两份缓冲(54,146 B)也搬进 CCM**,但 CCM 只剩 7,904 B → 必须先按 R-9 缩池并缩堆(解锁链 → `../内存管理/RAM预算台账.md` §3)。⚠ 迁移前必须过 DMA 可达性清单:区域放置与"堆/栈禁为 DMA 源/目的"的规则族(R1~R4)以 `../内存管理/内存内容分配策略.md` §4 为准,本仓另有两条实证同族约束(ADC1 DMA 目的缓冲必须在 `RW_IRAM1`;CCM 上做 DMA 静默不落地)。
|
||||
|
||||
**Flash 侧(Code+RO)**:基线为 214 个含码对象;**2026-10-11 复核为 182 个含码对象**(按 `.map` 组件表对象名归类,`App/`+`Src/`+`Drivers/BSP/` 合并为"应用/驱动自研",算法层单列)
|
||||
**Flash 侧(Code+RO,按 `.map` 组件表对象名归类)**
|
||||
|
||||
| 子系统 | Code+RO(基线) | 占镜像 | **2026-10-11** | **占镜像** |
|
||||
|--------|----------------|--------|----------------|-----------|
|
||||
| LVGL(含核心/绘制/控件/字体/缓存/图像) | ≈150,600 | **61.5%** | **152,185** | **55.4%** |
|
||||
| 应用/驱动自研(`App/` + `Src/` + `Drivers/BSP/`,不含 UI 页面) | 10,468(仅 App+Src) | 4.3% | **27,076** | 9.9% |
|
||||
| 网络(NET + NETCFG + lftpd) | 18,245 | 7.4% | **21,629** | 7.9% |
|
||||
| 手写 UI 页面/框架(`ui_*.o`,现 6,036 行) | 17,520 | 7.2% | **18,535** | 6.8% |
|
||||
| 存储(FatFs + dhara + NAND) | 8,222 | 3.4% | **15,133** | 5.5% |
|
||||
| HAL/CMSIS | 11,866 | 4.8% | **14,391** | 5.2% |
|
||||
| FreeRTOS + CMSIS-RTOS | 8,011 | 3.3% | **12,258** | 4.5% |
|
||||
| 算法层 L1/L2(`adc_input`/`phasor`/`sample_ring`,**新增**) | — | — | **1,589** | 0.6% |
|
||||
| 其他(startup/CMSIS 胶水等) | — | — | 5,842 | 2.1% |
|
||||
| **合计(含库成员与填充)** | **245,384** | 100% | **274,728** | 100% |
|
||||
| 子系统 | Code+RO | 占镜像 |
|
||||
|--------|---------|--------|
|
||||
| LVGL(核心/绘制/字体/缓存/图像) | 87,706 | **38.0%** |
|
||||
| 网络(NET + CH395F + NETCFG + lftpd) | 27,561 | 11.9% |
|
||||
| 存储(FatFs + dhara + NAND + 卷锁) | 19,265 | 8.3% |
|
||||
| 手写 UI 页面/框架(`ui_*.o`) | 18,507 | 8.0% |
|
||||
| FreeRTOS + CMSIS-RTOS | 13,562 | 5.9% |
|
||||
| HAL/CMSIS | 13,532 | 5.9% |
|
||||
| 算法层 L1~L3(`adc_input`/`phasor`/`sample_ring`/`prot_*`) | 5,454 | 2.4% |
|
||||
| 其余(`App/` 应用与驱动自研、startup、C 库、填充) | ≈45,449 | ≈19.7% |
|
||||
| **合计** | **231,036** | 100% |
|
||||
|
||||
**复核要点**:LVGL 的**绝对量几乎没动**(150,600 → 152,185),占比从 61.5% 降到 55.4% 纯粹是因为**自研侧涨了 ≈30 KB**(看门狗 + Fault 采集 + ADC 全链 + 相量层 + 日志/观测)。→ **§5.4 的裁剪结论依旧成立且更划算**:省下的 54.6 KB 现在相当于镜像的 **19.9%**。
|
||||
**要点**:LVGL 的绝对量自 F-1/F-2/F-3 裁剪后**未再增长**(87,706 B),但仍是镜像最大单一子系统 → §5.4 的剩余裁剪(≈10 KB)与 F-5 的编译时长收益依旧成立。
|
||||
|
||||
### 5.2 结构性诊断(四条 + 未闭环部分)
|
||||
### 5.2 结构性诊断(三条)
|
||||
|
||||
1. **64 KB CCM 空转**,而 96.6% 的负载压在 128 KB SRAM1 上。
|
||||
→ **未闭环**:LVGL 池 **40,960 B** + UI 两份缓冲 **13,186 B** 仍在 SRAM1;堆迁入后 **CCM 只剩 16,304 B,装不下这 54 KB** → R-2 的剩余部分**必须先做 R-9(下调 `LV_MEM_SIZE`)或 R-4(帧副本去重)**才有余地。
|
||||
2. **任务栈全部动态取自 FreeRTOS 堆**:`osThreadAttr_t` 只设 `stack_size` 不设 `stack_mem`(`Src/freertos.c:64-105`)→ 栈 + idle/timer 栈 + TCB + IPC 全部从堆里扣,**留给动态分配的实际余量很紧**。
|
||||
→ **未闭环**:7 条任务(`defaultTask/netTask/ftpTask/testTask/uiTask/timeSyncTask/adcTask`)栈合计 **10,176 words = 40,704 B**,仍全部动态取自堆。实测 `load: OK (523B, heap free 8840B)` → 空闲约 **8.8 KB / 49,152 B**,历史最低水位(`xPortGetMinimumEverFreeHeapSize`)**6,640 B**(2026-10-11 L2 相量 + L1-6 上链后由 7,152 B 降下来);同日 `adcTask` 栈由 512 抬到 **640 words**(静态最坏链 1,080 B),继续蚕食堆余量。**R-6(栈静态化)是把"池内碎片"变"可核算静态区"的正解,且其前置条件(观测常开)已满足。**
|
||||
3. **零观测**:`xPortGetFreeHeapSize`/`xPortGetMinimumEverFreeHeapSize`/`uxTaskGetStackHighWaterMark` 全库零调用,无法回答"还能加多少"。
|
||||
→ 已解决(三面观测:`[STACK]` 运行时水位 + `scripts/stack_report.py` 静态最坏链 + `ram_report.py`/`check_mem_numbers.py` 门禁),不再列为待办。
|
||||
4. **MicroLIB 512 B C 堆是隐形地雷**:任何新代码写一个 `malloc` 都会中招。
|
||||
→ **未闭环**:`Heap_Size EQU 0x200` 未变、`.map` 仍 `Removing startup_stm32f407xx.o(HEAP), (512 bytes)`;铁律已进 AGENTS.md(只用 `pvPortMalloc/vPortFree` 或收进平台后端),但**没有机械化检查**——`check_coding_standard.py` 未含 `malloc(` 正则 → §5.5 第 5 条未落地。
|
||||
1. **CCM 已被堆占掉 87.9%(只剩 7,904 B)**,而 LVGL 池 + UI 两份缓冲 **54,146 B** 仍在 SRAM1。
|
||||
→ R-2 的剩余部分**必须先做 R-9(下调 `LV_MEM_SIZE`)+ 缩堆**才有余地;顺序不可颠倒(`../内存管理/RAM预算台账.md` §3)。
|
||||
2. **任务栈全部动态取自 FreeRTOS 堆**:`osThreadAttr_t` 只设 `stack_size` 不设 `stack_mem`(`Src/freertos.c`)→ 8 条产品任务栈合计 **9,792 words = 39,168 B**(另 testTask 2,048 words 仅测试构建)连同 idle/timer 栈、TCB、IPC 全部从堆里扣,**留给动态分配的实际余量很紧**(堆 56 KB 是 2026-10-12 B5 扩容后的值)。
|
||||
→ **R-6(栈静态化)是把"池内碎片"变"可核算静态区"的正解,前置条件(观测常开 + `stack_report.py` 每任务最坏链)已满足。** 实时水位以串口 `[STACK]` / 自检打印为准,不在本文固化快照。
|
||||
3. **MicroLIB 512 B C 堆是隐形地雷**:任何新代码写一个 `malloc` 都会中招。
|
||||
→ `Heap_Size EQU 0x200` 未变、`.map` 仍 `Removing startup_stm32f407xx.o(HEAP), (512 bytes)`;铁律已进 AGENTS.md(只用 `pvPortMalloc/vPortFree` 或收进平台后端),但**没有机械化检查**——`check_coding_standard.py` 未含 `malloc(` 正则 → §5.5 第 5 条未落地。
|
||||
|
||||
### 5.3 RAM 优化路线(收益/风险/优先级)
|
||||
|
||||
| 编号 | 措施 | 收益 | 风险 | 优先级 | **2026-10-11 状态** |
|
||||
|------|------|------|------|--------|---------------------|
|
||||
| **R-2** | **启用 CCM**:`.sct` 增 `RW_IRAM2 0x10000000 0x00010000 { *(CCM_DATA) *(.bss.CCM_DATA) }`;对 LVGL 池用 `LV_MEM_ATTR __attribute__((section("CCM_DATA")))`,UI 四份帧缓冲同样加段属性;用 `APP_CCM_ENABLE` 宏包裹(克隆片兜底 = 全部回 SRAM1) | **−54,122 B(52.9 KiB)** = 40,960 + 6,400 + 6,762 | 中:必须确保这些缓冲**不被任何 DMA 直接寻址**。已核实 UI 发送路径 memcpy 进 CH395F 自有 SRAM1 DMA 缓冲(`ch395f.c:1132-1190`),LVGL 为纯 CPU;**NAND 路径(N-11)绝对不可迁入** | **P1,本季度** | 🟡 **只做一半**:`.sct` 加了 `RW_CCM`,但**只收 `heap_4.o`**(49,184 B)→ SRAM1 −49,184 B。LVGL 池 + UI 两份缓冲(54,146 B)**未迁**;`APP_CCM_ENABLE` 宏**未采用**(该宏已从 `app_cfg.h` 删除)。⚠ 复核新增前置条件:**CCM 只剩 16,304 B,这 54 KB 装不下** → 必须先做 R-9 或 R-4 |
|
||||
| **R-3** | 存储页缓冲合并:`gd5f.s_bbt_page_buf` 与 `nand_ftl.s_copy_buf` 复用(BBT 仅在 init 期使用);`nand_ftl` 三块 2 KB 中 `s_page_buf`(dhara scratch) 与 `s_copy_buf` 不可并发 | **−2 ~ −4 KB** | 中:需严格审查 dhara 调用序列(copy 期间不会用 map scratch) | P2 | ❌ 未办(合并未做);🟡 但 `s_bbt_page_buf` 已由 2,048 B 收紧为 **272 B**(2026-09-21,等效省 1,776 B) |
|
||||
| **R-4** | UI 帧副本去重:同一 3,200 B 帧当前存 **4 份**(`g_ui_draw_buf` → `g_ui_fbuf` → `g_lcdmem_data` → `g_tx`)。让 `ui_flush_cb` 直接把 `color_p` 交给 sink、sink 在发送时才拼帧头(就地写 8 B 头 + 复用同一 buffer) | **−6.4 ~ −9.6 KB** | 中:需要 sink 与 LVGL 刷新生命周期对齐(同任务,可控) | P1 | ❌ 未办(`ui_port.o` 6,420 + `ui_net_sink.o` 6,766 = 13,186 B,副本数未变) |
|
||||
| **R-5** | `configMAX_PRIORITIES` 56 → 32(实际最高用到 `osPriorityHigh` 级别) | **−480 B** | 低 | P2 | ❌ 未办(`FreeRTOSConfig.h:69` 仍 56;`pxReadyTasksLists[56]` = 1,120 B 仍在) |
|
||||
| **R-6** | 任务栈改**静态分配**(`stack_mem` 指向各自 `.bss` 数组),从堆里释放 32,768 B | 堆可用 +32 KB(**总量不变**,但把"池内碎片"变成"可核算静态区") | 低-中:静态后溢出检测更难发现;先测水位再定尺寸 | P2 | ❌ 未办(仍全部 `stack_size` 动态)。⚠ 前置条件已满足:观测已三面常开,`stack_report.py` 已给出每任务最坏链 → 可直接按实测值定尺寸 |
|
||||
| **R-8** | 观测常开:新增 `memStatsTask`(最低优先级,1 Hz,512 w)打印 `xPortGetFreeHeapSize` / `xPortGetMinimumEverFreeHeapSize` / 各任务高水位 / `lv_mem_monitor`,并支持串口命令按需打印 | 0(可核算) | 低 | **P1**(是 R-2/R-6 的前置) | 🟡 **目标达成、形态不同**:未建 `memStatsTask`,改为 ① 开机/自检打印 `[STACK]` 水位 + 堆空闲;② `scripts/stack_report.py`(静态最坏链)+ `ram_report.py`;③ `check_mem_numbers.py` 门禁 + `docs/内存管理/data/` 快照。**已足够支撑 R-2/R-6 决策** |
|
||||
| R-9 | `LV_MEM_SIZE` 40 KB → 依 R-8 实测峰值下调(既有方案预估 16 KB) | −16 ~ −24 KB | 低(有 R-8 兜底) | P2 | ❌ 未办(`lv_conf.h:44` 仍 `(40 * 1024)`)。⚠ 复核:`simulator/tests/check_content_pages.py` 已带**池水位门禁** → 实测峰值数据已具备,本条只差改数值 + 真机复跑(⚠ 两端 `lv_conf.h` 要同步改) |
|
||||
| 编号 | 措施 | 收益 | 风险 | 优先级 | 状态 |
|
||||
|------|------|------|------|--------|------|
|
||||
| **R-2** | **启用 CCM 承载 LVGL 池与 UI 缓冲**:对 `work_mem_int` 与 UI 帧/绘制缓冲加段属性(`.sct` 已有 `RW_CCM`) | **−54,146 B** | 中:必须确保这些缓冲**不被任何 DMA 直接寻址**。已核实 UI 发送路径 memcpy 进 CH395F 自有 SRAM1 DMA 缓冲,LVGL 为纯 CPU;**NAND 路径(规则 R2/R3)绝对不可迁入** | **P1(W3)** | 🟡 **只做一半**:`RW_CCM` 只收 `heap_4.o`(57,376 B)→ SRAM1 已减 49 KB+。⚠ 前置条件:**CCM 只剩 7,904 B,这 54 KB 装不下** → 必须先 R-9 + 缩堆 |
|
||||
| **R-3** | 存储页缓冲合并:`nand_ftl` 三块 2 KB 中 `s_page_buf`(dhara scratch) 与 `s_copy_buf` 不可并发,可复用 | **−2 KB** | 中:需严格审查 dhara 调用序列(copy 期间不会用 map scratch) | P2 | ❌ 未办(`s_bbt_page_buf` 已单独收紧为 272 B) |
|
||||
| **R-4** | UI 帧副本去重:同一 3,200 B 帧当前存 **4 份**(`g_ui_draw_buf` → `g_ui_fbuf` → `g_lcdmem_data` → `g_tx`)。让 `ui_flush_cb` 直接把 `color_p` 交给 sink、sink 发送时才拼帧头 | **−6.4 ~ −9.6 KB** | 中:需要 sink 与 LVGL 刷新生命周期对齐(同任务,可控) | P1 | ❌ 未办(`ui_port.o` 6,420 + `ui_net_sink.o` 6,766 = 13,186 B,副本数未变) |
|
||||
| **R-6** | 任务栈改**静态分配**(`stack_mem` 指向各自 `.bss` 数组),从堆里释放 ≈39 KB | 堆可用 +39 KB(**总量不变**,但把"池内碎片"变成"可核算静态区") | 低-中:静态后溢出检测更难发现;先测水位再定尺寸 | P2 | ❌ 未办。⚠ 前置已满足:观测三面常开 + `stack_report.py` 已给出每任务最坏链 → 可直接按实测值定尺寸 |
|
||||
| R-9 | `LV_MEM_SIZE` 40 KB → 依实测峰值下调(既有方案预估 16 KB) | −16 ~ −24 KB(SRAM1) | 低(有池水位门禁兜底) | P2(**R-2 后半的前置**) | ❌ 未办(两份 `lv_conf.h` 仍 `(40 * 1024)`)。⚠ `simulator/tests/check_content_pages.py` 已带**池水位门禁** → 实测峰值数据已具备,本条只差改数值 + 真机复跑(**两端 `lv_conf.h` 必须同步改**,`lv-conf-sync` 钩子会拦) |
|
||||
|
||||
**组合结果预估(注意措施之间存在重叠,不可简单相加)**
|
||||
> ⚠️ **R-2 与 R-4 不可叠加计算**:R-4 省的是"副本份数",R-2 已把这四份缓冲整体搬到 CCM,因此 **R-4 在 R-2 之后省的是 CCM 而非 SRAM1**(CCM 侧 13,186 B → ≈6.8 KB,为后续 UI 扩展腾空间)。若只做 R-4 不做 R-2,则直接为 SRAM1 省 6.4 KB——两条路线对 RAM 总量等价,**但顺序决定收益落在哪个区域**。
|
||||
>
|
||||
> **R-5 已判定不可行(原建议 `configMAX_PRIORITIES` 56→32 省 480 B)**:CMSIS-RTOS2 包装层 `freertos_os2.h:293` 有 `#if (configMAX_PRIORITIES != 56) #error`——改小直接编译失败。为 480 B 去改第三方包装层不划算,**本条关闭**(登记簿 N-27 的评估清单已据此剔除 R-5)。
|
||||
|
||||
| 组合 | SRAM1 变化 | 说明 |
|
||||
|------|-----------|------|
|
||||
| 基线 | 126,584 B / **96.6%** | 余 4,488 B |
|
||||
| **+ 实际执行(2026-10-11 实测)** | **91,488 B / 69.8%** | 余 **39,584 B**。实际做的 ≠ 预估路径:**R-2 只搬堆(−49,184 B → CCM 49,232 B / 75.1%)** + R-7(−8,192 B)+ BBT 缓冲收紧(−1,776 B);抵消项 = adcTask 栈、`sample_ring` 1,448 B、`console_log` 4,120 B、Fault/看门狗/日志新增 |
|
||||
| + R-2(CCM 启用,原预估全量) | **72,462 B / 55.3%** | −54,122 B;CCM 用 54,122 B(仍余 11 KB)。⚠ 复核:该预估**已不可直接执行**——堆先占了 CCM 49,184 B,CCM 只剩 16,304 B,装不下 LVGL 池 + UI 缓冲这 54 KB |
|
||||
| + R-3(存储页缓冲合并) | **≈66.3 KB / 50.6%** | −2,048 ~ −4,096 B(BBT 收紧已等效省 1,776 B) |
|
||||
| + R-5(优先级 56→32) | **≈65.8 KB / 50.2%** | −480 B |
|
||||
|
||||
> ⚠️ **R-2 与 R-4 不可叠加计算**:R-4(UI 帧副本 4→2)省的是"副本份数",R-2 已把这四份缓冲整体搬到 CCM,因此 **R-4 在 R-2 之后省的是 CCM 而非 SRAM1**(CCM 侧 13,162 B → 6,762 B,为后续 UI 扩展腾出 6.4 KB CCM 空间)。若只做 R-4 不做 R-2,则直接为 SRAM1 省 6.4 KB——两条路线对 RAM 总量等价,**但顺序决定收益落在哪个区域**:先做 R-2 时,R-4 应重新定性为"CCM 优化"。
|
||||
|
||||
最终形态(原预估):**SRAM1 约 50%、CCM 约 20% 使用率**,`L6406E`(P1-10 测试镜像溢出)随之消解,并为 ADC 数据路径与 RS485 协议栈预留预算空间。
|
||||
|
||||
> **2026-10-11 修正(未闭环部分)**:原预估的**执行顺序已不可按原样走**——实际走到 **SRAM1 69.8% / CCM 75.3%**,因为选了"先搬堆"而非"先搬 LVGL 池 + UI 缓冲",**CCM 已被堆占掉 75%(只剩 16,304 B)**。要拿到剩余收益,顺序必须改为 **R-9(下调 `LV_MEM_SIZE`,最省事的杠杆)或 R-4(帧副本去重)→ 再做 R-2 后半段**。另两条仍开放:**`L6406E` 未完全消解**(登记簿留 P1-10 收尾:CH395F 套件构建实测链接确认 + `@test` 闭环);RS485 协议栈前置件 `crc.c`/`ringbuf.c` 已删除,**需从零重做**而非"注册"。
|
||||
|
||||
> 与 `docs/内存管理/RAM使用分析与优化方案.md` 的关系:本表**沿用其阶段划分**(阶段 0 测量 / 阶段 1.1 池收缩 / 阶段 1.2 CCM / 阶段 2 堆收缩),新增的是 ①R-4 帧副本去重(原文档未识别 4 份副本)②R-3 存储侧缓冲合并 ③N-11 的 **DMA 可达性硬边界**(原文档未提出,属实施风险关键点)④观测前置条件(已落地,见 §5.5)。
|
||||
与 `../内存管理/RAM使用分析与优化方案.md` 的关系:本表**沿用其阶段划分**(阶段 0 测量 / 阶段 1.1 池收缩 / 阶段 1.2 CCM / 阶段 2 堆收缩),本报告新增的是 ①R-4 帧副本去重(原文档未识别 4 份副本)②R-3 存储侧缓冲合并 ③**DMA 可达性硬边界**(原报告 N-11 提出,现已沉淀为 `../内存管理/内存内容分配策略.md` §4 规则 R2/R3,属实施风险关键点)。
|
||||
|
||||
### 5.4 Flash 优化(未闭环:F-4 / F-5 / F-6)
|
||||
|
||||
> **F-1 / F-2 / F-3 已落地并销项(2026-10-11)**:`Lib/lv_conf.h` 与 `simulator/lv_conf.h` 对齐为同一特性子集(只留 `LV_DRAW_SW_SUPPORT_I1`、零控件、`LV_USE_THEME_SIMPLE 0`、`LV_USE_FLEX/GRID 0`)→ **实测省 64,576 B**:`ER_IROM1` 274,724 → **210,148 B**,Flash 26.3% → **20.1%**。比本报告原估(54,630 B)多省约 10 KB——锚点消失后,`blend_to_i1` 内部按**源**格式的分支与 `transform` 的格式分支也一并退出。完整记录(对象级对照、上游 9.3.0 漏守卫的配套补丁、ui-verify 证据)见 `../内存管理/RAM使用分析与优化方案.md` §2.6.4 与 `../UI设计/UI_设计架构.md` §1.4 第 10 条。
|
||||
> **F-1 / F-2 / F-3 已落地并销项(2026-10-11)**:两份 `lv_conf.h` 对齐为同一特性子集 → **实测省 64,576 B**,Flash 26.3% → 20.1%(现 22.0%,增量来自 B4/B5 功能代码)。完整记录见 `../内存管理/RAM使用分析与优化方案.md` §2.6.4 与 `../UI设计/UI_设计架构.md` §1.4 第 10 条。
|
||||
|
||||
| 编号 | 措施 | 可省 Flash | 依据 | **2026-10-11 状态** |
|
||||
|------|------|-----------|------|---------------------|
|
||||
| **F-4** | 关闭未用的绘制子模块与 `LV_USE_SNAPSHOT`(MCU 端)/`LV_USE_OBJ_PROPERTY`/`LV_USE_FLOAT` 等 | 可评估部分 **≈10 KB** | 新镜像对象实测:`mask` 3,862 + `box_shadow` 3,246 + `draw_sw_img` 2,960 + `bin_decoder` 1,972 + `image_decoder` 952 + `triangle` 930 + `transform` 598 + `grad` 420 + `mask_rect` 372 = **15,312 B**;工程无图片、无阴影、无变换 | ❌ 未办(数字已按 F-1 后的新镜像重测,`transform` 已从 4,340 降到 598)。⚠ **不可盲目关**:`mask`/`mask_rect`/`grad` 是文字与矩形绘制的必经路径;真正可评估的是 `box_shadow` + `draw_sw_img` + `bin_decoder` + `image_decoder` + `triangle` ≈ **10.1 KB** |
|
||||
| **F-5** | 从 uvprojx 中**移除未使用的 LVGL 控件源文件**(201 个 → 实际需要的子集) | 编译时长 −40% 左右 | 与 F-2 配合;`lv_conf` 关开关后文件仍参与编译,删文件才省编译时间 | ❌ 未办(uvprojx 现挂 **306 个 `.c`,其中 LVGL 仍 201 个**)。⚠ F-2 落地后这些 TU 现在编出来是**空目标文件**(文件级 `#if` 全灭),删文件的收益更纯粹、风险更低 |
|
||||
| 编号 | 措施 | 可省 Flash | 依据 | 状态 |
|
||||
|------|------|-----------|------|------|
|
||||
| **F-4** | 关闭未用的绘制子模块与 `LV_USE_SNAPSHOT`(MCU 端)/`LV_USE_OBJ_PROPERTY`/`LV_USE_FLOAT` 等 | 可评估部分 **≈10 KB** | 对象实测:`box_shadow` 3,246 + `draw_sw_img` 2,960 + `bin_decoder` 1,972 + `image_decoder` 952 + `triangle` 930 ≈ **10.1 KB**;工程无图片、无阴影、无变换 | ❌ 未办。⚠ **不可盲目关**:`mask` 3,862 / `mask_rect` / `grad` 是文字与矩形绘制的必经路径 |
|
||||
| **F-5** | 从 uvprojx 中**移除未使用的 LVGL 控件源文件**(201 个 → 实际需要的子集) | 编译时长 −40% 左右 | 与 F-2 配合;`lv_conf` 关开关后文件仍参与编译,删文件才省编译时间 | ❌ 未办(uvprojx 现挂 **323 个 `.c`,其中 LVGL 仍 201 个**)。⚠ F-2 落地后这些 TU 现在编出来是**空目标文件**,删文件的收益更纯粹、风险更低 |
|
||||
| **F-6** | 双精度软浮点:`dadd`/`dmul`/`ddiv`/`depilogue`/`dfixul`(`mf_w.l`),来自 `printf` 的 `%f`/double 提升 | −1 KB + 运行期性能 | 日志与 UI 全用定点;把 `%f` 改整数刻度 | ❌ 未办(新镜像仍链入 `dadd.o`) |
|
||||
|
||||
**剩余可回收 ≈ 10–11 KB Flash**(F-4 可评估部分 + F-6);F-5 省的是编译时长不是 Flash。原"≈50 KB 死代码"的主体(64,576 B)已在 2026-10-11 消除。
|
||||
**剩余可回收 ≈ 10–11 KB Flash**(F-4 可评估部分 + F-6);F-5 省的是编译时长不是 Flash。
|
||||
|
||||
### 5.5 内存治理长效机制(+ 2026-10-11 复核)
|
||||
### 5.5 内存治理长效机制
|
||||
|
||||
> **已闭环(2026-10-12,登记簿 N-27 前半 / W1-0)**:① 超阈值即失败的 **`mem-budget` 钩子**(`ram_baseline.py --gate`,**92% 红线** + Top-10 RW+ZI 附表,无 `.map` 自适应跳过)② 趋势基线 **`scripts/ram_baseline.tsv`**(`--update` / `--trend`)③ **`../内存管理/RAM预算台账.md`**(子系统配额 + CCM 分配台账 + 超配额流程)。
|
||||
> **阈值与配额的权威值现在只在那份台账里**(本报告不再重复数值);`mem-numbers` 钩子继续防"文档数字漂移"。
|
||||
>
|
||||
> **已闭环(2026-10-11,登记簿 N-26)**:**DMA 可达性清单与规则族**——`../内存管理/内存内容分配策略.md` §3「全板 DMA 使用方清点」+ §4 规则 R1~R4(含 **R3 堆/栈禁为 DMA 源/目的**),落地为编译期窗口断言 + 启动期自检 + 运行时守卫三层(见 §4.3)。原"独立清单文档 + `_Static_assert`"的建议形态**已被这份更好的实现取代**。
|
||||
|
||||
仍开放一条:
|
||||
|
||||
1. **`scripts/ram_report.py` 升级为门禁**:超阈值(如 SRAM1 > 92%)即失败,并在 PR 描述里自动附 Top-10 对象表。
|
||||
→ **🟡 部分实现**:`scripts/check_mem_numbers.py` 已挂 pre-commit(以 `.map` 为**唯一事实源**,校验 `docs/内存管理/RAM使用分析与优化方案.md` 的 `MEM_SNAPSHOT:BEGIN/END` 受管区 + 散句陈旧数字扫描)——**防的是"文档数字漂移",不是"占用超阈值"**。⚠ 无 92% 阈值失败逻辑;且 CI 上无 `.map` 时该钩子自适应跳过(登记簿 **A-5 残余**)。
|
||||
→ ✅ **2026-10-12 闭环**:新增 `mem-budget` 钩子(`scripts/ram_baseline.py --gate`)——RW_IRAM1/RW_CCM >92% 即 FAIL + Top-10 RW+ZI 附表;无 `.map` 自适应跳过(A-5 残余口径不变)。
|
||||
2. **建立 `[计划] scripts/ram_baseline.tsv`**(`docs/内存管理/RAM使用分析与优化方案.md:172` 已承诺但未创建):每次构建记录 Code/RO/RW/ZI/Top 对象,形成趋势。
|
||||
→ **❌ 未建**;🟡 等效物已存在:`docs/内存管理/data/` 下 5 份 `ram_report`/`stack_report` 快照留档(人工触发,非 tsv 趋势表)。
|
||||
→ ✅ **2026-10-12 闭环**:`scripts/ram_baseline.tsv` 已建(`--update` 每次 @build 后追加;`--trend` 高亮 RW+ZI 增长 >1 KB 对象)。
|
||||
3. **RAM 预算台账**(同上,文档已承诺 `[计划] docs/内存管理/RAM预算台账.md`):按子系统配额(网络 12 KB / 存储 12 KB / UI 16 KB / RTOS 48 KB / 应用 8 KB),超配额必须先申请。
|
||||
→ **❌ 未建**。⚠ 复核:这条的价值在上升——堆已进 CCM 且只剩 16,304 B CCM 余量,"谁还能用 CCM"必须有台账,否则 R-2 后半段无法排期。
|
||||
→ ✅ **2026-10-12 闭环**:`docs/内存管理/RAM预算台账.md` 已建——子系统配额(网络 12/存储 12/UI 16/RTOS 堆 48/应用 8 KB,现状超配 = W3 债务如实展示)+ **CCM 分配台账**(谁能用 CCM、R-2 后半解锁链)+ 超配额流程 + 受管区自动生成。
|
||||
4. **DMA 可达性清单**(新增,源于 N-11):文档化"哪些缓冲必须 SRAM1",并在 CCM 迁移时对该清单加 `_Static_assert`/地址断言(`assert((addr & 0xFFF00000) == 0x20000000)`)。
|
||||
→ **🟡 半落地**:独立清单文档未建,但**铁律已进 AGENTS.md**("DMA 目的缓冲必须在 SRAM,DMA2 不可达 CCM 0x10000000"、"改 ADC 流后回 NVIC 核对");代码侧另有**运行时**守卫(`gd5f2gq5ue.c:110-136` 不可达回落轮询)。⚠ 仍缺**编译期/启动期断言**,且需补一条新铁律:**从 FreeRTOS 堆分配的缓冲不可被 DMA 直接寻址**(堆已在 CCM)。
|
||||
5. **禁止新增 C 库 `malloc`**:写进 `docs/代码规范/`,并在 `check_coding_standard.py` 加正则检查(`App/`、`Drivers/` 内出现 `malloc(` 即告警)。
|
||||
→ **🟡 前半已做、后半未做**:AGENTS.md 已有"自研代码禁用 C 库堆分配"铁律(含模拟器照不出来的原因);❌ `check_coding_standard.py` **未含 `malloc(` 正则** → 目前只靠人评审,属机械检查缺口。
|
||||
→ **🟡 前半已做、后半未做**:AGENTS.md 已有铁律(含模拟器照不出来的原因);❌ `check_coding_standard.py` **未含 `malloc(` 正则** → 目前只靠人评审,属机械检查缺口。
|
||||
|
||||
---
|
||||
|
||||
@@ -491,17 +431,15 @@ Select-String -Path 'MDK-ARM\STM32F407-Demo\STM32F407-Demo.map' -Pattern '__heap
|
||||
|
||||
| 层 | 现状 | 评价 |
|
||||
|----|------|------|
|
||||
| 内容页 | `ui_content_page.c` 描述符表 `s_defs[]` **仅 7 页**(DEVICE_INFO/AC/DC/PASSWORD/NET_CFG/RUN_LOG/SELFTEST_LOG) | ❌ **42 个菜单叶子中仅 7 个有内容页**,`menu_content_page_for()`(`ui_menu.c:155/:205`)是**手写 switch 映射**。**2026-10-11 复核:未改善**——`ui_menu_tab.h:28` 仍 42 节点(**叶子 33 个**),有内容页的叶子 **6 个**(PASSWORD 非叶子映射);`menu_content_page_for()` 现位于 `ui_menu.c:118-128`,仍是手写 `case 1u/3u/4u/30u/39u/40u:` |
|
||||
| 设计令牌 | **无**(每页自带 `CP_SCREEN_W/H 160`、`CP_TITLE_Y 2`、`CP_PAGE_LINE_Y 143`、`CP_ROW_BUF_LEN 32` 等布局常量) | ❌ 魔法数字分散在各页。**2026-10-11 复核:`Drivers/BSP/UI/ui_tokens.h` 仍不存在**(U1 未办) |
|
||||
| golden 回归 | 已建成,但**不在文档承诺的 `tools/ui_mock/`**,而是 `simulator/tests/` 四脚本:`check_menu_rows.py`(菜单 8 状态全像素)、`check_content_pages.py`(内容页黄金参考逐字节 + 文本断言 + LVGL 池水位门禁)、`regen_ref_png.py`、`check_remo_sink.py` | 🟡 **有基线但未入门禁**:两个脚本未挂 pre-commit / `ui-verify`;`docs/UI设计/UI_界面制作流程.md` / `UI_自动化测试流程.md` 仍指向不存在的 `tools/ui_mock/`(语义断链) |
|
||||
| 内容页 | `ui_content_page.c` 描述符表 `s_defs[]` **7 页**(DEVICE_INFO/AC/DC/PASSWORD/NET_CFG/RUN_LOG/SELFTEST_LOG) | ❌ `ui_menu_tab.h:28` 42 节点(**叶子 33 个**),有内容页的叶子 **6 个**(PASSWORD 非叶子映射);`menu_content_page_for()`(`ui_menu.c:118-128`)仍是手写 `case 1u/3u/4u/30u/39u/40u:` |
|
||||
| 设计令牌 | **无**(每页自带 `CP_SCREEN_W/H 160`、`CP_TITLE_Y 2`、`CP_PAGE_LINE_Y 143`、`CP_ROW_BUF_LEN 32` 等布局常量) | ❌ 魔法数字分散在各页,`Drivers/BSP/UI/ui_tokens.h` 不存在(U1 未办) |
|
||||
| golden 回归 | `simulator/tests/` 四脚本:`check_menu_rows.py`(菜单 8 状态全像素)、`check_content_pages.py`(内容页黄金参考逐字节 + 文本断言 + **LVGL 池水位门禁**)、`regen_ref_png.py`、`check_remo_sink.py` | 🟡 **有基线但未入门禁**:两个脚本未挂 pre-commit / `ui-verify` |
|
||||
|
||||
### 6.2 新增一个页面要走多少步(当前)
|
||||
|
||||
1. `ui_menu_tree.txt` 加节点 → 2. 重跑 `gen_menu.py` → 3. 新建 `ui_page_xxx.c` → 4. 在 `ui_content_page.c` 的枚举/`s_defs[]` 注册 → 5. 在 `ui_menu.c:menu_content_page_for()` 手写 `case N:`(**下标硬编码,表序一变即错**)→ 6. 注册到 `MDK-ARM/*.uvprojx` → 7. 注册到 `simulator/CMakeLists.txt` → 8. 新汉字跑 `font-regen`。
|
||||
|
||||
**5 步是纯机械劳动且 2 处易错(步骤 5 的魔法下标、步骤 6/7 漏注册)。**
|
||||
|
||||
> **2026-10-11 复核:8 步流程一步未减。** 步骤 5 的手写 `case` 仍在(`ui_menu.c:118-128`);步骤 6/7 的漏注册仍无机械校验(`check_registration.py` 未建)——但已新增一条**间接暴露路径**:若新文件落在新目录而没把目录加进 `uvprojx` 的 `<IncludePath>`,消费者 TU 会报 `cannot open source input file`(AGENTS.md 2026-10-10 记录),这类报错落在**别的文件**上、易误判,仍不等于"存在但未注册"的检查。
|
||||
**8 步里 5 步是纯机械劳动且 2 处易错(步骤 5 的魔法下标、步骤 6/7 漏注册)。** 步骤 6/7 如今有 `registration-check` 钩子兜底(存量走白名单),但**新页面落在新目录而没把目录加进 `uvprojx` 的 `<IncludePath>`** 时,报错落在**消费者 TU** 上(`cannot open source input file`),仍不等于"存在但未注册"的检查。
|
||||
|
||||
### 6.3 标准化目标:四层 + 一个闭环
|
||||
|
||||
@@ -535,7 +473,7 @@ graph LR
|
||||
#define UI_COL_BG LV_COLOR_WHITE
|
||||
#define UI_COL_SEL_FG UI_COL_BG
|
||||
#define UI_COL_SEL_BG UI_COL_FG
|
||||
/* 样式:只用 const 描述符(动态 lv_style 会每次泄漏 88 B,见 ui_content_page.c:100-104) */
|
||||
/* 样式:只用 const 描述符(动态 lv_style 会每次泄漏 88 B,见 ui_content_page.c) */
|
||||
extern const lv_style_const_prop_t UI_STYLE_FLAT[];
|
||||
```
|
||||
|
||||
@@ -561,8 +499,7 @@ extern const lv_style_const_prop_t UI_STYLE_FLAT[];
|
||||
| `records`(分页日志) | SOE/事故/操作/保护告警/保护启动/遥控/自检/运行记录/运行报告 | `record_provider_t{ count(); get(idx, ts, text); }`(sys_log 已是这个形态) |
|
||||
| `action`(确认型) | 强制复归、清除记录、手动录波 | 提示 → 二次确认 → 执行 → 结果日志 |
|
||||
|
||||
菜单树 42 个叶子中,**除已实现的 7 个外,其余 35 个可 100% 归入这 4 类原型**(form 21 个、records 9 个、detail 3 个、action 2 个)。这意味着**剩余页面工作量从"35 页 × 各自设计"降为"4 个原型 + 35 份数据绑定"**。
|
||||
> **2026-10-11 口径修正**:42 是 `ui_menu_tab.h:28 UI_MENU_TAB_COUNT`(根 + 41 节点)的**节点数**,**叶子实为 33 个**;已有内容页的叶子 **6 个** → 待落地 **27 页**(不是 35)。四类原型的分布按 27 页重算即可,结论不变。
|
||||
**口径**:`ui_menu_tab.h:28 UI_MENU_TAB_COUNT` = 42(根 + 41 节点),**叶子实为 33 个**;已有内容页的叶子 **6 个** → 待落地 **27 页**。四类原型的分布按 27 页重算即可。这意味着**剩余页面工作量从"27 页 × 各自设计"降为"4 个原型 + 27 份数据绑定"**。
|
||||
|
||||
**L3 页面实例** — 目标形态(以"遥测死区"为例,全部新代码约 30 行):
|
||||
|
||||
@@ -584,117 +521,97 @@ const ui_page_desc_t ui_page_deadzone = UI_FORM_PAGE("遥测死区", s_items_dea
|
||||
|
||||
产物:`ui_page_registry.c` 含 `node_index → (page_id, archetype, desc*)` 常量表 + `ui_page_registry_for(node)`;`ui_menu.c` 只需一次调用。生成器同时校验:`@page` 指向的描述符是否存在、是否有节点声明了页但无实例、是否有实例未被任何节点引用(编译期断言或生成期报错)。
|
||||
|
||||
**闭环门禁(1 天)**——未闭环 2.5 条:
|
||||
**闭环门禁(1 天)**——未闭环 2 条:
|
||||
|
||||
1. `[计划] scripts/check_registration.py`(同 §2.3 S-3)保证新页面两端都注册 → **❌ 仍未建**(`scripts/` 现有 11 个脚本,无此项)。
|
||||
2. **golden 回归**(原方案:`simulator --shot` 导出 1bpp 帧 + PNG 逐像素比对)已按另一路径建成(`simulator/tests/` 四脚本,见 §6.1)。**未闭环**:`UI_界面制作流程.md:413` 与 `UI_自动化测试流程.md:104` 仍指向不存在的 `tools/ui_mock/`;这些脚本未挂进 pre-commit / `ui-verify` 门禁。
|
||||
3. 字符集自动校验:构建前扫描所有 `ui_*.c` 中的汉字,与 `ui_cn_chars.txt` 求差集,缺失即 FAIL(把 `font-regen` 从"记得跑"变成"漏跑就红") → **❌ 未入门禁**:`font-regen` skill 已把四步固化并写进 AGENTS.md("含新汉字的 UI 文案提交前先跑"),但**仍是约定不是门禁**(无 pre-commit 钩子做差集检查)。
|
||||
1. **golden 回归入门禁**:`simulator/tests/` 四脚本已建成,但未挂进 pre-commit / `ui-verify`。
|
||||
2. **字符集自动校验**:构建前扫描所有 `ui_*.c` 中的汉字,与 `ui_cn_chars.txt` 求差集,缺失即 FAIL(把 `font-regen` 从"记得跑"变成"漏跑就红")→ ❌ 未入门禁(`font-regen` skill 已把四步固化并写进 AGENTS.md,但**仍是约定不是门禁**)。
|
||||
|
||||
### 6.4 UI 侧的内存纪律(必须写进规范)
|
||||
|
||||
| 规则 | 依据 |
|
||||
|------|------|
|
||||
| 页面**不得**新增静态大缓冲;文本缓冲统一用 `UI_BUF_STRLEN` | 现有 `s_ts/s_desc` 已是范式 |
|
||||
| 每页**只用** `lv_style_const_prop_t`,禁止运行期 `lv_style_init` | `ui_content_page.c:100-104` 已验证动态样式每次泄漏 88 B |
|
||||
| 优先自绘(`lv_draw_*` + `lv_text_get_width`),新控件需评审(会破坏 §5.4 F-2 **已落地**的裁剪,且须两端同步) | LVGL 现占镜像 **41.6%**(87,706 / 210,623 B;裁剪前 55%) |
|
||||
| 每页**只用** `lv_style_const_prop_t`,禁止运行期 `lv_style_init` | 已验证动态样式每次泄漏 88 B |
|
||||
| 优先自绘(`lv_draw_*` + `lv_text_get_width`),新控件需评审(会破坏 §5.4 F-2 **已落地**的裁剪,且须两端同步) | LVGL 现占镜像 **38.0%**(87,706 / 231,036 B) |
|
||||
| 帧缓冲任何改动必须遵守 R-4(副本数 ≤ 2) | 当前 4 副本 12.8 KB |
|
||||
| `LVGL 池`用量必须经 `lv_mem_monitor` 实测后才允许扩大 | 现 40 KB,预估可降到 16 KB |
|
||||
| `LVGL 池`用量必须经 `lv_mem_monitor` / 池水位门禁实测后才允许扩大 | 现 40 KB,预估可降到 16 KB(R-9) |
|
||||
|
||||
### 6.5 实施顺序(UI 专项,总计约 8 人日;2026-10-11 复核)
|
||||
### 6.5 实施顺序(UI 专项,总计约 8 人日)
|
||||
|
||||
| 步骤 | 内容 | 交付判据 | **2026-10-11 状态** |
|
||||
|------|------|---------|---------------------|
|
||||
| U1 | `ui_tokens.h` 令牌化(纯替换,不改行为) | `@build` PASS + 模拟器截图与替换前逐像素一致 | ❌ 未办(`ui_tokens.h` 不存在)。🟡 **但它的验收条件如今已可机械执行**——golden 基线已建,"逐像素一致"从口头判据变成可跑断言 |
|
||||
| U2 | `ui_w_records`(合并 runlog/selftest) | 两页行为不变,代码 −1 个文件 | ❌ 未办(`ui_page_runlog.c` / `ui_page_selftest.c` 仍是两份结构几乎相同的代码) |
|
||||
| U3 | `ui_w_form` + `ui_page_desc_t` 原型化 + 生成器产注册表 | 手工 `menu_content_page_for()` 删除;新增一页只需"改树 + 加实例文件" | ❌ 未办(`ui_page_registry.c` / `gen_page_registry.py` 均不存在;手写 `case` 仍在) |
|
||||
| U4 | golden 回归(模拟器 `--shot` + PNG 比对)+ 字符集检查 + 注册检查入 pre-commit | 三个新 hook 全绿 | 🟡 **1/3 落地**:golden 已建(`simulator/tests/` 4 脚本,见 §6.1);❌ 字符集差集检查未入门禁;❌ 注册检查未入门禁 |
|
||||
| U5 | 用原型批量落剩余 35 页(每页 ≤30 行) | 菜单树全绿、无 `CONTENT_PAGE_COUNT` 哨兵命中 | ❌ 未动。**复核修正口径**:42 节点 / **33 叶子** / 6 个叶子有内容页 → 待做 **27 页**(不是 35) |
|
||||
| 步骤 | 内容 | 交付判据 | 状态 |
|
||||
|------|------|---------|------|
|
||||
| U1 | `ui_tokens.h` 令牌化(纯替换,不改行为) | `@build` PASS + 模拟器截图与替换前逐像素一致 | ❌ 未办。🟡 **验收条件如今可机械执行**——golden 基线已建,"逐像素一致"从口头判据变成可跑断言 |
|
||||
| U2 | `ui_w_records`(合并 runlog/selftest) | 两页行为不变,代码 −1 个文件 | ❌ 未办(两份结构几乎相同的代码仍在) |
|
||||
| U3 | `ui_w_form` + `ui_page_desc_t` 原型化 + 生成器产注册表 | 手工 `menu_content_page_for()` 删除;新增一页只需"改树 + 加实例文件" | ❌ 未办(`ui_page_registry.c` / `gen_page_registry.py` 均不存在) |
|
||||
| U4 | golden + 字符集检查 + 注册检查入 pre-commit | 三个新 hook 全绿 | 🟡 **1/3 落地**:golden 已建;❌ 字符集差集、❌ 注册检查未入门禁(注册检查钩子已存在,缺的是把它算作 UI 门禁的一环) |
|
||||
| U5 | 用原型批量落剩余 **27 页**(每页 ≤30 行) | 菜单树全绿、无 `CONTENT_PAGE_COUNT` 哨兵命中 | ❌ 未动 |
|
||||
|
||||
> **本轮不排期**(2026-10-11 已确认,登记簿 U 簇 / W6):等功能主线出结果后按产品需求启动;U4 残余(两脚本入门禁)可逢窗口顺带。
|
||||
|
||||
---
|
||||
|
||||
## 7. 统一改进路线图
|
||||
|
||||
### P0(1 周内,必须)
|
||||
> **顺序的唯一权威 = [`../任务规划/README.md`](../任务规划/README.md) §2**(W1 采集保护收尾 → W2 数据正确性 → W3 预算与内存 → W4 结构债 → W5 验证常态 → W6 UI 扩展 → W7 仓库决策;B2 RS-485 暂缓)。本节只保留"本报告条目 → 波次"的映射,不另立顺序。
|
||||
|
||||
| 编号 | 事项 | 验收 | **2026-10-11 状态** |
|
||||
|------|------|------|---------------------|
|
||||
| N-02 | FTP 鉴权(或生产构建默认关闭 FTP 写) | 错误口令登录被 `530` 拒绝;`@test` 加 FTP 标记校验 | ❌ **未办,且未登记进登记簿** → 复核建议:补登为 P1(现场可被任意主机改写 IP/MAC 并断网) |
|
||||
| N-06 | 5 个未注册 `.c`:注册或显式删除 + 白名单 | `check_registration.py` 零告警 | 🟡 **半**:3 个消解(2 删 1 注册);❌ `rs485_task.c`/`lftpd_log.c` 仍未处理,❌ 脚本与白名单未建 |
|
||||
|
||||
### P1(1 个月内)
|
||||
|
||||
| 编号 | 事项 | 预期 | **2026-10-11 状态** |
|
||||
|------|------|------|---------------------|
|
||||
| N-04 / R-2 | **CCM 启用**(LVGL 池 + UI 帧缓冲,`APP_CCM_ENABLE` 门控)+ N-11 DMA 边界文档与断言 | SRAM1 96.6% → ~55% | 🟡 **半**:堆 49,184 B 已进 CCM → SRAM1 **69.8%**;LVGL 池 + UI 缓冲未迁(CCM 只剩 16,304 B,**必须先做 R-9/R-4**);`APP_CCM_ENABLE` 未采用;N-11 侧改为**运行时守卫**,仍无编译期断言 |
|
||||
| R-4 | UI 帧副本 4 → 2 | −6.4 KB | ❌ 未办(`ui_port.o` 6,420 + `ui_net_sink.o` 6,766 未变) |
|
||||
| N-12/N-13 | `dhara_nand_is_free` 全页校验;`dhara_nand_copy` 处理 `DHARA_NO_PAGE` | 掉电注入测试通过 | ❌ 未办(两处代码原样) |
|
||||
| N-16 | 日志常驻 `FIL` + 批量 flush;UI 记录读缓存升级 | 单条日志 NAND 操作次数下降 ≥50% | ❌ 未办(每条仍 open/write/close) |
|
||||
| D-1 | 芯片手册图片降采样 / 拆 submodule | clone 40 MB → ~8 MB | ❌ 未办;⚠ 且 `.git` 已膨胀到 **149 MB** → 还需一次历史重写,优先级上升 |
|
||||
| U1–U4 | UI 令牌化 + 原型库 + 生成器 + golden | 新增一页 ≤30 行 | 🟡 **U4 的 golden 已建**(`simulator/tests/` 4 脚本);U1/U2/U3 未动;U4 的注册检查与字符集检查未入门禁 |
|
||||
| P1-7 / P1-8 / P1-10 | 沿用台账(MAC 写序 / 重建失败恢复 / 测试 RAM 溢出) | 台账闭环 | P1-7/P1-8 本轮未复核,仍按台账跟踪;**P1-10 🟡 收尾中**(登记簿唯一 P 类项,剩"套件构建实测链接确认 + `@test` 闭环"两步) |
|
||||
|
||||
### P2(一个季度内)
|
||||
|
||||
`R-3/R-5/R-6/R-9`、`F-4/F-5/F-6`、S-1/S-2/S-5、P2-1..P2-16 余项。
|
||||
|
||||
> **2026-10-11 复核**:`R-3/R-5/R-6/R-9`、`F-4/F-5/F-6`、**S-1/S-2** ❌ 未办(`NETCFG`/`UI` 的语义层错位、4 处裸 `extern` 原样);**S-5 🟡 已实现核心**(`App/fs/vol_lock.c` + 主机侧 33 例单测),"可选全序列卷锁"的剩余范围在登记簿。
|
||||
|
||||
### P3(机会性)
|
||||
|
||||
UI 剩余页面批量落地(U5)、目录级层次迁移(S-1 的物理搬迁)、`app_cfg.h` 开关体系重构、`Lib/lv_conf.h` 迁至 `Config/`。
|
||||
|
||||
> **2026-10-11 复核**:四条全部未动。⚠ 优先级更新:`Lib/lv_conf.h` 迁至 `Config/` 原建议"与 F-1..F-3 合并做"——**F-1..F-3 已于同日落地但位置未迁**,现需单独做,且要一并处理 `simulator/lv_conf.h`(两份必须保持同一特性子集,见 `../UI设计/UI_设计架构.md` §1.4 第 10 条);U5 的口径改为 **27 页**(33 叶子 − 6 已实现)。
|
||||
| 波次 | 本报告条目 | 验收要点 |
|
||||
|------|-----------|---------|
|
||||
| **W2 数据正确性** | N-12 / N-13(登记簿 N-21) | 整页扫描 + `DHARA_E_UNSUPPORTED` + **主机侧 dhara 移植层单测**(一并补覆盖率缺口) |
|
||||
| **W3 预算与内存** | R-9 → R-2 后半 → R-3/R-4/R-6 逐项评估 | 按 `../内存管理/RAM预算台账.md` §3 解锁链走,每步前后跑 `stack_report.py` / `ram_report.py` |
|
||||
| **W4 结构债** | N-16、N-14、F-4/F-5/F-6、S-1/S-2/S-4/S-5;`rs485_task.c` 随 B2 出注册白名单 | `--strict` 默认化;`bsp_err_t` 进规范 |
|
||||
| **W5 验证常态** | P1-10 收尾(构建实测链接 + `@test` 闭环) | 逢窗口顺手做 |
|
||||
| **W6 UI 扩展** | U4 残余 → U1 → U2/U3 → U5(27 页) | 新增一页 ≤30 行;**本轮不排期** |
|
||||
| **W7 仓库决策** | D-1(登记簿 N-29) | **已决策暂不处理**;推送/协作前重评 |
|
||||
|
||||
### 交付物清单(可直接排期)
|
||||
|
||||
| 交付物 | 类型 | 来源条目 | **2026-10-11 状态** |
|
||||
|--------|------|---------|---------------------|
|
||||
| `[计划] scripts/check_registration.py` | 新脚本 + pre-commit hook | S-3 / N-06 | ❌ **仍未建**(`scripts/` 11 个脚本里没有它)——这是本报告里**唯一一条"1 小时工作量、至今未做"**的机械检查 |
|
||||
| `scripts/ram_baseline.tsv` + `docs/内存管理/RAM预算台账.md` | 文档承诺落地 | §5.5 | ✅ **2026-10-12 已建**(`ram_baseline.py` 三模式:`--gate`/`--update`/`--trend`/`--write`;另有 `mem-budget` 钩子) |
|
||||
| 交付物 | 类型 | 来源条目 | 状态 |
|
||||
|--------|------|---------|------|
|
||||
| `test/host/dhara/`(移植层单测) | 主机侧单测 + pre-commit hook | N-12/N-13 | ❌ 未建——**这是唯一能防住"同类缺陷再犯"的手段** |
|
||||
| `Drivers/BSP/UI/ui_tokens.h` | 令牌层 | U1 | ❌ 未建 |
|
||||
| `Drivers/BSP/UI/ui_w_{list,kv,records,form,msgbox,title}.{c,h}` | 组件库(需双端注册) | U2/U3 | ❌ 未建 |
|
||||
| `tools/menu_gen/gen_menu.py` 扩展 + `ui_page_registry.c` 生成 | 生成器 | U3 | ❌ 未建(`gen_menu.py` 未扩展,注册表不存在) |
|
||||
| `[计划] docs/内存管理/DMA可达性清单.md` | 规范(含"哪些缓冲禁止进 CCM") | N-11 | 🟡 **半**:独立清单未建,但铁律已进 AGENTS.md + 代码有运行时守卫;⚠ 需补"堆缓冲不可 DMA"这一新条 |
|
||||
| `tools/menu_gen/gen_menu.py` 扩展 + `ui_page_registry.c` 生成 | 生成器 | U3 | ❌ 未建 |
|
||||
| `check_coding_standard.py` 加 `malloc(` 正则 | 门禁补强 | §5.5 第 5 条 | ❌ 未建 |
|
||||
| 字符集差集检查 + golden 挂 pre-commit | 门禁补强 | U4 残余 | ❌ 未建 |
|
||||
|
||||
---
|
||||
|
||||
## 附录 A 关键证据索引
|
||||
|
||||
| 结论 | 证据 | **2026-10-11 复核** |
|
||||
|------|------|---------------------|
|
||||
| SRAM1 96.6%、余 4,488 B | map:`Total RW Size (RW Data + ZI Data) 126584 (123.62kB)`;scatter `RW_IRAM1 0x20000000 0x00020000` | 🟡 已缓解:`RW_IRAM1` **91,488 / 131,072 = 69.8%(余 39,584 B)**;`Total RW` 140,720 B |
|
||||
| MicroLIB C 堆 = 512 B | map `:17405 0x2001e878 - 0x00000200 Zero RW HEAP startup_stm32f407xx.o`;`__heap_limit 0x2001ea78`;`MDK-ARM/startup_stm32f407xx.s:43 Heap_Size EQU 0x200` | ✅ 结论不变:`Heap_Size EQU 0x200` 未改,map 现 `Removing startup_stm32f407xx.o(HEAP), (512 bytes)`(未被引用 → 整段移除) |
|
||||
| lftpd 已迁 FreeRTOS 堆 | map `lftpd_io.o refers to heap_4.o(i.pvPortMalloc)` | 不变 |
|
||||
| 任务栈全部动态分配 | `Src/freertos.c:64-105` 的 `osThreadAttr_t` 无 `.stack_mem`;`freertos.o` ZI 仅 1,104 B | 不变(R-6 未办);7 任务栈合计 10,176 words,其中 adcTask 已抬到 640 words |
|
||||
| NAND 直接 DMA 调用方缓冲 | `gd5f2gq5ue.c:200`、`:258`(`GD5F_DMA_THRESHOLD = 32`) | 🟡 模式未变(`:325` 等),阈值改 **1024**(`gd5f2gq5ue.h:78`)+ 新增**运行时 DMA 可达性守卫**(`:110-136`,回落轮询) |
|
||||
| CH395F memcpy 自有缓冲 | `ch395f.c:1132-1190` | 不变(UI 缓冲仍可迁 CCM 的前提依旧成立) |
|
||||
| FTP 无鉴权 | `Drivers/BSP/NET/lftpd/lftpd.c:367-371` | ❌ 仍在:现 `lftpd.c:375-379`(`cmd_pass`)/ `:553-557`(`cmd_user`) |
|
||||
| 端口分配 | `App/sync/time_sync.c:25 TIME_SYNC_PORT 8888`;`Drivers/BSP/UI/ui_net_sink.h:29 UI_NET_SINK_PORT 7003`;FTP 21 | 不变 |
|
||||
| 42 菜单叶子 / 7 内容页 | `Drivers/BSP/UI/ui_menu_tab.c`(生成,42 节点);`ui_content_page.c:84-92 s_defs[]` | 🟡 口径修正:`ui_menu_tab.h:28 UI_MENU_TAB_COUNT 42`(根 + 41 节点)→ **叶子 33**、**有内容页的叶子 6**(枚举 7 页含 PASSWORD) |
|
||||
| 手写映射 | `ui_menu.c:155/:205 menu_content_page_for()` | 仍在,现位于 `ui_menu.c:118-128`(手写 `case 1u/3u/4u/30u/39u/40u:`) |
|
||||
| 文档体量 | 工作树字节统计(见 §3.1 表) | 见 §3.1 复核列:受控 2,363 文件 / 77.7 MB,`docs/` 849 / 44.4 MB,图片 703 张 / 36.3 MB,`.git` **149.3 MB** |
|
||||
| 结论 | 证据(2026-10-14) |
|
||||
|------|---------------------|
|
||||
| SRAM1 74.9%、余 32,928 B;CCM 87.9%、余 7,904 B | map `Execution Region RW_IRAM1 Size: 0x00017f60, Max: 0x00020000` / `RW_CCM Size: 0x0000e020, Max: 0x0000ff00`;`ram_baseline.tsv` 末行 |
|
||||
| MicroLIB C 堆 = 512 B | `MDK-ARM/startup_stm32f407xx.s` `Heap_Size EQU 0x200`;map `Removing startup_stm32f407xx.o(HEAP), (512 bytes)`(未被引用 → 整段移除) |
|
||||
| 任务栈全部动态分配 | `Src/freertos.c` 的 `osThreadAttr_t` 无 `.stack_mem`;8 条产品任务栈合计 9,792 words(R-6 未办) |
|
||||
| DMA 可达性三层防线(原 N-11 的处置) | 编译期窗口断言 `gd5f2gq5ue.h:96-107`(负数组 typedef)→ 启动期自检 `nand_ftl.c:241-243` → 运行时守卫 `gd5f_dma_buf_ok()`(`gd5f2gq5ue.c:121-139`);规则族 R1~R4 → `../内存管理/内存内容分配策略.md` §4;负路径用例 TC-GD5F-704/705 |
|
||||
| CH395F memcpy 自有缓冲 | `ch395f.c` SPI2 DMA 收发缓冲(`s_spi2_dma_tx/rx[2052]`)→ UI 缓冲仍可迁 CCM 的前提成立 |
|
||||
| dhara 两处缺陷 | `nand_ftl.c:152-179`(`uint8_t buf[64]`)/ `:204-216`(read→prog 直传,无哨兵判断) |
|
||||
| 日志逐条开关 | `sys_log_mcu.c:124-141`(`FA_WRITE | FA_OPEN_APPEND` → `f_write` → `f_close`,失败重建重试一次);`wdev.log` 同模式 `:486-489` |
|
||||
| 端口分配 | `App/sync/time_sync.c` `TIME_SYNC_PORT 8888`;`Drivers/BSP/UI/ui_net_sink.h` `UI_NET_SINK_PORT 7003`;FTP 21 |
|
||||
| 菜单 42 节点 / 33 叶子 / 6 个有内容页 | `ui_menu_tab.h:28 UI_MENU_TAB_COUNT 42`;`ui_content_page.c:84-92 s_defs[]`(7 页含 PASSWORD) |
|
||||
| 手写映射 | `ui_menu.c:118-128 menu_content_page_for()`(`case 1u/3u/4u/30u/39u/40u:`) |
|
||||
| 注册反向校验已机械化,仅剩一条刻意缺口 | `scripts/check_registration.py`(`KNOWN_GAPS` 只含 `App/task/rs485_task.c`,E-59/B2 刻意未接线)+ pre-commit `registration-check`;`lftpd_log.c` 已删除并入 `lftpd_auth.c` |
|
||||
| 仓库体量 | 受控 2,466 文件 / 79.3 MB;`docs/` 56.9 MB;`docs/芯片手册/` 图片 703 张 / 36.3 MB;`.git` **235.3 MB** |
|
||||
|
||||
## 附录 C 评审中确认"无需改动"的设计(避免后续误改)
|
||||
|
||||
| 项 | 结论 |
|
||||
|----|------|
|
||||
| CH395F SPI 分频 = 8 | **PCB 约束,禁止"优化"**(AGENTS 铁律,实测一致) |
|
||||
| 就绪屏障用 Event Flags 而非魔法延时 | 正确,保留 |
|
||||
| 就绪屏障用 Event Flags 而非魔法延时 | 正确,保留(就绪位必须 `osFlagsNoClear`) |
|
||||
| FatFs `FF_FS_REENTRANT=1` + 真实互斥 | 正确,保留(多数移植偷工) |
|
||||
| 配置引擎属主 = defaultTask | 正确(P1-3 已收敛),任何新代码不得跨任务触碰 |
|
||||
| 配置引擎属主 = defaultTask | 正确,任何新代码不得跨任务触碰 |
|
||||
| UI 只用 `lv_style_const_prop_t` | 正确且必要,禁止"顺手改成动态样式" |
|
||||
| `ffsystem.c` 引用 `sys_clock.h` | 有意为之(中间件需要真实时间),保留但在分层图中显式标注 |
|
||||
| UI 自绘而非 LVGL 控件 | 正确(1 bpp + 小 RAM),并是 Flash 裁剪的前提 |
|
||||
| `configMAX_PRIORITIES = 56` | **不可下调**:CMSIS-RTOS2 `freertos_os2.h` 硬性 `#error` 要求等于 56(原 R-5 建议因此关闭) |
|
||||
| 两份 `lv_conf.h` 同一特性子集 | 必要(F-1/F-2/F-3 的前提),由 `lv-conf-sync` 钩子守 |
|
||||
|
||||
---
|
||||
|
||||
**报告结束。**
|
||||
|
||||
> **2026-10-11 复核收尾**:
|
||||
> - ⚠ **台账漏登两条**:本报告 **N-02(FTP 无鉴权)** 与 **N-12/N-13(dhara 移植缺陷)** 既未修复也未登记在 `../任务规划/README.md` → 建议补登。
|
||||
> - ⚠ **编号撞车**:本报告曾用 N-18 指"无 CI"(该条已销项删除),而登记簿的 N-18 = "8 路电气量分属两片转换器(V0.2 改版项)"。引用时一律带文档名。
|
||||
> - ✅ `docs/内存管理/RAM预算台账.md` 与 `scripts/ram_baseline.tsv` **已于 2026-10-12 创建**(见 §5.5 各条闭环标注)。
|
||||
> - 本报告按 `docs/README.md` 的定位是**体系层评审报告,不是待办池**——待办一律以 `../任务规划/README.md` 为准;本报告只保留**未闭环问题的发现 + 证据**,修复即销项。
|
||||
> 本报告按 `../README.md` 的定位是**体系层评审报告,不是待办池**——待办与顺序一律以 [`../任务规划/README.md`](../任务规划/README.md) 为准;本报告只保留**未闭环问题的发现 + 证据**,修复即销项。
|
||||
|
||||
---
|
||||
|
||||
@@ -702,28 +619,32 @@ UI 剩余页面批量落地(U5)、目录级层次迁移(S-1 的物理搬
|
||||
|
||||
| 日期 | 类型 | 说明 |
|
||||
|------|------|------|
|
||||
| 2026-09-18 | 初版 | 全量审查;基线 `HEAD = 2d0ec35`、`.map` 链接于 2026-09-16 12:33;产出 N-01..N-18 / D-1..D-7 / S-1..S-5 / R-1..R-9 / F-1..F-6 / U1..U5 编号体系 |
|
||||
| 2026-09-18 | 实施记录 | N-01 按方案 A 落地(两处必要调整:分配收进 `cfg_file_store` 后端、`_Static_assert` 改 typedef 负数组) |
|
||||
| 2026-09-25 | 归档 | §3 文档分布章节标注"已归档(章节保留作历史)" |
|
||||
| 2026-10-10 | 就地更新 | N-10 改走"门控"并销项 |
|
||||
| 2026-10-11 | 现状复核 | 按当前代码与 `.map` 重跑全部数字并就地标注(§0.1 评级、§1.3 口径、§2.1 规模、§3.1 体量、§4.x 逐条、§5.1 基线双列 + 对象排行、§5.3/§5.4 状态列、§6/§7 状态);复核基线 `HEAD = 54d6d2d` + 00:38 `.map` |
|
||||
| **2026-10-11** | **修复即销项(本次)** | 与登记簿同一规则:**已修复项的分析正文与表格行从本报告删除**,报告只呈现未闭环问题(**874 → 733 行**,114 KB → 84 KB)。删除范围:§4.4.1 N-01 方案与实施记录、§4.1 N-03a/b·N-07·N-08·P2-13、§4.2 N-10、§4.8 P2-14/P2-15/N-17/N-18、§3.3 D-2..D-7、§5.3 R-1/R-7、§6.1 已闭环四层与字体、§7 P0/P1 已办行、交付物清单已建项、附录 A 已修行、**附录 B 断链清单整节**。§0.2/§0.4 改写为**未闭环清单**。原始推理与取证在未闭环条目中一律保留 |
|
||||
| **2026-10-11** | **实施 + 销项:F-1/F-2/F-3** | `Lib/lv_conf.h` 与 `simulator/lv_conf.h` 对齐为同一特性子集(只留 `LV_DRAW_SW_SUPPORT_I1`、5 个未用控件类全关、`LV_USE_THEME_SIMPLE 0`、`LV_USE_FLEX/GRID 0`,并删掉 9.3 不存在的 `LV_USE_THEME_BASIC` 与无效 `LV_USE_OBJ`);配套补 `lv_draw_sw_blend_to_i1.c` 上游漏的守卫 → **省 64,576 B**:`ER_IROM1` 274,724 → **210,148 B**,Flash 26.3% → **20.1%**(比原估 54,630 B 多约 10 KB)。验证:`@build` 0 错 0 警;ui-verify 五步全过(**11 页黄金参考在裁剪前生成、裁剪后逐字节一致**,菜单 8 状态像素一致,池水位 5440/5520 → 5368/5448);`@test` 真机 PASS。本报告同步:§5.4 只留 F-4/F-5/F-6(数字按新镜像重测)、§0.1 Flash 评级 B→A−、§0.2 Top 6→Top 5、§0.4 Flash 行、§5.1 加二次实测、附录 A 删两条已闭环证据行 |
|
||||
| 2026-09-18 | 初版 | 全量审查;基线 `HEAD = 2d0ec35`、`.map` 链接于 2026-09-16;产出 N-01..N-18 / D-1..D-7 / S-1..S-5 / R-1..R-9 / F-1..F-6 / U1..U5 编号体系 |
|
||||
| 2026-10-11 | 实施 + 销项:F-1/F-2/F-3 | 两份 `lv_conf.h` 对齐同一特性子集 → 省 64,576 B;验证链(`@build` / ui-verify / `@test`)与对象级对照见 `../内存管理/RAM使用分析与优化方案.md` §2.6.4 |
|
||||
| **2026-10-15** | **登记簿同步销项** | 本报告的 N-03c / N-11 对应登记簿 **N-20 / N-26** 两行已按「完成即销项」从 `../任务规划/登记簿.md` §5 删除(并清 `../任务规划/README.md` §1/§2 与 `排期详述.md` §1 的引用,W4 链由 6 项减为 5 项、结构/健壮性计数 9→7)。删除前补齐去处记录:`../子系统设计/看门狗设计说明.md` §4.4 新增 `Error_Handler` 统一降级一节、`../内存管理/内存内容分配策略.md` §4 R2 补编译期窗口断言与启动期自检两层 + §8 落点索引两行。同批订正登记簿三处过时内容:N-23 残余去掉已删除的 `lftpd_log.c`、N-25 去掉已删除的 `NET_RECV_TIMEOUT_MS`、N-27 剔除不可行的 R-5 并把 CCM 余量改为实测 7,904 B、N-29 的 `.git` 由 149 MB 订正为实测 235.3 MB |
|
||||
| **2026-10-14** | **清理:删除已完成与过时内容** | ① **已修复项按销项删除**(去处见下表):N-02(FTP 鉴权)、N-03c(`Error_Handler` 降级)、**N-11(DMA 可达性三层防线 + 规则族 R1~R4)**、S-3(注册反向校验)、P2-5/P2-6(SD2506 负温度与 WRTC)、P2-8(`NET_RECV_TIMEOUT_MS` 已删)、P2-9(`mkdir` 幂等重试)、§5.5 前三条(内存治理三件套)、交付物清单已建项。② **删除过时层**:2026-09-16 / 2026-10-11 双列基线表与"复核期间未提交改动"口径说明、旧"组合结果预估"表、逐条"2026-10-11 复核"批注、历史变更记录行——内存数字改由 `../内存管理/RAM预算台账.md` 与 `scripts/ram_baseline.tsv` 持有。③ **按 2026-10-14 `.map` 与代码重测**全部保留结论的数字(含 `lftpd_log.c` 已删除并入 `lftpd_auth.c`,N-06 残余只剩 `rs485_task.c` 一条刻意缺口)。④ **修正三处错误**:R-5(`configMAX_PRIORITIES` 56→32)**判定不可行**(CMSIS-RTOS2 `#error`);原 §7 把报告 S-5(驱动统一错误码)与登记簿 S-5(卷锁覆盖面)混为一谈;原 §5.5 第 4 条建议的 `_Static_assert` 形态在 AC5 上取不到链接期地址,已被"窗口断言 + 启动自检 + 运行时守卫"三层取代。⑤ 报告自有编号**不回改、不重排**(`../编号规范.md`) |
|
||||
|
||||
### 已销项条目的记录去处
|
||||
|
||||
> 删除前已逐条核对:以下去处文档均含完整记录,删了不丢信息。
|
||||
> 删除前已逐条核对:以下去处文档/代码均含完整记录,删了不丢信息。
|
||||
|
||||
| 已销项条目 | 去处 |
|
||||
|-----------|------|
|
||||
| N-01(配置引擎 C 堆必失败) | `../子系统设计/配置文件设计说明.md` §6.2 / §8(v1.13) |
|
||||
| N-01(配置引擎 C 堆必失败) | `../子系统设计/配置文件设计说明.md` §6.2 / §8 |
|
||||
| N-02(FTP 无鉴权,登记簿 N-19) | `../子系统设计/网络配置说明.md` §3.4(`[ftp] user/pwd_hash/write`、恒定时间比较、5 败锁 60 s、出厂默认口令告警、明文嗅探边界)+ `../产品需求/产品需求设计文档.md` §FTP 鉴权 + `Drivers/BSP/NET/lftpd/lftpd_auth.c` + 主机侧 `test/host/sha256/`、`test/host/ftp_auth/` |
|
||||
| N-03a/N-03b/N-07/N-08(IWDG、`configASSERT`、两个钩子、4 个 Fault 现场) | `../子系统设计/看门狗设计说明.md`(§4.4、§10.1/§10.2)+ AGENTS.md「平台约束」 |
|
||||
| N-03c(`Error_Handler` 死循环,登记簿 **N-20**,2026-10-15 已销项) | `../子系统设计/看门狗设计说明.md` §4.4(统一降级:1 条自检 + `NVIC_SystemReset()`、三条实现约束含 `__builtin_return_address` 不可用的实证、内核前日志路径安全性、重生成存活三层)+ 实施代码 `Src/main.c` 的 `USER CODE Error_Handler_Debug` 区注释 + `scripts/check_cubemx_survival.py` 审计项 |
|
||||
| N-06 主体(`crc.c`/`ringbuf.c`/`lftpd_log.c` 删除、`adc_task.c` 注册)+ S-3(注册反向校验,登记簿 N-23) | `scripts/check_registration.py`(`KNOWN_GAPS` 白名单 + `--strict`)+ `../代码规范/pre-commit使用说明.md`(`registration-check`);`lftpd_log.c` 并入 `Drivers/BSP/NET/lftpd/lftpd_auth.c` |
|
||||
| **N-11**(NAND 直 DMA 调用方缓冲 / CCM 迁移硬边界,登记簿 **N-26**,2026-10-15 已销项) | `../内存管理/内存内容分配策略.md` §3(全板 DMA 使用方清点)+ §4 规则 R1~R4(**R3 堆/栈禁为 DMA 源/目的**,含"缓冲自身地址无法编译期断言"这条边界)+ §8 落点索引;代码三层 = `gd5f2gq5ue.h:96-107` 编译期窗口断言 → `nand_ftl.c:241-243` 启动期自检 → `gd5f_dma_buf_ok()` 运行时强制;负路径用例 TC-GD5F-704/705 |
|
||||
| N-10(UI accept 门控) | `../UI设计/RemoDispBus协议与接收设计说明.md` §3 + 看门狗设计说明 §11.4 |
|
||||
| P1-1(ADC 数据路径) | `../子系统设计/ADC采样节拍设计说明.md` §10/§11 + `App/algo/README.md` |
|
||||
| N-17(栈/堆水位观测) | `../内存管理/RAM使用分析与优化方案.md` + `../测试说明/实机测试实施指南.md` |
|
||||
| N-18(本报告口径:无 CI) | `../测试说明/测试开发标准流程.md` §9 + `../环境与部署/CI配置指南.md` |
|
||||
| N-17(栈/堆水位观测)+ R-8(观测常开) | `../内存管理/RAM使用分析与优化方案.md` + `../测试说明/实机测试实施指南.md`(`[STACK]` 水位 + `stack_report.py` + `ram_report.py`) |
|
||||
| N-18(本报告口径:无 CI) | `../测试说明/测试开发标准流程.md` §9 + `../CI/README.md` |
|
||||
| P2-5 / P2-6(SD2506 负温度解析、WRTC 解锁顺序) | `Drivers/BSP/SD2506/sd2506.c`(符号扩展 `val \| 0xF0`;WRTC1→WRTC2/3 顺序按手册,上电即写禁止态) |
|
||||
| P2-8(`net_recv` 30 s 阻塞超时) | `Drivers/BSP/NET/net_config.h` 头注(2026-10-13 recv 语义主流化:删除 `NET_RECV_TIMEOUT_MS`,预算由调用方显式给)+ `../网络/Net层阻塞模型架构设计.md` |
|
||||
| P2-9(`mkdir` 失败不再重试) | `App/log/sys_log_mcu.c`(`s_fs_ready` 幂等 + `mkdir /log fail (%d), will retry` + 上报自检) |
|
||||
| P2-13 / P2-14 / P2-15 | AGENTS.md(`test-suite-switch`、`keil-build`、`stlink-flash`)+ `../测试说明/ST-LINK_CLI_复位使用说明.md` |
|
||||
| D-2 / D-3 / D-4 / D-5 / D-6 / D-7 | `../文档规范.md` + `../代码规范/pre-commit使用说明.md`;断链由 `scripts/check_doc_links.py` 门禁接管(`--all` = 129 文档 / 0 失效) |
|
||||
| U4(golden 回归) | `simulator/tests/` 四脚本 + `../UI设计/UI_自动化测试流程.md` |
|
||||
| D-2 / D-3 / D-4 / D-5 / D-6 / D-7 | `../文档规范.md` + `../代码规范/pre-commit使用说明.md`;断链由 `scripts/check_doc_links.py` 门禁接管 |
|
||||
| U4 主体(golden 回归) | `simulator/tests/` 四脚本 + `../UI设计/UI_自动化测试流程.md`(残余 = 挂门禁,见 §6.3) |
|
||||
| R-1 / R-7 | `../子系统设计/看门狗设计说明.md` + AGENTS.md 任务表(`scripts/gen_task_table.py` 生成区) |
|
||||
| F-1 / F-2 / F-3(LVGL 死代码裁剪,2026-10-11) | `../内存管理/RAM使用分析与优化方案.md` §2.6.4(对象级前后对照 + 上游漏守卫的配套补丁);`../UI设计/UI_设计架构.md` §1.4 第 10 条(**两份 `lv_conf.h` 必须同一特性子集**这条新硬约束);`../UI设计/UI_自动化测试流程.md` 变更记录(池水位基线 5440/5520 → 5368/5448 及理由) |
|
||||
| §5.5 前三条(92% 门禁 / 趋势基线 / 预算台账,登记簿 N-27 前半) | `../内存管理/RAM预算台账.md`(阈值与配额的**唯一权威**)+ `scripts/ram_baseline.py`(`--gate/--update/--trend/--write`)+ `../代码规范/pre-commit使用说明.md`(`mem-budget`) |
|
||||
| F-1 / F-2 / F-3(LVGL 死代码裁剪) | `../内存管理/RAM使用分析与优化方案.md` §2.6.4;`../UI设计/UI_设计架构.md` §1.4 第 10 条(**两份 `lv_conf.h` 必须同一特性子集**);`../UI设计/UI_自动化测试流程.md` 变更记录(池水位基线) |
|
||||
|
||||
@@ -292,12 +292,13 @@ static void phase7_test_timeout(void)
|
||||
}
|
||||
|
||||
/* TC 704:多 Socket 并发 TCP Client。
|
||||
* Socket 0~7 由索引寻址 + 缓冲显式分配即可全部使用(FUN_PARA bit0 是保留位,
|
||||
* 与 Socket 个数无关,见 TRAP-NET-15);本用例同时打开 Socket 0~7,
|
||||
* 各自连 PC echo server,每路独立收发 PHASE7_EXCH_SIZE 字节回显并比对,
|
||||
* 验证 8 个 Socket 均能独立工作。依赖 PC 端 tcp_server 支持并发连接。 */
|
||||
* 并发上限 = NET_MAX_SOCKETS(8) − 3 个常驻监听(FTP / 对时 / 远显)= 5;
|
||||
* 本用例同时打开 Socket 0~4,各自连 PC echo server,每路独立收发
|
||||
* PHASE7_EXCH_SIZE 字节回显并比对,验证 5 个 Socket 均能独立工作。
|
||||
* 依赖 PC 端 tcp_server 支持并发连接(--max-conn ≥ 5)。
|
||||
* (2026-10-15:原值 8 超出并发上限,socket create #5 必失败。) */
|
||||
#ifndef PHASE7_MULTI_COUNT
|
||||
#define PHASE7_MULTI_COUNT 8
|
||||
#define PHASE7_MULTI_COUNT 5
|
||||
#endif
|
||||
#ifndef PHASE7_MULTI_BASE_PORT
|
||||
#define PHASE7_MULTI_BASE_PORT 51000
|
||||
@@ -853,6 +854,7 @@ void net_layer_test_main(void)
|
||||
int32_t sockfd = -1;
|
||||
int32_t phase_active = 0;
|
||||
uint32_t accept_retry = 0;
|
||||
uint32_t gen = 0; /* 建立监听时的网络代次(代次变化 = 网络已重建) */
|
||||
struct net_sockaddr_in client_addr;
|
||||
int32_t addrlen = sizeof(client_addr);
|
||||
|
||||
@@ -880,6 +882,7 @@ void net_layer_test_main(void)
|
||||
return;
|
||||
}
|
||||
DBG_INFO("Test task: listening on 8080 (single-socket mode)");
|
||||
gen = net_get_generation(); /* 记录本监听对应的网络代次 */
|
||||
|
||||
/* ==================== 事件驱动阶段 ====================
|
||||
* Phase 6/8~11(NET 层)在 TCP 监听循环中运行,需要 PC 客户端连接。
|
||||
@@ -898,6 +901,25 @@ void net_layer_test_main(void)
|
||||
) {
|
||||
int32_t acc = net_accept(sockfd, (struct net_sockaddr *)&client_addr, &addrlen);
|
||||
if (acc < 0) {
|
||||
/* 网络重建(代次变化)→ 旧监听随芯片复位失效,重建 8080 监听 */
|
||||
if (net_get_generation() != gen) {
|
||||
struct net_sockaddr_in addr;
|
||||
DBG_INFO("Test task: network rebuilt, relisten 8080");
|
||||
net_close(sockfd);
|
||||
sockfd = net_socket(NET_AF_INET, NET_SOCK_STREAM);
|
||||
memset(&addr, 0, sizeof(addr));
|
||||
addr.sin_family = NET_AF_INET;
|
||||
addr.sin_port = net_htons(8080);
|
||||
if (sockfd < 0 ||
|
||||
net_bind(sockfd, (struct net_sockaddr *)&addr, sizeof(addr)) < 0 ||
|
||||
net_listen(sockfd) < 0) {
|
||||
DBG_ERROR("Test task: relisten failed");
|
||||
return;
|
||||
}
|
||||
gen = net_get_generation();
|
||||
accept_retry = 0;
|
||||
continue;
|
||||
}
|
||||
if (accept_retry % 100 == 0) {
|
||||
DBG_INFO("Test task: waiting for connection...");
|
||||
}
|
||||
|
||||
+1
-1
@@ -10,7 +10,7 @@
|
||||
|---|---|
|
||||
| `run_boot_test.py` | **`@test` 一键闭环**:开串口+清日志 → 烧录 → wait-idle → `verify_log` 校验(退出码 0=PASS) |
|
||||
| `verify_log.py` | **日志标记校验**:Required / Forbidden 标记 → PASS / FAIL;可选 `--require-suite-summary` 校验套件汇总行(`=== <名称>: N/M PASSED (failed=0) ===` 且 `N>0`),抓"没跑到汇总行/断言数为 0"的盲区(T-2) |
|
||||
| `e02_probe.py` | E-02 专项探针(错误码传播审计) |
|
||||
| `e02_probe.py` | E-02 专项探针(历史审计编号) |
|
||||
|
||||
### 网络 / FTP
|
||||
|
||||
|
||||
@@ -33,6 +33,7 @@
|
||||
* TC-CFG-021 非法键定义拒绝(UINT len 非 1/2/4、MAC len≠6、STR len>79)
|
||||
* TC-CFG-022 段名超长拒绝(≥ CFG_NAME_MAX)
|
||||
* TC-CFG-023 挂回调段 data_size > CFG_SNAP_MAX 拒绝
|
||||
* TC-CFG-024 键名超长拒绝(≥ CFG_NAME_MAX);恰好 15 字符(= CFG_FILE_MAX_NAME_LEN)接受
|
||||
* —— load 契约(cfg_file_load)——
|
||||
* TC-CFG-030 文件缺失 -> 生成出厂模板写盘 + 返回 0
|
||||
* TC-CFG-031 文件存在 -> 解析有效键进 RAM 副本
|
||||
@@ -574,6 +575,31 @@ static void tc_register(void) {
|
||||
r.p_cb = NULL;
|
||||
CHECK(cfg_file_register(&r) == 0, "same section without callback accepted");
|
||||
}
|
||||
|
||||
printf("[TC-CFG-024] key name length limit\n");
|
||||
{
|
||||
cfg_section_reg_t r;
|
||||
static const cfg_key_def_t long_key[] = {
|
||||
{ "0123456789abcdef", CFG_VAL_UINT, 0u, 1u } /* 16 chars >= CFG_NAME_MAX(16) */
|
||||
};
|
||||
static const cfg_key_def_t max_key[] = {
|
||||
{ "0123456789abcde", CFG_VAL_UINT, 0u, 1u } /* 15 chars = CFG_FILE_MAX_NAME_LEN */
|
||||
};
|
||||
|
||||
vfs_reset();
|
||||
memset(&r, 0, sizeof(r));
|
||||
r.name = "klen";
|
||||
r.p_data = &s_net_data;
|
||||
r.p_defaults = &s_net_def;
|
||||
r.data_size = 8u;
|
||||
r.key_count = 1u;
|
||||
|
||||
r.p_keys = long_key;
|
||||
CHECK(cfg_file_register(&r) == -1, "key name >= 16 chars rejected");
|
||||
|
||||
r.p_keys = max_key;
|
||||
CHECK(cfg_file_register(&r) == 0, "key name == 15 chars accepted");
|
||||
}
|
||||
}
|
||||
|
||||
/* TC-CFG-030~034:load 契约 */
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env python3
|
||||
"""E-02 头阻塞专项台架探针(timeSync 侧,A/B 对照用)。
|
||||
|
||||
场景(错误码传播审计.md E-02 的 timeSync 触发形态):
|
||||
场景(历史审计 E-02 的 timeSync 触发形态,属主文档已于 2026-10-15 删除):
|
||||
1. 一个"挂起"的对时客户端连上 :8888 后不发任何数据(空闲/故障客户端,
|
||||
常见工况)——旧固件在此触发 30s 阻塞 net_recv 独占 netTask,
|
||||
全体消费者的队列消息停摆最长 30s;
|
||||
|
||||
Reference in New Issue
Block a user