Add VENDOR to SourceType. HDMI 2.0/FRL fill TMDS1204 PCB numbers as VENDOR RECOMMENDED; TMDS1204-specific skew/vias/data_rate/SIGDET stay PHY_DEPENDENT. HDMI 1.4 TMDS remains UNKNOWN. Not HDMI Forum STANDARD.
300 lines
13 KiB
Python
300 lines
13 KiB
Python
"""Recovered-PDF pack: USB Electrical CTS, Type-C FTS, DVI 1.0, IEEE 802.3-2012 §2."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import json
|
|
|
|
from backend.periscopex.models import (
|
|
Component,
|
|
ComponentType,
|
|
DesignGraph,
|
|
Net,
|
|
NetType,
|
|
PinConnection,
|
|
)
|
|
from backend.periscopex.protocol_catalog import load_catalog
|
|
from backend.periscopex.protocol_recognize import recognize_physical_buses
|
|
|
|
|
|
def _cite_ok(c) -> None:
|
|
assert c.value_kind == "NUMERIC"
|
|
assert c.value is not None
|
|
src = c.source
|
|
assert src is not None
|
|
assert src.document
|
|
assert src.organization
|
|
assert src.revision
|
|
assert src.page
|
|
assert src.section or src.table
|
|
|
|
|
|
def test_usb_cts_hs_numeric_cited_no_zdiff_90():
|
|
cat = load_catalog()
|
|
hs = next(p for p in cat.physical_interfaces if p.id == "usb2-hs-dpair")
|
|
by = {c.parameter: c for c in hs.constraints}
|
|
_cite_ok(by["data_rate"])
|
|
assert by["data_rate"].value == 480.00
|
|
assert by["data_rate"].unit == "Mb/s"
|
|
assert by["data_rate"].source.document == "Universal Serial Bus Specification"
|
|
assert "2.0" in by["data_rate"].source.revision
|
|
assert by["data_rate"].source.section == "7.1.11"
|
|
assert by["rise_time"].value == 300.0
|
|
assert by["fall_time"].value == 300.0
|
|
assert by["pull_up"].value == 1500.0
|
|
assert by["dc_resistance"].value == 17.0
|
|
assert by["dc_resistance_captive_cable_device"].value == 23.0
|
|
assert by["dc_resistance_host_hub_downstream"].value == 13.0
|
|
for key in (
|
|
"data_rate", "rise_time", "fall_time", "pull_up", "dc_resistance",
|
|
"dc_resistance_captive_cable_device", "dc_resistance_host_hub_downstream",
|
|
"cable_differential_impedance", "pcb_trace_nominal_zdiff",
|
|
):
|
|
_cite_ok(by[key])
|
|
assert by["cable_differential_impedance"].value == 90.0
|
|
assert by["cable_differential_impedance"].source_type == "CABLE"
|
|
assert by["pcb_trace_nominal_zdiff"].value == 90.0
|
|
assert by["pcb_trace_nominal_zdiff"].mandatory == "RECOMMENDED"
|
|
assert by["pcb_trace_nominal_zdiff"].source_type == "PCB"
|
|
z = by["differential_impedance"]
|
|
assert z.value_kind == "UNKNOWN"
|
|
assert z.value is None
|
|
ls = next(p for p in cat.physical_interfaces if p.id == "usb2-ls-dpair")
|
|
ls_rate = next(c for c in ls.constraints if c.parameter == "data_rate")
|
|
_cite_ok(ls_rate)
|
|
assert ls_rate.value == 1.50
|
|
fs = next(p for p in cat.physical_interfaces if p.id == "usb2-fs-dpair")
|
|
fs_rate = next(c for c in fs.constraints if c.parameter == "data_rate")
|
|
_cite_ok(fs_rate)
|
|
assert fs_rate.value == 12.000
|
|
blob = json.dumps(z.model_dump())
|
|
assert "90" not in blob
|
|
|
|
|
|
def test_type_c_rp_rd_from_cabcon_r25_vbus_volts_unknown():
|
|
cat = load_catalog()
|
|
rec = next(p for p in cat.physical_interfaces if p.id == "usb-c-receptacle")
|
|
by = {c.parameter: c for c in rec.constraints}
|
|
_cite_ok(by["rp"])
|
|
assert by["rp"].value == 56000.0
|
|
assert by["rp"].source.table == "Table 4-27"
|
|
assert by["rp"].source.revision == "Release 2.5, March 2026"
|
|
assert by["rp"].source_type == "CONNECTOR"
|
|
_cite_ok(by["rd"])
|
|
assert by["rd"].value == 5100.0
|
|
assert by["rd"].source.table == "Table 4-28"
|
|
_cite_ok(by["ra"])
|
|
assert by["ra"].value == 800.0
|
|
assert by["ra"].source_type == "CABLE"
|
|
_cite_ok(by["voltage"])
|
|
assert by["voltage"].value == 4.75
|
|
assert by["voltage"].unit == "V"
|
|
assert by["voltage"].source.table == "Figure 4-39"
|
|
assert by["voltage"].source.page == "233"
|
|
assert "2.5" in by["voltage"].source.revision
|
|
assert by["voltage"].source_type == "CABLE"
|
|
assert any("not USB PD vSafe5V" in x for x in by["voltage"].conditions)
|
|
_cite_ok(by["vbus_requirements"])
|
|
assert by["vbus_requirements"].value == 4.0
|
|
assert by["vbus_requirements"].source.table == "Figure 4-39"
|
|
_cite_ok(by["electrical_thresholds"])
|
|
assert by["electrical_thresholds"].value == 1.50
|
|
assert by["electrical_thresholds"].source.table == "Table 4-32"
|
|
assert by["electrical_thresholds"].source.page == "240"
|
|
assert "August 2019" in by["electrical_thresholds"].source.revision
|
|
assert by["electrical_thresholds"].source_type == "PCB"
|
|
_cite_ok(by["vopen_source_default"])
|
|
assert by["vopen_source_default"].value == 1.65
|
|
_cite_ok(by["vra_source_default_max"])
|
|
assert by["vra_source_default_max"].value == 0.15
|
|
_cite_ok(by["vrd_detect_threshold_default"])
|
|
assert by["vrd_detect_threshold_default"].value == 1.60
|
|
_cite_ok(by["termination"])
|
|
assert by["termination"].value == 126000.0
|
|
assert by["termination"].source.table == "Table 4-30"
|
|
assert "2.5" in by["termination"].source.revision
|
|
assert by["termination"].source_type == "CONNECTOR"
|
|
_cite_ok(by["timing"])
|
|
assert by["timing"].value == 100.0
|
|
assert by["timing"].source.table == "Table 4-34"
|
|
assert "2.5" in by["timing"].source.revision
|
|
_cite_ok(by["t_vbuson_max"])
|
|
assert by["t_vbuson_max"].value == 275.0
|
|
assert by["t_vbuson_max"].source.table == "Table 4-32"
|
|
assert by["t_vbuson_max"].source.page == "247"
|
|
assert "2.5" in by["t_vbuson_max"].source.revision
|
|
assert by["vsafe5v"].value_kind == "UNKNOWN"
|
|
assert "vSafe5V" in (by["vsafe5v"].needed_document or "")
|
|
_cite_ok(by["gnd_ir_drop_cable"])
|
|
assert by["gnd_ir_drop_cable"].value == 250.0
|
|
assert by["gnd_ir_drop_cable"].source_type == "CABLE"
|
|
assert by["gnd_ir_drop_cable"].mandatory == "OPTIONAL"
|
|
_cite_ok(by["vbus_ir_drop_cable"])
|
|
assert by["vbus_ir_drop_cable"].value == 500.0
|
|
assert "Functional Test" in by["vbus_ir_drop_cable"].source.document
|
|
|
|
|
|
def test_dvi_not_hdmi_numeric_from_dvi_10():
|
|
cat = load_catalog()
|
|
logical = {p.id for p in cat.logical_protocols}
|
|
assert "dvi" in logical
|
|
assert "mini-hdmi" not in logical
|
|
dvi = next(p for p in cat.physical_interfaces if p.id == "dvi-1.0-tmds")
|
|
assert dvi.logical_protocol_id == "dvi"
|
|
assert dvi.connector == "DVI"
|
|
by = {c.parameter: c for c in dvi.constraints}
|
|
_cite_ok(by["termination"])
|
|
assert by["termination"].value == 50.0
|
|
assert by["termination"].source.table == "Table 4-2"
|
|
_cite_ok(by["differential_impedance"])
|
|
assert by["differential_impedance"].value == 100.0
|
|
assert by["differential_impedance"].source.table == "Table 4-7"
|
|
assert by["differential_impedance"].source.organization == "DDWG"
|
|
hdmi = next(p for p in cat.physical_interfaces if p.id == "hdmi-1.4-tmds-type-a")
|
|
hz = next(c for c in hdmi.constraints if c.parameter == "differential_impedance")
|
|
assert hz.value_kind == "UNKNOWN"
|
|
assert hz.value is None
|
|
h20 = next(p for p in cat.physical_interfaces if p.id == "hdmi-2.0-tmds-type-a")
|
|
z20 = next(c for c in h20.constraints if c.parameter == "differential_impedance")
|
|
_cite_ok(z20)
|
|
assert z20.value == 90.0
|
|
assert z20.source_class == "VENDOR"
|
|
assert z20.source_type == "VENDOR"
|
|
assert z20.mandatory == "RECOMMENDED"
|
|
assert "TMDS1204" in z20.source.document
|
|
assert z20.source_class != "NORMATIVE"
|
|
assert z20.source_type != "STANDARD"
|
|
skew20 = next(c for c in h20.constraints if c.parameter == "intra_pair_skew")
|
|
assert skew20.value_kind == "PHY_DEPENDENT"
|
|
assert skew20.value is None
|
|
assert skew20.source_type == "VENDOR"
|
|
assert skew20.source and "SLLSF57A" in (skew20.source.revision or "")
|
|
sig20 = next(c for c in h20.constraints if c.parameter == "sigdet_wakeup")
|
|
assert sig20.value_kind == "PHY_DEPENDENT"
|
|
assert sig20.source_type == "VENDOR"
|
|
assert "SLLA633" in (sig20.source.revision or "")
|
|
h14_skew = next(c for c in hdmi.constraints if c.parameter == "intra_pair_skew")
|
|
assert h14_skew.value_kind == "UNKNOWN"
|
|
hby = {c.parameter: c for c in hdmi.constraints}
|
|
_cite_ok(hby["cec"])
|
|
assert hby["cec"].value == 27000.0
|
|
assert hby["cec"].source.table == "CEC Table 2"
|
|
assert "1.3" in hby["cec"].source.revision
|
|
assert hby["cec"].source_type == "PCB"
|
|
_cite_ok(hby["cec_device_capacitance"])
|
|
assert hby["cec_device_capacitance"].value == 200.0
|
|
assert hby["cec_device_capacitance"].source.table == "Table 4-27"
|
|
_cite_ok(hby["cec_cable_capacitance"])
|
|
assert hby["cec_cable_capacitance"].value == 700.0
|
|
assert hby["cec_cable_capacitance"].source_type == "CABLE"
|
|
_cite_ok(hby["cec_vol_max"])
|
|
assert hby["cec_vol_max"].value == 0.6
|
|
_cite_ok(hby["cec_voh_min"])
|
|
assert hby["cec_voh_min"].value == 2.5
|
|
_cite_ok(hby["cec_interconnect_resistance"])
|
|
assert hby["cec_interconnect_resistance"].value == 5.0
|
|
frl = next(p for p in cat.physical_interfaces if p.id == "hdmi-frl-pcb")
|
|
fz = next(c for c in frl.constraints if c.parameter == "differential_impedance")
|
|
assert fz.value == 90.0
|
|
assert fz.source_class == "VENDOR"
|
|
assert fz.source_type == "VENDOR"
|
|
fdr = next(c for c in frl.constraints if c.parameter == "data_rate")
|
|
assert fdr.value_kind == "PHY_DEPENDENT"
|
|
assert fdr.value is None
|
|
assert fdr.source_class == "VENDOR"
|
|
assert fdr.source_type == "VENDOR"
|
|
sink = next(p for p in cat.physical_interfaces if p.id == "tmds1204-hdmi-sink")
|
|
assert sink.logical_protocol_id == "tmds1204"
|
|
sby = {c.parameter: c for c in sink.constraints}
|
|
_cite_ok(sby["differential_impedance"])
|
|
assert sby["differential_impedance"].value == 90.0
|
|
assert sby["differential_impedance"].source_type == "VENDOR"
|
|
assert sby["differential_impedance"].source_class == "VENDOR"
|
|
assert sby["differential_impedance"].mandatory == "RECOMMENDED"
|
|
assert sby["differential_impedance"].source.table == "Table 8-6"
|
|
assert sby["differential_impedance"].source.organization == "Texas Instruments"
|
|
assert "SLLSF57A" in sby["differential_impedance"].source.revision
|
|
assert sby["differential_impedance"].source_class != "NORMATIVE"
|
|
src = next(p for p in cat.physical_interfaces if p.id == "tmds1204-hdmi-source")
|
|
rby = {c.parameter: c for c in src.constraints}
|
|
assert rby["differential_impedance"].value == 75.0
|
|
assert rby["differential_impedance"].source.table == "Table 8-2"
|
|
assert rby["differential_impedance"].source_class == "VENDOR"
|
|
assert rby["differential_impedance"].source_type == "VENDOR"
|
|
assert sby["sigdet_wakeup"].value_kind == "PHY_DEPENDENT"
|
|
assert sby["sigdet_wakeup"].source_type == "VENDOR"
|
|
g = DesignGraph(
|
|
components={
|
|
"J3": Component(
|
|
reference="J3", value="DVI-D receptacle",
|
|
footprint="DVI_D",
|
|
component_type=ComponentType.CONNECTOR,
|
|
pins={"1": "TX0+"},
|
|
),
|
|
},
|
|
nets={"TX0+": Net(
|
|
name="TX0+", net_type=NetType.SIGNAL,
|
|
pins=[PinConnection(component_ref="J3", pin_number="1")],
|
|
)},
|
|
)
|
|
insts = recognize_physical_buses(g)
|
|
logs = {i.logical_protocol_id for i in insts}
|
|
assert "dvi" in logs
|
|
assert "hdmi-1.4" not in logs
|
|
assert "hdmi-2.0" not in logs
|
|
|
|
|
|
def test_ieee8023_section2_100base_tx_not_10base_or_1000():
|
|
cat = load_catalog()
|
|
tx = next(p for p in cat.physical_interfaces if p.id == "100base-tx-mdi")
|
|
by = {c.parameter: c for c in tx.constraints}
|
|
_cite_ok(by["data_rate"])
|
|
assert by["data_rate"].value == 100.0
|
|
assert by["data_rate"].source.document.startswith("IEEE Std 802.3-2012")
|
|
assert by["data_rate"].source.revision == "2012"
|
|
assert by["data_rate"].source.section == "21.1"
|
|
_cite_ok(by["cable_channel"])
|
|
assert by["cable_channel"].value == 100.0
|
|
assert by["cable_channel"].source_type == "CABLE"
|
|
assert by["cable_channel"].source.section == "25.4.9.2.2"
|
|
z = by["differential_impedance"]
|
|
assert z.value_kind == "UNKNOWN"
|
|
assert "TP-PMD" in (z.needed_document or "")
|
|
ten = next(p for p in cat.physical_interfaces if p.id == "10base-t-mdi")
|
|
tby = {c.parameter: c for c in ten.constraints}
|
|
_cite_ok(tby["data_rate"])
|
|
assert tby["data_rate"].value == 10.0
|
|
assert tby["data_rate"].source.revision == "2015"
|
|
assert tby["data_rate"].source.section == "14.1.1"
|
|
assert tby["data_rate"].source.page == "374"
|
|
_cite_ok(tby["cable_channel"])
|
|
assert tby["cable_channel"].value == 100.0
|
|
assert tby["cable_channel"].source_type == "CABLE"
|
|
assert tby["cable_channel"].source.section == "14.4.2.2"
|
|
assert tby["differential_impedance"].value_kind == "UNKNOWN"
|
|
assert "PCB" in (tby["differential_impedance"].needed_document or "")
|
|
gbe = next(p for p in cat.physical_interfaces if p.id == "1000base-t-mdi")
|
|
gby = {c.parameter: c for c in gbe.constraints}
|
|
_cite_ok(gby["data_rate"])
|
|
assert gby["data_rate"].value == 1000.0
|
|
assert gby["data_rate"].source.revision == "2012"
|
|
assert gby["data_rate"].source.section == "40.1"
|
|
assert gby["data_rate"].source.page == "179"
|
|
_cite_ok(gby["cable_channel"])
|
|
assert gby["cable_channel"].value == 100.0
|
|
assert gby["cable_channel"].source_type == "CABLE"
|
|
assert gby["cable_channel"].source.section == "40.7.2.2"
|
|
assert gby["differential_impedance"].value_kind == "UNKNOWN"
|
|
_cite_ok(gby["peak_differential_output"])
|
|
assert gby["peak_differential_output"].value == 0.67
|
|
assert gby["peak_differential_output"].source_type == "PHY"
|
|
x = next(p for p in cat.physical_interfaces if p.id == "1000base-x-pcb")
|
|
xr = next(c for c in x.constraints if c.parameter == "data_rate")
|
|
_cite_ok(xr)
|
|
assert xr.value == 1000.0
|
|
assert xr.source.section == "36.1.1"
|
|
fx = next(p for p in cat.physical_interfaces if p.id == "100base-fx-pcb")
|
|
fxr = next(c for c in fx.constraints if c.parameter == "data_rate")
|
|
_cite_ok(fxr)
|
|
assert fxr.value == 100.0
|
|
assert fxr.source.section == "26.1"
|