"""IDS 数据共享模块。
提供 JSON 加载和 HTML 表格渲染函数,
供 render_ids_acq_map / render_ids_exc_map / render_ids_daq_reg / render_ids_awg_reg 复用。
"""
import json
from pathlib import Path
from collections import OrderedDict
# 输出顺序(先列出的模块排在前面)
ACQ_MODULE_ORDER = ["MCU_INS", "MCU_DAT", "DAQ_REG", "DAQ_PAR", "DAQ_FLT"]
EXC_MODULE_ORDER = ["MCU_INS", "MCU_DAT", "AWG_REG", "AWG_IDX", "AWG_WVE"]
# ---------- 数据加载 ----------
def _load_ids(filepath: str) -> dict:
"""加载 IDS JSON 文件并返回解析后的 dict。"""
path = Path(filepath)
if not path.exists():
raise FileNotFoundError(f"IDS 文件不存在: {path}")
with open(path, "r", encoding="utf-8") as f:
return json.load(f)
# ---------- HTML 工具 ----------
def _td(text: str, **kwargs) -> str:
"""生成
单元格,支持 rowspan / style 等属性。"""
attrs = " ".join(f'{k}="{v}"' for k, v in kwargs.items() if v is not None)
return f" | {text} | " if attrs else f"{text} | "
def _th(text: str) -> str:
return f"{text} | "
def _bit_range_str(bits: list) -> str:
"""将 [15, 8] 或 [7] 转为位段字符串。"""
if len(bits) == 1:
return str(bits[0])
return f"{bits[0]}:{bits[-1]}"
# ---------- 映射表渲染 ----------
def render_mapping_acq_table(data: dict) -> str:
"""渲染 msmt_acq 通道模块基地址表。"""
mi = data.get("MappingInfo", {}).get("msmt_acq", {})
return _render_mapping_table(mi, ACQ_MODULE_ORDER, "ACQ")
def render_mapping_exc_table(data: dict) -> str:
"""渲染 msmt_exc 通道模块基地址表。"""
mi = data.get("MappingInfo", {}).get("msmt_exc", {})
return _render_mapping_table(mi, EXC_MODULE_ORDER, "EXC")
def _render_mapping_table(mapping: dict, module_order: list, label: str) -> str:
"""通用的通道模块基地址渲染。"""
rows = []
# 收集所有模块名
all_modules = set()
for ch_info in mapping.values():
all_modules.update(ch_info.get("Modules", {}).keys())
# 按 module_order 排序,未在列表中的放最后
ordered = [m for m in module_order if m in all_modules]
ordered += sorted(all_modules - set(module_order))
for mod_name in ordered:
for ch in sorted(mapping.keys(), key=int):
info = mapping[ch]
modules = info.get("Modules", {})
if mod_name not in modules:
continue
m = modules[mod_name]
exaddr = info.get("Exaddr", "")
cid = info.get("Cid", "")
rows.append(
""
f"| ch{ch} | "
f"{exaddr} | "
f"{cid} | "
f"{mod_name} | "
f"{m.get('StartAddress', '')} | "
f"{m.get('Size', '')} | "
f"{m.get('Info', '')} | "
"
"
)
if not rows:
return "(无映射数据)
"
header = (
""
"| 通道 | Exaddr | Cid | "
"模块 | 起始地址 | 大小 | 说明 | "
"
"
)
return f""
# ---------- 寄存器表渲染 ----------
def render_daq_reg_table(data: dict) -> str:
"""渲染 DAQ_REG 寄存器汇总表 + 位域明细。"""
regs = data.get("Modules", {}).get("DAQ_REG", {})
return _render_reg_table(regs, "DAQ_REG")
def render_awg_reg_table(data: dict) -> str:
"""渲染 AWG_REG 寄存器汇总表 + 位域明细。"""
regs = data.get("Modules", {}).get("AWG_REG", {})
return _render_reg_table(regs, "AWG_REG")
def _render_reg_table(regs: dict, label: str) -> str:
"""通用寄存器表渲染(汇总表 + 每位域明细)。"""
if not regs:
return "(无寄存器数据)
"
# 按偏移地址排序
sorted_regs = sorted(regs.values(), key=lambda r: int(r.get("OffsetAddress", "0x0"), 16))
# ---- 汇总表 ----
summary_rows = []
for r in sorted_regs:
name = list(regs.keys())[list(regs.values()).index(r)]
offset = r.get("OffsetAddress", "")
perm = r.get("Permission", "")
desc = r.get("SegDescription", "")
summary_rows.append(
""
f"| {name} | "
f"{offset} | "
f"{perm} | "
f"{desc} | "
"
"
)
summary = (
""
"| 寄存器名 | 偏移地址 | 权限 | 描述 |
"
f"{''.join(summary_rows)}"
"
"
)
# ---- 位域明细表(仅含字段数 > 0 的寄存器) ----
detail_parts = []
for r in sorted_regs:
fields = r.get("Fields", [])
if not fields:
continue
name = list(regs.keys())[list(regs.values()).index(r)]
offset = r.get("OffsetAddress", "")
field_rows = []
for f in fields:
bits = f.get("Bits", [])
field_name = f.get("FieldName", "")
fdesc = (f.get("FieldDescription", "") or "").replace("\n", "
")
reset = f.get("ResetValue", "")
field_rows.append(
""
f"[{_bit_range_str(bits)}] | "
f"{field_name} | "
f"{reset} | "
f"{fdesc} | "
"
"
)
if field_rows:
detail_parts.append(
f"{name}({offset})
"
""
"| 位段 | 字段名 | 复位值 | 描述 |
"
f"{''.join(field_rows)}"
"
"
)
if detail_parts:
return f"{summary}
{''.join(detail_parts)}"
return summary