Files
STM32F4-Base/test/host/cal_write.py
T
wandering1 7c505b2457 refactor(adc): 最小二乘拟合移出固件,只留 PC 侧唯一实现
用户裁定(2026-11-13):设备本体只需要校正后的参数,不需要自己拟合
标定曲线,故固件侧最小二乘拟合整体移出,拟合的唯一实现留在 PC 侧
test/host/cal_fit.py。

删除的死代码(生产零调用、上一轮 map 里已被 linker 标 Removing):
- adc_cal.h:adc_cal_fit() 声明、8 个拒绝码、5 个常量
- adc_cal.c:s_div_round() / s_fit_accum() / adc_cal_fit() 共 224 行
- adc_cal_test.c:tc_00b_fit 226 行(184 -> 150 条)

原样保留的设备侧安全闸:
- adc_cal_apply() 折算、adc_cal_set() / adc_cal_set_ratio() 参数合法
  带拦截(防工具写坏参数)、adc_cal_flags() / adc_cal_prot_blocked() /
  adc_cal_rail_ths()。设备不「算」,但必须「用」和「验」。

测试面:
- cal_fit.py 转为唯一实现,新增 --selftest:承接原 C 侧金标向量
  (r_q16=39322000 / b=12)与 4 条拒绝路径,共 11 条断言;已做变异
  测试证明它会红(改坏圆整口径 -> 2 条 FAIL)
- cal_two_point.py 删除,两点工具由多点拟合取代

文档口径统一为「求参在 PC、设备只做折算与合法带校验」,6 篇 docs 同步;
执行卡改名 ADC多点标定执行流程.md(正文同步 5 点最小二乘口径)。

cfg 热重载吞段缺陷的解析器契约与 TC-CONFIG-063 机器钉一并入库。
Program Size 不变(Code=256196):删掉的是从未链接进镜像的死代码。

验证:Keil 0 errors 0 warnings;adc_cal 150/150;selftest 11/11;
ci_local.py RC=0(static 48/48、manual 三根、size-gate、host-unit
4341/4341);doc-links / mermaid / mojibake 全 0。
2026-11-13 08:09:09 +08:00

93 lines
3.6 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/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())