77779d49d6
UI 面:ui_data 增加深度 4 参数写队列(请求 168 B、队列 .bss 672 B)与状态机 OK/ERR_RANGE/ERR_LOCKED/ERR_BUSY,ui_data_feed 出队后按注入 ops 走「闭锁 → 整批 预检 → 逐项 prot_set_set_sealed」,只提交改动位图;par 帧尾追加 cal_block (口径 = UA/UN/IA 三路 ADC_CAL_F_VALID,与 protect_task 判据同构,不用 rt.eng 反推,V0.1 下 eng 恒 0)、UI_DATA_VER 升到 2。参数/定值/控制字/软压板四叶绑定 内容页(UI_PAGE_MAP_COUNT 12→16,复用四个查看模块,零新增 .c),编辑态按 is_editable 分派,LOCK(写不进去)与「未标定」(仍可改值)两源两通道两词。 记录面:syslog_request_clear/state/apply 三段式删除 API(UI 只发请求,落地在 defaultTask 的 drain 尾部且必须后置,卷锁一律 try,幂等只认 FR_NO_FILE); 事故/告警/启动/操作/遥控五类各有一个真实写入点,记录类型 = 日志 ID 本身 (一类一个 /log 严格 8.3 文件;64B 定长体没有类型字段位,塞字段会砸掉既有读者)。 为守 protectTask 872 B 静态最坏链另拆 syslog_post_quiet()(无 DBG 的投递核, 丢弃留痕挪到 drain 侧差值补发),syslog_post 对外语义逐字不变。 为什么两道合成一笔而不是各一笔(实测,不是省事):simulator/main.c 同时消费 两道新增 API(整定 pump 与 logtest 清除用例),按道切文件会让中间提交编不过; RAM 受管快照与体积同码凭证描述的是合并后的 .map,拆开必落在「台账与 .map 不同 码」这条红线上。pre-commit 跑钩子前会 stash 未 staged 部分,这类耦合没法绕。 实测:@build 0 错误 0 警告;Code 228,260 / RO 24,960 / RW 1,440 / ZI 135,976 B; RW_IRAM1 79,992 B = 61.0%、RW_CCM 87.9%(阈值 92%);九个任务静态最坏链全 PASS, protectTask 872 B / 57% 改前后逐字节不变(记录投递没垫栈)。主机单测 ui_data 82→ 164、sys_log_mcu 106→137、prot_elm 47→60、iec104 141→154、iec104_serv 28→34, 既有断言零删改;48 个钩子 --all-files 全绿;编号门禁可判定 86.34%(基线 86.0%)、 不可判定 1,153 处低于上限 1,166;doc-links 无法判定 0;UI 黄金 18 页扩到 27 页 连跑两次逐字节一致;字库 diff 空。 顺手修掉三处既有缺陷(都是本轮第一个消费者才暴露):sim_syslog.c 的 s_paths 行宽 16 而 "sim_selftest.log" 正好 16 字符没有 NUL 位(stat/remove 读越过数组尾,此前 靠后面 .rodata 碰巧为 0);ui_w_setlist 二态行 ENTER 不回绕(控制字与软压板出厂值 全在最后一项,按了像没反应而叠层里已是越界值);生成物 ui_menu_tab.h 与 gen_menu.py 模板漂移(上一笔改了模板没重跑生成器),现随生成器输出对齐。 未收口(不算完成):保存后重启值保持与主站 C_RD 读回两条只能上板,台架窗口执行; LOCK 屏显与越界反显的页面侧在模拟器造不出来(模拟器不跑定值自检、无 NAND), 已由生成侧单测与代码注释点名差距;同类页数与钩子数陈述残留另立待办。
311 lines
19 KiB
C
311 lines
19 KiB
C
/*
|
||
* 模块名称:System Log — 运行/自检记录引擎(双端共享核心)
|
||
* 模块功能:定长 64B 文本日志记录的公共 API、格式常量与行拆分;
|
||
* MCU 后端 = FatFS /log 目录日志文件(sys_log_mcu.c),模拟器后端 = 宿主文件(sim_syslog.c)
|
||
* 适用平台:STM32F407ZGTx + PC 模拟器(共享头,无 OS/LVGL 依赖)
|
||
* 作者:王建锋
|
||
* 创建日期:2026-09-14
|
||
* 修改记录:
|
||
* v1.0 2026-09-14 王建锋 创建初始版本(设计见 docs/子系统设计/运行与自检记录设计说明.md §4)
|
||
* v1.2 2026-10-26 王建锋 新增「记录删除」API(UI 装置维护「清除记录」的前置,
|
||
* 道F task-4;判据 docs/任务规划/UI补齐.md §2 第 3 行
|
||
* 「不允许只做一个没有实际效果的按钮」):
|
||
* 共享层 syslog_request_clear() / syslog_clear_state()
|
||
* (双端都实现,UI 侧只准用这两个)+ MCU 后端专属
|
||
* syslog_clear_apply()(落地半边,仅 defaultTask)。
|
||
* 请求与落地分离的理由与执行点写在下面声明处
|
||
* v1.1 2026-10-24 王建锋 仅契约注释更正,与 App/log/sys_log_mcu.c 的 C/F 两项
|
||
* 整改同步(无签名、无行为改动):
|
||
* syslog_get_record 写死容量要求(ts_len > SYSLOG_TS_LEN、
|
||
* desc_len > SYSLOG_DESC_MAX)并明确"容量不足一律 -1、
|
||
* 不截断、不写调用方缓冲"——旧注释像是"给少了会被截断",
|
||
* 实际是整条读不到;syslog_post 写明必须假设丢弃存在、
|
||
* 且丢弃留痕已按通道节流(节流后无丢弃计数)
|
||
*/
|
||
|
||
#ifndef SYS_LOG_H
|
||
#define SYS_LOG_H
|
||
|
||
#ifdef __cplusplus
|
||
extern "C" {
|
||
#endif
|
||
|
||
#include <stdint.h>
|
||
#include <stddef.h>
|
||
|
||
/*
|
||
* 日志 ID:决定落盘文件与容量上限
|
||
*
|
||
* ⚠ **记录类型 = 日志 ID 本身**(一类记录 = /log 下一个严格 8.3 短名的文件),
|
||
* 记录体内**没有**类型字段位(Lead 裁定 2026-10-26,task-10):64B 定长格式被
|
||
* UI 记录页(文本读者)与主机解码工具同时按固定偏移读,塞类型字节等于当场砸掉
|
||
* 这两批既有读者;而运行/自检记录已经在这份格式里跑了很久,不能为五类新记录
|
||
* 改版本位。于是"这条记录是什么类型"由它在哪个文件里回答。
|
||
* 同理二进制 SOE 通道的 soe_type_t 本轮**不动**:改它必须同步 UI 侧的类型名表
|
||
* (类型名表在 UI 侧 <Drivers/BSP/UI/ui_w_soe.c>,不在本道写域),而且 SOE
|
||
* 页与这五页是两套读者。
|
||
* 口径与五个写入点已登记进 App/log/README.md(task-11「记录 5 页」按此做)。
|
||
*/
|
||
typedef enum {
|
||
SYSLOG_RUN = 0u, /* 运行记录 /log/run.log:上电/重启事件 */
|
||
SYSLOG_SELFTEST, /* 自检记录 /log/selftest.log:开机自检故障(仅故障才写) */
|
||
/* ↓ 五类记录(docs/UI设计/页面扩充详细方案.md §3.6 的五行,task-10 落写入点)
|
||
* ⚠ 只准**尾部追加**:id 值即枚举序 = 两端 s_paths[]/s_caps[] 的下标,
|
||
* 中间插值会让老文件被新 id 读成别的类型(静默错类别,比崩更难查)。 */
|
||
SYSLOG_ACCIDENT, /* 事故记录 /log/accid.log:跳闸投退=1 的元件动作 */
|
||
SYSLOG_ALARM, /* 保护告警 /log/alarm.log:跳闸投退=0 或该项不存在的元件动作 */
|
||
SYSLOG_START, /* 保护启动 /log/start.log:元件 picked 上升沿 */
|
||
SYSLOG_OPER, /* 操作记录 /log/oper.log:强制复归 / 清除记录 / 对时 / 定值保存 */
|
||
SYSLOG_YK, /* 遥控记录 /log/yk.log:104 遥控的选择 / 执行 / 拒绝 */
|
||
SYSLOG_COUNT /* 哨兵值,非有效 ID */
|
||
} syslog_id_t;
|
||
|
||
/*
|
||
* 记录格式(定长 64B,一行一条;设计文档 §4.2):
|
||
* [0..18] "YYYY-MM-DD HH:MM:SS"(ISO 8601 空格变体,19 字符;墙钟无效 = "1970-01-01 08:00:00")
|
||
* [19] ' '
|
||
* [20..29] epoch 秒 ASCII "%010u"(机器解析/上电重启分类用;墙钟无效 = "0000000000")
|
||
* [30] ' '
|
||
* [31..58] 描述 UTF-8(≤28B = 9 汉字),不足补 '\0'
|
||
* [59..63] '\0' 填充
|
||
*/
|
||
#define SYSLOG_REC_SIZE 64u /* 单条记录字节数(定长) */
|
||
#define SYSLOG_TS_LEN 19u /* 时间戳字段长度 "YYYY-MM-DD HH:MM:SS" */
|
||
#define SYSLOG_EPOCH_OFFS 20u /* epoch ASCII 字段偏移 */
|
||
#define SYSLOG_EPOCH_LEN 10u /* epoch ASCII 字段长度(2026 年 Unix 秒 = 10 位) */
|
||
#define SYSLOG_DESC_OFFS 31u /* 描述字段偏移 */
|
||
#define SYSLOG_DESC_MAX 28u /* 描述最大字节数(受框架行缓冲 CP_ROW_BUF_LEN=32 约束) */
|
||
|
||
/*
|
||
* 容量上限(条数;满时删除重建,设计文档 §4.3)
|
||
*
|
||
* ⚠ **上限是逻辑上限,不是预分配**:文件按追加写自然增长,一条不写就不占簇;
|
||
* 到顶才 unlink 重建(照 run.log 先例)。七类全满的名义峰值 =
|
||
* (1024+512+512+1024+1024+512+256) × 64B = **304 KB**,NAND 2 GB、且这些
|
||
* 记录只在事件边沿才写(判据动作/遥控/人工操作),不构成容量或磨损瓶颈。
|
||
* 告警/启动给到 1024 是因为一次系统故障会连片触发多个元件,别让最想了解
|
||
* 故障过程的两类记录最先被截掉。
|
||
*/
|
||
#define SYSLOG_RUN_MAX 1024u /* /log/run.log:64KB */
|
||
#define SYSLOG_SELFTEST_MAX 512u /* /log/selftest.log:32KB */
|
||
#define SYSLOG_ACCIDENT_MAX 512u /* /log/accid.log:32KB(跳闸稀有,换长历史) */
|
||
#define SYSLOG_ALARM_MAX 1024u /* /log/alarm.log:64KB */
|
||
#define SYSLOG_START_MAX 1024u /* /log/start.log:64KB */
|
||
#define SYSLOG_OPER_MAX 512u /* /log/oper.log:32KB */
|
||
#define SYSLOG_YK_MAX 256u /* /log/yk.log:16KB(低频,与事故同稀有) */
|
||
|
||
/*
|
||
* 上电/重启分类窗口(秒):run.log 末条 epoch 距 now < 该值 → "reboot",否则 "power on"
|
||
*/
|
||
#define SYSLOG_REBOOT_WINDOW_S 600u
|
||
|
||
/*
|
||
* 函数功能:投递一条日志(任意上下文;非阻塞,队列满则丢弃)
|
||
* 入口参数:id - 日志 ID syslog_id_t
|
||
* desc - 描述串(UTF-8;超过 SYSLOG_DESC_MAX 的部分丢弃,落盘只留前 28 字节)
|
||
* 本参数**投递时即拷贝进待发条目**:调用方缓冲区可立即复用,
|
||
* 不要求生命周期覆盖到落盘(2026-10-24 台架实证后由「只存指针」
|
||
* 改为条目内嵌定长缓冲,理由见 sys_log_mcu.c 的 syslog_entry_t 注释)
|
||
* 指针本身不可为 NULL const char *
|
||
* 返回值:无
|
||
* 限定条件:MCU 端 FreeRTOS 启动前调用走静态待发数组(由 defaultTask 挂载后落盘)
|
||
* 函数说明:调用方**必须假设投递可能被丢弃**——MCU 后端(sys_log_mcu.c)队列 8 槽、
|
||
* 启动前待发数组 8 槽,卷被 ftpTask 长期占用时 defaultTask 会把整批回投
|
||
* 队列(队列因此可长时间处于满态),此时本函数直接丢弃该条,并只在
|
||
* "转入故障"的那一次留痕(丢弃留痕按正常→故障节流,F 项整改 2026-10-24;
|
||
* 节流后**丢弃总数没有计数**,要计量得另加计数器)。必须留住的证据走
|
||
* sys_log_evidence(),不要靠 syslog_post 重试。
|
||
* 模拟器后端(simulator/sim/sim_syslog.c)是单线程直写宿主文件、**没有
|
||
* 队列与丢弃**,因此上面这段满态语义只约束 MCU 端。
|
||
*/
|
||
void syslog_post(syslog_id_t id, const char *desc);
|
||
|
||
/*
|
||
* 函数功能:投递一条日志——**调用链上不带日志行缓冲**的那一个版本
|
||
* 入口参数:id - 日志 ID syslog_id_t
|
||
* desc - 描述串(NUL 结尾;超过 SYSLOG_DESC_MAX 截断),同 syslog_post
|
||
* 返回值:无
|
||
* 限定条件:任意上下文;MCU 端不碰 FatFs、不碰卷锁、不阻塞
|
||
* 函数说明:为什么要有第二个投递口(不是洁癖):每个 DBG_* 调用点在调用者栈上
|
||
* 内联约 216 B 行缓冲,而 syslog_post 的两个"满态丢弃留痕"分支就躺在
|
||
* 它自己的帧里——于是"调一次 post"在静态最坏链上等于"带上这两处缓冲"。
|
||
* protectTask 的静态最坏链是 B9 写进 DoD 的硬线(872 B / 57%,当年在
|
||
* post 里加一条 DBG_* 实测垫到 1192 B = stack_report FAIL),iec104Task
|
||
* 同样是深链任务,所以这五类记录的写入点一律走本函数。
|
||
* 代价是丢弃时不当场留痕:只累加 syslog_post_dropped(),由唯一写者
|
||
* defaultTask 在 syslog_drain() 里按差值补一条(照 soe_store 的先例)。
|
||
* 与 syslog_post 的差别**只有留痕路径**,收/丢的判据逐条相同。
|
||
* 模拟器后端没有队列也没有栈预算问题,本函数等价于 syslog_post。
|
||
*/
|
||
void syslog_post_quiet(syslog_id_t id, const char *desc);
|
||
|
||
/*
|
||
* 函数功能:取 syslog_post_quiet() 通道的累计丢弃条数(可观测性)
|
||
* 入口参数:无
|
||
* 返回值:MCU 端 = 队列满 / 启动前数组满累计次数;模拟器端恒 0(直写不丢) uint32_t
|
||
* 函数说明:与 soe_store_dropped() 同款定位。留痕由 drain 按差值上报,本函数是
|
||
* 给单测与台架读数用的,不参与任何判定路径。
|
||
*/
|
||
uint32_t syslog_post_dropped(void);
|
||
|
||
/*
|
||
* 函数功能:获取记录条数(= filesize / SYSLOG_REC_SIZE,O(1))
|
||
* 入口参数:id - 日志 ID syslog_id_t
|
||
* 返回值:条数;文件缺失/未挂载返回 0 uint32_t
|
||
*/
|
||
uint32_t syslog_count(syslog_id_t id);
|
||
|
||
/*
|
||
* 函数功能:读取第 idx 条记录(时间戳 + 描述,均 NUL 结尾)
|
||
* 入口参数:id - 日志 ID syslog_id_t
|
||
* idx - 记录序号(0 起) uint32_t
|
||
* p_ts - 时间戳输出缓冲(不可为 NULL) char *
|
||
* ts_len- p_ts 容量,必须 > SYSLOG_TS_LEN(即 ≥ SYSLOG_TS_LEN+1 = 20 字节) size_t
|
||
* p_desc- 描述输出缓冲(不可为 NULL) char *
|
||
* desc_len - p_desc 容量,必须 > SYSLOG_DESC_MAX(即 ≥ 29 字节) size_t
|
||
* 返回值:0 - 成功;-1 - 越界 / 读失败 / **缓冲容量不足** int
|
||
* 限定条件:容量不足一律返回 -1,**不做静默截断、也不写调用方一个字节**
|
||
* (C 项整改 2026-10-24;旧注释只写"≥…+1 字节"像是"给少了会被截断",
|
||
* 照它给 28 字节缓冲的结果是整条读不到而不是读到 27 字符)。
|
||
* 描述字段在写入侧已截到 SYSLOG_DESC_MAX,所以按上面的最小容量给缓冲
|
||
* 就一定装得下,读侧不需要第二道截断。
|
||
* MCU 后端与模拟器后端(sim_syslog.c)在这条守卫上取值相同,行为一致;
|
||
* 模拟器侧那份同样不可达的截断支还留在文件里(未列入本轮改动范围)。
|
||
* 调用方:uiTask 的日志页(行缓冲 32B)与 SYSLOG 取证打印。
|
||
*/
|
||
int syslog_get_record(syslog_id_t id, uint32_t idx, char *p_ts, size_t ts_len, char *p_desc, size_t desc_len);
|
||
|
||
/*
|
||
* 函数功能:读取末条记录的 epoch 秒(上电/重启分类用)
|
||
* 入口参数:id - 日志 ID syslog_id_t
|
||
* p_epoch- 输出缓冲(不可为 NULL;无记录时置 0) uint32_t *
|
||
* 返回值:0 - 成功读到末条;-1 - 文件缺失/空 int
|
||
*/
|
||
int syslog_last_epoch(syslog_id_t id, uint32_t *p_epoch);
|
||
|
||
/*
|
||
* 记录删除(「清除记录」):请求 → 落地分离
|
||
*
|
||
* 为什么必须分两步:defaultTask 是本模块**唯一写者**(存储架构说明 §10.1 第 7 条),
|
||
* uiTask 直接 f_unlink 会与写者的追加写/「容量满 unlink 重建」交错,而且删除要走
|
||
* 卷锁 + FAT 回写——uiTask 在 IWDG required_mask 内、每 100 ms 喂一次心跳,
|
||
* 给它一条最坏数百 ms 的存储路径就是拿误复位当代价。故 UI 侧只登记请求,
|
||
* 真正的删除在 defaultTask 的 syslog_drain() 尾部执行
|
||
* (范式同 App/algo/prot_elm.c 的 prot_elm_request_reset():单字节标志 + 消费者落地)。
|
||
*
|
||
* 状态码(syslog_clear_state 返回值;写成宏而不是枚举,与本头既有 SYSLOG_* 常量同族)
|
||
*/
|
||
#define SYSLOG_CLEAR_NONE 0 /* 从未请求过清除(上电初值) */
|
||
#define SYSLOG_CLEAR_OK 1 /* 已清空:文件不在盘上,同拍 syslog_count() 必为 0 */
|
||
#define SYSLOG_CLEAR_WAIT (-1) /* 请求排队中:等 defaultTask 下一轮 drain(含卷占用顺延、卷未就绪挂起) */
|
||
#define SYSLOG_CLEAR_FAIL (-2) /* 最近一次落地失败:原文件未被删除,可再发一次请求 */
|
||
|
||
/*
|
||
* 函数功能:登记「清除某日志全部记录」的请求(任意上下文;不碰存储、不阻塞)
|
||
* 入口参数:id - 日志 ID syslog_id_t
|
||
* 返回值:0 - 请求已登记(同一 id 重复登记合并为一次,幂等)
|
||
* -1 - id 越界(请求未登记,状态一个字节都没动) int
|
||
* 限定条件:非唯一写者的上下文(uiTask / netTask / iec104Task)**只能**用本函数发起
|
||
* 删除,不得直调 MCU 后端的 syslog_clear_apply()
|
||
* 函数说明:本函数**不等于"已清除"**,只代表"已受理"——MCU 端的删除动作发生在
|
||
* defaultTask 的下一次 syslog_drain()(50 ms 节拍),结果读
|
||
* syslog_clear_state(),事实复核读 syslog_count()。
|
||
* ⚠ 两端时序有别(同 syslog_post 的队列/直写差异,那边写在 post 的头注释里):
|
||
* MCU 端返回后状态通常是 SYSLOG_CLEAR_WAIT;模拟器端单线程、本调用内
|
||
* 同步落地,返回后立即是 OK/FAIL,**永远不会读到 WAIT**。UI 侧要按
|
||
* "WAIT 也正常"写判断,别把 WAIT 当失败。
|
||
* 刻意**不**在删除成功后补一条 "records cleared" 留痕:判据要求
|
||
* syslog_count() 归零,写了立刻变 1;要留痕归操作记录/SOE
|
||
* (docs/任务规划/UI补齐.md 第 6 项的写入方),不是本 API 的职责。
|
||
*/
|
||
int syslog_request_clear(syslog_id_t id);
|
||
|
||
/*
|
||
* 函数功能:查「清除记录」的状态(给 UI 出真实反馈,不是"按了就算成功")
|
||
* 入口参数:id - 日志 ID syslog_id_t
|
||
* 返回值:SYSLOG_CLEAR_NONE(0) / SYSLOG_CLEAR_OK(1) / SYSLOG_CLEAR_WAIT(-1) /
|
||
* SYSLOG_CLEAR_FAIL(-2);id 越界按 NONE 返回(等价"从没请求过") int
|
||
* 限定条件:任意上下文(MCU 端只读两个 volatile 单字节,Cortex-M 上原子,无锁)
|
||
* 函数说明:排队位优先于结果字节——否则连点两次会先把上一次的结果当成这次的,
|
||
* 还在排队的请求被显示成"已清空"。
|
||
* 无锁交接的最坏竞态只有两种,都不产生错误数据:① 写者已销账、尚未写
|
||
* 结果的那几个指令周期里读 → 读到上一次的结果(同向,多为 OK);
|
||
* ② 上一次失败被新请求清零 → 那次失败不再显示(用户已在重新发起,
|
||
* 语义正确)。为它上临界区要引 FreeRTOS 头 + 宿主桩,不值。
|
||
*/
|
||
int syslog_clear_state(syslog_id_t id);
|
||
|
||
/*
|
||
* MCU 后端专属 API(sys_log_mcu.c;模拟器端无对应实现,勿在共享代码调用)
|
||
*/
|
||
|
||
/*
|
||
* 函数功能:日志引擎初始化(创建 FreeRTOS 消息队列)
|
||
* 入口参数:无
|
||
* 返回值:0 - 成功;-1 - 队列创建失败 int
|
||
* 限定条件:app_main_init() 起始处调用,先于任何 syslog_post()
|
||
*/
|
||
int syslog_mcu_init(void);
|
||
|
||
/*
|
||
* 函数功能:卷挂载成功后的一次性处理(建 /log 目录 + 写"上电/重启"分类记录)
|
||
* 入口参数:无
|
||
* 返回值:无
|
||
* 限定条件:defaultTask f_mount/f_mkfs 成功且置位 SYS_EVT_STORAGE_READY 前调用一次
|
||
*/
|
||
void syslog_mcu_mounted(void);
|
||
|
||
/*
|
||
* 函数功能:排空待发日志并落盘(启动前数组 + 运行期队列,FIFO)
|
||
* 入口参数:无
|
||
* 返回值:无
|
||
* 限定条件:仅 defaultTask(唯一写者)调用;卷未就绪时直接返回(条目滞留待重试)
|
||
* 本函数尾部同时消费「清除记录」请求(syslog_request_clear 的落地半边,
|
||
* 排在条目排空之后——删除必须是本轮对这两个文件的最后一次盘上动作,
|
||
* 先删后写会把刚排空的旧记录又落回去,"清除"就变成没效果的按钮)
|
||
*/
|
||
void syslog_drain(void);
|
||
|
||
/*
|
||
* 函数功能:立即删除某日志的全部记录(「清除记录」的落地半边,MCU 后端专属)
|
||
* 入口参数:id - 日志 ID syslog_id_t
|
||
* 返回值:0 - 记录已清空(含"文件本就不存在"的幂等成功,见下)
|
||
* -1 - 未清空:卷被占用或删除失败,**原文件一个字节都没少** int
|
||
* 限定条件:仅 defaultTask(syslog 唯一写者)上下文,且调用处**不得持卷锁**
|
||
* (卷锁非递归锁);卷锁一律 try(vol_lock_wait(0),本任务 = 看门狗
|
||
* 喂狗点,阻塞等锁 = 停喂 = IWDG 误复位)
|
||
* 函数说明:其它上下文请调 syslog_request_clear()(本头文件上方);本函数在
|
||
* MCU 后端之外**没有任何实现**,共享代码误调会在链接期报错,
|
||
* 这比运行时断言硬。产品路径上唯一的调用者是 syslog_drain 尾部的
|
||
* 请求消费循环,直接调用只用于板级套件与主机单测。
|
||
* 幂等口径:只有 FR_NO_FILE 算"已经没有什么可删了"→ 返 0;
|
||
* FR_NO_PATH(/log 目录不在)**不算**幂等——记录确实读不到,但成因是
|
||
* 目录没了而不是"被清空",补目录归 syslog_mcu_mounted() 每 2s 的重试,
|
||
* 这里如实返 -1,不把卷异常洗成"清除成功"。
|
||
* 名字/参数类错误码(FR_INVALID_NAME 等)一律只返 -1 不做任何补救动作:
|
||
* 本函数压根没有卷级动作(无 f_mkdir / 无 f_mkfs / 不重试 unlink),
|
||
* 这正是存储架构说明 §10.1 第 10 条在删除路径上的落地形态。
|
||
*/
|
||
int syslog_clear_apply(syslog_id_t id);
|
||
|
||
/*
|
||
* 函数功能:把一条取证行追加到 /log/wdev.log(掉电不丢;变长行,不走 64B 定长格式)
|
||
* 入口参数:p_desc - 取证描述行(调用方已格式化;不可为 NULL) const char *
|
||
* 返回值:0 - 成功;-1 - 卷占用或写失败(证据可能回滚,**不阻断判定**) int
|
||
* 限定条件:poller(defaultTask)上下文调用;卷锁一律 try(绝不阻塞,
|
||
* 本上下文 = 看门狗喂狗点)
|
||
* 函数说明:第 7 轮取证通道(设计见 docs/子系统设计/看门狗设计说明.md 2026-10-02 变更记录:
|
||
* 误复位后 RAM 态随复位消失、stall 行经僵尸串口丢失,故证据必须落盘)。
|
||
* 内部在释放卷锁后立刻追加一条 s_append(SYSLOG_RUN, ...) 写另一个
|
||
* 文件——FTL 单页缓存语义为"写到不同 LPN 才把前一脏页刷进 NAND",
|
||
* 没有该 flush 诱导,本行证据会在约 1.7s 后的 IWDG 复位中回滚丢失。
|
||
* 文件 > 8KB 时先 unlink 重建,防长跑无界增长。
|
||
*/
|
||
int sys_log_evidence(const char *p_desc);
|
||
|
||
#ifdef __cplusplus
|
||
}
|
||
#endif
|
||
|
||
#endif /* SYS_LOG_H */
|