7efa58d9a1
分两段(用户裁定 2026-11-02):先做地址迁移,再把同类字面量收敛成
单一真源,以后再改地址只动一处。
一、IP 迁移 192.168.1.100 → 192.168.31.100(gw 同步 → .31.1)
- 工厂默认:Drivers/BSP/NETCFG/net_cfg.c 的 NET_CFG_DEF_IP/_GW
- 注释/文档示例、主机与板级测试、台架 py 脚本、两份 sim_config.ini
- 字节序教学点同步换算 hex:0x6401A8C0 → 0x641FA8C0(内存
C0 A8 1F 64),旧版示例引文与历史 Trap 记录按冻结纪律不动
- UI 黄金基准:网口设置 4 态 + shot_info 共 5 张 .bin 由
check_content_pages.py --update 重刷(渲染值 IP 变了,属预期变更)
- 保留判定:客户点表引用(IEC104/继电保护规划)、芯片手册摘录、
日期冻结的变更记录行、已退役台架档案 MDK-ARM/retracted_bench_*
二、单一真源收口(A+B+C+D,用户批准全做)
- 新建 test/host/bench_defaults.py:台架 py 默认值唯一定义点
(DEVICE_IP/DEVICE_GW/PC_IP/NET_BCAST),22 个脚本改为引用;
MDK-ARM 两探针与 scripts/board_ui_nav.py 经 sys.path shim 引入
- test/board/net_test_task.h 新增 TEST_PC_PEER_IP,板测三处
PHASE*_REMOTE_IP 改引该宏(保留 -D 覆盖);Phase1 断言改
memcmp 数组比较,数组各只出现一次
- simulator/tests/check_content_pages.py 从 net_cfg.c 正则解析
NET_CFG_DEF_* 推导期望值(解析失败即报错、不静默兜底),
脚本内台架 IP 字面量清零
- 装饰性注释去具体值(net_cfg.h/net_socket.h/net_socket.c/
net_socket_sim.c);字节序教学 hex 对刻意保留为唯一写值点
- 刻意不动:主机单测夹具 IP(逐文件钉住的任意值是正确测试
实践)、文档正文 IP(那是文档内容本身)
顺带:scripts/gen_task_table.py 规范串清掉「,B5」——编号清退提交
72b4b094 改了受管区没重跑生成器,task-table 门禁因此一直红
验证:产品 @build 0/0;CH395F 套件开关构建 0/0 后还原产品态;
6 套主机单测 rc=0;content_pages(含宏推导路径)/菜单 8 态/
推流位比对全 PASS;bom-drift 99 无漂移;doc-links/coding-standard/
cppcheck 绿;py_compile 23 文件 + --help 冒烟(含 shim 绝对路径)
113 lines
4.5 KiB
Python
113 lines
4.5 KiB
Python
#!/usr/bin/env python3
|
||
"""头阻塞专项台架探针(timeSync 侧,A/B 对照用)。
|
||
|
||
场景(历史审计的头阻塞触发形态,属主文档已于 2026-10-15 删除):
|
||
1. 一个"挂起"的对时客户端连上 :8888 后不发任何数据(空闲/故障客户端,
|
||
常见工况)——旧固件在此触发 30s 阻塞 net_recv 独占 netTask,
|
||
全体消费者的队列消息停摆最长 30s;
|
||
2. 2s 后从 PC 发起 FTP(:21) 连接,测 banner 到达时延 = 队列响应性:
|
||
修复前 ≈ 25~30s(队头冻结),修复后 ≈ 数百 ms 内;
|
||
3. 34s 时 30s 总预算应已耗尽:设备拆掉该会话(net_drop_conn:
|
||
FIN 关闭 + 本层收口 + 重监听),随后**本探针模拟守规矩对端**:
|
||
close 自己的 socket;
|
||
4. 芯片回 CLOSED(TC-NET-204 模式 A:TIME_WAIT 过渡 ~150ms)→ relisten,
|
||
:8888 应能再接受新连接(3s 重试窗内);新连接发完整 8 字节 TIME 包 →
|
||
设备应落 "wall clock updated"。
|
||
|
||
⚠ 定案口径(TRAP-NET-07 定案更正 2026-10-11 + 《网络自愈架构设计》§5.2 E13):CH395F close
|
||
**无 RST 语义**。若对端内核存活(app 挂起但 socket 不关,内核自动 ACK FIN),
|
||
芯片停在 FIN_WAIT_2、监听恢复受限于对端 close——探针第 3 步的 close 正是
|
||
模拟"对端配合"这一可恢复边界;不配合场景的兜底是芯片 TIMEOUT/keepalive
|
||
拆僵尸会话(E13 定案,30~90s)。
|
||
|
||
用法: python e02_probe.py <run-tag>
|
||
退出码: 0 = 队列响应性 PASS;1 = FAIL;2 = 探针自身异常
|
||
"""
|
||
import socket
|
||
import sys
|
||
import time
|
||
|
||
import bench_defaults # 台架连接默认值单一真源
|
||
|
||
DEV = bench_defaults.DEVICE_IP
|
||
tag = sys.argv[1] if len(sys.argv) > 1 else "run"
|
||
|
||
t0 = time.time()
|
||
|
||
|
||
def log(msg):
|
||
print("[%s] %9.3f %s" % (tag, time.time() - t0, msg), flush=True)
|
||
|
||
|
||
def main():
|
||
# 1. 挂起对时客户端:连接后不发任何数据
|
||
ts = socket.create_connection((DEV, 8888), timeout=5)
|
||
log("time-sync conn open (hung client: sends nothing)")
|
||
|
||
# 2. 2s 后测 FTP banner 时延(队列响应性)
|
||
time.sleep(2.0)
|
||
t1 = time.time()
|
||
banner = None
|
||
try:
|
||
ftp = socket.create_connection((DEV, 21), timeout=35)
|
||
banner = ftp.recv(256)
|
||
dt = time.time() - t1
|
||
log("FTP banner after %8.1f ms: %r" % (dt * 1000, banner[:40]))
|
||
ftp.close()
|
||
except Exception as e:
|
||
dt = time.time() - t1
|
||
log("FTP connect FAIL after %8.1f ms: %r" % (dt * 1000, e))
|
||
dt = None
|
||
queue_ok = (banner is not None) and (dt is not None) and (dt < 3.0)
|
||
log("queue responsiveness: %s (banner %s ms)"
|
||
% ("PASS" if queue_ok else "FAIL",
|
||
("%.0f" % (dt * 1000)) if dt is not None else "n/a"))
|
||
|
||
# 3. 等 30s 总预算耗尽(设备应拆会话:FIN + 本层收口 + 重监听)
|
||
remain = 34.0 - (time.time() - t0)
|
||
if remain > 0:
|
||
time.sleep(remain)
|
||
|
||
# 3b. 模拟守规矩对端:设备已发 FIN(drop_conn),本端 close 配合拆链。
|
||
# CH395F close 无 RST 语义(TRAP-NET-07 定案更正):不配合的内核存活对端
|
||
# 会把芯片停在 FIN_WAIT_2,监听恢复受限于对端 close——不在本探针判据内。
|
||
try:
|
||
ts.close()
|
||
log("hung client socket closed (cooperate with device FIN)")
|
||
except OSError:
|
||
pass # 设备已先拆连,本地 close 报 ECONNRESET 属预期
|
||
|
||
# 4. 监听应已重建(芯片 TIME_WAIT 过渡 ~150ms + relisten):3s 重试窗
|
||
t2 = time.time()
|
||
listener_ok = False
|
||
ts2 = None
|
||
while time.time() - t2 < 3.0:
|
||
try:
|
||
ts2 = socket.create_connection((DEV, 8888), timeout=2)
|
||
break
|
||
except Exception as e:
|
||
log("second time-sync conn retry: %r" % (e,))
|
||
time.sleep(0.3)
|
||
if ts2 is not None:
|
||
dt2 = time.time() - t2
|
||
epoch = int(time.time())
|
||
log("new time-sync conn in %6.0f ms, sent full TIME packet (epoch=%d)"
|
||
% (dt2 * 1000, epoch))
|
||
ts2.sendall(b"TIME" + epoch.to_bytes(4, "big"))
|
||
time.sleep(1.5) # 留时间给设备处理并打日志
|
||
ts2.close()
|
||
listener_ok = True
|
||
else:
|
||
log("second time-sync conn FAIL (3s window)")
|
||
log("OVERALL: queue=%s listener=%s"
|
||
% ("PASS" if queue_ok else "FAIL", "PASS" if listener_ok else "FAIL"))
|
||
return 0 if (queue_ok and listener_ok) else 1
|
||
|
||
|
||
if __name__ == "__main__":
|
||
try:
|
||
sys.exit(main())
|
||
except Exception as e:
|
||
print("[%s] PROBE ERROR: %r" % (tag, e), flush=True)
|
||
sys.exit(2)
|