SNTP 设置(不排) #57
Reference in New Issue
Block a user
Delete Branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
当前对时走 8888 私有协议,SNTP 客户端与产品口径均未建立。重开条件:SNTP 客户端立项。
出处:docs/任务规划/登记簿.md §8 第 7 项、docs/任务规划/UI补齐.md §5
来源:docs/任务规划/(2026-11-02 由 super_agent_bot 建档,跟踪 #5)
@super_agent_bot 我已经给我们的板子连上了网络了,SNTP可以考虑开始,我的建议是成熟的方案,就不要重复造轮子。请从网络上调研成熟的方案,那个适合我们当前项目的部署,没有成熟的我们参考别人的设置思想。请给我调研结果
好的:先调研适合我们板子与固件的成熟 SNTP 时间同步方案,给出对比与推荐,不先写代码。
This is by an automated agent, not a human.
SNTP 成熟方案调研(面向本项目部署)
0. 结论(先说答案)
apps/sntp.c与 lwIP 的 UDP/定时器/DNS 深度耦合,而本项目根本没有 lwIP(CH395F 芯片内置 TCP/IP 协议栈,做 socket 卸载)。引入整套 lwIP 与选 CH395F 的立项思路相悖,RAM 代价也远超 92% 内存红线的余量。docs/测试说明/单元测试/主机单测覆盖率口径.md对 UDP 绕过 netTask 的定案),SNTP 立项正好是它的第一个消费者。1. 本项目现状盘点(调研先对齐适配面)
docs/产品需求/产品需求设计文档.md§9.1.2 需求 17「SNTP 对时」:参考产品走 SNTP,现以私有 TCP 8888 + 104C_CS顶替,目标 = SNTP 客户端;docs/任务规划/登记簿.md挂「SNTP 客户端立项」为重启条件App/util/sys_clock.c:SD2506 RTC(温补、电池保持)+ HAL Tick 基准法;时基口径 = 内部一律本地钟面(用户裁定 2026-10-27,docs/子系统设计/系统墙钟时间维护说明.md§1.1),任何来源写入前先换算本地钟面sys_clock_set(unix_secs, &sd_time)/sys_clock_set_unix():一次性更新运行基准并回写 SD2506 掉电保持;文档 §8 明确预留「典型应用:SNTP/NTP 同步得到 Unix 秒数 → …」App/sync/time_sync.c:TCP Server :8888,8 字节"TIME"+epoch,跑在独立timeSyncTask(栈 640 字,等SYS_EVT_NET_READY屏障);TIMESYNC_READY事件位预留无人用net_socket.h:471「不支持域名解析」);UDP 三接口net_bind/net_sendto/net_recvfrom是 netTask 串行契约的「直碰 SPI 三例外」,其中net_sendto/net_recvfrom带 netTask 上下文守卫(非 netTask 调用回NET_ERR_NOT_IN_NETTASK=-12),2026-10-15 定案「本平台暂不使用 UDP」SENDBUF_FREE(TRAP-NET-04)docs/UI设计/页面补齐规划.md建议 3 字段可编辑列表:等 SNTP 客户端立项再接线);配置走/config.ini,网口段已有 UI 保存即生效模式tools/arch_diagram/gen_watchdog_svg.py)一句话:时间落库、任务壳子、UI 占位、事件位、看门狗预算全部就绪,缺的只是「从 NTP 服务器拿 UTC」这 48 字节往返 + 配置模型。
2. 候选方案横向对比(成熟方案清单)
core_sntp_client.c+core_sntp_serializer.c),纯 C90/C99,无任何 OS/网络栈依赖、零堆分配,GCC Cortex-M 实测 -Os 约 2.0 KB Flash;MISRA C:2012 + Coverity + CBMC 内存安全证明;官方长期维护(v1.3.1 随 FreeRTOS 202406 LTS 出货)apps/sntp.c(BSD-3,Simon Goldschmidt 等)sntp_init()→ 回调写 RTC)udp_new/sys_timeouts/dns),剥离 lwIP 移植≈重写;引 lwIP 则与 CH395F 卸载架构冲突且 RAM 代价大。业界自评也注明:无多源择优、无驯服(slew)、非线程安全sntp库3. 推荐方案:coreSNTP 怎么用
coreSNTP 分两层,建议用下层(serializer),上层(managed client)按需:
core_sntp_serializer.h)。不依赖任何平台接口,拿来就编。Sntp_SendTimeRequest / Sntp_ReceiveTimeResponse一整套托管循环(含服务器拒绝/KoD 处理、重试超时推进),但要求实现 5 个平台接口:DNS 解析、UDP 发送、UDP 接收、取系统时间、置系统时间(认证接口可选)。我们无 DNS——接口回固定 IP 即可(一行的事);UDP 接口挂到 net 层改造后的队列 API 上。为什么这不是「半成品轮子」:48 字节报文的组装/解析/校验/边界条件(NTP era 2036 回绕、KOOD、认证字段)是全库最容易写出隐性 bug 的部分,恰好 coreSNTP 用 CBMC 证明过内存安全、经 Coverity 静态分析、由 AWS 开源团队长期维护、代码量小到评审一屏能读完。我们写的只是「搬运工」适配层。
4. 落到本项目的集成设计(供立项评审)
4.1 数据流(复用现有骨架)
4.2 与既有三源的关系
8888(人工推送)、104
C_CS(UTC)、SNTP 三个写入口并存时按 §1.1 裁定执行「任何来源写入前先换算本地钟面」,源间优先级属产品定义,需拍板(§6 待决项,建议:SNTP 在线时以其为准、8888 保留一键纠偏、失败期 RTC 自守)。4.3 硬前置:UDP 通道串行化改造
net_sendto/net_recvfrom现状直碰 SPI、非 netTask 调用被守卫拒绝,且net_recvfrom是轮询自旋实现——不能直接给 timeSyncTask 用(会违反「所有 net_* 经 netTask 串行」的模块契约,自旋还会吃掉喂狗预算)。改造方向仓内文档已有定案:走netMsgQueue、per-task 结果槽(勿给net_msg_t加回传字段,AGENTS 明文禁止,错误码搭任务通知值)。工作量 1~2 天,改完 TC-NETSOCK 主机单测已有 UDP 场景假件(ch395f_fake.h报文头可脚本化),扩展即可。4.4 socket / 内存 / 栈预算
ram_report.py/stack_report.py前后对比即可,预期不触线。4.5 UI 页 31「SNTP设置」与 config.ini
按
docs/UI设计/页面补齐规划.md占位做 3~5 字段(建议):使能 / 服务器 IP / 备用服务器 IP / 轮询周期 / (端口默认 123 可隐藏);存/config.ini新增[sntp]段,沿用网口设置「UI 保存立即生效」模式。字段名与默认值随立项定。5. 别人的「设置思想」——可直接抄的部署参数(RFC 4330 + 工业实践)
这一节即使最终选自研也必须照办,全是成熟实现的共同作业。
5.1 发送节奏(RFC 4330 §5/§10 原文约束)
5.2 轮询周期怎么定(本项目算术版)
最大超时由振子容差 + 精度需求算出:
T_max ≈ 允许误差 ÷ 漂移率(RFC 4330 §10 第 1 步,且不小于 15 分钟)。代入我们 SD2506(温补,文档按 ±20 ppm ≈ ±1.7 s/天):参考产品是「SNTP 对时」档位,建议默认 1 小时(站内私有服务器压力可忽略),可配置。
5.3 响应合法性检查(sanity,防陈旧/伪造包)
RFC 4330 建议全套照抄:① 回包源 IP/端口 = 请求目的互换;② Originate Timestamp 必须等于本端请求的 Transmit Timestamp(T1)——这是防伪关键;③ Mode=4(unicast 应答);④ LI/Stratum/Transmit Timestamp 任一为 0 或 Mode 不对 → 丢弃;⑤ paranoid 档:Root Delay / Root Dispersion ∈ [0, 1 s)。offset/delay 公式:
t = ((T2−T1)+(T3−T4))/2,d = (T4−T1)−(T3−T2)——请求里填 T1 才能算往返补偿并防重放。时间戳换算:NTP 秒自 1900-01-01,减 2208988800 得 Unix 秒(无数实现栽过这 68 年差,代码注释直接写死出处)。5.4 时基与时区(我们项目的特有条款)
NTP 报文只有 UTC。按 §1.1 裁定「内部一律本地钟面、不存时区」,换算 = UTC 秒 + 480 s 常量(中国无夏令时)后走
sys_clock_set_unix(),与 104C_CS现行为同构。UI 上不需要也不应出现时区参数。5.5 步进(step)与日志乱序
SNTP 客户端语义是直接置钟(无 NTP 驯服环)。钟往回跳会让 SOE/七本记录的时标出现回头序——保护装置取证场景敏感。建议抄「阈值步进」做法:小偏移(如 <2 s)只记日志不动钟(漂移反正下次一起纠)、大偏移步进并打
[SNTP] step offset=…留痕;未来若要做无感收敛再加 slew。每次同步成功/失败都进运行日志,掉线期间走 SD2506 守时(漂移预算见 5.2)。5.6 服务器地址现实选项(本项目无 DNS → 全部填 IP)
210.72.145.44(国家授时中心 ntp.ntsc.ac.cn)、ntp.aliyun.com、ntp.tencent.com、0~3.cn.pool.ntp.org的解析 IP;注意这些是域名型服务,IP 会变,验收环境可用、量产配置应指向站内源6. 需要拍板的问题(立项前)
docs/算法/继电保护功能复现规划.md)——需要拿原始点表确认:参考产品到底是标准 SNTP,还是「主站收 NTP 再转发」的私有协议(若是后者,我们 8888 已覆盖,SNTP 需求可能只是「支持对接站内 NTP」)。7. 下一步(若确认推进)
按仓内规矩拆两步走:① UDP 队列化改造(1
2 天 + 主机单测扩展,独立 PR)→ ② SNTP 客户端(coreSNTP 两文件入1.5 天,UI 页与配置迁移各再 0.5 天)。全程Lib/登记 + 适配层 + 单测 + 台架:用网内 PC 跑 chrony 当假服务器,或直连公网验收;1/keil-build+ 台架闭环,不动 8888 现有行为。8. 主要参考
apps/sntp.c(BSD-3,不适用原因存档)— https://pigweed.googlesource.com/third_party/github/STMicroelectronics/stm32_mw_lwip/+/refs/heads/main/src/apps/sntp/sntp.c ;ST 社区标准路线(CubeMX+lwIP+RTC,供对照)— https://qa-community.st.com/topic/show?tid=142013docs/子系统设计/系统墙钟时间维护说明.md(§1.1 时基裁定 / §8 落库 API / §15 8888 协议)、docs/网络/BSD_Socket_API_使用指南.md§6(UDP 现状定案)、docs/测试说明/单元测试/主机单测覆盖率口径.md(UDP 队列化后续项与理由)、docs/产品需求/产品需求设计文档.md§9.1.2 需求 17、docs/算法/继电保护功能复现规划.md(点表 SNTP 5105 条目)SNTP 调研完成,完整中文报告已发在本工单线程:调研结果。结论:主选 coreSNTP(MIT,约 2KB Flash,零堆分配),只需约 200–300 行适配;前置条件是把 UDP 收发队列化(现有 netTask 串行契约的已知待办)。备选了 lwIP/嵌入式开源实现等对比与排除理由都在报告里,未改任何代码。
@super_agent_bot 我们自己的PC可以部署SNTP服务器嘛?
This is by an automated agent, not a human.
可以——而且已经在这台开发 PC 上配好并实测通过。PC 双网卡本来就在台架网段 192.168.31.x:以太网 192.168.31.161 / WLAN 192.168.31.13,板子接哪个口就用哪个地址。
已完成的配置(Windows 内置 W32Time 服务器模式,未装第三方软件)
time.windows.com+ntp.aliyun.com,服务置自动并运行,UDP 123 已监听 0.0.0.0stratum=5、mode=4、偏移 ≈ 0 s ✓配置中踩到一个严格客户端都会踩的坑:默认应答是
LI=3、stratum=0("本钟不可信",KoD 变体)——w32tm自己测不拒收,但按 RFC 4330 的客户端会直接丢弃。修法是把HKLM\SYSTEM\CurrentControlSet\Services\W32Time\Parameters\AnnounceFlags设为 5(权威+可信)后重启服务,之后应答 stratum=5。另拉了 coreSNTP 源码核实:core_sntp_serializer.c校验响应只查mode==4、不查 version 字段(Windows 以 NTPv3 口径回 VN=3)——所以这台 PC 直接可用于板端联调,不必为此换 Meinberg NTP。可在 PC 上复现验证(无需板子)
或任意 SNTP 客户端:发 48 字节包(首字节 0x23 + 47×0x00)到 UDP 123,应回 byte0=0x1C、stratum=5。
两点说明
[sntp]服务器地址换成站内时钟源即可,板端逻辑完全一致。回退方法(想撤销随时可回):
NtpServer\Enabled改回 0、删防火墙规则SNTP Server for bench 192.168.31.0/24、Restart-Service w32time。能,而且不用装第三方软件——已经直接在这台开发 PC 上部署好并实测通过:Windows 内置时间服务开服务器模式,上游走 time.windows.com + ntp.aliyun.com;防火墙 UDP 123 只放行台架网段 192.168.31.0/24,Tailscale 段不暴露。实测两个网卡查询均应答正常(stratum 5、偏移≈0)。板子侧把 SNTP 服务器地址填 192.168.31.161 或 .13 即可用。详细配置、踩坑记录和验证命令都在 #57 评论。