readout_program/doc_builder/renderers/render_ids.py

186 lines
5.9 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.

"""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:
"""生成 <td> 单元格,支持 rowspan / style 等属性。"""
attrs = " ".join(f'{k}="{v}"' for k, v in kwargs.items() if v is not None)
return f"<td {attrs}>{text}</td>" if attrs else f"<td>{text}</td>"
def _th(text: str) -> str:
return f"<th>{text}</th>"
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(
"<tr>"
f"<td>ch{ch}</td>"
f"<td>{exaddr}</td>"
f"<td>{cid}</td>"
f"<td><code>{mod_name}</code></td>"
f"<td><code>{m.get('StartAddress', '')}</code></td>"
f"<td>{m.get('Size', '')}</td>"
f"<td>{m.get('Info', '')}</td>"
"</tr>"
)
if not rows:
return "<p>(无映射数据)</p>"
header = (
"<tr>"
"<th>通道</th><th>Exaddr</th><th>Cid</th>"
"<th>模块</th><th>起始地址</th><th>大小</th><th>说明</th>"
"</tr>"
)
return f"<table>{header}{''.join(rows)}</table>"
# ---------- 寄存器表渲染 ----------
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 "<p>(无寄存器数据)</p>"
# 按偏移地址排序
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(
"<tr>"
f"<td><strong>{name}</strong></td>"
f"<td><code>{offset}</code></td>"
f"<td>{perm}</td>"
f"<td>{desc}</td>"
"</tr>"
)
summary = (
"<table>"
"<tr><th>寄存器名</th><th>偏移地址</th><th>权限</th><th>描述</th></tr>"
f"{''.join(summary_rows)}"
"</table>"
)
# ---- 位域明细表(仅含字段数 > 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", "<br>")
reset = f.get("ResetValue", "")
field_rows.append(
"<tr>"
f"<td><code>[{_bit_range_str(bits)}]</code></td>"
f"<td><strong>{field_name}</strong></td>"
f"<td>{reset}</td>"
f"<td>{fdesc}</td>"
"</tr>"
)
if field_rows:
detail_parts.append(
f"<h4>{name}{offset}</h4>"
"<table>"
"<tr><th>位段</th><th>字段名</th><th>复位值</th><th>描述</th></tr>"
f"{''.join(field_rows)}"
"</table>"
)
if detail_parts:
return f"{summary}<br>{''.join(detail_parts)}"
return summary