refactor(time_sync)!: 退役 TCP :8888 对时任务,timeSyncTask 转纯 SNTP 校时节拍宿主(#78)
CI / 静态门禁 (pre-commit) (push) Failing after 43s
CI / 主机侧单测 (MSVC) (push) Failing after 45s
CI / 静态门禁 (pre-commit) (pull_request) Failing after 45s
CI / 主机侧单测 (MSVC) (pull_request) Failing after 45s

SNTP 客户端已随 #73/PR #77 上线合入(merge 2b848c4a),用户裁定
8888 对时任务退出历史舞台(gitea:77 线程原话,跟踪 Issue #78)。

生产侧(App/sync/time_sync.c v2.0,任务入口名不变,freertos.c 零改动):
- 删除 :8888 监听、TIME 包重组、sys_clock 写入、OPER 落痕、
  net_drop_conn 队头自救整条链(TIME_SYNC_PORT 宏随退役删除)
- 任务体收敛为:就绪屏障(100ms 分片、osFlagsNoClear)→
  200ms 校时节拍 task_wd_beat → time_sntp_run(net_get_generation())
  → 分片延时;喂狗节奏(TASK_WD_TIMESYNC=5,required_mask)不变
- 时钟写入口自此 = SNTP / UI 手工 / 104 C_CS,双写竞态(后写者赢)
  随之消失(墙钟说明 §15 退役公告、§16 现势口径)

工具与测试:
- 删除 test/host/time_sync_server.py(对时源)与 e02_probe.py
  (队头阻塞探针,载体随监听退役;判据脚本 v5_log_gap_report.py
  保留供旧日志解读)
- time_sync 主机单测重写 v2.0:33 断言覆盖分片延时 / 屏障 /
  SNTP 节拍与网络代次当轮交接 / 未出网守门;stub 的
  net_socket.h 裁剪至 net_get_generation 作编译期绊线
- 覆盖率基线 --update-baseline 收口(time_sync.c 101→20 行为刻意
  缩减,全仓 48/48 套绿)

文档与图:墙钟说明 §15 改退役公告(教训保留:CH395F FIN 丢未读
缓冲)、§16 单一网络来源;产品需求 FR-TIME-2 退役注记、§6.3 重写;
架构总览 / 软件架构规格 / 网络配置 / 网络自愈 §9.3 / BSD 指南 /
看门狗说明心跳与白名单行 / 实机测试指南 / 部署环境 / 继保规划 /
UI补齐时基口径 / 页面补齐规划 SNTP 页行 / 任务规划 README 叶数与
暂缓项行(SNTP 叶已绑、UI_PAGE_MAP_COUNT=31 口径)等约 30 处现势
口径同步;arch / net_stack 两图生成器与 SVG 同笔重跑。

台账:ram_baseline --update + check_mem_numbers --write + 体积凭证
(Code 254,648→253,428,−1,220 B)。静态链复测发现 timeSyncTask
1,904 B / iec104Task 1,600 B 低于 ISR 硬线:master 2b848c4a 同判据
timeSyncTask 即 2,056 B(本 PR 只减不增,−152 B 旧任务自身帧),
双 FAIL 为 #74/#77 后既有债;抬栈属 Ask-first 未擅自执行,登记簿
新增「静态链硬线双 FAIL」待台架复采,复测快照入 docs/内存管理/data。

验证:keil-build 0 错 0 警;time_sync/sntp 主机单测绿;
ci_local 全绿;doc-links --all 0。
This commit is contained in:
2026-11-04 18:07:03 +08:00
parent 2b848c4a0b
commit 3a2f9b21fb
50 changed files with 621 additions and 1567 deletions
-83
View File
@@ -1,83 +0,0 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
本地时间同步服务(PC -> MCU 板子)
功能:
周期性把本机(PC)的本地时间,通过 TCP 推送到 STM32 板子。
板子端在 timeSyncTask 中以 TCP Server 方式监听端口,收到后调用
sys_clock_set_unix() 更新系统墙钟并写回 SD2506 RTC,使板子时间 == 你电脑的时间。
协议(板子端实现见 App/sync/time_sync.c 的 time_sync_handle_conn):
字节 0..3 : 魔术字 "TIME" (0x54 0x49 0x4D 0x45)
字节 4..7 : 本地 Unix 时间戳,uint32,大端(主机字节序转换后由板子分解)
用法:
python time_sync_server.py # 默认推送到设备 IP(bench_defaults.DEVICE_IP):8888
python time_sync_server.py <设备IP> # 指定板子 IP
python time_sync_server.py <设备IP> 9000 3 # 指定端口与间隔(秒)
按 Ctrl+C 停止。
"""
import socket
import struct
import sys
import time
import calendar
import bench_defaults # 台架连接默认值单一真源
DEFAULT_MCU_IP = bench_defaults.DEVICE_IP
DEFAULT_PORT = 8888
DEFAULT_INTERVAL = 5.0
def main():
mcu_ip = sys.argv[1] if len(sys.argv) > 1 else DEFAULT_MCU_IP
port = int(sys.argv[2]) if len(sys.argv) > 2 else DEFAULT_PORT
interval = float(sys.argv[3]) if len(sys.argv) > 3 else DEFAULT_INTERVAL
print("[time_sync] 本地时间推送服务已启动(TCP 客户端)")
print(f" 目标板子 : {mcu_ip}:{port}")
print(f" 推送间隔 : {interval}s")
print(f" 协议帧 : 'TIME' + uint32(BE) 本地 Unix 时间戳")
print("[time_sync] 按 Ctrl+C 停止")
print("-" * 48)
while True:
try:
# 本地 wall-clock 当作 UTC 算出的 epoch(与电脑显示一致)。
# 注意:板子 RTC 存本地时间且 unix_to_sd2506 无时区处理,
# 故必须发"本地墙钟当 UTC"的伪 epoch(calendar.timegm),
# 不能用 time.mktime(返回真正 UTC epoch,会导致板子慢 8 小时)。
local_epoch = int(calendar.timegm(time.localtime()))
pkt = b"TIME" + struct.pack(">I", local_epoch)
with socket.create_connection((mcu_ip, port), timeout=5) as sock:
sock.sendall(pkt)
# 关键:发送后保持连接打开,给板子留出读完 8 字节的窗口。
# 若立即 close,CH395F 收到 FIN 会丢弃接收缓冲里尚未被板子读出的
# 8 字节时间包,导致板子 net_recv 看到 CLOSED 而无数据、时间同步失败。
# 板子会话收尾**不再 close**(单连接监听跨会话常驻,
# EOF 时 net_close 会连监听一起毁掉)——这里 recv 等 2s 宽限后由
# 本端关闭;板子 net 层 auto_relisten 随即恢复监听,下一轮照常连接。
sock.settimeout(2.0)
try:
sock.recv(64)
except (socket.timeout, OSError):
pass
now_str = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
print(f"[{time.strftime('%H:%M:%S')}] -> {now_str} (epoch={local_epoch})")
except OSError as e:
print(f"[{time.strftime('%H:%M:%S')}] 连接/发送失败: {e}")
time.sleep(interval)
if __name__ == "__main__":
try:
main()
except KeyboardInterrupt:
print("\n[time_sync] 已停止")