Files
super_agent_bot 72b4b0943c docs: clear task and layer shorthand IDs
Replace task/batch shorthand IDs and residual layer labels in
human-facing docs with semantic phrases. Add the new cleanup
policy to docs/编号规范.md and update the entry docs.

Machine keys (TC/CODE-RULE/MENU-STATE/TRAP/FR), hardware
designators/pins/MAC, protocol/version numbers and frozen
historical evidence are intentionally kept.

Docs only; no code behavior change. Verified with
check_doc_links.py --all and git diff --check.
2026-11-02 03:33:51 +08:00

119 lines
9.3 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# App/log/ — 日志子系统
> 两类日志:**持久化运行日志**(`sys_log`,落 NAND)与**控制台日志**(`console_log`,走串口)。
> 两者都遵循**单写者**模型,避免多任务交错输出。
## 文件一览
| 文件 | 作用 |
|---|---|
| `sys_log.h` | **日志接口(平台无关)**:定长 64B 记录,七类各一个 `/log` 文件(run / selftest / accid / alarm / start / oper / yk)|
| `sys_log_mcu.c` | `sys_log` 的 MCU 端后端实现(NAND + FatFs) |
| `console_log.c/h` | **控制台单写者日志**:多任务日志经队列汇入唯一写者,避免串口输出交错 |
| `soe_rec.c/h` | **SOE 记录纯编解码**:64B 定长记录(CP56Time2a 时标 + 类型 + 元件号 + 单调序号 + 值 + sum8 撕裂校验),零 I/O 零 OS 依赖,主机单测覆盖 |
| `soe_store.c/h` | **SOE 落盘胶水**:`/log/soe.log`,protectTask 投递(零文件系统)→ defaultTask 排空落盘 |
## 关键机制
### syslog(运行/自检记录)
- **唯一写者 = defaultTask**;其它任务只投递,不直接写盘
- **单记录定长 64 B**,循环写;待机页可显示记录
- **内核启动前的日志**走**无锁静态缓冲** `s_preboot[8]` 暂存(因为内核启动前不能建队列),
内核启动后由 `syslog_drain` 惰性创建真队列并排空
- ⚠️ 写盘必须校验 `f_write` 返回的**字节数**(该 FatFs 移植在簇分配失败时返回 `FR_OK` + 短写,
不报错误码);追加写必须 `FA_WRITE|FA_OPEN_APPEND`(`FA_OPEN_APPEND` 单独用**不含写位**)
- **清除记录 = 请求 / 落地分离**:非写者上下文(uiTask 等)只能 `syslog_request_clear(id)`
置一个标志(零盘触点、零卷锁),真正的 `f_unlink` 在 **defaultTask** 的 `syslog_drain()`
**尾部**执行——顺序也是判据的一部分:排在条目排空之后,否则本轮刚排空的旧记录会被
写回去、`syslog_count()` 不归零。结果读 `syslog_clear_state(id)`
(`NONE/OK/WAIT/FAIL`),事实复核读 `syslog_count()`。
落地函数 `syslog_clear_apply(id)` 是 MCU 后端专属(模拟器不实现 → 共享代码误调在
链接期就报错):卷锁一律 try,卷占用返 -1 且**不动原文件**;幂等只认 `FR_NO_FILE`,
`FR_NO_PATH` 如实返 -1 且**不做任何卷级动作**(不补目录、不重格式化)
- 删除的作用域 = 上表七个记录文件(`syslog_request_clear(id)` 逐 id 独立请求);取证文件
`wdev.log` 与 `soe.log` 各有各的属主与通道,不在本 API 作用域,想清它们要另开 API。
清除成功会往**操作记录**里落一条 `clear <文件>`——但清 `oper.log` 自己时**刻意不投**,
否则"我清除了记录"这条会把刚删空的文件又写成 1 条,直接砸掉「删除后 `syslog_count()`
归零」这条判据(`TC-SYSLOG-133b` 钉住)
- ⚠ 宿主后端(`simulator/sim/sim_syslog.c`)与 MCU 端**判据相同、时序不同**:模拟器单线程,
七类对应工作目录下七份宿主文件(`sim_accid.log` 等),`syslog_post_quiet()` 在本端
等价于 `syslog_post()`(宿主进程没有那条栈硬线,也没有队列与丢弃);
`syslog_request_clear()` 调用内就删完了,因此 `WAIT` 态在模拟器上永不出现
(同 `syslog_post` 在两端"有队列 / 直写无队列"的差异)
### 五类记录与「记录类型 = 日志 ID」(道F task-10,2026-10-26;task-11 记录 5 页按此做,2026-10-28 五页已落地)
**决策一:记录类型就是 `syslog_id_t` 本身,一类记录 = `/log` 下一个严格 8.3 短名的文件。**
64B 定长记录体里**没有类型字段位**:`[0..18]` 时标 / `[19]` 空格 / `[20..29]` epoch /
`[30]` 空格 / `[31..58]` 描述 / 尾部补零,这个布局被 UI 记录页与主机解码工具按**固定偏移**
读了了很久(run.log / selftest.log 是既有文件,既有读者)。塞类型字节要么挪走 epoch
(上电/重启分类就断),要么挪走描述(屏上少字),且两端读者同批改——所以
"这条记录是什么类型"由**它在哪个文件里**回答。`TC-SYSLOG-136` 把这条钉成机器断言:
同一条内容在七类之间逐字节相同,记录体不编码类型。
**决策二:不动 `soe_type_t`(二进制 SOE 通道保持现有 8 型)。** 加 SOE 类型必须同步 UI 侧
`ui_w_soe.c` 的类型名表(那是另一位队友的写域),而 SOE 页与这五页本就是两套读者
(二进制解码器 vs 文本列表)。**别把新类型顺手加进 SOE**:那会同时造出
"同一个事件两个真源"。
| 记录 | 日志 ID / 文件 | 容量上限 | 写入点 | 触发判据 |
|---|---|---|---|---|
| 事故 | `SYSLOG_ACCIDENT` / `accid.log` | 512 | `App/task/protect_task.c:188` | `asserted` 上升沿**且**该元件跳闸投退项 = 1 |
| 保护告警 | `SYSLOG_ALARM` / `alarm.log` | 1024 | 同文件 `191` | `asserted` 上升沿**且**跳闸投退项 = 0 或该元件无此项 |
| 保护启动 | `SYSLOG_START` / `start.log` | 1024 | 同文件 `183` | `picked` 上升沿(越限电平,早于/等于动作) |
| 操作 | `SYSLOG_OPER` / `oper.log` | 512 | `App/protocol/iec104/iec104_pts.c:582/610`、`App/task/default_task.c:266`、`App/log/sys_log_mcu.c:682`(宿主 `sim_syslog.c:245`) | 强制复归受理 / 软压板投退落地 / 定值**真落盘成功** / 清除记录成功 |
| 遥控 | `SYSLOG_YK` / `yk.log` | 256 | `App/protocol/iec104/iec104_pts.c:581/584/590/594/604/606/617` | 104 双点命令的选择段、执行段、非法 DPC、未知 IOA 各一条 |
- **"哪些元件算跳闸"只有一个真源**:定值表 `g_prot_set_meta` 里的 `PS_*_TRIP`(枚举注释
即"0 告警 / 1 跳闸")+ 实例表 `k_pe[]` 的 `trip_ctl` 列。分类入口
`prot_elm_record_kind()`(`App/algo/prot_elm.c`)里**没有第二份元件名单**,
没有该投退项的五项(OV/UV/3U0/OF/UF)填 `PROT_ELM_NO_TRIP=0xFF` → 恒告警;
`TC-PROTELEM-015` 逐元钉住"逐项独立 / 改定值即改类别 / 无此项者不受别人定值影响"。
- **描述只用 ROM 常量或 `prot_elm_name()` 直传**:所有写入点零 `snprintf`、零拼接。
最长一条 20 字节 < `SYSLOG_DESC_MAX`(28);`TC-IEC104-030` 逐条量长度(超 28 会被
投递侧静默截断,屏上少几个字,没人会去数)。
- ⚠️ **两个投递口,按调用者的栈预算选**:`syslog_post()` 的两个"满态丢弃留痕"分支
内联着日志行缓冲(每处约 216 B 栈),因此 `syslog_post_quiet()` 给静态最坏链吃紧的
任务用(**protectTask、iec104Task 必须用它**),丢弃只累加 `syslog_post_dropped()`、
由唯一写者 defaultTask 在 `syslog_drain()` 里按差值补一条留痕——同 `soe_store_post`
当年那条 `872 → 1192 B FAIL` 的实证纪律。收/丢判据两个口完全一致。
- **读侧契约(给 task-11;2026-10-28 五页已按此接上)**:`syslog_count(id)` + `syslog_get_record(id, idx, ts, ts_len,
desc, desc_len)` 与运行/自检记录**同一枚 reader**,"最近 20 条"= 从 `count-20` 起读;
`count()==0` 就是空态,页面显示"无记录"。**不要**在共享代码里调 MCU 专属的
`syslog_clear_apply()`(模拟器不实现 → 链接期报错是故意的);清除一律走
`syslog_request_clear()` + `syslog_clear_state()`,并把 `WAIT` 当正常态看(模拟器端
永不出现 `WAIT`,见下条)。
### console_log(控制台单写者)
- 多任务的生产者 → **单写者消费者**,消除任务间日志行交错
- 设计详见 `docs/子系统设计/控制台单写者日志设计说明.md`
### soe(SOE 事件顺序记录,SOE 记录)
- **记录 = 64 B 定长二进制**(`soe_rec.h` 布局),落 `/log/soe.log`;
与 run.log 分文件——run.log 是文本记录、有 UI/主机读取方,二进制 SOE
混入会破坏读取器;分文件保持"定长 64B + 条数=fsize/64 + 满删重建 +
FTP 下载 + 主机解码"同一套先例
- **生产者 = protectTask**(元件动作/返回、软压板投退、采样闭锁/恢复六类
边沿):`soe_store_post()` 纯 RAM(取时标 + 组记录 + 队列/待发环),
**零 NAND I/O**;⚠️ **post 内禁 `DBG_*`**——会把 protectTask 静态最坏链
垫高一帧(实证 872→1192 B FAIL),丢弃留痕由 drain(defaultTask)差值上报
- **唯一写者 = defaultTask**:挂 `syslog_drain()` 尾部(继承其卷就绪门),
50 ms 节拍 → SOE 落盘延迟 ≤50 ms;写盘纪律全套照 syslog(卷锁 try /
`FA_WRITE|FA_OPEN_APPEND` / 校验字节数 / 满删重建 / 失败留痕去重),
**绝不把名字/参数类错误码归入卷损坏触发集**
- **时标口径**:sys_clock 秒域时基 → CP56 ms 域 = 秒×1000(亚秒恒 0,
不造假);墙钟未建 → IV 位如实置位;seq 仅上电生命周期内单调
(容量重建不重置,仅复位重置——主机解码按 boot 段分段断言)
- 主机侧:`test/host/soe/decode_soe.py` 解码 + 断言(校验和/seq 单调/
CP56↔epoch UTC 交叉);⚠️ 交叉校验用 `calendar.timegm`,不是本地时区的
`dt.timestamp()`(+08 机差 28800 s,首跑实证坑)
## 相关文档
- `docs/子系统设计/控制台单写者日志设计说明.md`
- `docs/子系统设计/运行与自检记录设计说明.md`
- FatFs 陷阱:`AGENTS.md`「平台约束」