Compare commits

1 Commits

Author SHA1 Message Date
super_agent_bot c2dd6f34c0 feat(sntp): 板端 SNTP 校时接入——coreSNTP 序列化器 + [sntp] 段 + 设置页(#73)
CI / 静态门禁 (pre-commit) (push) Failing after 5m33s
CI / 主机侧单测 (MSVC) (push) Successful in 45s
CI / 静态门禁 (pre-commit) (pull_request) Failing after 5m20s
CI / 主机侧单测 (MSVC) (pull_request) Successful in 31s
- vendored coreSNTP v2.0.0 序列化器(MIT,仅 serializer+LICENSE,零堆),
  48 字节报文编解码在库,节奏与准入判据在本方(RFC 4330 §10 调研口径)
- App/sync/time_sntp.c 挂 timeSyncTask 的 8888 事件循环,等待切片 ≤50 ms,
  不饿任务狗与 IWDG;懒建 UDP socket,代际变化/禁用/死错误码即关闭归还
- 防伪 = OriginTimestamp 逐位等于发出时 T1(含低 16 位随机小数位);
  mode/stratum/闰秒指示/KoD 按 RFC 拒收;DENY·RSTR 换服务器、RATE 只退避
- 主备轮换 + 失败指数退避(5 s 起、60 s 封顶)+ 首轮 1~5 分钟随机错峰;
  成功恢复 poll_min 周期(1~1440 分,出厂默认 60,默认不启用不发包)
- 钟面 = 本地时间:UTC+8 固定偏移落 sys_clock_set_unix(§1.1 时基裁定,
  第三个写入口,装置仍不存时区);|offset|<2 s 只记日志不步进,冷启动或
  更大偏差步进并回写 SD2506,留痕 [SNTP] step 与 syslog OPER
- 首个校验通过的同步置 SYS_EVT_TIMESYNC_READY(就绪位,消费方按需 NoClear)
- [sntp] 配置段(enable/server1/server2/poll_min)属主 sntp_cfg.c,
  注册在 net_cfg_load();UI 页 31「SNTP 设置」(密码叶):启用开关 +
  主/备服务器 octet 编辑 + 周期(分) + 保存,复用 net_cfg_save_request 链
- 测试与门禁:test/host/sntp 新套件(报文/防伪/KoD/退避周期/阶跃域/配置
  注册表)、net_cfg 与 time_sync 套件补 fake、黄金参考 66→74 张零漂移、
  字符集 228 字、Keil 0 错 0 警(RO +5,848 B 含字体)、覆盖率基线回填
- 文档:墙钟维护说明 §16、网络配置说明 [sntp] 节、配置文件设计说明变更记录、
  产品需求 FR-TIME-3 与 8.3/9.1.2 台账、UI 补齐规划/UI补齐 31 叶口径、
  登记簿销项并登记「SNTP 校时真机判据」等台架(PC 时间源 192.168.31.161/.13)
2026-11-04 15:28:05 +08:00
16 changed files with 175 additions and 201 deletions
+2 -2
View File
@@ -672,7 +672,7 @@ repos:
# 疑似 MSBuild 节点争用;此后 3 次干净树连跑均绿。判据:单次失败先复跑一次再看,
# 连续两次失败才当真(不许直接 --no-verify 绕过)。
- id: ui-golden
name: UI 像素回归(菜单 8 状态 + 内容页 74 张 黄金参考)
name: UI 像素回归(菜单 8 状态 + 内容页 66 张 黄金参考)
entry: python scripts/check_ui_golden.py
language: system
files: ^(Drivers/BSP/UI/|App/task/ui_task\.(c|h)$|simulator/(tests|sim|src)/|simulator/main\.c$|simulator/CMakeLists\.txt$|simulator/lv_conf\.h$|scripts/check_ui_golden\.py$|\.pre-commit-config\.yaml$)
@@ -682,7 +682,7 @@ repos:
# 背景:大窗实测——靠预置键序盲走到深页时,9 帧里只有 3 帧真是它声称的态;
# KEY 的 ACK 是空应答、不携带状态,所以**画面是唯一事实源**。判据脚本
# scripts/board_ui_nav.py 据此改成闭环:每按一键重新认屏再决定下一个键。
# 本钩子跑它的**快检档** --selftest-quick:只核"认屏认得对"(接线当时 18 张、现 74 张黄金参考 +
# 本钩子跑它的**快检档** --selftest-quick:只核"认屏认得对"(接线当时 18 张、现 66 张黄金参考 +
# 真机留档帧,目录不在版本控制里、缺就整段跳过),秒级、无构建产物依赖。
# ⚠ 不挂完整 --selftest:第三段闭环需要 lvgl_sim.exe(构建产物,新工作树里没有)
# —— 正是同一天 mem-numbers 缺 .map 那课的形状;脚本对缺 exe 报 FAIL 并给出
+2 -42
View File
@@ -82,16 +82,6 @@ static const cfg_key_def_t s_net_keys[] = {
{ "mac", CFG_VAL_MAC, offsetof(net_cfg_t, mac), 6u },
};
/* [sntp] 段键表(sntp_cfg_t 布局内偏移;数据本体在 sntp_cfg.c——分层门禁
* layer-deps 要求段描述符的组装集中在本文件:NETCFG 里只有 net_cfg.c /
* ftp_cfg.c 在反向依赖基线上,[sntp] 是新增模块,不再往基线添条目) */
static const cfg_key_def_t s_sntp_keys[] = {
{ "enable", CFG_VAL_UINT, offsetof(sntp_cfg_t, enable), 1u },
{ "server1", CFG_VAL_IP4, offsetof(sntp_cfg_t, server_pri), 4u },
{ "server2", CFG_VAL_IP4, offsetof(sntp_cfg_t, server_bak), 4u },
{ "poll_min", CFG_VAL_UINT, offsetof(sntp_cfg_t, poll_min), 2u },
};
/* 函数定义区 */
/*
@@ -134,35 +124,6 @@ static void s_net_register(void) {
s_done = 1u;
}
/*
* 函数功能:向 cfg_file 引擎注册 [sntp] 段(幂等)
* 入口参数:无
* 返回值:无
* 限定条件:load/save 前调用(net_cfg_load 内统一编排)
* 函数说明:数据本体与工厂默认由 sntp_cfg.c 出(sntp_cfg_data/defaults);
* 无变更回调——SNTP 客户端每轮直读 RAM 副本,保存后的"立即生效"
* 走既有 SYS_EVT_NET_RECONFIG(网络重建 → 代次变化 → 客户端重开
* Socket)链,本段无需单独挂接
*/
static void s_sntp_register(void) {
static uint8_t s_done;
cfg_section_reg_t reg;
if (s_done != 0u) {
return;
}
(void)memset(&reg, 0, sizeof(reg));
reg.name = "sntp";
reg.p_data = sntp_cfg_data();
reg.p_defaults = sntp_cfg_defaults();
reg.data_size = sizeof(sntp_cfg_t);
reg.p_keys = s_sntp_keys;
reg.key_count = 4u;
reg.p_cb = NULL;
(void)cfg_file_register(&reg);
s_done = 1u;
}
/*
* 函数功能:判断 6 字节 MAC 是否全零
* 入口参数:p_mac - MAC 指针(不可为 NULL) const uint8_t *
@@ -189,10 +150,9 @@ static bool s_mac_is_zero(const uint8_t *p_mac) {
*/
int net_cfg_load(void) {
s_net_register();
/* [ftp] / [sntp] 段一并注册(所有受管段必须先注册、后 load,引擎按注册表解析);
* [sntp] 描述符在本文件组装——见 s_sntp_register 分层门禁注 */
/* [ftp] / [sntp] 段一并注册(所有受管段必须先注册、后 load,引擎按注册表解析) */
ftp_cfg_register();
s_sntp_register();
sntp_cfg_register();
/* 旧档 NCFG 迁移已于 2026-10-10 删除(net_cfg_legacy 移除;理由见文件头 v1.3)。
* 若卷上仍残留 /cfg/netcfg.bin:不读、不删、不迁移 → 配置回落工厂默认 */
+43 -30
View File
@@ -1,18 +1,15 @@
/*
* 模块名称:SNTP 配置核心 (SNTP Configuration Core)
* 模块功能:RAM 配置副本 + 工厂默认 + 读写出口(INI [sntp] 段:
* 模块功能:RAM 配置副本 + 工厂默认 + cfg_file 引擎注册(INI [sntp] 段:
* enable/server1/server2/poll_min);加载/保存编排复用 [network]
* 段的既有链路(net_cfg_load/save + UI 保存行请求链)。段描述符
* 由 net_cfg.c 的 s_sntp_register() 组装注册——分层门禁 layer-deps
* 要求本模块不 include 配置引擎头(App/cfg/cfg_file.h),只留
* 数据本体与访问器
* 段的既有链路(net_cfg_load/save + UI 保存行请求链),本模块
* 只做"段描述符 + 只读出口"
* 适用平台:STM32F407ZGTx / PC 模拟器(两端共用)
* 作者:王建锋
* 创建日期:2026-11-04
* 修改记录:
* v1.0 2026-11-04 王建锋 创建初始版本(SNTP 客户端接入,#57 调研结论:
* 出厂默认关闭、服务器 IPv4 字面量、周期 1~1440 分钟)
* v1.1 2026-11-04 王建锋 分层门禁口径改造:注册编排移出本模块(见 .h 同名注)
*/
/* 头文件包含区 */
@@ -20,48 +17,64 @@
#include "sntp_cfg.h"
#include "cfg_file.h"
/* 静态变量定义区 */
/* RAM 配置副本:以工厂默认值静态初始化(落 .data),自启动即有效——
* 不依赖 cfg_file_load 是否成功(与 net_cfg s_cfg 同一口径)。
* 命名带 s_sntp_ 前缀:net_cfg.c 与本文件会在同一 TU 里被主机单测并入
* (test/host/net_cfg),裸 s_cfg/s_defaults 会同名重定义 */
static sntp_cfg_t s_sntp_cfg = {
* 不依赖 cfg_file_load 是否成功(与 net_cfg s_cfg 同一口径) */
static sntp_cfg_t s_cfg = {
.enable = SNTP_CFG_DEF_ENABLE,
.server_pri = SNTP_CFG_DEF_SERVER,
.server_bak = SNTP_CFG_DEF_SERVER,
.poll_min = SNTP_CFG_DEF_POLL_MIN,
};
/* 工厂默认(引擎注册 p_defaults 指向;与 s_sntp_cfg 初值共用宏单一来源) */
static const sntp_cfg_t s_sntp_defaults = {
/* 工厂默认(引擎注册 p_defaults 指向;与 s_cfg 初值共用宏单一来源) */
static const sntp_cfg_t s_defaults = {
.enable = SNTP_CFG_DEF_ENABLE,
.server_pri = SNTP_CFG_DEF_SERVER,
.server_bak = SNTP_CFG_DEF_SERVER,
.poll_min = SNTP_CFG_DEF_POLL_MIN,
};
/* [sntp] 段键表(sntp_cfg_t 布局内偏移) */
static const cfg_key_def_t s_sntp_keys[] = {
{ "enable", CFG_VAL_UINT, offsetof(sntp_cfg_t, enable), 1u },
{ "server1", CFG_VAL_IP4, offsetof(sntp_cfg_t, server_pri), 4u },
{ "server2", CFG_VAL_IP4, offsetof(sntp_cfg_t, server_bak), 4u },
{ "poll_min", CFG_VAL_UINT, offsetof(sntp_cfg_t, poll_min), 2u },
};
/* 函数定义区 */
/*
* 函数功能:取 [sntp] 段 RAM 副本(引擎注册专用写入口)
* 函数功能:向 cfg_file 引擎注册 [sntp] 段(幂等)
* 入口参数:无
* 返回值:RAM 配置副本指针(恒非空) sntp_cfg_t *
* 限定条件:仅 net_cfg.c 组段描述符用;业务读走 sntp_cfg_get(),
* UI 编辑走 sntp_cfg_set()
* 返回值:无
* 限定条件:load/save 前调用(net_cfg_load 内统一编排)
* 函数说明:段数据 = s_cfg RAM 副本;工厂默认 = s_defaults;无变更回调——
* SNTP 客户端每轮直接读 RAM 副本,配置保存后的"立即生效"由
* 既有 SYS_EVT_NET_RECONFIG(网络重建 → 代次变化 → 客户端重开
* Socket)自然达成,无需本模块单独挂接
*/
sntp_cfg_t *sntp_cfg_data(void) {
return &s_sntp_cfg;
}
void sntp_cfg_register(void) {
static uint8_t s_done;
cfg_section_reg_t reg;
/*
* 函数功能:取工厂默认值(引擎注册 p_defaults 指向)
* 入口参数:无
* 返回值:工厂默认结构指针(只读,恒非空) const sntp_cfg_t *
* 限定条件:仅 net_cfg.c 组段描述符用
*/
const sntp_cfg_t *sntp_cfg_defaults(void) {
return &s_sntp_defaults;
if (s_done != 0u) {
return;
}
(void)memset(&reg, 0, sizeof(reg));
reg.name = "sntp";
reg.p_data = &s_cfg;
reg.p_defaults = &s_defaults;
reg.data_size = sizeof(sntp_cfg_t);
reg.p_keys = s_sntp_keys;
reg.key_count = 4u;
reg.p_cb = NULL;
(void)cfg_file_register(&reg);
s_done = 1u;
}
/*
@@ -71,7 +84,7 @@ const sntp_cfg_t *sntp_cfg_defaults(void) {
* 限定条件:无
*/
const sntp_cfg_t *sntp_cfg_get(void) {
return &s_sntp_cfg;
return &s_cfg;
}
/*
@@ -83,7 +96,7 @@ const sntp_cfg_t *sntp_cfg_get(void) {
*/
void sntp_cfg_set(const sntp_cfg_t *p_new) {
if (p_new != NULL) {
(void)memcpy(&s_sntp_cfg, p_new, sizeof(s_sntp_cfg));
(void)memcpy(&s_cfg, p_new, sizeof(s_cfg));
}
}
@@ -94,7 +107,7 @@ void sntp_cfg_set(const sntp_cfg_t *p_new) {
* 限定条件:无
*/
uint16_t sntp_cfg_poll_min(void) {
uint16_t v = s_sntp_cfg.poll_min;
uint16_t v = s_cfg.poll_min;
if ((v < SNTP_CFG_POLL_MIN_MIN) || (v > SNTP_CFG_POLL_MIN_MAX)) {
return SNTP_CFG_DEF_POLL_MIN;
+8 -22
View File
@@ -1,18 +1,14 @@
/*
* 模块名称:SNTP 配置([sntp] 段)
* 模块功能:板端 SNTP 客户端配置——RAM 副本 + 工厂默认 + 读写出口
* ([sntp] 段:enable / server1 / server2 / poll_min);段描述符
* 由 net_cfg.c 在 net_cfg_load 里组好交引擎(分层门禁 layer-deps:
* 本模块不 include 引擎头);消费者(App/sync/time_sntp.c)与 UI 页
* 经 sntp_cfg_get() 只读访问,配置引擎属主仍为 defaultTask
* 模块功能:板端 SNTP 客户端配置——RAM 副本 + 工厂默认 + cfg_file 引擎注册
* ([sntp] 段:enable / server1 / server2 / poll_min);消费者
* (App/sync/time_sntp.c)与 UI 页经 sntp_cfg_get() 只读访问,
* 配置引擎属主仍为 defaultTask
* 适用平台:STM32F407ZGTx / PC 模拟器(两端共用)
* 作者:王建锋
* 创建日期:2026-11-04
* 修改记录:
* v1.0 2026-11-04 王建锋 创建初始版本(SNTP 客户端接入,#57 调研结论)
* v1.1 2026-11-04 王建锋 分层门禁口径:sntp_cfg_register 改为
* sntp_cfg_data/sntp_cfg_defaults 数据口,
* 段描述符编排移 net_cfg.c(本模块不再依赖引擎头)
*/
#ifndef SNTP_CFG_H
@@ -43,22 +39,12 @@ typedef struct {
} sntp_cfg_t;
/*
* 函数功能:取 [sntp] 段 RAM 副本(引擎注册专用写入口)
* 函数功能:向 cfg_file 引擎注册 [sntp] 段(幂等)
* 入口参数:无
* 返回值:RAM 配置副本指针(恒非空,静态常驻) sntp_cfg_t *
* 限定条件:仅供 net_cfg.c 组 [sntp] 段描述符交配置引擎(net_cfg_load 编排);
* 分层门禁 layer-deps:本模块不 include cfg_file.h,段注册集中在
* net_cfg.c(同层基线文件)完成
* 返回值:无
* 限定条件:cfg_file_load 之前调用(net_cfg_load 内统一编排)
*/
sntp_cfg_t *sntp_cfg_data(void);
/*
* 函数功能:取工厂默认值(引擎注册 p_defaults 指向)
* 入口参数:无
* 返回值:工厂默认结构指针(只读,恒非空) const sntp_cfg_t *
* 限定条件:同上,net_cfg.c 组段描述符专用
*/
const sntp_cfg_t *sntp_cfg_defaults(void);
void sntp_cfg_register(void);
/*
* 函数功能:取 [sntp] 段 RAM 副本(只读)
Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.2 KiB

@@ -47,10 +47,10 @@ dhara 失败类 +84;RO 另 +208,全是该失败类名表)→ `ER_IROM1`
<!-- MEM_SNAPSHOT:BEGIN generated by scripts/check_mem_numbers.py -->
| 区域 | 用量 | 容量 | 占比 |
|---|---|---|---|
| ER_IROM1 | 284,800 B (278.12 KB) | 1,048,576 B (1024 KB) | 27.2% |
| RW_IRAM1 | 94,736 B (92.52 KB) | 131,072 B (128 KB) | 72.3% |
| ER_IROM1 | 284,804 B (278.13 KB) | 1,048,576 B (1024 KB) | 27.2% |
| RW_IRAM1 | 94,744 B (92.52 KB) | 131,072 B (128 KB) | 72.3% |
| RW_CCM | 57,376 B (56.03 KB) | 65,280 B (64 KB) | 87.9% |
| **Flash (ROM 合计)** | **286,872 B (280.1 KB)** | 1,048,576 B (1024 KB) | **27.4%** |
| **Flash (ROM 合计)** | **286,884 B (280.2 KB)** | 1,048,576 B (1024 KB) | **27.4%** |
<!-- MEM_SNAPSHOT:END -->
各区的容量与常量来源:
+3 -3
View File
@@ -15,10 +15,10 @@
<!-- MEM_BUDGET:BEGIN generated by scripts/ram_baseline.py -->
| 区域 | 用量 | 容量 | 占比 | 门禁(≤92%) |
|---|---|---|---|---|
| ER_IROM1 (Flash) | 284,800 B | 1,048,576 B | 27.2% | 参考 |
| ER_IROM1 (Flash) | 284,804 B | 1,048,576 B | 27.2% | 参考 |
| RW_CCM | 57,376 B | 65,280 B | 87.9% | PASS |
| UNINIT_CCM | 48 B | 256 B | 18.8% | 参考 |
| RW_IRAM1 | 94,736 B | 131,072 B | 72.3% | PASS |
| RW_IRAM1 | 94,744 B | 131,072 B | 72.3% | PASS |
| 子系统(静态 RW+ZI;除 RTOS 堆在 CCM 外均在 SRAM1) | 现值 | 配额 | 状态 |
|---|---|---|---|
@@ -27,7 +27,7 @@
| UI | 36,475 B | 16 KB | ⚠ 超 19.6 KB |
| RTOS 堆 | 57,376 B | 56 KB | 堆=配额 |
| 应用 | 26,433 B | 8 KB | ⚠ 超 17.8 KB |
| 其它 | 10,792 B | — | 参考 |
| 其它 | 10,794 B | — | 参考 |
<!-- MEM_BUDGET:END -->
- **门禁**:pre-commit `mem-budget` 钩子(`scripts/ram_baseline.py --gate`)——
+3 -4
View File
@@ -200,10 +200,9 @@ write=1
### 3.7 `[sntp]` 段:SNTP 校时参数(2026-11-04 新增,板端 SNTP 客户端接入,#57 调研结论)
板端 SNTP 客户端的持久载体(消费方 = `App/sync/time_sntp.c`,挂在 timeSyncTask
既有循环上,48 字节报文走 PR #74 后的 UDP socket 通道;数据本体 =
`Drivers/BSP/NETCFG/sntp_cfg.h/.c`(纯段数据 + 读写出口,不依赖引擎头——分层门禁
layer-deps 口径),段描述符由 `net_cfg.c` 的 `s_sntp_register()` 组装,注册编排 =
`net_cfg_load()` 统一调用——与 [ftp] 同路径,「先注册后 load」成立):
既有循环上,48 字节报文走 PR #74 后的 UDP socket 通道;段属主 =
`Drivers/BSP/NETCFG/sntp_cfg.h/.c`,注册 = `net_cfg_load()` 内 `sntp_cfg_register()`
统一编排——与 [ftp] 同路径,「先注册后 load」成立):
| 键 | 含义 | 工厂默认 | getter 合法带(带外自愈回默认) |
|---|---|---|---|
@@ -590,4 +590,4 @@ void adc_cfg_init(void)
| 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 同步 |
| 2026-10-26 | v1.15:**新增 `[comm]` 段(道G task-8,「UI 补齐」波次里的非 UI 前置项)**——`App/protocol/iec104/iec104_comm.h/.c` 配对模块(104 公共地址 / 监听端口 2 键,getter 合法带自愈,adc_cal 先例);内核前 `iec104_comm_init()` 注册([adc_cal] / [run_par] 同「先注册后 load」契约);生效 = **改后重启**(不挂回调、不新增事件位,区别于 [network] 免重启重建);段占位 5→6 / 8,键表与主站地址不做理由 → `docs/子系统设计/网络配置说明.md` §3.6;机器钉 = `test/host/cfg_file` TC-CONFIG-056/057(段/键上限)+ `test/host/iec104` TC-IEC104-031~033(模板/重载/带外/ca 端到端)
| 2026-11-04 | v1.16:**新增 `[sntp]` 段(板端 SNTP 客户端接入,#57 调研结论落地)**——`Drivers/BSP/NETCFG/sntp_cfg.h/.c`(enable / server1 / server2 / poll_min 4 键;出厂默认**关闭 + 服务器留空 + 60 分钟** = "未配置零网络足迹"口径;`poll_min` 带外自愈 1..1440 → 60 不写回 RAM);数据本体 = `Drivers/BSP/NETCFG/sntp_cfg.h/.c`(不依赖引擎头,分层门禁 layer-deps 口径),段描述符由 `net_cfg.c` 的 `s_sntp_register()` 组装,注册编排 = `net_cfg_load()`(与 [ftp] 同编排,先注册后 load);消费方 = `App/sync/time_sntp.c`(挂 timeSyncTask 既有循环,vendor `Lib/coreSNTP` serializer 做 48B 报文编解码/防欺骗校验);保存立即生效 = 每轮直读 RAM 副本 + 网络代次重建弃 UDP socket 重散布,**无段回调、不新增事件位**;段占位 6→7 / 8;键表与生效细则 → `docs/子系统设计/网络配置说明.md` §3.7;机器钉 = `test/host/net_cfg` TC-NETCFG-005/006b..d/007(段注册契约)+ `test/host/sntp`(RFC 4330 §10 节奏 / §5.3 防欺骗 / §5.5 步进策略 / poll 钳位)
| 2026-11-04 | v1.16:**新增 `[sntp]` 段(板端 SNTP 客户端接入,#57 调研结论落地)**——`Drivers/BSP/NETCFG/sntp_cfg.h/.c`(enable / server1 / server2 / poll_min 4 键;出厂默认**关闭 + 服务器留空 + 60 分钟** = "未配置零网络足迹"口径;`poll_min` 带外自愈 1..1440 → 60 不写回 RAM);注册 = `net_cfg_load()` 内 `sntp_cfg_register()`(与 [ftp] 同编排,先注册后 load);消费方 = `App/sync/time_sntp.c`(挂 timeSyncTask 既有循环,vendor `Lib/coreSNTP` serializer 做 48B 报文编解码/防欺骗校验);保存立即生效 = 每轮直读 RAM 副本 + 网络代次重建弃 UDP socket 重散布,**无段回调、不新增事件位**;段占位 6→7 / 8;键表与生效细则 → `docs/子系统设计/网络配置说明.md` §3.7;机器钉 = `test/host/sntp`(RFC 4330 §10 节奏 / §5.3 防欺骗 / §5.5 步进策略 / 段注册契约)
+1 -1
View File
@@ -16,4 +16,4 @@ date code ro rw zi er_irom1 er_pct iram1 iram1_pct ccm ccm_pct top_rwzi
2026-10-30 246720 29836 2052 149708 276556 26.4 94336 72.0 57376 87.9 heap_4.o=57376;lv_mem_core_builtin.o=16384;lftpd.o=7884;ui_net_sink.o=6770;ui_port.o=6432;nand_ftl.o=6216;wave_ring.o=5296;sb_link.o=4376;ch395f.o=4162;console_log.o=4132
2026-11-02 247548 29836 2052 149740 277384 26.5 94368 72.0 57376 87.9 heap_4.o=57376;lv_mem_core_builtin.o=16384;lftpd.o=7884;ui_net_sink.o=6802;ui_port.o=6432;nand_ftl.o=6216;wave_ring.o=5296;sb_link.o=4376;ch395f.o=4162;console_log.o=4132
2026-11-03 249112 29836 2052 149996 278948 26.6 94624 72.2 57376 87.9 heap_4.o=57376;lv_mem_core_builtin.o=16384;lftpd.o=7884;ui_net_sink.o=6802;ui_port.o=6432;nand_ftl.o=6216;wave_ring.o=5296;sb_link.o=4376;ch395f.o=4162;console_log.o=4132
2026-11-04 254648 30152 2072 150088 284800 27.2 94736 72.3 57376 87.9 heap_4.o=57376;lv_mem_core_builtin.o=16384;lftpd.o=7884;ui_net_sink.o=6802;ui_port.o=6432;nand_ftl.o=6216;wave_ring.o=5296;sb_link.o=4376;ch395f.o=4162;console_log.o=4132
2026-11-04 254652 30152 2080 150088 284804 27.2 94744 72.3 57376 87.9 heap_4.o=57376;lv_mem_core_builtin.o=16384;lftpd.o=7884;ui_net_sink.o=6802;ui_port.o=6432;nand_ftl.o=6216;wave_ring.o=5296;sb_link.o=4376;ch395f.o=4162;console_log.o=4132
1 date code ro rw zi er_irom1 er_pct iram1 iram1_pct ccm ccm_pct top_rwzi
16 2026-10-30 246720 29836 2052 149708 276556 26.4 94336 72.0 57376 87.9 heap_4.o=57376;lv_mem_core_builtin.o=16384;lftpd.o=7884;ui_net_sink.o=6770;ui_port.o=6432;nand_ftl.o=6216;wave_ring.o=5296;sb_link.o=4376;ch395f.o=4162;console_log.o=4132
17 2026-11-02 247548 29836 2052 149740 277384 26.5 94368 72.0 57376 87.9 heap_4.o=57376;lv_mem_core_builtin.o=16384;lftpd.o=7884;ui_net_sink.o=6802;ui_port.o=6432;nand_ftl.o=6216;wave_ring.o=5296;sb_link.o=4376;ch395f.o=4162;console_log.o=4132
18 2026-11-03 249112 29836 2052 149996 278948 26.6 94624 72.2 57376 87.9 heap_4.o=57376;lv_mem_core_builtin.o=16384;lftpd.o=7884;ui_net_sink.o=6802;ui_port.o=6432;nand_ftl.o=6216;wave_ring.o=5296;sb_link.o=4376;ch395f.o=4162;console_log.o=4132
19 2026-11-04 254648 254652 30152 2072 2080 150088 284800 284804 27.2 94736 94744 72.3 57376 87.9 heap_4.o=57376;lv_mem_core_builtin.o=16384;lftpd.o=7884;ui_net_sink.o=6802;ui_port.o=6432;nand_ftl.o=6216;wave_ring.o=5296;sb_link.o=4376;ch395f.o=4162;console_log.o=4132
+8 -8
View File
@@ -1,15 +1,15 @@
{
"built_at": "2026-11-04T16:02:00+08:00",
"fingerprint": "d7469ca87322ba5a9203a63da8aa530267d2bb7fee259cbf70b804bb09adaf5f",
"built_at": "2026-11-04T15:27:25+08:00",
"fingerprint": "e751bf9d9e5b2e351e0114011e1c7dea0330dc93f487da36cc20141b349b5395",
"fingerprint_files": 1479,
"fingerprint_source": "git-index",
"gated_regions": [
"RW_IRAM1",
"RW_CCM"
],
"git_head": "c2dd6f34c0ab7217071c19b7e930d0435a376fbf",
"git_head": "c1beec50e7d29734a253430c003e9c498f7448e3",
"map": "MDK-ARM/STM32F407-Demo/STM32F407-Demo.map",
"map_mtime": 1793778916,
"map_mtime": 1793777236,
"pct": {
"ER_IROM1": 27.16,
"RW_CCM": 87.89,
@@ -19,7 +19,7 @@
"regions": {
"ER_IROM1": {
"max": 1048576,
"size": 284800
"size": 284804
},
"RW_CCM": {
"max": 65280,
@@ -27,7 +27,7 @@
},
"RW_IRAM1": {
"max": 131072,
"size": 94736
"size": 94744
},
"UNINIT_CCM": {
"max": 256,
@@ -37,9 +37,9 @@
"schema": 2,
"scope_note": "\u540c\u7801\u51ed\u8bc1\uff1a\u6307\u7eb9\u8986\u76d6\u56fa\u4ef6\u4f53\u79ef\u76f8\u5173\u6e90\u7801\uff0c\u53e3\u5f84\u89c1\u672c\u811a\u672c docstring",
"sizes": {
"code": 254648,
"code": 254652,
"ro_data": 30152,
"rw_data": 2072,
"rw_data": 2080,
"zi_data": 150088
},
"threshold_pct": 92.0,
+25 -26
View File
@@ -377,20 +377,20 @@
"lines_valid": 36
},
"Drivers/BSP/NETCFG/net_cfg.c": {
"func_rate": 0.9412,
"funcs_covered": 16,
"funcs_valid": 17,
"line_rate": 0.9685,
"lines_covered": 123,
"lines_valid": 127
"func_rate": 0.9375,
"funcs_covered": 15,
"funcs_valid": 16,
"line_rate": 0.9646,
"lines_covered": 109,
"lines_valid": 113
},
"Drivers/BSP/NETCFG/sntp_cfg.c": {
"func_rate": 1.0,
"funcs_covered": 5,
"funcs_valid": 5,
"line_rate": 0.9474,
"lines_covered": 18,
"lines_valid": 19
"func_rate": 0.75,
"funcs_covered": 3,
"funcs_valid": 4,
"line_rate": 0.8519,
"lines_covered": 23,
"lines_valid": 27
},
"Drivers/BSP/ScreenLink/sb_link.c": {
"func_rate": 1.0,
@@ -576,10 +576,9 @@
},
"net_cfg": {
"files": {
"Drivers/BSP/NETCFG/net_cfg.c": 127,
"Drivers/BSP/NETCFG/sntp_cfg.c": 19
"Drivers/BSP/NETCFG/net_cfg.c": 113
},
"lines_total": 146,
"lines_total": 113,
"ok": true
},
"net_events": {
@@ -705,9 +704,9 @@
"sntp": {
"files": {
"App/sync/time_sntp.c": 248,
"Drivers/BSP/NETCFG/sntp_cfg.c": 19
"Drivers/BSP/NETCFG/sntp_cfg.c": 27
},
"lines_total": 267,
"lines_total": 275,
"ok": true
},
"soe": {
@@ -876,12 +875,12 @@
"files_generated_excluded": 5,
"files_tested": 54,
"files_untested": 177,
"func_rate": 0.9292,
"funcs_covered": 643,
"funcs_valid": 692,
"line_rate": 0.9018,
"lines_covered": 8633,
"lines_valid": 9573,
"func_rate": 0.9275,
"funcs_covered": 640,
"funcs_valid": 690,
"line_rate": 0.9014,
"lines_covered": 8624,
"lines_valid": 9567,
"modules_ok": 48,
"modules_total": 48
},
@@ -1252,11 +1251,11 @@
},
{
"code_lines": 25,
"path": "Drivers/BSP/NETCFG/sntp_cfg.h"
"path": "Drivers/BSP/bsp_err.h"
},
{
"code_lines": 25,
"path": "Drivers/BSP/bsp_err.h"
"code_lines": 24,
"path": "Drivers/BSP/NETCFG/sntp_cfg.h"
},
{
"code_lines": 24,
+21 -43
View File
@@ -16,11 +16,6 @@
* 口令判定归 test/host/ftp_cfg/ 模块,两边不重复也不互相顶包。
* (不能把 ftp_cfg.c 也 include 进来:两个 .c 都有 static s_cfg,
* 同一个 TU 里直接重定义。)
* - [sntp] 段:描述符由 net_cfg.c 的 s_sntp_register() 组装(分层
* 门禁后 sntp_cfg.c 不再自注册),所以本测试直接**编译真实的
* sntp_cfg.c 数据本体**(纯 stdint/string,无引擎依赖,改名后的
* s_sntp_cfg 与 net_cfg.c 的 s_cfg 不再同名冲突),并用假引擎
* 截获注册内容——段键表/偏移/默认值的机器钉在这里打。
* ⚠ 引擎的解析/写盘/沉降契约已由 test/host/cfg_file/(103 条)覆盖,
* 本模块刻意不重测引擎,只测 net_cfg.c 这一层的编排与交接。
*
@@ -42,10 +37,8 @@
* TC-NETCFG-003 未 load 时 gw = 192.168.31.1
* TC-NETCFG-004 未 load 时 mac = 全零(哨兵 = 不覆盖芯片内置 MAC)
* —— 注册与 load(TC-NETCFG-005..011)——
* TC-NETCFG-005 首次 load 注册 [network]+[sntp] 各恰好一次(且 load 返回 0)
* TC-NETCFG-005 首次 load 注册 [network] 段恰好一次(且 load 返回 0)
* TC-NETCFG-006 首次 load 一并注册 [ftp] 段(FTP 鉴权:所有受管段先注册、后 load)
* TC-NETCFG-006b [sntp] 描述符内容:段名/键表(enable/server1/server2/poll_min
* 偏移 0/1/5/10 长 1/4/4/2)/默认值(关 + 60 分钟)/无变更回调
* TC-NETCFG-007 重复 load 不重复注册(幂等;否则引擎按"段名重复"拒登 → 静默失配)
* TC-NETCFG-008 注册描述符内容:段名/尺寸/键数/默认值指针/变更回调/数据指针 = RAM 副本
* TC-NETCFG-009 load 成功:返回 0 且留一条 INFO、不误报 ERROR
@@ -107,10 +100,8 @@
/* 真实引擎头(接口原汁)+ 被测生产源(原样纳入);dbg_log.h 命中本目录 stub */
#include "cfg_file.h"
#include "net_cfg.h"
#include "sntp_cfg.h"
#include "net_cfg.c"
#include "sntp_cfg.c"
/* ===================== 断言框架 ===================== */
@@ -146,13 +137,14 @@ typedef struct {
const void *p_defaults;
size_t data_size;
uint8_t key_count;
const cfg_key_def_t *p_keys; /* 键表是生产文件里的 static const,指针长期有效,不必深拷贝 */
void (*p_cb)(void);
} fake_reg_t;
static fake_reg_t g_regs[CFG_FILE_MAX_SECTIONS];
static int g_reg_n;
static int g_ftp_reg_calls; /* ftp_cfg_register 被 net_cfg_load 调了几次 */
static int g_sntp_reg_calls; /* sntp_cfg_register 同上 */
static int g_sntp_reg_before_load; /* 其中发生在 cfg_file_load 之前的次数(先注册后 load 契约) */
static int g_load_calls;
static int g_save_calls;
static int g_apply_calls;
@@ -189,7 +181,6 @@ int cfg_file_register(const cfg_section_reg_t *p_reg)
rec->p_defaults = p_reg->p_defaults;
rec->data_size = p_reg->data_size;
rec->key_count = p_reg->key_count;
rec->p_keys = p_reg->p_keys;
rec->p_cb = p_reg->p_cb;
g_reg_n++;
return 0;
@@ -216,10 +207,21 @@ void ftp_cfg_register(void)
g_ftp_reg_calls++;
}
/* [sntp] 段归 test/host/sntp/ 模块测;同 ftp 口径:只计数 + 先注册后 load 序 */
void sntp_cfg_register(void)
{
g_sntp_reg_calls++;
if (g_load_calls == 0) {
g_sntp_reg_before_load++;
}
}
static void fake_reset(void)
{
g_reg_n = 0;
g_ftp_reg_calls = 0;
g_sntp_reg_calls = 0;
g_sntp_reg_before_load = 0;
g_load_calls = 0;
g_save_calls = 0;
g_apply_calls = 0;
@@ -289,41 +291,17 @@ static void tc_register_load(void)
printf("-- TC-NETCFG-005..011 register + load --\n");
fake_reset();
rc = net_cfg_load();
CHECK((rc == 0) && (g_reg_n == 2) && (strcmp(g_regs[0].name, "network") == 0),
"TC-NETCFG-005 first load registers [network] + [sntp] exactly once each");
CHECK((rc == 0) && (g_reg_n == 1) && (strcmp(g_regs[0].name, "network") == 0),
"TC-NETCFG-005 first load registers [network] exactly once");
CHECK((g_ftp_reg_calls == 1) && (g_load_calls == 1),
"TC-NETCFG-006 also registers [ftp], registered before load");
{
const fake_reg_t *rs = (g_reg_n == 2) ? &g_regs[1] : NULL;
const sntp_cfg_t *d = (const sntp_cfg_t *)(rs != NULL ? rs->p_defaults : NULL);
int keys_ok = (rs != NULL) && (rs->key_count == 4u) && (rs->p_keys != NULL);
CHECK((rs != NULL) && (strcmp(rs->name, "sntp") == 0) && keys_ok &&
(rs->data_size == sizeof(sntp_cfg_t)) &&
(rs->p_data == (const void *)sntp_cfg_data()) &&
(rs->p_cb == NULL),
"TC-NETCFG-006b [sntp] descriptor: name/4 keys/size/RAM copy/no cb");
CHECK(keys_ok &&
(strcmp(rs->p_keys[0].name, "enable") == 0) &&
(rs->p_keys[0].type == CFG_VAL_UINT) &&
(rs->p_keys[0].offset == 0u) && (rs->p_keys[0].len == 1u) &&
(strcmp(rs->p_keys[1].name, "server1") == 0) &&
(rs->p_keys[1].type == CFG_VAL_IP4) &&
(rs->p_keys[1].offset == 1u) && (rs->p_keys[1].len == 4u) &&
(strcmp(rs->p_keys[2].name, "server2") == 0) &&
(rs->p_keys[2].type == CFG_VAL_IP4) &&
(rs->p_keys[2].offset == 5u) && (rs->p_keys[2].len == 4u) &&
(strcmp(rs->p_keys[3].name, "poll_min") == 0) &&
(rs->p_keys[3].type == CFG_VAL_UINT) &&
(rs->p_keys[3].offset == 10u) && (rs->p_keys[3].len == 2u),
"TC-NETCFG-006c [sntp] key table: enable/server1/server2/poll_min at 0/1/5/10");
CHECK((d != NULL) && (d->enable == 0u) && (d->poll_min == 60u) &&
(d->server_pri[0] == 0u) && (d->server_bak[0] == 0u),
"TC-NETCFG-006d [sntp] factory defaults: off + empty servers + 60 min");
}
CHECK((g_sntp_reg_calls == 1) && (g_sntp_reg_before_load == 1),
"TC-NETCFG-006b also registers [sntp], registered before load");
rc = net_cfg_load();
CHECK((rc == 0) && (g_reg_n == 2) && (g_ftp_reg_calls == 2),
"TC-NETCFG-007 repeated load does not re-register [network]/[sntp]");
CHECK((rc == 0) && (g_reg_n == 1) && (g_ftp_reg_calls == 2) &&
(g_sntp_reg_calls == 2),
"TC-NETCFG-007 repeated load does not re-register [network]");
CHECK((strcmp(g_regs[0].name, "network") == 0) &&
(g_regs[0].data_size == sizeof(net_cfg_t)) &&
-3
View File
@@ -21,9 +21,6 @@
桩的边界(细节见测试单元文件头):
配置文件引擎用**真实头**(接口原汁)+ 测试单元内的可控实现;[ftp] 段的
ftp_cfg_register 只计数——它归 test/host/ftp_cfg/ 模块,两边不互相顶包。
sntp_cfg.c 是分层门禁后的纯数据本体,随 net_cfg.c 一并编译入 TU,
[sntp] 段描述符(键表/偏移/工厂默认)由假引擎截获断言——段注册契约
的机器钉在本模块(TC-NETCFG-005/006b..d/007)。
用法(仓库根目录):
python test/host/net_cfg/run_unit_test.py
+55 -13
View File
@@ -6,9 +6,7 @@
* RFC 4330 §10 节奏(初始散布/失败翻倍封顶/成功重排)、§5.3 防欺骗
* (源 IP:port / originate 精确匹配 / mode / LI=3 / stratum / KoD)、
* §5.5 步进策略(±2s 死区、冷启动直采 T3、时区面 +28800)、
* poll 钳位与 set 入口、代次/停用收口。
* ([sntp] 段描述符注册断言在 test/host/net_cfg——分层门禁后
* 描述符由 net_cfg.c 组装,本套件只并 sntp_cfg.c 数据本体。)
* [sntp] 配置注册与 poll 钳位、代次/停用收口。
* 约束:生产 .c 以 #include 方式并入——static 白盒可达;fake 计数前缀唯一,
* 避免同名 tentative static 静默合并(2026-10-10 教训)。
*/
@@ -25,6 +23,7 @@
#include "sys_clock.h"
#include "sys_events.h"
#include "sys_log.h"
#include "cfg_file.h"
#include "dbg_log.h"
/* ---- fake 存储(stub/dbg_log.h 已声明 g_dbg_*_count extern,此处落定义) ---- */
@@ -79,8 +78,12 @@ static struct sntp_t_recv g_recv_q[SNTP_T_NET_RECV_MAX];
static int g_recv_head, g_recv_tail;
static uint32_t g_recv_last_timeout_ms; /* 最近一次 recv 的片超时(50ms 断言) */
/* ---- cfg fake:[sntp] 段描述符组装已移 net_cfg.c(分层门禁),注册内容
* 断言归 test/host/net_cfg;本套件只需 sntp_cfg.c 数据本体可用,无引擎调用 ---- */
/* ---- cfg fake:只截获注册描述符(真实引擎注册时深拷贝,fake 同构复刻——
* 只存指针会悬空:net_cfg/sntp_cfg 都传栈上临时 reg,首轮 AV 教训) ---- */
static cfg_section_reg_t g_cfg_reg_store;
static cfg_key_def_t g_cfg_keys[16];
static const cfg_section_reg_t *g_cfg_reg;
static int g_cfg_reg_calls;
/* ---- dbg 宏(stub/dbg_log.h 已声明 g_dbg_*,此处无需再定义宏) ---- */
@@ -245,6 +248,23 @@ uint32_t net_get_generation(void)
return g_gen;
}
/* ---- cfg_file fake ---- */
int cfg_file_register(const cfg_section_reg_t *reg)
{
if (reg == NULL || reg->key_count > 16u) {
return -1;
}
g_cfg_reg_store = *reg;
if (reg->p_keys != NULL) {
memcpy(g_cfg_keys, reg->p_keys,
sizeof(cfg_key_def_t) * (size_t)reg->key_count);
g_cfg_reg_store.p_keys = g_cfg_keys;
}
g_cfg_reg = &g_cfg_reg_store;
g_cfg_reg_calls++;
return 0;
}
/* ---- 生产代码并入(顺序:vendor → 配置 → 客户端) ---- */
#include "core_sntp_serializer.c"
#include "sntp_cfg.c"
@@ -265,6 +285,7 @@ static void s_case_reset(void)
sntp_cfg_t *c;
/* 配置先归零,再借代次跳变走"生产复位通道"(关 socket + 状态回 IDLE) */
sntp_cfg_register();
c = (sntp_cfg_t *)(void *)sntp_cfg_get();
c->enable = 0u;
memset(c->server_pri, 0, 4);
@@ -351,13 +372,38 @@ static void s_feed(const uint8_t *resp, int len, const uint8_t *src_ip,
/* ============================ 测试用例 ============================ */
static void tc_poll_clamp(void)
static void tc_cfg_register(void)
{
const cfg_section_reg_t *r;
sntp_cfg_t *c;
/* [sntp] 段描述符/键表/默认值的注册断言在 test/host/net_cfg(描述符
已改由 net_cfg.c 组装);这里只钉客户端实际消费的 poll 钳位口 */
s_case_reset();
/* 全局快照进局部再判空:g_cfg_reg 会被 s_case_reset 清零,cppcheck 不认
「上一行刚判过」的全局解引用(nullPointerRedundantCheck),快照写法消警 */
r = g_cfg_reg;
CHECK(r != NULL && strcmp(r->name, "sntp") == 0, "cfg: name=sntp");
if (r != NULL) {
const cfg_key_def_t *k = r->p_keys;
CHECK(r->key_count == 4u, "cfg: 4 keys");
CHECK(r->data_size == sizeof(sntp_cfg_t), "cfg: data_size");
CHECK(strcmp(k[0].name, "enable") == 0 && k[0].type == CFG_VAL_UINT &&
k[0].offset == 0u && k[0].len == 1u, "cfg: enable");
CHECK(strcmp(k[1].name, "server1") == 0 && k[1].type == CFG_VAL_IP4 &&
k[1].offset == 1u && k[1].len == 4u, "cfg: server1");
CHECK(strcmp(k[2].name, "server2") == 0 && k[2].type == CFG_VAL_IP4 &&
k[2].offset == 5u && k[2].len == 4u, "cfg: server2");
CHECK(strcmp(k[3].name, "poll_min") == 0 && k[3].type == CFG_VAL_UINT &&
k[3].offset == 10u && k[3].len == 2u, "cfg: poll_min");
/* 出厂默认:关闭 + 服务器留空 + 60 分钟(调研 §7) */
CHECK(((const sntp_cfg_t *)r->p_defaults)->enable == 0u, "cfg: default off");
CHECK(((const sntp_cfg_t *)r->p_defaults)->poll_min == 60u, "cfg: default 60m");
}
/* 注册幂等 */
g_cfg_reg_calls = 0;
sntp_cfg_register();
sntp_cfg_register();
CHECK(g_cfg_reg_calls == 0, "cfg: idempotent register");
/* poll 钳位(自检愈口,不写回 RAM) */
c = (sntp_cfg_t *)(void *)sntp_cfg_get();
c->poll_min = 0u; CHECK(sntp_cfg_poll_min() == 60u, "cfg: poll 0 -> 60");
c->poll_min = 1441u; CHECK(sntp_cfg_poll_min() == 60u, "cfg: poll 1441 -> 60");
@@ -365,10 +411,6 @@ static void tc_poll_clamp(void)
CHECK(c->poll_min == 0u || c->poll_min == 2u || c->poll_min == 1441u,
"cfg: clamp no writeback");
c->poll_min = 60u;
/* set(NULL) 不改写 + set 整包拷贝(UI 编辑入口的行为钉) */
sntp_cfg_set(NULL);
CHECK(sntp_cfg_poll_min() == 60u, "cfg: set(NULL) no-op");
}
static void tc_disabled_silent(void)
@@ -938,7 +980,7 @@ int main(void)
printf("=== SNTP Client Tests ===\n");
#define TC(fn) do { printf("[" #fn "]\n"); fn(); } while (0)
TC(tc_poll_clamp);
TC(tc_cfg_register);
TC(tc_disabled_silent);
TC(tc_first_send_window);
TC(tc_cold_start_step_t3);