栈整改不抬栈:删旧档迁移、FIL静态化、日志行缓冲按模块收紧、钩子脱离HAL,defaultTask链5312→2776B
This commit is contained in:
@@ -8,7 +8,7 @@
|
||||
"stack-overflow-check": "d4735e3a265e16ee",
|
||||
"malloc-failed-hook": "6b86b273ff34fce1",
|
||||
"assert-not-deadloop": "d4a00718ab2bd071",
|
||||
"assert-impl": "908de37a05c944ce",
|
||||
"assert-impl": "5d862ceb21c77a86",
|
||||
"stack-overflow-hook-impl": "a006edbd30d2c4d7",
|
||||
"malloc-failed-hook-impl": "fcd7250e5cd6403b",
|
||||
"stack-overflow-hook-helper": "cacd9fd028be9b5b",
|
||||
|
||||
@@ -55,7 +55,8 @@ STM32F407ZGTx @168MHz(HSE 8MHz → PLL M=4/N=168/P=2);**仅 Keil MDK-ARM v
|
||||
- **FatFs 文件名约束(2026-09-20 台架实证,`.fschk` 无限重格式化事故根因)**:本移植 `Lib/FatFs/ffconf.h` 为 `FF_USE_LFN=0`,**只支持严格 8.3 短名**——主名≤8 字符、扩展≤3 字符、**不得以点开头**(`.fschk` 会被 `ff.c create_short` 把点后当扩展域解析超限 → `f_open` 恒返 `FR_INVALID_NAME`(6),纯 RAM 名字判定、不碰盘)。ff.c `create_short` 全部拒绝点已加 DEBUG 打印:`[ERR][FATFS] SFN reject (原因) seg='名字片段' bad_ch=坏字符`,非法名字调用看开机日志即可定位。自愈类逻辑**严禁**把名字/参数类错误码(`FR_INVALID_NAME` 等)归入卷损坏触发集(整卷重格式化不可逆)
|
||||
- **ADC 取数只用 `tpafe5160_snapshot()`(原子快照)**(2026-10-10 修 E-44/E-45/E-58):旧的 `get_buf()` / `data_ready()` / `clear_ready()` 已从驱动**删除**——`get_buf` 只给缓冲区指针、任务再逐通道拷,两步之间被 BUSY EXTI 抢占并跨过一帧周期就拷回**两帧混合**数据(8 通道失去同一时刻性,且无错误指示);`s_ready` 电平标志有三个写者,`start_conv_irq` 触发前清 0 = **重触发本身就会抹掉一帧未消费数据**。现口径:帧序号只增不清(`tpafe5160_frame_seq()`)、取数=临界区内拷贝(`tpafe5160_snapshot(dst, count)` 返回 1/0/-1,**仅任务上下文**)、FRSTDATA 全程无跳变(芯片不驱动并行总线)由 `tpafe5160_frstdata_err()` 计数且 `tpafe5160_init()` 首帧自检直接返回 `-3` + `[ERR]`
|
||||
- **接 ADC / RS-485 消费者前的强制门禁(E-59,2026-10-10 固化)**:`adc_task` / `rs485_task` 从空桩转为真实消费者**之前**必须确认——① 驱动契约已修:TPAFE **E-44 / E-45 / E-58 已修 ✅**、RS485 **E-36 / E-37 已修 ✅** 但 **E-50(单缓冲无同步 → 包撕裂)未修 ❌**、**E-49(TX 超时拉 DE)未修 ❌**;② 栈预算:两任务**尚未入 `Src/freertos.c` 栈表**,建任务前后各跑一次 `scripts/stack_report.py`。与"改栈前跑 `stack_report.py`"同级。另按 N-18:V0.1 上两片转换器之间**禁止**做相位/功率/功率因数类运算
|
||||
- **`DBG_*` 每条日志约 90 B Flash + 192 B 栈**(2026-10-02 S10 实测):`dbg_log.h` 的 `DBG_INFO/ERROR/DEBUG` 在**每个调用点内联** `char __con_line[DBG_CON_LINE_MAX]`(`console_log.h` 定义 **192 B**)+ 完整 `snprintf` 调用序列 → 单条约 **90 B Flash**(字符串常量另计)。给新模块接入日志时按"条数 × 90 B"估算 Flash 代价(实测 `sd2506_init` 加 6 条 = +576 B;`app_main` 加 3 条 = +180 B);**深调用链模块另需核算栈**(每条日志在栈上多占 192 B,会进 `stack_report.py` 的最坏链)。故**日志不是免费的**——已覆盖的步骤不要再加"进入前/完成后"重复锚点,只在真正黑洞(原先静默返回)处补
|
||||
- **`DBG_*` 每条日志约 90 B Flash + 216 B 栈**(2026-10-02 S10 实测;2026-10-10 修正栈量):`dbg_log.h` 的 `DBG_INFO/ERROR/DEBUG` 在**每个调用点内联**行缓冲 `char __con_line[DBG_LINE_BUF_MAX]`(默认 = `console_log.h` 的 `DBG_CON_LINE_MAX` **192 B**)+ 时间戳缓冲 **24 B**(已并入同一数组,原为独立 32 B)+ 完整 `snprintf` 调用序列 → 单条约 **90 B Flash**(字符串常量另计)。给新模块接入日志时按"条数 × 90 B"估算 Flash 代价(实测 `sd2506_init` 加 6 条 = +576 B;`app_main` 加 3 条 = +180 B);**深调用链模块另需核算栈**——每条日志在栈上多占一份行缓冲、会进 `stack_report.py` 的最坏链:实测 defaultTask 那条链上 9 个帧各含一份 → **约 1.5 KB 纯粹是日志行缓冲**(2026-10-10 把该链 5312 → 2776 B 的主要杠杆之一)。故**日志不是免费的**——已覆盖的步骤不要再加"进入前/完成后"重复锚点,只在真正黑洞(原先静默返回)处补
|
||||
- **深调用链模块收紧日志行缓冲:`#define DBG_LINE_BUF_MAX 128U`,写在 `#include "dbg_log.h"` 之前**(2026-10-10 加)。已收紧:`nand_ftl.c`/`gd5f2gq5ue.c`/`cfg_file.c`/`net_cfg.c`/`net_socket.c`/`ch395f.c`/`time_sync.c`/`default_task.c`。⚠ **取值必须 ≥ 该模块最长日志行**(时间戳 20 + 标签 + 正文),否则该行被截断——各文件注释已写出实测行长。改前/改后各跑一次 `stack_report.py`
|
||||
|
||||
<!-- TASK_TABLE:BEGIN generated by scripts/gen_task_table.py -->
|
||||
| Task | 栈 (words) | 优先级 |
|
||||
@@ -77,7 +78,7 @@ STM32F407ZGTx @168MHz(HSE 8MHz → PLL M=4/N=168/P=2);**仅 Keil MDK-ARM v
|
||||
- `app_main_init`(时间子系统优先,使后续日志带时间戳):`sd2506_init` → `sys_clock_init`(墙钟;RTC 故障时降级默认时间基准并返回 -1 触发"时钟芯片异常"自检;`sys_clock_get` 每 30 天惰性再基准化防 49.7 天 tick 回绕)→ `rs485_init` → `gd5f2gq5ue_init` → `tpafe5160_init` → SD2506 诊断 → `tpafe5160_start_conv_irq`
|
||||
- **就绪屏障**(`App/app/sys_events.h` Event Flags,取代魔法延时):`SYS_EVT_NET_READY`(netTask 置位)/ `STORAGE_READY`(defaultTask:卷挂载 + 网络配置加载完成)/ `FTP_READY` / `TIMESYNC_READY`;消费者用 `osEventFlagsWait` 阻塞等待
|
||||
- netTask:`net_stack_bring_up`(配置已由 defaultTask 在屏障前加载,本任务只读 RAM 副本 → `net_init` + PHY 强制 100M 全双工 → 递增网络代次号)→ 置 NET_READY → 循环 `net_poll` + `net_process_messages`;消费 `SYS_EVT_NET_RECONFIG` → 立即重建网络(新 IP 免重启生效,各 TCP 服务据代次号重建监听)
|
||||
- defaultTask:`f_mount` forced(无卷自动 `f_mkfs` FAT32;挂载后卷健康探针:小写两击确认,FAT 区陈旧/擦除时自动重格式化自愈,`/config.ini` 回落工厂默认——2026-09-20 /log 写失败修复)→ 网络配置加载(`net_cfg_load`,首启含旧档迁移)→ STORAGE_READY → LED 闪烁;同时是 syslog(`/log/run.log`·`selftest.log`,定长 64B 记录)的**唯一写者**与**配置引擎属主**(`cfg_file` 静态态单任务收敛于此:UI 保存请求执行 `net_cfg_save_run` + 2s `cfg_file_poll`,经 `SYS_EVT_CFG_SAVE` 事件唤醒;netTask/uiTask 不得直接触碰配置引擎,见 P1-3)
|
||||
- defaultTask:`f_mount` forced(无卷自动 `f_mkfs` FAT32;挂载后卷健康探针:小写两击确认,FAT 区陈旧/擦除时自动重格式化自愈,`/config.ini` 回落工厂默认——2026-09-20 /log 写失败修复)→ 网络配置加载(`net_cfg_load`;旧档迁移已于 2026-10-10 删除,见「模块约定」网口配置条)→ STORAGE_READY → LED 闪烁;同时是 syslog(`/log/run.log`·`selftest.log`,定长 64B 记录)的**唯一写者**与**配置引擎属主**(`cfg_file` 静态态单任务收敛于此:UI 保存请求执行 `net_cfg_save_run` + 2s `cfg_file_poll`,经 `SYS_EVT_CFG_SAVE` 事件唤醒;netTask/uiTask 不得直接触碰配置引擎,见 P1-3)
|
||||
- 全景 `docs/架构设计/项目架构总览.md`(六层分层 / 启动时序 / 存储·网络·UI 栈 / 目录组织)
|
||||
|
||||
## 硬件引脚
|
||||
@@ -99,7 +100,7 @@ STM32F407ZGTx @168MHz(HSE 8MHz → PLL M=4/N=168/P=2);**仅 Keil MDK-ARM v
|
||||
- 所有 `net_*` socket 操作经 `netMsgQueue` 消息队列在 netTask 串行执行(线程安全);非 netTask 任务直接调 `net_*` API,勿直接碰 CH395F 驱动
|
||||
- **`net_*` 公开 API 的错误码经"任务通知值"回传**(2026-09-21 实证):`net_msg_t` 是**按值拷入队列**的,netTask 改的是自己那份副本,调用方永远看不到 → 错误码搭 `xTaskNotify()` 通知值回来(失败=负的具体错误码如 `NET_ERR_WOULDBLOCK`、成功=字节数/描述符),公开 API 恢复 errno 后对外统一返回 -1。**勿给 `net_msg_t` 加"回传用"字段**(调用方只会读到栈垃圾;曾据此"修"错误码,导致 `ui_net_sink` 每次空轮询都误判为真错误 → 连上即 `net_close`)
|
||||
- **单连接 socket 的断开语义**:监听 Socket 在 CONNECT 后自身即数据通道(`g_client == g_listen`),EOF 时 net 层已 `auto_relisten`;应用层**不得**在 EOF 时 `net_close` 该 fd(会连监听一起毁掉 → 端口"连接被拒"),仅当数据 fd ≠ 监听 fd(模拟器多连接后端)时才关
|
||||
- 网口配置:`/config.ini` [network] 段(工厂默认 192.168.1.100/24、gw .1;MAC 全零 = 芯片内置;UI 保存立即生效;旧档 `/cfg/netcfg.bin` 首启自动迁移)→ `docs/子系统设计/网络配置说明.md`
|
||||
- 网口配置:`/config.ini` [network] 段(工厂默认 192.168.1.100/24、gw .1;MAC 全零 = 芯片内置;UI 保存立即生效;**旧档 `/cfg/netcfg.bin` 迁移已于 2026-10-10 删除**——`net_cfg_legacy.c/h` 整体移除,旧档若存在则被忽略(不读/不删/不迁移)、配置回落工厂默认;删除理由 = 该一次性路径把整条配置写链挂进启动期调用图,defaultTask 静态最坏链 +600 B,且本仓库无携带旧档的设备)→ `docs/子系统设计/网络配置说明.md`
|
||||
- **新 .c 文件必须手动注册到两处**才能双端编译:`MDK-ARM/STM32F407-Demo.uvprojx` + `simulator/CMakeLists.txt`(用 `new-source-file` skill)
|
||||
- **`MDK-ARM/*.uvprojx` 每次 `@build` 后被 Keil UV4 自动改写,改动一律不入库**(2026-09-29 实测):UV4 构建时会把工程 XML 归一化成它本机风格的旧式写法(`<Tag />` → `<Tag></Tag>`、XML 声明加 `standalone="no"`),并把 `PackID` 降到**本机装的 DFP 版本**(本机实测 `3.1.1` → `3.0.0`,属**降级**)。这些差异是环境相关的,提交后会把别人的 Pack 版本也一起改掉。**判断方法**:`git diff MDK-ARM/STM32F407-Demo.uvprojx` 里若只见 XML 格式/`PackID` 差异而**无源文件挂载增删** → `git checkout -- MDK-ARM/STM32F407-Demo.uvprojx` 丢弃。只有真的新增/删除源文件(`grep 文件名` 计数变化)才提交
|
||||
- 测试构建:`test/board/test_config.h` 的 `TEST_SUITE_CH395F/STORAGE/GD5F/RTC` **互斥**(一次只能启用一个,`#error`);全部注释 = 产品构建;**该开关受 pre-commit 钩子 `test-suite-switch` 门禁**(默认要求产品构建,跑完套件回归须改回;确需提交测试构建用 `ALLOW_TEST_BUILD=1` 显式放行——2026-10-01 实测已提交 HEAD 里 `TEST_SUITE_CH395F` 长期开启,纯靠人记得改,故补此门禁);**破坏性用例默认关闭**:同文件 `ENABLE_DESTRUCTIVE_TESTS`(默认注释)控制写/擦 NAND、格式化、坏块注入与 FatFS 写类用例——关闭时套件为**只读模式**(开机横幅 `mode: READ-ONLY`,可随时在在用设备上跑、不动卷内容与容量),只在**产品首次上电/产线首启**或明确需要时打开(`mode: DESTRUCTIVE`);2026-09-21 实测一轮破坏性 GD5F 运行即让 dhara 多记一个坏块(容量 95248 → 95200;该计数持久化在 dhara journal checkpoint 头里,普通恢复模式清不掉,需全片擦除——见 `docs/测试说明/存储维护与容量恢复.md`);CH395F 套件 `test/board/ch395f_test.h`:硬件层 Phase 1~5 与 NET 层 Phase 6~11 互斥;CH395F 硬件层模式下 netTask(基础线程:无条件创建、全构建唯一实例)入口自挂起(不运行),testTask 独占 CH395F
|
||||
|
||||
+1
-1
@@ -14,7 +14,7 @@ FreeRTOS/CMSIS-RTOS API**(见 `AGENTS.md`「平台约束」)。
|
||||
| 目录 | 内容 | README |
|
||||
|---|---|---|
|
||||
| `app/` | **应用入口与全局**:`app_main.c/h`(初始化入口)、`app_cfg.h`(编译开关)、`sys_events.h`(就绪事件) | [`app/README.md`](app/README.md) |
|
||||
| `cfg/` | **配置引擎**:`/config.ini` 解析 + 持久化 + 旧档迁移 | [`cfg/README.md`](cfg/README.md) |
|
||||
| `cfg/` | **配置引擎**:`/config.ini` 解析 + 原子持久化(旧二进制档已废弃,2026-10-10) | [`cfg/README.md`](cfg/README.md) |
|
||||
| `sync/` | **时间同步任务**:`time_sync.c/h` | [`sync/README.md`](sync/README.md) |
|
||||
| `log/` | **日志子系统**:syslog(NAND)+ 控制台单写者日志 | [`log/README.md`](log/README.md) |
|
||||
| `task/` | **FreeRTOS 任务实现**(6 个任务) | [`task/README.md`](task/README.md) |
|
||||
|
||||
+4
-3
@@ -1,6 +1,6 @@
|
||||
# App/cfg/ — 配置引擎
|
||||
|
||||
> **`/config.ini` 配置引擎**:分层解析、持久化(原子写)、旧档迁移。
|
||||
> **`/config.ini` 配置引擎**:分层解析、持久化(原子写)。
|
||||
> 属主 = **defaultTask**(单任务收敛,静态态);其它任务不得直接触碰。
|
||||
|
||||
## 文件一览
|
||||
@@ -18,10 +18,11 @@
|
||||
- **零分配共享核心**:核心逻辑不含任何分配符号,动态内存收进平台后端
|
||||
(`cfg_store_alloc/free`:MCU→`pvPortMalloc`,模拟器→宿主堆)
|
||||
- **原子写**:写 `/config.TMP` 后 `f_rename` 替换,避免掉电损坏
|
||||
- **旧档迁移**:首启时把旧格式转换为当前格式(`net_cfg_legacy.c` 负责网络段)
|
||||
- **旧档迁移已删除(2026-10-10)**:旧格式 `/cfg/netcfg.bin` 不再读取——存在则被忽略(不读、
|
||||
不删、不迁移),配置回落工厂默认;`net_cfg_legacy.c/h` 与 `cfg_store_legacy_path()` 已移除
|
||||
- **自研代码禁用 C 库堆分配**:MicroLIB 堆仅 512B(`malloc` 必返回 NULL)
|
||||
|
||||
## 相关文档
|
||||
|
||||
- `docs/子系统设计/配置文件设计说明.md` — 完整设计(分层/解析/持久化/迁移)
|
||||
- `docs/子系统设计/配置文件设计说明.md` — 完整设计(分层/解析/持久化)
|
||||
- `docs/子系统设计/网络配置说明.md` — 网络段
|
||||
|
||||
@@ -41,6 +41,10 @@
|
||||
|
||||
#include "sys_log.h" /* 配置读写失败上报自检记录(双端共享接口,MCU 端 preboot/队列安全) */
|
||||
|
||||
/* 深调用链模块(配置引擎在 defaultTask 启动链与保存链上,下接 FatFS → FTL):
|
||||
* 日志行缓冲收到 128 B(默认 192)。本模块最长行 "load: file %luB > %uB, corrupt,
|
||||
* factory template regenerated" 渲染后 ≈ 91 B(含时间戳 21 + 标签)< 128 → 不截断 */
|
||||
#define DBG_LINE_BUF_MAX 128U
|
||||
#define DBG_TAG "[CFG]"
|
||||
#include "dbg_log.h"
|
||||
|
||||
|
||||
@@ -103,8 +103,8 @@ const char *cfg_store_config_path(void);
|
||||
/* 函数功能:取配置文件临时文件路径(write_atomic 内部用) */
|
||||
const char *cfg_store_tmp_path(void);
|
||||
|
||||
/* 函数功能:取旧版配置遗留文件路径(net_cfg_legacy 迁移用) */
|
||||
const char *cfg_store_legacy_path(void);
|
||||
/* 注:旧版遗留档 getter `cfg_store_legacy_path()` 已于 2026-10-10 随旧档迁移
|
||||
* net_cfg_legacy 一并删除(旧格式 /cfg/netcfg.bin 不再兼容、不再读取) */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* 模块名称:cfg_file_store (MCU 后端)
|
||||
* 模块功能:cfg_file 存储后端——NAND 上 FatFS 文件 /config.ini(卷根,8.3 合规);
|
||||
* 原子写 = 临时文件 config.TMP(与目标同目录)+ f_rename;mtime 变更令牌 =
|
||||
* (fdate << 16) | fmtime;旧版遗留文件 /cfg/netcfg.bin 供迁移读取
|
||||
* (fdate << 16) | fmtime
|
||||
* 适用平台:STM32F407ZGTx
|
||||
* 作者:王建锋
|
||||
* 创建日期:2026-09-14
|
||||
@@ -37,7 +37,6 @@
|
||||
|
||||
static const char s_path[] = "/config.ini";
|
||||
static const char s_path_tmp[] = "/config.TMP";
|
||||
static const char s_path_legacy[] = "/cfg/netcfg.bin";
|
||||
|
||||
/* 函数定义区 */
|
||||
|
||||
@@ -49,9 +48,14 @@ static const char s_path_legacy[] = "/cfg/netcfg.bin";
|
||||
* p_nread - 实际读字节数输出(不可为 NULL) size_t *
|
||||
* 返回值:0 - 成功;-1 - 文件缺失/读失败 int
|
||||
* 限定条件:卷已挂载(未挂载时 f_open 返回 FR_NO_SYSTEM,转 -1)
|
||||
* 函数说明:FIL 为**函数级 static**而非局部——本 FatFs 移植 FF_FS_TINY=0,
|
||||
* `FIL` 内含 `buf[FF_MAX_SS]`=512 B(Lib/FatFs/ff.h),一个局部对象就吃掉
|
||||
* 528 B 栈,是配置/syslog 调用链栈深的主要来源(2026-10-10 栈预算整改)。
|
||||
* 安全性:整个 FIL 生命周期都在 `vol_lock_wait()/release()` 区间内,
|
||||
* 跨任务访问被卷锁串行化,且本函数不递归、不嵌套自身
|
||||
*/
|
||||
int cfg_store_read(const char *p_path, uint8_t *p_buf, size_t cap, size_t *p_nread) {
|
||||
FIL f;
|
||||
static FIL f; /* static:省 528 B 栈;卷锁内串行使用 */
|
||||
FRESULT fr;
|
||||
UINT br = 0u;
|
||||
|
||||
@@ -116,9 +120,11 @@ static int s_build_tmp_path(const char *p_path, char *p_out, size_t cap) {
|
||||
* len - 数据长度 size_t
|
||||
* 返回值:0 - 成功;-1 - 写/改名失败(目标文件保持不动,临时文件清理) int
|
||||
* 限定条件:卷已挂载;中途失败(含掉电)不损坏目标文件
|
||||
* 函数说明:`FIL` 用函数级 static 而非局部(FF_FS_TINY=0 → 单个 FIL = 528 B 栈);
|
||||
* 与 cfg_store_read 各持自己的 static 对象,互不共享,且全程在卷锁区间内
|
||||
*/
|
||||
int cfg_store_write_atomic(const char *p_path, const uint8_t *p_buf, size_t len) {
|
||||
FIL f;
|
||||
static FIL f; /* static:省 528 B 栈;卷锁内串行使用 */
|
||||
FRESULT fr;
|
||||
UINT bw = 0u;
|
||||
char tmp_path[CFG_STORE_TMP_PATH_MAX];
|
||||
@@ -233,14 +239,10 @@ const char *cfg_store_tmp_path(void) {
|
||||
}
|
||||
|
||||
/*
|
||||
* 函数功能:取旧版配置遗留文件路径
|
||||
* 入口参数:无
|
||||
* 返回值:"/cfg/netcfg.bin"(旧 NCFG 二进制格式) const char *
|
||||
* 限定条件:无
|
||||
* 旧版遗留文件 /cfg/netcfg.bin 的路径 getter(cfg_store_legacy_path)已于
|
||||
* 2026-10-10 随旧档迁移 net_cfg_legacy 一并删除:无调用者即无必要保留
|
||||
* (留着"看起来还支持旧档"的入口会误导后续维护)
|
||||
*/
|
||||
const char *cfg_store_legacy_path(void) {
|
||||
return s_path_legacy;
|
||||
}
|
||||
|
||||
/*
|
||||
* 函数功能:分配共享核心临时缓冲(FreeRTOS 堆)
|
||||
|
||||
+70
-4
@@ -36,7 +36,9 @@
|
||||
#include "task.h"
|
||||
#include "cmsis_os.h"
|
||||
#include "sys_events.h"
|
||||
#include "sys_log.h"
|
||||
/* 刻意不 include "sys_log.h":日志子系统不得回调本模块(调用图成环 →
|
||||
* armlink 静态栈深在每个任务上虚高,见 dbg_console_drain 故障路径注释)。
|
||||
* TX 故障留痕改由写者任务在 drain 之外补记 */
|
||||
|
||||
/* ===== 控制台单写者日志(2026-09-24 加固,HardFault 定位结论驱动)=====
|
||||
* 背景:旧路径 DBG_* → printf → fputc **每字符一次** HAL_UART_Transmit。HAL 的锁只保证
|
||||
@@ -66,6 +68,17 @@
|
||||
* IWDG 误复位(round 8a 台架现场)。改用 DWT CYCCNT(内核硬件周期计数,不依赖任何
|
||||
* 中断/uwTick)做判据;DWT 使能失败时退回 HAL_UART_Transmit(旧行为,功能不退化)。 */
|
||||
#define CON_TX_TIMEOUT_CYC (SystemCoreClock / 10U) /* 发送硬上界 = 100ms 对应周期数 */
|
||||
/*
|
||||
* DWT 不可用时的**指令计数**上界(替代 HAL_UART_Transmit 回退,2026-10-10)。
|
||||
* 为什么不再回退 HAL:① HAL_UART_Transmit 的超时判据是 HAL_GetTick——断言/停摆
|
||||
* 现场 tick 未必在走,等待无上界;② 它的调用链 `HAL_UART_Transmit →
|
||||
* UART_WaitOnFlagUntilTimeout` 会被 armlink 挂进**每个**碰日志的任务的最坏链
|
||||
* (configASSERT 在 FreeRTOS 内部可达 → 三个内核钩子都在链尾),实测每条链多背
|
||||
* 64 B 栈。计数上界同样有界、零外部依赖。
|
||||
* 取值:115200 bps 下一字节 87 µs;轮询循环 ~5 周期 → 每字节约 3000 次迭代,
|
||||
* 取 20000 留 6 倍余量(单字节卡死最多数毫秒级即放弃,不无限自旋)
|
||||
*/
|
||||
#define CON_TX_GUARD_MAX 20000u
|
||||
#define CON_APPEND_WAIT_CYC (SystemCoreClock / 5U) /* 缓冲满等待硬上界 = 200ms 对应周期数 */
|
||||
|
||||
static uint8_t s_con_ring[DBG_CON_RING_SIZE];
|
||||
@@ -73,6 +86,7 @@ static volatile uint16_t s_con_head; /* 生产者写入位置 */
|
||||
static volatile uint16_t s_con_tail; /* 写者读取位置 */
|
||||
static volatile uint32_t s_con_drop; /* 因缓冲满丢弃的行数 */
|
||||
static volatile uint32_t s_con_tx_fault; /* TX 失败(僵尸通道)次数,均经外设软复位自愈 */
|
||||
static volatile uint8_t s_con_tx_fault_log; /* TX 故障留痕待上报(由写者任务在 drain 之外补记 run.log) */
|
||||
static volatile uint32_t s_con_cool_until; /* 故障冷却截止 tick(0 = 无冷却) */
|
||||
static volatile uint8_t s_con_draining; /* 1 = 处于 drain 中(重入保护) */
|
||||
static volatile uint8_t s_con_writer_up; /* 1 = 写者已注册(此后走环形缓冲) */
|
||||
@@ -109,13 +123,45 @@ static void con_dwt_ensure(void) {
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* 函数功能:DWT 不可用时的计数上界发送(每字节/TC 各数 CON_TX_GUARD_MAX 次)
|
||||
* 入口参数:u - USART 寄存器基址(调用方已判非 NULL) USART_TypeDef *
|
||||
* p_buf - 待发数据;len - 字节数
|
||||
* 返回值:HAL_OK - 已发出;HAL_TIMEOUT - 计数上界内未完成(本块放弃)
|
||||
* 限定条件:USART1 已初始化
|
||||
* 函数说明:刻意不用 HAL_UART_Transmit——理由见 CON_TX_GUARD_MAX 处注释
|
||||
* (tick 依赖不可信 + 其调用链污染所有任务的最坏栈链)
|
||||
*/
|
||||
static HAL_StatusTypeDef con_tx_counted(USART_TypeDef *u, const uint8_t *p_buf, uint16_t len) {
|
||||
uint32_t guard;
|
||||
uint16_t i;
|
||||
|
||||
for (i = 0U; i < len; i++) {
|
||||
guard = 0U;
|
||||
while ((u->SR & USART_SR_TXE) == 0U) {
|
||||
if (++guard >= CON_TX_GUARD_MAX) {
|
||||
return HAL_TIMEOUT;
|
||||
}
|
||||
}
|
||||
u->DR = (uint16_t)p_buf[i];
|
||||
}
|
||||
guard = 0U;
|
||||
while ((u->SR & USART_SR_TC) == 0U) {
|
||||
if (++guard >= CON_TX_GUARD_MAX) {
|
||||
return HAL_TIMEOUT;
|
||||
}
|
||||
}
|
||||
return HAL_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* 函数功能:有界裸发送(不依赖 uwTick / HAL 超时)
|
||||
* 入口参数:p_buf - 待发数据;len - 字节数(调用方已限 ≤ DBG_CON_CHUNK_MAX)
|
||||
* 返回值:HAL_OK - 已全部写入发送寄存器;HAL_TIMEOUT - 有界上界内未完成
|
||||
* 限定条件:USART1 已初始化
|
||||
* 函数说明:寄存器级轮询 TXE/TC,超时判据用 DWT CYCCNT(CON_TX_TIMEOUT_CYC);
|
||||
* DWT 未使能时退回 HAL_UART_Transmit(旧行为)。本函数只做 TX,
|
||||
* DWT 未使能时走 con_tx_counted(指令计数上界,2026-10-10 取代
|
||||
* HAL_UART_Transmit 回退)。本函数只做 TX,
|
||||
* 不触碰 RX/错误标志——僵尸通道自愈由调用方按返回值处理。
|
||||
* ⚠ USART1 未初始化(huart1.Instance == NULL,如 HAL_Init 早期或
|
||||
* 断言/故障上报路径)时立即返回 HAL_ERROR:否则会解引用 NULL 去读写
|
||||
@@ -131,7 +177,7 @@ static HAL_StatusTypeDef con_tx_bounded(const uint8_t *p_buf, uint16_t len) {
|
||||
return HAL_ERROR; /* USART1 未初始化:无可用通道,安全让位 */
|
||||
}
|
||||
if (s_con_dwt_up == 0U) {
|
||||
return HAL_UART_Transmit(&huart1, (uint8_t *)p_buf, len, DBG_CON_TX_TIMEOUT_MS);
|
||||
return con_tx_counted(huart1.Instance, p_buf, len);
|
||||
}
|
||||
|
||||
u = huart1.Instance;
|
||||
@@ -254,7 +300,14 @@ void dbg_console_drain(void) {
|
||||
if (s_con_tx_fault == 1U) {
|
||||
static const char note[] = "\r\n[WARN] CONSOLE tx fault: UART reinit (self-healed)\r\n";
|
||||
|
||||
syslog_post(SYSLOG_RUN, "console tx fault, uart reinit"); /* 仅 run.log,不入自检判定 */
|
||||
/* 刻意**不在这里**调 syslog_post():syslog_post → dbg_console_write_line
|
||||
* → con_append → dbg_console_drain 会与本函数构成**调用图成环**。运行时
|
||||
* 有 s_con_draining 重入标志挡着,不会真递归;但 armlink 静态调用图会把
|
||||
* 整条日志尾巴在每个任务的最坏链上多叠一层(实测 6 个任务的最坏链末尾
|
||||
* 全是这个环)→ 栈深数字虚高、真实风险反而被掩盖。
|
||||
* 改法:只置标志,由写者任务(defaultTask 主循环,本就是 syslog 唯一
|
||||
* 写者)在 drain **之外**补记 run.log(见 dbg_console_tx_fault_log_take) */
|
||||
s_con_tx_fault_log = 1U;
|
||||
(void)dbg_console_write_raw(note, (unsigned)sizeof(note) - 1U);
|
||||
}
|
||||
break; /* 故障即止:本轮 drain 到此为止,让位主循环 */
|
||||
@@ -401,6 +454,19 @@ uint32_t dbg_console_tx_fault(void) {
|
||||
return s_con_tx_fault;
|
||||
}
|
||||
|
||||
/*
|
||||
* 函数功能:取走"控制台 TX 故障待上报"标志(读后清)
|
||||
* 返回值:1 - 需要补记一条 run.log 证据,0 - 无
|
||||
* 限定条件:**写者任务**(defaultTask)在 dbg_console_drain() 之外调用
|
||||
* 函数说明:断调用图成环用,见 dbg_console_drain 故障路径注释
|
||||
*/
|
||||
uint8_t dbg_console_tx_fault_log_take(void) {
|
||||
uint8_t pending = s_con_tx_fault_log;
|
||||
|
||||
s_con_tx_fault_log = 0U;
|
||||
return pending;
|
||||
}
|
||||
|
||||
/*
|
||||
* 函数功能:MicroLIB printf 底层重定向(库内部/遗留 printf 调用)
|
||||
* 函数说明:同样只把字节交给单写者路径;未注册写者时直发(与旧行为一致)
|
||||
|
||||
@@ -37,6 +37,11 @@ extern "C" {
|
||||
* dbg_console_drain - 写者任务排空缓冲并发送(单次有界;TX 失败自动软复位自愈)
|
||||
* dbg_console_dropped - 因缓冲满丢弃的行数(诊断)
|
||||
* dbg_console_tx_fault - 因僵尸通道软复位自愈的次数(诊断)
|
||||
* dbg_console_tx_fault_log_take
|
||||
* - 取走"TX 故障待上报"标志(读后清)。**必须**由写者任务在
|
||||
* dbg_console_drain() 之外调用后自行 syslog_post——本模块
|
||||
* 刻意不调日志子系统,否则形成 write_line→con_append→drain
|
||||
* →syslog_post→write_line 调用图成环,静态栈深全线虚高
|
||||
*/
|
||||
#define DBG_CON_LINE_MAX 192U /* 单行文本上限(含结尾 '\0',超出截断) */
|
||||
int dbg_console_write_line(const char *line, unsigned len);
|
||||
@@ -45,6 +50,7 @@ void dbg_console_writer_attach(void);
|
||||
void dbg_console_drain(void);
|
||||
uint32_t dbg_console_dropped(void);
|
||||
uint32_t dbg_console_tx_fault(void);
|
||||
uint8_t dbg_console_tx_fault_log_take(void);
|
||||
|
||||
/*
|
||||
* 函数功能:MicroLIB printf 底层重定向(C 库 retarget 钩子,须为全局符号)
|
||||
|
||||
@@ -67,7 +67,8 @@ static volatile uint8_t s_mount_fail_reported; /* P2-9:建目录失败日
|
||||
* 限定条件:仅 defaultTask(唯一写者)调用;卷已挂载
|
||||
*/
|
||||
static int s_append(syslog_id_t id, const char *desc) {
|
||||
FIL f;
|
||||
static FIL f; /* static:FF_FS_TINY=0 → 局部 FIL 吃 528 B 栈;
|
||||
* 本函数全程在 vol_lock 区间内,跨任务被卷锁串行化 */
|
||||
FRESULT fr;
|
||||
UINT bw = 0u;
|
||||
uint8_t rec[SYSLOG_REC_SIZE];
|
||||
@@ -168,7 +169,8 @@ static int s_append(syslog_id_t id, const char *desc) {
|
||||
* 心跳,绝不能阻塞等锁;busy = 本次读失败(UI 下轮刷新重读,非故障)。
|
||||
*/
|
||||
static int s_read_raw(syslog_id_t id, uint32_t idx, uint8_t *p_rec) {
|
||||
FIL f;
|
||||
static FIL f; /* static:省 528 B 栈;open~close 全在卷锁区间内
|
||||
* (uiTask 与写者任务由 vol_lock 串行化,见上方 P2-10 说明) */
|
||||
FRESULT fr;
|
||||
UINT br = 0u;
|
||||
int rc;
|
||||
@@ -439,11 +441,12 @@ int syslog_last_epoch(syslog_id_t id, uint32_t *p_epoch) {
|
||||
* 容量护栏:> 8KB 先 unlink 重建,防长跑无界增长(8.3 合法名 wdev.log)。
|
||||
*/
|
||||
int sys_log_evidence(const char *p_desc) {
|
||||
FIL f;
|
||||
static FIL f; /* static:省 528 B 栈(FF_FS_TINY=0 → FIL=528 B) */
|
||||
static char line[192]; /* static:省 192 B 栈;本函数只有 poller(defaultTask)
|
||||
* 一个调用者(task_wd_poll 内),且全程在卷锁区间内 */
|
||||
FRESULT fr;
|
||||
UINT bw = 0u;
|
||||
UINT line_len;
|
||||
char line[192];
|
||||
char ts[SYSLOG_TS_LEN + 1u];
|
||||
int n;
|
||||
int rc = 0;
|
||||
|
||||
@@ -23,6 +23,9 @@
|
||||
#include "sys_events.h"
|
||||
#include "task_watchdog.h"
|
||||
|
||||
/* 深调用链模块(timeSyncTask 栈仅 2048 B,本任务链 = 建监听 → net_bind → CH395F):
|
||||
* 日志行缓冲收到 128 B(默认 192),本模块最长行渲染后 < 128 → 不截断 */
|
||||
#define DBG_LINE_BUF_MAX 128U
|
||||
#define DBG_TAG "[TIME_SYNC]"
|
||||
#include "dbg_log.h"
|
||||
|
||||
|
||||
+13
-2
@@ -33,6 +33,10 @@
|
||||
#include "cfg_file.h"
|
||||
#include "sys_log.h"
|
||||
#include "sys_events.h"
|
||||
/* 深调用链模块(本任务 = 存储 bring-up + 配置引擎属主 + syslog 唯一写者,
|
||||
* 全项目最深链在此):日志行缓冲收到 128 B(默认 192),本模块最长行渲染后
|
||||
* < 128 → 不截断 */
|
||||
#define DBG_LINE_BUF_MAX 128U
|
||||
#include "dbg_log.h"
|
||||
#include "task_watchdog.h"
|
||||
#include "vol_lock.h"
|
||||
@@ -191,6 +195,12 @@ void default_task_func(void *argument) {
|
||||
/* 控制台唯一发送点:把环形缓冲中的日志按块发出(无待发时立即返回) */
|
||||
task_wd_seg(TASK_WD_SEG_DRAIN);
|
||||
dbg_console_drain();
|
||||
/* 控制台 TX 故障留痕:由本任务(syslog 唯一写者)在 drain **之外**补记 run.log。
|
||||
* console_log 内部刻意不调 syslog_post —— 那会构成日志调用图成环,
|
||||
* 让 armlink 静态栈深在每个任务上都多叠一条日志尾巴(见 console_log.c) */
|
||||
if (dbg_console_tx_fault_log_take() != 0U) {
|
||||
syslog_post(SYSLOG_RUN, "console tx fault, uart reinit");
|
||||
}
|
||||
/* 执行待处理保存(配置引擎属主:写盘 + 成功后立即应用);无请求 = 空操作 */
|
||||
#if !defined(TEST_SUITE_STORAGE)
|
||||
task_wd_seg(TASK_WD_SEG_CFGSAVE);
|
||||
@@ -405,7 +415,8 @@ static FRESULT storage_bring_up(FATFS *fs) {
|
||||
* 判定、不碰盘)→ 曾误入下方结构性错误集合 → 每 boot 假失败 →
|
||||
* 无限重格式化。探针名必须严格 8.3:名≤8、扩展≤3、不以点开头。 */
|
||||
#define FS_VOL_PROBE(h) do { \
|
||||
FIL __chk; \
|
||||
static FIL __chk; /* static:FF_FS_TINY=0 → 局部 FIL 吃 528 B 栈;探针只在 \
|
||||
* defaultTask 启动/自愈路径跑,无并发 */ \
|
||||
static const uint8_t __chkbuf[8] = { 0 }; \
|
||||
UINT __bw = 0u; \
|
||||
FRESULT __wr; \
|
||||
@@ -465,7 +476,7 @@ static FRESULT storage_bring_up(FATFS *fs) {
|
||||
DBG_INFO("[FS] FATFS mounted");
|
||||
/* 日志引擎挂载后处理:建 /log 目录 + 写"上电/重启"分类记录(唯一写者) */
|
||||
syslog_mcu_mounted();
|
||||
/* 加载网络配置进 RAM 副本(配置引擎属主 = 本任务;首启含旧档迁移;
|
||||
/* 加载网络配置进 RAM 副本(配置引擎属主 = 本任务;只读 INI,
|
||||
* 文件缺失/损坏 = 工厂默认,不阻塞组网)。须在置位 STORAGE_READY 前,
|
||||
* 使"存储就绪"屏障蕴含"配置已就绪",netTask 组网时配置恒有效 */
|
||||
(void)net_cfg_load();
|
||||
|
||||
+3
-2
@@ -10,8 +10,9 @@
|
||||
| `task_watchdog.c/h` | **独立看门狗(IWDG)判定状态机**:任务心跳位图 + defaultTask 单一喂狗者 |
|
||||
|
||||
> **已删除(2026-10-02)**:`crc.c/h`(CRC-16 Modbus / CRC-8)与 `ringbuf.c/h`(SPSC 环形缓冲)
|
||||
> 两模块**零调用者**且未编入任何构建——CRC 唯一使用点 `net_cfg_legacy.c` 自带静态
|
||||
> `s_crc16_modbus()`,环形缓冲由 `App/log/console_log.c` 内联实现(`s_con_ring`)。
|
||||
> 两模块**零调用者**且未编入任何构建——CRC 从未被链接使用:名义上的关联点 `net_cfg_legacy.c`
|
||||
> (旧档 `/cfg/netcfg.bin` 迁移,**该文件亦已于 2026-10-10 删除**)自带静态 `s_crc16_modbus()`,
|
||||
> 从不调用本模块;环形缓冲由 `App/log/console_log.c` 内联实现(`s_con_ring`)。
|
||||
> 保留只会造成"有统一实现"的误导,故整体移除(详见 `docs/待处理内容.md` E-15 销项)。
|
||||
|
||||
## 设计要点
|
||||
|
||||
@@ -24,7 +24,12 @@
|
||||
|
||||
/*
|
||||
* 调试输出配置
|
||||
* 深调用链模块(ch395f_spi_fault_set 等出现在 netTask/ftpTask/timeSyncTask
|
||||
* 最坏链尾部):日志行缓冲收到 128 B(默认 192)。本模块最长行
|
||||
* "HAL_SPI_TransmitReceive_DMA FAIL: %d, SPI_State=%d, SPI_Error=0x%lX, DMA_State=%d"
|
||||
* 渲染后 ≈ 102 B(含时间戳 21 + 标签)< 128 → 不截断
|
||||
*/
|
||||
#define DBG_LINE_BUF_MAX 128U
|
||||
#define DBG_TAG "[CH395]"
|
||||
#include "dbg_log.h"
|
||||
|
||||
|
||||
@@ -16,7 +16,11 @@
|
||||
|
||||
/*
|
||||
* 调试输出配置
|
||||
* 深调用链模块(NAND 驱动在 FTL 之下):日志行缓冲收到 128 B(默认 192)。
|
||||
* 本模块最长行 "ID mismatch: expected MID=0x.. DID=0x.., got MID=0x.. DID=0x.."
|
||||
* 渲染后 ≈ 103 B(含时间戳 21 + 标签)< 128 → 不截断
|
||||
*/
|
||||
#define DBG_LINE_BUF_MAX 128U
|
||||
#define DBG_TAG "[NAND]"
|
||||
#include "dbg_log.h"
|
||||
|
||||
|
||||
@@ -26,6 +26,11 @@
|
||||
#define FTL_FATFS_OFFSET 0U
|
||||
|
||||
/* 调试输出配置 */
|
||||
/* 深调用链模块(FatFS → 本 FTL → dhara → NAND 是 defaultTask 最坏链的主干):
|
||||
* 日志行缓冲收到 128 B(默认 192)。本模块最长行 "[2026-10-10 08:00:00][ERR][NAND_FTL]
|
||||
* Cache flush failed: LPN=4294967295 err=-2147483648" ≈ 84 B < 128 → 不截断。
|
||||
* 核算 scripts/stack_report.py,见 docs/内存管理/RAM使用分析与优化方案.md */
|
||||
#define DBG_LINE_BUF_MAX 128U
|
||||
#define DBG_TAG "[NAND_FTL]"
|
||||
#include "dbg_log.h"
|
||||
|
||||
|
||||
@@ -25,7 +25,11 @@
|
||||
|
||||
/*
|
||||
* 调试输出配置
|
||||
* 深调用链模块(net_bind/net_send/net_poll 是 netTask/ftpTask/timeSyncTask
|
||||
* 最坏链的主干):日志行缓冲收到 128 B(默认 192)。本模块最长行渲染后
|
||||
* ≈ 100 B(含时间戳 21 + 标签)< 128 → 不截断
|
||||
*/
|
||||
#define DBG_LINE_BUF_MAX 128U
|
||||
#define DBG_TAG "[NET]"
|
||||
#include "dbg_log.h"
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Drivers/BSP/NETCFG/ — 网络配置
|
||||
|
||||
> 网络参数的**加载 / 保存 / 旧档迁移**(IP、掩码、网关等)。
|
||||
> 网络参数的**加载 / 保存**(IP、掩码、网关等)。
|
||||
> 本模块是**网络配置的持久化层**,与 `App/cfg/cfg_file.c`(配置引擎)配合工作。
|
||||
|
||||
## 文件一览
|
||||
@@ -8,12 +8,17 @@
|
||||
| 文件 | 作用 |
|
||||
|---|---|
|
||||
| `net_cfg.c/h` | 网络配置加载(`net_cfg_load`)/ 保存(`net_cfg_save_run`)+ RAM 副本管理 |
|
||||
| `net_cfg_legacy.c/h` | **旧版配置档迁移**(首启时把旧格式转换为当前格式) |
|
||||
|
||||
> **已删除(2026-10-10)**:`net_cfg_legacy.c/h`——旧二进制档 `/cfg/netcfg.bin` 的"首启自动迁移"。
|
||||
> 现口径:旧档若存在则被**忽略**(不读、不删、不迁移),配置直接回落工厂默认(`/config.ini`
|
||||
> `[network]` 段)。删除理由:该一次性路径把整条配置写链(`net_cfg_save → cfg_file_save →
|
||||
> cfg_store_write_atomic → f_rename → FatFS → dhara FTL`)挂进启动期调用图,使 defaultTask 的
|
||||
> armlink 静态最坏栈链 +600 B,而本仓库不存在携带旧档的设备。
|
||||
|
||||
## 工作流
|
||||
|
||||
```
|
||||
defaultTask:net_cfg_load(含旧档迁移)→ 置 STORAGE_READY
|
||||
defaultTask:net_cfg_load → 置 STORAGE_READY
|
||||
↓ (网络配置在屏障前已加载)
|
||||
netTask:只读 RAM 副本 → net_stack_bring_up(不在 netTask 里读盘)
|
||||
↓
|
||||
|
||||
@@ -2,8 +2,7 @@
|
||||
* 模块名称:Network Configuration Core (配置核心)
|
||||
* 模块功能:RAM 配置副本 + 工厂默认 + 加载/保存编排 + 实际 MAC 影子 +
|
||||
* IPv4 字符串转换;存储经 cfg_file 通用配置文件引擎(INI [network]
|
||||
* 段:ip/mask/gw/mac);旧版 NCFG 二进制格式归 net_cfg_legacy
|
||||
* (首启一次性迁移)
|
||||
* 段:ip/mask/gw/mac)
|
||||
* 适用平台:STM32F407ZGTx / PC 模拟器(两端共用)
|
||||
* 作者:王建锋
|
||||
* 创建日期:2026-09-10
|
||||
@@ -12,6 +11,12 @@
|
||||
* v1.1 2026-09-14 王建锋 存储迁移至 cfg_file 引擎(INI);旧 NCFG 代码移至 net_cfg_legacy
|
||||
* v1.2 2026-09-15 王建锋 保存改跨任务交接(request/state/run + 通知回调);
|
||||
* 引擎属主 = defaultTask(P1-3 竞态修复)
|
||||
* v1.3 2026-10-10 王建锋 **删除旧档 NCFG 迁移**(net_cfg_legacy 整体移除):该兼容
|
||||
* 路径把整条配置写链(net_cfg_save → cfg_file_save →
|
||||
* cfg_store_write_atomic → f_rename → FTL)挂进启动期调用图,
|
||||
* 使 defaultTask 静态最坏链 +600 B;本仓库无携带
|
||||
* /cfg/netcfg.bin 的设备,故按"不保留旧档兼容"处置。
|
||||
* 旧档若存在 → 被忽略(不读、不删、不迁移),配置回落工厂默认
|
||||
*/
|
||||
|
||||
/* 头文件包含区 */
|
||||
@@ -23,10 +28,11 @@
|
||||
|
||||
#include "net_cfg.h"
|
||||
|
||||
#include "net_cfg_legacy.h"
|
||||
|
||||
#include "cfg_file.h"
|
||||
|
||||
/* 深调用链模块(net_cfg_load/save 在 defaultTask 启动链与保存链上):
|
||||
* 日志行缓冲收到 128 B(默认 192),本模块最长行渲染后 < 128 → 不截断 */
|
||||
#define DBG_LINE_BUF_MAX 128U
|
||||
#define DBG_TAG "[NET_CFG]"
|
||||
#include "dbg_log.h"
|
||||
|
||||
@@ -140,9 +146,8 @@ static bool s_mac_is_zero(const uint8_t *p_mac) {
|
||||
int net_cfg_load(void) {
|
||||
s_net_register();
|
||||
|
||||
/* 首启先迁旧档 NCFG(有效 → 旧值物化进新文件);新文件已存在则跳过 */
|
||||
(void)net_cfg_legacy_migrate();
|
||||
|
||||
/* 旧档 NCFG 迁移已于 2026-10-10 删除(net_cfg_legacy 移除;理由见文件头 v1.3)。
|
||||
* 若卷上仍残留 /cfg/netcfg.bin:不读、不删、不迁移 → 配置回落工厂默认 */
|
||||
if (cfg_file_load() != 0) {
|
||||
/* 严重错误:引擎已将 RAM 副本复位工厂默认,行为仍安全 */
|
||||
DBG_ERROR("load: cfg_file_load FAIL");
|
||||
|
||||
@@ -7,8 +7,9 @@
|
||||
* = 不覆盖芯片内置 MAC。cfg_file 引擎为静态单任务设计,调用收敛于
|
||||
* 单一属主任务(MCU = defaultTask:就绪屏障前加载 / 保存执行 / 2s
|
||||
* poll;模拟器 = 主循环);UI 保存只投递请求,netTask 只读 RAM 副本
|
||||
* 函数说明:旧版 NCFG 二进制格式(magic+ver+CRC-16+18B 字段)归 net_cfg_legacy,
|
||||
* 首启一次性迁移进通用配置文件
|
||||
* 函数说明:旧版 NCFG 二进制格式(magic+ver+CRC-16+18B 字段)的迁移路径
|
||||
* (net_cfg_legacy)**已于 2026-10-10 删除** → 旧档 /cfg/netcfg.bin
|
||||
* 不再读取/迁移,携带旧档的设备升级后回落工厂默认(理由见 net_cfg.c v1.3)
|
||||
* 适用平台:STM32F407ZGTx / PC 模拟器(两端共用)
|
||||
* 作者:王建锋
|
||||
* 创建日期:2026-09-10
|
||||
|
||||
@@ -1,125 +0,0 @@
|
||||
/*
|
||||
* 模块名称:net_cfg_legacy
|
||||
* 模块功能:旧版 NCFG 二进制配置一次性迁移——读遗留文件 → 校验 magic/ver/CRC →
|
||||
* 填网络配置 RAM 副本 → 经 cfg_file 引擎生成新文件(带旧值)→ 删旧文件
|
||||
* 适用平台:STM32F407ZGTx / PC 模拟器(两端共用;平台路径经 cfg_file_store 后端)
|
||||
* 作者:王建锋
|
||||
* 创建日期:2026-09-14
|
||||
* 修改记录:
|
||||
* v1.0 2026-09-14 王建锋 创建初始版本(P3:net_cfg 引擎化,旧格式代码迁入)
|
||||
*/
|
||||
|
||||
/* 头文件包含区 */
|
||||
#include <string.h>
|
||||
|
||||
#include "net_cfg_legacy.h"
|
||||
|
||||
#include "net_cfg.h"
|
||||
|
||||
#include "cfg_file.h"
|
||||
|
||||
#include "cfg_file_store.h"
|
||||
|
||||
#define DBG_TAG "[NET_CFG]"
|
||||
#include "dbg_log.h"
|
||||
|
||||
/* 常量定义区 */
|
||||
|
||||
#define NET_CFG_MAGIC 0x4647434Eu /* 'NCFG'(文件字节序 N,C,G,F;小端装载) */
|
||||
#define NET_CFG_VER 1u /* 磁盘格式版本 */
|
||||
|
||||
/* 旧磁盘格式(两端布局一致:u32 4 对齐;字段区 18B 连续,CRC 覆盖之) */
|
||||
typedef struct {
|
||||
uint32_t magic; /* NET_CFG_MAGIC */
|
||||
uint16_t ver; /* 格式版本 */
|
||||
uint16_t crc; /* CRC-16/MODBUS(覆盖 ip..mac 共 18B) */
|
||||
uint8_t ip[4];
|
||||
uint8_t mask[4];
|
||||
uint8_t gw[4];
|
||||
uint8_t mac[6];
|
||||
} net_cfg_blob_t;
|
||||
|
||||
/* 静态函数声明区 */
|
||||
static uint16_t s_crc16_modbus(const uint8_t *p_data, size_t len);
|
||||
|
||||
/* 函数定义区 */
|
||||
|
||||
/*
|
||||
* 函数功能:CRC-16/MODBUS(无查表逐位算法)
|
||||
* 入口参数:p_data - 数据指针 const uint8_t *
|
||||
* len - 数据长度 size_t
|
||||
* 返回值:CRC-16 值 uint16_t
|
||||
* 限定条件:p_data 非空(len 可为 0,返回初始值 0xFFFF)
|
||||
* 函数说明:文件私有(数据量 ≤32B,性能无关)
|
||||
*/
|
||||
static uint16_t s_crc16_modbus(const uint8_t *p_data, size_t len) {
|
||||
uint16_t crc = 0xFFFFu;
|
||||
|
||||
for (size_t i = 0u; i < len; i++) {
|
||||
crc = (uint16_t)(crc ^ (uint16_t)p_data[i]);
|
||||
for (int b = 0; b < 8; b++) {
|
||||
if (crc & 0x0001u) {
|
||||
crc = (uint16_t)((crc >> 1) ^ 0xA001u);
|
||||
}
|
||||
else {
|
||||
crc = (uint16_t)(crc >> 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
return crc;
|
||||
}
|
||||
|
||||
/*
|
||||
* 函数功能:旧 NCFG 二进制配置一次性迁移到通用配置文件
|
||||
* 入口参数:无
|
||||
* 返回值:0 - 迁移成功,或无旧文件/新文件已存在(正常);-1 - 迁移失败 int
|
||||
* 限定条件:调用方须已注册 [network] 段(net_cfg_load 内部完成)
|
||||
* 函数说明:见 net_cfg_legacy.h 同名函数说明
|
||||
*/
|
||||
int net_cfg_legacy_migrate(void) {
|
||||
net_cfg_blob_t blob;
|
||||
uint8_t buf[32];
|
||||
size_t nread = 0u;
|
||||
cfg_file_stat_t st;
|
||||
net_cfg_t tmp;
|
||||
const char *p_legacy;
|
||||
|
||||
/* 新文件已存在 = 已迁移过(或已有配置):跳过 */
|
||||
if (cfg_store_stat(cfg_store_config_path(), &st) == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
p_legacy = cfg_store_legacy_path();
|
||||
if (cfg_store_read(p_legacy, buf, sizeof(buf), &nread) != 0
|
||||
|| nread != sizeof(net_cfg_blob_t)) {
|
||||
DBG_INFO("legacy: no legacy file, skip");
|
||||
return 0;
|
||||
}
|
||||
|
||||
(void)memcpy(&blob, buf, sizeof(blob));
|
||||
if (blob.magic != NET_CFG_MAGIC || blob.ver != NET_CFG_VER
|
||||
|| s_crc16_modbus(blob.ip, 18u) != blob.crc) {
|
||||
DBG_INFO("legacy: blob invalid (magic/ver/crc), file kept for inspection");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* 填 RAM 副本(net_cfg_get 只读,经 net_cfg_set 可写接口整体回灌)
|
||||
* → 经引擎物化旧值到新文件(此时新文件必缺失 → 生成模板带旧值) */
|
||||
(void)memcpy(&tmp, net_cfg_get(), sizeof(tmp));
|
||||
(void)memcpy(tmp.ip, blob.ip, 4u);
|
||||
(void)memcpy(tmp.mask, blob.mask, 4u);
|
||||
(void)memcpy(tmp.gw, blob.gw, 4u);
|
||||
(void)memcpy(tmp.mac, blob.mac, 6u);
|
||||
net_cfg_set(&tmp);
|
||||
|
||||
if (net_cfg_save() != 0) {
|
||||
DBG_ERROR("legacy: migrate save FAIL");
|
||||
return -1;
|
||||
}
|
||||
(void)cfg_store_remove(p_legacy);
|
||||
|
||||
DBG_INFO("legacy: migrated to config file (ip=%u.%u.%u.%u)",
|
||||
(unsigned)blob.ip[0], (unsigned)blob.ip[1],
|
||||
(unsigned)blob.ip[2], (unsigned)blob.ip[3]);
|
||||
return 0;
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
/*
|
||||
* 模块名称:net_cfg_legacy
|
||||
* 模块功能:旧版 NCFG 二进制配置一次性迁移到通用配置文件(net_cfg 旧磁盘格式
|
||||
* 的拥有者:magic 'NCFG' + ver + CRC-16/MODBUS + 18B 字段)
|
||||
* 适用平台:STM32F407ZGTx / PC 模拟器(两端共用;平台路径经 cfg_file_store 后端)
|
||||
* 作者:王建锋
|
||||
* 创建日期:2026-09-14
|
||||
* 修改记录:
|
||||
* v1.0 2026-09-14 王建锋 创建初始版本(P3:net_cfg 引擎化,旧格式代码迁入)
|
||||
*/
|
||||
|
||||
#ifndef NET_CFG_LEGACY_H
|
||||
#define NET_CFG_LEGACY_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*
|
||||
* 函数功能:旧 NCFG 二进制配置(28B)一次性迁移到通用配置文件
|
||||
* 入口参数:无
|
||||
* 返回值:0 - 迁移成功,或无旧文件/新文件已存在(正常);
|
||||
* -1 - 迁移失败(新文件未生成) int
|
||||
* 限定条件:调用方须已注册 [network] 段(net_cfg_load 内部完成)
|
||||
* 函数说明:新文件已存在 → 跳过(已迁移过);旧文件有效 → 填网络配置 RAM
|
||||
* 副本 → 经引擎生成新文件(带旧值)→ 删旧文件;旧文件缺失/无效 →
|
||||
* 不动旧文件(留人工检查),新文件按工厂默认生成
|
||||
*/
|
||||
int net_cfg_legacy_migrate(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* NET_CFG_LEGACY_H */
|
||||
@@ -13,7 +13,7 @@
|
||||
| `SD2506/` | SD2506 RTC | I2C | 实时时钟驱动 | `docs/问题记录/SD2506_Trap_Records.md` |
|
||||
| `RS485/` | RS-485 半双工 | UART5 | 收发方向控制(DE 引脚)+ 时序 | — |
|
||||
| `NET/` | BSD Socket 网络抽象层 | — | Socket API + select + 轻量 FTP 服务器 | `docs/网络/`(含 `Net层阻塞模型架构设计.md`) |
|
||||
| `NETCFG/` | 网络配置 | — | `/config.ini` 网络段的加载/保存 + 旧档迁移 | `docs/子系统设计/网络配置说明.md` |
|
||||
| `NETCFG/` | 网络配置 | — | `/config.ini` 网络段的加载/保存(旧 NCFG 档已删除,2026-10-10) | `docs/子系统设计/网络配置说明.md` |
|
||||
| `UI/` | LVGL UI 组件 | — | 菜单/内容页/组件/中文字体 | `docs/UI设计/` |
|
||||
|
||||
## 根级文件
|
||||
|
||||
+60
-23
@@ -42,12 +42,49 @@ extern "C" {
|
||||
*/
|
||||
#ifdef DBG_ENABLE
|
||||
|
||||
/*
|
||||
* 行缓冲上限(栈预算旋钮,2026-10-10 加)
|
||||
* 默认 = 控制台单行上限 DBG_CON_LINE_MAX(192)。
|
||||
* ⚠ 本数组是**在每个日志调用点的栈帧里内联**的,会进 armlink 最坏调用链:
|
||||
* 实测存储/配置那条链上 9 个帧各含 192 B 行缓冲 + 32 B 时间戳缓冲
|
||||
* → defaultTask 静态最坏链 5312 B 里约 1.5 KB 纯粹是日志行缓冲。
|
||||
* 故**深调用链模块**(存储 FTL/NAND、配置引擎、网络驱动、时间同步)应在
|
||||
* 包含本文件前显式收紧,例如 `#define DBG_LINE_BUF_MAX 128U`;
|
||||
* 取值须 ≥ 该模块最长日志行(含时间戳 20 + 标签 + 正文),否则该行被截断。
|
||||
* 核算:scripts/stack_report.py(改前/改后各跑一次)
|
||||
*/
|
||||
#ifndef DBG_LINE_BUF_MAX
|
||||
#define DBG_LINE_BUF_MAX DBG_CON_LINE_MAX
|
||||
#endif
|
||||
|
||||
/*
|
||||
* 时间戳文本缓冲上限:sys_clock_get_str() 恒写 "----/--/-- --:--:--" 或
|
||||
* "%04d-%02d-%02d %02d:%02d:%02d" = 19 字符 + '\0' → 24 足够(原 32 是随手取整,
|
||||
* 每个日志调用点白占 8 B 栈)
|
||||
*/
|
||||
#define DBG_TS_BUF_MAX 24U
|
||||
|
||||
/*
|
||||
* 有界格式化 + 交单写者控制台(行缓冲由调用方提供,便于与时间戳缓冲共用数组)
|
||||
*/
|
||||
#define DBG_EMIT(p_line, ...) do { \
|
||||
int __con_n = snprintf((p_line), DBG_LINE_BUF_MAX, __VA_ARGS__); \
|
||||
if (__con_n > 0) { \
|
||||
unsigned __con_len = (__con_n >= (int)DBG_LINE_BUF_MAX) \
|
||||
? (unsigned)(DBG_LINE_BUF_MAX - 1u) : (unsigned)__con_n; \
|
||||
(void)dbg_console_write_line((p_line), __con_len); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
/*
|
||||
* 可重定向的打印函数,用户可在编译选项或 net_config.h 中预定义
|
||||
* #define DBG_PRINT(...) my_printf(__VA_ARGS__)
|
||||
* ⚠ 2026-10-10 起:带时间戳的 DBG_ERROR/DBG_INFO/DBG_DEBUG 走 **DBG_EMIT**
|
||||
* (与行缓冲共用一个数组,省一帧栈);要整体改道请重定义 `DBG_EMIT(p_line, ...)`
|
||||
* ——它是所有日志的唯一落地点。只定义 DBG_PRINT 仅影响不带时间戳的 DBG_PRINT。
|
||||
*
|
||||
* 默认走单写者控制台(App/log/console_log.c):
|
||||
* DBG_PRINT 在调用点用库 snprintf 有界格式化整行,再一次性交给 dbg_console_write_line
|
||||
* DBG_EMIT 在调用点用库 snprintf 有界格式化整行,再一次性交给 dbg_console_write_line
|
||||
* 入环形缓冲,由 defaultTask 唯一发送——
|
||||
* ① 行与行不会字符级交错(旧 printf→fputc 每字符一次 HAL_UART_Transmit 会交错);
|
||||
* ② 进 UART 的缓冲恒为控制台内部缓冲,调用方脏指针到不了 UART
|
||||
@@ -55,13 +92,8 @@ extern "C" {
|
||||
*/
|
||||
#ifndef DBG_PRINT
|
||||
#define DBG_PRINT(...) do { \
|
||||
char __con_line[DBG_CON_LINE_MAX]; \
|
||||
int __con_n = snprintf(__con_line, sizeof(__con_line), __VA_ARGS__); \
|
||||
if (__con_n > 0) { \
|
||||
unsigned __con_len = (__con_n >= (int)sizeof(__con_line)) \
|
||||
? (unsigned)(sizeof(__con_line) - 1u) : (unsigned)__con_n; \
|
||||
(void)dbg_console_write_line(__con_line, __con_len); \
|
||||
} \
|
||||
char __con_line[DBG_LINE_BUF_MAX]; \
|
||||
DBG_EMIT(__con_line, __VA_ARGS__); \
|
||||
} while (0)
|
||||
#endif
|
||||
|
||||
@@ -75,29 +107,34 @@ extern "C" {
|
||||
|
||||
#ifdef APP_TIMESTAMP_ENABLE
|
||||
/*
|
||||
* 时间戳输出宏 — 在日志行首追加 [YYYY-MM-DD HH:MM:SS] 格式的系统墙钟时间
|
||||
* sys_clock_get_str() 线程安全(内部使用 DWT US 计数,无锁)
|
||||
* 兼容宏:单独取时间戳文本(当前无调用者;缓冲为复合字面量,仅在本表达式内有效)
|
||||
*/
|
||||
#define DBG_TS() sys_clock_get_str((char[32]){0}, 32)
|
||||
#define DBG_TS() sys_clock_get_str((char[DBG_TS_BUF_MAX]){0}, DBG_TS_BUF_MAX)
|
||||
|
||||
/*
|
||||
* DBG_ERROR / DBG_INFO / DBG_DEBUG(带时间戳版)
|
||||
* 时间戳缓冲与行缓冲**共用一个数组**(每个调用点省一帧 24 B 栈):行文本占前
|
||||
* DBG_LINE_BUF_MAX 字节,时间戳文本切片自其后。snprintf 的全部实参先于其执行
|
||||
* 求值完毕,故"先写时间戳切片、再格式化行首"不冲突。
|
||||
*/
|
||||
/*
|
||||
* DBG_ERROR - 错误输出,受 DBG_ENABLE + APP_TIMESTAMP_ENABLE 控制
|
||||
*/
|
||||
#define DBG_ERROR(fmt, ...) do { \
|
||||
char __ts_buf[32]; \
|
||||
(void)__ts_buf; \
|
||||
DBG_PRINT("[%s]" "[ERR]" DBG_TAG " " fmt "\r\n", \
|
||||
sys_clock_get_str(__ts_buf, sizeof(__ts_buf)), ##__VA_ARGS__); \
|
||||
char __con_line[DBG_LINE_BUF_MAX + DBG_TS_BUF_MAX]; \
|
||||
DBG_EMIT(__con_line, "[%s]" "[ERR]" DBG_TAG " " fmt "\r\n", \
|
||||
sys_clock_get_str(__con_line + DBG_LINE_BUF_MAX, DBG_TS_BUF_MAX), \
|
||||
##__VA_ARGS__); \
|
||||
} while (0)
|
||||
|
||||
/*
|
||||
* DBG_INFO - 信息输出,受 DBG_ENABLE + APP_TIMESTAMP_ENABLE 控制
|
||||
*/
|
||||
#define DBG_INFO(fmt, ...) do { \
|
||||
char __ts_buf[32]; \
|
||||
(void)__ts_buf; \
|
||||
DBG_PRINT("[%s]" DBG_TAG " " fmt "\r\n", \
|
||||
sys_clock_get_str(__ts_buf, sizeof(__ts_buf)), ##__VA_ARGS__); \
|
||||
char __con_line[DBG_LINE_BUF_MAX + DBG_TS_BUF_MAX]; \
|
||||
DBG_EMIT(__con_line, "[%s]" DBG_TAG " " fmt "\r\n", \
|
||||
sys_clock_get_str(__con_line + DBG_LINE_BUF_MAX, DBG_TS_BUF_MAX), \
|
||||
##__VA_ARGS__); \
|
||||
} while (0)
|
||||
|
||||
/*
|
||||
@@ -105,10 +142,10 @@ extern "C" {
|
||||
*/
|
||||
#ifdef DBG_DEBUG_ENABLE
|
||||
#define DBG_DEBUG(fmt, ...) do { \
|
||||
char __ts_buf[32]; \
|
||||
(void)__ts_buf; \
|
||||
DBG_PRINT("[%s]" DBG_TAG "(%s:%d) " fmt "\r\n", \
|
||||
sys_clock_get_str(__ts_buf, sizeof(__ts_buf)), __func__, __LINE__, ##__VA_ARGS__); \
|
||||
char __con_line[DBG_LINE_BUF_MAX + DBG_TS_BUF_MAX]; \
|
||||
DBG_EMIT(__con_line, "[%s]" DBG_TAG "(%s:%d) " fmt "\r\n", \
|
||||
sys_clock_get_str(__con_line + DBG_LINE_BUF_MAX, DBG_TS_BUF_MAX), \
|
||||
__func__, __LINE__, ##__VA_ARGS__); \
|
||||
} while (0)
|
||||
#else
|
||||
#define DBG_DEBUG(fmt, ...)
|
||||
|
||||
@@ -1458,11 +1458,6 @@
|
||||
<FileType>1</FileType>
|
||||
<FilePath>..\Drivers\BSP\NETCFG\net_cfg.c</FilePath>
|
||||
</File>
|
||||
<File>
|
||||
<FileName>net_cfg_legacy.c</FileName>
|
||||
<FileType>1</FileType>
|
||||
<FilePath>..\Drivers\BSP\NETCFG\net_cfg_legacy.c</FilePath>
|
||||
</File>
|
||||
<File>
|
||||
<FileName>nand_ftl.c</FileName>
|
||||
<FileType>1</FileType>
|
||||
|
||||
@@ -130,7 +130,7 @@ STM32F4-Base/
|
||||
│ │ │ ├── net_socket.c/h # Socket API
|
||||
│ │ │ ├── net_select.c/h # select/poll 多路复用
|
||||
│ │ │ └── lftpd/ # 轻量 FTP 服务器
|
||||
│ │ ├── NETCFG/ # 网络配置(加载/保存/旧档迁移)
|
||||
│ │ ├── NETCFG/ # 网络配置(/config.ini [network] 段加载/保存)
|
||||
│ │ ├── UI/ # LVGL UI 组件
|
||||
│ │ └── dbg_log.h / dbg_cfg.h # 调试日志(DBG_INFO 等)
|
||||
│ ├── STM32F4xx_HAL_Driver/ # ST HAL 库
|
||||
|
||||
+28
-11
@@ -94,15 +94,24 @@ static int hook_ptr_ok(const void *p)
|
||||
* defaultTask 1024 words:扛 mount+mkfs+FAT 探针+cfg 加载+syslog 写+配置引擎
|
||||
* (全深层 FatFS I/O)。原 512,2KB 实测峰值溢出——开启
|
||||
* configCHECK_FOR_STACK_OVERFLOW=2 后被钩子抓到(2026-09-21)。
|
||||
* netTask 960 words:静态最坏链 2664 B(发送停滞→断连→重监听→SPI 故障→日志尾,
|
||||
* 真实直调链,日志主导:链上 5 帧各含 192 B __con_line + 尾部 ~696 B);3840 B
|
||||
* 配置余量 1176 B(30.6%),过 stack_report 规则。运行时水位仅 ~1.1 KB(错误尾未
|
||||
* 2026-10-10 栈整改(**未抬栈**,靠削链达标):静态最坏链 5312 → 2776 B、
|
||||
* 实测峰值 3392 → 2152 B(余 1944 B / 47%)。四个杠杆:① 删旧档 NCFG 迁移
|
||||
* (net_cfg_legacy,−600 B 链);② 6 处局部 `FIL` 改函数级 static(FF_FS_TINY=0
|
||||
* → 单个 FIL = 528 B 栈);③ 日志行缓冲按模块收紧 `DBG_LINE_BUF_MAX 128`
|
||||
* + 时间戳缓冲并入行缓冲(每个日志调用点原内联 192+32 B);④ 断言/故障钩子
|
||||
* 脱离 HAL 发送回退 + 缓冲静态化(configASSERT 在 FreeRTOS 内部可达 →
|
||||
* 钩子在**每个**任务的最坏链尾)。详见 docs/内存管理/RAM使用分析与优化方案.md
|
||||
* netTask 960 words:静态最坏链 1872 B(2026-10-10 整改后;整改前 2664 B:
|
||||
* 发送停滞→断连→重监听→SPI 故障→日志尾,日志主导);3840 B 配置余量 1968 B
|
||||
* (51%),过 stack_report 规则。运行时水位仅 ~0.9 KB(错误尾未
|
||||
* 触发,不可作依据)。曾试 net_drain_chip_rx scratch 静态化,实测仅省 16 B 栈
|
||||
* (ARMCC 已叠放不重叠局部量)反增 256 B BSS,已回退——见 net_socket.c 注释。
|
||||
* testTask 2048 words:存储套件 deep call chain + 局部缓冲,原 1024(4 KB)实测溢出
|
||||
* (2026-09-20)。仅启用测试套件时创建。
|
||||
* timeSyncTask 512 words:本区下方手工定义(不在 `.ioc` 的 Tasks01 里 → 重生成会丢,
|
||||
* 靠审计 WARN 提示),只做读 RTC + 置就绪事件位,无深调用链。
|
||||
* 靠审计 WARN 提示),建监听 → net_bind → CH395F → 日志尾。2026-10-10 整改后
|
||||
* 静态最坏链 1024 B(整改前 1736 B)、实测峰值 616 B;⚠ 余量 1024 B **正好**
|
||||
* 等于 ISR 底线 → 本任务链上再加任何调用(或新日志行)都必须先抬栈。
|
||||
*/
|
||||
/* 存储测试变量(g_storage_stats / s_perf_buf)已迁至 test/board/storage_test_task.c */
|
||||
osThreadId_t timeSyncTaskHandle;
|
||||
@@ -435,7 +444,10 @@ void vApplicationAssertFailed(const char *file, long line)
|
||||
{
|
||||
static const char msg_head[] = "\r\n[ERR] ASSERT FAILED ";
|
||||
const char *p = file;
|
||||
char num[16];
|
||||
/* 缓冲一律 static(不放栈上):本钩子是"内核状态已不可信"的终点路径,打印完即
|
||||
* 复位,不存在并发/重入;放栈上会让 armlink 把这 81 B 挂进每个任务的最坏链
|
||||
* (configASSERT 在 FreeRTOS 内部可达 → 每条链尾都有本钩子) */
|
||||
static char num[16];
|
||||
int i;
|
||||
|
||||
/* 文件名只取末段(全路径太长且无信息量) */
|
||||
@@ -449,8 +461,8 @@ void vApplicationAssertFailed(const char *file, long line)
|
||||
}
|
||||
/* 有界拷贝:上限 48 字符 */
|
||||
{
|
||||
static char name[49]; /* static 存储(见上),作用域收到本块 */
|
||||
uint16_t len = 0u;
|
||||
char name[49];
|
||||
while ((len < 48u) && (p[len] != '\0')) {
|
||||
name[len] = p[len];
|
||||
len++;
|
||||
@@ -471,21 +483,26 @@ void vApplicationAssertFailed(const char *file, long line)
|
||||
if (line <= 0) {
|
||||
num[i++] = '0';
|
||||
} else {
|
||||
char rev[16];
|
||||
int n = 0;
|
||||
int j;
|
||||
|
||||
while ((line > 0) && (n < 15)) {
|
||||
rev[n++] = (char)('0' + (line % 10));
|
||||
num[n++] = (char)('0' + (line % 10)); /* 先逆序填入 */
|
||||
line /= 10;
|
||||
}
|
||||
while (n > 0) {
|
||||
num[i++] = rev[--n];
|
||||
for (j = 0; j < n / 2; j++) { /* 原地反转:省一个 16 B 缓冲 */
|
||||
char t = num[j];
|
||||
num[j] = num[n - 1 - j];
|
||||
num[n - 1 - j] = t;
|
||||
}
|
||||
i = n;
|
||||
}
|
||||
dbg_console_write_raw(num, (unsigned)i);
|
||||
|
||||
dbg_console_write_raw(" (resetting)\r\n", 15u);
|
||||
|
||||
HAL_Delay(200); /* 等 UART 移位寄存器排空 */
|
||||
/* 无需 HAL_Delay:dbg_console_write_raw → con_tx_bounded 已等到 TC(移位寄存器
|
||||
* 排空)才返回;去掉 HAL_Delay 亦少一条 HAL 依赖(断言现场 tick 未必可信) */
|
||||
NVIC_SystemReset();
|
||||
}
|
||||
/* USER CODE END Application */
|
||||
|
||||
+1
-1
@@ -80,7 +80,7 @@ docs/
|
||||
|
||||
| 文档 | 内容 |
|
||||
|---|---|
|
||||
| [`配置文件设计说明.md`](子系统设计/配置文件设计说明.md) | `/config.ini` 配置引擎:分层、解析、持久化与旧档迁移 |
|
||||
| [`配置文件设计说明.md`](子系统设计/配置文件设计说明.md) | `/config.ini` 配置引擎:分层、解析、原子持久化(旧 NCFG 档已废弃) |
|
||||
| [`网络配置说明.md`](子系统设计/网络配置说明.md) | 网口设置页:IP/掩码/网关,UI 保存即时生效 |
|
||||
| [`系统墙钟时间维护说明.md`](子系统设计/系统墙钟时间维护说明.md) | `sys_clock`:RTC 基准、tick 回绕防护、30 天惰性再基准化 |
|
||||
| [`控制台单写者日志设计说明.md`](子系统设计/控制台单写者日志设计说明.md) | 控制台日志单写者模型(避免多任务交错输出) |
|
||||
|
||||
+14
-14
@@ -8,39 +8,39 @@
|
||||
</style>
|
||||
</defs>
|
||||
<text x="440.0" y="22" text-anchor="middle" class="title">FreeRTOS 任务栈预算(48KB 堆,2026-09-21 已迁 CCM)</text>
|
||||
<text x="440.0" y="40" text-anchor="middle" class="legend-text" fill="#777">数据: 2026-09-21 @build + FTP 128KB 实测(data/stack_report_20260921.md)</text>
|
||||
<text x="440.0" y="40" text-anchor="middle" class="legend-text" fill="#777">数据: 2026-10-10 @build + 开机/空闲实测(data/stack_report_20261010.md);最坏 = max(静态最坏链, 实测峰值)</text>
|
||||
<text x="190" y="54" class="legend-text" fill="#555">浅色条 = 分配栈 深色条 = 最坏占用(max(静态最坏, 实测峰值)) 下方文字 = 实测余量/判定</text>
|
||||
<text x="186" y="72" text-anchor="end" dominant-baseline="central" class="label" fill="#333">defaultTask</text>
|
||||
<rect class="bar-seg" x="190" y="64" width="162.5" height="16" fill="#BBDEFB" rx="3"/>
|
||||
<rect x="190" y="64" width="110.1" height="16" fill="#2196F3" rx="3"/>
|
||||
<text x="190" y="91" dominant-baseline="central" class="legend-text" fill="#333">配置 4096B | 实测峰值 2136B | 最坏 2776B | 余量 1320B (32%) <tspan fill="#2E7D32" font-weight="bold">PASS</tspan></text>
|
||||
<text x="190" y="91" dominant-baseline="central" class="legend-text" fill="#333">配置 4096B | 实测峰值 2152B | 最坏 2776B | 余量 1320B (32%) <tspan fill="#2E7D32" font-weight="bold">PASS</tspan></text>
|
||||
<text x="186" y="112" text-anchor="end" dominant-baseline="central" class="label" fill="#333">netTask</text>
|
||||
<rect class="bar-seg" x="190" y="104" width="162.5" height="16" fill="#BBDEFB" rx="3"/>
|
||||
<rect x="190" y="104" width="23.3" height="16" fill="#2196F3" rx="3"/>
|
||||
<text x="190" y="131" dominant-baseline="central" class="legend-text" fill="#333">配置 4096B | 实测峰值 588B | 最坏 588B | 余量 3508B (85%) <tspan fill="#2E7D32" font-weight="bold">PASS</tspan></text>
|
||||
<rect class="bar-seg" x="190" y="104" width="152.3" height="16" fill="#BBDEFB" rx="3"/>
|
||||
<rect x="190" y="104" width="74.3" height="16" fill="#2196F3" rx="3"/>
|
||||
<text x="190" y="131" dominant-baseline="central" class="legend-text" fill="#333">配置 3840B | 实测峰值 920B | 最坏 1872B | 余量 1968B (51%) <tspan fill="#2E7D32" font-weight="bold">PASS</tspan></text>
|
||||
<text x="186" y="152" text-anchor="end" dominant-baseline="central" class="label" fill="#333">ftpTask</text>
|
||||
<rect class="bar-seg" x="190" y="144" width="162.5" height="16" fill="#BBDEFB" rx="3"/>
|
||||
<rect x="190" y="144" width="47.0" height="16" fill="#2196F3" rx="3"/>
|
||||
<text x="190" y="171" dominant-baseline="central" class="legend-text" fill="#333">配置 4096B | 实测峰值 1184B | 最坏 1184B | 余量 2912B (71%) <tspan fill="#2E7D32" font-weight="bold">PASS</tspan></text>
|
||||
<rect x="190" y="144" width="48.2" height="16" fill="#2196F3" rx="3"/>
|
||||
<text x="190" y="171" dominant-baseline="central" class="legend-text" fill="#333">配置 4096B | 实测峰值 740B | 最坏 1216B | 余量 2880B (70%) <tspan fill="#2E7D32" font-weight="bold">PASS</tspan></text>
|
||||
<text x="186" y="192" text-anchor="end" dominant-baseline="central" class="label" fill="#333">testTask</text>
|
||||
<rect class="bar-seg" x="190" y="184" width="325.0" height="16" fill="#FFE0B2" rx="3"/>
|
||||
<rect x="190" y="184" width="13.8" height="16" fill="#FF9800" rx="3"/>
|
||||
<text x="190" y="211" dominant-baseline="central" class="legend-text" fill="#333">配置 8192B | 实测峰值 348B | 最坏 348B | 余量 7844B (95%) <tspan fill="#2E7D32" font-weight="bold">PASS</tspan></text>
|
||||
<rect x="190" y="184" width="19.7" height="16" fill="#FF9800" rx="3"/>
|
||||
<text x="190" y="211" dominant-baseline="central" class="legend-text" fill="#333">配置 8192B | 实测峰值 496B | 最坏 496B | 余量 7696B (93%) <tspan fill="#2E7D32" font-weight="bold">PASS</tspan></text>
|
||||
<text x="186" y="232" text-anchor="end" dominant-baseline="central" class="label" fill="#333">uiTask</text>
|
||||
<rect class="bar-seg" x="190" y="224" width="650.0" height="16" fill="#FFE0B2" rx="3"/>
|
||||
<rect x="190" y="224" width="151.7" height="16" fill="#FF9800" rx="3"/>
|
||||
<text x="190" y="251" dominant-baseline="central" class="legend-text" fill="#333">配置 16384B | 实测峰值 3824B | 最坏 3824B | 余量 12560B (76%) <tspan fill="#2E7D32" font-weight="bold">PASS</tspan></text>
|
||||
<rect x="190" y="224" width="159.3" height="16" fill="#FF9800" rx="3"/>
|
||||
<text x="190" y="251" dominant-baseline="central" class="legend-text" fill="#333">配置 16384B | 实测峰值 4016B | 最坏 4016B | 余量 12368B (75%) <tspan fill="#2E7D32" font-weight="bold">PASS</tspan></text>
|
||||
<text x="186" y="272" text-anchor="end" dominant-baseline="central" class="label" fill="#333">timeSyncTask</text>
|
||||
<rect class="bar-seg" x="190" y="264" width="81.2" height="16" fill="#BBDEFB" rx="3"/>
|
||||
<rect x="190" y="264" width="16.7" height="16" fill="#2196F3" rx="3"/>
|
||||
<text x="190" y="291" dominant-baseline="central" class="legend-text" fill="#333">配置 2048B | 实测峰值 420B | 最坏 420B | 余量 1628B (79%) <tspan fill="#2E7D32" font-weight="bold">PASS</tspan></text>
|
||||
<rect x="190" y="264" width="40.6" height="16" fill="#2196F3" rx="3"/>
|
||||
<text x="190" y="291" dominant-baseline="central" class="legend-text" fill="#333">配置 2048B | 实测峰值 616B | 最坏 1024B | 余量 1024B (50%) <tspan fill="#2E7D32" font-weight="bold">PASS</tspan></text>
|
||||
<text x="186" y="314" text-anchor="end" dominant-baseline="central" class="label" fill="#333">idle</text>
|
||||
<rect class="bar-seg" x="190" y="308" width="20.3" height="12" fill="#90A4AE" rx="2"/>
|
||||
<text x="214.3125" y="314" dominant-baseline="central" class="legend-text" fill="#333">512B(未实测)</text>
|
||||
<text x="186" y="336" text-anchor="end" dominant-baseline="central" class="label" fill="#333">timer</text>
|
||||
<rect class="bar-seg" x="190" y="330" width="40.6" height="12" fill="#90A4AE" rx="2"/>
|
||||
<text x="234.625" y="336" dominant-baseline="central" class="legend-text" fill="#333">1024B(未实测)</text>
|
||||
<text x="190" y="360" class="label" fill="#555">堆总量: 49152B (48KB, RW_CCM) 任务栈合计: 38912B (38.0KB) + 内核栈 1536B</text>
|
||||
<text x="190" y="360" class="label" fill="#555">堆总量: 49152B (48KB, RW_CCM) 任务栈合计: 38656B (37.8KB) + 内核栈 1536B</text>
|
||||
<text x="190" y="376" class="label" fill="#555">实测: free=8784B / min_ever=4848B(2026-09-21,含 FTP 负载) 判定: 6/6 PASS(余量 ≥ max(1024B, 配置×30%))</text>
|
||||
<rect x="190" y="400" width="10" height="10" fill="#2196F3" rx="2"/>
|
||||
<text x="204" y="408" class="legend-text" fill="#333">Normal 优先级</text>
|
||||
|
||||
|
Before Width: | Height: | Size: 5.1 KiB After Width: | Height: | Size: 5.1 KiB |
+11
-10
@@ -47,8 +47,6 @@ digraph refgraph_full {
|
||||
"Drivers/BSP/NET/net_types.h" [fillcolor="#dbeafe", color="#1d4ed8"];
|
||||
"Drivers/BSP/NETCFG/net_cfg.c" [fillcolor="#dbeafe", color="#1d4ed8"];
|
||||
"Drivers/BSP/NETCFG/net_cfg.h" [fillcolor="#dbeafe", color="#1d4ed8"];
|
||||
"Drivers/BSP/NETCFG/net_cfg_legacy.c" [fillcolor="#dbeafe", color="#1d4ed8"];
|
||||
"Drivers/BSP/NETCFG/net_cfg_legacy.h" [fillcolor="#dbeafe", color="#1d4ed8"];
|
||||
"Drivers/BSP/RS485/rs485.c" [fillcolor="#dbeafe", color="#1d4ed8"];
|
||||
"Drivers/BSP/RS485/rs485.h" [fillcolor="#dbeafe", color="#1d4ed8"];
|
||||
"Drivers/BSP/SD2506/sd2506.c" [fillcolor="#dbeafe", color="#1d4ed8"];
|
||||
@@ -93,6 +91,7 @@ digraph refgraph_full {
|
||||
"Drivers/BSP/dbg_log.h" [fillcolor="#dbeafe", color="#1d4ed8"];
|
||||
"Drivers/CMSIS/Device/ST/STM32F4xx/Include/stm32f4xx.h" [fillcolor="#f3f4f6", color="#9ca3af"];
|
||||
"Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal.h" [fillcolor="#f3f4f6", color="#9ca3af"];
|
||||
"Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal_adc.h" [fillcolor="#f3f4f6", color="#9ca3af"];
|
||||
"Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal_cortex.h" [fillcolor="#f3f4f6", color="#9ca3af"];
|
||||
"Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal_dma.h" [fillcolor="#f3f4f6", color="#9ca3af"];
|
||||
"Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal_exti.h" [fillcolor="#f3f4f6", color="#9ca3af"];
|
||||
@@ -106,6 +105,7 @@ digraph refgraph_full {
|
||||
"Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal_tim.h" [fillcolor="#f3f4f6", color="#9ca3af"];
|
||||
"Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal_uart.h" [fillcolor="#f3f4f6", color="#9ca3af"];
|
||||
"Inc/FreeRTOSConfig.h" [fillcolor="#dbeafe", color="#1d4ed8"];
|
||||
"Inc/adc.h" [fillcolor="#dbeafe", color="#1d4ed8"];
|
||||
"Inc/dma.h" [fillcolor="#dbeafe", color="#1d4ed8"];
|
||||
"Inc/gpio.h" [fillcolor="#dbeafe", color="#1d4ed8"];
|
||||
"Inc/i2c.h" [fillcolor="#dbeafe", color="#1d4ed8"];
|
||||
@@ -124,6 +124,7 @@ digraph refgraph_full {
|
||||
"Middlewares/Third_Party/FreeRTOS/Source/CMSIS_RTOS_V2/cmsis_os2.h" [fillcolor="#f3f4f6", color="#9ca3af"];
|
||||
"Middlewares/Third_Party/FreeRTOS/Source/include/FreeRTOS.h" [fillcolor="#f3f4f6", color="#9ca3af"];
|
||||
"Middlewares/Third_Party/FreeRTOS/Source/include/task.h" [fillcolor="#f3f4f6", color="#9ca3af"];
|
||||
"Src/adc.c" [fillcolor="#dbeafe", color="#1d4ed8"];
|
||||
"Src/dma.c" [fillcolor="#dbeafe", color="#1d4ed8"];
|
||||
"Src/freertos.c" [fillcolor="#dbeafe", color="#1d4ed8"];
|
||||
"Src/gpio.c" [fillcolor="#dbeafe", color="#1d4ed8"];
|
||||
@@ -207,7 +208,6 @@ digraph refgraph_full {
|
||||
"App/fs/vol_lock.h" -> "外部/系统头文件" [color="#f59e0b", penwidth=0.6, style=dashed];
|
||||
"App/log/console_log.c" -> "App/app/sys_events.h" [color="#2563eb", penwidth=1.0];
|
||||
"App/log/console_log.c" -> "App/log/console_log.h" [color="#2563eb", penwidth=1.0];
|
||||
"App/log/console_log.c" -> "App/log/sys_log.h" [color="#2563eb", penwidth=1.0];
|
||||
"App/log/console_log.c" -> "Inc/usart.h" [color="#2563eb", penwidth=1.0];
|
||||
"App/log/console_log.c" -> "Middlewares/Third_Party/FreeRTOS/Source/CMSIS_RTOS_V2/cmsis_os.h" [color="#94a3b8", penwidth=0.7];
|
||||
"App/log/console_log.c" -> "Middlewares/Third_Party/FreeRTOS/Source/include/FreeRTOS.h" [color="#94a3b8", penwidth=0.7];
|
||||
@@ -343,16 +343,9 @@ digraph refgraph_full {
|
||||
"Drivers/BSP/NET/net_types.h" -> "外部/系统头文件" [color="#f59e0b", penwidth=0.6, style=dashed];
|
||||
"Drivers/BSP/NETCFG/net_cfg.c" -> "App/cfg/cfg_file.h" [color="#2563eb", penwidth=1.0];
|
||||
"Drivers/BSP/NETCFG/net_cfg.c" -> "Drivers/BSP/NETCFG/net_cfg.h" [color="#2563eb", penwidth=1.0];
|
||||
"Drivers/BSP/NETCFG/net_cfg.c" -> "Drivers/BSP/NETCFG/net_cfg_legacy.h" [color="#2563eb", penwidth=1.0];
|
||||
"Drivers/BSP/NETCFG/net_cfg.c" -> "Drivers/BSP/dbg_log.h" [color="#2563eb", penwidth=1.0];
|
||||
"Drivers/BSP/NETCFG/net_cfg.c" -> "外部/系统头文件" [color="#f59e0b", penwidth=0.6, style=dashed];
|
||||
"Drivers/BSP/NETCFG/net_cfg.h" -> "外部/系统头文件" [color="#f59e0b", penwidth=0.6, style=dashed];
|
||||
"Drivers/BSP/NETCFG/net_cfg_legacy.c" -> "App/cfg/cfg_file.h" [color="#2563eb", penwidth=1.0];
|
||||
"Drivers/BSP/NETCFG/net_cfg_legacy.c" -> "App/cfg/cfg_file_store.h" [color="#2563eb", penwidth=1.0];
|
||||
"Drivers/BSP/NETCFG/net_cfg_legacy.c" -> "Drivers/BSP/NETCFG/net_cfg.h" [color="#2563eb", penwidth=1.0];
|
||||
"Drivers/BSP/NETCFG/net_cfg_legacy.c" -> "Drivers/BSP/NETCFG/net_cfg_legacy.h" [color="#2563eb", penwidth=1.0];
|
||||
"Drivers/BSP/NETCFG/net_cfg_legacy.c" -> "Drivers/BSP/dbg_log.h" [color="#2563eb", penwidth=1.0];
|
||||
"Drivers/BSP/NETCFG/net_cfg_legacy.c" -> "外部/系统头文件" [color="#f59e0b", penwidth=0.6, style=dashed];
|
||||
"Drivers/BSP/RS485/rs485.c" -> "Drivers/BSP/RS485/rs485.h" [color="#2563eb", penwidth=1.0];
|
||||
"Drivers/BSP/RS485/rs485.h" -> "Inc/main.h" [color="#2563eb", penwidth=1.0];
|
||||
"Drivers/BSP/SD2506/sd2506.c" -> "Drivers/BSP/SD2506/sd2506.h" [color="#2563eb", penwidth=1.0];
|
||||
@@ -363,6 +356,9 @@ digraph refgraph_full {
|
||||
"Drivers/BSP/TPAFE5160/tpafe5160.c" -> "Drivers/BSP/TPAFE5160/tpafe5160.h" [color="#2563eb", penwidth=1.0];
|
||||
"Drivers/BSP/TPAFE5160/tpafe5160.c" -> "Drivers/BSP/dbg_log.h" [color="#2563eb", penwidth=1.0];
|
||||
"Drivers/BSP/TPAFE5160/tpafe5160.c" -> "Inc/main.h" [color="#2563eb", penwidth=1.0];
|
||||
"Drivers/BSP/TPAFE5160/tpafe5160.c" -> "Middlewares/Third_Party/FreeRTOS/Source/include/FreeRTOS.h" [color="#94a3b8", penwidth=0.7];
|
||||
"Drivers/BSP/TPAFE5160/tpafe5160.c" -> "Middlewares/Third_Party/FreeRTOS/Source/include/task.h" [color="#94a3b8", penwidth=0.7];
|
||||
"Drivers/BSP/TPAFE5160/tpafe5160.c" -> "外部/系统头文件" [color="#f59e0b", penwidth=0.6, style=dashed];
|
||||
"Drivers/BSP/TPAFE5160/tpafe5160.h" -> "Inc/main.h" [color="#2563eb", penwidth=1.0];
|
||||
"Drivers/BSP/UI/ui_content_page.c" -> "Drivers/BSP/UI/ui_content_page.h" [color="#2563eb", penwidth=1.0];
|
||||
"Drivers/BSP/UI/ui_content_page.c" -> "Drivers/BSP/UI/ui_deco.h" [color="#2563eb", penwidth=1.0];
|
||||
@@ -409,6 +405,7 @@ digraph refgraph_full {
|
||||
"Drivers/BSP/UI/ui_net_sink.c" -> "Drivers/BSP/NET/net_types.h" [color="#2563eb", penwidth=1.0];
|
||||
"Drivers/BSP/UI/ui_net_sink.c" -> "Drivers/BSP/UI/ui_net_sink.h" [color="#2563eb", penwidth=1.0];
|
||||
"Drivers/BSP/UI/ui_net_sink.c" -> "Drivers/BSP/UI/ui_net_sink_backend.h" [color="#2563eb", penwidth=1.0];
|
||||
"Drivers/BSP/UI/ui_net_sink.c" -> "Drivers/BSP/dbg_log.h" [color="#2563eb", penwidth=1.0];
|
||||
"Drivers/BSP/UI/ui_net_sink.c" -> "test/board/net_latency_test.h" [color="#2563eb", penwidth=1.0];
|
||||
"Drivers/BSP/UI/ui_net_sink.c" -> "test/board/test_config.h" [color="#2563eb", penwidth=1.0];
|
||||
"Drivers/BSP/UI/ui_net_sink.c" -> "外部/系统头文件" [color="#f59e0b", penwidth=0.6, style=dashed];
|
||||
@@ -456,12 +453,14 @@ digraph refgraph_full {
|
||||
"Drivers/BSP/dbg_log.h" -> "Drivers/BSP/dbg_cfg.h" [color="#2563eb", penwidth=1.0];
|
||||
"Drivers/BSP/dbg_log.h" -> "外部/系统头文件" [color="#f59e0b", penwidth=0.6, style=dashed];
|
||||
"Inc/FreeRTOSConfig.h" -> "外部/系统头文件" [color="#f59e0b", penwidth=0.6, style=dashed];
|
||||
"Inc/adc.h" -> "Inc/main.h" [color="#2563eb", penwidth=1.0];
|
||||
"Inc/dma.h" -> "Inc/main.h" [color="#2563eb", penwidth=1.0];
|
||||
"Inc/gpio.h" -> "Inc/main.h" [color="#2563eb", penwidth=1.0];
|
||||
"Inc/i2c.h" -> "Inc/main.h" [color="#2563eb", penwidth=1.0];
|
||||
"Inc/iwdg.h" -> "Inc/main.h" [color="#2563eb", penwidth=1.0];
|
||||
"Inc/main.h" -> "Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal.h" [color="#94a3b8", penwidth=0.7];
|
||||
"Inc/spi.h" -> "Inc/main.h" [color="#2563eb", penwidth=1.0];
|
||||
"Inc/stm32f4xx_hal_conf.h" -> "Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal_adc.h" [color="#94a3b8", penwidth=0.7];
|
||||
"Inc/stm32f4xx_hal_conf.h" -> "Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal_cortex.h" [color="#94a3b8", penwidth=0.7];
|
||||
"Inc/stm32f4xx_hal_conf.h" -> "Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal_dma.h" [color="#94a3b8", penwidth=0.7];
|
||||
"Inc/stm32f4xx_hal_conf.h" -> "Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal_exti.h" [color="#94a3b8", penwidth=0.7];
|
||||
@@ -476,6 +475,7 @@ digraph refgraph_full {
|
||||
"Inc/stm32f4xx_hal_conf.h" -> "Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal_uart.h" [color="#94a3b8", penwidth=0.7];
|
||||
"Inc/stm32f4xx_hal_conf.h" -> "外部/系统头文件" [color="#f59e0b", penwidth=0.6, style=dashed];
|
||||
"Inc/usart.h" -> "Inc/main.h" [color="#2563eb", penwidth=1.0];
|
||||
"Src/adc.c" -> "Inc/adc.h" [color="#2563eb", penwidth=1.0];
|
||||
"Src/dma.c" -> "Inc/dma.h" [color="#2563eb", penwidth=1.0];
|
||||
"Src/freertos.c" -> "App/app/sys_events.h" [color="#2563eb", penwidth=1.0];
|
||||
"Src/freertos.c" -> "App/sync/time_sync.h" [color="#2563eb", penwidth=1.0];
|
||||
@@ -508,6 +508,7 @@ digraph refgraph_full {
|
||||
"Src/main.c" -> "Drivers/BSP/SD2506/sd2506.h" [color="#2563eb", penwidth=1.0];
|
||||
"Src/main.c" -> "Drivers/BSP/TPAFE5160/tpafe5160.h" [color="#2563eb", penwidth=1.0];
|
||||
"Src/main.c" -> "Drivers/BSP/dbg_log.h" [color="#2563eb", penwidth=1.0];
|
||||
"Src/main.c" -> "Inc/adc.h" [color="#2563eb", penwidth=1.0];
|
||||
"Src/main.c" -> "Inc/dma.h" [color="#2563eb", penwidth=1.0];
|
||||
"Src/main.c" -> "Inc/gpio.h" [color="#2563eb", penwidth=1.0];
|
||||
"Src/main.c" -> "Inc/i2c.h" [color="#2563eb", penwidth=1.0];
|
||||
|
||||
+123
-68
@@ -221,14 +221,6 @@
|
||||
"path": "Drivers/BSP/NETCFG/net_cfg.h",
|
||||
"class": "fp"
|
||||
},
|
||||
{
|
||||
"path": "Drivers/BSP/NETCFG/net_cfg_legacy.c",
|
||||
"class": "fp"
|
||||
},
|
||||
{
|
||||
"path": "Drivers/BSP/NETCFG/net_cfg_legacy.h",
|
||||
"class": "fp"
|
||||
},
|
||||
{
|
||||
"path": "Drivers/BSP/RS485/rs485.c",
|
||||
"class": "fp"
|
||||
@@ -537,6 +529,14 @@
|
||||
"path": "Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal.h",
|
||||
"class": "tp"
|
||||
},
|
||||
{
|
||||
"path": "Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal_adc.h",
|
||||
"class": "tp"
|
||||
},
|
||||
{
|
||||
"path": "Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal_adc_ex.h",
|
||||
"class": "tp"
|
||||
},
|
||||
{
|
||||
"path": "Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal_cortex.h",
|
||||
"class": "tp"
|
||||
@@ -621,6 +621,10 @@
|
||||
"path": "Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal_uart.h",
|
||||
"class": "tp"
|
||||
},
|
||||
{
|
||||
"path": "Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_ll_adc.h",
|
||||
"class": "tp"
|
||||
},
|
||||
{
|
||||
"path": "Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_ll_bus.h",
|
||||
"class": "tp"
|
||||
@@ -677,6 +681,14 @@
|
||||
"path": "Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal.c",
|
||||
"class": "tp"
|
||||
},
|
||||
{
|
||||
"path": "Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_adc.c",
|
||||
"class": "tp"
|
||||
},
|
||||
{
|
||||
"path": "Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_adc_ex.c",
|
||||
"class": "tp"
|
||||
},
|
||||
{
|
||||
"path": "Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_cortex.c",
|
||||
"class": "tp"
|
||||
@@ -757,6 +769,10 @@
|
||||
"path": "Inc/FreeRTOSConfig.h",
|
||||
"class": "fp"
|
||||
},
|
||||
{
|
||||
"path": "Inc/adc.h",
|
||||
"class": "fp"
|
||||
},
|
||||
{
|
||||
"path": "Inc/dma.h",
|
||||
"class": "fp"
|
||||
@@ -4725,6 +4741,10 @@
|
||||
"path": "Middlewares/Third_Party/FreeRTOS/Source/timers.c",
|
||||
"class": "tp"
|
||||
},
|
||||
{
|
||||
"path": "Src/adc.c",
|
||||
"class": "fp"
|
||||
},
|
||||
{
|
||||
"path": "Src/dma.c",
|
||||
"class": "fp"
|
||||
@@ -5883,12 +5903,6 @@
|
||||
"kind": "fp-fp",
|
||||
"include": "sys_events.h"
|
||||
},
|
||||
{
|
||||
"from": "App/log/console_log.c",
|
||||
"to": "App/log/sys_log.h",
|
||||
"kind": "fp-fp",
|
||||
"include": "sys_log.h"
|
||||
},
|
||||
{
|
||||
"from": "App/log/console_log.h",
|
||||
"to": "外部/系统头文件",
|
||||
@@ -7029,12 +7043,6 @@
|
||||
"kind": "fp-fp",
|
||||
"include": "net_cfg.h"
|
||||
},
|
||||
{
|
||||
"from": "Drivers/BSP/NETCFG/net_cfg.c",
|
||||
"to": "Drivers/BSP/NETCFG/net_cfg_legacy.h",
|
||||
"kind": "fp-fp",
|
||||
"include": "net_cfg_legacy.h"
|
||||
},
|
||||
{
|
||||
"from": "Drivers/BSP/NETCFG/net_cfg.c",
|
||||
"to": "App/cfg/cfg_file.h",
|
||||
@@ -7059,42 +7067,6 @@
|
||||
"kind": "fp-ext",
|
||||
"include": "stddef.h"
|
||||
},
|
||||
{
|
||||
"from": "Drivers/BSP/NETCFG/net_cfg_legacy.c",
|
||||
"to": "外部/系统头文件",
|
||||
"kind": "fp-ext",
|
||||
"include": "string.h"
|
||||
},
|
||||
{
|
||||
"from": "Drivers/BSP/NETCFG/net_cfg_legacy.c",
|
||||
"to": "Drivers/BSP/NETCFG/net_cfg_legacy.h",
|
||||
"kind": "fp-fp",
|
||||
"include": "net_cfg_legacy.h"
|
||||
},
|
||||
{
|
||||
"from": "Drivers/BSP/NETCFG/net_cfg_legacy.c",
|
||||
"to": "Drivers/BSP/NETCFG/net_cfg.h",
|
||||
"kind": "fp-fp",
|
||||
"include": "net_cfg.h"
|
||||
},
|
||||
{
|
||||
"from": "Drivers/BSP/NETCFG/net_cfg_legacy.c",
|
||||
"to": "App/cfg/cfg_file.h",
|
||||
"kind": "fp-fp",
|
||||
"include": "cfg_file.h"
|
||||
},
|
||||
{
|
||||
"from": "Drivers/BSP/NETCFG/net_cfg_legacy.c",
|
||||
"to": "App/cfg/cfg_file_store.h",
|
||||
"kind": "fp-fp",
|
||||
"include": "cfg_file_store.h"
|
||||
},
|
||||
{
|
||||
"from": "Drivers/BSP/NETCFG/net_cfg_legacy.c",
|
||||
"to": "Drivers/BSP/dbg_log.h",
|
||||
"kind": "fp-fp",
|
||||
"include": "dbg_log.h"
|
||||
},
|
||||
{
|
||||
"from": "Drivers/BSP/RS485/rs485.c",
|
||||
"to": "Drivers/BSP/RS485/rs485.h",
|
||||
@@ -7143,6 +7115,12 @@
|
||||
"kind": "fp-fp",
|
||||
"include": "main.h"
|
||||
},
|
||||
{
|
||||
"from": "Drivers/BSP/TPAFE5160/tpafe5160.c",
|
||||
"to": "外部/系统头文件",
|
||||
"kind": "fp-ext",
|
||||
"include": "string.h"
|
||||
},
|
||||
{
|
||||
"from": "Drivers/BSP/TPAFE5160/tpafe5160.c",
|
||||
"to": "Drivers/BSP/TPAFE5160/tpafe5160.h",
|
||||
@@ -7155,6 +7133,18 @@
|
||||
"kind": "fp-fp",
|
||||
"include": "main.h"
|
||||
},
|
||||
{
|
||||
"from": "Drivers/BSP/TPAFE5160/tpafe5160.c",
|
||||
"to": "Middlewares/Third_Party/FreeRTOS/Source/include/FreeRTOS.h",
|
||||
"kind": "fp-tp",
|
||||
"include": "FreeRTOS.h"
|
||||
},
|
||||
{
|
||||
"from": "Drivers/BSP/TPAFE5160/tpafe5160.c",
|
||||
"to": "Middlewares/Third_Party/FreeRTOS/Source/include/task.h",
|
||||
"kind": "fp-tp",
|
||||
"include": "task.h"
|
||||
},
|
||||
{
|
||||
"from": "Drivers/BSP/TPAFE5160/tpafe5160.c",
|
||||
"to": "Drivers/BSP/dbg_log.h",
|
||||
@@ -7473,6 +7463,12 @@
|
||||
"kind": "fp-fp",
|
||||
"include": "net_latency_test.h"
|
||||
},
|
||||
{
|
||||
"from": "Drivers/BSP/UI/ui_net_sink.c",
|
||||
"to": "Drivers/BSP/dbg_log.h",
|
||||
"kind": "fp-fp",
|
||||
"include": "dbg_log.h"
|
||||
},
|
||||
{
|
||||
"from": "Drivers/BSP/UI/ui_net_sink.h",
|
||||
"to": "外部/系统头文件",
|
||||
@@ -8397,6 +8393,30 @@
|
||||
"kind": "tp-tp",
|
||||
"include": "stm32f4xx_hal_conf.h"
|
||||
},
|
||||
{
|
||||
"from": "Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal_adc.h",
|
||||
"to": "Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal_def.h",
|
||||
"kind": "tp-tp",
|
||||
"include": "stm32f4xx_hal_def.h"
|
||||
},
|
||||
{
|
||||
"from": "Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal_adc.h",
|
||||
"to": "Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_ll_adc.h",
|
||||
"kind": "tp-tp",
|
||||
"include": "stm32f4xx_ll_adc.h"
|
||||
},
|
||||
{
|
||||
"from": "Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal_adc.h",
|
||||
"to": "Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal_adc_ex.h",
|
||||
"kind": "tp-tp",
|
||||
"include": "stm32f4xx_hal_adc_ex.h"
|
||||
},
|
||||
{
|
||||
"from": "Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal_adc_ex.h",
|
||||
"to": "Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal_def.h",
|
||||
"kind": "tp-tp",
|
||||
"include": "stm32f4xx_hal_def.h"
|
||||
},
|
||||
{
|
||||
"from": "Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal_cortex.h",
|
||||
"to": "Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal_def.h",
|
||||
@@ -8583,6 +8603,12 @@
|
||||
"kind": "tp-tp",
|
||||
"include": "stm32f4xx_hal_def.h"
|
||||
},
|
||||
{
|
||||
"from": "Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_ll_adc.h",
|
||||
"to": "Drivers/CMSIS/Device/ST/STM32F4xx/Include/stm32f4xx.h",
|
||||
"kind": "tp-tp",
|
||||
"include": "stm32f4xx.h"
|
||||
},
|
||||
{
|
||||
"from": "Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_ll_bus.h",
|
||||
"to": "Drivers/CMSIS/Device/ST/STM32F4xx/Include/stm32f4xx.h",
|
||||
@@ -8667,6 +8693,18 @@
|
||||
"kind": "tp-tp",
|
||||
"include": "stm32f4xx_hal.h"
|
||||
},
|
||||
{
|
||||
"from": "Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_adc.c",
|
||||
"to": "Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal.h",
|
||||
"kind": "tp-tp",
|
||||
"include": "stm32f4xx_hal.h"
|
||||
},
|
||||
{
|
||||
"from": "Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_adc_ex.c",
|
||||
"to": "Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal.h",
|
||||
"kind": "tp-tp",
|
||||
"include": "stm32f4xx_hal.h"
|
||||
},
|
||||
{
|
||||
"from": "Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_cortex.c",
|
||||
"to": "Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal.h",
|
||||
@@ -8787,6 +8825,12 @@
|
||||
"kind": "fp-ext",
|
||||
"include": "stdint.h"
|
||||
},
|
||||
{
|
||||
"from": "Inc/adc.h",
|
||||
"to": "Inc/main.h",
|
||||
"kind": "fp-fp",
|
||||
"include": "main.h"
|
||||
},
|
||||
{
|
||||
"from": "Inc/dma.h",
|
||||
"to": "Inc/main.h",
|
||||
@@ -8855,8 +8899,8 @@
|
||||
},
|
||||
{
|
||||
"from": "Inc/stm32f4xx_hal_conf.h",
|
||||
"to": "外部/系统头文件",
|
||||
"kind": "fp-ext",
|
||||
"to": "Drivers/STM32F4xx_HAL_Driver/Inc/stm32f4xx_hal_adc.h",
|
||||
"kind": "fp-tp",
|
||||
"include": "stm32f4xx_hal_adc.h"
|
||||
},
|
||||
{
|
||||
@@ -38853,6 +38897,12 @@
|
||||
"kind": "fp-tp",
|
||||
"include": "lvgl.h"
|
||||
},
|
||||
{
|
||||
"from": "Src/adc.c",
|
||||
"to": "Inc/adc.h",
|
||||
"kind": "fp-fp",
|
||||
"include": "adc.h"
|
||||
},
|
||||
{
|
||||
"from": "Src/dma.c",
|
||||
"to": "Inc/dma.h",
|
||||
@@ -38991,6 +39041,12 @@
|
||||
"kind": "fp-tp",
|
||||
"include": "cmsis_os.h"
|
||||
},
|
||||
{
|
||||
"from": "Src/main.c",
|
||||
"to": "Inc/adc.h",
|
||||
"kind": "fp-fp",
|
||||
"include": "adc.h"
|
||||
},
|
||||
{
|
||||
"from": "Src/main.c",
|
||||
"to": "Inc/dma.h",
|
||||
@@ -39970,13 +40026,13 @@
|
||||
"stddef.h",
|
||||
"stdint.h"
|
||||
],
|
||||
"Drivers/BSP/NETCFG/net_cfg_legacy.c": [
|
||||
"string.h"
|
||||
],
|
||||
"Drivers/BSP/SD2506/sd2506.c": [
|
||||
"stdio.h",
|
||||
"string.h"
|
||||
],
|
||||
"Drivers/BSP/TPAFE5160/tpafe5160.c": [
|
||||
"string.h"
|
||||
],
|
||||
"Drivers/BSP/UI/ui_content_page.c": [
|
||||
"string.h"
|
||||
],
|
||||
@@ -40145,7 +40201,6 @@
|
||||
"stdint.h"
|
||||
],
|
||||
"Inc/stm32f4xx_hal_conf.h": [
|
||||
"stm32f4xx_hal_adc.h",
|
||||
"stm32f4xx_hal_can.h",
|
||||
"stm32f4xx_hal_can_legacy.h",
|
||||
"stm32f4xx_hal_cec.h",
|
||||
@@ -41600,13 +41655,13 @@
|
||||
]
|
||||
},
|
||||
"stats": {
|
||||
"files_indexed": 1420,
|
||||
"includes_parsed": 5700,
|
||||
"resolved": 4630,
|
||||
"unresolved": 1070,
|
||||
"files_indexed": 1425,
|
||||
"includes_parsed": 5706,
|
||||
"resolved": 4637,
|
||||
"unresolved": 1069,
|
||||
"nodes_fp": 147,
|
||||
"nodes_tp": 1259,
|
||||
"ext_names": 352
|
||||
"nodes_tp": 1264,
|
||||
"ext_names": 351
|
||||
},
|
||||
"include_dirs": [
|
||||
"Inc",
|
||||
|
||||
+1762
-1756
File diff suppressed because it is too large
Load Diff
|
Before Width: | Height: | Size: 358 KiB After Width: | Height: | Size: 361 KiB |
@@ -87,17 +87,19 @@ digraph refgraph_module {
|
||||
"BSP/NET" -> "Src/Inc (CubeMX)" [color="#2563eb", penwidth=1.2, label="×2"];
|
||||
"BSP/NET" -> "test" [color="#2563eb", penwidth=1.2, label="×2"];
|
||||
"BSP/NET" -> "外部/系统头文件" [color="#94a3b8", penwidth=0.7, label="×3"];
|
||||
"BSP/NETCFG" -> "App" [color="#2563eb", penwidth=1.2, label="×3"];
|
||||
"BSP/NETCFG" -> "BSP(公共)" [color="#2563eb", penwidth=1.2, label="×2"];
|
||||
"BSP/NETCFG" -> "外部/系统头文件" [color="#94a3b8", penwidth=0.7, label="×3"];
|
||||
"BSP/NETCFG" -> "App" [color="#2563eb", penwidth=1.2, label="×1"];
|
||||
"BSP/NETCFG" -> "BSP(公共)" [color="#2563eb", penwidth=1.2, label="×1"];
|
||||
"BSP/NETCFG" -> "外部/系统头文件" [color="#94a3b8", penwidth=0.7, label="×2"];
|
||||
"BSP/RS485" -> "Src/Inc (CubeMX)" [color="#2563eb", penwidth=1.2, label="×1"];
|
||||
"BSP/SD2506" -> "BSP(公共)" [color="#2563eb", penwidth=1.2, label="×1"];
|
||||
"BSP/SD2506" -> "Src/Inc (CubeMX)" [color="#2563eb", penwidth=1.2, label="×2"];
|
||||
"BSP/SD2506" -> "外部/系统头文件" [color="#94a3b8", penwidth=0.7, label="×1"];
|
||||
"BSP/TPAFE5160" -> "BSP(公共)" [color="#2563eb", penwidth=1.2, label="×1"];
|
||||
"BSP/TPAFE5160" -> "FreeRTOS" [color="#2563eb", penwidth=1.2, label="×2"];
|
||||
"BSP/TPAFE5160" -> "Src/Inc (CubeMX)" [color="#2563eb", penwidth=1.2, label="×2"];
|
||||
"BSP/TPAFE5160" -> "外部/系统头文件" [color="#94a3b8", penwidth=0.7, label="×1"];
|
||||
"BSP/UI" -> "App/log" [color="#2563eb", penwidth=1.2, label="×2"];
|
||||
"BSP/UI" -> "BSP(公共)" [color="#2563eb", penwidth=1.2, label="×5"];
|
||||
"BSP/UI" -> "BSP(公共)" [color="#2563eb", penwidth=1.2, label="×6"];
|
||||
"BSP/UI" -> "BSP/NET" [color="#2563eb", penwidth=1.2, label="×2"];
|
||||
"BSP/UI" -> "BSP/NETCFG" [color="#2563eb", penwidth=1.2, label="×1"];
|
||||
"BSP/UI" -> "LVGL" [color="#2563eb", penwidth=1.2, label="×9"];
|
||||
@@ -112,7 +114,7 @@ digraph refgraph_module {
|
||||
"FreeRTOS" -> "CMSIS" [color="#94a3b8", penwidth=0.7, label="×1"];
|
||||
"FreeRTOS" -> "Src/Inc (CubeMX)" [color="#94a3b8", penwidth=0.7, label="×1"];
|
||||
"FreeRTOS" -> "外部/系统头文件" [color="#94a3b8", penwidth=0.7, label="×14"];
|
||||
"HAL" -> "CMSIS" [color="#94a3b8", penwidth=0.7, label="×14"];
|
||||
"HAL" -> "CMSIS" [color="#94a3b8", penwidth=0.7, label="×15"];
|
||||
"HAL" -> "Src/Inc (CubeMX)" [color="#94a3b8", penwidth=0.7, label="×1"];
|
||||
"HAL" -> "外部/系统头文件" [color="#94a3b8", penwidth=0.7, label="×1"];
|
||||
"LVGL" -> "FatFs" [color="#94a3b8", penwidth=0.7, label="×1"];
|
||||
@@ -133,7 +135,7 @@ digraph refgraph_module {
|
||||
"Src/Inc (CubeMX)" -> "BSP/TPAFE5160" [color="#2563eb", penwidth=1.2, label="×1"];
|
||||
"Src/Inc (CubeMX)" -> "CMSIS" [color="#2563eb", penwidth=1.2, label="×1"];
|
||||
"Src/Inc (CubeMX)" -> "FreeRTOS" [color="#2563eb", penwidth=1.2, label="×4"];
|
||||
"Src/Inc (CubeMX)" -> "HAL" [color="#2563eb", penwidth=1.2, label="×15"];
|
||||
"Src/Inc (CubeMX)" -> "HAL" [color="#2563eb", penwidth=1.2, label="×16"];
|
||||
"Src/Inc (CubeMX)" -> "lftpd" [color="#2563eb", penwidth=1.2, label="×1"];
|
||||
"Src/Inc (CubeMX)" -> "test" [color="#2563eb", penwidth=1.2, label="×3"];
|
||||
"Src/Inc (CubeMX)" -> "外部/系统头文件" [color="#94a3b8", penwidth=0.7, label="×4"];
|
||||
|
||||
+555
-541
File diff suppressed because it is too large
Load Diff
|
Before Width: | Height: | Size: 101 KiB After Width: | Height: | Size: 104 KiB |
@@ -372,9 +372,11 @@ sequenceDiagram
|
||||
- 实现:`defaultTask` 每 2 s `f_stat` 比对 (size, mtime),连续 2 次稳定才重载(沉降去抖);`[network]` 段变化 → `SYS_EVT_NET_RECONFIG` → 网络重建(代次 +1,服务自愈)。
|
||||
- 判据:FTP 改 IP 后 2~5 s 生效(网络重建含等链路 ≤3 s)。
|
||||
|
||||
**FR-CFG-4 旧档迁移**
|
||||
- 需求:旧固件的 `/cfg/netcfg.bin`(NCFG 二进制)首启自动迁移为 INI 并删除旧文件。
|
||||
- 判据:迁移后日志 `cfg file: legacy NCFG migrated`,配置保留。
|
||||
**FR-CFG-4 旧档迁移**(已取消 · 2026-10-10)
|
||||
- 原需求:旧固件的 `/cfg/netcfg.bin`(NCFG 二进制)首启自动迁移为 INI 并删除旧文件——**已取消,不再实现**。
|
||||
- 现口径:旧档若存在则被**忽略**(不读、不删、不迁移),配置直接回落工厂默认(`/config.ini` `[network]` 段模板)。
|
||||
- 取消理由:该一次性路径把整条配置写链(`net_cfg_save → cfg_file_save → cfg_store_write_atomic → f_rename → FatFS → dhara FTL`)挂进启动期调用图,defaultTask 静态最坏栈链 +600 B;本仓库不存在携带旧档的设备。
|
||||
- 判据:卷上残留 `/cfg/netcfg.bin` 时开机不产生任何迁移日志、旧档不被改动,`/config.ini` 按工厂默认生成。
|
||||
|
||||
**FR-CFG-5 扩展性**
|
||||
- 需求:未来所有模块配置(ADC/RS-485/端口等)进同一文件、按段组织。
|
||||
@@ -577,7 +579,7 @@ mac=00:00:00:00:00:00
|
||||
| 需求 | 要求 | 落地 |
|
||||
|---|---|---|
|
||||
| **自恢复** | 任务死锁/饿死/断言死循环 → 硬件复位 | IWDG + 心跳位图(§5.7) |
|
||||
| **掉电不丢配置** | 配置原子写 + 旧档迁移 | tmp+rename + NCFG→INI 迁移 |
|
||||
| **掉电不丢配置** | 配置原子写(旧档迁移已取消,2026-10-10) | tmp+rename;旧 `/cfg/netcfg.bin` 不读、不删、不迁移 |
|
||||
| **错误可追溯** | 错误码分级/透传/留痕,不吞不猜 | 错误码通道四要素(分类/透传/分级/留痕) |
|
||||
| **存储自愈** | 卷损坏可探针/自愈;丢弃可观测 | 卷健康探针 + 丢弃计数 + TX 僵尸通道自愈 |
|
||||
| **不误杀** | 正常长耗时窗口不触发复位 | 启动段不喂狗 + 心跳切片 + 白名单 |
|
||||
@@ -888,3 +890,4 @@ cfg-file-unit-test、test-suite-switch、gitlint。
|
||||
| 日期 | 变更 | 说明 |
|
||||
|---|---|---|
|
||||
| 2026-10-05 | 初版 | 基于项目全量内容(架构 / 子系统 / UI / 测试 / 硬件网表 / 待办)编写完整产品需求设计文档:产品定位、六层架构与任务模型、V0.1 硬件规格、10 类功能需求(含 2 项待实现)、接口规范、非功能需求、UI 规格、待实现项与路线图、验收判据 |
|
||||
| 2026-10-10 | FR-CFG-4 旧档迁移**取消** | 删除旧固件 `/cfg/netcfg.bin`(NCFG 二进制)的首启自动迁移:旧档若存在则被忽略(不读、不删、不迁移),配置回落工厂默认。理由:该一次性路径把整条配置写链挂进启动期调用图,defaultTask 静态最坏栈链 +600 B,而本仓库不存在携带旧档的设备;`net_cfg_legacy.c/h` 与 `cfg_store_legacy_path()` 一并移除。§7.1「掉电不丢配置」同步 |
|
||||
|
||||
+72
-19
@@ -18,7 +18,7 @@
|
||||
- F407 另有 **64KB CCM RAM**:**已于 2026-09-21 启用**并把 FreeRTOS 堆迁入(§1.2)
|
||||
- 起步时没有任何运行时测量手段:不知道每个任务实际用了多少栈,改栈全靠拍脑袋
|
||||
|
||||
当前状态(**以 §2.1 受管快照为准**,由 `.map` 自动生成):RW_IRAM1 **84,960 / 131,072 B(64.8%)**、RW_CCM **49,184 / 65,280 B(75.3%)**。⚠️ **任务栈:2026-10-04 重采(产品构建 V5 30 min 负载)显示 `defaultTask` 峰值升至 3664B/4096(余量 432B ≈ 10%,已低于 30% 判据)**,详见 §2.3 注与 `../待处理内容.md` §6(登记 `待处理内容.md` S-1)。
|
||||
当前状态(**以 §2.1 受管快照为准**,由 `.map` 自动生成):RW_IRAM1 **89,168 / 131,072 B(68.0%)**、RW_CCM **49,184 / 65,280 B(75.3%)**。✅ **任务栈:2026-10-10 削链后 `defaultTask` 实测峰值 2152B/4096(余 47%)、静态最坏链 2776B(余 32%)**,6 任务全过 `stack_report.py` 判据(曾于 2026-10-04 升至 3664B/4096 ≈ 10%,登记为 S-1,现已销项),详见 §2.3 与"2026-10-10 复测"小节。
|
||||
|
||||
本方案三个目标:
|
||||
|
||||
@@ -36,10 +36,10 @@
|
||||
<!-- MEM_SNAPSHOT:BEGIN generated by scripts/check_mem_numbers.py -->
|
||||
| 区域 | 用量 | 容量 | 占比 |
|
||||
|---|---|---|---|
|
||||
| ER_IROM1 | 268,128 B (261.84 KB) | 1,048,576 B (1024 KB) | 25.6% |
|
||||
| RW_IRAM1 | 85,040 B (83.05 KB) | 131,072 B (128 KB) | 64.9% |
|
||||
| ER_IROM1 | 267,528 B (261.26 KB) | 1,048,576 B (1024 KB) | 25.5% |
|
||||
| RW_IRAM1 | 89,168 B (87.08 KB) | 131,072 B (128 KB) | 68.0% |
|
||||
| RW_CCM | 49,184 B (48.03 KB) | 65,280 B (64 KB) | 75.3% |
|
||||
| **Flash (ROM 合计)** | **268,876 B (262.6 KB)** | 1,048,576 B (1024 KB) | **25.6%** |
|
||||
| **Flash (ROM 合计)** | **268,276 B (262.0 KB)** | 1,048,576 B (1024 KB) | **25.6%** |
|
||||
<!-- MEM_SNAPSHOT:END -->
|
||||
|
||||
各区的容量与常量来源:
|
||||
@@ -51,7 +51,7 @@
|
||||
| FreeRTOS 堆 (heap_4) | 48 KB(49,152 B),**位于 RW_CCM**;实测 `free=8,784 / min_ever=4,848` B | `Inc/FreeRTOSConfig.h:71` `configTOTAL_HEAP_SIZE` |
|
||||
| C 库堆/栈 (startup) | 512 B / 1 KB,启动期 main() 用 | map `startup_stm32f407xx.o` HEAP/STACK 节 |
|
||||
|
||||
### 2.2 静态大项排行(2026-09-21 当前,完整台账 `data/ram_report_20260921.md`)
|
||||
### 2.2 静态大项排行(2026-10-10 当前,完整台账 `data/ram_report_20261010.md`)
|
||||
|
||||
**RW_IRAM1(主 SRAM)**,按 ZI/RW 合计降序:
|
||||
|
||||
@@ -72,6 +72,11 @@
|
||||
| 13–17 | ≤560 | `spi.o` / `usart.o` / `lftpd_io.o` / `lv_init.o` / `net_socket.o` | 外设句柄、`FIL`、LVGL 全局、socket 表 |
|
||||
| 其余 | ~1.7 KB | 约 25 个 .o | 小型 RW/ZI |
|
||||
|
||||
> **2026-10-10 栈整改带来的静态增量(+4,128 B,本质是"把 528 B 的 `FIL` 从栈搬到 BSS")**:
|
||||
> `sys_log_mcu.o` 1,912 B(3 处 `FIL` 静态化 = 1,584 + 证据行缓冲 192)、`default_task.o` 2,712 B
|
||||
> (卷探针 `FIL` 528 + `default_fatfs`/`fs_work`)、`cfg_file_store_mcu.o` 1,104 B(2 处 `FIL` = 1,056)。
|
||||
> 同期 Flash **−600 B**(删旧档迁移)。台账:`data/ram_report_20261010.md`。
|
||||
|
||||
**RW_CCM(CCM)**:`heap_4.o` 49,184 B(FreeRTOS 堆 49,152 B + RW 32 B)——2026-09-21 由主 SRAM 迁入(§1.2),不再计入主 SRAM。
|
||||
|
||||
**静态合计(以 §2.1 受管快照为准)**:RW_IRAM1 **87,040 B(85.00 KB / 128 KB,66.4%)** + RW_CCM **49,184 B(48.03 KB / 64 KB,75.0%)** = **136,224 B(RW+ZI)**。
|
||||
@@ -86,20 +91,18 @@
|
||||
|
||||
`Src/freertos.c` 中 `osThreadAttr_t.stack_size` 单位为**字节**(CubeMX 生成代码,`1024 * 4` 表示 4096 字节):
|
||||
|
||||
> ⚠️ **下表"实测峰值"列为 2026-09-21 快照,已过时**:2026-10-04 产品构建(`suite=NONE`)V5 30 min
|
||||
> 真实负载重采(串口 `[STACK]`,证据 `/tmp/v5_soak_serial_20261003.log`)——**defaultTask 3664B/4096
|
||||
> (余量 432B ≈ 10%,已低于 30% 判据,登记 S-1)**、ftpTask 2516B/4096(38%)、netTask 1228B/4096(70%)、
|
||||
> uiTask 4060B/16384(75%)、timeSyncTask 792B/2048(61%)、testTask 496B/8192(93%)。
|
||||
> 栈水位随 A2/A3/A4 + IWDG + 卷锁 + 堆告警等陆续入链持续上升,**本表需随 `stack_report.py` 重新基线**。
|
||||
> ✅ **本表已于 2026-10-10 重新基线**(产品构建 `suite=NONE`,开机 + 空闲采样,静态链取 `stack_report.py`)。
|
||||
> 此前 2026-10-04 的 V5 30 min 重采曾把 defaultTask 推到 **3664B/4096(余量 432B ≈ 10%,登记 S-1)**;
|
||||
> 2026-10-10 的栈整改(**未抬栈**,见 §4 阶段 0 的"2026-10-10 复测")把它压回 **2152B/4096**,S-1 已销项。
|
||||
|
||||
| 任务 | 配置栈 | 字节 | 实际职责 | 2026-09-21 实测峰值(§0.6) |
|
||||
| 任务 | 配置栈 | 字节 | 实际职责 | 2026-10-10 实测峰值 / 静态最坏链 |
|
||||
|---|---|---|---|---|
|
||||
| uiTask | `4096*4` | 16KB | LVGL 1bpp 离屏渲染(渲染缓冲在静态区,栈只走调用链) | 3824 B(余量 76%)→ 可大幅缩减 |
|
||||
| netTask | `1024*4` | 4KB | CH395F 轮询(DMA 搬运,栈压力小) | 588 B(余量 85%) |
|
||||
| ftpTask | `1024*4` | 4KB | lftpd FTP 服务 | 1184 B(余量 71%,§1.4 静态化后) |
|
||||
| testTask | `2048*4` | 8KB | 测试套件(产品构建空转;存储套件深链需要) | 348 B(产品构建) |
|
||||
| defaultTask | `1024*4` | 4KB | FatFS 挂载/探针 + 配置引擎 + syslog + 栈水位探针 | 2136 B(余量 47%) |
|
||||
| timeSyncTask | `512*4` | 2KB | TCP 时间同步 | 420 B(余量 79%) |
|
||||
| uiTask | `4096*4` | 16KB | LVGL 1bpp 离屏渲染(渲染缓冲在静态区,栈只走调用链) | 4016 B(余 75%)/ 静态 1336 B → 可大幅缩减 |
|
||||
| netTask | `960*4` | 3.75KB | CH395F 轮询(DMA 搬运,栈压力小) | 920 B(余 76%)/ 静态 1872 B |
|
||||
| ftpTask | `1024*4` | 4KB | lftpd FTP 服务 | 740 B(余 81%)/ 静态 1216 B |
|
||||
| testTask | `2048*4` | 8KB | 测试套件(产品构建不创建;存储套件深链需要) | 未创建 / 静态 496 B |
|
||||
| defaultTask | `1024*4` | 4KB | FatFS 挂载/探针 + 配置引擎 + syslog + 栈水位探针 | 2152 B(余 47%)/ 静态 2776 B |
|
||||
| timeSyncTask | `512*4` | 2KB | TCP 时间同步 | 616 B(余 69%)/ 静态 **1024 B**(= ISR 底线,无再加深空间) |
|
||||
| idle(内核) | `configMINIMAL_STACK_SIZE=128` | 0.5KB | 空闲 | 未观测(未取句柄) |
|
||||
| timer(内核) | `configTIMER_TASK_STACK_DEPTH=256` | 1KB | 软定时器 | 未观测 |
|
||||
|
||||
@@ -322,7 +325,7 @@ void vApplicationMallocFailedHook(void)
|
||||
|
||||
要点与边界:
|
||||
|
||||
- defaultTask 的静态最坏链是**配置保存/旧档迁移**路径,不是首启探针路径:
|
||||
- defaultTask 的静态最坏链是**配置保存/旧档迁移**路径,不是首启探针路径(**2026-09-21 当时的链;旧档迁移已于 2026-10-10 删除、日志行缓冲已按模块收紧,现链见下方"2026-10-10 复测"**):
|
||||
`net_cfg_load → net_cfg_legacy_migrate → net_cfg_save → cfg_file_save → s_write_template → s_write_doc → cfg_store_write_atomic → f_rename → follow_path → dir_next → create_chain → put_fat → move_window → sync_window → disk_write → ftl_flush_cache → dhara_map_write → prepare_write → auto_gc → dhara_map_gc → ... → trace_path → dhara_journal_read_meta → dhara_nand_read → gd5f_read_from_cache → HAL_SPI_Receive → ... → SPI_WaitFlagStateUntilTimeout`。
|
||||
**2776 B > 2048 B** → 512 words 栈必然溢出,与 2026-09-21 实测完全一致。
|
||||
- 帧宽榜直接点名宽度大户(自身帧):`s_append` 704 B(FIL 512 + 记录 64 + 时间戳)、`StartDefaultTask` 560 B(探针 `FIL __chk`)、`cfg_store_read`/`cfg_store_write_atomic` 576 B、LVGL 绘制 624/560/400 B——与 §1.4 的整改项对得上。**lftpd 三项已于 2026-09-21 静态化(§1.4),已退出帧宽榜前 15**(原 `handle_control_channel` 1104 B、`receive_file`/`send_file` 1088 B、`send_response` 800 B)。
|
||||
@@ -330,6 +333,56 @@ void vApplicationMallocFailedHook(void)
|
||||
- testTask 在产品构建里只是 `osDelay` 空循环(168 B);2048 words 是给**存储套件构建**(`TEST_SUITE_STORAGE`)预留的,测套件时应重跑本脚本看该构建的静态值。
|
||||
- **测 ftpTask 的复现配方**:设备就绪后跑 `& '.venv\Scripts\python.exe' test/host/ftp_speed_test.py --size 128`(STOR 128KB + RETR + 逐字节比对),再按上面命令叠加串口日志出报告。**不要用裸 TCP 工具探测 21 端口**——CH395F 单客户端复用,探测会占掉唯一会话(见 FTP 指南 §8.9)。
|
||||
|
||||
#### 2026-10-10 复测:**不抬栈**把 defaultTask 从 FAIL 拉回 PASS(S-1 销项)
|
||||
|
||||
触发点:登记簿 S-1(2026-10-04 实测 defaultTask 3664B/4096,余量 10%)。叠加静态链后判据更严——
|
||||
**静态最坏链已涨到 5312 B > 配置 4096 B(margin −1216 B)**。本次刻意**不动栈值**,改为削链:
|
||||
|
||||
| 任务 | 配置 (B) | 静态最坏 改前 → 改后 | 实测峰值 改前 → 改后 | 判定 |
|
||||
|---|---|---|---|---|
|
||||
| **defaultTask** | 4096 | **5312 → 2776** | 3392 → **2152** | FAIL → **PASS(余 1320 B / 32%)** |
|
||||
| netTask | 3840 | 2664 → 1872 | 1008 → 920 | PASS(51%) |
|
||||
| ftpTask | 4096 | 1800 → 1216 | 756 → 740 | PASS(70%) |
|
||||
| uiTask | 16384 | 1536 → 1336 | 4024 → 4052 | PASS(75%) |
|
||||
| **timeSyncTask** | 2048 | **1736 → 1024** | 760 → 616 | FAIL → **PASS(余 1024 B = ISR 底线,正好卡住)** |
|
||||
| testTask | 8192 | 928 → 496 | —(产品构建不创建) | PASS(93%) |
|
||||
|
||||
四个杠杆(按收益排序,只动自研代码,第三方 dhara/FatFS/HAL 一行未改):
|
||||
|
||||
1. **删旧档 NCFG 迁移**(`Drivers/BSP/NETCFG/net_cfg_legacy.c/h` 整体移除,链 −600 B):
|
||||
`net_cfg_load` 无条件调 `net_cfg_legacy_migrate()`,把整条配置**写**链(`net_cfg_save →
|
||||
cfg_file_save → s_write_template → s_write_doc → cfg_store_write_atomic → f_rename → FTL`)
|
||||
挂进启动期调用图。本仓库无携带 `/cfg/netcfg.bin` 的设备 → 按"不保留旧档兼容"处置;
|
||||
旧档若存在则**忽略**(不读、不删、不迁移),配置回落工厂默认。
|
||||
2. **6 处局部 `FIL` 改函数级 `static`**(每处 −528 B):`Lib/FatFs/ffconf.h` `FF_FS_TINY=0` →
|
||||
`FIL` 内含 `buf[FF_MAX_SS]` = 512 B。落点 `App/log/sys_log_mcu.c`(3 处)、
|
||||
`App/cfg/cfg_file_store_mcu.c`(2 处)、`App/task/default_task.c` 探针宏(1 处)。
|
||||
安全性依据:整个 FIL 生命周期都在 `vol_lock_wait()/release()` 区间内(跨任务被卷锁串行化)
|
||||
+ 配置引擎/syslog 写者单任务属主(P1-3)。先例 = 2026-09-21 lftpd 9 处大局部缓冲静态化。
|
||||
3. **日志行缓冲按模块收紧 + 时间戳缓冲并入行缓冲**(每个日志调用点原内联 `192 + 32 = 224 B`):
|
||||
`dbg_log.h` 新增 `DBG_LINE_BUF_MAX`(默认仍 = `DBG_CON_LINE_MAX` 192),深链模块
|
||||
(`nand_ftl.c`/`gd5f2gq5ue.c`/`cfg_file.c`/`net_cfg.c`/`net_socket.c`/`ch395f.c`/`time_sync.c`/
|
||||
`default_task.c`)收到 **128**;`DBG_TS_BUF_MAX` 32 → 24 且与行缓冲共用一个数组。
|
||||
实测链上 9 个帧各含一份行缓冲 → **仅这一项就占 defaultTask 最坏链约 1.5 KB**。
|
||||
⚠ 取值须 ≥ 该模块最长日志行(各文件注释里已给出实测行长),否则该行被截断。
|
||||
4. **内核钩子脱离 HAL 发送路径**:`configASSERT` 在 FreeRTOS 内部可达 → `vApplicationAssertFailed`
|
||||
挂在**每个**任务的最坏链尾;它原走 `dbg_console_write_raw → con_tx_bounded →
|
||||
(DWT 不可用时)HAL_UART_Transmit → UART_WaitOnFlagUntilTimeout`。现 `con_tx_bounded` 的
|
||||
DWT 回退改为**指令计数上界**(`CON_TX_GUARD_MAX`),HAL 尾巴从所有链上消失;钩子自身
|
||||
`name[49]/num[16]/rev[16]` 改 static + 原地反转、去掉 `HAL_Delay`(断言现场 tick 未必可信)。
|
||||
|
||||
代价与复核:静态 BSS **+4,128 B**(ZI 133,524 → 137,652;RW_IRAM1 64.9% → 68.1%),Flash 反而 −36 B;
|
||||
FreeRTOS 堆不变(`free=17248 / min_ever=9312`)。验证链:`@build` 0/0 → `@test` 真机 PASS(含烧录回读)
|
||||
→ `stack_report.py` **6/6 PASS**。
|
||||
|
||||
顺带揪出并修掉的**两个静态虚高源**:① `dbg_console_drain` 故障路径调 `syslog_post` →
|
||||
`write_line → con_append → drain → syslog_post → write_line` **调用图成环**(运行时有
|
||||
`s_con_draining` 重入标志挡着不会真递归,但 armlink 把整条日志尾巴在每个任务上多叠一层)——
|
||||
现改为置标志、由写者任务在 drain 之外补记 run.log(`dbg_console_tx_fault_log_take()`);
|
||||
② 上述 HAL 发送回退。**教训:静态链异常高时先查"链尾是不是日志/钩子",再动业务代码。**
|
||||
|
||||
**留作候选、本轮刻意未做**:① **共享静态行缓冲池**(`dbg_console_line_claim()/release()` 发还栈上数组,改为从 2 个静态槽领取)——可再削每条日志帧的全部 152 B(全链再省 ~1.3 KB),但把"日志缓冲在调用者栈上"改成"跨任务共享 + 抢占失败即丢行",**改变日志并发语义**,需配套主机侧单测才动;② `timeSyncTask` 静态余量已正好等于 1024 B ISR 底线,**该链上再加任何调用都必须先抬栈**(已在 `Src/freertos.c` 栈注释里写明)。
|
||||
|
||||
#### 阶段 0 验收
|
||||
|
||||
- 串口可见 `[STACK]` 报告:每任务 `peak_used/free_min` + 堆 `free/min_ever`
|
||||
@@ -393,7 +446,7 @@ ISR 余量:该任务运行期间可能被中断打断的最深中断链(SPI/
|
||||
| netTask | 4KB | **2KB** | 实测 588B → 1024+1024=2048B |
|
||||
| ftpTask | 4KB | **3KB** | 实测 1184B(§1.4 静态化后)→ 1776+1024=2800B → 3KB;再降须放宽 ISR 余量并复测 |
|
||||
| testTask | 8KB | **2KB** | 产品构建空转(实测 348B)→ 1024+1024;存储套件构建按该构建静态值另放大 |
|
||||
| defaultTask | 4KB | **保持 4KB** | 静态最坏 2776B(配置保存/旧档迁移深链,§0.6)→ 缩减必溢出 |
|
||||
| defaultTask | 4KB | **保持 4KB** | 2026-10-10 削链后静态最坏 2776B / 实测 2152B(余 32%);曾达 5312B 溢出判据,见"2026-10-10 复测" |
|
||||
| timeSyncTask | 2KB | **保持 2KB** | 实测 420B → 1024+1024=2048B,无缩减空间 |
|
||||
|
||||
缩减后任务栈合计 38,912 → 21,504 B(**省 17,408 B / ~17 KB**,全部在 CCM 堆内,主 SRAM 不受影响)。
|
||||
|
||||
@@ -0,0 +1,197 @@
|
||||
# STM32F4-Base RAM/Flash Usage Report
|
||||
|
||||
> Generated: 2026-10-10 09:17 Map: `STM32F407-Demo.map`
|
||||
|
||||
## 1. Grand Totals (全局总量)
|
||||
|
||||
| Metric | Value |
|
||||
|---|---|
|
||||
| Code (inc. data) | 252,092 B (246.2 KB) |
|
||||
| RO Data | 15,436 B (15.1 KB) |
|
||||
| RW Data (initialized) | 748 B (0.73 KB) |
|
||||
| ZI Data (zero-init) | 137,652 B (134.4 KB) |
|
||||
| **Total RO (Code + RO)** | **267,528 B (261.3 KB)** |
|
||||
| **Total RW (RW + ZI) = SRAM used** | **138,400 B (135.16 KB)** |
|
||||
| **Total ROM (Code + RO + RW init)** | **268,276 B (262.0 KB)** |
|
||||
|
||||
## 2. 执行区水位 (Execution Regions)
|
||||
|
||||
| Region | Base | Size | Max | Util% |
|
||||
|---|---|---|---|---|
|
||||
| ER_IROM1 | 0x08000000 | 267,528 B (261.26 KB) | 1,048,576 B (1024 KB) | 25.5% |
|
||||
| RW_CCM | 0x10000000 | 49,184 B (48.03 KB) | 65,280 B (64 KB) | 75.3% |
|
||||
| UNINIT_CCM | 0x1000FF00 | 48 B (0.05 KB) | 256 B (0 KB) | 18.8% |
|
||||
| RW_IRAM1 | 0x20000000 | 89,168 B (87.08 KB) | 131,072 B (128 KB) | 68.0% |
|
||||
|
||||
## 3. RW_IRAM1 逐符号明细(ZI + RW,按大小降序)
|
||||
|
||||
| # | Address | Size (B) | Size (KB) | Type | Section | Object |
|
||||
|---|---|---|---|---|---|---|
|
||||
| 1 | 0x200083F0 | 40,960 | 40.00 | Zero | .bss | lv_mem_core_builtin.o |
|
||||
| 2 | 0x20013DF2 | 6,746 | 6.59 | Zero | .bss | ui_net_sink.o |
|
||||
| 3 | 0x200123F0 | 6,408 | 6.26 | Zero | .bss | ui_port.o |
|
||||
| 4 | 0x200048C4 | 6,200 | 6.05 | Zero | .bss | nand_ftl.o |
|
||||
| 5 | 0x200060FC | 4,616 | 4.51 | Zero | .bss | lftpd.o |
|
||||
| 6 | 0x200031B0 | 4,104 | 4.01 | Zero | .bss | ch395f.o |
|
||||
| 7 | 0x200016E0 | 4,096 | 4.00 | Zero | .bss | console_log.o |
|
||||
| 8 | 0x20002718 | 2,712 | 2.65 | Zero | .bss | default_task.o |
|
||||
| 9 | 0x20000F68 | 1,912 | 1.87 | Zero | .bss | sys_log_mcu.o |
|
||||
| 10 | 0x20007B48 | 1,720 | 1.68 | Zero | .bss | cmsis_os2.o |
|
||||
| 11 | 0x2000756C | 1,220 | 1.19 | Zero | .bss | tasks.o |
|
||||
| 12 | 0x20000B18 | 1,104 | 1.08 | Zero | .bss | cfg_file_store_mcu.o |
|
||||
| 13 | 0x20015850 | 1,024 | 1.00 | Zero | | startup_stm32f407xx.o |
|
||||
| 14 | 0x200041B8 | 800 | 0.78 | Zero | .bss | gd5f2gq5ue.o |
|
||||
| 15 | 0x20000858 | 704 | 0.69 | Zero | .bss | cfg_file.o |
|
||||
| 16 | 0x20004604 | 704 | 0.69 | Zero | .bss | net_socket.o |
|
||||
| 17 | 0x200003B8 | 560 | 0.55 | Zero | .bss | spi.o |
|
||||
| 18 | 0x200005E8 | 552 | 0.54 | Zero | .bss | usart.o |
|
||||
| 19 | 0x20007304 | 552 | 0.54 | Zero | .bss | lftpd_io.o |
|
||||
| 20 | 0x20008200 | 496 | 0.48 | Zero | .bss | lv_init.o |
|
||||
| 21 | 0x20007A30 | 280 | 0.27 | Zero | .bss | timers.o |
|
||||
| 22 | 0x200044F8 | 268 | 0.26 | Zero | .bss | rs485.o |
|
||||
| 23 | 0x20000134 | 152 | 0.15 | Data | .data | lftpd.o |
|
||||
| 24 | 0x20013CF8 | 152 | 0.15 | Zero | .bss | ui_menu_view.o |
|
||||
| 25 | 0x20000358 | 84 | 0.08 | Zero | .bss | i2c.o |
|
||||
| 26 | 0x20000310 | 72 | 0.07 | Zero | .bss | adc.o |
|
||||
| 27 | 0x20000810 | 72 | 0.07 | Zero | .bss | stm32f4xx_hal_timebase_tim.o |
|
||||
| 28 | 0x200002CC | 65 | 0.06 | Zero | .bss | freertos.o |
|
||||
| 29 | 0x2000752C | 64 | 0.06 | Zero | .bss | queue.o |
|
||||
| 30 | 0x200001D0 | 60 | 0.06 | Data | .data | tasks.o |
|
||||
| 31 | 0x200026E0 | 56 | 0.05 | Zero | .bss | task_watchdog.o |
|
||||
| 32 | 0x20013D90 | 49 | 0.05 | Zero | .bss | ui_page_runlog.o |
|
||||
| 33 | 0x20013DC1 | 49 | 0.05 | Zero | .bss | ui_page_selftest.o |
|
||||
| 34 | 0x20000064 | 44 | 0.04 | Data | .data | task_watchdog.o |
|
||||
| 35 | 0x200000D4 | 44 | 0.04 | Data | .data | net_socket.o |
|
||||
| 36 | 0x20000100 | 36 | 0.04 | Data | .data | net_cfg.o |
|
||||
| 37 | 0x20000000 | 32 | 0.03 | Data | .data | freertos.o |
|
||||
| 38 | 0x20000298 | 32 | 0.03 | Data | .data | ui_standby.o |
|
||||
| 39 | 0x200044D8 | 32 | 0.03 | Zero | .bss | tpafe5160.o |
|
||||
| 40 | 0x20000044 | 24 | 0.02 | Data | .data | console_log.o |
|
||||
| 41 | 0x20000024 | 20 | 0.02 | Data | .data | cfg_file.o |
|
||||
| 42 | 0x200000B4 | 20 | 0.02 | Data | .data | gd5f2gq5ue.o |
|
||||
| 43 | 0x2000020C | 20 | 0.02 | Data | .data | timers.o |
|
||||
| 44 | 0x20000250 | 18 | 0.02 | Data | .data | ui_menu.o |
|
||||
| 45 | 0x20000124 | 16 | 0.02 | Data | .data | nand_ftl.o |
|
||||
| 46 | 0x200002B8 | 16 | 0.02 | Data | .data | ui_net_sink.o |
|
||||
| 47 | 0x20000038 | 12 | 0.01 | Data | .data | sys_log_mcu.o |
|
||||
| 48 | 0x200000A0 | 12 | 0.01 | Data | .data | stm32f4xx_hal.o |
|
||||
| 49 | 0x200000C8 | 12 | 0.01 | Data | .data | tpafe5160.o |
|
||||
| 50 | 0x20000224 | 12 | 0.01 | Data | .data | port.o |
|
||||
| 51 | 0x20000244 | 12 | 0.01 | Data | .data | ui_port.o |
|
||||
| 52 | 0x2000026C | 12 | 0.01 | Data | .data | ui_content_page.o |
|
||||
| 53 | 0x20000278 | 12 | 0.01 | Data | .data | ui_page_password.o |
|
||||
| 54 | 0x200003AC | 12 | 0.01 | Zero | .bss | iwdg.o |
|
||||
| 55 | 0x2000005C | 8 | 0.01 | Data | .data | sys_clock.o |
|
||||
| 56 | 0x20000094 | 8 | 0.01 | Data | .data | default_task.o |
|
||||
| 57 | 0x20000230 | 8 | 0.01 | Data | .data | ff.o |
|
||||
| 58 | 0x20000238 | 8 | 0.01 | Data | .data | ffsystem.o |
|
||||
| 59 | 0x20000264 | 8 | 0.01 | Data | .data | ui_menu_view.o |
|
||||
| 60 | 0x20000288 | 8 | 0.01 | Data | .data | ui_page_runlog.o |
|
||||
| 61 | 0x20000290 | 8 | 0.01 | Data | .data | ui_page_selftest.o |
|
||||
| 62 | 0x20000020 | 4 | 0.00 | Data | .data | app_main.o |
|
||||
| 63 | 0x20000090 | 4 | 0.00 | Data | .data | vol_lock.o |
|
||||
| 64 | 0x2000009C | 4 | 0.00 | Data | .data | net_task.o |
|
||||
| 65 | 0x200000AC | 4 | 0.00 | Data | .data | system_stm32f4xx.o |
|
||||
| 66 | 0x200001CC | 4 | 0.00 | Data | .data | lftpd_io.o |
|
||||
| 67 | 0x20000220 | 4 | 0.00 | Data | .data | cmsis_os2.o |
|
||||
| 68 | 0x20000240 | 4 | 0.00 | Data | .data | lv_textarea.o |
|
||||
| 69 | 0x200002C8 | 4 | 0.00 | Data | .data | mc_w.l(errno.o) |
|
||||
| 70 | 0x200000B0 | 2 | 0.00 | Data | .data | ch395f.o |
|
||||
| 71 | 0x20000284 | 2 | 0.00 | Data | .data | ui_page_net_cfg.o |
|
||||
| | | **89,155** | **87.07** | | | **Total** |
|
||||
|
||||
## 4. Image Component Sizes(RW + ZI > 0,按大小降序)
|
||||
|
||||
| # | Object | Code | RO | RW | ZI | RW+ZI |
|
||||
|---|---|---|---|---|---|---|
|
||||
| 1 | heap_4.o | 512 | 69 | 32 | 49,152 | 49,184 |
|
||||
| 2 | lv_mem_core_builtin.o | 410 | 0 | 0 | 40,960 | 40,960 |
|
||||
| 3 | ui_net_sink.o | 1,102 | 67 | 16 | 6,746 | 6,762 |
|
||||
| 4 | ui_port.o | 418 | 0 | 12 | 6,408 | 6,420 |
|
||||
| 5 | nand_ftl.o | 2,082 | 83 | 16 | 6,200 | 6,216 |
|
||||
| 6 | lftpd.o | 5,336 | 503 | 152 | 4,616 | 4,768 |
|
||||
| 7 | console_log.o | 968 | 55 | 24 | 4,096 | 4,120 |
|
||||
| 8 | ch395f.o | 2,796 | 345 | 2 | 4,104 | 4,106 |
|
||||
| 9 | default_task.o | 2,048 | 229 | 8 | 2,712 | 2,720 |
|
||||
| 10 | sys_log_mcu.o | 2,078 | 83 | 12 | 1,912 | 1,924 |
|
||||
| 11 | cmsis_os2.o | 1,216 | 0 | 4 | 1,720 | 1,724 |
|
||||
| 12 | tasks.o | 4,034 | 0 | 60 | 1,220 | 1,280 |
|
||||
| 13 | cfg_file_store_mcu.o | 380 | 24 | 0 | 1,104 | 1,104 |
|
||||
| 14 | startup_stm32f407xx.o | 36 | 392 | 0 | 1,024 | 1,024 |
|
||||
| 15 | gd5f2gq5ue.o | 3,930 | 478 | 20 | 800 | 820 |
|
||||
| 16 | net_socket.o | 6,682 | 779 | 44 | 704 | 748 |
|
||||
| 17 | cfg_file.o | 5,922 | 810 | 20 | 704 | 724 |
|
||||
| 18 | spi.o | 584 | 0 | 0 | 560 | 560 |
|
||||
| 19 | lftpd_io.o | 1,198 | 0 | 4 | 552 | 556 |
|
||||
| 20 | usart.o | 884 | 0 | 0 | 552 | 552 |
|
||||
| 21 | lv_init.o | 156 | 0 | 0 | 496 | 496 |
|
||||
| 22 | timers.o | 1,232 | 0 | 20 | 280 | 300 |
|
||||
| 23 | rs485.o | 120 | 0 | 0 | 268 | 268 |
|
||||
| 24 | ui_menu_view.o | 2,034 | 108 | 8 | 152 | 160 |
|
||||
| 25 | task_watchdog.o | 1,098 | 137 | 44 | 104 | 148 |
|
||||
| 26 | freertos.o | 656 | 452 | 32 | 65 | 97 |
|
||||
| 27 | i2c.o | 168 | 0 | 0 | 84 | 84 |
|
||||
| 28 | adc.o | 392 | 0 | 0 | 72 | 72 |
|
||||
| 29 | stm32f4xx_hal_timebase_tim.o | 152 | 0 | 0 | 72 | 72 |
|
||||
| 30 | queue.o | 2,840 | 0 | 0 | 64 | 64 |
|
||||
| 31 | ui_page_runlog.o | 168 | 93 | 8 | 49 | 57 |
|
||||
| 32 | ui_page_selftest.o | 168 | 93 | 8 | 49 | 57 |
|
||||
| 33 | tpafe5160.o | 704 | 67 | 12 | 32 | 44 |
|
||||
| 34 | net_cfg.o | 828 | 103 | 36 | 0 | 36 |
|
||||
| 35 | ui_standby.o | 1,208 | 159 | 32 | 0 | 32 |
|
||||
| 36 | ui_menu.o | 816 | 137 | 18 | 0 | 18 |
|
||||
| 37 | (incl. Padding) | 312 | 87 | 6 | 7 | 13 |
|
||||
| 38 | iwdg.o | 28 | 0 | 0 | 12 | 12 |
|
||||
| 39 | port.o | 762 | 73 | 12 | 0 | 12 |
|
||||
| 40 | stm32f4xx_hal.o | 116 | 0 | 12 | 0 | 12 |
|
||||
| 41 | ui_content_page.o | 1,720 | 199 | 12 | 0 | 12 |
|
||||
| 42 | ui_page_password.o | 686 | 167 | 12 | 0 | 12 |
|
||||
| 43 | ff.o | 7,962 | 282 | 8 | 0 | 8 |
|
||||
| 44 | ffsystem.o | 204 | 20 | 8 | 0 | 8 |
|
||||
| 45 | sys_clock.o | 1,788 | 286 | 8 | 0 | 8 |
|
||||
| 46 | app_main.o | 1,660 | 65 | 4 | 0 | 4 |
|
||||
| 47 | lv_textarea.o | 3,632 | 48 | 4 | 0 | 4 |
|
||||
| 48 | net_task.o | 1,452 | 72 | 4 | 0 | 4 |
|
||||
| 49 | system_stm32f4xx.o | 16 | 24 | 4 | 0 | 4 |
|
||||
| 50 | vol_lock.o | 92 | 0 | 4 | 0 | 4 |
|
||||
| 51 | errno.o | 8 | 0 | 4 | 0 | 4 |
|
||||
| 52 | ui_page_net_cfg.o | 1,004 | 93 | 2 | 0 | 2 |
|
||||
| | **All .o files** | **252,092** | **15,436** | **748** | **137,652** | **138,400** |
|
||||
|
||||
## 5. Flash (Code + RO Data) Top-30(按大小降序)
|
||||
|
||||
| # | Object | Code | RO Data | Code+RO |
|
||||
|---|---|---|---|---|
|
||||
| 1 | ff.o | 7,962 | 282 | 8,244 |
|
||||
| 2 | lv_draw_sw_blend_to_rgb565_swapped.o | 7,648 | 0 | 7,648 |
|
||||
| 3 | net_socket.o | 6,682 | 779 | 7,461 |
|
||||
| 4 | lv_draw_sw_blend_to_rgb565.o | 7,020 | 0 | 7,020 |
|
||||
| 5 | cfg_file.o | 5,922 | 810 | 6,732 |
|
||||
| 6 | lftpd.o | 5,336 | 503 | 5,839 |
|
||||
| 7 | lv_draw_sw_blend_to_argb8888.o | 5,412 | 0 | 5,412 |
|
||||
| 8 | lv_draw_sw_blend_to_i1.o | 5,272 | 0 | 5,272 |
|
||||
| 9 | lv_indev.o | 4,958 | 0 | 4,958 |
|
||||
| 10 | ui_font_cn_12.o | 0 | 4,626 | 4,626 |
|
||||
| 11 | lv_draw_sw_blend_to_rgb888.o | 4,560 | 0 | 4,560 |
|
||||
| 12 | lv_obj_pos.o | 4,526 | 16 | 4,542 |
|
||||
| 13 | lv_refr.o | 4,486 | 0 | 4,486 |
|
||||
| 14 | gd5f2gq5ue.o | 3,930 | 478 | 4,408 |
|
||||
| 15 | lv_draw_sw_transform.o | 4,340 | 0 | 4,340 |
|
||||
| 16 | lv_obj_style.o | 4,138 | 0 | 4,138 |
|
||||
| 17 | lv_obj_scroll.o | 4,126 | 0 | 4,126 |
|
||||
| 18 | lv_label.o | 4,042 | 45 | 4,087 |
|
||||
| 19 | tasks.o | 4,034 | 0 | 4,034 |
|
||||
| 20 | lv_draw_sw_mask.o | 3,862 | 0 | 3,862 |
|
||||
| 21 | lv_draw_sw_blend_to_l8.o | 3,778 | 0 | 3,778 |
|
||||
| 22 | lv_buttonmatrix.o | 3,586 | 125 | 3,711 |
|
||||
| 23 | lv_textarea.o | 3,632 | 48 | 3,680 |
|
||||
| 24 | stm32f4xx_hal_spi.o | 3,586 | 0 | 3,586 |
|
||||
| 25 | lv_draw_sw_blend_to_al88.o | 3,560 | 0 | 3,560 |
|
||||
| 26 | lv_draw_sw_blend_to_argb8888_premultiplied.o | 3,332 | 0 | 3,332 |
|
||||
| 27 | lv_draw_sw_box_shadow.o | 3,246 | 0 | 3,246 |
|
||||
| 28 | ch395f.o | 2,796 | 345 | 3,141 |
|
||||
| 29 | lv_indev_scroll.o | 3,068 | 0 | 3,068 |
|
||||
| 30 | lv_obj.o | 2,982 | 43 | 3,025 |
|
||||
| | **All .o files** | **252,092** | **15,436** | **267,528** |
|
||||
|
||||
> 自洽校验:per-file 252,092/15,436/748/137,652 vs Grand Totals 252,092/15,436/748/137,652(CodeΔ=+0 / ROΔ=+0 / RWΔ=+0 / ZIΔ=+0;精确一致(含 '('incl. Generated)'-'(incl. Padding)' 台账行))→ **PASS**
|
||||
@@ -0,0 +1,79 @@
|
||||
# Stack budget report
|
||||
|
||||
- Source: `MDK-ARM\STM32F407-Demo\STM32F407-Demo.htm` (Keil static call graph)
|
||||
- Linker run: Sat Oct 10 10:13:26 2026
|
||||
- Global maximum stack usage: **2776 B** (any call tree)
|
||||
- Runtime watermark: 5 task(s) from `tools\serial_tool\state\serial.log`
|
||||
|
||||
Rule: `margin = cfg - max(static_max_depth, runtime_peak)` must be >= max(1024 B ISR, 30% of cfg).
|
||||
|
||||
| Task | Entry | Cfg (B) | Static max (B) | Runtime peak (B) | Worst (B) | Margin (B) | Margin % | Verdict |
|
||||
|---|---|---|---|---|---|---|---|---|
|
||||
| defaultTask | `StartDefaultTask` | 4096 | 2776 | 2152 | 2776 | 1320 | 32% | PASS |
|
||||
| netTask | `StartNetTask` | 3840 | 1872 | 920 | 1872 | 1968 | 51% | PASS |
|
||||
| ftpTask | `StartFtpTask` | 4096 | 1216 | 740 | 1216 | 2880 | 70% | PASS |
|
||||
| uiTask | `StartUiTask` | 16384 | 1336 | 4016 | 4016 | 12368 | 75% | PASS |
|
||||
| testTask | `start_test_task` | 8192 | 496 | - | 496 | 7696 | 93% | PASS |
|
||||
| timeSyncTask | `time_sync_task` | 2048 | 1024 | 616 | 1024 | 1024 | 50% | PASS |
|
||||
|
||||
`Static max` = armlink worst-case call-tree depth; `Runtime peak` = measured high-water mark (boot + whatever workload ran before the sample); `Worst` = max of the two, which is what the verdict is computed from.
|
||||
|
||||
Runtime heap: free=17248 B, min_ever=9312 B
|
||||
|
||||
## Worst call chain per task
|
||||
|
||||
### defaultTask: 2776 B (own frame 0 B)
|
||||
|
||||
```
|
||||
StartDefaultTask -> default_task_func -> storage_bring_up -> net_cfg_load -> cfg_file_load -> s_write_template -> s_write_doc -> cfg_store_write_atomic -> f_rename -> sync_fs -> disk_ioctl -> ftl_flush_cache -> dhara_map_write -> prepare_write -> auto_gc -> dhara_map_gc -> try_recover -> raw_gc -> trace_path -> dhara_journal_read_meta -> dhara_nand_read -> gd5f_read_from_cache -> dbg_console_write_line -> con_append -> dbg_console_drain -> MX_USART1_UART_Init -> HAL_UART_Init -> HAL_UART_MspInit -> HAL_GPIO_Init
|
||||
```
|
||||
|
||||
### netTask: 1872 B (own frame 0 B)
|
||||
|
||||
```
|
||||
StartNetTask -> net_task_func -> net_process_messages -> net_send_locked -> net_poll -> handle_disconnect_event -> net_relisten_try -> net_relisten_locked -> ch395f_read_recv_buf -> ch395f_spi_dma_transfer -> ch395f_spi_fault_set -> dbg_console_write_line -> con_append -> dbg_console_drain -> MX_USART1_UART_Init -> HAL_UART_Init -> HAL_UART_MspInit -> HAL_GPIO_Init
|
||||
```
|
||||
|
||||
### ftpTask: 1216 B (own frame 24 B)
|
||||
|
||||
```
|
||||
StartFtpTask -> lftpd_start -> lftpd_inet_listen -> net_bind -> ch395f_open_socket -> ch395f_poll_cmd_status -> ch395f_get_cmd_status -> ch395f_write_cmd -> ch395f_spi_fault_set -> dbg_console_write_line -> con_append -> dbg_console_drain -> MX_USART1_UART_Init -> HAL_UART_Init -> HAL_UART_MspInit -> HAL_GPIO_Init
|
||||
```
|
||||
|
||||
### uiTask: 1336 B (own frame 0 B)
|
||||
|
||||
```
|
||||
StartUiTask -> ui_task_func -> ui_menu_init -> ui_menu_view_init -> lv_obj_create -> lv_obj_class_init_obj -> lv_theme_apply -> lv_obj_remove_style_all -> lv_obj_remove_style -> lv_obj_refresh_style -> refresh_children_style -> refresh_children_style (Cycle)
|
||||
```
|
||||
|
||||
### testTask: 496 B (own frame 224 B)
|
||||
|
||||
```
|
||||
start_test_task -> dbg_console_write_line -> con_append -> dbg_console_drain -> MX_USART1_UART_Init -> HAL_UART_Init -> HAL_UART_MspInit -> HAL_GPIO_Init
|
||||
```
|
||||
|
||||
### timeSyncTask: 1024 B (own frame 152 B)
|
||||
|
||||
```
|
||||
time_sync_task -> time_sync_open_listener -> net_bind -> ch395f_open_socket -> ch395f_poll_cmd_status -> ch395f_get_cmd_status -> ch395f_write_cmd -> ch395f_spi_fault_set -> dbg_console_write_line -> con_append -> dbg_console_drain -> MX_USART1_UART_Init -> HAL_UART_Init -> HAL_UART_MspInit -> HAL_GPIO_Init
|
||||
```
|
||||
|
||||
## Frame-size ranking (own frame, top 15)
|
||||
|
||||
| Bytes | Function |
|
||||
|---|---|
|
||||
| 624 | `lv_draw_sw_arc` |
|
||||
| 624 | `draw_indic` |
|
||||
| 560 | `draw_main` |
|
||||
| 400 | `draw_line_skew` |
|
||||
| 352 | `lv_draw_sw_triangle` |
|
||||
| 352 | `net_stack_bring_up` |
|
||||
| 344 | `s_append` |
|
||||
| 328 | `lv_obj_redraw` |
|
||||
| 328 | `view_frame_draw_cb` |
|
||||
| 320 | `wd_stall_evidence` |
|
||||
| 312 | `nc_draw_cb` |
|
||||
| 304 | `lv_draw_label_iterate_characters` |
|
||||
| 304 | `lv_draw_sw_box_shadow` |
|
||||
| 304 | `sys_clock_init` |
|
||||
| 304 | `draw_cursor` |
|
||||
@@ -193,9 +193,10 @@ sequenceDiagram
|
||||
|
||||
### 4.4 裸发(`dbg_console_write_raw`)
|
||||
|
||||
- 有界:`len > 256 → 256`(截尾);单次阻塞 `HAL_UART_Transmit`(超时 `0xFFFF`),不持临界区、不等待状态;
|
||||
- 有界:`len > 256 → 256`(截尾);发送走 `con_tx_bounded`(**寄存器级轮询 TXE/TC**,超时判据 = DWT `CYCCNT`,`CON_TX_TIMEOUT_CYC` = 100 ms 对应周期数),不持临界区、不等待状态;
|
||||
- **2026-10-10:DWT 不可用时改走 `con_tx_counted`(指令计数上界 `CON_TX_GUARD_MAX`),不再回退 `HAL_UART_Transmit`**。两个理由:① HAL 的超时判据是 `HAL_GetTick`——断言/停摆现场 tick 未必在走;② `HAL_UART_Transmit → UART_WaitOnFlagUntilTimeout` 这条尾巴会被 armlink 挂进**每个**碰日志的任务的最坏栈链(`configASSERT` 在 FreeRTOS 内部可达 → 三个内核钩子都在链尾),实测每条链多背 64 B;
|
||||
- 适用:内核前 / 未注册期、ISR、异常钩子(栈溢出 / 堆失败)、崩溃上报;
|
||||
- 调用方纪律:**只交已知合法的缓冲**——钩子侧先做指针范围校验(Flash / SRAM / CCM 窗口)并拷入本地缓冲再发,TCB 指针不接触 UART(`Src/freertos.c vApplicationStackOverflowHook`,2026-09-24 加固;指针不可信时发占位文本,"上报崩溃的代码不能再崩一次")。
|
||||
- 调用方纪律:**只交已知合法的缓冲**——钩子侧先做指针范围校验(Flash / SRAM / CCM 窗口)并拷入本地缓冲再发,TCB 指针不接触 UART(`Src/freertos.c vApplicationStackOverflowHook`,2026-09-24 加固;指针不可信时发占位文本,"上报崩溃的代码不能再崩一次")。2026-10-10 补充:钩子里的 `name[49]/num[16]` 改**函数级 static**(终点路径、打印完即复位,无并发)——放栈上会让这 81 B 出现在每个任务的最坏链上;行号转换改原地反转,去掉 `HAL_Delay`(`con_tx_bounded` 已等 TC)。
|
||||
|
||||
### 4.5 `fputc` 重定向(MicroLIB `printf`)
|
||||
|
||||
@@ -225,16 +226,21 @@ sequenceDiagram
|
||||
| `dbg_console_writer_attach` | `void (void)` | 写者任务、主循环前 | 注册唯一写者 | 仅一次(defaultTask) |
|
||||
| `dbg_console_drain` | `void (void)` | **仅写者任务** | 排空环并发出 + 刷丢弃计数 | defaultTask 主循环周期调用 |
|
||||
| `dbg_console_dropped` | `uint32_t (void)` | 任意 | 诊断:累计丢弃行数 | 外部读取 |
|
||||
| `dbg_console_tx_fault_log_take` | `uint8_t (void)` | **仅写者任务** | 取并清"TX 故障待上报"标志 | 2026-10-10 加:drain 内**不得**调 `syslog_post`(会成环),由 defaultTask 在 drain 之外补记 run.log |
|
||||
| `fputc` | `int (int ch, FILE *f)` | `printf` 调用点 | MicroLIB retarget 钩子 → 逐字节 `con_append` | 须为全局符号(C 库链接) |
|
||||
|
||||
## 6. 常量
|
||||
|
||||
| 常量 | 值 | 定义处 | 含义 |
|
||||
|------|-----|--------|------|
|
||||
| `DBG_CON_LINE_MAX` | 192 | `console_log.h` | 单行文本上限(含结尾 `'\0'`);`DBG_PRINT` 宏行缓冲尺寸;超限截断 |
|
||||
| `DBG_CON_LINE_MAX` | 192 | `console_log.h` | 单行文本上限(含结尾 `'\0'`);环形缓冲/入环截断上限;超限截断 |
|
||||
| `DBG_LINE_BUF_MAX` | = `DBG_CON_LINE_MAX`(深链模块设 **128**) | `dbg_log.h` | **调用点栈上行缓冲尺寸**(2026-10-10 加)。已收紧:`nand_ftl`/`gd5f2gq5ue`/`cfg_file`/`net_cfg`/`net_socket`/`ch395f`/`time_sync`/`default_task`。取值须 ≥ 该模块最长日志行,否则该行被截断 |
|
||||
| `DBG_TS_BUF_MAX` | 24 | `dbg_log.h` | 时间戳文本缓冲(`sys_clock_get_str` 恒写 19 字符 + `'\0'`);与行缓冲**共用一个数组** |
|
||||
| `DBG_CON_RING_SIZE` | 4096 | `console_log.c` | 环形缓冲字节数(必须为 2 的幂) |
|
||||
| `DBG_CON_CHUNK_MAX` | 256 | `console_log.c` | 写者单次发送上限 = 裸发上限 |
|
||||
| `DBG_CON_WAIT_MS` | 200 | `console_log.c` | 缓冲满时生产者最长等待(1ms/轮,仍满 → 丢弃 + 计数) |
|
||||
| `CON_TX_TIMEOUT_CYC` | `SystemCoreClock/10` | `console_log.c` | 裸发硬上界 = 100 ms 对应 DWT 周期数 |
|
||||
| `CON_TX_GUARD_MAX` | 20000 | `console_log.c` | DWT 不可用时的**计数**上界(每字节 / TC 各数一次;115200 下一字节约需 3000 次轮询,留 6 倍余量) |
|
||||
| 写者循环超时 | 50 ms | `App/task/default_task.c` | `osEventFlagsWait` 兜底周期 |
|
||||
|
||||
## 7. 失效模式与可观测性
|
||||
@@ -247,7 +253,7 @@ sequenceDiagram
|
||||
| ISR 直发撞写者发送中 | 立即 `HAL_BUSY` 返回 → 丢失,不挂死 | 未计数 | ISR 日志频率极低,best-effort 语义 |
|
||||
| 内核状态损坏(栈溢出 / 堆耗尽) | 钩子裸发固定文本 → 复位(栈溢出)/ 仅告警(堆) | `[ERR] STACK OVERFLOW task=…` / `[ERR] MALLOC FAILED …`;任务名范围校验 + 本地拷贝,TCB 指针不入 UART | — |
|
||||
| 调用方指针损坏(脏指针) | 无法进入 UART(缓冲恒为环 / 模块本地) | 2026-09-24 HardFault 路径结构性消除 | — |
|
||||
| UART 物理失效(发送卡死 / 超时) | `HAL_UART_Transmit` 返回 `HAL_TIMEOUT`;调用点忽略返回值(best-effort 控制台),该块丢弃 | 不入丢弃计数(与"缓冲满"独立);UART 故障由其他可观测面暴露(自检 / 其余日志) | 已知缺口:超时未计数(v2 可加超时计数) |
|
||||
| UART 物理失效(发送卡死 / 超时) | `con_tx_bounded` 在 DWT 上界内返回 `HAL_TIMEOUT` → 该块丢弃 + **UART 重初始化**(僵尸通道自愈,§12) | 2026-10-10 起:drain 内**只置标志** `s_con_tx_fault_log`,由 defaultTask 在 drain 之外 `syslog_post(SYSLOG_RUN, "console tx fault, uart reinit")` 补记 run.log(旧实现直接在 drain 里调 `syslog_post` → `write_line → con_append → drain → syslog_post → write_line` **调用图成环**,静态栈在每个任务上多叠一条日志尾巴) | 已知缺口:丢弃计数与故障计数不分离 |
|
||||
| `sys_evt` 对象缺失(句柄 NULL) | 唤醒空操作,50ms 兜底 | 至多 50ms 时延 | — |
|
||||
|
||||
## 8. 内存预算
|
||||
@@ -256,10 +262,12 @@ sequenceDiagram
|
||||
|----|------|------|
|
||||
| `s_con_ring` | 4096 B | BSS(SRAM1,非 CCM) |
|
||||
| `s_con_head/tail/drop/writer_up/writer_task` | ≈14 B | BSS |
|
||||
| 生产者行缓冲 `__con_line`(`DBG_PRINT` 宏局部) | 192 B/调用 | 调用者任务栈(入环后即释放,峰值非累积) |
|
||||
| 生产者行缓冲 `__con_line`(`DBG_EMIT` 宏局部) | 默认 192 B + 时间戳 24 B;**深链模块 128 + 24 B**/调用 | 调用者任务栈(入环后即释放,峰值非累积) |
|
||||
|
||||
**结论:静态 +4.1KB(SRAM1);FreeRTOS 堆零增量、无新任务/栈、无新内核对象。** 2026-09-25 实测:`heap free=8776B, min_ever=4816B`(CCM 堆不受影响);`__con_line` 192B 峰值在各任务既有栈预算内(任务栈按 2026-09-21 实测峰值 ×1.5 + 1KB ISR 余量定档,见 AGENTS.md 任务栈表;当日栈水位复测 6 任务全 PASS)。
|
||||
|
||||
> ⚠️ **2026-10-10 修正"行缓冲不贵"的结论**:行缓冲是**每个日志调用点**在栈上内联的一份数组,会进 armlink 最坏调用链。实测 defaultTask 那条最深链上 **9 个帧各含一份**(192 + 32 B)→ **约 1.5 KB 纯粹是日志行缓冲**,是该项目静态栈链的第一大项。处置 = `dbg_log.h` 新增 `DBG_LINE_BUF_MAX`(深链模块收到 128)+ 时间戳缓冲并入行缓冲(32 → 24),**未抬栈**即把该链 5312 → 2776 B。核算与前后对比见 `docs/内存管理/RAM使用分析与优化方案.md`"2026-10-10 复测"。
|
||||
|
||||
## 9. 设计决策与否决的替代方案
|
||||
|
||||
| # | 替代方案 | 否决 / 采纳理由 |
|
||||
@@ -334,3 +342,4 @@ sequenceDiagram
|
||||
| v1.0 | 2026-09-25 | 初版:完整设计说明(背景根因 / 单写者模型 / 详细设计 / API / 参数 / 失效模式 / 内存预算 / 设计决策 / 验证记录);实现位于 `App/log/console_log.{h,c}` |
|
||||
| v1.1 | 2026-09-25 | 文件拆分同步:写者任务体迁至 `App/task/default_task.c`(`Src/freertos.c` 只留 CubeMX 接线与崩溃钩子);§3.2 文件清单 / §4.3 / §6 / §11 位置引用更新 |
|
||||
| v1.2 | 2026-10-02 | 新增 §12 ORE 僵尸通道(台架 gen-288 实证:节奏性喂狗饥饿,非死等;缓解已做、TX-only 根治待办)+ §11 时间线两条 10-02 记录;§13 新增 O4;原 §12/§13 顺延为 §13/§14 |
|
||||
| v1.3 | 2026-10-10 | 栈链整改(**未抬栈**)三处:① 裸发改为纯寄存器轮询——DWT 不可用时走 `con_tx_counted`(计数上界),**不再回退 `HAL_UART_Transmit`**(tick 依赖不可信 + 其调用链污染所有任务最坏栈链);② 切断 `drain → syslog_post → write_line` **调用图成环**,改为置标志 + 写者任务在 drain 之外补记(新 API `dbg_console_tx_fault_log_take`);③ 行缓冲按模块可收紧(`dbg_log.h` 新增 `DBG_LINE_BUF_MAX`,深链模块 128)+ 时间戳缓冲并入行缓冲(32 → 24)。§4.4 / §5 / §6 / §7 / §8 同步;实测 defaultTask 静态最坏链 5312 → 2776 B |
|
||||
|
||||
+13
-12
@@ -1,6 +1,6 @@
|
||||
# 网口设置页配置说明
|
||||
|
||||
> 版本:v2.1 日期:2026-09-14
|
||||
> 版本:v2.2 日期:2026-10-10
|
||||
> 适用工程:STM32F4-Base(STM32F407ZGTx + CH395F 以太网控制器)
|
||||
> 范围:UI「网口设置」页可配置的网口参数(IP 地址 / 子网掩码 / 默认网关 / MAC 地址)——
|
||||
> 参数与默认值、持久化、生效链路、页面操作与权限。
|
||||
@@ -13,7 +13,7 @@
|
||||
|---|---|
|
||||
| **可配置** | IP 地址、子网掩码、默认网关、MAC 地址 |
|
||||
| **入口** | 屏幕:`通讯参数 → 网口设置`(修改密码 `123` 可编辑;查看密码 `000` 只读) |
|
||||
| **存储** | NAND Flash 文件 `/config.ini`(INI `[network]` 段,通用配置文件,掉电不丢);旧版 `/cfg/netcfg.bin` 首启自动迁移 |
|
||||
| **存储** | NAND Flash 文件 `/config.ini`(INI `[network]` 段,通用配置文件,掉电不丢);旧版 `/cfg/netcfg.bin` **不再读取**(存在则忽略,见 §3.2) |
|
||||
| **生效** | 按「保存」后**立即生效**(网络重建约 1~3s,既有 TCP 连接会断开,无需重启) |
|
||||
| **工厂默认** | `192.168.1.100` / `255.255.255.0` / `192.168.1.1` / 芯片内置 MAC |
|
||||
|
||||
@@ -83,17 +83,18 @@ mac=00:00:00:00:00:00
|
||||
|
||||
完整设计(引擎 / 双端 / 并发模型 D15)见 `docs/子系统设计/配置文件设计说明.md`。
|
||||
|
||||
### 3.2 旧版档迁移(首启)
|
||||
### 3.2 旧版二进制档 `/cfg/netcfg.bin`:已不再兼容(2026-10-10)
|
||||
|
||||
旧版格式 `/cfg/netcfg.bin`(28B:magic `'NCFG'` + ver + CRC-16/MODBUS + 18B 字段,格式拥有者 `net_cfg_legacy.c`):
|
||||
旧版格式 `/cfg/netcfg.bin`(28B:magic `'NCFG'` + ver + CRC-16/MODBUS + 18B 字段)的"首次启动自动迁移"已于 **2026-10-10 删除**(`net_cfg_legacy.c/h` 整体移除,该格式的解析代码不再存在)。
|
||||
|
||||
| `/config.ini` 缺失 | `/cfg/netcfg.bin` | 行为 |
|
||||
| `/config.ini` | `/cfg/netcfg.bin` | 行为 |
|
||||
|---|---|---|
|
||||
| 是 | 有效(magic/ver/CRC 通过) | 4 字段转 INI 行 → 写 `/config.ini`(带旧值)→ **删旧档** |
|
||||
| 是 | 缺失 / 无效 | 生成出厂模板;**保留旧档**(留人工检查) |
|
||||
| 否 | — | 正常加载现有文件(不迁移) |
|
||||
| 缺失 | 存在(有效或无效都一样) | 生成出厂模板 → **工厂默认**;旧档**被忽略**(不读、不删、不迁移) |
|
||||
| 缺失 | 缺失 | 生成出厂模板 → 工厂默认 |
|
||||
| 存在 | — | 正常加载现有文件 |
|
||||
|
||||
迁移单向:旧档转换后删除(避免双数据源);新文件存在时恒跳过。
|
||||
- **删除理由**:该一次性路径把整条配置**写**链(`net_cfg_save → cfg_file_save → cfg_store_write_atomic → f_rename → FatFS → dhara FTL`)无条件挂进启动期调用图,使 defaultTask 的 armlink 静态最坏栈链 **+600 B**;而本仓库不存在携带旧档的设备。
|
||||
- **对使用方的影响**:卷上仍残留旧档的设备升级本版本后,网口配置**回落工厂默认**(`192.168.1.100/24`、gw `.1`),需经 UI「网口设置」或 FTP 上传 `/config.ini` 重新配置。
|
||||
|
||||
### 3.3 存储后端(双端)
|
||||
|
||||
@@ -125,7 +126,7 @@ sequenceDiagram
|
||||
DT-->>NT: 置 SYS_EVT_STORAGE_READY(就绪屏障)
|
||||
NT->>NT: 等 SYS_EVT_STORAGE_READY(≤10s;超时用工厂默认继续)
|
||||
NT->>CFG: net_cfg_load()
|
||||
Note over CFG: 注册 [network] 段 → 首启自动迁旧档 → 读 /config.ini;缺失/非法键 → 工厂默认
|
||||
Note over CFG: 注册 [network] 段 → 读 /config.ini;缺失/非法键 → 工厂默认
|
||||
CFG-->>NT: RAM 副本(有效)
|
||||
NT->>CFG: net_cfg_get() → net_cfg_fmt_ipv4()
|
||||
CFG-->>NT: "192.168.001.100"
|
||||
@@ -212,7 +213,6 @@ ENTER 进入选中地址行 → `↑/↓` 调活动字节(0..255 **环绕**)
|
||||
| 文件 | 职责 |
|
||||
|---|---|
|
||||
| `Drivers/BSP/NETCFG/net_cfg.h/.c` | 配置核心:RAM 副本 + 工厂默认 + 加载/保存编排 + MAC 影子 + IPv4 格式化([network] 段注册) |
|
||||
| `Drivers/BSP/NETCFG/net_cfg_legacy.c` | 旧版 NCFG 二进制格式拥有者:首启一次性迁移(校验 → 物化 → 删旧档) |
|
||||
| `App/cfg/cfg_file.h/.c` | 通用配置文件引擎(双端共享核心:解析/校验/外科保存/模板/沉降轮询) |
|
||||
| `App/cfg/cfg_file_store.h` | 存储后端接口(带路径的文件操作) |
|
||||
| `App/cfg/cfg_file_store_mcu.c` | MCU 后端:FatFS `/config.ini`(`/config.TMP` + `f_rename` 原子写) |
|
||||
@@ -226,7 +226,7 @@ ENTER 进入选中地址行 → `↑/↓` 调活动字节(0..255 **环绕**)
|
||||
|
||||
| API | 说明 |
|
||||
|---|---|
|
||||
| `net_cfg_load()` | 注册 `[network]` 段 + 旧档迁移 + 从 `/config.ini` 加载到 RAM 副本;缺失/非法键回退工厂默认(恒返回 0) |
|
||||
| `net_cfg_load()` | 注册 `[network]` 段 + 从 `/config.ini` 加载到 RAM 副本;缺失/非法键回退工厂默认(恒返回 0) |
|
||||
| `net_cfg_save()` | 经 cfg_file 引擎写 `/config.ini`(外科手术式保存);0 成功 / -1 失败 |
|
||||
| `net_cfg_request_apply()` | 请求立即应用(页面保存成功后调用) |
|
||||
| `net_cfg_set_apply_cb()` | 注册"立即应用"平台回调 |
|
||||
@@ -265,5 +265,6 @@ ENTER 进入选中地址行 → `↑/↓` 调活动字节(0..255 **环绕**)
|
||||
|
||||
| 日期 | 变更 |
|
||||
|---|---|
|
||||
| 2026-10-10 | v2.2:**删除旧档 NCFG 迁移**——`net_cfg_legacy.c/h` 整体移除、`cfg_store_legacy_path()` 撤销;旧档 `/cfg/netcfg.bin` 若存在则被忽略(不读、不删、不迁移),配置回落工厂默认。理由:该一次性路径把整条配置写链挂进启动期调用图,defaultTask 静态最坏栈链 +600 B,且本仓库无携带旧档的设备 |
|
||||
| 2026-09-14 | v2.1:存储迁移至**通用配置文件** `/config.ini`(INI `[network]` 段,cfg_file 引擎:逐键校验 / 外科手术式保存 / 原子写 / 旧档首启迁移 / 沉降轮询);`net_cfg_store.*` 弃用(由 `cfg_file_store.*` 取代);对外 API 不变 |
|
||||
| 2026-09-10 | MAC 显示改为常识格式 **`A4:94:B6:12:34:56`**(冒号分隔,17 字符);页面布局左移(名 x=4 / 值 x=54)以容纳 102px 宽度,编辑光标段偏移随之为 3i |
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
| 项 | 现状 |
|
||||
|---|------|
|
||||
| 卷 | GD5F2GQ5UE SPI NAND **256MB**(2048 块 × 64 页 × 2KB),dhara FTL(磨损均衡/坏块管理),FatFS FAT32,`FF_USE_LFN=0` → **文件名必须 8.3** |
|
||||
| FTP | lftpd 根目录 = 卷根 `/`;现有文件 `/config.ini`、`/cfg/netcfg.bin`(均 8.3) |
|
||||
| FTP | lftpd 根目录 = 卷根 `/`;现有文件 `/config.ini`(8.3);旧档 `/cfg/netcfg.bin` 已废弃——现固件不读不写也不删(仅可能残留在旧设备上) |
|
||||
| 并发 | `FF_FS_REENTRANT=1` + 系统锁(`ffsystem.c` osMutex):单次 `f_*` 调用受保护,**多调用序列(open→seek→write→close)需单写者纪律** |
|
||||
| 墙钟 | `sys_clock_get_str(buf,20)` → `"YYYY-MM-DD HH:MM:SS"`;`sys_clock_get()` → Unix 秒(失败 = `UINT32_MAX`);SD2506 RTC + timeSyncTask TCP 校时 |
|
||||
| 挂载 | defaultTask:`f_mount(forced=1)`,空卷自动 `f_mkfs` FAT32,成功后置 `SYS_EVT_STORAGE_READY` |
|
||||
|
||||
+23
-25
@@ -34,7 +34,7 @@
|
||||
| ③ | FatFS 零并发保护(`FF_FS_REENTRANT=0`,应用层无锁) | ftpTask(FTP 传输)/ defaultTask(配置加载/保存/轮询)并发触卷 → 卷损坏 | `FF_FS_REENTRANT=1` + ffsystem.c 互斥钩子(§5.4)+ 三条一致性协议(D15:tmp+rename / 沉降去抖 / 单写者) |
|
||||
| ④ | 无变更检测 | FTP 上传后不生效(需重启) | defaultTask 每 2s `f_stat` 轮询(size + mtime)(§5.3) |
|
||||
| ⑤ | `FF_FS_NORTC=1` → 时间戳恒为固定值 | mtime 不变 → 无法检测"同尺寸编辑"(如 IP 尾段 100→200) | `NORTC=0` + `get_fattime`(复用调试日志墙钟源,运行期零 I2C)(§5.5) |
|
||||
| ⑥ | 固件升级无迁移 | 现场设备升级后用户配置丢失(回工厂默认) | NCFG blob → INI 自动迁移(§9) |
|
||||
| ⑥ | 固件升级无迁移 | 现场设备升级后用户配置丢失(回工厂默认) | NCFG blob → INI 自动迁移(§9;该迁移已于 2026-10-10 撤销) |
|
||||
| ⑦ | RAM 静态区仅余 5.8 KB(占用 95.4%) | 不能新增大静态缓冲 | 稳态零增量 + 暂态堆缓冲(§8) |
|
||||
|
||||
### 1.3 非目标(本期不做)
|
||||
@@ -57,7 +57,7 @@
|
||||
| D7 | 线程安全 | **`FF_FS_REENTRANT=1` + `Lib/FatFs/ffsystem.c`**(`ff_mutex_*` → osMutex,超时 1s) | FatFs 官方可重入方案;每次 f_* 调用加锁/放锁(逐次粒度,不长期阻塞 FTP 传输);`FR_TIMEOUT` 防死锁 |
|
||||
| D8 | 时间戳 | **`FF_FS_NORTC=0` + `get_fattime`(复用 `sys_clock` 墙钟,与调试日志时间戳同源)** | mtime 为真实时间、与日志时间戳一致;墙钟 = 开机 RTC 基准 + tick 推进,运行期零 I2C;墙钟无效时回退固定值(有开机告警) |
|
||||
| D9 | 写原子性 | **一切写入 = 临时文件 + `f_rename`**(设备保存 / FTP STOR / 出厂模板统一:先写 `<名>.TMP`(8.3 兼容),关文件成功后 rename 目标) | 同目录 rename = 单目录项写入,卷锁下原子 → 并发读者只见"旧完整文件或新完整文件",半截窗口结构消除;STOR 中途掉电仅残留 TMP(无害);逐键容错 + 下次保存自愈为次级兜底 |
|
||||
| D10 | 旧档迁移 | 新固件首启:NCFG blob → INI,**迁移后删除旧文件** | 防现场升级丢配置;否决"保留旧文件"(双数据源、陈旧值混乱) |
|
||||
| D10 | 旧档迁移 | ~~新固件首启:NCFG blob → INI,迁移后删除旧文件~~ → **2026-10-10 撤销:旧档不读、不删、不迁移** | 原理由:防现场升级丢配置;否决"保留旧文件"(双数据源、陈旧值混乱)。**撤销理由**:该一次性路径把整条配置写链(`net_cfg_save → cfg_file_save → cfg_store_write_atomic → f_rename → FatFS → dhara FTL`)挂进启动期调用图,defaultTask 静态最坏栈链 +600 B;本仓库不存在携带旧档的设备 → 按"不保留旧档兼容"处置(见 §9.1) |
|
||||
| D11 | 出厂默认 | 文件缺失时**自动生成带注释模板**并落盘 | 首启 / 恢复出厂场景;文件自身即"格式手册" |
|
||||
| D12 | 恢复出厂 | **FTP `DELE /config.ini`**(下次上电重新生成) | 本期不做 UI 入口(开放问题 O1) |
|
||||
| D13 | 双端 | 共享 `cfg_file` 核心 + 平台 store 后端(沿用 net_cfg_store 模式) | MCU = FatFS `/config.ini`;模拟器 = 宿主文件 `sim_config.ini` |
|
||||
@@ -130,7 +130,7 @@ mac=00:00:00:00:00:00
|
||||
|
||||
| 场景 | 加载行为 | 保存行为 |
|
||||
|---|---|---|
|
||||
| 文件不存在 | 工厂默认;自动生成模板(有旧 blob 时优先迁移,见 §9) | 写当前值 |
|
||||
| 文件不存在 | 工厂默认;自动生成模板(旧 blob 若存在也**不读、不迁移**,见 §9.1) | 写当前值 |
|
||||
| 段缺失 / 键缺失 | 该键取工厂默认 | 补写缺失键(段缺失则补整段) |
|
||||
| 键值非法 | 该键取工厂默认 + 日志 | 重写为合法值(自愈) |
|
||||
| 文件 > 4KB / 严重损坏 | 全部工厂默认 + `DBG_ERROR` | 整文件重生成(已知数据保留,未知内容丢失) |
|
||||
@@ -155,7 +155,7 @@ mac=00:00:00:00:00:00
|
||||
| `Lib/FatFs/ffconf.h` | 修改 | MCU | `FF_FS_REENTRANT` 0→1;`FF_FS_NORTC` 1→0 |
|
||||
| `App/util/sys_clock.c/.h` | 修改 | MCU | 新增 `sys_clock_get_time()`(日历时间获取器);改归 ④中间件层,自 `App/` 移入 `App/util/` |
|
||||
| `Drivers/BSP/NETCFG/net_cfg.h/.c` | 重构 | 双端 | `net_cfg_*` API 不变;load/save 走 cfg_file;注册 `[network]` 段 |
|
||||
| `Drivers/BSP/NETCFG/net_cfg_legacy.c` | **新增** | 双端 | 旧 NCFG blob 解析 + 迁移 |
|
||||
| `Drivers/BSP/NETCFG/net_cfg_legacy.c` | **已删除**(2026-10-10;曾于 P3 新增) | — | 旧 NCFG blob 解析 + 迁移;随"不保留旧档兼容"整体移除(见 §9.1) |
|
||||
| `Drivers/BSP/NETCFG/net_cfg_store.h` / `net_cfg_store_mcu.c` | **删除** | — | 由 `cfg_file_store.*` 取代 |
|
||||
| `simulator/sim/net_cfg_store_sim.c` | **删除** | 模拟器 | 由 `cfg_file_store_sim.c` 取代 |
|
||||
| `App/task/net_task.c` | 修改 | MCU | 主循环每 2s `cfg_file_poll()` |
|
||||
@@ -234,11 +234,7 @@ sequenceDiagram
|
||||
participant NS as 网络层
|
||||
DT->>FS: f_mount(无卷自动 f_mkfs)
|
||||
alt /config.ini 不存在
|
||||
alt 存在旧 /cfg/netcfg.bin
|
||||
DT->>FS: 读旧 blob 校验 → 转写 /config.ini → 删旧文件
|
||||
else 无旧文件
|
||||
DT->>FS: 生成出厂模板 → 写 /config.ini
|
||||
end
|
||||
DT->>FS: 生成出厂模板 → 写 /config.ini(旧 /cfg/netcfg.bin 不读、不删、不迁移)
|
||||
end
|
||||
DT->>FS: net_cfg_load():读 /config.ini → 解析入 RAM 副本(含 [network] 段注册)
|
||||
DT->>NT: 置 SYS_EVT_STORAGE_READY(= 卷挂载 + 配置就绪)
|
||||
@@ -385,11 +381,11 @@ void *cfg_store_alloc(size_t size); /* 失败返回 NULL,由调用方
|
||||
void cfg_store_free(void *p_buf); /* NULL 安全;只接受 cfg_store_alloc 返回值 */
|
||||
uint32_t cfg_store_heap_free(void); /* 空闲堆诊断量;模拟器恒 0 */
|
||||
|
||||
/* 路径由后端提供(MCU: /config.ini、/config.TMP、/cfg/netcfg.bin;
|
||||
* 模拟器: sim_config.ini、sim_config.ini.tmp、sim_netcfg.bin) */
|
||||
/* 路径由后端提供(MCU: /config.ini、/config.TMP;
|
||||
* 模拟器: sim_config.ini、sim_config.ini.tmp)
|
||||
* 注:旧版遗留档 getter cfg_store_legacy_path() 已于 2026-10-10 随旧档迁移删除 */
|
||||
const char *cfg_store_config_path(void);
|
||||
const char *cfg_store_tmp_path(void);
|
||||
const char *cfg_store_legacy_path(void);
|
||||
```
|
||||
|
||||
### 6.3 未来模块接入模板
|
||||
@@ -427,7 +423,7 @@ void adc_cfg_init(void)
|
||||
### 6.4 net_cfg 兼容承诺
|
||||
|
||||
- `net_cfg_load/save/get/set/get_mac/set_active_mac/fmt_ipv4/set_apply_cb/request_apply` **签名与语义全部不变**
|
||||
- 内部:`net_cfg_load` = 段注册 + 旧档迁移(`net_cfg_legacy_migrate`)+ `cfg_file_load`;`net_cfg_save` = `cfg_file_save`
|
||||
- 内部:`net_cfg_load` = 段注册 + `cfg_file_load`(旧档迁移已于 2026-10-10 删除);`net_cfg_save` = `cfg_file_save`
|
||||
- UI 页(`ui_page_net_cfg.c`)、启动流程(`net_task.c`)、模拟器入口(`main.c`)的**调用点无需改动**
|
||||
|
||||
## 7. 双端支持
|
||||
@@ -437,11 +433,11 @@ void adc_cfg_init(void)
|
||||
| 后端 | `cfg_file_store_mcu.c`(FatFS) | `cfg_file_store_sim.c`(宿主文件) |
|
||||
| 文件路径 | `/config.ini`(NAND 卷根) | `sim_config.ini`(工作目录) |
|
||||
| mtime 来源 | FAT 打包时间(`fdate<<16\|ftime`,分钟级粒度) | 宿主文件系统(秒级) |
|
||||
| 旧档迁移 | `/cfg/netcfg.bin`(NCFG blob) | `sim_netcfg.bin`(同格式) |
|
||||
| 旧档(已废弃) | `/cfg/netcfg.bin` **不读、不删、不迁移**(2026-10-10) | `sim_netcfg.bin` 同样不读、不删、不迁移 |
|
||||
| 变更轮询 | defaultTask 2s | 主循环 2s(编辑器改动 2s 内反映) |
|
||||
| 弃用 | — | `net_cfg_store_sim.c` 删除 |
|
||||
|
||||
模拟器行为:首跑无 `sim_config.ini` 而有 `sim_netcfg.bin` → 自动迁移并删旧文件;运行中用编辑器改 `sim_config.ini` → 2s 内自动重载(模拟器无网络重建概念,[network] 段"应用" = 刷新 RAM 副本)。
|
||||
模拟器行为:首跑无 `sim_config.ini` → 生成出厂模板(残留的 `sim_netcfg.bin` 被忽略);运行中用编辑器改 `sim_config.ini` → 2s 内自动重载(模拟器无网络重建概念,[network] 段"应用" = 刷新 RAM 副本)。
|
||||
|
||||
## 8. 内存预算
|
||||
|
||||
@@ -464,27 +460,28 @@ void adc_cfg_init(void)
|
||||
|
||||
## 9. 兼容与迁移
|
||||
|
||||
### 9.1 旧文件迁移(新固件首启)
|
||||
### 9.1 旧文件迁移:已删除(2026-10-10)
|
||||
|
||||
旧 NCFG 二进制档 `/cfg/netcfg.bin` 的"首启自动迁移"已整体删除(`net_cfg_legacy.c/h` 移除、`cfg_store_legacy_path()` 撤销)。现行为:
|
||||
|
||||
```
|
||||
/config.ini 缺失?
|
||||
├─ 是 → /cfg/netcfg.bin 存在且有效(magic/ver/CRC)?
|
||||
│ ├─ 是 → 4 字段转 INI 行 → 原子写 /config.ini → 删旧文件
|
||||
│ │ 日志: "cfg file: legacy NCFG migrated"
|
||||
│ └─ 否 → 生成出厂模板
|
||||
├─ 是 → 生成出厂模板 → 工厂默认
|
||||
│ (/cfg/netcfg.bin 无论存在与否、有效与否:不读、不删、不迁移)
|
||||
└─ 否 → 正常加载现有文件
|
||||
```
|
||||
|
||||
- 迁移单向:旧文件转换后删除(避免双数据源)
|
||||
- 旧 blob 损坏:按不存在处理 → 出厂模板(旧文件保留,可人工查看)
|
||||
- 旧格式(28B:magic 'NCFG' + ver + CRC-16/MODBUS + 18B 字段)已无解析代码;`App/util` 的 CRC-16/MODBUS 模块随之失去唯一调用者
|
||||
- **删除理由**:该一次性路径把整条配置**写**链(`net_cfg_save → cfg_file_save → cfg_store_write_atomic → f_rename → FatFS → dhara FTL`)挂进启动期调用图,使 defaultTask 的 armlink 静态最坏栈链 **+600 B**;而本仓库不存在携带旧档的设备
|
||||
- 残留旧档不会被自动清理,需要时可经 FTP 手工删除(该文件对现固件无任何作用)
|
||||
|
||||
### 9.2 现场升级 / 降级场景
|
||||
|
||||
| 场景 | 行为 |
|
||||
|---|---|
|
||||
| 旧设备(有 netcfg.bin)升级新固件 | 自动迁移,用户配置保留 |
|
||||
| 旧设备(有 netcfg.bin)升级新固件 | 旧档**被忽略**(不读、不删、不迁移)→ 配置回落工厂默认,需经 UI / FTP 重新配置(2026-10-10 起) |
|
||||
| 新设备 / 格式化卷 | 出厂模板 |
|
||||
| 新文件被**旧固件**读(降级) | 旧固件只读 `/cfg/netcfg.bin`(已删)→ 工厂默认;**降级需人工恢复网口配置**(已知限制,O2) |
|
||||
| 新文件被**旧固件**读(降级) | 旧固件只读 `/cfg/netcfg.bin`——现固件不读也不删该文件,故它仍在卷上、旧固件按旧值运行;**新旧固件配置互不同步**(已知限制,O2) |
|
||||
| 含未来段的新文件被旧固件读 | 旧固件不读该文件 → 文件不受影响 |
|
||||
|
||||
### 9.3 恢复出厂
|
||||
@@ -515,7 +512,7 @@ void adc_cfg_init(void)
|
||||
|---|---|---|
|
||||
| `cfg file: loaded OK` | 上电加载成功 | Required(P4 起纳入 `@test`) |
|
||||
| `cfg file: factory template written` | 首启 / 删文件 | 条件(手工) |
|
||||
| `cfg file: legacy NCFG migrated` | 旧文件迁移 | 条件(真机首次升级) |
|
||||
| `cfg file: legacy NCFG migrated` | 旧文件迁移 | **已作废**(2026-10-10 旧档迁移删除,该标记不再产生) |
|
||||
| `cfg file: saved OK` | UI 保存 | 条件(手工) |
|
||||
| `cfg file: change detected` | FTP 上传 | 条件(P7 闭环) |
|
||||
| `cfg file: ... FAILED` | 任何失败 | Forbidden |
|
||||
@@ -589,3 +586,4 @@ void adc_cfg_init(void)
|
||||
| 2026-09-22 | v1.12:**E-01 超长守卫根治**(错误码传播审计第一档 #3,commit d030cb0)——poll 的"超长=损坏"检查写在截断后读长(`s_load_file` 读长钉死 4096)上**恒假=死码**,超长文件被截断当有效解析 → 界外静默回工厂默认 → 基线粘住 → 用户配置销毁链。① poll 沉降分支判定改用 `cfg_store_stat` 真实 `st.size` 且**先于读取**,超长走"工厂默认 + 重建模板 + `cfg poll oversized` 自检留痕",**刻意不触发段回调**(避免按工厂 IP 重建网络造成静默失联,保留 FTP 修复通道,保存/重启收敛)② `s_surgical` 输出上限 `CFG_OUT_MAX`(5120) 收紧至 `CFG_FILE_MAX_LEN`(4096),超限走溢出中止路径(原文件不动 + `cfg save overflow` 自检)——消除"合法写出 4097~5120B 文件 = 下次开机销毁"的雷 ③ `s_write_doc` 唯一落盘闸口硬拒 >4096B(结构性保证)④ load 超长分支补 `cfg load oversized` 自检;`cfg_file.h` v1.2 契约同步;模拟器 cfgtest 新增两回归锁(4160B 伪造 → poll 判损坏重建;4000B 注释文件 → save 拒写且原文件未动)。**台架验证暴露并修复**:`cfg_store_write_atomic` MCU 后端 `f_rename` 对已存在目标返回 `FR_EXIST` 不覆盖 → 设备端一切"目标存在的覆盖写"(UI 保存/模板重建)静默失败、仅首启建文件成功——v1.9 已为模拟器后端修过同款(MSVC `rename()` C1117),MCU 侧漏了对称修复;修复 = rename 前先 `unlink` 目标(commit 70f1cc8)。双端 0 错 0 警、cfgtest PASS、台架 FTP 5047B 用例 poll/load 双路径自愈 PASS(重建 523B 工厂模板 + selftest 留痕 + 不掉线)、`@test` 默认闭环 PASS、ST-LINK 全片回读一致 |
|
||||
| 2026-10-03 | v1.13:**真机验证 PASS(A1 闭环)**——v1.11 的 P0-1 堆分配改造在真机上验证通过:`[CFG] load: OK (523B, heap free 8840B)`(**经 FreeRTOS 堆分配**,即 512B C 堆约束的验收点);Forbidden `FAIL`/`[ERR]` 零命中;FTP 改配置 IP→`192.168.1.101` 后**复位即加载生效**(`[NET_CFG] load: OK ip=192.168.1.101` + 芯片 `IP_INF` .101 + 21 端口探测可达),原档恢复后复测回 .100。真机全闭环 `@test` PASS 7/7。**台架步骤与判据见 `测试说明/实机测试实施指南.md` §3 / §10** |
|
||||
| 2026-10-04 | **P0-1 真机独立复跑 PASS(二次确认,代码零改动)**——`@build` 0/0(增量,无源文件新于镜像)→ `@test` **VERDICT PASS(rc=0)**:`[2026-10-04 00:01:21][CFG] load: OK (523B, heap free 8840B)` + `[NET_CFG] load: OK ip=192.168.1.100`,Forbidden `FAIL`/`ERROR`/`HardFault`/`[ERR]` 零命中,`selftest: no fault record`(先清掉 2026-10-02/03 故障注入窗口遗留的 67 条台账)→ ST-LINK 全片回读 `No difference found`(`0x08000000~0x08040F9B`)。**本次为 `待处理内容.md` §4.1「待验证」唯一未闭环项(P0-1)的收口**,该节现已清空 |
|
||||
| 2026-10-10 | v1.14:**删除旧档 NCFG 迁移(D10 撤销)**——`Drivers/BSP/NETCFG/net_cfg_legacy.{c,h}` 整体移除、`cfg_store_legacy_path()` 撤销(MCU / 模拟器后端与主机单测 `test/host/cfg_file/cfg_file_test.c` 同步删除),`net_cfg_load` 不再调用 `net_cfg_legacy_migrate()`;旧档 `/cfg/netcfg.bin` 若存在则被**忽略**(不读、不删、不迁移),配置回落工厂默认。理由:该一次性路径把整条配置写链挂进启动期调用图,defaultTask 静态最坏栈链 **+600 B**(该链整体 5312 → 2776 B,另三个杠杆见 `docs/内存管理/RAM使用分析与优化方案.md`),而本仓库不存在携带旧档的设备。连带影响:`App/util` 的 CRC-16/MODBUS 失去唯一调用者(现为零调用者);模拟器 `--cfgtest` 不再覆盖迁移场景;§2 D10 / §3.5 / §4.2 / §5.1 / §6.2 / §6.4 / §7 / §9 / §11.1 同步 |
|
||||
|
||||
+18
-18
@@ -38,7 +38,7 @@
|
||||
| 级别 | 数量 | 关键项 |
|
||||
|---|---|---|
|
||||
| **P1** | 1 (+1 收尾) | **P1-1 ADC 采样路径产品构建中死亡**;P1-10 测试固件构建实测闭环(主体已闭环,见 §3.1) |
|
||||
| 登记簿 | 10 | 网络:N-2(49s 日志静默,**低风险观察项**)、N-3(L5 基线重验)、N-4(pending 二期)、N-16(A2/A4 专项负向验证)、N-17(探针窗口心跳缺口);存储/日志:**S-1(defaultTask 栈余量 10%,需尽快处理)**、S-3(USART1 TX-only 根治)、S-4(dhara 重试自旋)、S-5(可选全序列卷锁);硬件:**N-18(8 路电气量分属两转换器 = V0.1 缺陷,V0.2 改版项)** |
|
||||
| 登记簿 | 9 | 网络:N-2(49s 日志静默,**低风险观察项**)、N-3(L5 基线重验)、N-4(pending 二期)、N-16(A2/A4 专项负向验证)、N-17(探针窗口心跳缺口);存储/日志:**S-3(USART1 TX-only 根治)**、S-4(dhara 重试自旋)、S-5(可选全序列卷锁);硬件:**N-18(8 路电气量分属两转换器 = V0.1 缺陷,V0.2 改版项)** |
|
||||
| 测试/基础设施 | 5 | T-7(CI runner 未就绪)+ 测试架构专项 **S12**(断言宏)、**S1-c**(可选单测)、**A-4**(采集链路测试约束)、**A-5 残余**(CI 体积门禁盲区) |
|
||||
|
||||
> **网络侧另有 E-xx 未闭环项**(E-12/15/16/23/24/25/26/27/28/30/47/48/49/50/58/59/61,共 17 项)
|
||||
@@ -51,8 +51,9 @@
|
||||
2. **真正的产品功能缺口在 ADC 与 RS-485 采集链路**:`adc_task`/`rs485_task` 均为空桩,
|
||||
DTU 的核心职责(数据采集与转发)**尚未实现**。这既是 P1-1 的根源,也是 E-59 那条
|
||||
"休眠缺陷闸门"的另一面——不是缺陷难修,而是**功能没接**。
|
||||
3. **验证债已基本还清,重心是"功能债" + 一项栈风险**:剩余验证债仅 **N-3(L5 基线重锁,
|
||||
待 PC peer)** 与 **S-1(defaultTask 栈余量已跌至 10%,见 §6)**。
|
||||
3. **验证债已基本还清,重心是"功能债"**:剩余验证债仅 **N-3(L5 基线重锁,待 PC peer)**
|
||||
(原 **S-1 栈风险已于 2026-10-10 削链闭环并销项**:defaultTask 静态最坏链 5312 → 2776 B、
|
||||
实测峰值 3392 → 2152 B,**未抬栈**,见 `docs/内存管理/RAM使用分析与优化方案.md`)。
|
||||
**当前最值得投入的是阶段 B(ADC/RS485 功能)**。
|
||||
|
||||
---
|
||||
@@ -72,7 +73,7 @@
|
||||
| 序 | 任务 | 前置 | 说明 |
|
||||
|---|---|---|---|
|
||||
| **B0** | **产品定义确认**(阻塞项) | — | 需甲方明确:① 采集是否持续 ② 采样率(**通道语义已于 2026-10-09 确认并固化 → `docs/硬件平台/ADC通道映射说明.md`**:UA/UB/UC/UN=`AIN1~4`、IA/IB/IC/IN=`AIN8~11`、V_ZL2=温度、其余 8 路备用;主板只做监视/辅助测量,计量在子板。**注意:8 路电气量分属 TPAFE/STM32 两片转换器属 V0.1 硬件缺陷 → N-18**,主板侧不得做跨转换器的相位/功率类运算) ③ 转发目标(MODBUS RTU?上行 TCP?)④ `APP_ADC_ENABLE`/`APP_RS485_ENABLE` 语义。**B1/B2 的规模完全取决于此** |
|
||||
| **B1** | **ADC 采集链路实现**(消化 P1-1;E-58 已闭环) | B0 + **E-59 门禁**(TPAFE 侧已满足) | 周期 CONVST 重触发 + `adc_task` 消费 **`tpafe5160_snapshot()`**(**2026-10-10 驱动契约已修**:E-44 FRSTDATA 有效性校验 + `init()` 首帧自检返 `-3`、E-45 帧序号取代就绪电平标志、E-58 临界区原子快照;旧 `get_buf`/`data_ready`/`clear_ready` **已删**,删除前零调用者);`adc_task.c` **已挂进 `uvprojx`**(此前 Keil/模拟器两边都不注册 = 永不编译;simulator 无任务层,只挂 Keil);**仍欠**:栈预算核算(两任务未入 `freertos.c` 栈表,建任务前后各跑 `stack_report.py`;先处理 S-1)+ 消费者本体 + 建任务走 **L1(`.ioc` 的 `FREERTOS.Tasks01`)**;**取数必须按 `docs/硬件平台/ADC通道映射说明.md`**(TPAFE `buf[2]=IA`/`buf[5]=UN`/`buf[6]=UA`;STM32 侧 ADC1 **已于 2026-10-09 生成**:`hadc1` + `MX_ADC1_Init()`、9 通道 Rank1~9、144 cycles、ADCCLK=21 MHz、软件触发,网名 ADC17=PC4 用 `ADC_CHANNEL_14`;⚠ 全仓库至今**无 `HAL_ADC_Start`** → STM32 侧一路未跑) |
|
||||
| **B1** | **ADC 采集链路实现**(消化 P1-1;E-58 已闭环) | B0 + **E-59 门禁**(TPAFE 侧已满足) | 周期 CONVST 重触发 + `adc_task` 消费 **`tpafe5160_snapshot()`**(**2026-10-10 驱动契约已修**:E-44 FRSTDATA 有效性校验 + `init()` 首帧自检返 `-3`、E-45 帧序号取代就绪电平标志、E-58 临界区原子快照;旧 `get_buf`/`data_ready`/`clear_ready` **已删**,删除前零调用者);`adc_task.c` **已挂进 `uvprojx`**(此前 Keil/模拟器两边都不注册 = 永不编译;simulator 无任务层,只挂 Keil);**仍欠**:栈预算核算(两任务未入 `freertos.c` 栈表,建任务前后各跑 `stack_report.py`;原 S-1 栈风险已于 2026-10-10 **削链销项**,defaultTask 现静态 2776/4096 余 32%、实测 2152 B)+ 消费者本体 + 建任务走 **L1(`.ioc` 的 `FREERTOS.Tasks01`)**;**取数必须按 `docs/硬件平台/ADC通道映射说明.md`**(TPAFE `buf[2]=IA`/`buf[5]=UN`/`buf[6]=UA`;STM32 侧 ADC1 **已于 2026-10-09 生成**:`hadc1` + `MX_ADC1_Init()`、9 通道 Rank1~9、144 cycles、ADCCLK=21 MHz、软件触发,网名 ADC17=PC4 用 `ADC_CHANNEL_14`;⚠ 全仓库至今**无 `HAL_ADC_Start`** → STM32 侧一路未跑) |
|
||||
| **B2** | **RS-485 采集链路实现**(消化 E-50、E-49) | B0 + **E-59 门禁**(**尚未满足**:E-50 / E-49 未修) | 双缓冲 + 序号(防包撕裂)+ DE 收尾(超时路径等 TC)+ 协议状态机(`App/protocol/` 正是为此预留) |
|
||||
|
||||
**建议**:驱动契约与编译接线已在 2026-10-10 铺完 → B1 的下一步是**栈预算 + 建任务(L1)**,
|
||||
@@ -84,7 +85,6 @@
|
||||
|---|---|---|---|
|
||||
| **C1** | **pending 二期(ACCEPT + SEND)** | 沿一期机制扩展;同期消化 E-25(net_select 语义)、E-24/E-27/E-28(跨上下文收口);基线重锁 + 探针族扩充 + 看门狗接 selftest。**设计基线见 §5.1** | 第二档 #2 / N-4 |
|
||||
| **C3** | **存储侧日志管线**(消化 N-2) | 丢弃可观测性**代码已具备**(`console_log.c` `s_con_drop`+`[ERR] CONSOLE dropped`、`sys_log_mcu.c` 队列满 `DBG_ERROR`、TX 僵尸通道自愈);V5 30 min 日志**未复现 49s 静默**(运行期 >10s 静默全为 ~28s、均在 `e02_probe` 窗口内=N-17)。剩余:与 S8(非阻塞日志)合并评估 + **S-3(USART1 TX-only 结构根治)** | N-2 / S-3 |
|
||||
| **C4** ⚠️ | **defaultTask 栈余量**(S-1,**需尽快处理**) | **2026-10-04 实测 3664/4096(余量 432 B ≈ 10%,远低于 30% 判据)**。处置:栈 4096→4608(CCM 堆余量可覆盖 +512B)或 GC 链局部削减;**建议随阶段 B 之前先做** | S-1 |
|
||||
| **C5** | 一档剩余 | E-49(RS485 DE 收尾)、E-15(ringbuf 定去留——**已确认零调用者,倾向删除**)、E-61(SD2506 注释订正)、E-16(cfg_file 段名长度)、E-26(UDP 定案,倾向移除)、E-23、E-30 | 一档/二档 |
|
||||
| **C6** | **USART1 TX-only 结构根治**(S-3) | 灭 ORE 僵尸机制根源:改 `.ioc` 令 USART1 不使能 RX / PA10 不复用为 `USART1_RX` → CubeMX 重生成 → 跑 `check_cubemx_survival.py`。属结构性改动,需单开一轮 + 复跑台架闭环 | S-3 |
|
||||
|
||||
@@ -102,7 +102,7 @@
|
||||
【阶段 B 功能】 B0 产品定义确认 ─┬─ B3 E-59 门禁固化(并行)
|
||||
(当前最高优先) └─ E-58 原子快照 → B1 ADC → B2 RS485
|
||||
↓
|
||||
【阶段 C 结构】 C1 pending 二期 ─ C3 日志管线(N-2/S-3) ─ C4 栈(S-1)
|
||||
【阶段 C 结构】 C1 pending 二期 ─ C3 日志管线(N-2/S-3)
|
||||
─ C5 收口 ─ C6 USART1 TX-only
|
||||
↓
|
||||
【阶段 D 常态】 D2 N-3 / D5 N-16 负向 / D6 N-17 探针窗口
|
||||
@@ -145,7 +145,6 @@
|
||||
|
||||
| # | 事项 | 发现 | 证据与现状 | 出处 |
|
||||
|---|---|---|---|---|
|
||||
| S-1 | defaultTask 静态最坏链余量贴线:`storage_bring_up → … → dhara GC → SPI` 链 | 2026-09-22;2026-10-04 重采升级 | **2026-10-04 重采(升级为需尽快处理)**:产品构建(`suite=NONE`)V5 30 min 真实负载实测 **3664B/4096(余量 432B = 10%)**,**已远低于 30% 判据**。处置:栈 4096→4608(CCM 堆余量可覆盖 +512B)或 GC 链缓冲局部削减;建议**提前到阶段 B 之前**处理 | 本文件 §2.2 C4 / §6 |
|
||||
| S-3 | **USART1 TX-only 结构根治(灭 ORE 僵尸机制)**——ORE 锁存在外设软复位后毫秒级重锁(PA10 悬空 + RX 使能),是 2026-10-02 台架"背靠背 drain 拉长主循环 → 喂狗节奏饥饿 → IWDG 误复位"的**机制根源**。现仅有缓解(单次 drain 250ms 预算 + 发送故障后 300ms 冷却),**未根治** | 2026-10-02(台架 gen-288) | **待办**:改 `.ioc` 令 USART1 为 TX-only → CubeMX 重生成 → 跑 `scripts/check_cubemx_survival.py`。结构性改动,需单开一轮并复跑台架闭环 | `子系统设计/控制台单写者日志设计说明.md` §12(含 O4) |
|
||||
| S-4 | **dhara 重试自旋残留**——`try_recover()` 的 `DHARA_MAX_RETRIES`(8) 自旋在坏块密集时仍可能长时间占用 defaultTask(喂狗点) | 2026-10-02 | 低优先:现有 `vol_lock` + 喂狗节奏缓解;若台架再出"存储侧喂狗饥饿"再排期 | `Lib/dhara/map.c` |
|
||||
| S-5 | **可选全序列卷锁**——现卷锁仅覆盖 `syslog` / `cfg` / `lftpd` 三条路径(`vol_lock_wait(0)` try 语义),其它潜在访问点(如 UI 读日志)未纳入 | 2026-10-02 | 待评估:先确认是否真有第二写者;无则关闭本项 | `App/fs/vol_lock.{c,h}` |
|
||||
@@ -244,8 +243,8 @@ S14 已在 workflow 显式提示"体积门禁未执行"(`::notice::`)并在
|
||||
|
||||
**完成判据**:存在**强制的**体积校验路径(CI 侧或本地侧),且文档明确其边界。
|
||||
|
||||
> **注**:本项与 §2.2 C4(**S-1:defaultTask 栈 3664/4096 ≈ 10%**,需尽快处理)是同一话题的两面
|
||||
> ——S-1 是**具体风险**,本项是**门禁缺口**。
|
||||
> **注**:本项与栈预算是同一话题的两面——**具体栈风险(原 S-1)已于 2026-10-10 削链闭环销项**
|
||||
> (defaultTask 静态最坏链 5312 → 2776 B、实测 3392 → 2152 B,**未抬栈**),本项仍是**门禁缺口**。
|
||||
|
||||
---
|
||||
|
||||
@@ -311,21 +310,22 @@ S14 已在 workflow 显式提示"体积门禁未执行"(`::notice::`)并在
|
||||
|
||||
## 6. 诊断基线(供后续对照)
|
||||
|
||||
> **2026-10-04 重采**:栈/堆 = **运行时高水位**(产品构建 `suite=NONE`,V5 30 min 真实负载,串口 `[STACK]`,
|
||||
> 证据 `/tmp/v5_soak_serial_20261003.log`);静态区 = `.map` 受管快照。
|
||||
> ⚠️ **栈水位较 2026-09-21 基线明显上升**(defaultTask 2136→**3664 B**、ftpTask 1184→**2516 B**),
|
||||
> 系功能与加固陆续入链所致。**S-1 需尽快处理**,见 §2.2 C4。
|
||||
> **2026-10-10 重采(栈)/ 2026-10-04 重采(堆)**:栈 = **运行时高水位 + armlink 静态最坏链双口径**
|
||||
> (产品构建 `suite=NONE`,开机 + 空闲采样,串口 `[STACK]` + `stack_report.py`);静态区 = `.map` 受管快照。
|
||||
> ✅ **栈水位已回落**:2026-10-04 曾升到 defaultTask **3664 B**(登记 S-1);2026-10-10 削链
|
||||
> (删旧档迁移 + `FIL` 静态化 + 日志行缓冲按模块收紧 + 钩子脱离 HAL)后实测 **2152 B**、
|
||||
> 静态最坏链 **2776 B**,**未抬栈**即达标。完整核算见 `docs/内存管理/RAM使用分析与优化方案.md`。
|
||||
|
||||
| 项 | 当前值(2026-10-04) | 出处 |
|
||||
| 项 | 当前值(栈:2026-10-10;其余:2026-10-04) | 出处 |
|
||||
|---|---|---|
|
||||
| 产品构建 Flash (ER_IROM1) | 266,632 B / 1024 KB(25.4%);ROM 合计 **267,372 B** | `.map` 受管快照 |
|
||||
| 产品构建 RW_IRAM1 | **84,960 / 131,072 B(64.8%)** | `.map` 受管快照(`RAM使用分析与优化方案.md` §2.1) |
|
||||
| 产品构建 RW_CCM | 49,184 / 65,280 B(75.3%) | 同上 |
|
||||
| 实测堆 | free=8,664 / **min_ever=4,728 B** | V5 串口 `[STACK] heap` |
|
||||
| **defaultTask 栈峰值** | **3664 / 4096(余量 432 B ≈ 10%,⚠️ 低于 30% 判据)** | V5 串口 `[STACK]`(产品构建) |
|
||||
| netTask 栈峰值 | 1228 / 4096(余量 70%) | 同上 |
|
||||
| ftpTask 栈峰值 | 2516 / 4096(余量 38%) | 同上 |
|
||||
| uiTask 栈峰值 | 4060 / 16384(余量 75%) | 同上 |
|
||||
| **defaultTask 栈峰值** | **2152 / 4096(余 1944 B = 47%);静态最坏链 2776 B(余 32%)** | `[STACK]` + `stack_report.py`(产品构建) |
|
||||
| netTask 栈峰值 | 920 / 3840(余 76%);静态 1872 B | 同上 |
|
||||
| ftpTask 栈峰值 | 740 / 4096(余 81%);静态 1216 B | 同上 |
|
||||
| uiTask 栈峰值 | 4016 / 16384(余 75%);静态 1336 B | 同上 |
|
||||
| timeSyncTask 栈峰值 | 792 / 2048(余量 61%) | 同上 |
|
||||
| testTask 栈峰值(产品态空转) | 496 / 8192(余量 93%) | 同上 |
|
||||
| 队列响应性(挂起客户端) | 92.5ms(pending 一期) | `e02_probe.py` |
|
||||
|
||||
@@ -126,7 +126,7 @@ if (sys_evtHandle != NULL) {
|
||||
> 因此只在 netTask 上下文广播。
|
||||
|
||||
### Step 3 defaultTask 置位存储就绪(生产者)
|
||||
在 `defaultTask` 完成 FTL/FatFS 挂载 **+ 网络配置加载(`net_cfg_load`,含首启旧档迁移;失败回退工厂默认)** 后:
|
||||
在 `defaultTask` 完成 FTL/FatFS 挂载 **+ 网络配置加载(`net_cfg_load`;旧档 `/cfg/netcfg.bin` 不读、不迁移,失败回退工厂默认)** 后:
|
||||
```c
|
||||
osEventFlagsSet(sys_evtHandle, SYS_EVT_STORAGE_READY);
|
||||
```
|
||||
|
||||
+3
-2
@@ -163,7 +163,7 @@ flowchart LR
|
||||
end
|
||||
```
|
||||
|
||||
- 掉电持久化:`net_cfg` 配置(通用配置文件 `/config.ini`,INI `[network]` 段,cfg_file 引擎),保存后下次上电生效、或立即生效(网络重建)、外部变更 4s 沉降后自动重载;旧版 NCFG 二进制(`/cfg/netcfg.bin`)首启自动迁移。
|
||||
- 掉电持久化:`net_cfg` 配置(通用配置文件 `/config.ini`,INI `[network]` 段,cfg_file 引擎),保存后下次上电生效、或立即生效(网络重建)、外部变更 4s 沉降后自动重载;旧版 NCFG 二进制(`/cfg/netcfg.bin`)**已不再读取**——存在则忽略(不读、不删、不迁移),配置回落工厂默认(自动迁移已于 2026-10-10 删除)。
|
||||
- 日志记录:`sys_log` 引擎写定长 64B 文本记录到 `/log/run.log`(运行记录)与 `/log/selftest.log`(自检记录),defaultTask 唯一写者,FTP 可直下(详见 `docs/子系统设计/运行与自检记录设计说明.md`);实时调试流 = 控制台单写者日志(USART1,4KB 环形缓冲 + defaultTask 唯一发送,详见 `docs/子系统设计/控制台单写者日志设计说明.md`)。
|
||||
- NAND 坏块表(BBT)持久化在保留块池,不交给 dhara 管理。
|
||||
|
||||
@@ -266,7 +266,7 @@ STM32F4-Base/
|
||||
│ ├── SD2506/ RTC
|
||||
│ ├── RS485/ 半双工串口
|
||||
│ ├── NET/ net_socket / net_select / lftpd
|
||||
│ ├── NETCFG/ 网口配置(INI [network] 段 + 旧档 NCFG 迁移)
|
||||
│ ├── NETCFG/ 网口配置(INI [network] 段)
|
||||
│ ├── UI/ LVGL UI(与模拟器共用)
|
||||
│ └── dbg_log.h/dbg_cfg.h 分级日志
|
||||
├── Lib/ 第三方:LVGL v9.2、FatFs、FreeRTOS、CMSIS
|
||||
@@ -343,3 +343,4 @@ flowchart LR
|
||||
| 2026-09-21 | **栈宽整改落地(内存方案 §1.4:lftpd 大局部缓冲静态化)**:`Drivers/BSP/NET/lftpd/lftpd.c` + `lftpd_log.c` 共 **9 处**大局部数组(`message[256]`/`response[512]`/`name[256]`×2/`buffer[1024]`×2/`read_buffer[512]`/`arg_buf[512]`/`client` 会话上下文/日志 `buffer[256]`)改为函数级 `static`(lftpd 单客户端、全部在 ftpTask 内串行);**ftpTask 实测峰值 3480 → 1184 B(余量 15% → 71%,判定 PASS)**,静态调用图 2528 → 472 B,代价静态 BSS +4,616 B(RW_IRAM1 82,048 / 131,072 B,余量仍 ~48 KB);§2.1 栈实测数据同步,原"涨栈到 1600 words"方案取消;FTP 功能回归 10/10 + 128KB 逐字节一致 |
|
||||
| 2026-09-24 → 09-25 | **控制台单写者日志**(09-24 实证驱动:多任务并发日志字符级交错 + HardFault 脏指针直达 UART):4KB 环形缓冲 + defaultTask 唯一发送(行级原子 + 指针可控)+ 内核前/ISR/异常钩子有界直发回退 + `fputc` 收敛到单写者路径;09-24 初版实施于 `Src/usart.c` USER CODE 区,09-25 迁出至 `App/log/console_log.{h,c}`(HAL 生成文件不含应用代码),`dbg_log.h` 改 `#include "console_log.h"`(调用点零改动),`Src/usart.c` 恢复纯 CubeMX 形态;`@build` 0/0 + `@test` PASS;详见 `docs/子系统设计/控制台单写者日志设计说明.md` |
|
||||
| 2026-09-25 | **defaultTask 任务体文件拆分**:`Src/freertos.c` 的 `StartDefaultTask` 任务体(存储 bring-up / 配置引擎属主 / 控制台单写者 attach+drain / syslog 落盘 / LED / 栈水位探针 `stack_probe_poll`)整体迁至 `App/task/default_task.c`(`default_task_func()`,与其余任务文件同址);`freertos.c` 恢复"CubeMX 接线 + 崩溃钩子"形态(719→361 行),`@build` 0/0 复验;栈配置属性仍定义于 `freertos.c`(`stack_report` 数据源不变) |
|
||||
| 2026-10-10 | **删除旧档 NCFG 迁移(栈整改)**:`Drivers/BSP/NETCFG/net_cfg_legacy.{c,h}` 整体移除、`cfg_store_legacy_path()` 撤销,`net_cfg_load` 不再调用 `net_cfg_legacy_migrate()`;旧档 `/cfg/netcfg.bin` 若存在则被忽略(不读、不删、不迁移),配置回落工厂默认。理由:该一次性路径把整条配置写链挂进启动期调用图,defaultTask 静态最坏栈链 +600 B,本仓库无携带旧档的设备。同轮栈整改(未抬栈):defaultTask 静态最坏链 5312 → 2776 B / 实测峰值 3392 → 2152 B、timeSyncTask 1736 → 1024 B,6 任务全 PASS;代价静态 BSS +4,128 B |
|
||||
|
||||
@@ -328,7 +328,7 @@ static void phaseN_run(void) {
|
||||
| `App/cfg/cfg_file.c` | 1250 行 | ✅ 已覆盖(139 断言,2026-10-02 S1-b) | 后端抽象(`cfg_file_store.h`) | 内存虚拟 FS 桩;**首测即抓出外科手术保存死码 P0**(见 §5) |
|
||||
| `App/log/sys_log_mcu.c` | — | ⬜ 候选 | 记录编解码(定长 64B) | 编解码纯逻辑;写入端依赖 FatFS + 队列,测编解码即可 |
|
||||
| `App/util/time_sync.c` | — | ⬜ 候选 | 协议帧编解码 | 报文组装/解析纯逻辑;网络收发不测 |
|
||||
| `Drivers/BSP/NETCFG/net_cfg_legacy.c` | — | ⬜ 候选 | 旧档 NCFG 迁移 + 自复制 CRC | CRC 校验与旧格式解析;可与 cfg_file 同桩 |
|
||||
| `Drivers/BSP/NETCFG/net_cfg_legacy.c` | — | ⛔ 已删除(2026-10-10) | — | 旧档 NCFG 迁移整体移除(旧档 `/cfg/netcfg.bin` 不读、不删、不迁移),测试候选随之撤销 |
|
||||
| `App/net/*`(网络栈上层) | — | ⬜ 待评估 | 依赖 socket/CH395F | 纯协议状态机部分或可测,需先确认抽象质量 |
|
||||
| `App/util/rs485.c` | — | ⏸ 待功能实现 | — | 上游 B2;当前为空桩 |
|
||||
| `Drivers/BSP/TPAFE5160/*.c` | — | ❌ 不适格 | — | 寄存器序列为主,需真机时序 |
|
||||
@@ -615,6 +615,7 @@ CI 只在 push / PR 时跑,且需 runner 就绪。**提交前自查、或 runn
|
||||
|
||||
| 日期 | 变更 |
|
||||
|---|---|
|
||||
| 2026-10-10 | §4.2.1 台账:`Drivers/BSP/NETCFG/net_cfg_legacy.c` 由 `⬜ 候选` 改为 **`⛔ 已删除`**——旧档 NCFG 迁移整体移除(`net_cfg_legacy.{c,h}` 删除、`cfg_store_legacy_path()` 撤销;旧档 `/cfg/netcfg.bin` 不读、不删、不迁移,配置回落工厂默认),该测试候选随之撤销 |
|
||||
| 2026-10-02 | **S6**:`test/run_all_suites.py` 新增 **`--check-build`**(只编译不烧录,纯离机,不需要 MCU/串口/ST-LINK);新增 **§3.6.1** 说明其解决的问题(测试构建无独立门禁,2026-08~09 CH395F 套件实例)、判定语义与用法。**实测 4 套件全部 `BUILD_OK: 0 errors, 0 warnings`**(即 T-4 提到的"CH395F 不可编译"已修复) |
|
||||
| 2026-10-02 | **S1-b + S2**:新增 **§4.2.1「L0.5 适格模块台账」**(判据 + 模块状态表 + "两条实证":sys_clock / cfg_file 首测即各抓一处生产缺陷);§4.1 登记 `test/host/cfg_file/` 新单测。同步新增 [`配置文件单元测试说明.md`](配置文件单元测试说明.md)(含抓出的 `s_encode` 返回值误判 P0 缺陷记录) |
|
||||
| 2026-10-02 | **S3 + S14**:§9.1 第 2 条改正(原文"强制跑 `mem-numbers`"自相矛盾 → 改为"按 `.map` 有无自适应跳过")并加 🔴 门禁盲区声明;§9.2 补 S3 结果可见性(`Tee-Object` 落盘 + `$GITHUB_STEP_SUMMARY` + `::notice::` 汇总行,不用 `actions/upload-artifact`)。另:§4.1 登记 `test/host/sys_clock/` 新单测(S1-a) |
|
||||
|
||||
+11
-7
@@ -507,12 +507,15 @@ $env:DTU_KEIL_UV4 = 'D:\NotExist\UV4.exe' # 仅当前会话,不动用户级
|
||||
|
||||
| 任务 | 栈大小 | 优先级 |
|
||||
|---|---|---|
|
||||
| defaultTask | 2048 | Normal |
|
||||
| netTask | 4096 | Normal |
|
||||
| ftpTask | 4096 | Normal |
|
||||
| testTask | 4096 | BelowNormal |
|
||||
| uiTask | 16384 | BelowNormal |
|
||||
| timeSyncTask | 2048 | Normal |
|
||||
| defaultTask | 1024 | Normal |
|
||||
| netTask | 960 | Normal |
|
||||
| ftpTask | 1024 | Normal |
|
||||
| testTask | 2048 | BelowNormal |
|
||||
| uiTask | 4096 | BelowNormal |
|
||||
| timeSyncTask | 512 | Normal |
|
||||
|
||||
> 上表由 `scripts/gen_task_table.py` 同源(唯一来源 `Src/freertos.c` / `.ioc` 的 `FREERTOS.Tasks01`);
|
||||
> 2026-10-10 栈整改**未改任何栈值**,靠削调用链达标(详见 `docs/内存管理/RAM使用分析与优化方案.md`)。
|
||||
|
||||
> 挖潜方向(未实施):SRAM3 64 KB / CCM 64 KB 未映射——详见 `docs/内存管理/`。
|
||||
> 部署侧含义:**不要做任何需要额外 RAM 的固件定制**,新增功能先过内存预算。
|
||||
@@ -540,7 +543,7 @@ $env:DTU_KEIL_UV4 = 'D:\NotExist\UV4.exe' # 仅当前会话,不动用户级
|
||||
|
||||
| 参数 | 工厂默认 | 修改方式 |
|
||||
|---|---|---|
|
||||
| IP | **192.168.1.100**(静态,无 DHCP) | 屏幕 `通讯参数 → 网口设置`(修改密码 `123`)保存后**立即生效**(网络重建约 1~3 s);或预置 `/config.ini`(INI;旧版 `/cfg/netcfg.bin` 首启自动迁移) |
|
||||
| IP | **192.168.1.100**(静态,无 DHCP) | 屏幕 `通讯参数 → 网口设置`(修改密码 `123`)保存后**立即生效**(网络重建约 1~3 s);或预置 `/config.ini`(INI;旧版 `/cfg/netcfg.bin` **不再读取**——存在则忽略、不迁移,配置回落工厂默认,2026-10-10 起) |
|
||||
| 子网掩码 | 255.255.255.0(/24) | 同上 |
|
||||
| 默认网关 | 192.168.1.1 | 同上 |
|
||||
| MAC | 全零 = 芯片内置 MAC | 同上(全零是"使用芯片内置 MAC"的哨兵,不是"MAC 为 0") |
|
||||
@@ -644,6 +647,7 @@ $env:DTU_KEIL_UV4 = 'D:\NotExist\UV4.exe' # 仅当前会话,不动用户级
|
||||
|
||||
| 日期 | 变更 |
|
||||
|---|---|
|
||||
| 2026-10-10 | **删除旧档 NCFG 迁移**(升级/迁移口径变更):旧固件遗留的 `/cfg/netcfg.bin` 不再"首启自动迁移"——旧档若存在则被忽略(不读、不删、不迁移),配置直接回落工厂默认(`/config.ini` `[network]` 段模板)。`net_cfg_legacy.c/h` 与 `cfg_store_legacy_path()` 已移除;携带旧档的设备升级后需经 UI 或 FTP 重新配置网口。§五 现场部署 IP 行同步 |
|
||||
| 2026-10-02 | **模拟器构建修复**(配置引擎重构遗留):`simulator/CMakeLists.txt` 的配置文件引擎引用同步到迁移后位置——包含目录 `App/`→`App/cfg/`(`cfg_file.h`/`cfg_file_store.h`)、源文件 `App/cfg_file.c`→`App/cfg/cfg_file.c`、包含目录 `test/`→`test/board/`(`test_config.h`/`net_latency_test.h`);全量 include 离线核查无其他断链,模拟器全量构建恢复(`--cfgtest` 四场景 PASS,rc=0)。§2.12 验证链 ⑤ 行同步更新 |
|
||||
| 2026-10-02 | 更正 Device Pack 必装范围:`Keil::CMSIS` pack 不再列为必装项——本工程不依赖它(核心头文件由仓库 `Drivers/CMSIS/` 提供,`.uvprojx` 只引用 DFP pack;2026-10-02 本机实测未装 CMSIS pack 构建 0/0 通过),且其 keil.com 直链(5.7.0~6.1.0)均已下架 404;必装的只有 `Keil::STM32F4xx_DFP`(3.1.1,与 `.uvprojx` PackID 一致)。§2.2 / 第 2 步 / 搭建清单 / §2.10 同步更正 |
|
||||
| 2026-10-02 | 新增 §2.12「跨机验证(第二台机器 / 换机验收清单)」:变量配置 + sanity check → 六步验证链(含期望结果与失败诊断,含模拟器既有 CMake 问题标注)→ 反向 fail-fast 测试 → 通过判定,作为方案跨机验收的标准操作 |
|
||||
|
||||
@@ -104,7 +104,6 @@ set(SYSLOG_SOURCES
|
||||
# 网络配置(双端共享核心 + cfg_file 引擎 + 平台存储后端;MCU 端编 cfg_file_store_mcu.c,见 Keil 工程)
|
||||
set(NETCFG_SOURCES
|
||||
${NETCFG_DIR}/net_cfg.c
|
||||
${NETCFG_DIR}/net_cfg_legacy.c
|
||||
${PROJECT_ROOT}/App/cfg/cfg_file.c
|
||||
sim/cfg_file_store_sim.c
|
||||
)
|
||||
|
||||
+9
-9
@@ -18,7 +18,7 @@ simulator/
|
||||
│ ├── sim_port.c / .h # 显示/输入端口(SDL 窗口 + 键盘 + mono 主题),替代 MCU 端 ui_port.c
|
||||
│ ├── net_socket_sim.c # 网络后端:Winsock 实现 net_* BSD API,替代 MCU 端 net_socket.c(CH395F)
|
||||
│ ├── ui_net_sink_backend_sim.c # RemoDispBus 平台 backend:取帧/注键(配合共享 ui_net_sink.c)
|
||||
│ └── cfg_file_store_sim.c # 配置文件存储后端:本地 sim_config.ini(旧档 sim_netcfg.bin 首启自动迁移)
|
||||
│ └── cfg_file_store_sim.c # 配置文件存储后端:本地 sim_config.ini(旧档 sim_netcfg.bin 已废弃,不读不删)
|
||||
├── lv_conf.h # 模拟器专用 LVGL 配置(与 MCU 端 Lib/lv_conf.h 相互独立)
|
||||
├── i1_to_png.py # 截图转 PNG:把 --screenshot 的 I1(1bpp) 原始位图转成 PNG(见 §3.5)
|
||||
├── tests/ # 无头回归脚本 + 本地黄金参考(见 §3.6,流程文档 docs/UI设计/UI_自动化测试流程.md)
|
||||
@@ -47,11 +47,11 @@ simulator/
|
||||
| `sim/sim_port.c` | 创建 SDL 窗口显示设备(`lv_sdl_window_create`)、初始化 **mono 主题**(`lv_theme_mono_init`,1bpp 必需)、创建键盘输入设备并挂默认输入组。**不创建鼠标**(纯键盘导航,与 MCU 端 keypad 一致)。`sim_port_get_screen_mono()` 经 `SDL_RenderReadPixels` 读回屏幕像素转 1bpp,供推流取帧 |
|
||||
| `sim/net_socket_sim.c` | 网络后端:Winsock 实现 `net_*` BSD Socket API(`socket`/`bind`/`listen`/`accept`/`recv`/`send`/`close`),替代 MCU 端 `Drivers/BSP/NET/net_socket.c`(CH395F) |
|
||||
| `sim/ui_net_sink_backend_sim.c` | RemoDispBus 平台 backend:`ui_net_sink_get_lcdmem`→`sim_port_get_screen_mono`、`ui_net_sink_inject_key`→`lv_group_send_data`;配合**共享** `Drivers/BSP/UI/ui_net_sink.c`(协议服务端,双端同一份,TCP 7003) |
|
||||
| `sim/cfg_file_store_sim.c` | 通用配置文件存储后端:本地文件 `sim_config.ini`(`fopen`/`rename` 原子写),替代 MCU 端 `App/cfg/cfg_file_store_mcu.c`(FatFS);旧档 `sim_netcfg.bin` 首启自动迁移进 `sim_config.ini` |
|
||||
| `sim/cfg_file_store_sim.c` | 通用配置文件存储后端:本地文件 `sim_config.ini`(`fopen`/`rename` 原子写),替代 MCU 端 `App/cfg/cfg_file_store_mcu.c`(FatFS);旧档 `sim_netcfg.bin` **已废弃**——不读、不删、不迁移(2026-10-10) |
|
||||
| `lv_conf.h` | 模拟器专用 LVGL 配置。与 MCU 端 `Lib/lv_conf.h` 的关键差异见 §3.3 |
|
||||
| `dbg_log.h` | MCU 版 `dbg_log.h` 依赖 `sys_clock.h`(RTC 时间戳),PC 无法编译。此 stub 把 `DBG_INFO/ERROR/DEBUG` 映射到 `printf`;因 `simulator/` 在 include 路径最前,**优先生效**覆盖 MCU 版 |
|
||||
| `build_sim.bat` / `build_sim.ps1` | 一键构建入口:vswhere 探测本机 VS 大版本(16=2019 / 17=2022 / 18=2026,取已装最高)→ 映射 CMake 生成器;`build/` 缓存生成器与本机不符(换机/升级 VS)时自动删除重建(带重试,抗文件锁)。**构建入口一律走它,文档/命令中勿写死生成器版本**;`.bat` 仅负责绕过 PowerShell 执行策略并转交 `.ps1` |
|
||||
| `CMakeLists.txt` | 收集 LVGL 源码(`../Lib/lvgl`)+ 共享 UI 源码(`../Drivers/BSP/UI`)+ 通用配置文件引擎(`../App/cfg_file.c`、`../Drivers/BSP/NETCFG` 的 net_cfg/net_cfg_legacy)+ `sim/` 平台层,链接预编译 SDL2,产出 `lvgl_sim.exe` |
|
||||
| `CMakeLists.txt` | 收集 LVGL 源码(`../Lib/lvgl`)+ 共享 UI 源码(`../Drivers/BSP/UI`)+ 通用配置文件引擎(`../App/cfg_file.c`、`../Drivers/BSP/NETCFG` 的 net_cfg;`net_cfg_legacy` 已于 2026-10-10 删除)+ `sim/` 平台层,链接预编译 SDL2,产出 `lvgl_sim.exe` |
|
||||
| `i1_to_png.py` | 把 `--screenshot` 产出的 I1(1bpp) 原始位图转成 PNG,便于离线比对设计稿。详见 §3.5 |
|
||||
| `tests/` | 无头回归脚本(菜单 8 状态像素回归、内容页文本断言 + 黄金参考回归);`ref/` 为**本地生成物、不入库**(首次 `--update` 生成)。详见 §3.6 |
|
||||
|
||||
@@ -114,7 +114,7 @@ LVGL 场景(同一份 ui_menu.c)
|
||||
| 输入 | 远端 keypad(`ui_port_queue_key`,网络回传键码) | SDL 键盘(`lv_sdl_keyboard_create`) |
|
||||
| 主题 | 无主题(`LV_USE_THEME_* = 0`),控件用内置基础样式 | **mono 主题必须开启**(否则 1bpp 黑底黑字) |
|
||||
| 日志 | `Drivers/BSP/dbg_log.h`(USART1 + RTC 时间戳) | `simulator/dbg_log.h`(printf stub) |
|
||||
| 业务任务 | netTask / ftpTask / timeSyncTask 等 | 无(仅编译纯软件部分的配置文件引擎 net_cfg/cfg_file,可离线验证配置加载/保存/旧档迁移) |
|
||||
| 业务任务 | netTask / ftpTask / timeSyncTask 等 | 无(仅编译纯软件部分的配置文件引擎 net_cfg/cfg_file,可离线验证配置加载/保存) |
|
||||
| 时钟 | `lv_tick_inc` 由 ui_task 手动喂(10ms 周期) | SDL 驱动内部 `lv_tick_set_cb(SDL_GetTicks)`,**不可再手动喂** |
|
||||
|
||||
### 2.4 关键设计决策
|
||||
@@ -123,7 +123,7 @@ LVGL 场景(同一份 ui_menu.c)
|
||||
2. **CMake + MSVC**:`build_sim.ps1` 按本机 VS 版本自动选生成器(16=2019 / 17=2022 / 18=2026;不同机器版本不同,**勿写死**),`-A x64`;MSVC 下加 `/utf-8` 消除中文注释的 C4819 警告
|
||||
3. **共享 UI 源码**:`ui_menu.c` / `ui_font_cn_12.c` 直接编译 `Drivers/BSP/UI/` 原件,改一处两端同时生效
|
||||
4. **纯键盘导航**:不创建鼠标/触摸设备,与 MCU 端 keypad 操作语义一致(↑↓←→ / Enter / Esc)
|
||||
5. **UI 为主**:不含 CH395F 网络 / NAND 存储 / ADC 等硬件业务;通用配置文件引擎(`cfg_file`)与 `net_cfg` 核心为纯软件,配置加载/保存/旧档迁移可在模拟器离线验证(`sim_config.ini` / `sim_netcfg.bin`)
|
||||
5. **UI 为主**:不含 CH395F 网络 / NAND 存储 / ADC 等硬件业务;通用配置文件引擎(`cfg_file`)与 `net_cfg` 核心为纯软件,配置加载/保存可在模拟器离线验证(`sim_config.ini`;旧档 `sim_netcfg.bin` 已废弃、不参与)
|
||||
|
||||
---
|
||||
|
||||
@@ -232,15 +232,15 @@ UI 改动的自动化门禁脚本(完整流程见 `docs/UI设计/UI_自动化
|
||||
|
||||
### 3.7 配置文件自检(--cfgtest)
|
||||
|
||||
配置引擎"加载 → 轮询 → 重载 → 保存"的进程内闭环验证(无需窗口 / LVGL,退出码 0=PASS / 非 0=FAIL),在当前工作目录产生 `sim_config.ini`(`sim_netcfg.bin` 参与迁移时):
|
||||
配置引擎"加载 → 轮询 → 重载 → 保存"的进程内闭环验证(无需窗口 / LVGL,退出码 0=PASS / 非 0=FAIL),在当前工作目录产生 `sim_config.ini`:
|
||||
|
||||
```powershell
|
||||
.\build\Debug\lvgl_sim.exe --cfgtest
|
||||
```
|
||||
|
||||
验证链:`net_cfg_load`(含旧档自动迁移)→ 第 1 次 poll 建基线 → 伪造"外部编辑"(原子写,等价 FTP 上传/文本编辑器)→ 2 次 poll 沉降(对应真机 4s 沉降)→ 断言 RAM 副本已更新为新值 → 对已存在文件做外科式保存、回读校验注释/值无损。
|
||||
验证链:`net_cfg_load`(旧档迁移已于 2026-10-10 删除,只走 INI)→ 第 1 次 poll 建基线 → 伪造"外部编辑"(原子写,等价 FTP 上传/文本编辑器)→ 2 次 poll 沉降(对应真机 4s 沉降)→ 断言 RAM 副本已更新为新值 → 对已存在文件做外科式保存、回读校验注释/值无损。
|
||||
|
||||
空目录运行 = 验证出厂模板生成;预置有效 `sim_netcfg.bin` = 验证旧档迁移(迁移后删除);无效旧档(CRC 不符)= 保留旧文件 + 生成出厂模板。窗口模式主循环以与 MCU netTask 相同的 2s 周期调用 `cfg_file_poll()`:外部文件变更沉降后自动重载 `[network]` 段(模拟器无网络栈,变更回调为空操作,仅日志可见)。
|
||||
空目录运行 = 验证出厂模板生成;超限文件(>4096 B)= 判损坏并重建出厂模板;超限文档保存 = 拒绝且不动原文件。窗口模式主循环以与 MCU netTask 相同的 2s 周期调用 `cfg_file_poll()`:外部文件变更沉降后自动重载 `[network]` 段(模拟器无网络栈,变更回调为空操作,仅日志可见)。
|
||||
|
||||
---
|
||||
|
||||
@@ -273,7 +273,7 @@ UI 改动的自动化门禁脚本(完整流程见 `docs/UI设计/UI_自动化
|
||||
|
||||
## 五、边界说明
|
||||
|
||||
- 模拟器**跑 UI + 配置文件引擎**:不含 CH395F 网络、NAND 存储、ADC、RS-485 等硬件业务;`cfg_file` 引擎与 `net_cfg`(纯软件部分)在模拟器编译运行,可离线验证配置加载/保存/旧档迁移
|
||||
- 模拟器**跑 UI + 配置文件引擎**:不含 CH395F 网络、NAND 存储、ADC、RS-485 等硬件业务;`cfg_file` 引擎与 `net_cfg`(纯软件部分)在模拟器编译运行,可离线验证配置加载/保存
|
||||
- 模拟器**含** `ui_net_sink`(Winsock 版 RemoDispBus 推流服务端,TCP 7003)——远端看图链路
|
||||
可在模拟器上验证(`simulator/tests/check_remo_sink.py`);CH395F 真实网络栈仍只在 MCU 上验证
|
||||
- `build/` 为生成物,可随时删除重建(已在 `.gitignore` 中忽略)
|
||||
|
||||
+4
-3
@@ -20,7 +20,8 @@
|
||||
*
|
||||
* 配置轮询自检模式(无窗口、进程内闭环、退出码 0=PASS / 非0=FAIL):
|
||||
* lvgl_sim.exe --cfgtest
|
||||
* 验证链:net_cfg_load(含旧档迁移)→ poll 建基线 → 伪造外部编辑
|
||||
* 验证链:net_cfg_load(只读 INI;旧 NCFG 档迁移已于 2026-10-10 删除)
|
||||
* → poll 建基线 → 伪造外部编辑
|
||||
* (原子写新文档,等价 FTP 上传/文本编辑器)→ poll 两次(4s 沉降)
|
||||
* → 断言 RAM 副本已按新文件重载
|
||||
*
|
||||
@@ -239,7 +240,7 @@ static const uint8_t s_cfgtest_ip[4] = { 10u, 0u, 0u, 1u };
|
||||
|
||||
/*
|
||||
* @brief 配置轮询自检(无窗口、无需 LVGL/SDL,进程内闭环)
|
||||
* @note 验证链:net_cfg_load(含旧档迁移)→ poll 建基线 → 伪造外部编辑
|
||||
* @note 验证链:net_cfg_load(只读 INI)→ poll 建基线 → 伪造外部编辑
|
||||
* → poll 两次(沉降去抖)→ 重载并更新 RAM 副本
|
||||
* @return 0 PASS,非 0 FAIL
|
||||
*/
|
||||
@@ -250,7 +251,7 @@ static int run_cfgtest(void)
|
||||
|
||||
setvbuf(stdout, NULL, _IONBF, 0);
|
||||
|
||||
(void)net_cfg_load(); /* 加载 / 旧档迁移(含 [network] 段注册) */
|
||||
(void)net_cfg_load(); /* 加载 INI(含 [network] 段注册;旧 NCFG 档不再读取) */
|
||||
|
||||
cfg_file_poll(); /* 第 1 次 poll:建立变更基线 */
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* 模块名称:cfg_file_store (模拟器后端)
|
||||
* 模块功能:cfg_file 存储后端——模拟器工作目录宿主文件 sim_config.ini;
|
||||
* 原子写 = 临时文件 sim_config.ini.tmp + rename;mtime 变更令牌 =
|
||||
* 宿主文件 mtime(秒级);旧版遗留文件 sim_netcfg.bin 供迁移读取
|
||||
* 宿主文件 mtime(秒级)
|
||||
* 适用平台:PC 模拟器
|
||||
* 作者:王建锋
|
||||
* 创建日期:2026-09-14
|
||||
@@ -24,7 +24,6 @@
|
||||
|
||||
static const char s_path[] = "sim_config.ini";
|
||||
static const char s_path_tmp[] = "sim_config.ini.tmp";
|
||||
static const char s_path_legacy[] = "sim_netcfg.bin";
|
||||
|
||||
/* 函数定义区 */
|
||||
|
||||
@@ -144,14 +143,9 @@ const char *cfg_store_tmp_path(void) {
|
||||
}
|
||||
|
||||
/*
|
||||
* 函数功能:取旧版配置遗留文件路径
|
||||
* 入口参数:无
|
||||
* 返回值:"sim_netcfg.bin"(与 MCU 端旧格式一致,两端可互读) const char *
|
||||
* 限定条件:无
|
||||
* 旧版遗留档 getter(cfg_store_legacy_path)已于 2026-10-10 随旧档迁移
|
||||
* net_cfg_legacy 一并删除:旧格式 sim_netcfg.bin 不再读取
|
||||
*/
|
||||
const char *cfg_store_legacy_path(void) {
|
||||
return s_path_legacy;
|
||||
}
|
||||
|
||||
/*
|
||||
* 函数功能:分配共享核心临时缓冲(宿主 CRT 堆)
|
||||
|
||||
@@ -262,6 +262,7 @@ def main():
|
||||
ok = True
|
||||
|
||||
# 清理手工运行残留的配置存储文件(模拟器工作目录),防"工厂默认值"像素参考被污染
|
||||
# (sim_netcfg.bin 是旧档时代的产物:旧档迁移已于 2026-10-10 删除,此处只做兼容清理)
|
||||
stale = Path.cwd() / "sim_netcfg.bin"
|
||||
if stale.exists():
|
||||
stale.unlink()
|
||||
|
||||
@@ -98,7 +98,6 @@ static int s_read_count = 0;
|
||||
/* 路径常量(与生产逻辑无关,仅作为桩内部标识) */
|
||||
static const char *s_cfg_path = "/config.ini";
|
||||
static const char *s_tmp_path = "/config.tmp";
|
||||
static const char *s_legacy_path = "/netcfg.dat";
|
||||
|
||||
/* ---- 堆:直接映射宿主 CRT(单测不模拟 MicroLIB 512B 堆约束) ---- */
|
||||
void *cfg_store_alloc(size_t size) {
|
||||
@@ -171,7 +170,6 @@ int cfg_store_remove(const char *p_path) {
|
||||
|
||||
const char *cfg_store_config_path(void) { return s_cfg_path; }
|
||||
const char *cfg_store_tmp_path(void) { return s_tmp_path; }
|
||||
const char *cfg_store_legacy_path(void) { return s_legacy_path; }
|
||||
|
||||
/* ---- sys_log 桩:只计数自检留痕(不落盘) ---- */
|
||||
#include "sys_log.h"
|
||||
|
||||
@@ -73,23 +73,23 @@ FLASH_CODE_SUB = [
|
||||
("其他 (长尾)", 56638, "#E0E0E0"), # remainder
|
||||
]
|
||||
|
||||
# ── Task stack budgets (2026-09-21 @build + FTP 128KB 实测; data/stack_report_20260921.md) ──
|
||||
# ── Task stack budgets (2026-10-10 @build + 开机/空闲实测; data/stack_report_20261010.md) ──
|
||||
# (name, cfg, prio, worst, peak_used, margin, margin_pct, verdict, desc)
|
||||
# worst = max(静态最坏深度, 实测峰值); margin = cfg - worst
|
||||
TASK_STACKS = [
|
||||
("defaultTask", 4096, "Normal", 2776, 2136, 1320, 32, "PASS", "FatFS 挂载/探针 + 配置引擎 + syslog + 栈探针"),
|
||||
("netTask", 4096, "Normal", 588, 588, 3508, 85, "PASS", "CH395F 轮询、消息处理"),
|
||||
("ftpTask", 4096, "Normal", 1184, 1184, 2912, 71, "PASS", "lftpd FTP 服务(大缓冲已静态化)"),
|
||||
("testTask", 8192, "BelowNormal", 348, 348, 7844, 95, "PASS", "测试套件(产品构建空转)"),
|
||||
("uiTask", 16384, "BelowNormal", 3824, 3824, 12560, 76, "PASS", "LVGL UI 主循环"),
|
||||
("timeSyncTask", 2048, "Normal", 420, 420, 1628, 79, "PASS", "TCP 时间同步"),
|
||||
("defaultTask", 4096, "Normal", 2776, 2152, 1320, 32, "PASS", "FatFS 挂载/探针 + 配置引擎 + syslog + 栈探针"),
|
||||
("netTask", 3840, "Normal", 1872, 920, 1968, 51, "PASS", "CH395F 轮询、消息处理"),
|
||||
("ftpTask", 4096, "Normal", 1216, 740, 2880, 70, "PASS", "lftpd FTP 服务(大缓冲已静态化)"),
|
||||
("testTask", 8192, "BelowNormal", 496, 496, 7696, 93, "PASS", "测试套件(产品构建不创建,取静态最坏链)"),
|
||||
("uiTask", 16384, "BelowNormal", 4016, 4016, 12368, 75, "PASS", "LVGL UI 主循环"),
|
||||
("timeSyncTask", 2048, "Normal", 1024, 616, 1024, 50, "PASS", "TCP 时间同步(余量正好卡在 ISR 底线)"),
|
||||
]
|
||||
KERNEL_STACKS = [("idle", 512), ("timer", 1024)] # 128/256 words
|
||||
|
||||
HEAP_TOTAL = 49152 # configTOTAL_HEAP_SIZE(位于 RW_CCM)
|
||||
HEAP_FREE = 8784 # 2026-09-21 实测(含 FTP 负载)
|
||||
HEAP_MIN_EVER = 4848
|
||||
TOTAL_STACKS = sum(t[1] for t in TASK_STACKS) # 38,912
|
||||
TOTAL_STACKS = sum(t[1] for t in TASK_STACKS) # 38,656
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# SVG helpers
|
||||
@@ -287,7 +287,7 @@ def gen_taskstack_svg():
|
||||
|
||||
svg = svg_header(W, H)
|
||||
svg += f'<text x="{W/2}" y="22" text-anchor="middle" class="title">FreeRTOS 任务栈预算(48KB 堆,2026-09-21 已迁 CCM)</text>\n'
|
||||
svg += f'<text x="{W/2}" y="40" text-anchor="middle" class="legend-text" fill="#777">数据: 2026-09-21 @build + FTP 128KB 实测(data/stack_report_20260921.md)</text>\n'
|
||||
svg += f'<text x="{W/2}" y="40" text-anchor="middle" class="legend-text" fill="#777">数据: 2026-10-10 @build + 开机/空闲实测(data/stack_report_20261010.md);最坏 = max(静态最坏链, 实测峰值)</text>\n'
|
||||
svg += f'<text x="{BAR_X}" y="{Y_START-10}" class="legend-text" fill="#555">浅色条 = 分配栈 深色条 = 最坏占用(max(静态最坏, 实测峰值)) 下方文字 = 实测余量/判定</text>\n'
|
||||
|
||||
y = Y_START
|
||||
|
||||
Reference in New Issue
Block a user