Updates
This commit is contained in:
132
analysis/registers.py
Normal file
132
analysis/registers.py
Normal file
@@ -0,0 +1,132 @@
|
||||
"""Parse SN65DSI83 and DSIM register dumps into structured flags.
|
||||
|
||||
DSIM PHY_TIMING bit-field layout is undocumented in the i.MX 8M Mini RM.
|
||||
We log raw hex AND decoded cycle counts so they can be cross-checked
|
||||
against kernel dmesg output that prints the cycle counts explicitly.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Optional
|
||||
|
||||
from config import (
|
||||
BYTE_CLK_HZ,
|
||||
SN65_ERR_SOT,
|
||||
SN65_ERR_SYNCH,
|
||||
SN65_ERR_UNC,
|
||||
SN65_FLICKER_MASK,
|
||||
)
|
||||
|
||||
|
||||
def _to_int(v) -> Optional[int]:
|
||||
if v is None:
|
||||
return None
|
||||
if isinstance(v, int):
|
||||
return v
|
||||
s = str(v).strip().lower()
|
||||
try:
|
||||
if s.startswith("0x"):
|
||||
return int(s, 16)
|
||||
return int(s, 16)
|
||||
except ValueError:
|
||||
return None
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# SN65DSI83
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
def parse_sn65(reg_json: dict) -> dict:
|
||||
"""Extract structured flicker flags from /sn65_registers response.
|
||||
|
||||
Accepts either the server's pre-parsed shape (with explicit bool keys)
|
||||
or a raw {register: hex} mapping; falls back to bit-decoding in either case.
|
||||
"""
|
||||
irq_raw = _to_int(reg_json.get("irq_stat_raw"))
|
||||
if irq_raw is None:
|
||||
regs = reg_json.get("registers", {})
|
||||
irq_raw = _to_int(regs.get("e5") or regs.get("E5") or regs.get("0xE5"))
|
||||
irq_raw = irq_raw or 0
|
||||
|
||||
pll_raw = _to_int(reg_json.get("registers", {}).get("0a")) if reg_json.get("registers") else None
|
||||
clk_raw = _to_int(reg_json.get("registers", {}).get("0b")) if reg_json.get("registers") else None
|
||||
|
||||
pll_locked = reg_json.get("pll_locked")
|
||||
if pll_locked is None and pll_raw is not None:
|
||||
pll_locked = bool(pll_raw & 0x80)
|
||||
|
||||
clk_detected = reg_json.get("clk_detected")
|
||||
if clk_detected is None and clk_raw is not None:
|
||||
clk_detected = bool(clk_raw & 0x01)
|
||||
|
||||
sot_err = bool(irq_raw & SN65_ERR_SOT)
|
||||
synch_err = bool(irq_raw & SN65_ERR_SYNCH)
|
||||
unc_ecc_err = bool(irq_raw & SN65_ERR_UNC)
|
||||
flicker_detected = bool(irq_raw & SN65_FLICKER_MASK)
|
||||
|
||||
return {
|
||||
"irq_stat_raw": f"0x{irq_raw:02X}",
|
||||
"irq_stat_int": irq_raw,
|
||||
"pll_locked": bool(pll_locked) if pll_locked is not None else None,
|
||||
"clk_detected": bool(clk_detected) if clk_detected is not None else None,
|
||||
"sot_err": sot_err,
|
||||
"synch_err": synch_err,
|
||||
"unc_ecc_err": unc_ecc_err,
|
||||
"flicker_detected": flicker_detected,
|
||||
"registers": reg_json.get("registers", {}),
|
||||
}
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# DSIM PHY_TIMING / PHY_TIMING1 / PHY_TIMING2
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
def _cycles_to_ns(cycles: int) -> float:
|
||||
return cycles / BYTE_CLK_HZ * 1e9
|
||||
|
||||
|
||||
def parse_dsim(reg_json: dict) -> dict:
|
||||
pt = _to_int(reg_json.get("PHY_TIMING"))
|
||||
pt1 = _to_int(reg_json.get("PHY_TIMING1"))
|
||||
pt2 = _to_int(reg_json.get("PHY_TIMING2"))
|
||||
|
||||
out: dict = {
|
||||
"PHY_TIMING_raw": f"0x{pt:08X}" if pt is not None else None,
|
||||
"PHY_TIMING1_raw": f"0x{pt1:08X}" if pt1 is not None else None,
|
||||
"PHY_TIMING2_raw": f"0x{pt2:08X}" if pt2 is not None else None,
|
||||
}
|
||||
|
||||
if pt is not None:
|
||||
hs_exit = (pt >> 4) & 0xF
|
||||
lpx = pt & 0xF
|
||||
out["hs_exit_cycles"] = hs_exit
|
||||
out["hs_exit_ns"] = _cycles_to_ns(hs_exit)
|
||||
out["lpx_cycles"] = lpx
|
||||
out["lpx_ns"] = _cycles_to_ns(lpx)
|
||||
|
||||
if pt1 is not None:
|
||||
clk_zero = (pt1 >> 24) & 0xFF
|
||||
clk_post = (pt1 >> 16) & 0xFF
|
||||
clk_trail = (pt1 >> 8) & 0xFF
|
||||
clk_prepare = pt1 & 0xFF
|
||||
out["clk_zero_cycles"] = clk_zero
|
||||
out["clk_zero_ns"] = _cycles_to_ns(clk_zero)
|
||||
out["clk_post_cycles"] = clk_post
|
||||
out["clk_post_ns"] = _cycles_to_ns(clk_post)
|
||||
out["clk_trail_cycles"] = clk_trail
|
||||
out["clk_trail_ns"] = _cycles_to_ns(clk_trail)
|
||||
out["clk_prepare_cycles"] = clk_prepare
|
||||
out["clk_prepare_ns"] = _cycles_to_ns(clk_prepare)
|
||||
|
||||
if pt2 is not None:
|
||||
hs_prepare = (pt2 >> 16) & 0xFF
|
||||
hs_zero = (pt2 >> 8) & 0xFF
|
||||
hs_trail = pt2 & 0xFF
|
||||
out["hs_prepare_cycles"] = hs_prepare
|
||||
out["hs_prepare_ns"] = _cycles_to_ns(hs_prepare)
|
||||
out["hs_zero_cycles"] = hs_zero
|
||||
out["hs_zero_ns"] = _cycles_to_ns(hs_zero)
|
||||
out["hs_trail_cycles"] = hs_trail
|
||||
out["hs_trail_ns"] = _cycles_to_ns(hs_trail)
|
||||
|
||||
return out
|
||||
Reference in New Issue
Block a user