fix(cfg): 配置热重载吞段缺陷修复 + 两点标定工具链与台架实测落档
修复运行期改配置被打回出厂值的缺陷:cfg_file_poll() 按段循环复用同一 份读缓冲,而 s_parse() 通过 s_split_line()/s_key_value() 就地改写缓冲 (把换行与等号换成 NUL)。第一个段解析完,缓冲里已没有键值行,后续 7 个段静默保持出厂值;随后 run_par_store_save() 又把这份出厂值写回 config.ini,用户的标定值被永久覆盖。开机路径 cfg_file_load() 只解析一 轮,所以该缺陷长期不可见,只在运行中改配置时发作。 - s_parse() 改为非破坏性:入参 const char *,逐行 memcpy 到栈缓冲 (CFG_LINE_TEST_MAX + 1)后再交给会破坏缓冲的解析子函数;超长行跳 过(保存侧已拒绝落盘超长受管键行)。 - 新增 TC-CONFIG-063:同时改两段内容,断言第二个注册段也重载成功、 含负值 INT 键存活,把「热重载吞段」钉成机器面。 新增两点标定台架工具链(test/host/): - cal_two_point.py:整数算术镜像 adc_cal_two_point(),支持单路模式与 从执行卡 CALDATA 表批量求解(--from-doc),带合法带与零点自检拦截。 - cal_write.py:复用 iec104_master 作库,经 104 定值段写 r 后写 b 并 读回校验,是所有写入的唯一入口。 adc_task 的 meas: 心跳行精度提到 4 位小数,标定读数需要。 文档:新增《采样数据校正全流程》(端到端导航)与《ADC 两点标定执行 流程》(台架执行卡,含 CALDATA 可填表);ADC通道映射说明新增 §7.3 台 架实测结果(UA 554.687914、IA 29.634259,出厂默认值保持不变);配置 文件设计说明新增解析器契约 v1.19;采集与算法层设计说明 §13 系列与 README 索引同步。 台架实测:UA r=554.687914(出厂 1000.0 偏大 1.80 倍,根因是接线分压 使 PT 一次侧只拿到一半电压,实测与参数算定 606.06 只差 8.5%)、IA r=29.634259(与出厂 29.4118 只差 0.76%,反证链路未算错)。UN 按用户 裁定本轮不标定,保护闭锁(vl=0x11)是预期行为,未伪造 VALID。 同时入库 .dsh/roles 角色定义(原被 .gitignore 挡住)。
This commit is contained in:
@@ -0,0 +1,92 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
"""两点标定写入器:C_SE_NC_1 两段写下发 r/b,C_RD 读回复核。
|
||||
|
||||
复用台架已验收主站库 test/host/iec104_master.py(不重写协议层)。
|
||||
地址(App/algo/run_par.c run_par_104_write):r = 0x8050+slot,
|
||||
b = 0x8048+slot;slot UA0/UN3/IA4。执行卡:
|
||||
docs/测试说明/专项验证/ADC两点标定执行流程.md §4。
|
||||
|
||||
用法:
|
||||
python test/host/cal_write.py --r 0x8050=995.99 --b 0x8048=-1 \
|
||||
--read 0x8050,0x8048 --expect 995.99,-1
|
||||
python test/host/cal_write.py --read 0x8050,0x8054 --expect 995.99,29.52
|
||||
|
||||
写入顺序刻意**先 r 后 b**:b 走 adc_cal_set() 置 VALID 位,而 VALID 要求
|
||||
r 已在带——先让 r 就位,语义干净。--b 必须是整数码值。
|
||||
PN(否定确认)= 执行段拒绝:看串口 `[ERR] set ch=... rejected` 行。
|
||||
输出纯 ASCII,可直接重定向归档为台架证据;exit 0 全过 / 1 有失败 / 2 连接或协议错误。
|
||||
"""
|
||||
import argparse
|
||||
import os
|
||||
import sys
|
||||
|
||||
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
|
||||
import bench_defaults # noqa: E402
|
||||
import iec104_master as m104 # noqa: E402
|
||||
|
||||
|
||||
def parse_pair(text):
|
||||
addr_s, val_s = text.split("=", 1)
|
||||
return int(addr_s, 0), float(val_s)
|
||||
|
||||
|
||||
def main():
|
||||
ap = argparse.ArgumentParser()
|
||||
ap.add_argument("--ip", default=bench_defaults.DEVICE_IP)
|
||||
ap.add_argument("--port", type=int, default=2404)
|
||||
ap.add_argument("--r", action="append", default=[],
|
||||
help="0xADDR=FLOAT ratio write (repeatable, issued first)")
|
||||
ap.add_argument("--b", action="append", default=[],
|
||||
help="0xADDR=INT zero-code write (repeatable, sets VALID)")
|
||||
ap.add_argument("--read", default="",
|
||||
help="comma-separated IOA list, C_RD readback")
|
||||
ap.add_argument("--expect", default="",
|
||||
help="comma-separated expected values, same order as --read")
|
||||
a = ap.parse_args()
|
||||
|
||||
reads = [x.strip() for x in a.read.split(",") if x.strip()]
|
||||
expects = [float(x) for x in a.expect.split(",")] if a.expect else []
|
||||
if not a.r and not a.b and not reads:
|
||||
ap.error("need at least one --r / --b / --read")
|
||||
|
||||
ck = m104.Checks()
|
||||
try:
|
||||
m = m104.Master(a.ip, a.port)
|
||||
except Exception as exc:
|
||||
print("CONNECT FAIL: %r" % (exc,))
|
||||
return 2
|
||||
|
||||
try:
|
||||
m._send(m104.u_frame(m104.U_STARTDT_ACT), "U STARTDT act")
|
||||
ck.add("startdt_con", m.wait_event(
|
||||
lambda e: e[0] == "startdt_con", 5.0) is not None)
|
||||
|
||||
for text in a.r: # 1) ratio first
|
||||
addr, val = parse_pair(text)
|
||||
m104.se_write(m, ck, addr, val, "r_%04X" % addr)
|
||||
|
||||
for text in a.b: # 2) zero + VALID
|
||||
addr, val = parse_pair(text)
|
||||
if abs(val - round(val)) > 1e-6:
|
||||
print("WARN b=%s not an integer code, truncated to %.0f"
|
||||
% (text, round(val)))
|
||||
val = float(round(val))
|
||||
m104.se_write(m, ck, addr, val, "b_%04X" % addr)
|
||||
|
||||
for i, addr_s in enumerate(reads):
|
||||
want = expects[i] if i < len(expects) else 0.0
|
||||
m104.rd_set(m, ck, int(addr_s, 0), want, "rd_%s" % addr_s)
|
||||
finally:
|
||||
m.close()
|
||||
|
||||
bad = [n for n, ok, _ in ck.items if not ok]
|
||||
print("SUMMARY %s total=%d fail=%d" %
|
||||
("PASS" if not bad else "FAIL", len(ck.items), len(bad)))
|
||||
if bad:
|
||||
print("FAILED: %s" % ", ".join(bad))
|
||||
return 0 if not bad else 1
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
Reference in New Issue
Block a user