138aebc6d6ce2ef2c5f4b0677d9285c0fa11bcc8
160 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
2808ea9fb8 |
fix(104主站工具): RX 解析按本仓 6 字节头取位——PN 在 cause 字节 bit6(道D 批2.5 R1)
大窗实锤(2026-10-25,V5 间隙连 2404 复放两笔越界写):板端对 51.0@0x8030 与 2.0@0x8034 均回 type=50 / cause 字节=0x47(7|PN 0x40)——固件行为正确、无需重烧。 本工具 _asdu 旧解析按标准 2 字节 COT 的习惯去 byte[3](本仓语义 = OA+EVI)找 PN (恒 False),且 cause 字节未 &0x3F(拒绝帧读成 cot=71)→ actcon_of(type, True) 永不匹配 → E2_dbig / E2_kband exec / G2 三条 PN 断言超时。历史用例全部 want_pn=False,False 配恒 False 恒真,故 B6~D2 无人暴露;E2/G2 首次真机断言 负确认即命中(审计定位 lane-d,task-21 修复)。 - 提取纯函数 decode_cot(cause_byte) -> (cot&0x3F, bit6),_asdu 改用;byte[3] 不再 参与 PN;TX 侧 asdu() 未动(与固件 RX 本就对称) - COT_PN 常量处 NOTE 注释:本仓 B4 自定义 6 字节压缩头(T/PN/RBT=bit7/6/4 同字节, byte[3]=OA+EVI),引用 App/protocol/iec104/iec104_asdu.c put_hdr 为准;标注根治 走 COT=2 标准化合并单(登记簿「104 ASDU 头非标-COT1 压缩」,本票不动固件) - 新增离线样本单测 test/host/test_iec104_master_rx.py(纯 stdlib 无台架,6 用例: 两条窗口捕获帧字节重建 + 正例 actcon + 旧错误解码反证 + matcher 语义) - RX log 语义变化:拒绝帧从 cot=71 变为 cot=7 + " PN" 后缀(v5_log_gap_report.py 已核无 cot= 解析耦合) gate:py_compile 双文件过;单测 6/6 OK;全钩子常规跑(见提交记录);写域仅 test/host/iec104_master.py + test/host/(票面内),未加钩子(yaml 在写域外, 如需常态化由 lead 批 2.5 顺手)。 |
||
|
|
4332142680 |
feat(ui-pages): 遥信量 33 行固定名表页接实时快照(新增 yx_dp)
批 4 主体(票 task-15;规格 docs/UI设计/页面扩充详细方案.md §3.1.3 方案 A)。V0.1 只有 6 点有 硬件来源,其余 27 点在屏上就是 "--"——这是真实状态,不是页面没做完。 页面与数据 - 33 行固定名表(Flash const)+ 动态分页(8 行/页 = 5 页)。两处命名不照抄文档简写:idx0~3 屏上写「位置1~4」而非「YK1~4 位置」(遥信页出现 YK 前缀会被读成遥控对象,对应关系留在注释); idx30 写「保护闭锁」(写侧位号注释的语义即此,用编号反而丢信息)。idx4~13、idx31~32 点表未 定义功能名,如实写点号占位(YX5…、YX32),不编造功能名。 - 值映射次序:先判无效 → 再判单/双点 → 最后看位值。无效位上的位值不代表任何事实,次序颠倒就会 把垃圾位画成「复归」。 - 快照新增 yx_dp 双点位图(+8 B)。不教页面"前 4 点是双点":单双点是 104 点表事实(YX_DP_N / iec104_pts_yx_is_dp),抄进表现层就是第二真相——点表把双点段挪位或改起始下标,屏上不报错, 只会用错词形容同一个点。写侧逐点问 is_dp() 拼位图。 - UI_DATA_YX_N(33) 与 iec104_pts_yx_count() 编译期比不了(那个 #define 在协议层 .c 内),故写侧 留一条一次性 DBG_ERROR(约 90 B Flash,只在真漂移时打一次)。名表行数 = UI_DATA_YX_N 由数组 宽度法编译期守卫钉住(ARMCC C99 无 _Static_assert,本仓惯用写法)。 - 补 include 一条实测坑:DBG_ERROR 是宏,漏 include "dbg_log.h" 时 ARMCC 把它当隐式声明函数放过 编译期,错落在链接期(L6218E Undefined symbol DBG_ERROR)——报错点离根因隔了一整个链接步骤, 已在 include 处写明「DBG_TAG 必须在 include 之前」。 一个只有像素文本断言能抓到的截断 bug - 照抄批 1 的 *_PUT(dst, 源) 宏(长度取 sizeof(源)),但本表源是 const char *const 数组的 **元素(指针)**,sizeof 得 4 → 「故障总」被截成「故」,而 "YX9" 恰好 4 字节看起来完全正常。 编译器 / cppcheck / 编码钩子全不响。定位来自断言:第 2 页「过流Ⅰ段」匹配不到,同一行值列 「复归」却在原位 = 名字被截、值没错位。修法:长度取目标缓冲容量 UI_BUF_STRLEN。同名宏、不同 参数类别(数组 vs 指针),批 1 那处本身是对的,照抄才中招——教训写在宏定义上方。 模拟器与覆盖诚实性 - 固定帧发布 yx_dp = 0x0F,但刻意不把这几位置进 yx_valid:V0.1 无开入硬件,屏上就是 "--"。不用 「让它显示合位/分位」的假数据填满画面,那等于让黄金参考声称本机有开关位置遥信。 - 代价如实登记:合位/分位这条词映射当前**没有任何自动化证据**(像素恒 IV;页面依赖 LVGL 进不了 主机单测)。已写进方案 §3.1.3 落地注与契约落地进度·四,作为开入落地后的台架判据,不假装测过。 测试 - 主机单测 +2 条(TC-UIDATA-009c 双点位图原样透传、不被 valid 掩;009d 点数 33 的独立见证,注明 绊红时要同步改哪四处)→ 85/85。 - 文本断言 +33 条(yx / yxp2 两态,含页码钉住 33/8 = 5 页的分页数学);两页像素基线单独一笔。 - font-charset 本批零新增字:名表用字全部命中既有 183 字子集——「置/故/障/总/外/部」正属批 1 成组并入 KEEP_EXTRA 的那批字,第二次兑现(当时若按 extract 输出重写字符集,这些字早被洗掉, 上屏是空白,而门禁只会说「字不在清单里」)。 体积(同一棵树、构建前后的实测增量) - Code 224272→224688(+416);RO 24040→24640(+600);RW 1324→1328(+4); ZI 134844→135088(+244)→ Flash 约 +1020 B、RAM +248 B。 - RO 增量主要是 33 行名表与名称串,是"把 33 个真点名上屏"的代价,不是可省开销。 跳过的门禁(三条同族,同一根因):mem-numbers / mem-budget / size-gate(L0c)——台账与体积凭证 回填是 Lead 单写者,本分支不做静默处理,数值见上。 |
||
|
|
67c469fa40 |
feat(ui-pages): SOE 记录页接 soe_store 只读遍历(类型 7/8 首次上屏)
ui_w_soe 组件(task-14 落)此前两端都没绑 reader,只能显示"无记录"空态。本批补齐三件事:
App 侧只读遍历、两端 reader 绑定、SOE 记录页与菜单注册。
App/log/soe_store 只读 API(Lead 已放行,本批独占这两个文件)
- soe_store_count() / soe_store_read(idx, soe_rec_t*):与 syslog_count /
syslog_get_record 同构——8 条一窗(512 B)整块读、命中窗口零 I/O、卷锁 try(0 超时)
非阻塞;定长记录逐条 open 等于同一扇区开 4 次,SPI NAND 上这个差距是肉眼可见的卡顿
- 读者不得看到半成品记录,三道保障缺一不可(规则写进 soe_store.h 头注,不只是提交信息):
① 条数只数整条 64 B 槽(写者留下的半条尾槽天然不计入);② 窗口代数:写者每次成功落盘 /
容量重建在**卷锁区间内**自增代数,读者比对填窗时记下的代数,不符即重填(对齐 32 位读写
在 ARM 上原子,跨任务无需临界区,最坏多读一轮);③ 单条硬门槛:soe_rec_parse() 校版本 +
校验和,撕裂/半写一律拒收
- 容忍的竞态只有一个:count 与 read 之间新落一条 → 本轮少看一条,下轮重绘(200 ms)自然
追上;所以边界一律用锁内重取的条数,不信调用方传进来的旧值
- API **不带类型掩码**(Lead 裁定 2026-10-25):5 个记录页怎么分组是界面语义,不进日志存储
层;环容量小、页渲染全扫无成本,真变大了再加带 mask 的优化 API(YAGNI)
⚠ 顺带修掉一颗定时炸弹:菜单生成器与生成物漂移
- 提交里的 Drivers/BSP/UI/ui_menu_tab.h 带着 5 个表查询 API 的规范注释块,而
tools/menu_gen/gen_menu.py 只会输出"声明 + 行尾短注释"——说明历史上有人**手改生成物**
补注释、没回灌生成器。我这次加 #page=soe 后重新生成,等于把那些注释抹掉,bsp-err 立刻
报 5 条 return-doc
- 修法不是把生成物改回去(下次重新生成还会再抹一次),而是把注释块**回灌进生成器**;
回灌后重跑 gen_menu.py 产出的 ui_menu_tab.h 与 HEAD **逐字节一致**(git diff 为空),
漂移关闭。生成物里的手工优化 = 一定会被覆盖的优化,要么进生成器要么别改生成物
时标口径(跨模块陷阱,注释即防线)
- 页面时标取记录内的 CP56(事件自己的时标,不是"现在")。它与运行/自检记录页同口径,靠两条
事实叠出来:sys_clock 的 epoch 域本身就是本地时间(App/util/sys_clock.h 的
sys_clock_set_unix 注明"Unix epoch time (秒,本地时间)"),而 soe_rec.c 的 epoch→CP56
分解不加任何时区偏移。**谁"顺手补 8 小时",SOE 页就会和文本记录页差 8 小时**;要引显式
时区必须两侧一起改
显示名回正:类型 7 用源词"未标定闭锁"
- 组件名字表里原写作"标定闭锁"——缩掉一个"未"字后意思可以读成"把标定闭锁了",与"因未标定
而闭锁"几乎相反;源词见 App/log/soe_rec.h 与"数据可信"卡 5,UI 表现层无权改写事实词
- 模拟器的 3 条假记录刻意含一条 type 7 + ELM_NONE(非元件支路):这是 7/8 两个新类型
**真的接上屏**的第一个像素级证据——只有主机断言时,名字表写错也照样一片绿
- 主机测试的宽度护栏随之按"画到哪一列"分列:动作/返回进值列(4 汉字 = 12 字节),其余类型
名进名列(7 汉字 = 21 字节);原来一刀切 12 字节会把正常名字判成违规
页面与注册
- 新建 Drivers/BSP/UI/ui_page_soe.{c,h}:薄跳板,一条记录两行共用组件内单条读盘缓存,
实例独立(两页共用一份缓存会互相命中对方记录号,task-6 的教训)
- 菜单树 SOE记录 加 #page=soe;重生成 4 个生成物,uvprojx / CMakeLists 两处注册由生成器
自动写入(本批 uvprojx 只含这一条新增,无 UV4 抖动)
- reader 绑定在两端适配层:真机 App/task/ui_task.c(CP56 → UI 视图 + 容量钳位),
模拟器 simulator/main.c(固定 3 条、时标固定串,保证黄金参考可复现)
两处被门禁当场抓住的记录(都是有效拦截,不是噪音)
- id-check 拦下注释里裸引"P2-10":编号引用必须可判定归属,代码注释也一样 → 改为指向
App/log/sys_log_mcu.c 与事实本身,不留裸编号
- 又一次 BOM 铁律现场复现:一次编辑剥掉 ui_w_soe.c 的 BOM,ARMCC 立刻报一串 #8/#7/#20
假语法错(missing closing quote 之类),而 MSVC 侧 0 警告完全照不出来;补回 EF BB BF
即 0/0。本批提交前逐文件比 HEAD 做了 BOM 漂移审计(临时脚本,不入库)——建议把这条
审计固化进 ui-verify skill 或门禁(不在本道写域,已回报 Lead)
验证
- @build:0 错误 0 警告;模拟器:0 警告
- 内容页回归 15 项 PASS:新增 soe 页 9 条文本断言(两条时标、过流Ⅰ段+动作、+返回、
未标定闭锁、页码),其余 11 页逐字节不变;菜单 8 状态 PASS、池 5368 B
- soe 页刷新黄金参考前出图肉眼确认:6 行两两成对、19 字符时标在 94 px 名列内不越屏、
非元件行的类型名落在名列且值列为空
- test/host/ui_data 83/83、test/host/soe 32/32;13 个代码/文档/注册类钩子(含
coding-standard、bsp-err、id-check、cppcheck、registration-check、layer-deps、
font-charset、doc-links)全 Passed
- 全量钩子红项只有同族三条:mem-numbers / mem-budget / size-gate(L0c),root cause 一条:
Flash/RAM 台账与同码凭证回填归单写者 → 本批 --no-verify
体积(相对
|
||
|
|
8c72698666 |
feat(运行参数): 卡10 run_par真源收编+104段0x8020~0x8058读写映射(道D M6-①)
新增 App/algo/run_par.c/h(「数据可信」卡 10,lead 四裁落地): - [run_par] cfg 段:遥测死区 9 键 int32 毫单位(db_ua…db_freq),工厂默认 = 卡 6 额定 0.5% 档(500mV×4 / 5mA×4 / 500mHz);注册走 adc_cal 同款内核前 契约(app_main_init),不挂回调 = 引擎副本即生效值;键数 9≤16 不拆段 - 真源收编(裁③):pts 层 s_yc_db 运行时副本删除,COV 每拍实时读 run_par (协议→算法向下依赖,同 meas 先例;无投递无缓存 = 顺序/幂等平凡成立); iec104_pts_yc_set_deadband()/deadband() 保留为转发壳,壳内保留"成功清 半截确认计数"语义并由 TC-IEC104-027 追加断言钉住(裁⑤) - 104 地址映射(裁①):0x8030~0x8038 死区 9 点 / 0x8040~0x8047 k 覆盖 / 0x8048~0x804F b 覆盖(逐项地址本仓自定——复现规划 §5.4 权威表不在仓, 送检点表到位后替换 run_par.c 顶部常量段一处;已在 IEC104 §3.4 表头挂账); 路由顺序 = run_par 表先、未命中落 prot_set——0x8027~0x802A 属 prot_set 告警段永不覆盖,TC-IEC104-029 双向往返钉死;空隙地址自然 COT14/PN - 通道系数覆盖 = adc_cal_set 代理(裁②a):合法带/越带 [ERR] 留痕全复用, run_par 不存第二份系数(防双真源);单侧写 RMW 用另一侧当前生效值; 回显 = 生效值视图(文件坏值被哨兵回退 ROM 时主站看到的就是下游吃到的); adc_cal 配套:+adc_cal_b_codes() 读取口(回显/RMW 用)+ set() 授权写者 注记扩至 iec104Task 直通路径(单字原子契约同「数据可信」§4.4) - 持久化(裁②b):新事件位 SYS_EVT_RUN_PAR_SAVE(1<<8);iec104Task 主循环 peek 投递 → defaultTask run_par_store_save() 一条事件一趟 cfg_file_save 整档外科(覆盖 [run_par] 9 键 + 联动 [adc_cal] 两段);失败脏保留 = 天然 重试(B7 prot_set 同款)。C_SE 现行无"暂停/测试态"门控——文档现行如此 不造新语义,送检若要求接线点已写进 §3.4 注(裁④) 测试:新建 test/host/run_par(TC-RUNPAR-001~008,67 断言,真实 cfg 引擎 + 真实 adc_cal + 内存虚拟盘同 adc_cal 套件先例;[run_par] 注册契约/落盘往返/ 外改文件即副本生效/两段式不提交不置脏/合法带拒+RMW+生效值回显/init 幂等 重注册留痕);iec104 套扩真链 TU(cfg_file+adc_cal+run_par 非桩,141 断言: +TC-IEC104-029 路由 + 壳清确认计数 3 断言);meas 套静态更名 s_snap*→ s_ms_snap*(与 cfg_file.c s_snap 同 TU 相撞,D1 同款改名法,226 断言不变); iec104_serv 套补 run_par_dirty_peek 假件。id_registry 建族 TC-HOST-RUNPAR (游标 008)+ TC-HOST-IEC104 游标 028→029;新钩子 run-par-unit-test + iec104 钩子触发面随真链扩;uvprojx +run_par.c(合法入库)+ SIM_EXEMPT 登记 (模拟器不编 104 协议,已核实 CMake 面)。 文档:IEC104 §3.4 运行参数段表(含送检替换账/门控未来条件/代理声明)、§7、 §8 第 4 条、变更记录;网络配置说明新增 §3.5 [run_par] 键表;复现规划 §5.4 补运行参数段落实进度。**遗留(交 lead)**:数据可信 §4.4 "引擎 RAM 副本" 一节当时的措辞对象含 pts 侧副本,s_yc_db 删除后该句过时(裁③b 点名,§4.4 在写域外未动)。 gate:@build 0/0(Code=219620 RO=22036 RW=1280 ZI=132864);vs 0cbae7d: Flash +1912B、RAM(RW+ZI) +8B(37B 新静态被链接器并洞吸收);iec104Task 栈 1456B/margin 43%、defaultTask 3032B 不变;id-check/doc-links/cppcheck/ coding-standard 实跑过;--all-files 全量 45 钩子实跑(43 绿 + 仅 mem-budget / mem-numbers 两红 = 台账受管区 vs .map 漂移,回填属 lead 单写者区,批 1/道D-1 /D2 同口径):gate: only mem-budget/mem-numbers pending lead ledger backfill BOM/CR/U+FFFD/字面量 ASCII 逐文件自查通过。 |
||
|
|
acc547efaf |
feat(104遥测): 卡9改读L2快照+死区运行化2点确认 + 卡11绑频0x401D(道D M5/M6)
卡 9(App/protocol/iec104/iec104_pts.*,「数据可信」,docs/子系统设计/ IEC104上行设计说明.md §3.1/§4 同步): - 数据源换轨:板端默认 YC 源从直读 phasor 改为**整体透传 L2 遥测快照** (meas_get 双区无锁;"新不新、能不能信"只在发布侧判一次,M5-② 落地); iec104_pts_src_t 表尾追加 yc_read_ex(带品质)——旧注入源走 legacy 退路, 品质由返回值推导,行为与卡 9 前**完全一致**(存量假源用例零改动) - 品质映射 s_q_map:MEAS_QDS_* 低字节=线上 QDS 同值直传;CLIPPED→IV (「削顶通道 104 恒 IV」口径不变、从点表绑死 -1 改品质驱动——UB/UC/IB/ IC/IN 五路现绑快照槽,V0.2/N-18 削顶消失后**零改动自动启用**);IV 优先 NT;快照从未发布(开机 <200ms)→ IV|NT;无效信息体清零(旧线上口径保持) - 死区运行化:运行时副本 s_yc_db(ROM 默认 = 点表列,卡 6 额定 0.5% 档不变) + iec104_pts_yc_set_deadband()/iec104_pts_yc_deadband()——卡 10 运行参数段 (8020H)的接线点已留;非法 idx/负值/NaN 拒绝、成功时清该点待确认计数 - COV 遥测腿升级(lead 裁②"卡 9 是消费者"):判定 = 相对**上次上送值**(非 上次读值,防慢漂移吃基准)连续 2 个新测量点越死区才确认上送;回摆入带即 撤销候选;品质翻转当拍直报(含 0x401D 的 IV 进出)。测量点推进:板端按 快照 seq 去重(100ms poll vs 200ms 快照——不去重则同一帧把单点噪声计满 2 点,抗噪语义失效);注入源=每次调用一测点(单测步进自持) 卡 11:YC 表加 src 类型(PTS_SRC_MEAS/FREQ);0x401D 绑快照 freq_hz(与 freq_get 同源);snap.freq_valid==0 → IV 清零(卡 11 DoD 原句) 测试与文档:test/host/iec104 97→127 断言——TC-008 语义更新为 2 点确认; 新 TC-IEC104-025~028(024 号被存量 B7 用例裸标签占用,让号并改用全家长 形态)板端默认源走**真实 L2 链**(ring→phasor→freq→meas,非桩):未发布 NT/值透传/CLIPPED→IV 清零/绑频收敛 ±0.02Hz/未新鲜 IV/死区运行档压旧档/ 回摆撤销/seq 去重同帧不计数/换帧只变品质按集合直报;id_registry 族游标 023→028;IEC104 上行设计说明 §3.1 表+注/§4/§7/§8 第 4 条/变更记录同步。 无新 .c(uvprojx 零改动);PC 主站读回一致与频率 ±0.01Hz 属网络对端验证 ——步骤清单已发 lead 排窗,本轮零台架动作。 gate:@build 0 错 0 警(Code=218128 RO=21624 RW=1272 ZI=132864);增量 vs adeef7d:Flash +348B、RAM(RW+ZI) +48B(低于 96B 预估,链接器并洞), IRAM1 58.5% 不变;iec104Task 栈 worst=1456B margin=1104B(43%) PASS 无抬栈 (stack_report);--all-files 全量实跑:其余钩子全绿(含修掉一处 cppcheck variableScope 后),仅 mem-budget + mem-numbers 两红 = 台账受管区 vs .map 漂移(回填属 lead 单写者区,批 1/道D-1 同口径): gate: only mem-budget/mem-numbers pending lead ledger backfill BOM/CR/U+FFFD/字面量 ASCII 逐文件自查通过(未触碰带 BOM 文件)。 |
||
|
|
969fc5c132 |
merge: task/n17-probe 合入 v2-on-ui
任务 n17(1 个提交)经 task-worktree 回收: - fix(网络): 主动拆会话登记即返——drop 路径不再占用 netTask(登记簿 N-17 收口) |
||
|
|
62987b4596 |
Merge branch 'v2-on-ui' into task/meas-snap
# Conflicts: # scripts/id_registry.json |
||
|
|
a3c6e89378 |
fix(网络): 主动拆会话登记即返——drop 路径不再占用 netTask(登记簿 N-17 收口)
道F 批 2 / task-17。定位 + 单点收口,不开 net 层跨上下文大口子。
【定位(链路,全部代码可复核)】
探针挂起 30s → time_sync.c:149 预算耗尽 → :187 net_drop_conn()。NET_MSG_
DROP_CONN 处理器(net_drop_conn_locked)内同步跑 net_sock_reset_sync
(QUARANTINE)(2ms 节奏、400ms 底/600ms 顶,自家注释原记「等待期 netTask
有界占用 ~400-600ms」):netTask 的 1ms 主循环冻结在同一迭代 → NET 位
停摆;串行总线整窗停摆 → UI 推流/FTP/104 在途消息回执顺延;对时调用方
睡在 net_wait_result 等回执期间无分片心跳 → 五位同窗缺席 → 连续 8 个
100ms 抽样停喂 → 声明 [WD] task stall(V5 时代 req=0x37、快照只剩 bit0,
即日志 mask=0x00000001)。被动断连/EOF 走 net_listener_tick 异步沉降机
(D10 条令)故纯 FTP 负载 0 stall——只有主动 drop 留在同步原语里。
【修复】监听型 fd 的芯片拆除改为 net_listener_settle(QUARANTINE) +
net_listener_request(REQ_DROP) 登记即返,拆链/排渣/等 CLOSED/重建全部
交 net_listener_tick 30ms 节奏——与被动释放同一台机器(E16 台架实证该
自建序列 RST 10/10、FIN 5/5)。非监听 client fd 无监听可保,同步形态
原样保留(全仓零生产调用者)。返回值语义显式改为「拆除与重建已登记」
(net_socket.h 注释按 lead 要求写明,防未来调用方按旧语义写)。
APP_ASSERT(S12 试点)分派门与断言位置未动,登记时序下仍成立。
【评估否决留档(lead 要求论证入文档)】「缩短重建重试 5×2s」不采:
该退避在 time_sync_open_listener() bind/listen 失败路径、已被
time_sync_delay_fed() 分片喂保护、不在缺口链上;缩短反撞 TRAP-NET-09
沉降窗。全文见 docs/网络/网络自愈架构设计.md §4.6(已改写)。
【竞态与信源核对】① 主路径置 CLOSED 后迟到的 DISCONNECT/TIMEOUT 被
net_events 状态门拦截(只认活会话态),不会把刚登记的 QUARANTINE 降级;
② 零新增读清点——全局寄存器唯一读者仍 net_poll,隔离窗两处本 Socket
读清是 net_listener_tick 原位,§4.10 三条准入判据不触发;③ E13 物理
边界(对端不配合 FIN_WAIT_2 长尾)逐字不变,只移动等待发生的位置。
【测试】net_socket 主机套件 457/457:TC-NETSOCK-240f/321b/321b2/460e
重锚到登记式(settle+REQ_DROP、rst 机零启动、tick 预算 ≤20、无 [ERR]),
新增 321g/h/i + 460f 钉住 client fd 旧同步形态。全量 --all-files 40 绿。
【体积增量(vs scripts/ram_baseline.tsv 2026-10-25 行)】
ER_IROM1 237328→237344(+16 B);RW_IRAM1 75792(+0);ZI 0。
@build 0 错误 0 警告(Code=215948 RO=21396 RW=1232 ZI=131984)。
gate: only mem-budget/mem-numbers pending lead ledger backfill
test-coverage 本条**绿**(已覆盖行净增,未动用裁决③的覆盖率例外——
旧同步路径行经 client fd 新用例继续被覆盖,净差非负)。其余含
id-check/doc-links/全部主机单测绿。仅 mem-numbers/mem-budget 两红 =
台账 +16B 漂移待回填(lead 单写者禁区)。
【越界申报】① test/host/net_socket/{ns_s3_msg,ns_s4_state,ns_s5_io}.c
(批准③同类:只动本任务相关用例,未碰他人行);② docs/网络/
网络自愈架构设计.md §4.6 改写(lead 本任务指令明示)。登记簿 N-17
销项与 README 波次行归 lead;docs/内存管理 数字未碰(禁区)。
台架:V5 复跑判据(e02_probe + FTP ≥30min 零 stall / 零复位)属网络
对端类——待 lead 排窗,步骤清单随 done 消息发出。
|
||
|
|
48bc50e794 |
feat(遥测快照): 卡8 meas 双区快照模块 + adc_task 200ms 唯一发布点(道D M5)
卡 8(App/algo/meas.*,新增;布局权威 docs/任务规划/数据可信.md §4.5): - meas_snap_t = §4.5 布局(sizeof 72 B;字段偏移由 TC-MEAS-002 钉死——卡 9/ UI 按整体拷贝消费,破布局=破协议;谐波 k-bin 扩展(docs/算法/继电保护功能 复现规划.md L2-8)只许尾部追加,留口注释已写进 meas.h) - 并发 = phasor 双区 + 单字节索引翻转(L2-7 同型,无锁);seq 只增供判"换帧"; meas_get 失败路径清零填充(-2 未就绪时调用方可安全读) - 值口径 = A-lite 裁决(lead 2026-10-25 快裁,推翻票面全链):基波有效值瞬时 透传,复用 phasor_calc 纯核 → 与 phasor 使用区同拍同值(TC-MEAS-005 逐位 相等钉死);不做 4 点平均/方和根(§4.5"200 ms 是上送节拍不是平均窗") - 品质注入:CLIPPED 位图唯一源 = adc_cal_flags()(「数据可信」§4.2 三态表, 编排方注入、本层不链 adc_cal);取窗不足路 = IV|NT 且整帧 valid=0 但照常 发布(品质节拍性刷新);TEMP = 最新一点透传 + NT(「数据可信」决策 5); MEAS_QDS_* 低字节 = 104 QDS 线上值(本层不 include 协议层头——分层方向, 卡 9 直接截低字节映射);OV 留位不填(判据待运行参数化,卡 10 域) - adc_task.c 编排:新帧拍 freq_run() 后按 **tick 经过**分频(非拍计数,idle/ skip 拍会拉长名义节拍)调 meas_tick()——全仓调用点数 = 1(「数据可信」§8 风险表"快照双写"行评审判据);meas_init 挂 adc_task_init(不动 app_main.c); 心跳新增 meas: 行(seq/v/ua·un·ia_mv/f/fv)作 M5 台架观测面 - 死区 2 点确认状态机本卡不建(卡 9 迁移 104 语义时随建,lead 裁③);104 层 现有 deadband 常量未动;频率点绑定归卡 11 - 实测采样类判据(读数 vs 注入源)= 待台架实测,本卡零台架动作 测试与注册:新套件 test/host/meas(226/226,链真源 meas+phasor+sample_ring 免桩;覆盖 seq/双区无撕裂/布局/品质汇总/回绕/守卫);id_registry 建族 TC-HOST-MEAS(游标 011);meas-unit-test 钩子 + SIM_EXEMPT 一条 + uvprojx 仅增 meas.c 单条挂载(diff 已核零 UV4 抖动);App/algo/README.md §1/§2/ §3.9/§4 同步(设计说明大节与 AGENTS 口径留 lead 收口,同批 1 先例) gate:@build 0 错 0 警(Code=216352 RO=21476 RW=1232 ZI=132128);RAM 增量 RW+ZI = +152 B(快照双区恰 +144 B = 卡面 DoD;余 s_meas_ms 等编排状态), IRAM1 57.8%→约 57.9%;Flash(Code+RO+RW)+696 B;adcTask 静态最坏链 1408 B / margin 1152 B(45%)PASS(stack_report 实测,无抬栈);BOM/CR/U+FFFD/ 字面量 ASCII 逐文件自查通过(未触碰带 BOM 文件)。pre-commit run --all-files 实跑:其余钩子全绿(含 doc-links/id-check/ 覆盖率总闸/双端注册/ui-golden/全部主机单测套),仅 mem-budget + mem-numbers 两条红 = 台账受管区 vs .map 漂移(Flash/RAM 台账回填属 lead 单写者区,批 1 同口径): gate: only mem-budget/mem-numbers pending lead ledger backfill |
||
|
|
98664a11ed |
merge: task/ui-data-feed 合入 v2-on-ui
任务 ui-data(2 个提交)经 task-worktree 回收: - feat(ui-data): ui_data 三通道快照 + ui_data_feed 装配 + SOE 显示名映射 - feat(ui-font): 字库补 SOE 显示名用字 采/样/恢/效(179→183 字 / 274→278 字形) |
||
|
|
201d713226 |
feat(ui-data): ui_data 三通道快照 + ui_data_feed 装配 + SOE 显示名映射
按 docs/UI设计/UI_数据供给设计说明.md 的 D 方案把 App→UI 数据通道落地:
App 组帧、BSP 存帧、页面只读;UI 侧零 App include,薄包装只在两端适配层。
本笔是纯增层、不接任何页面 → 零像素变化(菜单 8 状态 + 内容页 11 页黄金
参考逐字节不变,simulator/tests/ref 无 diff,未刷基线)。
新增
- Drivers/BSP/UI/ui_data.{c,h}:实时量 rt / 参数 par / 装置信息 info 三通道存储
+ 发布序号盖章 + 只读访问。零 App include、零 LVGL include(分层叶子);
读写同在 uiTask 上下文串行 → 无锁、无双缓冲、无 seqlock(契约 §5.1)。
- App/app/ui_data_feed.{c,h}:快照唯一填充者。rt/info 每 200 ms 一帧,par 只在
prot_set_checksum() 变化时重发;首轮立即发布,免启动初期闪一下 "--"。
- Drivers/BSP/UI/ui_w_soe.{c,h}:SOE 二进制记录的显示名映射与注入式 reader
契约。未标定闭锁=7 / 标定复归=8 已进表——编号按 App/log/soe_rec.h 与
App/algo/prot_elm.h 现场数过(类型 1..8 + 哨兵 9、元件 0..8、ELM_NONE=0xFF、
FLG_IV=0x80),不采信文档与消息转述。reader 备好但两端未绑定:落盘侧还
没有只读 API(Lead 已裁该 API 归下一工作项),未注入按"无记录"空态渲染。
量纲诚实性(契约 §4.1 同步改成真值口径,不再抄旧码值表述)
- eng 不写"0 = 原始码值":标定层 ROM 系数是引脚侧 LSB,采样环折算出来的就是
ADC 引脚电压(承诺边界 docs/任务规划/数据可信.md §2.6);电气 8 路
adc_cal_flags() 的 VALID 全置位才升 eng=1 二次值——整帧共用一个 eng,只要
还有一路是引脚电压就不能贴"二次值"标签,宁可整体保守。
- TEMP 不参与线性标定 → 恒带新增品质位 UI_DATA_Q_RAW=0x20,页面不挂单位。
- UB/UC/IB/IC/IN 无基波相量实例(V0.1 削顶)→ Q_IV|Q_OV;未满一周波 → Q_NT。
- 谐波另开 ph[] 相量实例槽带:yc 的语义通道下标容不下同通道的二次/五次谐波。
接线与双端注册
- App/task/ui_task.c:ui_menu_init 之前 ui_data_init + 首帧发布;主循环每轮
ui_data_feed_tick() 排在 ui_port_step 之前(本轮渲染用本轮刚发布的帧)。
- simulator/main.c:发布固定合成帧(无头与窗口两个初始化点,先于建页);
定值不手抄 40 个数,改为链入 App/algo/prot_set.c 取出厂默认(抄表等于造
第二真相);build_date 用固定串而非 __DATE__,否则跨天重建会把装置信息页
黄金参考刷掉,而黄金参考是判据本身。
- 注册:uvprojx 加 3 条(App 组 ui_data_feed.c + UI 组 ui_data.c/ui_w_soe.c)与
simulator/CMakeLists.txt;ui_data_feed.c 不进模拟器 → check_registration.py 的
SIM_EXEMPT 加一行(App/app/app_main.c 先例,已报备)。
主机单测与钩子
- test/host/ui_data:82 断言全绿。钉三类事:快照语义(首帧前读 -1、序号由本层
盖章、三通道互不串台、NULL 防御、init 幂等复位);跨层不透明下标现场一致
(yc 序 = adc_semantic_t、q10 序 = prot_set_id_t,同一 TU 里 include 两侧头);
SOE 编号与名字表现场一致(八类事件都有名、采样/标定四个词互不相同、
名长不超列宽、越界回占位)。
- .pre-commit-config.yaml 加 ui-data-unit-test 钩子(第 43 个,Lead 已批自加)。
- scripts/id_registry.json 建族 TC-HOST-UIDATA(属主登记处 = 单测目录,同
TC-HOST-ADCCAL 先例;不建族则新号被编号门禁判"未登记前缀")。
体积(相对 HEAD 台账 Code 215744 / RO 21396 / RW 1224 / ZI 131984)
- Code +1272 B、RO +108 B(字库 4 字,见上一笔)、RW +24 B、ZI +696 B
→ ER_IROM1 238520 B(22.7%)、RW_IRAM1 76504 B(58.4%,台账 57.8%)。
- .map 逐项:ui_data.o 488 B(Code 184/RW 12/ZI 476)、ui_data_feed.o 221 B
(1034/12/209);LVGL 池 0 增量;ui_w_soe 未接线不进镜像(.map 无其符号)。
- 台架未跑(本笔零像素、零接线):首帧时刻、200 ms 刷新、eng 升档与遥信
位图真值全部留"待台架实测",接线完成后请 Lead 排窗。
遗留与风险(随回报进台账)
- 写路径(契约 §6 的 param_request/state)不落:无消费者就是永不执行的死码,
随整定 4 页一起落;届时须先定"UI 整定 vs iec104Task 写 prot_set"的并发口径
(prot_set_set_sealed 的影子区非重入)。
- 公共地址 CA 未下发:固件里 CA 逐帧从 ASDU 头解析,无集中常量可取。
- 遥信位图与 App/protocol/iec104/iec104_pts.c 板端源是两处镜像(该文件位号
写在函数体内未导出,UI 不得 include 协议头),开入采集落地时应并成单源。
- 版本类字段是本文件内的宏(仓库无产品级版本登记表,值沿用页面既有显示
值);软件校验位在拿到构建期 CRC 步骤前一律显示 "--",不抄参考遗留值。
gate: 全量钩子(--all-files)40 项通过;cppcheck/test-cppcheck/coding-standard/
layer-deps(基线仍 3 条)/registration/bsp-err(存量 38 条不变)/font-charset/
id-check(增量无新账)/doc-links/ui-golden/主机单测与覆盖率全绿;唯一红项是
mem-numbers 与 mem-budget——两者只因 Flash/RAM 台账未回填(禁区,归 Lead)。
gate: only mem-budget/mem-numbers pending lead ledger backfill
自查:BOM(Drivers/BSP/UI/* 与 App/task/ui_task.c 保持 EF BB BF,新建 UI 两件
同规范;App/app 与 test/host 无 BOM 与本目录一致);CR = 0 全 LF;U+FFFD = 0;
字符串字面量纯 ASCII(中文只进注释)。
|
||
|
|
484d068250 |
feat(存储): 写回缓存空闲 flush 兜底——卷空闲周期 CTRL_SYNC(登记簿 N-22 收口)
道F 批 2 / task-16。FTL 单页写回缓存(nand_ftl.c s_cache_dirty)与 dhara journal 只在换页/整页写/f_close 时刷出,漏网脏页的掉电驻留窗无上限。本 提交以最小面收口:不碰 GD5F/dhara 驱动,全部走既有 FatFs CTRL_SYNC 路径。 实现 App/fs/vol_idle_sync.[ch](新增,仅 MCU 端,uvprojx App 组注册): - 四级门:STORAGE_READY 就绪门 → 5 s 节流(无符号差回绕安全判据)→ vol_lock_wait(0) try(锁被持有=文件序列在做,跳过,不改 STOR 持有期 语义)→ disk_ioctl(0, CTRL_SYNC); - clean 态脏标志+journal 双短路、零 NAND 触点;脏态最坏 = 一次 f_close 的同步段同型成本,不引入新磨损来源; - 失败按边沿 latch 一条 DBG_ERROR、成功重新武装;失败路径也成对放锁; - TEST_SUITE_STORAGE 构建整体 no-op(卷由 testTask 独占)。 接线:defaultTask 主循环 syslog_drain 之后(default_task.c v1.3)。 文档:docs/架构设计/STM32F4-Base存储架构说明.md §5.5 补空闲兜底与边界; 本板无掉电检测硬件、不做掉电前强制 flush、勿当掉电保护——口径同步落 注释与文档(sys_log_mcu.c 两处旧「暂不做」注释随实现改口)。 测试:新主机单测 test/host/vol_idle_sync/(TC-VOLSYNC-001..012,19 断言 全过);scripts/id_registry.json 建 TC-HOST-VOLSYNC 族(仿 ADCCAL 先例); .pre-commit-config.yaml 加 vol-idle-sync-unit-test hook(只加自己条目)。 越界申报(①②③ 均 lead 批准,④ 为门禁连带必要): ① App/task/default_task.c 单点接线(include + 1 调用 + 头修改记录); ② docs/架构设计/STM32F4-Base存储架构说明.md §5.5; ③ .pre-commit-config.yaml 单 hook + scripts/id_registry.json 单族; ④ scripts/check_registration.py SIM_EXEMPT 加一行(vol_idle_sync.c 模拟器 侧豁免,registration-check GAP 所需;与批准③同类别但未列名,特此申报)。 体积增量(vs scripts/ram_baseline.tsv 2026-10-25 行): Flash(Code+RO) 237140→237328(+188 B)、RW 1224→1232(+8 B)、ZI 0; 增量 = 3 个文件级 static + 一处 DBG_ERROR 调用点;栈/堆无变化。 gate: only mem-budget/mem-numbers pending lead ledger backfill 全量 pre-commit --all-files:40 项 Passed,仅 mem-numbers(D-7 体积档)与 mem-budget 两条红 = 台账数字待回填(增量如上,属 lead 单写者禁区); 其余含 doc-links/id-check/registration/test-coverage/全部主机单测皆绿。 @build 0 错误 0 警告(Code=215932 RO=21396 RW=1232 ZI=131984)。 台架:空闲 sync 实机节奏(clean 零触点、脏态时长、无心跳扰动)属实际 测量采样类——本批跳过,留「待台架实测」。 |
||
|
|
db9f256fd0 |
docs(收口): 批 1 台架记录与门禁/产物分家口径落档(道C 文案兑现)
- test/board/ch395f_test.h:f3 轮台架记录追加——VERDICT PASS, task stall 468→14(net 类 431→0,掩码复活实锤),余 13 条为 netTask 自挂起前喂一次 vs 精确匹配判据的语义打架 + 1 条 uiTask 瞬态 + 1 条设计内 P2 留痕;lead 裁决不放宽超集判定 - 主机单测覆盖率口径.md:中间产物路径 L80 与坑 12 重写为 %TEMP%/dtu_host/<工作树哈希>/ 分家 + runs 独占(adabb6a 落地, 旧固定共享名作废;判据正文指向 harness 顶部) - 并行任务工作树方案.md §5 表:单测产物一行——不需要锁但必须 按树分家(对照 build/bench 真独占) - 门禁说明/cubemx-survival.md §6:新增第 7 条「基线漏项=静默不检」 (net-msgq-adopt 实证,--write 后抽查新增条目) - 门禁说明/id-check.md §5:拦下过真事追加——P1-10 注释裸编号被 校验 6 拦(紧邻写法在 C 注释同样生效) |
||
|
|
73f9e10492 |
merge: task/P1-10-test-fw 合入 v2-on-ui
任务 P1-10(8 个提交)经 task-worktree 回收:
- chore(size): sync 追平后重盖体积同码凭证(v2 索引指纹,1396 文件)
- docs(P1-10): sync 追平后补记四档复测数字(产品基线已前进,旧注保留)
- merge: v2-on-ui 追平至 task/P1-10-test-fw(含 A-3 卡5~7 与 B-3 记录 reader)
- test(P1-10): 套件回归 forbidden 换成显式四 Fault 标签 + 台架记录 21/21
- fix(WD): HW 测试模式掩码死分支复活——include 缺失自
|
||
|
|
8c28f3bfdd |
docs(收口同步): 批 1 落地后 AGENTS/104/算法层口径更新 + SOE 7/8 消费面补齐
- AGENTS.md:钩子 40→42、主机单测钩子 16→18(adc-cal/prot-dim)、 覆盖率总闸 28→35 套、layer-deps 基线 6→3(记录 reader 注入兑现) - IEC104上行设计说明.md:遥测读数改工程量口径 + 死区额定 0.5% 重定 已落地(卡 6);§8 第 4 条改写、变更记录追加行 - 采集与算法层设计说明.md:状态行/红线③/幅值门三处由「标定未实现」 更新为「折算已落地、精度复核待卡 12 注入」 - App/log/soe_rec.h 类型注释表补 7/8 两行(lane-a 口误 6/7 已勘误, 真值按枚举链 SAMPLE_RESUME=6 连续计数) - test/host/soe/decode_soe.py:TYPE_NAMES + docstring 补 7/8—— 否则台架 FTP 下载校验会把标定闭锁记录判 bad type 误红(隐藏消费边); soe 套件 32/32 复跑绿 |
||
|
|
d07a9a4d67 |
docs(P1-10): sync 追平后补记四档复测数字(产品基线已前进,旧注保留)
sync 到 |
||
|
|
a28123115d |
merge: v2-on-ui 追平至 task/P1-10-test-fw(含 A-3 卡5~7 与 B-3 记录 reader)
按 lead 信号 sync 追平:主干 59da40b(cal-lockout-dim)+ 891ca81(UI-rec-reader)+ 383b450(台账与凭证回填)合入本任务分支,为下一轮台架做准备(台架镜像必须建立在 追平后的代码上,否则烧进去的 hex 与主干不同码,体积门禁的凭证也对不上)。 唯一冲突:scripts/size_attestation.json —— **取主干侧**(383b450 刚按合并后的固件重盖 过,数字更新;本分支侧是 |
||
|
|
5f1057ac74 |
test(P1-10): 套件回归 forbidden 换成显式四 Fault 标签 + 台架记录 21/21
台架第一轮(boot log 20261025_050539)判 VERDICT FAIL,命中 469 条 [ERR],两类:
1) [ERR][CH395] ch395f P2 boundary fault @get_state sn —— **设计内**:Phase 15 的
sn 越界负向用例故意命中驱动守卫(Drivers/BSP/CH395F/ch395f.c 的
ch395f_p2_fault_note():首次 DBG_ERROR、之后只计数),用例本身 PASS;
2) [ERR][WD] task stall ×468 —— **设计外**,已在
|
||
|
|
ffd462ef3c |
feat(保护标定): 卡5 未标定闭锁 + 卡6 下游三常数重定 + 卡7 量纲回归单测
卡 5(protect_task.c 第⑤闭锁源,「数据可信」§4.3 决策 1=闭锁): - UA/UN/IA 的 adc_cal VALID 未全置位 → prot_elm_init + 本拍不 eval;每拍现查 flags、无自有状态(卡 12 标定写入后自动解锁);判据链优先级 = 采样可信在前、 标定可用在后(数据都是旧的谈不上标定) - 边沿日志用 DBG_INFO 而非 [ERR]:未标定是出厂常态、非故障,且 @test 禁用 [ERR](「默认构建保护不动作 = 期望」的台架判据同步项已在 MR 报 lead); SOE 分型 SOE_T_CAL_BLOCK/RESUME(soe_rec.h 枚举尾追加,值 6/7——reader 侧 显示标签映射归道B reader,MR 已报) - 台架旁路 = 编译期宏 DTU_BENCH(§4.3:不进 cfg 不进 104;本仓所有提交目标 都不定义它 = 产品恒强制闭锁) 卡 6(下游三常数按工程量重定,依据同源 docs/任务规划/数据可信.md §2.3): - FREQ_AMP_MIN(freq.h):语义从拟定码值域重定为二次值 V——50 V = 0.5×Un (标称 100 V),断保险/PT 空载/浮空必低于之;数值沿用 50.0f 属巧合并在 注释明写;eng=0 过渡期本门恒失效 → OF/UF 按必不启动填充,与卡 5 同向安全 - k_yc[].deadband(iec104_pts.c):9 点按「额定 0.5 %」规则重定:电压类 0.5 %×100 V=0.5、电流类 0.5 %×1 A=0.005、频率维持 0.5 Hz 绝对值(非额定 比,卡 10 运行参数化);标称基准与 prot_set 头部同源,防两处真相 - g_prot_set_meta[](prot_set.c):数值/范围复核结论=不动(0~4×标称自洽), 文件头补量纲口径块:A/V = 二次值、标称 100 V/1 A、OV120=1.2Un/UV20=.2Un/ 3U0 15=.15Un、OC1/2/3=10/5/2×Ir、OL=1.0×Ir;PS_ID_COUNT/blob VER 未动 - iec104 套件 TC-008 死区用例同步重定标(100.4 带内 / 101.25 越带),97/97 卡 7(test/host/prot_dim 新套件,真实链 adc_cal→ring→phasor→prot_elm): - 用例从 ADC 码值出发、显式写出 code↔二次值互逆换算(dim_code vs apply), 折算点被旁路或量纲再错位断言立刻翻转(M4 判据⑥「不该动作时不动作」) - 合成 ROM 覆写(#undef K_Q16 宏)模拟卡 12 标定后板级口径,走 adc_cal_set 正规路径置 VALID;b=-30 码全链对消进 rms 断言 - 38/38:基线静默(含 OL 低定值陷阱)、反错配对照(raw 码值灌环复现历史事故 必假动作 vs 经折算必静默)、OC1/2/3+OL+OV+UV+3U0 七类逐一:越限定值→ 受控启动拍→dly-2 不动作/+5 动作→返回系数带内保持→跌破释放、双件聚合位图 独立性(撤 IA 只回 OC1) 测试与注册:prot-dim-unit-test 钩子 + TC-HOST-PROTDIM 族(游标 010,B 层口径 同 ADCHEALTH/ADCCAL 先例);无新 MCU 源文件(uvprojx/SIM_EXEMPT 零改动) gate:@build 0 错 0 警(Code=215640 RO=21388 RW=1220 ZI=131980 vs 基线 215440/19780/1220/131980 → Flash +1808 B、RAM 零增量);protectTask 静态最坏 链 872 B/margin 1176 B(57%)PASS,adcTask 不变;staged 门禁除 mem-numbers/ mem-budget(台账漂移,回填归 lead)外全绿: gate: only mem-budget/mem-numbers pending lead ledger backfill BOM/CR/U+FFFD/字面量 ASCII 已逐文件自查(本轮未触碰带 BOM 文件) |
||
|
|
adabb6af12 |
fix(test): 主机单测/覆盖率产物按工作树分家 + 每次跑独占目录(task-10)
现象(2026-10-25 三条道并行开发实测,看板 task-10):全量 ci_local 的 L0 里 test-cppcheck / test-coverage 偶发 "files were modified by this hook",单独重跑 即绿、工作树零改动。根因在 unit_test_harness:obj/exe 直接落在**全机共用**的 %TEMP%,名字由套件名派生(%TEMP%\net_socket_tests.exe、%TEMP%\net_socket_obj), 多棵工作树并行跑同名套件必然互踩。 真正要命的不是编不过,而是**结论张冠李戴**:A 树编译完,B 树把同名 exe 又盖一 遍,A 树随后 subprocess 执行的是 B 树编出来的二进制——两棵树的 summary_marker 一模一样,harness 分辨不出来,于是拿别人的运行结果给自己判 PASS。这种失败不会 变红,只会静默给出错误结论,比红难查一个量级。 修法(不是加锁): - 产物根按**工作树**分家:%TEMP%\dtu_host\<仓库根路径 sha1 前 10 位>\。树身份取 harness 文件自身位置(test/host/common 往上三级),不依赖 cwd/环境变量;工作树 之间只联接 .venv 与模拟器 SDK,test/host 每棵树各有一份,所以这个身份可靠。 - **每次运行再独占一个子目录** runs\<pid>-<纳秒>\,obj 与 exe 都放进去,跑完 finally 删(含 Ctrl-C 路径)。这一步顺带把"同树并发同名套件"也消灭了:两个 进程既拿不到同一个 exe,也拿不到同一个 .obj(实测共享根时并发会因 obj 撞名 直接编不过,返回 rc=2)。没有牺牲缓存:每个测试单元就一个 .c,cl 每次整体重编, "共享 obj 省编译"本来就是错觉。**不加锁**:这里没有需要互斥的独占资源,只是 名字撞了;加锁等于把 L0.5 变成 build/bench 那样的全局串行。 - 独占目录里留 <exe>.owner.json(suite / repo_root / pid / started):需要证明"这 份产物属于哪棵树哪次跑"时有的可查,不必靠时间戳猜。 - 编译返回 0 但产物不存在 → 明确报环境错误,绝不跑来路不明的二进制。 - 两个开关:DTU_HOST_BUILD 改产物根(CI/容器固定路径),DTU_HOST_BUILD_KEEP=1 保留本次目录(要单步调试 exe 时用)。判据单一事实源 = host_build_root()。 - scripts/check_test_coverage.py 同源改造:work_root 由固定共享名 dtu_test_cov 改为 复用 harness 的 host_build_root()/coverage,并同步 --work-dir 帮助文案与 docstring (docs 里"并行期每人只跑 --module 自己模块"那条规避就此作废,它是为绕开旧共享名 而写的)。顺带删掉因此不再使用的 import tempfile。 附带修一处同族不诚实(做本任务时从自己的输出里发现):ci_local 的收尾那行以前 无条件打印"L0 + L0b + L0c + L0.5 全部通过",--l05-only 时等于把没跑过的段宣布 为通过——正是 A-5 那个"SKIP 冒充 PASS"的镜像版。改为只列本次真正跑过的段。 自证(都是实跑,不是推演): - 两棵树身份并发跑同一套件:把修好的 harness 复制成 A/B 两个树身份(repo_root 不 同 → 两个不同产物根),套件 BUILD 从真仓库加载,各跑 4 轮并发 → 8/8 rc=0, 两侧 roots 分别是 …\55deb98e3b 与 …\902100bc41,互不可见。 - 敌意场景:把两边 DTU_HOST_BUILD 强行指到同一目录(旧写法必撞 exe/obj)→ 8/8 rc=0,共享根下只剩一个空的 runs/。同树并发同理被这一条覆盖。 - 单套:test/host/sha256 rc=0(13/13),产物确实落在 …\4b9166f602\runs\<pid>-…; 覆盖率 --module sha256 rc=0(line=111/114 func=7/7),落在 …\coverage\sha256。 - 全量:ci_local --l05-only → 33 runner(s),2276/2276 assertions passed,fail=0。 - 临时目录与 scratch 已清理(脚本在仓库外,不入库;ci-artifacts/ 之外无残留)。 文档:test/host/common/README.md 新增"产物目录归属"一节(落点结构、为什么按树、 为什么每次独占、两个开关、一行命令查当前树的产物根);harness 顶部注释是判据正文。 docs 侧两处按分工归 lead 在 done 时统一改,合并请求里已给可直接粘贴的替换文本: docs/测试说明/主机单测覆盖率口径.md 的产物目录条与"坑 12"、以及并行任务工作树 方案.md 的产物归属条。AGENTS.md 与 docs/** 本次一个字节没动。 RAM/Flash 增量:0 B(纯测试工具链,不进固件)。gate:见提交钩子输出,未用 --no-verify。 遗留:tools/font_gen/make_font.py 同样用固定共享名(%TEMP%\simsun_regular.ttf、 font_extra_<cp>.c)——同一类跨树竞态,但属道B 字体域,我没动,建议另开一张卡。 |
||
|
|
16917bf165 |
test(P1-10): CH395F 套件三档构建实测 + 修阶段开关行尾跨行注释的切换陷阱
P1-10 剩余①「CH395F 套件实际构建确认链接通过」今天才真正有数:产品基线 + 三档 测试配置(ARMCC,全部 0 错误 0 警告;.sct 保持 128 KB 未动,符合 P1-10 写的 "不建议扩到 192KB"): 配置(TEST_SUITE_CH395F + 阶段) Code ZI RW_IRAM1 距 92% 余量 产品基线(阶段全关) 214,104 131,852 75,632 57.7% 44,954 B 默认阶段 11/14(只切套件宏) 217,468 134,076 77,920 59.5% 42,666 B NET 层全开 6~11/13/14 218,992 141,688 85,552 65.3% 35,034 B HW 层全开 1~5/12/15(最坏态) 229,256 147,176 90,952 69.4% 29,634 B HW 层无需 PC 1/12/15(冒烟用) 215,244 134,896 78,672 60.0% 41,914 B P1-10 specifically 关心的 PHASE5 三块静态缓冲(3 x PHASE5_CHUNK_SIZE = 3 x 4093) 确实进了链接,不是"理论上会在":hw_full 的 ch395f_test_task.o 数据段 = 12,285 B (12,279 + 该 TU 其余 6 B)。于是"理论余量足够但未实测"改成了实测:最坏态仍余 29,634 B(RW_IRAM1 上限 131,072 B,92% 线 120,586 B)。RW_CCM 四档恒为 57,376 B / 87.9%——测试代码不进 CCM,但该区已经贴着红线,将来往 CCM 加东西要单独核算。 顺手修掉一个把实测挡了三年的坑(就是它让第一轮 hw 配置炸掉的): ENABLE_PHASE11/14 两行的说明是**挂在行尾的跨行块注释**。而"关掉一个阶段"的标准动 作是在行首加 //,// 只注释到行尾 → 块注释从第二行起变成裸代码,实测 188 条 error #7: unrecognized token,报点落在注释续行上,看着像头文件坏了、其实只是注释 被腰斩。run_all_suites.py 的 _rewrite_config 只改 TEST_SUITE_* 行(那些行没有行尾 跨行注释)所以一直没暴露;ch395f_test.h 恰是"人手工切阶段"的入口,必须自身安全。 修法:把两段说明挪到 #define 行的上一段,行尾只留同行闭合的短注释;并在开关区后面 写清"开关行注释规范"+ 上面这张实测表(同一事实只在这一处,销项时文档引它)。 验证(_wt/P1-10-test-fw,每步都实跑 @build): - V1 产品态(改注释后):0/0,Code/RO/RW/ZI = 214104/20388/1204/131852,与主干 2026-10-25 台账行逐项相同 → 本改动零体积增量。 - V2 只切套件宏(默认阶段 11/14):0/0,RW_IRAM1 77,920 B / 59.5%。 - V3 **朴素行注释切换**(正是炸掉第一轮的那个动作)改到 HW 1/12/15:0/0,且尺寸与 用 #undef/#define 覆盖法得到的 hw_nopc 逐字节相同(215244/23656/1200/134896) → 陷阱确认已消除,两条改法等价。 - V4 还原后产品重建:0/0,数字回到基线;test_config.h 与 ch395f_test.h 均按字节还原 (git status 只剩本文件这一处改动,测试宏没有留在树里,test-suite-switch 无需放行)。 - 产物身份戳实测:hw_nopc = "Oct 25 2026 04:32:16 suite=CH395F dstr=off"、产品态 = "Oct 25 2026 04:32:25 suite=NONE dstr=off" → dstr=off 三档一致,破坏性开关全程关。 RAM 增量:0 B。gate:改动只命中 no-mojibake / trailing-whitespace / end-of-file-fixer / check-added-large-files / id-check / mem-budget,全部 0;未用 --no-verify。 P1-10 剩余②(@test 烧录抓日志)需要 bench 锁,已把镜像与锚点清单交给 lead 执行; 真机跑 Phase 2~5 / 8 / 11 / 13 / 14 需 PC 端 tcp_server / peer 配合(Phase 11 还要 制造死对端,E11),属"实际测量采样"类,按用户指示本轮跳过,不在本提交声称做过。 |
||
|
|
3528644e9d |
feat(采集标定): 卡2 adc_cal 折算模块 + 卡4 系数落盘 + L5-2 码值贴轨检出
卡 2(App/algo/adc_cal.*,新增;adc_task.c:335 折算点收口): - 模型:工程量 =(code+b)×k(「数据可信」§4.1);k 以 int32 Q16(µV/码×65536) 落盘、b 以 int32 码值落盘;ROM 默认 = 卡 1 定死的引脚侧 LSB,Q16 下整除无 舍入(TPAFE 10,000,000=152.587890625 µV/码;STM32 52,800,000=805.6640625) - adc_task 每拍 frame[s] 改 adc_cal_apply()(现单位 = ADC 引脚电压 V,eng=0, 二次值语义等 VALID);TEMP 透传码值(决策 5);不缓存 k_f 副本——逐点由 RAM 现值派生(无回调设计下杜绝陈旧系数;18k flops/s 可忽略) - 三态 flags(§4.2):VALID = 文件位图 ∧ k 在合法带;CLIPPED 按来源运行期 派生(V0.2/N-18 后自动恒 0);消费者判可用性只查 adc_cal_flags() - 合法带哨兵:k∉ROM×[0.5,2.0] 或 |b|>8192 → 折算回退 ROM + 每通道每开机 一条 [ERR] + VALID 压制(位图说谎也兜住)——同时挡坏文件与坏标定 - 两点标定公式 adc_cal_two_point() 算术核齐备(int64、±舍入界、斜率/零点 守卫 -1/-2 分档);台架两点标定(卡 12)按用户指示未跑,留台架注入口径: 心跳新增 cal: 行(ua/un/ia_mv 定点 + vl/cl/rail 位图,未标定 vl 应恒 0x00、 cl 应恒 0xE6,注入饱和电平 rail 位应起) 卡 4([adc_cal] k_ua..k_in+valid / [adc_cal_ofs] b_ua..b_in,§4.4 布局): - 两段注册进 cfg 引擎(data_size 33/32,不挂回调——RAM 副本即生效值); adc_cal_init() 落 app_main_init 内核前(注册必须先于 defaultTask 的 cfg_file_load;跨任务读走 4 字节对齐字,µs 级混窗为「数据可信」§4.4 明载 设计);文件缺失/损坏 = 引擎回退工厂默认 = ROM 表本体(默认即理论系数) - adc_cal_set():整定写入口(属主上下文),越带拒绝 RAM 不动 - 单测走真实 cfg_file 引擎集成:文件值生效 / 越界 k 哨兵兜住且不报 VALID / 超长损坏文件回退默认且 flags 无 VALID(卡 4 DoD 原句)/ 段缺失默认 L5-2(adc_health v1.2,越界门限按 FS 百分比、码值域与标定正交): - adc_health_rail_watch():连续 20 拍(=一周波)贴同侧轨带(TPAFE±98%半量程、 STM32 顶 98%/底 2%,门限由 adc_cal_rail_ths 供)且此前见过中带释放沿才 锁存——空载恒 0 / 开机恒 0 合法工况不误报(短板评测 §6.2 判据①); adc_task 编排:边沿 DBG_ERROR + SYSLOG 每开机一次 + 心跳 rail/edge 位图 - 健康用例 60/60(+13):释放沿/清零/交替/双侧/init 复位/越界通道守卫 测试与注册:新套件 test/host/adc_cal(89/89,8 通道×≥3 码点期望值由 LSB 常数独立推导、Q16 无舍入、set 边界含端点、两点还原合成 k/b 往返); 编号形态返工一轮:TC-ADCCAL-00A~00D 改 014~017、注释 FS-1 字样改写、 id_registry 族 pattern 转义修正、族游标登至 017;coding-standard 返工: 公开实现函数补齐函数头注释块(CODE-RULE-09) uvprojx 仅增 adc_cal.c 一条挂载(diff 已核零抖动);SIM_EXEMPT/id_registry (TC-HOST-ADCCAL 族)/adc-cal-unit-test 钩子行按 new-source-file 与 B 层口径 补齐;覆盖率 34/34 套件 89.6%,adc_cal.c 99.2%(baseline --update 属共享 台账文件,留 lead done 后统一回填) gate:@build 0 错 0 警(Code=215440 RO=19780 RW=1220 ZI=131980); RAM 增量 +144 B(RW+16/ZI+128:贴轨 9×6B + 两段 RAM 副本,IRAM1 57.7%→ 约 57.8%);Flash +1336B/+920B RO。adcTask 栈 worst=1344B margin 1216B (47%) PASS(stack_report 实测)。staged 门禁除 mem-numbers/mem-budget 外 全绿(该两条 = 台账漂移,回填 --write 落 docs/内存管理/** 单写者区,按 Lead 既定例外归 lead done 后处理): gate: only mem-budget/mem-numbers pending lead ledger backfill BOM/CR/U+FFFD/字面量 ASCII 已逐文件自查(本次未触碰任何带 BOM 文件) |
||
|
|
231dc81239 |
merge: task/cal-scale-doc 合入 v2-on-ui
任务 cal-scale(1 个提交)经 task-worktree 回收: - feat(采集标定): 卡1 TPAFE 量程口径定死 + 卡3 cfg_file 补 CFG_VAL_INT |
||
|
|
411594bf67 |
feat(采集标定): 卡1 TPAFE 量程口径定死 + 卡3 cfg_file 补 CFG_VAL_INT
卡 1(文档口径;卡 0/12 实测类按用户指示跳过,只落口径与占位): - ADC通道映射说明.md 文首摘要行的 ±10 V 更正为 ±5 V 双极性:板上 RANGE 接 GND,±5 V 满量程 = 10 V 跨度,LSB ≈ 152.59 µV/码(@引脚) - §7 TPAFE 量程行重写并括注 ±10 V 是芯片可选档(RANGE=HIGH,跨度 20 V、 LSB 305.18 µV)、本板未用;§1 缺陷实质 2 补「满量程 = 10 V 跨度」 - 新增 §7.1 端到端量纲链路分段口径:②引脚侧 LSB 系数定死(TPAFE 152.59 / STM32 805.66 µV/码,纯转换器事实、与前端网络无关,卡 2 的 ROM 默认按此 冻结);③1k+1k 网络「2:1 分压 vs 源阻抗匹配」两读法待卡 0 注入斜率判别; ④端子→AINn 变比为仓库缺口待卡 0b;305.18/1611.3 定性为读法 A 的条件值、 判别前禁入代码;§9 变更记录编号不动(继保规划有指向本文件 §9 的跨文档 引用),新增行追加于其后 - 全仓其余 ±10 V 仅剩芯片手册转写与 tpafe5160 RANGE 枚举可选档注释 (芯片能力描述,非本板口径);数据可信.md §2.1 冲突挂账归 lead 销项 卡 3(代码;cfg_file.c 带 BOM,编辑后核 EF BB BF 完好): - 新增值类型 CFG_VAL_INT(枚举尾部追加、既有值不变;len 1/2/4 小端补码): s_decode_int() = strtol + ERANGE + 宽度上下界双校验(两端 long 均 32 位, 超范围文本饱和成 LONG_MAX 仅比界抓不住,ERANGE 必查);s_encode() 带负号 %ld 输出;cfg_file_register() 拒 INT 非法 len - 单测新增 TC-CONFIG-006/007/008:-1 / INT32_MIN / INT32_MAX / 越界拒绝 (含饱和带 2147483648)/ 编码带负号 / [sys] 段 load-save-load 往返一致 / 注册拒绝 INT len=3 —— cfg_file 套件 200/200 PASS - 回归:net_cfg 45/45、ftp_cfg 16/16 PASS,既有 network/ftp 段行为不变 - 越界改动说明:TC-CONFIG-006~008 定义行登记进属主文档 docs/测试说明/配置文件单元测试说明.md(id-check 增量拦截要求在属主登记处 补定义,该文件不在本卡写范围但为门禁唯一修复路径,仅追加 3 行用例 + 1 行 变更记录,lead 评审时留意) gate:@build 0 错误 0 警告(Code=214104 RO=18860 RW=1204 ZI=131852); RAM 增量 0 B(RW/ZI 与 ram_baseline 2026-10-24 行完全一致,IRAM1 57.7%、 CCM 87.9% 不变),Flash +324 B;uvprojx 零挂载变化、未入库。 staged 门禁全绿,唯 mem-numbers / mem-budget 因 Flash 增量需台账回填 (--write 目标 docs/内存管理/** 属单写者文件,本道不得触碰): gate: only mem-budget/mem-numbers pending lead ledger backfill (--all-files 全量自查确认失败面仅此两条;BOM/CR/U+FFFD/字面量 ASCII 已 手工自查) |
||
|
|
56893709fe |
feat(S12): 模块级轻量断言宏 APP_ASSERT + net_socket 状态机不变量试点 2 处
规格:docs/任务规划/测试与架构专项.md §2.1(模块级轻量断言宏,必须零生产开销)。
本提交只做道C-1:新增断言宏 + 2 处试点,不开 net 层大口子、不新增 test/host 目录。
改动
- 新增 Drivers/BSP/app_assert.h:APP_ASSERT 两级裁剪。
· 关闭态(默认,产品构建):编译期消失、零符号零代码;条件仍进 sizeof 的
不求值上下文,写错变量名/比较类型会当场报错,不会出现"裁掉=从没被编译器看过"。
· 打开态:失败交 configASSERT 用的同一个钩子 vApplicationAssertFailed()
(裸控制台打 [ERR] ASSERT FAILED file:line 后软复位);宿主端(模拟器 /
主机单测)落 stderr + abort(),非零退出码不会被一键回归静默吞掉。
- 开关 APP_ASSERT_ENABLE 默认注释,策略与 ENABLE_DESTRUCTIVE_TESTS 同级。
- 纯宏、无函数、无数据,不新增 .c → 不涉及双端注册(.h 靠 include 路径找到)。
- Drivers/BSP/NET/net_socket.c:2 处试点,都落在"函数头写了限定条件、函数体
一项都没检查"的缺口上。
· net_close_locked:控制块必须落在 s_net_socks 数组内且 in_use——此前给出
越界或已释放指针会一路走到 memset(sizeof(net_sock_t)),直接踩脏 fd 表。
· net_drop_conn_locked:进入时必须 in_use + TCP 流 + 会话处于 ESTABLISHED
或 CONNECTING——函数体无条件置 CLOSED 并登记重建,将来绕过
NET_MSG_DROP_CONN 分派门的新调用路径会拆掉一个健康监听器(症状与 N-30
一族同源难查),断言把这条状态机不变量钉成机器可查。
两处均 netTask 上下文、非中断、非高频;条件纯读无副作用;既有错误返回分支
一条都没改(断言不替代错误码,见 app_assert.h 第四节纪律)。
- test/host/net_socket/run_unit_test.py:include_dirs 补 Drivers/BSP 一行,使该
套单测编 net_socket.c 时用真 app_assert.h,不造桩——假件与真头漂移正是本
runner「常量闸」要防的那类自洽假绿;stub 目录仍在最前,同名头命中不受影响。
- Drivers/BSP/README.md:根级文件表补 app_assert.h 一行。
两处有意偏离示意稿(理由已写进头注释)
1) 断言点不再额外发一条 DBG_ERROR:钩子本身已打印 file:line,而每条 DBG_*
调用点约 90 B Flash + 216 B 栈(AGENTS「日志不是免费的」);断言点又常在
「内核状态已不可信」的现场,走裸控制台比走日志行缓冲稳。
2) 头落 Drivers/BSP(与 dbg_log.h、bsp_err.h 同级)而非示意稿的 App/util:它是
纯宏叶子能力,落 App/util 会让 BSP 新增一条反向 include App 层头的边,而
layer-deps 存量基线只减不增、加不进去;落 Drivers/BSP 已在 MCU 与模拟器双端
include 路径内 → 双端零工程文件改动(uvprojx / CMakeLists 一字未动)。
验证(工作树 _wt/S12-assert,分支 task/S12-assert)
- @build 产品态:BUILD_OK,0 错误 0 警告。
- 体积与 RAM:Code=213780 RO=18860 RW=1204 ZI=131852,与 scripts/ram_baseline.tsv
的 2026-10-24 基线行完全相同 → Flash/RAM 增量 0 B;.map 中 app_assert 相关
符号 0 条(规格完成判据"无新增符号")。gate 全绿,无需 mem-budget 例外。
- 打开态实测(临时取消注释编译,跑完已还原成注释态):0 错 0 警,
Code=213916(2 处断言共 +136 B ≈ 68 B/处,无每调用点栈代价),RW/ZI 不变。
- 宿主 MSVC 三态实测:关闭态断言不求值但条件仍做类型检查(错误标识符报
C2065);打开态真条件不触发、假条件 stderr 打 [ASSERT] FAILED 后 abort;
net_socket 主机单测 452/452 通过(用真头,开关默认关)。
- 门禁实跑:cppcheck(warning/perf/portability/style)、no-mojibake、coding-standard、
layer-deps、bsp-err、id-check、doc-links、registration-check、mem-budget 全 0。
- 台架 @test 未跑:bench 锁归 Lead;产品态本改动零行为差异,无需烧录回归。
遗留
- 打开态未在台架上真跑一轮(需 bench 锁 + 一个故意造假的注入点):待台架实测。
- 文档销项(测试与架构专项.md §2.1、并行分道方案.md 对应行、AGENTS 任务表)
归主工作树统一处理,本分支未碰 docs/任务规划/**。
|
||
|
|
15aa08552c |
docs(问题记录): 删除项目审查与优化建议报告,结论并入模块文档与编号规范
用户裁定:该报告大部分内容已闭环,可删除;仍有价值的迁到合适文档。删前逐条核对, 确认绝大多数结论在仓内早已有权威副本(LV_DRAW_SW_COMPLEX / osFlagsNoClear / SPI 分频 8 / 分层反向依赖存量基线等),只迁真正独有的四类内容: 1. 暂缓理由与重开条件(三条量化门槛)→ RAM 使用分析与优化方案 §4,并明确「本节是唯一 权威」,其它文档只留指针;同时把 10 处指向报告 §5.3 的重开条件引用改指该节。 2. 2026-10-22「常驻 vs 动态」三项诊断(静态前五块 43,462 B = 58%;动态面只有 heap_4, 故栈余量=CCM 余量;栈深主因是日志/配置写链)→ 同文档 §2.5。 3. `_fp_digits` 1,018 B 删不掉的机理与 F-6 根因修法(Q10 宏改单精度,−332 B,4.49e6 例 逐位等价)→ §2.6.4。 4. 「UI 侧缓冲进 CCM」要按 DMA 可达性二分(LVGL 池可进,帧缓冲/推流缓冲不可)→ 暂缓清单。 编号侧(报告曾是 6 个族的属主登记处): - 原报告 §9 的 26 行「号 → 现在详述于」对照表迁到 docs/编号规范.md 新增 §4.5,6 族 owner_docs 改指该节。规范正文含大量写法示例,直接当定义集会误伤,故 check_ids.py 新增 `_def_owners`:snapshot_only 族剔除规范正文,只恢复可判定、不参与悬空/撞号/裸形 /紧邻判定(实测若不分,裸形 S1 误报 238 条、S-3 与登记簿 S-3 误判重复定义)。 - 11 个已死号(N-03b/N-10~N-13/N-20/N-21/N-24/N-26/S-1/S-2)在 id_aliases.json 登记 status=void 并写明去处——它们被约 110 处代码注释与文档引用,原先只靠「报告里顺带提过 一句」才算有定义,报告一删就集体悬空。N-21/S-1/S-2 一号两义,注记已分别标明。 - 顺带修 id_aliases.json 的 note 被脚本累积重复 26 次;修 registry 里 3 处仍指向改名前的 任务卡文件名(W1-采集保护收尾.md / W8-数据可信.md),以及 iec104_master.py 两处同类注释。 门禁:check_ids --strict 通过(可判定 8747/10410 = 84.02%,基线由 82.6% 抬到 84.0%); check_doc_links --all --sections-strict 通过(177 文档);pre-commit 相关钩子全过。 |
||
|
|
4a09d4c63f |
fix(log): syslog_post 投递即拷贝(台架实证驱动的 B 方案整改)
待发条目 syslog_entry_t 原为 {id, const char *desc},只存调用方指针,
隐含「desc 必须活到落盘」的契约,但契约既未写进 sys_log.h、也无机械
检查。台架一次可控实验照出后果:testTask 临时钩子复用同一块缓冲连投
12 条带序号记录、并与 8 MB FTP STOR(占住卷锁)重叠,落盘的 12 条变
成「1~5 + 第 12 条七份」——滞留条目全部别名到该缓冲最后一次写入。
叠加卷忙整批回投(条目可滞留到卷空闲),投栈缓冲即成悬垂读。
改法(B 方案):条目内嵌 char desc[SYSLOG_DESC_MAX + 1u],syslog_post
投递时按 SYSLOG_DESC_MAX 截断拷贝并补终止符;sys_log.h 参数说明同步
写明「投递即拷贝、不要求生命周期覆盖到落盘」。
R1 台架正/负双向实证(非破坏性,钩子与临时改动已全量反向还原):
- 修复在位:12/12 全落、序号严格递增、无重无缺(768 B = 12x64)
- 临时把 -2 支路改成 rc == -2 && 0u:只落 5/12、6~12 全丢,两轮独立
复现一致,且该轮无 queue full 留痕 => 丢的路径确为「卷忙整批丢」
RAM/Flash 前后(scripts/ram_report.py 同口径,同一 .map 来源):
- ZI 131,500 -> 131,852 B(+352 B;s_preboot/s_batch_src 各 8 条
由 8 B 变 32 B);RW_IRAM1 75,280/57.4% -> 75,632/57.7%
- Code 213,720 -> 213,780 B(+60 B);RW 1,204 B 不变
- RW_CCM 静态不变(57,376 B / 87.9%);队列存储多要 192 B 取自
FreeRTOS 堆池,烧后串口水位 [STACK] heap free=15624 min_ever=8464
余量充足;总量仍远低于 mem-budget 92% 红线
测试:sys_log_mcu 套件 104 -> 106 条全绿,新增 TC-SYSLOG-108(投出
后改写调用方缓冲,落盘必须仍是投递时原文)与 TC-SYSLOG-108b(超长
在条目内钳位)。假消息队列护栏 MQ_MAXMSG 由 24 抬到 40:条目变大后
它拒收一切 Put、从既有用例起整片失败,属「尺寸变了就响」的正向记录。
主机侧此前照不出该类问题,是因为用例传字面量、静态存储期无限。
门禁 pre-commit run --all-files:39 项中 37 通过,含 test-coverage
(已覆盖行只增不减)、id-check(0 条台账外新发现、游标 TC-SYSLOG-108)、
doc-links --sections-strict、coding-standard、cppcheck/test-cppcheck、
bsp-err、layer-deps、no-mojibake、ui-golden、font-charset。仅
mem-numbers 与 mem-budget 失败:docs/内存管理/ 受管台账仍记改前
131,500/213,720。按分支约定不在分支上 --write 受管台账,留待合回
主干时统一回填,故 --no-verify 提交。
真机:产品构建 0 错 0 警告,重烧 + 回读校验 OK(suite=NONE dstr=off)、
启动标记齐全、无 [ERR]、VERDICT PASS。
|
||
|
|
924ac3d428 |
test(host): 断言字面量统一纯 ASCII,30 文件 1535 行
用户裁定「统一」。口径就是 AGENTS 铁律:字符串字面量必须纯 ASCII (无 BOM 文件里奇数个汉字会吞掉结束引号,偶数才侥幸通过),中文只写注释。 四名队友按目录分四组并行、写范围互斥:net_socket 418 行(6 文件)、 console_log/sys_log_mcu/soe_store/cfg_file_store_mcu 268 行(4 文件)、 11 个存量套件 404 行 + adc_input 89 行、iec104 与 lftpd 与 NET 四套等 356 行 (9 文件)。runner 的 .py 文档串不在口径内(Python 源不经 ARMCC 代码页)。 两套口径必须分清:粗口径(按行切引号)普查 = 34 文件 / 1,552 行;严格口径 (状态机剥掉块/行注释与字符常量后再取字符串字面量)= 30 文件 / 1,535 行。 差值那 4 个文件的命中全在注释里(ns_peers.c、net_socket/stub/ns_rtos.h、 common/ch395f_fake.h、common/fatfs_fake.c)——按口径一处都不该改,改了等于 把中文从注释里搬走、正好违背口径。粗口径绝不能当交付判据,否则要么白改 注释、要么留下「这行为什么没改」的悬案。 Lead 独立终检(不采信自报)五条硬判据,结果 30 文件漂移 0:① 每文件 TC 号 集合与 HEAD 逐字相同 ② 断言宏调用点数不变 ③ 行数与 HEAD 完全相等(专抓 整文件回写把尾部含 main() 吃掉的截断,第 1 轮真发生过两次)④ 剥注释后代码区 非 ASCII 字符 = 0 ⑤ 字节卫生(BOM 与 HEAD 一致、无 CR、无 U+FFFD、单尾换行)。 另用「逐行把字面量整体替换成空串后与 HEAD 必须逐行相等」机械证明只改了字面量; 各套 --module 覆盖率与断言数逐字不变(net_socket 887/889·53/53、console_log 199/200·16/16、sys_log_mcu 324/326·13/13、adc_input 103/103、sys_clock 100/100) → 生产码零改动,基线不需重登。 闸拦下一处真实回归(我的验收器没抓到):ns_s6_edges.c 翻译时把一个上一轮 已整改成平实描述的编号又写回了 CHECK 标签。原因很清楚:「只改字面量」并不 等于「只改无害内容」,标签里完全可以带进未登记族的编号形态;而 Lead 的自动 验收器只比对了 TC 形 id 集合,未覆盖 L/E/N/S/TRAP 等族。教训:批量改标签的 守卫必须加一条「新串不得出现任何已登记前缀族之外的编号形态」,且结构不变式 只覆盖自己想到的维度时不能替代真闸。 Lead 自查另清掉 126 处写坏的反斜杠(JS→Python 转义层数翻倍,把 markdown 反引号写成反斜杠+反引号),恰好发生在记录这条教训的那一节里。 文档:docs/测试说明/主机单测覆盖率口径.md §9 新增「第 2 轮」小节(两套口径对照 表、五条终检判据、六条手法含「转换说明符序列必须逐位相同」取代「禁止裸 %」、 三条协作纪律含先改板再派工与临时文件带组前缀、后续项 3 条)+ 变更记录一行。 后续项(本轮不做):把剥注释词法扫描器收进 scripts 当门禁(需用户点头并先定 test/ 是否纳入 coding-standard);iec104 的简写编号归族(牵 id_registry, 不能顺手做);替换器加「编号形态白名单」校验。 gate: pre-commit run --all-files -> 39 hooks, 37 Passed; failed = mem-numbers + mem-budget(受管快照与本树 .map 的漂移,属第 1 轮生产码改动的遗留,非本批 增量)。本批只碰 test/host/**,不进 Keil 编译面也不进模拟器 CMake,**RAM/Flash 增量 = 0**;实测水位 RW_IRAM1 57.4%、RW_CCM 87.9%,均低于 92% 红线。 id-check 0 台账外新账(可判定 84.63% > 基线 82.6%);test-coverage 33/33 全绿; cppcheck / coding-standard / bsp-err / layer-deps / doc-links 全 Passed。 按仓内分支约定 --no-verify 提交,台账 --write 回填留待主工作树合并后。 |
||
|
|
5a806d8a26 |
fix(log,net): 处置主机单测照出的 10 条现状,撤销 1 条误报
用户裁定「全部修」。第 1 轮修复跨三名队友、写范围互斥、零越界;
11 条登记现状 → 10 条已处置 + 1 条撤销(非阻塞 recv 「看不见 EOF」是误报:
net_recv_locked:1885 的非阻塞分支已把 CLOSED||session_dead 判成 EOF(0),
动手前读码才发现,误报比漏报更贵)。
存储与日志(App/log/sys_log_mcu.c、soe_store.c、cfg_file_store_mcu.c、sys_log.h)
A 卷忙整批丢日志:批量路径补 rc==-2 分支整批回投(不计故障/不打日志/
保序);此前一批最多 8 条既不落盘也不回投,而文档写着「条目不丢」
B rc==-1 文案与行为相反:改 write fail, requeue + 正常→故障节流
C 删永不可达的截断支;容量契约写死 sys_log.h(不足一律 -1、不写调用方字节)
D 自愈触发集违规(比原报告更严重):新增代码侧唯一入口 s_is_selfheal_code,
触发集收敛为 {DISK_ERR,INT_ERR,NO_FILESYSTEM,DENIED},移出名字/参数类码——
旧集合在 8.3 同名同因下每轮删一次自己的历史日志且永不自愈,正是存储架构
§10.1 第 10 条严禁的归集;soe_store 侧同源取更保守子集(打开失败绝不 unlink)
E 注释里的 FR_NO_SYSTEM 不存在,改 FR_NOT_READY / FR_NO_FILESYSTEM
F syslog_post 满态留痕节流(A 修好后「队列常驻满」成必然场景,不修等于用
新刷屏换掉静默丢);丢弃语义一字未改
NET(net_socket.c/.h、net_types.h、net_socket_sim.c、lftpd.c)
IP 字节序统一到 POSIX 网络序:改 net_inet_addr(&s_addr[0]==第一段)+ 出向
IP 数组按内存字节顺位拆装(进与出同时换族→芯片侧数组净效果不变,550h 钉住)
+ 模拟器逐字同步;ntoa 函数体未动,只改对它注释里取了废弃族值的例子——
那正是两套约定长期共存不被发现的原因。lftpd 两处算术核对确认无需改
UDP 绕过 netTask:两入口加执行任务上下文守卫,新码 NET_ERR_NOT_IN_NETTASK
(-12,重试永远无意义);结论口径=危险面已结构性关掉、串行化改造仍未做。
附带关掉第二条更隐蔽的路:非 netTask 自旋 recvfrom 期间控制块被 close 并
把同一 sockfd 分给新会话→旧自旋者消费新会话数据报
控制台(console_log.c/.h):冷却改独立 s_con_cooling 标志(旧写法在 tick==0 那
拍冷却等于没记);con_append 的判空位+推进 head+整行拷贝收进同一临界区(旧
为区外 check-then-act,环 >95% 满时可静默覆盖且既不打 [ERR] 也不计 dropped);
Instance==NULL 与僵尸通道分诊(未初始化绝不 reinit);三本账分离 + 新读口
dbg_console_tx_timeout();[ERR] 行改为发成功才销账
测试:net_socket 452、console_log 127、sys_log_mcu 104、soe_store 27、
cfg_file_store_mcu 34;回归 net_listener 34 / net_events 34 / net_pending 43 /
net_select 22 / lftpd 35 / lftpd_inet 28 / lftpd_io 33 / iec104_serv 28 /
nand_port 149 / vol_lock 33 / soe 32 / cfg_file 151 全绿。原「按现状钉住」的
用例全部翻正向;console_log 用「逐条退回旧实现」做变异自证,失败集合单调增长
6→11→18→22(把一条本来空转的断言逼了出来)。
游标抬升:TC-NETSOCK-545→560、TC-SYSLOG-100→107、TC-CONLOG-135→167。
文档:控制台设计说明 §4.1 口径与 §13-O2 销项 + v1.5;运行与自检记录 §4.4/§4.5
四条;存储架构 §10.1 第 10 条推论(指向 s_is_selfheal_code);TRAP-NET-21 后续
条目;BSD 指南新增 §9.0 s_addr 唯一约定;覆盖率口径 §9「第 1 轮修复处置」表 +
后续项 5 条 + 台架复验 7 条 + 新坑 8 条 + 变更记录。
后续项(本轮刻意不做,理由见 §9):UDP 改走 netMsgQueue(需 per-task 结果槽,
net_msg_t 按值拷贝、禁止加回传字段,且要真机回归);sim_syslog.c 同源不可达
支(本轮编译验证不到,不交没编译过的改动);syslog_post 丢弃计数;
dbg_console_tx_timeout() 读端接线(STALL 行是被解析的证据行,加字段要连解析端
与台架判据一起改);104 来源地址日志(现网无输出点)。
gate: @build 0 errors 0 warnings(Code=213720 RO=18860 RW=1204 ZI=131500)。
pre-commit run --all-files -> 39 hooks, 36 Passed; failed = mem-numbers +
mem-budget(受管快照与本树首次构建产物的漂移,非本批增量)+ id-check(已修,
现 0 台账外新账,可判定 84.63% > 基线 82.6%)。实测水位 RW_IRAM1 57.4%、
RW_CCM 87.9%,均低于 92% 红线;RAM/Flash 本批增量为数个 static 变量。
test-coverage / cppcheck / coding-standard / bsp-err / layer-deps / doc-links
全 Passed;全量覆盖率 33/33 套件、line 89.3%、func 92.3%、逐文件下降 0。
按仓内分支约定 --no-verify 提交,台账 --write 回填留待主工作树合并后。
|
||
|
|
794906cdc8 |
test(host): P2 覆盖率批次,5 套主机单测与共享假 FatFs
P2 五个文件全部进分母(三名队友并行,写范围互斥、零越界):
net_socket 420 条 / 881-883=99.8%、52-52 函数(S1~S6 分片)
sys_log_mcu 75 条 / 310-313=99.0%、12-12
console_log 104 条 / 188-189=99.5%、15-15
cfg_file_store_mcu 34 条 / 97-97=100%、10-10
soe_store 26 条 / 78-79=98.7%、4-4
合计 659 条断言,P2 本体 1554-1561=99.6%、93-93 函数。
账:套件 28→33 全绿;files_tested 32→37;未触及 112→107(.c 34→29,
恒等式 29 = 0(P1剩) + 0(P2) + 29(P3) 咬合,§9 终点判据达成);分母
4684→6245 插桩行;line 85.8%→89.3%;func 90.1%→92.2%(这批 5 个文件
全都以 ≥98.7% 进分母,故未摊薄)。--update-baseline 前后逐文件比对:
下降 0 个文件。
基建:新建 test/host/common/fatfs_fake.{h,c}(以真实 ff.h 为声明源、只
定义三文件实际调用的 9 个 f_*,缺哪个链接期响;卷忙/短写/FR_DENIED
可注入;短名违规分档);扩展 ch395f_fake 为纯新增(g_fx/g_fxchip 另开
一份世界 + ext_reset 挂进既有复位,既有三套面一字不动),并按真头修正
两个错值常量(SOCKET_OPEN 0x01→0x05、TCP_ESTABLISHED 0x05→0x04),
另在 net_socket runner 加真头/假件同名常量文本核对闸(负例验证过)。
存量回归:net_listener 34、net_events 34、net_pending 43、net_select 22、
nand_port 149、lftpd_io 33、vol_lock 33、soe 32、cfg_file 151 全绿。
编号:补 TC-HOST-{NETSOCK,SYSLOG,CFGFST,SOESTORE,CONLOG} 五族(22→27,
先补族再引号);net_socket 模块码由自取的两字母 NS 正名为 NETSOCK;
id-check 增量拦截无台账外新账,可判定比例 83.27%(基线 82.6%)。
文档:覆盖率口径 §9 新增「P2 落地」(含两套分母口径差、10 条现状表、
12 条可复用手法与并发红线),§8 第 1 条改「清单已吃穿」,补变更记录。
本提交未改任何生产代码(App/Drivers/Src/Lib/MDK-ARM 零触碰)。
10 条现状已逐条登记在 §9(含 sys_log_mcu.c:509~537 卷忙整批丢日志、
net_socket.c 同文件两套 IP 字节序、UDP 两 API 绕过 netTask),已获指示
全部修复,另开一轮(含测试字面量统一纯 ASCII)。
gate: pre-commit run --all-files → 39 hooks, 38 Passed; only mem-numbers
Failed(本工作树从未 @build,无 .map 事实源,属分支期已知陷阱);
mem-budget Passed;test-coverage 与 id-check Passed。RAM/Flash 增量 = 0
(纯测试批次)。按仓内分支约定走 --no-verify,台账回填留待主树合并后。
|
||
|
|
ec2dbc9e01 |
chore(merge): 回填内存台账与钩子规范化,收口 task/cov-host-line-coverage
done cov 已把 15 个提交合入主干(合并提交 c8de948),但它的门禁按已知顺序跑在 @build 之前(skill 实测陷阱那条),比对用的是合并前的旧 .map,台账必然失配。 这里按 skill 的官方处置在主工作树回填,使主干自身全绿。 内存台账(@build 已在 done 里跑过:0 错 0 警,Code=213652 RO=18860 RW=1192 ZI=131504;主工作树的 .map 是权威值): - scripts/ram_baseline.py --update(趋势行 2026-10-24:RW_IRAM1 75,272 B 57.4% / RW_CCM 57,376 B 87.9%)+ --write(受管区);check_mem_numbers.py --write。 - RAM使用分析与优化方案.md 两处正文数字:「当前状态」那句刷成合并后的真值 (75,264 → 75,272,日期改 2026-10-24);2026-10-23 那条变更行里的裸 B 值 232,536 改为 KB + 快照文件指针——**历史结论一字未改**,只是不再在正文里留 会过期的裸字节值(--scan 的判据正是"曾是区域值、现已不是",无内联豁免)。 - 补一行本次合并的变更:RAM +8 B(net_cfg.c 为 WAIT 契约修复新增 s_save_busy)、 Flash -24 B(lftpd_string 改名删死循环 + net_select 去冗余守卫)、CCM 零增量。 覆盖率口径文档:修我自己留下的占位符泄漏——§9 有一段写的时候用 @@ 当反引号哨兵 (run_code 里反引号与模板串冲突),漏做还原,共 52 处。后果不只是难看: - `docs/网络/网络自愈架构设计.md` §4.10 因失去反引号而不再被识别为"紧邻写法", 被 doc-links(钩子带 --sections-strict)按**自引用**判成失效章节——这条真红了。 - "test/host/common/ch395f_fake.h + .c" 被整体当路径引用检查,报文件不存在。 - 另有一处未配对的 @@ 与一个 ``` 残留,以及过期计数("套件 21+"、"族数 16"), 改为落地实测值:TC-HOST 族 16 → 22、套件 16 → 28,并指向下方落地进度表。 核对:该文档 @@ 残留 0、U+FFFD 0、无 CRLF。 12 个 run_unit_test.py:end-of-file-fixer 去掉末尾多余空行。分支期我用 --no-verify 提交(只为跳过 .map 台账那两条已知误报),把这两个改写型钩子的规范化机会一起 跳掉了——本批由钩子自己改正,**内容零改动**,也正是"提交门禁不该长期绕过"的账单。 自查:pre-commit run --all-files 在本工作树 **38 Passed / 0 Failed**(含 16 个主机 单测钩子实跑);doc-links --all --sections-strict 0 问题;mem-numbers --scan 绿。 未 push(推送需用户明确指示)。 |
||
|
|
957ec64645 |
test(APP/104): iec104_serv 模块(28 条,84.2%)——P1 十三块全部进分母
P1 收官批次。新增 test/host/iec104_serv/,iec104_serv.c 覆盖 117/139 = 84.2%。 做法:把生产源整个 #include 进 TU,直接驱动它的 7 个 static 辅助函数——**不跑 iec104_serv_task 的无限主循环**(那是 never-returning 的任务体,不适合单测;事件组 相关支路用 sys_evtHandle=NULL 走"不可用"分支)。链路层与 pts 层给假件:链路协议本身 有 test/host/iec104 的 97 条专测,本模块只管服务怎么活、怎么死、怎么重生。 钉住的契约: - 建监听:2404 端口过 htons、绑 NET_INADDR_ANY;socket/bind/listen 任一失败都要把 已经拿到的号关掉(漏关就是每次重试漏一个 socket 号,CH395F 只有 8 个)。 - **网络代次一变就拆掉旧连接与旧监听并重建**:现场改 IP 后端口必须在新地址上继续 服务,这条不重建就是"设备换了 IP 之后 104 主站再也连不上"。 - accept 门控:监听未就绪不 accept;表项已失效时把监听号丢掉、下一轮重建。 - 单连接 socket 的断线语义:对端 FIN 时只关数据口,**监听必须留着**;数据号与监听 号同一个时绝不关(关了就端口失联)。recv 返 -1 且 errno 是 WOULDBLOCK 是正常空转, 不能当成错误丢连接;真错误则丢弃并**当场重建监听**,不留空窗。 - 判死用**连续**短写计数:一次成功即复位。写成累计就会把偶发拥塞误判成断线,主站 看到的就是莫名掉线(连到 3 次才判死,I104_SEND_FAIL_MAX)。 - 32 分频探活:无可读数据时不是每轮都去收(省 CPU 预算),到点才收一次;对端 FIN 后 复位计数器。协议状态掉回 IDLE 也要丢并重生(否则服务挂着但永不服务)。 - 时钟桥接两个溢出边界:epoch 秒超过 32 位一律拒绝且不碰时钟(截断写进 RTC 就是乱值); 未对时(sys_clock_get 返回 UINT32_MAX)回 UINT64_MAX 哨兵而不是 0(否则对端会以为 设备时间是 1970-01-01)。 主机侧兼容处理(写进桩注释):真实 App/util/sys_clock.h 会 include sd2506.h(RTC 芯片 驱动)一路拉到 HAL,PC 上编不动,故桩掉 sys_clock.h 但**两个签名与真实头逐字一致**; 104 的头散在 App 与 Drivers/BSP 的多个子目录(iec104_serv.h/iec104_link.h/iec104_pts.h/ task_watchdog.h/sys_events.h/prot_set.h/sd2506.h…),逐个手写 include 目录必漏且报错会 落在被测源上、极易误读成生产代码坏了——运行器改为**按目录实际是否含 .h 自动收集**。 自查:初跑红 2 条,都是我的场景问题(分频到点那轮 recv 返回 0 会走对端 FIN 支路, 应给 -1 + WOULDBLOCK;"重建失败丢监听号"必须同时让表项失效),改正后 28/28。 P1 收官合计:12 个新模块、**308 条断言**;套件 16 → **28** 全绿;files_tested 19 → **32**; 未触及 .c 47 → **34**;恒等式 34 = 0(P1 剩) + 5(P2) + 29(P3);分母 2,893 → **4,684** 行; line=4020/4684(85.8%)、func=300/333(90.1%)。百分比"降"是摊薄不是回退(lftpd.c 64.3%、 lftpd_io.c 53.5% 这类只测主体的文件也进了分母),按 §5 口径该盯 files_tested/files_untested。 亮点:lftpd_inet.c **127/127 = 100%**、net_listener.c 99.2%、net_events.c 97.8%。 编号补建 TC-HOST-I104SRV(游标 041),TC-HOST 族数 20 → 22。§9 的落地进度表补齐并 统一为 NET 拆出的四块 ①②③④。 自查门禁:test-cppcheck Passed;check_ids --strict 通过;doc-links 35 处(= 存量); 10 个新增/改动文件 BOM/CR/U+FFFD/行尾逐项净。零生产代码改动,未跑 @build。 --all-files 仍只有 mem-numbers / mem-budget(.map 台账漂移,等 Lead 合并后统一回填) 与 ui-golden(ref/*.bin 不入库)三条失败,与本分支改动无关。 |
||
|
|
a0c261b5ee |
test(NET/lftpd): lftpd 控制通道模块(35 条),FTP 一套四块全部进分母
新增 test/host/lftpd/,lftpd.c 覆盖 304/473 = 64.3%。做法是把生产源整个 #include 进 TU,于是命令表 commands[]、17 个 static cmd_* 与 handle_control_channel 都能直接驱动: 假 inet 层给"脚本化命令行队列 + 响应记录",假 io 层给"极简内存视图 + 可注入失败", 认证与配置当可注入黑盒(认证本身有 test/host/ftp_auth 的 10 条专测,不重复验)。 钉住的契约(都是真机上贵、却难按需复现的那几类): - STOR 传到一半写失败必须 **unlink 半成品**:否则 Flash 上永久留个坏文件,现场表现 是"升级包传坏了再也传不上去"。真机要卡准"传一半掐线"的时机,这里注一个短写就行。 - 数据通道是单连接 socket:LIST/RETR/STOR 用完必须关监听并把 data_socket 复位成 -1; accept 失败要报 425 不留残口,会话退出(QUIT 或对端断线)时 cleanup 也要关掉还没 用的被动监听。漏一次就是下一条命令拿着上一个号继续 accept,偶发连不上。 - 命令名缓冲只有 command_tmp[4+1],前置判断 if (index >= 5) 就是防 memcpy 越界; 恰好 5 个字符必须被拒(改一行这条就响)。 - 认证前置白名单:未登录只放行 USER/PASS/QUIT/FEAT/SYST/NOOP,其余一律 530;口令错 必须清 auth_user_ok 强制重走 USER;被锁与口令错都只回 530,不给攻击者区分提示; 配置读不到时 USER 无法匹配、PASS 直接 530(fail-closed)。 - 写开关([ftp] write_en=0)必须在**碰文件之前**挡住 STOR/DELE,且不去 accept 数据 通道;DELE 不许删目录。 - 227/229 编码:IP 经 net_htonl 后按高字节到低字节排(就是点分序),端口高/低两字节; 拿不到本机 IP 时要把刚建的监听关掉。FEAT 多行:首行 211-、四条能力无状态码、末行 211 结束(共 6 条响应)。 - 220 欢迎没送达(对端已走)就直接收工,不空转读命令;该留痕按真实分级算 INFO 而不是 ERROR(真实 private/lftpd_log.h 把 lftpd_log_peer 归到 INFO:任何人连 21 端口就走 就能无限制造固件级 ERROR,还会撞掉 @test 的 Forbidden 标记 [ERR])。 - 传输循环每轮喂狗(lftpd_task_wd_beat 计数可断言)。 主机侧两个必要的兼容处理(都写在桩注释里,不是随手改): 1. lftpd.c 会 include ff.h,而这份 FatFs 在 Windows 支路上把 winsock.h 拉进来,它带 "#define s_addr S_un.S_addr" 的 BSD 兼容宏,会把真实 net_types.h 里的字段声明 uint32_t s_addr; 展开成 uint32_t S_un.S_addr; 直接炸(实测 C2143 在 "." 前缺 ";")。 桩里只 #undef 这个污染宏,让固件那份结构体定义原样参与编译,被测代码读的还是真字段。 2. 引号 include 先从 lftpd.c 自己目录找 private/lftpd_log.h,桩目录赢不过它——于是 顺着用真实那份(它只是把 lftpd_log_* 映射成 DBG_*),只桩最底下的 dbg_log.h。这样 真实日志分级也一起被编译验证,比我自己重写一套更对。 自查(35 条里前两轮红了 4 条,全是**我的期望/前置态写错**,实现均正确):未登录时 FOO 被白名单以 530 拦掉测不到 502 分派;227 的 IP 顺序我把 htonl 前后搞反;FEAT 是 6 条响应我按 5 条索引;PASV 之后走完整会话会被 cleanup 关掉监听(那正是 006 要验的 行为),观察 PASV 留下的状态必须直调 cmd_pasv。 覆盖率与台账:套件 26 → 27 全绿;files_tested 30 → 31;未触及 .c 36 → 35;分母 4,072 → 4,545 行。**总体 line_rate 88.4% → 85.9% 是摊薄不是回退**(64.3% 的文件进 了分母),按 §5 口径要盯 files_tested/files_untested——它从 19 一路涨到 31。 恒等式 35 = 1(P1 剩 iec104_serv.c) + 5(P2) + 29(P3)。编号补建 TC-HOST-LFTPD (游标 034),族数 20 → 21。 自查门禁:test-cppcheck Passed;check_ids --strict 通过;doc-links 35 处(= 存量); 9 个文件 BOM/CR/U+FFFD/行尾逐项净。零生产代码改动,未跑 @build。--all-files 仍只有 mem-numbers / mem-budget(.map 台账漂移,等 Lead 合并后统一回填)与 ui-golden (ref/*.bin 不入库)三条失败,与本分支改动无关。 |
||
|
|
8aaf9bbb0e |
test(NET/lftpd): lftpd_inet 模块(28 条,127/127 = 100%)
FTP 的 socket 适配层吃满——全仓第一个 **100% 行覆盖**的文件(127/127)。 新增 test/host/lftpd_inet/,28 条断言全部 MSVC 编译通过并 PASS。 钉住的契约: - 端口字节序:bind 前必须过 net_htons(sin_port 的注释就写着"网络字节序"),问名字 回来要 ntohs 还原;问不到名字报 -1,不拿脏端口当结果。 - 失败路径一律关 socket:建口失败不 bind;bind 失败关口不 listen;listen 失败关口 并各留一条 ERROR(漏关就是白占一个号,CH395F 只有 8 个)。 - accept 每轮失败都让出 CPU(同一段里也喂狗),直到成功;**网络代次一变立刻撤掉 accept**——否则改了 IP 之后监听还挂在旧代次上,端口在新地址上根本不通。这是现场 最常见的自愈路径,台架上要凑"对面正连着我顺手改 IP"极难。 - 带超时的 accept:监听门撤防时**立即放弃**,不对着死监听耗满窗口;对端一直不开 数据通道就按 100ms 步进等满再 INFO 收场。 - read_line:CRLF 就地截成结束符(FTP 命令行的边界);跨包分片要能拼出整行;读到 0 (对端关闭)立刻失败;-2 表示这一片超时继续等;其它负值**原样返回**(错误码不许被 吞成 -1);等待按 200ms 分片、30 s 总预算到点退出(分片写错就饿死看门狗);缓冲 填满仍无行尾要失败且**不越界写**(最后一格留给结束符)。 - 短写续传:net_send 可以只写一部分,续传必须从正确偏移接着写(少半条响应就是协议 错乱);写 0 字节按失败处理;二进制写成功时回请求长度。 桩的口径:private/lftpd_inet.h 与 net_types.h 用真实头;net_socket.h 是桩但函数原型 与真实头逐字一致,并**照做真实头对 FreeRTOS.h / task.h 的 include**(lftpd_inet.c 的 TickType_t / vTaskDelay / pdMS_TO_TICKS 就是从那条链上拿的,桩少这一行就是 C2065)。 lftpd_task_wd_beat 是 __weak 空实现、主机侧替换不掉,因此用同段代码里的"睡 100ms" 次数当喂狗轮数的代理(写进桩注释,不假装能直接数到喂狗)。accept 循环带 100 轮跑飞 保险(net_select 批次被挂死教训换来的)。 覆盖率与台账:套件 25 → 26 全绿;files_tested 29 → 30;未触及 .c 37 → 36;分母 3,945 → 4,072 行;line=3599/4072(**88.4%**,连涨三批)、func=272/299(91.0%)。 恒等式 36 = 2(P1 剩:lftpd.c 与 iec104_serv.c) + 5(P2) + 29(P3) 仍咬合。编号补建 TC-HOST-LFTINET(游标 070),族数 19 → 20。 自查:test-cppcheck Passed;check_ids --strict 通过;doc-links 35 处(= 存量); 9 个新增/改动文件 BOM/CR/U+FFFD/行尾逐项净。零生产代码改动,未跑 @build。 --all-files 仍只有 mem-numbers / mem-budget(.map 台账漂移,等 Lead 合并后统一回填) 与 ui-golden(ref/*.bin 不入库,新 worktree 天生没有黄金参考)三条失败,与本分支无关。 |
||
|
|
59e6d77224 |
test(NET): net_events 模块(34 条,覆盖 97.8%),NET 三块收官
假 CH395F 的第三批、也是 NET 域最后一块。net_events.c 覆盖 175/179 = 97.8%。共享 假芯片本批补齐**对端六元组**(get_remot_ipp 的 6 字节)与**链路变更计数**( link_change_count / link_up_cached 改为可预置,原来硬编码 0/1)。 钉住的契约(都是真机上会发生、却不能按需复现的那类): - 对端六元组解析:remote_ip 是**低字节在前**拼的(192.168.1.50 -> 0x3201A8C0,与 网络序相反)。钉住它是防止有人"顺手改成大端",让所有按 IP 比对/白名单静默错位。 - 陈旧中断防误判:芯片说 TCP 还 ESTABLISHED 时,迟到的 DISCONNECT 一律忽略并报 ERROR(拆活会话的代价是 104 主站看到莫名掉线);一条数据都没收就报断且芯片接收区 还有字节,判为疑似误报、只置 lost_conn_seen 延后交给对账器。 - 正常断开:优雅级沉降 + session_dead + last_peer_port 记旧端口 + 转 CLOSED + 发事件。 - 超时:ESTABLISHED 走隔离级沉降并置 released_abnormal —— 这正是 net_pending 收尾时 把挂起 recv 报成 CONNRESET 而不是 0 的那条输入(TC-NETPEND-014),**跨文件因果** 只有两边都能离线跑才可测。 - 丢中断自愈:芯片已连上而软件还写着 LISTENING 时补一次 accept;若软件已 CLOSED 则 只留痕不凭空造会话(TC-NETEV-042b 记现状)。 - 对账器:100ms 周期闸门(同一时刻不重复查芯片);链路计数**基线那趟不打日志** (0xFFFF 哨兵,否则每次上电都冒一条假"link up")、变化即留痕;五种不一致形态的 稳定计数分三档(会话死亡要连观 4 次、芯片偷重开监听 2 次、丢 CONNECT 自接 1 次); 动作后 1000ms 冷却内不重复折腾;U11 重同步(软件 CLOSED 而芯片在 LISTEN -> 直接跟 芯片,不做多余重建);不在用的槽位直接跳过。 三条初判失败的复盘(都是**我的期望值/场景写错**,实现是对的):① remote_ip 字节序 我按网络序写了期望;② 自愈场景我用了 CLOSED 态,而 accept 分支只认 LISTENING/ CONNECTING,改场景并补一条现状断言;③ 链路"基线不打日志"我测在非基线场景(s_ link_last 是函数内 static,跨场景本就延续)。对账器的 s_last/s_bad[]/s_cool[] 都是 函数内 static(外部够不着),因此每个形态**各占一个 fd**、时基单调前进,互不串扰。 覆盖率与台账:套件 24 → 25 全绿;files_tested 28 → 29;未触及 .c 38 → 37;分母 3,766 → 3,945 行;line=3472/3945(**88.0%**,连涨两批)、func=263/290(90.7%)。 恒等式 37 = 3(P1 剩) + 5(P2) + 29(P3) 仍咬合。编号补建 TC-HOST-NETEV(游标 058), 族数 18 → 19。 自查:test-cppcheck Passed(含补齐后的假芯片);check_ids --strict 通过;doc-links 35 处(= 存量);16 个新增/改动文件 BOM/CR/U+FFFD/行尾逐项净。零生产代码改动,未跑 @build。--all-files 仍只有 mem-numbers / mem-budget(.map 台账漂移,等 Lead 合并后 统一 --write 回填)与 ui-golden(simulator/tests/ref/*.bin 不入库,新 worktree 没有 黄金参考)三条失败,与本分支改动无关;提交按并行分支约定走 --no-verify。 |
||
|
|
b4441f0e1e |
test(NET): net_pending 模块(43 条,覆盖 87.1%),钉住通知值回传契约
假 CH395F 的第二批消费者。新增 test/host/net_pending/,net_pending.c 覆盖 169/194 = 87.1%。共享假芯片补了**缓冲尺寸宏链的同构转抄**(RAM_BLOCK 512 / SEND_BLOCKS 2 → SEND_BUF 1024;RECV_BLOCKS 4 → RECV_BUF 2048 → SPI_DMA_BUF 2052 → SPI_DMA_MAX_PAYLOAD 2048),于是 net_pending.h 里的 NET_SEND_CHUNK_MAX 是**真值 1024**,分块断言测的是芯片上界而不是假件自己发明的数字。 本模块的核心契约是跨上下文回传:AGENTS 模块约定写着 net_* 的错误码经**任务通知值** 回传(net_msg_t 按值拷入队列,netTask 改的是自己那份副本,调用方永远看不到;也勿给 net_msg_t 加回传字段,否则调用方读到栈垃圾)。台架读不到通知值,所以把 xTaskNotify 做成可观测假件(记目标句柄与通知值)之后,这条契约才第一次被真正验证。 钉住的契约: - 注册闸门:越界 fd 报 BADF;同 fd 已有挂起报 BUSY;caller 为空报 BUSY;**属主任务 自己发起被拒**(自己等自己等于死锁 netTask);to_ms=0 记为无限等(不置 deadline)。 - 到达与截断:读量钳在调用方缓冲内(绝不越界写别人的 buf);readable 但芯片没数据时 只清标志继续等,不误交 0 字节。 - 收尾四条分支:还有残留先把最后一包读走再收尾(**不丢尾包**);干净结束报 0 并按 auto_relisten 请求重开监听(不自动重开的不被偷偷要求重建);released_abnormal 报 CONNRESET 而不是 0(调用方要能分辨好坏收尾);session_dead 与 CLOSED 同路。 - settle_close:没挂起时直接返回不打扰芯片;有残留交还字节数;无残留报 CONNRESET。 - 挂起发送:参数校验(buf 空 / len<=0 / sent<0 / sent>=len 报 INVAL);单次写入钳在 NET_SEND_CHUNK_MAX;**deadline 每写一轮就续期**(还在推进就不该被 1000ms 掐死, FTP 上传大文件最容易撞这条);停滞不前进才报 TIMEDOUT;槽位消失或会话塌掉都**交还 已发字节数**(不是错误码,调用方据此算进度);cancel 留痕且幂等;**clear 不发通知** (与 recv 侧同一条纪律,不给调用方假答复)。 自查:42/43 首跑,唯一红的是**我的测试构造缺陷**——无限等那条没先把槽位置成在用, 被 in_use==0 兜底分支提前收口,测不到时间轴;补 mk_sock 后 43/43。reset_all 从上一 批的教训直接带过来(连被测模块的 static 挂起表与属主句柄一起复位),这次没再红。 覆盖率与台账:套件 23 → 24 全绿;files_tested 27 → 28;未触及 .c 39 → 38;分母 3,572 → 3,766 行;line=3297/3766(87.5%)、func=255/282(90.4%)。恒等式 38 = 4(P1 剩) + 5(P2) + 29(P3) 仍咬合。编号补建 TC-HOST-NETPEND(游标 040), 族数 17 → 18;注册表仍只做增量插入。 自查门禁:test-cppcheck Passed;check_ids --strict 通过;doc-links 35 处(= 存量); 12 个新增/改动文件 BOM/CR/U+FFFD/行尾逐项净。零生产代码改动,未跑 @build。 --all-files 仍只有 mem-numbers / mem-budget(.map 台账漂移,等 Lead 合并后统一回填) 与 ui-golden(ref/*.bin 不入库)三条失败,与本分支改动无关。 |
||
|
|
0a3b932395 |
test(NET): 假 CH395F 芯片落地 + net_listener 模块(34 条,覆盖 99.2%)
按 §9 规格做假芯片的第一批消费者。新增 test/host/common/ch395f_fake.{h,c}:15 个
函数的**真实原型逐字照抄**(含 ch395f_sock_state_t{open,tcp_state} 与 ERR_SUCCESS/
PROTO_TYPE_TCP/SOCKET_CLOSED/TCP_CLOSED/TCP_LISTEN 的真实取值),脚本化模型沿用本仓
既有假件风格:读函数按调用序号取返回队列(耗尽回落最后一个值)、写函数记次数与
最近入参、外加一条**调用顺序日志**让时序契约可断言。两条芯片怪癖必须复刻:
① get_sock_int_status **整体读即清**、无按位清除手段(AGENTS 模块约定 B3 实证坑,
不复刻就照不出"顺手全量清一遍把别的在用 Socket 门焊死");② *_cached 是**缓存值**
而非现场值,"监听还活着"的判据是 (open != CLOSED && tcp_state == LISTEN)。
各模块 stub/ch395f.h **只做转发** include 共享件(规格里拍板的方案):三份假芯片各自
漂移会让"假件与被测代码同时错"再也报不出来,签名与常量只能有一份定义。
新增 test/host/net_listener/,34 条断言,net_listener.c 覆盖 125/126 = **99.2%**。
钉住的契约(真机上一闪而过、台架凑不齐的组合):
- 四道互相牵制的时间闸门:30ms 退避(20ms 不重试、30ms 重试)、隔离级 400ms 与
优雅级 100ms(399ms/99ms 不放行、400ms/100ms 放行)、**800ms 上限只留痕且不放弃
请求**(留痕只打一次,到 2000ms 预算耗尽才报 ERROR 交对账器)。排期登记里那句
"沉降窗 800ms 上限只留痕"至此第一次有了可执行的验证。
- 该不该重建:芯片仍报 LISTEN 就不重建且清空请求;有挂起 recv/send 时让路但**保留
请求**(挂起结束自动补做);五种条件静默放弃(非 LISTENING/CLOSED 态、
auto_relisten=0、非 STREAM、local_port=0、in_use=0)。
- 失败不留半成品:open 失败关回去并回 BUSY;listen 失败也必须 close_socket。
- 重建后簿记:转 LISTENING、清 send_ready/recv_bytes/remote_ip(_arr)/remote_port、旧
remote_port 记进 last_peer_port、清 lost_conn_seen/released_abnormal;源端口与协议
取自表项本身(监听端口不能漂)。
- 芯片时序:清接收 → 关断 → 读即清 → 读状态(顺序不可换);清理接收区单次读钳到
256B、最多 16 轮、读到空即停。越界 fd 全程静默且不打扰芯片;请求去重保留首个 reason。
测试自查修了两处(都不是生产问题但值得记):
① reset_all 只复位假世界、**没复位被测模块自己的 static**(s_relisten_req/_next/_dead/
_quarantine/_settle_*/_capped),一上来红了 9 条;改用模块自带的 net_listener_clear()
清,顺带验证了 clear 的完整性。
② 沉降窗边界必须在**独立场景**测:放行判定与 30ms 退避共用 s_relisten_next,同一条
链里"恰好 400ms"那轮 tick 会被上一轮设的退避槽挡掉。这本身是个该知道的事实——
**hold 到点后最坏还要再等一个退避周期(实测 ≤30ms)才真正放行**,已写进用例注释。
另留痕一处死分支:net_relisten_locked 的 NET_ERR_BADF 从 tick **不可达**(tick 在调用
前就因表项为空放弃),TC-NETLIS-026 记着,新增调用点时要重新审视。
桩的口径:net_listener.h/net_types.h/net_config.h/net_pending.h 用**真实头**(net_sock_t
字段与各枚举一改即编译期报错);net_socket.h 是桩,但 net_set_errno 与 NET_ERR_RETURN_1
照抄真实头同名宏(net_socket.h:528/532);真实 net_pending.h 原型带 TaskHandle_t,故
宿主 FreeRTOS.h 补一个 void* typedef(只出现在签名里,被测代码从不传它)。
覆盖率与台账:套件 22 → 23 全绿;files_tested 26 → 27;未触及 .c 40 → 39;分母
3,446 → 3,572 行;line=3128/3572(87.6%,本批净涨因为新进来的文件几乎全绿)、
func=243/266(91.3%)。恒等式 39 = 5(P1 剩) + 5(P2) + 29(P3) 仍咬合。编号补建
TC-HOST-NETLIS(游标 026),族数 16 → 17;注册表仍只做增量插入。
自查:test-cppcheck Passed(连假芯片一起过);check_ids --strict 通过;doc-links 35 处
(= 存量);新增文件 BOM/CR/U+FFFD/行尾逐项净。**本增量零生产代码改动**,未跑 @build。
--all-files 仍只有 mem-numbers / mem-budget(.map 台账漂移,等 Lead 合并后统一回填)
与 ui-golden(ref/*.bin 不入库,新 worktree 天生没有黄金参考)三条失败,与本分支无关。
|
||
|
|
5224f21622 |
fix(NET,lftpd): 处置覆盖率照出的三处死路径(改名 + 修 timeout=0 + 激活异常集)
三处都由本轮 P1 新增的主机单测照出,用户逐条裁定后实施。共同性质:都不是改动引入
的回归,而是**从没被执行到的分支**——生产路径上要么没有调用者、要么没走边界,所以
编译器(0 错 0 警)、cppcheck、真机日志对它都无话可说。
1) 缺陷一(选 a:改名,行为零变化)
lftpd_string_trim 的尾部循环起点落在 strlen(p) 那一格 NUL,isspace(0) 为假 →
循环体一次都不执行,"尾部空白从未被裁",而名字承诺两头都去。改名
lftpd_string_ltrim + 删掉那条死循环 + 在 .h/.c 写明"只去前导"。不去尾才是对的:
RFC 959 以命令终止符 CRLF 界定命令,参数(PASS 口令、含空格的文件名)的尾随
空格属于参数本体,去掉等于静默改数据;CRLF 已由 lftpd_inet_read_line 截断。
调用点 lftpd.c 同步改名。全库无遗留真引用(余 6 处旧名均为解释改名历史的散文)。
2) 缺陷二(按推荐修)
net_select 的 timeout = {0,0} 换算出 timeout_ms = 0,而退出条件写着
if ((timeout_ms > 0) && (已用时 >= timeout_ms)) → 超时永不生效,退化成死等;
POSIX 语义是"只查一轮立即返回"。去掉 timeout_ms > 0 这个错误前置即可。就绪
检查在本判断之前,故有就绪时仍立刻带计数返回;同文件 net_poll_events 的
timeout >= 0 本来就对,现在两条对齐。风险面:拿它当"非阻塞查一遍"会让 netTask
回不到主循环,而 netTask 在 IWDG required_mask 里(串行 socket 栈唯一执行者)。
3) 缺陷三(选 ①:按 POSIX 置位)
exceptfds 是恒为空的死参数:循环开头 p_sock == NULL → continue 先跳过,而
check_socket_error() 只有"表项为空 / fd 越界"才返回 1,越界的 i 又不在本循环
范围内 → 调用方按 POSIX 直觉用它收异常,永远什么都收不到,且返回码不报错。
把异常判定提到 continue 之前:表项不存在的 fd 计入 exceptfds 与返回计数,并更新
函数注释。选 ① 会改变返回计数语义,故补一条"未请求异常集时不计数"的用例,
确保只查可读的老调用方不被误伤(TC-NETSEL-012b)。
测试同步翻转:原 TC-NETSEL-008 / TC-NETSEL-012 是"现状桩、改了会响",现在改成正向
契约,并新增 TC-NETSEL-012c(异常位只落到被请求的那个集合);TC-LFTSTR-005 从
"尾部不裁"的现状登记改为正向契约(尾随空格必须保留)。net_select 22/22、
lftpd_io 33/33 全绿。
@build:0 错误 0 警告。实测体积 ER_IROM1 232,512 B(快照 232,536 → **−24 B**)、
Flash 233,704 B(−20 B)、RW_IRAM1 75,272 B(+8 B 是上一提交 net_cfg 那个字节,
本批零新增)、**RW_CCM 57,376 B 不变**;四档百分比 22.2/57.4/87.9/22.3 全不变。
Code 减少 36 B 即删掉的死循环。
覆盖率台账:门禁如实报了一次 lftpd_string.c 已覆盖行 8 → 7(**代码少了一行**,不是
覆盖退化),已 --update-baseline 重登;现 22/22 套件、line=3003/3446(87.1%)、
func=236/259(91.1%)、tested_files=26、untested_files=118。
文档:主机单测覆盖率口径 §9 新增"三处死路径的处置"小节(裁定、改法、影响、钉住
它的用例一一对应),并把两处"等裁定"的登记改为已处置。
自查:coding-standard / test-cppcheck / id-check --strict(无台账外新账)/ doc-links
(35 处 = 存量)全过;八个改动文件与 HEAD 逐项比对 BOM/CR/U+FFFD/行尾无变化
(这几个文件本就不带 BOM,未被动过)。pre-commit --all-files 仍只有三条失败且与
本分支无关:mem-numbers / mem-budget(.map 与 docs/内存管理 受管快照漂移,增量见
上,按并行分支约定不在分支里 --write,等 Lead 合并后统一回填)与 ui-golden
(simulator/tests/ref/*.bin 在 .gitignore 内,新建 worktree 天生没有黄金参考)。
|
||
|
|
658bc40ccc |
test(NET): net_select 模块(21 条)与 NET 域首份 ch395f 桩,登记两处死路径
P1 的 NET 四块开了第一块:新增 test/host/net_select/,21 条断言全部 MSVC 编译
通过并 PASS。net_select.c 一个芯片函数都不调,所以它是四块里唯一不需要假芯片的,
先把它拿下,顺带把 NET 域的桩骨架立起来。
钉住的契约:
- 就绪位回写:入参集合里未就绪的 fd 必须被清掉,只留就绪的(POSIX 语义);未请求
的集合不被写回、可以传 NULL。
- 状态准入:LISTENING 即使 readable 也不算可读(accept 语义不在这层);ESTABLISHED
+ send_ready 才可写;CONNECTING 时 send_ready 不作数。
- 边界:nfds 为 0 / 负 / 超过 NET_MAX_SOCKETS 都返回 -1(不许扫出 socket 表外)。
- 超时算术:tv_usec 是**整除截断**(1999us 当 1ms 而不是 2ms);timeout=NULL 时
无限等并由对端事件唤醒;poll 的 timeout=0 首轮即退、每轮先清 revents。
用可控 tick(每问一次 +1)+ 可控 osDelay(计数、可指定轮数后造一个就绪 socket)
把这些变成确定性轮数,台架上根本构造不出"没人来连时该怎么退"。
照出两处**死路径**(只登记,未改语义;全库唯一调用点 test/board/net_test_task.c
传的是 NULL 与非零 tv,今天没有受害者):
1. net_select 的 timeout = {0,0} 换算出 timeout_ms = 0,而退出条件写的是
if ((timeout_ms > 0) && (已用时 >= timeout_ms)) → **超时 0 永不触发退出**,退化成
无限等;POSIX 在这里必须立刻返回 0。同文件 net_poll_events 写的 timeout >= 0
是对的,两条并排放着正好是对照。风险面:谁拿它当"非阻塞查一遍",netTask 就
回不到主循环,而 netTask 在 IWDG required_mask 里。
2. exceptfds 是恒为空的死参数:循环体开头 p_sock == NULL → continue 先跳过,
check_socket_error 的 NULL 分支从 select 里到不了。按 POSIX 直觉用它收异常的人
会永远什么都收不到。
两处都用"现状桩"钉成改了会响(用例名里写明不是期望行为)。另修掉我自己写错的一条
用例:给 timeout=NULL 又没有就绪 fd,直接死循环——已在假 osDelay 里加了 500 轮
保险(跑飞就 exit(2)),因为挂死的测试会把 exe 文件名占住、让后续构建报 LNK1104。
桩的边界写死在文件头:net_select.h / net_types.h / net_config.h 用真实头(net_sock_t
字段名与 NET_SOCK_STATE_* 一改即编译期报错);main.h / cmsis_os.h / FreeRTOS.h /
task.h 是本目录桩;新建的 ch395f.h 是**空壳**,只服务不调芯片函数的文件——
net_pending / net_events / net_listener 直接调十余处 ch395f_*,要的是可脚本化返回的
假芯片,不要把这个空壳当成"NET 域桩已就绪"。
覆盖率:套件 21 → 22 全绿;files_tested 25 → 26;未触及 .c 41 → 40;分母 3,332 →
3,446 行;net_select.c 97/114(85.1%)。恒等式更新为 40 = 6(P1 剩) + 5(P2) + 29(P3)。
编号按 B 层口径补建 TC-HOST-NETSEL(游标 019),TC-HOST 族现共 16 族;注册表仍只
做增量插入。
自查:test-cppcheck Passed;check_ids --strict 通过;doc-links = 35 处(= 存量);
BOM/CR/U+FFFD/行尾逐项净。本增量零生产代码改动,未跑 @build。--all-files 仍只有
mem-numbers / mem-budget(.map 台账漂移,等 Lead 合并后统一回填)与 ui-golden
(ref/*.bin 不入库,新 worktree 天生没有黄金参考)三条失败,与本分支无关。
|
||
|
|
6bdf063f50 |
test(NET/lftpd): P1 增补 lftpd_io 模块(33 条),登记 FTP 域一处潜伏缺陷
新增 test/host/lftpd_io/:一个 TU 同时纳入生产源 lftpd_io.c 与 lftpd_string.c (两者静态符号不冲突,省一套桩),33 条断言全部 MSVC 编译通过并 PASS。 钉住的契约(都是真机上偶发、日志看不出根因的那类): - 路径规范化:**".." 上跳过头仍被钳在根内**("/a" + "../../x" = "/x")——FTP 客户端 可发任意路径,这是安全属性;绝对名忽略 base、"." 丢弃、段间多余斜杠折叠、 NULL 入参容忍、全空结果归 "/"。 - 分配失败:这个函数返回 pvPortMalloc 出来的指针(历史上正是它落在 C 库 malloc 上, RAM 方案 §4.2.1)。用**可注入失败的假堆**跑两条分支:首块失败 → NULL;结果缓冲 失败 → NULL **且第一块已 vPortFree**(不泄漏堆)。模拟器宿主 CRT 永不失败,这条 只有假堆能构造。 - 卷锁时机:open 成功**故意不释放**(整个传输期独占卷,由 close 释放),失败必须 释放并留 ERROR;单文件槽守卫 s_file_open 命中时**不碰卷锁也不碰 FatFs**。 - 等卷锁循环每轮喂看门狗(lftpd_task_wd_beat):defaultTask 与 FTP 争卷时这里可能 空转上百毫秒,漏喂就是整机复位。脚本化 vol_lock_wait 的返回序列直接构造 2 轮空等。 - lftpd_string_trim:行首空白由**返回指针**跳过、原缓冲不搬移(调用点 lftpd.c 用的 正是返回值);全空白串返回空串。 **本批照出一处,未改语义、只登记**:lftpd_string_trim 的尾部循环写成 for (i = strlen(p); i >= 0 && isspace(p[i]); i--),i 起步那格是 NUL、isspace(0) 为假 → 循环一次都不执行,**尾部空白与 CRLF 从未被裁掉**。今天不发作是因为 CRLF 在 lftpd_inet_read_line 里已用 strstr 截断、且唯一调用点只关心行首;风险在于"以后有人 拿它去尾部空白"不会生效。修法只要一行(i 从 strlen(p)-1 起),但那会改变 FTP 参数 (含空格的文件名/口令)的可见行为,需要 FTP 域一起过,**留给用户裁定**;当前用 TC-LFTSTR-005 把现状钉成"改了会响"(明确标注是现状桩、不是期望行为)。 未覆盖也写在文件头:lftpd_io_read/write/close/stat/unlink/opendir/readdir/closedir 要先把假 FIL/FILINFO 的字段语义(fptr、obj.objsize、fname 等)做实,否则断言会落在 假件自己写的规则上;这 8 个 f_* 只给了可链接的 FR_INT_ERR 实现,走进即失败不静默。 覆盖率:套件 20 → 21 全绿;files_tested 23 → 25;未触及 .c 43 → 41;分母 3,163 → 3,332 行;lftpd_io.c 85/159(53.5%)、lftpd_string.c 8/10。总体 line_rate 88.9% → 87.2% —— **这是摊薄不是回退**(新进来的文件只测了一半,分母涨得比分子快),已按 §5 口径写进口径文档 §9 的落地进度表;恒等式更新为 41 = 7(P1 剩) + 5(P2) + 29(P3)。 编号:按 B 层口径补建 2 族 TC-HOST-LFTPIO(游标 037)与 TC-HOST-LFTSTR(005), TC-HOST 族现共 **15** 族;id_registry.json 仍只做增量插入(无重排)。 自查:test-cppcheck Passed;coding-standard Passed;check_ids --strict 通过(无台账外 新账);check_doc_links --all = 35 处(= 存量,本分支贡献 0);新增/改动文件 BOM/CR/ U+FFFD/行尾卫生逐项净。**本增量零生产代码改动**(只加测试、注册表与文档),故未跑 @build。pre-commit --all-files 仍只有三条失败且与本分支无关:mem-numbers / mem-budget (本 worktree 上次 @build 生成的 .map 与受管快照漂移,增量 ER_IROM1 +12B、RW_IRAM1 +8B、CCM 0,按并行分支约定不在分支里 --write,等 Lead 合并后统一回填)与 ui-golden (simulator/tests/ref/*.bin 在 .gitignore 内,新 worktree 天生没有黄金参考)。 |
||
|
|
b1291f1308 |
test(NETCFG,CFG): P1①四个主机单测模块,并修 net_cfg 的 WAIT 契约与定长错记
按 docs/测试说明/主机单测覆盖率口径.md §9 的清单吃 P1 第①批「配置与工具」四块, 新增 4 个主机单测模块共 104 条断言,全部 MSVC 编译通过并 PASS: - test/host/net_cfg/(45 条):出厂默认可用、注册幂等与内容、load 报 -1 仍返回 0 (RAM 恒有效契约)、跨任务保存交接状态机 IDLE/WAIT/OK/FAIL、MAC 三态优先级、 IPv4 定长格式化。 - test/host/ftp_cfg/(16 条):[ftp] 段注册(**p_cb 必须为 NULL**,口令下次登录才 生效)、默认口令判定大小写不敏感、NULL 一律判不等(fail-closed)。 - test/host/prot_set_store/(16 条):blob 返回码分流 1 无档 / 0 成功 / **2 换代 (只打 INFO)** / -1 损坏;写盘失败必须回置脏标志(否则定值静默丢失)。 - test/host/task_prof/(27 条):无效样本闸门(防 DWT 复位把 max 抬到 2^32)、 未 enter 就 exit 不记账、首次 5s + 每 2s 节流、环形缓冲与裸发两通道、 周期→微秒换算随 SystemCoreClock 变。 覆盖率收益(已 --update-baseline 登记):套件 16 → 20 全绿;files_tested 19 → 23; 未触及 125 → 121 个文件(.c 47 → 43、9,657 → 9,228 行);分母 2,893 → 3,163 插桩 行;line=2811/3163(88.9%)、func=225/240(93.8%)。§9 的恒等式同步更新且仍咬合: 43 = 9(P1 剩) + 5(P2) + 29(P3)、9,228 = 2,188 + 2,226 + 4,814。 新单测照出并修掉两处真问题(都在 net_cfg,不是测试写错): 1. 实现违反自己的文档契约:net_cfg.h 明写"属主任务写盘中显示 WAIT",但 net_cfg_save_run 为了不丢新请求会先清 pending 再写盘 → 写盘那几百毫秒里 UI 保存行退回上一轮的 OK/IDLE(第一次保存按 ENTER 后屏幕上还是 ENTER),用户只 会再按一次。补 s_save_busy 标志,TC-NETCFG-028/026/030 钉死(含失败路径必须 清 busy,否则 UI 永久卡 WAIT)。 2. "定长 11 字符"是错的:%03u.%03u.%03u.%03u = 4 段×3 位 + 3 个点 = **15**。这个数 错了 4 处(net_cfg.h、net_cfg.c、网络配置说明.md 两处)——是我照抄它才撞上 FAIL,错在文档不是代码。已全部更正,并确认 len ≥ 16 的要求与 UI_BUF_STRLEN=32 本来就没问题(无截断风险)。 桩的口径(沿用既有模块,不另起一套):真实头优先——cfg_file.h / cfg_file_store.h / console_log.h / prot_set.h 全用真头(接口一漂移就编译期报错),只有 main.h 必须桩 (真实 main.h 拉整棵 HAL 头树,PC 上编不动;桩里字段名与位掩码宏名与 CMSIS 一致)。 prot_set_store 连真实 prot_set.c 一起编:blob 的编解码与脏标志在它里面,只有拿真 serialize 产出的 blob 才能造出"换代"与"损坏"两种真实形态,手搓等于测自己的桩。 配置引擎本身(解析/写盘/沉降)归 test/host/cfg_file 的 103 条,本批不重复测。 编号门禁:按 2026-10-21 批 3 的 B 层口径补建 4 族 TC-HOST-*(NETCFG 游标 056 / FTPCFG 014 / PROTSTOR 016 / TASKPROF 020,代码即属主登记处)。这一步不是走形式: 建族之前文档里引用 TC-NETCFG-028 被判「台账之外新账」直接卡提交,建族后才通过; 编号规范 §8.4 变更记录加一行说明族数 9 → 13。id_registry.json 只做增量插入(+88 行, 无重排)。 自查(提交时 pre-commit run --all-files,**仅 3 条失败且都与本分支改动无关**): - mem-numbers / mem-budget:本 worktree 因需验证代码改动而 @build 过,新生成的 .map 与 docs/内存管理 受管快照漂移。实测增量 ER_IROM1 +12 B、RW_IRAM1 +8 B、Flash +16 B、**CCM 0**,水位百分比全不变(改动 = 1 个静态字节 + 几条指令)。按并行分支 约定**不在分支里 --write**,台账由 Lead 合并后统一回填。 - ui-golden:simulator/tests/ref/*.bin 写在 .gitignore 里(黄金参考是本地生成物), 新建的 worktree 天生没有,报的是"缺黄金参考"而非像素差异;本分支零 UI 文件改动。 - 其余全部 Passed,含 @build 0 错误 0 警告、test-cppcheck(它抓到过我一条 p!=NULL 后又解引用的写法,已改为断言+显式守卫)、coding-standard、doc-links(35 处=存量)、 id-check --strict、mojibake 与 BOM/CR/U+FFFD/行尾逐项卫生。 - 自审修掉自己写的两条恒真断言(形如 x==0?1:1 的假绿)与一个重复编号标签。 - 4 个新模块**尚未挂 pre-commit 钩子**:.pre-commit-config.yaml 是单写文件,任务工作 树内不改;覆盖率脚本按 test/host/**/run_unit_test.py 自动发现,已实跑 20/20。 - 未跑 @test:改动仅 1 个静态字节 + UI 保存行的显示时序,无硬件语义变化。 |
||
|
|
78248a1cdf |
feat(S-5): 收编 SD2506/TPAFE 并给 dhara 失败分类,门禁基线 19→17
前一笔立契约与门禁(`Drivers/BSP/bsp_err.h` + `bsp-err` 钩子 + RS485 试点);这一笔按用户
指定顺序 C3 → C1 → C2 把三个模块真正收编,并让存储失败第一次变得可读、可分类。
**C3 · SD2506 整模块(11 个公共 API + 6 个内部 helper)**:三枚私有宏 `SD2506_OK`/
`SD2506_ERROR`/`SD2506_I2C_ERROR` **删除而不是留别名**——留别名等于新代码还能用旧形状,
把迁移洗掉;编译器替我们找全所有调用点。新增 `sd2506_err_from_hal()`,**把 I2C 超时从
"和没人应答共用一个 −2"里拆出来归成 `BSP_ERR_TIMEOUT`(可重试)**——SD2506 是启动链第一站、
I2C1 上电时序敏感,这是本波唯一真正的语义改善,不是改名。`sd2506_init` 的 charge 寄存器
**回读校验不符**原返参数类错误,改归 `BSP_ERR_IO`(那不是调用方的错)。
**C1 · 同形两义**:`GD5F_BUSY_TIMEOUT` → `GD5F_WAIT_EXPIRED`(**值 −2 不变**,纯消"名字叫
TIMEOUT 其实是返回码")。**GD5F 私有码集整体收编刻意没做**:169 处引用里 48 处在板级套件、
还要动 Trap 记录用词,属另一波带真机+套件回归的工作,不夹带。TPAFE5160 收编 23 处:
`BUSY_TIMEOUT → BSP_ERR_TIMEOUT`、`ERROR → BSP_ERR_PARAM`(**同值 −1,行为零变化**)、
`FRSTDATA_ERR → BSP_ERR_NO_DEVICE`(E-44 的本义就是"芯片没驱动 DB 总线",归到器件无响应比
私有 −3 有用,且避开与 `BSP_ERR_TIMEOUT` 撞值)。实测 `tpafe5160.o`/`gd5f2gq5ue.o` 的 Code
增量为 **0**——改名不产生一条指令。
⚠ **`tpafe5160_snapshot()` 刻意不套成败码**:它是 1=有新帧 / 0=无新帧 / −1=参数错 的三态
**状态**返回,0 不是错误而是"这一拍没有新数据",强行收编会把慢消费者的正常路径变成失败。
顺带订正我上一版在 `bsp_err.h` 的断言——"本层只有 `net_*` 把数量与错误挤同一返回值"是错的,
`snapshot`/`adc_input_poll` 就是第二族;两族现都已写明并各注保留理由。
**C2 · FTL 坍缩点分类**:`ftl_flush_cache`/`ftl_read_page` 不再把 dhara 失败压成
`GD5F_ERROR`,
按**处置差异**分三类,并在最早同时知道 LPN 与原始码的位置就地打印:`ECC`/`TOO_BAD` →
`BSP_ERR_CRC`(页级,重试或换页,不代表卷坏);`JOURNAL_FULL`/`MAP_FULL` →
`BSP_ERR_NO_SPACE`(介质健康但块池/日志见底,此时重格式化只是把问题推回去);
`BAD_BLOCK`/`RECOVER`/`CORRUPT_MAP`/越界 → `BSP_ERR_IO`(完整性故障,保卷 + 上报,不许自愈
重格式化)。这与 **E-31** 是同一条纪律的两端。可读名用自建短表:**本仓 dhara 没有编
`error.c`,用 `dhara_strerror()` 会直接链接失败**。`disk_read`/`disk_write` 仍回
`RES_ERROR`
(FatFs 契约);要让 defaultTask 卷健康探针按类分支还差跨调用存活的快照 → C4 待还。
**两次靠核实拦住的自我错误**:① 我一度认定 `DBG_ERROR("... err=%d", err)` 是把结构体塞进
varargs 的格式 bug——核 `Lib/dhara/error.h` 后确认 `dhara_error_t` 是 `enum`(标量),那行日志
本来合法,改了反而是引入错误;② `bsp-err` 一次 `replace_all` 越界把 8 处 **GD5F 码空间**的
判据改成 `!= BSP_OK`(数值同为 0、无行为变化),但那正是"把两个码空间混起来",已逐一还原。
`cppcheck` 亦抓到 `cls` 声明作用域过宽,已收进失败分支。
**验证**:`@build` 0 错 0 警告(`Code` 213,648、RO 18,860、`ER_IROM1` 232,508 B /
22.2%、
`ROM 合计` 233,696;**RAM 三项零增量**);`@test` PASS(692 ms,烧入戳 `Oct 23 01:35:32`)
且逐条读到被改模块的锚点:`SD2506 init: OK (ret=0)` 与 ID/时间/温度/电池四条读回正常、
`ADC init: OK`、`NAND init: OK`、`Map resumed: 14094/97504`、`adc=` 帧计数持续递增(证明
snapshot 三态未被改坏)、`[ERR]`/Fault/FAIL 0 条。主机单测:系统时钟 100/100、dhara NAND
移植层 149/149(两者都因本次改动需补 `Drivers/BSP` include 路径,补后在钩子内实跑 Passed)。
`pre-commit run` 全量 RC=0(20 个实跑钩子 Passed);`bsp-err` 基线 **19 → 17**(还掉两个
`*_BUSY_TIMEOUT = -2`)、`--prune` 干净;`doc-links --all --sections-strict` 147 篇
0 问题;
`id-check --strict`、`layer-deps`、`mem-numbers`、`mem-budget`、`ui-golden` 全过;33
个文件
字节卫生 0 异常(无 CR / 无 U+FFFD / 无行尾空格 / 均有尾换行)。
**口径与数字联动**:新增 `docs/架构设计/STM32F4-Base存储架构说明.md` §10.4(三类码与处置
理由);`pre-commit使用说明.md` §2.27 与 `AGENTS.md` 基线计数 19 → 17;TPAFE README、
GD5F 测试指南与 Trap 记录均**保留旧名留痕**以便对旧日志;配图桶按 .map 对象级增量重算
(`dhara/FTL` 10,931 → 11,222,+291 全部落在 `nand_ftl.o`;应用代码/UI +36 落在
`app_main.o`;其余散量入"其他"7,557;桶和 = Code+RO 断言通过、文本溢出 0);
`ram_baseline --update/--write`、`ram_report_20261023.md` 快照、报告 §1.3/§5.1/§5.4
与
部署文档 §3.3 数字全部同步;报告 §0.4/§9 的 S-5 状态改为 🟡 主体已落地。
|
||
|
|
23daa3d9ad |
chore(台架): 删零引用的一次性探针、修可信判据工具登录、清理口径落文
两件事一起做:把"没人用又已经失效"的一次性探针清掉,把"台架现场脏"这件事的口径写进文档。 **删除(5 个文件,全库零引用)**:`MDK-ARM/ftp_retr_abort_probe.py`(其职能已被 `test/host/ftp_abort_probe.py` 取代,Trap 记录引用的也是后者)与整个 `MDK-ARM/bench_diag/` (4 个诊断脚本:abort_gap / pcref / recover / sink_recycle)。删除判据三条同时成立:① 全库 `git grep` 除自身外零引用;② 自 2026-10-11 设备启用 FTP 鉴权起,脚本里写死的匿名登录必然 530 → 已经跑不动 11 天;③ 都是"跑一次拿现场"的诊断件,价值在结论而结论已沉淀进 Trap 记录。 需要时从 git 历史取回(`test/host/README.md` 与 `MDK-ARM/README.md` 都写明了这一点)。 **刻意保留并修好**:`MDK-ARM/ftp_freeze_probe.py`——它不是一次性件: `CH395F_Trap_Records.md` 拿它当"177 轮 SHA-256 全匹配"的**可信复现配方**、 `BSD_Socket_API_使用指南.md` 把它列进排障判据、`Drivers/BSP/NET/lftpd/README.md` 也指它。 删掉它等于删掉文档指定的真值工具。改为 `--user/--password`(默认出厂 admin/admin,模块常量 `FTP_USER`/`FTP_PASS`,两处登录点都读它),实测一轮:`ROUND 1 size=4096 stor=OK retr=OK hash=MATCH`、`SUMMARY pass=1 fail=0`——修前它连 530 都过不去。 **台架设备清理(不动仓库内容)**:`/` 根目录实测残留 **27 个探针文件 / 262 KB**(`AB000x`、 `A000x`、`R000x`、`SZ2K~64K`、`E12A`、`DIAG_A`、`PP0~PP4`——正是刚删的那批一次性探针留下的)。 逐个 `DELE` 后剩 `LOG` + `CONFIG.INI` + `PROT_SET.BIN` 三条目。**判据:只删显式点名的文件, 绝不 glob**;保留清单必须含 `/config.ini`(网口 + FTP 鉴权)、`/PROT_SET.BIN`(保护定值 blob, `PROT_SET_BLOB_SZ` = 176 B,删了等于定值清零)、`/log` 目录。清完两步验收:`@test` PASS (630 ms,定值巡检与配置加载都在这条链上)+ `ftp_list_fill_test.py` PASS(29 行 / 1851 B / 完成回包 226,26 个新文件全列出)。口径写进 `docs/测试说明/存储维护与容量恢复.md` 新 §4.1 (明确它是"动作 D 清文件",与 A 重建 BBT / B 全片擦除 / C 容量恢复区分——那三个会丢卷内容)。 门禁:`py_compile`(freeze 探针)通过;`check_doc_links.py --all --sections-strict` 146 文档 0 问题(删除的 5 个文件确认无任何文档引用);`check_ids.py --strict` 增量拦截通过(可判定 82.82%);`layer-deps` 通过;4 个改动文件字节卫生 BOM 无 / CR 0 / U+FFFD 0 / 无行尾空格。 本轮无固件改动,未跑 `@build`(设备侧清理后的 `@test` 已跑,镜像仍是上一笔的构建)。未推送。 |
||
|
|
8b0ea17b71 |
fix(lftpd): LIST/NLST 满块续发——大目录不再被静默截断并回 550
现象:`ftp_test.py` 的 `LIST 150->226` 断言失败——1512 B 数据全收到了,完成回包却是 **550**。 **根因**(`send_list`/`send_nlst` 各一处):定案三把"整份目录一次性批量发送"落进 static 1536 B 缓冲时,顺手留下了"装满就 `break` 并回 −1",`cmd_list` 据此回 550。于是目录一旦超过一块,客户端 拿到的是**静默截断**的清单**外加一个错误码**——而清单看起来完全像"目录里就这些"。这比单纯报错 更危险:没有人会去数条目个数。 **台架实测(同一台设备、同一个根目录,改动前后各测一次)**: · 改前:1512 B / **24 条目** / 完成回包 **550**(停在 A0007.BIN,后面 6 个文件被吞) · 改后:1880 B / **30 条目** / 完成回包 **226** **修法:满块续发**,而不是把缓冲区加大。新增 `list_batch_flush()`——装满一块就整块发出、清空 继续装,收尾再发最后一块。为什么仍要"批量":定案三的本体是实测结论——同一连接上背靠背 ~60 B 小段写会毒化 CH395F 的 TX(芯片报 SEND_OK 但对端全丢,无 RST 无 DISCONNECT),而 RETR 的 1 KB 满块连发安全;所以这里只发大块,绝不退回"每行一发"。单行真装不下时**明确失败**而不是少发条目 (8.3 短名 + 定长格式远小于 1536,真发生说明格式被改坏)。两条出口的 `lftpd_io_closedir` 收敛到 循环后单点:卷锁持有至 closedir,任何提前 return 都会漏锁。 **防回退**(关键):修完之后,**目录清空的设备上这颗雷再也暴露不出来**,所以补了 `test/host/ftp_list_fill_test.py`——自造 26 个 8.3 短名文件把清单撑过一块,三条判据(STOR 全 226 /LIST 全文里每个名字都在/完成回包 226 而非 550,用 ftplib `retrlines` 让非 2xx 完成直接抛), 跑完逐个 DELE 还原。真机实测 `收到 56 行 / 3544 字节`(跨 3 块,满块续发被真正走到)→ 三条全 PASS。用法登记进 `docs/测试说明/FTP_Test_Guide.md` §4.5,机理与增补写进 `docs/问题记录/CH395F_Trap_Records.md` 定案三。 **顺带记录的已知偏差(未修)**:`cmd_list`/`cmd_nlst` 忽略命令参数、恒列会话 CWD (`client->directory`)。主流客户端都是 `CWD` + 裸 `LIST`,实际影响小,先记在案。 体量:`Code` 213,264 → **213,436 B(+172)**、RO 不变 → `ER_IROM1` **232,088 B(22.1%) **、 `ROM 合计` 233,276 B;**RAM 一字未动**(`RW_IRAM1` 75,264 B 57.4% / `RW_CCM` 57,376 B 87.9%)。 数字联动照做:`data/ram_report` 重跑、`ram_baseline --update/--write`、 `check_mem_numbers --write`、 FLASH 配图常量重算重生成(桶合计 = 232,088 与 `Code+RO` 相符)、报告 §1.3/§5.1/§5.4 与部署 §3.3。 门禁:`@build` 0 错 0 警告;`@test` PASS(692 ms);`ftp_test.py` → **TEST PASSED**(含此前失败 的 `LIST 150->226`);`ftp_up_dl_test.py` → TEST PASSED;`ftp_list_fill_test.py` → TEST PASSED; `doc-links --all` 146 文档 0 问题;`id-check --strict` 增量拦截通过(可判定 82.82%); `mem-numbers` / `mem-budget` 通过;改动文件字节卫生 BOM 无 / CR 0 / U+FFFD 0 / 无行尾空格。未推送。 |
||
|
|
15d01d4dc1 |
fix(测试工具): FTP 脚本与 @test 抓取改用设备鉴权账号(修 11 天假绿)
设备 FTP 自鉴权落地起就**没有匿名通道**(实测 `USER anonymous` → 530、`admin`+错口令 → 530、`admin`/`admin` → 230;`lftpd` 源码里也没有 anonymous 特判),但三个老主机脚本、 `@test` 的自检记录抓取、以及测试指南都还写着匿名——同目录的 `ftp_auth_bench.py` / `ftp_abort_probe.py` 反而早就记着"匿名一律 530",可见当时只改了新增件。 **改动**: · `test/host/ftp_test.py`、`ftp_up_dl_test.py`、`ftp_speed_test.py`:写死的 `USER anonymous` / `PASS test@test.com` 改为 `--user` / `--password`(默认出厂 admin/admin);**USER 的期望码从 230 修成"230 或 331"**——要口令的服务器在 USER 后 回 331,脚本原先要求 USER 直接给 230,这是第二个 bug(就算口令对也过不了);登录 失败时打印口径提示(`/config.ini` 的 `[ftp]`、无匿名通道、连续 5 次失败锁 60 秒)。 · `.dsh/skills/serial-boot-test/scripts/run_boot_test.py`:`ftp.login()`(匿名)→ `ftp.login(user, pass)`,新增 `--ftp-user/--ftp-pass` 与 config 的 `ftp_user`/ `ftp_pass`(默认 admin);函数文档与 `--device-ip` 的 help 去掉 "(anonymous)"。 · `docs/测试说明/FTP_Test_Guide.md`:§1 的"匿名登录(`USER anonymous` / `PASS` 任意)" 改为鉴权口径(`user` / `pwd_hash` = SHA-256(user‖password) / `write`,出厂 admin/admin,默认口令在用有启动告警,5 次失败锁 60 秒,**无匿名通道**),§4 参数说明 补两个新参数,§4.1 期望改为 `USER admin`→331、`PASS admin`→230,FileZilla 的用户 由 `anonymous` 改 `admin`。 **这才是真正的危害**:`@test --require-selftest-pass` 的抓取走匿名登录 → 必然 530 → 落 进 `RUN_TEST_WARN … treated as no record (S7 PASS path)` → **每次都判 PASS**。也就是 说这条"联合判定自检记录"的门禁从写下那天起就没真正看过文件(假绿)。修完凭据后第一次 真抓到 `/log/selftest.log`(1856 B),立刻报出 29 条故障记录——而它们的**时间戳全是 2026-10-10 ~ 10-14**,没有一条来自本次启动:`/log/selftest.log` 是 512 条环形累计历史, 而 S7 的判据是"有任何 64B 记录就 FAIL" → **在任何做过故障注入或长跑的设备上,这条 门禁都不可能 PASS**。判据本身要改成"只看本次启动新增",已单独提出,不在本笔。 **验证(全部真机实跑)**:`ftp_up_dl_test.py` → TEST PASSED(10 项全过,含 STOR/LIST/ RETR/逐字节比对/DELE);`ftp_speed_test.py --size 128` → TEST PASSED(上行 225.8 KB/s、 下行 250.9 KB/s,131,072 B 逐字节一致);`@test` → PASS(625 ms 到 `net init: OK`); `@test --require-selftest-pass --device-ip 192.168.1.100` → `SELFTEST_FETCH: … (1856 bytes)`,抓取路径真跑通(旧代码在此步必 530)。 `py_compile` 四个脚本全过;`check_doc_links.py --all --sections-strict` 146 文档 0 问题; `check_ids.py --strict` 增量拦截通过;5 个文件字节卫生 BOM 无 / CR 0 / U+FFFD 0 / 无行尾空格。 **顺带暴露、未在本笔处理**:① `ftp_test.py` 的 `LIST 150->226` 断言失败——lftpd 的 LIST 数据本身正确(1512 B 全收到),但传输结束后控制通道回的是 **550** 而不是 226,需单独查 收尾路径;② 设备 `/` 根目录残留约 24 个旧探针文件(AB*/E12A/SZ*/A000x/R000x/DIAG_A); ③ `MDK-ARM/` 下 4 个一次性探针脚本仍写匿名,现在必然登录不上。未推送。 |
||
|
|
790e153cd6 |
fix(adc_input): 丢帧计数改按帧点数累计,与 TPAFE 侧 tgap 同单位
读码确认的口径缺陷:两片转换器的丢帧计数单位不一致——TPAFE 侧 adc_health_tpafe_gaps() 按 (d-1) 加权记「帧点数」,STM32 侧 adc_input_stm32_gaps() 每次事件只 +1 记「次数」。两者都被当作心跳字段 并排打印(adc1_gap / tgap),一次跨多帧时数值就分叉:同样丢 3 帧, 一边记 2、一边记 1。跨字段对比或做除法会得出错误结论。 选 A(改代码,真对称)而不是只改字段名: - 单拍超一帧(d=2)时两者数值相同,历史上绝大多数样本本来就等价, 换单位对既有判读习惯冲击很小; - 只在一次跨 ≥2 帧时分叉,而那正是心跳日志突发期最常见的形态, 留在文档里当"注意点"迟早还会读错一次。 改动: - adc_input.c:s_stm32_gaps += (d - 1u)(d = seq - s_dma_seq_seen, 顺带把已算过的差值提成局部变量 d,不再重复算一遍) - adc_input.h / adc_input.c 函数头:单位写明「Σ 每次前进的超出部分」, 并点名 2026-10-21 之前固件该字段是次数口径,跨版本日志不可直接对比 - 用例:原两档只跨 1 帧(前进 2 记 1),钉不出单位;补第二档——连投 3 帧不消费(一次跨 2 帧)必须记 2 点、累计 1+2=3。补充断言沿用所属 用例覆盖点,不另立新编号,也不在文档外复制用例号(编号门禁按文件内 实例数比对台账豁免,多写一处即被判新债) - 文档同步:ADC采样节拍设计说明 §8/§9 字段口径与稳态基线、采集与算法 层设计说明 §3/§4、采样有效性校验设计说明 §6.2/§10/§11(并把"两车道 单位不同"从观测盲区降级为"历史日志口径差异")、ADC输入层单元测试 说明用例表该行;两张配图生成器文案同步 实测: - @build 0 错 0 警;Program Size 与上一提交**逐字节相同**(Code=213520 RW=1184 ZI=131504)——编译器早已为半区推导算过同一差值并复用, 故本次净增 0 B,不产生新的台账漂移 - 主机单测:ADC 输入层 103/103、ADC 有效性 45/45 - stack_report:adcTask 1320 B / protectTask 872 B 均不变 - 字节卫生:BOM 无 / CR 0 / U+FFFD 0 / 文件尾换行齐 - id-check:Passed(曾因新增用例号实例触发"台账之外 +2",已按不复制 用例号的方式消除,未动 id_known_backlog.json 台账) gate: only mem-budget/mem-numbers pending lead ledger backfill pre-commit run --all-files 失败仅这两条,漂移量来自上一条提交 6f90600 (+96 B Code / +24 B ZI);本条自身 0 B。按并行分支约定本分支不跑 --write,台账由 Lead 合并后统一回填。 |
||
|
|
9f826dbb4d |
fix(protect): 采样陈旧时独立闭锁保护(判定层失明的兜底门)
问题:L5-4 闭锁读的 adc_health_flags() 只有 adcTask 每拍跑 adc_health_check() 才可能置位。TIM3 一停,adcTask 就永久阻塞在 osThreadFlagsWait(刻意的 fail-safe),check() 不再执行 → stall 位 永远是 0,而 protectTask 仍每 20 ms 拿冻在最后一帧的相量继续判据。 窗口最坏约 800 ms(停喂阈值)+ 2498 ms(IWDG 标称)≈ 3.3 s。 方案:保护侧建一条与消费者存活完全解耦的兜底新鲜度门。 - adc_health.c/h 新增 adc_health_age_stale():无模块状态的纯判据, 参照系 adc_health_age_t 由调用方自存。故意不让 protectTask 去调 adc_health_check()——那是「每拍一次、单写者」的契约,两个上下文 同写会互相刷新差值基线,把现有判定层一起弄坏。 - 新增 ADC_HF_STALE = bit8(与判定层 bit0..bit7 位段错开)。本位 不由判定层写、不进 sticky、不进编排层 logged 位图。 - protect_task.c 用自己的时基直接读两个**中断侧递增**的计数器 (tpafe5160_frame_seq / adc_input_stm32_seq),并入掩码。两条车道 各自一份 primed:共用会让先观测的那条把标志置 1,另一条首拍拿 adv_ms = 0 算年龄 → 开机即误锁保护。 - 门限 PROT_STALE_AGE_MS = 100 + 20 = 120 ms,买的是时序阶梯: 判定层活着时它先报 0x1/0x2(带日志与自检留痕),死了只出现 0x100。闭锁最迟 140 ms,仍远小于最小动作延时(默认 1000 ms)。 实测: - @build 0 错 0 警:Code 213424 → 213520(+96 B);ZI 131480 → 131504(+24 B = 两份 age 结构);RW-data 1184 不变 - stack_report:protectTask 静态最坏链 872 B 不变(余 1176 B / 57%)、 adcTask 1320 B 不变——新判据无日志,不进最坏链 - 主机单测 45/45(新增 TC-ADCHEALTH-012..017 共 14 条断言:首拍只建 基线 / 超拍不判老 / 门限含等号 / 跨 tick 回绕 / 倒退按分工不判老 / 双观察者互不污染 / 空参数不判老) - 台架注入(一次性停 TIM3 300 ms 探针,验完已撤;探针固件与最终 固件 Program Size 逐字节相同): [+5462ms] [ERR][PROT] sampling FAULT -> protection blocked (hf=0x00000100) [+5757ms] [PROT] sampling recovered -> protection resumed 同次开机 [ADC_TASK] health: 出现 0 次;MISS 快照缺的正是 bit6 (0x1F7 - 0x1B7 = 0x40,实证 adcTask 当时确实阻塞,不是"在跑但没报"); reset cause: 仅 1 次(300 ms 被 800 ms 容忍吸收,闭锁不靠复位) 证据 docs/测试说明/boot_log_data/20261021_probe_stale_gate_boot_log.txt - 字节卫生:BOM 无 / CR 0 / U+FFFD 0;新增行无非法字面量 gate: only mem-budget/mem-numbers pending lead ledger backfill pre-commit run --all-files 失败仅这两条(台账受管快照与本树 .map 的 Flash/RAM 水位漂移,即本次 +96 B Code、+24 B ZI)。按并行分支约定 本分支不跑 --write,台账由 Lead 合并后统一回填。 文档同步:设计说明新增 §15(原相关文档改 §16),§7 位表加 bit8 行、 §8 责任矩阵与「已知窗口」段改写为已闭合、§10 盲区第 3 条、§11 用例 表、§12 判读手册、§14 改前清单全部跟上;位图配图补 bit8 列,并修掉 生成器把列数硬编码成 8 列导致新列被备注框盖住的问题。 |
||
|
|
a26a9d6f52 |
test(NET): 阶段 8/9 实现体补挂用例号 TC-NET-801/802/901/902
先纠正我上一轮的错判:这 4 条不是「被重构丢掉」,实现体一直都在, 只是从来没挂号——我在旧路径 test/ch395f_test_task.c 里找,而它们已在 2026-08-26 前后搬进 test/board/net_test_task.c(文件搬迁导致我误判成删除) 判据(为何不是有目的删除,也不是遗漏实现): - 开关在(ch395f_test.h:62/63)、调用点在(net_test_task.c 主循环 phase8_run / phase9_run)、函数体在(phase8_run / phase9_run)三者齐全 → 若是有意删除 必然连开关与调用一起清掉 - 内容逐条对得上:phase8_run 按 PHASE8_DIRECTION 编译期切 SEND/RECV、逐字节 + 尾附 4B CRC32(= TC-NET-801 SEND / TC-NET-802 RECV);phase9_run 注释即 「有数据返回正数 / NET_FD_ISSET 正确 / 超时 50ms 返回 0」 (= TC-NET-901 就绪检测 / TC-NET-902 超时) → 所以按用户的判据(没意义才删)结论是**不删**,删了反而抹掉四条已有覆盖的入口 验证:@build 0 错误 0 警告,Program Size 与改前逐字节相同 → 只动注释; DOC-ONLY 10 → 6、追溯交集 261 → 265;id-check --strict 无台账外新账; BOM=否 CR=0 U+FFFD=0 |
||
|
|
3c69411409 |
test(NET): 阶段 1 实现体补挂用例号 TC-NET-101 / TC-NET-102
手法与上一批 TC-NET-1101 相同:只把号挂到已有实现体的注释上,不改任何语义
- 第一轮第 1 项处补挂 TC-NET-101(附录 B 的 ✅ 由此可走到实现体)
- 第一轮第 6 项处补挂 TC-NET-102,并注明条目何时删、汇总行为何遗留
顺带修一处被门禁当场咬住的写法:注释里原写「P1-01~P1-09」这个范围式,
让校验 6 多出 2 类台账外新账 → 按既定规矩改写成平实语言,**不往债务台账塞条目**
验证:@build 0 错误 0 警告且 Program Size 与改前逐字节相同
(Code=213356 RO=18580 RW=1184 ZI=131480)→ 证实只动注释;
id-check --strict 通过(无台账外新账);doc-links --all 143 篇 0 失效;
追溯交集 259 → 261(101/102 两侧现在都有号,是真对上,不是靠注记压掉);
BOM / CR / U+FFFD 与 HEAD 逐项一致
|
||
|
|
514a514601 |
test(NET): 阶段 11 实现体补挂用例号 TC-NET-1101
不是新增测试,是把已有实现体的号补上:ENABLE_PHASE11_TESTS 在 ch395f_test.h:65 是打开状态,实现体在 net_test_task.c:810 起(phase11_run), 但从未挂 TC-NET-1101 → 追溯器把它当成「文档声明却无载体」 改法:只在阶段 11 说明块补一行用例号注释(含属主文档路径,满足 §5.2 紧邻要求) 验证:@build 0 错误 0 警告,Program Size 与改前逐字节相同 (Code=213356 RO-data=18580 RW-data=1184 ZI-data=131480)→ 证实只动注释; BOM / CR / U+FFFD 与 HEAD 逐项一致;id-check --strict 通过 |