"""M9 L3 CHANNEL certifier: structure + skip; numeric only with existing FACT.""" from __future__ import annotations import json from backend.periscopex.models import ( Component, ComponentType, DesignGraph, Net, NetType, PinConnection, ) from backend.periscopex.protocol_catalog import ( ConstraintSource, PhysicalInterface, ProtocolConstraint, ) from backend.periscopex.protocol_l0 import protocol_exam from backend.periscopex.protocol_l3 import ( _pack, certify_instance_l3, certify_l3, remaining_margin_ps, ) from backend.periscopex.protocol_recognize import ( PhysicalBusInstance, recognize_physical_buses, ) def _ic(ref: str, pins: dict[str, str], *, mpn: str = "", value: str = "") -> Component: return Component( reference=ref, value=value or mpn, footprint="", component_type=ComponentType.IC, mpn=mpn or None, pins=pins, ) def _net(name: str, *pairs: tuple[str, str]) -> Net: return Net( name=name, net_type=NetType.SIGNAL, pins=[PinConnection(component_ref=r, pin_number=p) for r, p in pairs], ) def _usb_connected() -> DesignGraph: return DesignGraph( components={ "U1": _ic("U1", {"1": "USB_D+", "2": "USB_D-"}, mpn="CH340E"), "J2": Component( reference="J2", value="USB2_TypeA", footprint="USB_A", component_type=ComponentType.CONNECTOR, pins={"2": "USB_D+", "3": "USB_D-"}, ), }, nets={ "USB_D+": _net("USB_D+", ("U1", "1"), ("J2", "2")), "USB_D-": _net("USB_D-", ("U1", "2"), ("J2", "3")), }, ) def _hdmi_graph() -> DesignGraph: pins = {"1": "HDMI_TX0_P", "2": "HDMI_TX0_N", "3": "HDMI_CLK_P", "4": "HDMI_CLK_N"} return DesignGraph( components={ "U8": _ic("U8", pins, mpn="ADV7511", value="HDMI transmitter"), "J8": Component( reference="J8", value="HDMI-A", footprint="HDMI", component_type=ComponentType.CONNECTOR, pins=pins, ), }, nets={n: _net(n, ("U8", p), ("J8", p)) for p, n in pins.items()}, schematic_fields={"J8": {"protocol": "hdmi-1.4-tmds-type-a"}}, ) def _pcie_graph() -> DesignGraph: pins = {"1": "PCIE_TX_P", "2": "PCIE_TX_N", "3": "PCIE_RX_P", "4": "PCIE_RX_N"} return DesignGraph( components={ "U7": _ic("U7", pins, mpn="PI7C9X2G304GP", value="PCIe switch"), "J7": Component( reference="J7", value="PCIe x1", footprint="PCIE", component_type=ComponentType.CONNECTOR, pins=pins, ), }, nets={n: _net(n, ("U7", p), ("J7", p)) for p, n in pins.items()}, schematic_fields={"U7": {"protocol": "pcie-phy-pcb"}}, ) def _axi_graph() -> DesignGraph: return DesignGraph( components={ "U3": _ic("U3", {"1": "AXI_AWVALID"}, mpn="XC7A100T", value="AXI4 interconnect"), }, nets={"AXI_AWVALID": _net("AXI_AWVALID", ("U3", "1"))}, ) def _cite() -> ConstraintSource: return ConstraintSource( document="Fixture channel pack", organization="TESTLAB", section="4.1", ) def _iface_with_numeric(*, il_db: float = -8.0, rl_db: float = -10.0, margin_ps: float = 0.0) -> PhysicalInterface: return PhysicalInterface( id="fixture-hs-dpair", logical_protocol_id="fixture-hs", bus_type="SERIAL", physical_layer="SERIAL_DIFFERENTIAL", pcb_relevant="YES", required_checks=[ "insertion_loss", "return_loss", "crosstalk", "timing_budget", "channel", ], constraints=[ ProtocolConstraint( id="fixture-il", parameter="insertion_loss", value_kind="NUMERIC", mandatory="MANDATORY", source_type="STANDARD", source_class="NORMATIVE", value=il_db, unit="dB", source=_cite(), ), ProtocolConstraint( id="fixture-rl", parameter="return_loss", value_kind="NUMERIC", mandatory="MANDATORY", source_type="STANDARD", source_class="NORMATIVE", value=rl_db, unit="dB", source=_cite(), ), ProtocolConstraint( id="fixture-xt", parameter="crosstalk", value_kind="NUMERIC", mandatory="RECOMMENDED", source_type="STANDARD", source_class="NORMATIVE", value=-20.0, unit="dB", source=_cite(), ), ProtocolConstraint( id="fixture-tb", parameter="timing_budget", value_kind="NUMERIC", mandatory="MANDATORY", source_type="STANDARD", source_class="NORMATIVE", value=margin_ps, unit="ps", source=_cite(), ), ], ) def _inst() -> PhysicalBusInstance: return PhysicalBusInstance( instance_id="fixture-1", logical_protocol_id="fixture-hs", physical_interface_id="fixture-hs-dpair", pcb_relevant="YES", confidence=1.0, evidence_kind="net_name", recognition_status="RECOGNIZED", nets=["CH_P", "CH_N"], host_ref="U1", ) def test_remaining_margin_is_total_minus_used(): assert remaining_margin_ps(200.0, 120.0) == 80.0 assert remaining_margin_ps(200.0, 120.0, 77.0) == 77.0 assert remaining_margin_ps(None, 10.0) is None def test_usb_hdmi_pcie_skip_without_channel_data(): for graph, token in ((_usb_connected(), "usb"), (_hdmi_graph(), "hdmi"), (_pcie_graph(), "pcie")): sec, findings = protocol_exam(graph) assert sec.max_level_reached == "L3" assert sec.macrophase == "M9" row = next( r for r in sec.recognized_instances if token in str(r.get("logical_protocol_id")).lower() or token in str(r.get("physical_interface_id")).lower() ) l3 = row["l3_checks"] assert l3 names = {c["check"] for c in l3} assert {"timing_budget", "insertion_loss", "return_loss", "crosstalk", "channel"} <= names assert all(c["result"] != "PASS" for c in l3) notes = " ".join(c.get("notes") or "" for c in l3) assert "non certificata a L3 per mancanza" in notes assert "OpenEMS" in notes blob = json.dumps(l3) assert "90" not in blob assert any(f.rule_id == "PE-PRT-L3-001" for f in findings) assert "s21" not in blob.lower() or "invent" in notes.lower() def test_axi_l3_not_applicable_not_fail(): sec, findings = protocol_exam(_axi_graph()) row = next( r for r in sec.recognized_instances if "axi" in str(r.get("logical_protocol_id")) ) l3 = row["l3_checks"] assert l3 assert all(c["result"] == "NOT_APPLICABLE" for c in l3) assert all(c["result"] != "FAIL" for c in l3) assert all(f.rule_id != "PE-PRT-L3-002" for f in findings) assert all(f.status != "ERROR" or f.source != "protocol_l3" for f in findings) def test_fixture_channel_pass_with_existing_fact(): iface = _iface_with_numeric() inst = _inst() data = { "instances": { inst.instance_id: { "insertion_loss_db": -3.0, "return_loss_db": -15.0, "crosstalk_db": -28.0, "total_budget_ps": 200.0, "used_budget_ps": 120.0, "channel_complete": True, } } } rows = certify_instance_l3(inst, iface, channel_data=data) by_check = {r.check: r for r in rows} assert by_check["insertion_loss"].result == "PASS" assert by_check["return_loss"].result == "PASS" assert by_check["timing_budget"].result == "PASS" assert by_check["timing_budget"].remaining_margin_ps == 80.0 assert by_check["channel"].result == "PASS" assert by_check["insertion_loss"].measured_db == -3.0 notes = " ".join(r.notes.lower() for r in rows) assert "not invented" in notes assert "not openems" in notes def test_fixture_channel_fail_mandatory_il(): iface = _iface_with_numeric() inst = _inst() data = { inst.instance_id: { "s21_db": -12.0, "s11_db": -15.0, "total_budget_ps": 200.0, "used_budget_ps": 50.0, } } rows = certify_instance_l3(inst, iface, channel_data=data) il = next(r for r in rows if r.check == "insertion_loss") assert il.result == "FAIL" findings = [] from backend.periscopex.protocol_l3 import l3_findings findings = l3_findings(inst, rows) assert any(f.rule_id == "PE-PRT-L3-002" and f.status == "ERROR" for f in findings) def test_recommended_never_fail_l3(): rec = _pack("crosstalk", "FAIL", "RECOMMENDED", notes="xt") assert rec.result != "FAIL" assert rec.status != "ERROR" def test_raw_touchstone_without_fact_is_skip_not_invented(): iface = _iface_with_numeric() inst = _inst() data = {inst.instance_id: {"sparam_file": "lane.s4p", "touchstone": "lane.s4p"}} rows = certify_instance_l3(inst, iface, channel_data=data) assert all(r.result != "PASS" for r in rows) notes = " ".join(r.notes for r in rows) assert "non certificata a L3" in notes assert "invent" in notes.lower() or "non inventati" in notes.lower() or "not invented" in notes.lower() blob = json.dumps([r.model_dump() for r in rows]) # no synthesized S21 numbers assert '"measured_db": null' in blob or all(r.measured_db is None for r in rows) def test_openems_method_is_explicit_skip(): iface = _iface_with_numeric() inst = _inst() data = { inst.instance_id: { "insertion_loss_db": -2.0, "method": "OpenEMS", "solver": "FEM", } } rows = certify_instance_l3(inst, iface, channel_data=data) notes = " ".join(r.notes for r in rows) assert "non certificata a L3" in notes assert all(r.result != "PASS" for r in rows) def test_no_sparam_invention_on_empty_channel_data(): insts = recognize_physical_buses(_usb_connected()) by, findings = certify_l3(insts, channel_data=None) rows = [r for lst in by.values() for r in lst] blob = json.dumps([r.model_dump() for r in rows]) assert "s21" not in blob.lower() assert all(r.measured_db is None for r in rows) assert any("mancanza" in r.notes for r in rows) assert any(f.rule_id == "PE-PRT-L3-001" for f in findings) def test_protocol_exam_attaches_l3_and_does_not_call_l0_electrical(): sec, _ = protocol_exam(_usb_connected()) row = sec.recognized_instances[0] assert row.get("l3_checks") assert all(c.get("level") == "L3" for c in row["l3_checks"]) notes = " ".join(c.get("notes") or "" for c in row["l3_checks"]) assert "L0/L1 are not electrical" in notes l0notes = json.dumps(row.get("l0_checks") or []) assert "ohm" not in l0notes.lower() or "not" in l0notes.lower()