Fill protocol packs from recovered USB CTS, Type-C FTS, DVI 1.0, and IEEE 802.3-2012 Section Two (2.74.0).
NUMERIC rows cite document title, revision, section/table, and page. USB Zdiff, Type-C Rp/Rd, 10BASE-T, and 1000BASE-T stay UNKNOWN. PDFs are not in git.
This commit is contained in:
@@ -297,6 +297,25 @@ def parse_catalog(raw: Any) -> ProtocolCatalog:
|
|||||||
raise ProtocolCatalogError(str(exc)) from exc
|
raise ProtocolCatalogError(str(exc)) from exc
|
||||||
|
|
||||||
|
|
||||||
|
def _cite(
|
||||||
|
*,
|
||||||
|
document: str,
|
||||||
|
organization: str,
|
||||||
|
revision: str,
|
||||||
|
section: str | None = None,
|
||||||
|
table: str | None = None,
|
||||||
|
page: str | None = None,
|
||||||
|
) -> dict[str, str | None]:
|
||||||
|
return {
|
||||||
|
"document": document,
|
||||||
|
"organization": organization,
|
||||||
|
"revision": revision,
|
||||||
|
"section": section,
|
||||||
|
"table": table,
|
||||||
|
"page": page,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
def _c(
|
def _c(
|
||||||
iface_id: str,
|
iface_id: str,
|
||||||
parameter: str,
|
parameter: str,
|
||||||
@@ -310,6 +329,9 @@ def _c(
|
|||||||
conditions: list[str] | None = None,
|
conditions: list[str] | None = None,
|
||||||
measurement_method: MeasurementMethod | None = None,
|
measurement_method: MeasurementMethod | None = None,
|
||||||
needed_document: str | None = None,
|
needed_document: str | None = None,
|
||||||
|
value: float | None = None,
|
||||||
|
unit: str | None = None,
|
||||||
|
source: dict[str, Any] | None = None,
|
||||||
) -> dict[str, Any]:
|
) -> dict[str, Any]:
|
||||||
row: dict[str, Any] = {
|
row: dict[str, Any] = {
|
||||||
"id": f"{iface_id}-{parameter}",
|
"id": f"{iface_id}-{parameter}",
|
||||||
@@ -318,12 +340,12 @@ def _c(
|
|||||||
"mandatory": mandatory,
|
"mandatory": mandatory,
|
||||||
"source_type": source_type,
|
"source_type": source_type,
|
||||||
"source_class": source_class,
|
"source_class": source_class,
|
||||||
"value": None,
|
"value": value,
|
||||||
"unit": None,
|
"unit": unit,
|
||||||
"source": None,
|
"source": source,
|
||||||
"conditions": conditions or [],
|
"conditions": conditions or [],
|
||||||
"value_origin": "SPEC",
|
"value_origin": value_origin,
|
||||||
"typical": False,
|
"typical": typical,
|
||||||
}
|
}
|
||||||
if measurement_method:
|
if measurement_method:
|
||||||
row["measurement_method"] = measurement_method
|
row["measurement_method"] = measurement_method
|
||||||
@@ -337,6 +359,47 @@ def _c(
|
|||||||
return row
|
return row
|
||||||
|
|
||||||
|
|
||||||
|
def _num(
|
||||||
|
iface_id: str,
|
||||||
|
parameter: str,
|
||||||
|
value: float,
|
||||||
|
unit: str,
|
||||||
|
*,
|
||||||
|
document: str,
|
||||||
|
organization: str,
|
||||||
|
revision: str,
|
||||||
|
section: str | None = None,
|
||||||
|
table: str | None = None,
|
||||||
|
page: str | None = None,
|
||||||
|
mandatory: MandatoryClass = "MANDATORY",
|
||||||
|
source_type: SourceType = "STANDARD",
|
||||||
|
source_class: SourceClass = "NORMATIVE",
|
||||||
|
conditions: list[str] | None = None,
|
||||||
|
measurement_method: MeasurementMethod | None = None,
|
||||||
|
) -> dict[str, Any]:
|
||||||
|
"""NUMERIC row. Every field carries title, revision, section/table, page."""
|
||||||
|
return _c(
|
||||||
|
iface_id,
|
||||||
|
parameter,
|
||||||
|
"NUMERIC",
|
||||||
|
mandatory=mandatory,
|
||||||
|
source_type=source_type,
|
||||||
|
source_class=source_class,
|
||||||
|
conditions=conditions,
|
||||||
|
measurement_method=measurement_method,
|
||||||
|
value=value,
|
||||||
|
unit=unit,
|
||||||
|
source=_cite(
|
||||||
|
document=document,
|
||||||
|
organization=organization,
|
||||||
|
revision=revision,
|
||||||
|
section=section,
|
||||||
|
table=table,
|
||||||
|
page=page,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def _skel_constraints(
|
def _skel_constraints(
|
||||||
iface_id: str,
|
iface_id: str,
|
||||||
parameters: list[str],
|
parameters: list[str],
|
||||||
@@ -472,20 +535,77 @@ HDMI_CHECKS = [
|
|||||||
"cec",
|
"cec",
|
||||||
"hpd",
|
"hpd",
|
||||||
]
|
]
|
||||||
|
DVI_CHECKS = [
|
||||||
|
"termination",
|
||||||
|
"differential_impedance",
|
||||||
|
"impedance_tolerance",
|
||||||
|
"rise_time",
|
||||||
|
"fall_time",
|
||||||
|
"intra_pair_skew",
|
||||||
|
"inter_lane_skew",
|
||||||
|
"electrical_levels",
|
||||||
|
"voltage",
|
||||||
|
"connector_requirements",
|
||||||
|
"data_rate",
|
||||||
|
"vias",
|
||||||
|
"stubs",
|
||||||
|
"return_path",
|
||||||
|
"topology",
|
||||||
|
]
|
||||||
|
# Recovered PDFs (USB Electrical CTS v1.08, Type-C Functional Test Rev 0.91, DVI 1.0).
|
||||||
|
# IEEE 802.3 is not on file — do not fill Ethernet numbers from these documents.
|
||||||
|
DOC_USB_CTS_108 = "USB 2.0 Electrical Compliance Test Specification"
|
||||||
|
REV_USB_CTS_108 = "Version 1.08, April 2026"
|
||||||
|
ORG_USBIF = "USB-IF"
|
||||||
|
DOC_USBC_FTS = (
|
||||||
|
"Universal Serial Bus Type-C Functional Test Specification Chapters 4 and 5"
|
||||||
|
)
|
||||||
|
REV_USBC_FTS = "Revision 0.91, March 3, 2024"
|
||||||
|
DOC_DVI_10 = "Digital Visual Interface (DVI)"
|
||||||
|
REV_DVI_10 = "Revision 1.0, 02 April 1999"
|
||||||
|
ORG_DDWG = "DDWG"
|
||||||
DOC_USB_BASE = (
|
DOC_USB_BASE = (
|
||||||
"USB-IF Base Specification (revision to fix when PDF is provided)"
|
"USB-IF USB 2.0 Specification (not on file; Electrical CTS v1.08 does not state this field)"
|
||||||
)
|
)
|
||||||
DOC_USB_ELEC = (
|
DOC_USB_ELEC = (
|
||||||
"USB-IF Electrical Compliance Specification (revision to fix when PDF is provided)"
|
"USB 2.0 Electrical Compliance Test Specification Version 1.08 April 2026 "
|
||||||
|
"(recovered; this PCB limit is not stated in the CTS)"
|
||||||
)
|
)
|
||||||
DOC_USB_CABLE = (
|
DOC_USB_CABLE = (
|
||||||
"USB-IF Cable and Connector Specification (revision to fix when PDF is provided)"
|
"USB Type-C Cable and Connector Specification (not on file; "
|
||||||
|
"Functional Test Spec Rev 0.91 references Table 4-15 / 4.4.2 without stating ohms or volts)"
|
||||||
)
|
)
|
||||||
DOC_USB_CTS = (
|
DOC_USB_CTS = DOC_USB_CTS_108 + " " + REV_USB_CTS_108
|
||||||
"USB-IF Compliance Test Specification (revision to fix when PDF is provided)"
|
DOC_USB_ECN = "USB ENGINEERING CHANGE NOTICE USB 2.0 DC Resistance (cited by Electrical CTS v1.08 §3.9)"
|
||||||
|
DOC_USB_LSFS = (
|
||||||
|
"USB 2.0 Specification LS/FS electrical (not on file; Electrical CTS v1.08 "
|
||||||
|
"§2 lists LS/FS test names without numeric criteria)"
|
||||||
)
|
)
|
||||||
DOC_USB_ECN = "USB-IF ECN applicable to the revision used"
|
|
||||||
DOC_IEEE_8023 = "IEEE 802.3 (clause for this variant; not on file)"
|
DOC_IEEE_8023 = "IEEE 802.3 (clause for this variant; not on file)"
|
||||||
|
DOC_IEEE_2012 = "IEEE Std 802.3-2012 IEEE Standard for Ethernet"
|
||||||
|
REV_IEEE_2012 = "2012"
|
||||||
|
ORG_IEEE = "IEEE"
|
||||||
|
DOC_IEEE_S1_C14 = (
|
||||||
|
"IEEE Std 802.3-2012 Section One Clause 14 (10BASE-T; not in Section Two)"
|
||||||
|
)
|
||||||
|
DOC_IEEE_S3_C40 = (
|
||||||
|
"IEEE Std 802.3-2012 Section Three Clause 40 (1000BASE-T; not in Section Two)"
|
||||||
|
)
|
||||||
|
DOC_IEEE_S3_C36 = (
|
||||||
|
"IEEE Std 802.3-2012 Section Three (1000BASE-X; not in Section Two)"
|
||||||
|
)
|
||||||
|
DOC_IEEE_TP_PMD = (
|
||||||
|
"ANSI X3.263:1995 TP-PMD (incorporated by IEEE 802.3-2012 Clause 25; not on file. "
|
||||||
|
"Section Two states 100 Ω as cabling/link-segment and as a ±1% test termination, "
|
||||||
|
"not as a PCB trace differential impedance)"
|
||||||
|
)
|
||||||
|
DOC_IEEE_OTHER = {
|
||||||
|
"2.5gbase-t": "IEEE 802.3bz / later 802.3 2.5GBASE-T clause (not in 2012 Section Two)",
|
||||||
|
"5gbase-t": "IEEE 802.3bz / later 802.3 5GBASE-T clause (not in 2012 Section Two)",
|
||||||
|
"10gbase-t": "IEEE Std 802.3-2012 Section Four Clause 55 (10GBASE-T; not in Section Two)",
|
||||||
|
"sgmii": "SGMII is not an IEEE 802.3 MDI clause in 2012 Section Two",
|
||||||
|
"10gbase-r": "IEEE 802.3 10GBASE-R clauses (not in 2012 Section Two)",
|
||||||
|
}
|
||||||
DOC_HDMI_ADOPTER = (
|
DOC_HDMI_ADOPTER = (
|
||||||
"HDMI Adopter specification (not on file; 1.4 vs 2.x vs FRL must not be mixed)"
|
"HDMI Adopter specification (not on file; 1.4 vs 2.x vs FRL must not be mixed)"
|
||||||
)
|
)
|
||||||
@@ -573,7 +693,7 @@ HYPERBUS_CHECKS = [
|
|||||||
|
|
||||||
|
|
||||||
def build_m0_catalog() -> dict[str, Any]:
|
def build_m0_catalog() -> dict[str, Any]:
|
||||||
"""Skeleton catalog. No numeric USB/ETH/HDMI/DDR values."""
|
"""Catalog. NUMERIC only with recovered-PDF cites. No invented ohms."""
|
||||||
logical: list[dict[str, Any]] = []
|
logical: list[dict[str, Any]] = []
|
||||||
physical: list[dict[str, Any]] = []
|
physical: list[dict[str, Any]] = []
|
||||||
|
|
||||||
@@ -612,6 +732,8 @@ def build_m0_catalog() -> dict[str, Any]:
|
|||||||
L("hdmi-2.0", "HDMI 2.0 TMDS", "SERIAL", "HDMI")
|
L("hdmi-2.0", "HDMI 2.0 TMDS", "SERIAL", "HDMI")
|
||||||
L("hdmi-frl", "HDMI FRL mode", "SERIAL", "HDMI",
|
L("hdmi-frl", "HDMI FRL mode", "SERIAL", "HDMI",
|
||||||
"FRL is distinct from TMDS. Do not copy TMDS numbers onto FRL.")
|
"FRL is distinct from TMDS. Do not copy TMDS numbers onto FRL.")
|
||||||
|
L("dvi", "DVI 1.0 TMDS", "SERIAL", "DVI",
|
||||||
|
"DVI is not HDMI. Numbers from DDWG DVI Revision 1.0 only.")
|
||||||
L("ddr-family", "DDR family (abstract)", "MEMORY", "DDR")
|
L("ddr-family", "DDR family (abstract)", "MEMORY", "DDR")
|
||||||
for gen, title in (
|
for gen, title in (
|
||||||
("ddr1", "DDR1"), ("ddr2", "DDR2"), ("ddr3", "DDR3"),
|
("ddr1", "DDR1"), ("ddr2", "DDR2"), ("ddr3", "DDR3"),
|
||||||
@@ -667,22 +789,22 @@ def build_m0_catalog() -> dict[str, Any]:
|
|||||||
L("can", "CAN / CAN FD", "PERIPHERAL", "CAN")
|
L("can", "CAN / CAN FD", "PERIPHERAL", "CAN")
|
||||||
L("rgmii", "RGMII MAC-PHY", "PERIPHERAL", "ETHERNET")
|
L("rgmii", "RGMII MAC-PHY", "PERIPHERAL", "ETHERNET")
|
||||||
|
|
||||||
def _usb2_cons(pid: str) -> list[dict[str, Any]]:
|
def _usb2_cons(pid: str, *, hs: bool = False) -> list[dict[str, Any]]:
|
||||||
docs = {
|
docs = {
|
||||||
"differential_impedance": DOC_USB_ELEC,
|
"differential_impedance": DOC_USB_ELEC if hs else DOC_USB_LSFS,
|
||||||
"impedance_tolerance": DOC_USB_ELEC,
|
"impedance_tolerance": DOC_USB_ELEC if hs else DOC_USB_LSFS,
|
||||||
"electrical_levels": DOC_USB_ELEC,
|
"electrical_levels": DOC_USB_ELEC if hs else DOC_USB_LSFS,
|
||||||
"rise_time": DOC_USB_ELEC,
|
"rise_time": DOC_USB_ELEC if hs else DOC_USB_LSFS,
|
||||||
"fall_time": DOC_USB_ELEC,
|
"fall_time": DOC_USB_ELEC if hs else DOC_USB_LSFS,
|
||||||
"intra_pair_skew": DOC_USB_ELEC,
|
"intra_pair_skew": DOC_USB_ELEC if hs else DOC_USB_LSFS,
|
||||||
"termination": DOC_USB_ELEC,
|
"termination": DOC_USB_ELEC if hs else DOC_USB_LSFS,
|
||||||
"dc_resistance": DOC_USB_ELEC,
|
"dc_resistance": DOC_USB_ELEC if hs else DOC_USB_LSFS,
|
||||||
"connector_requirements": DOC_USB_CABLE,
|
"connector_requirements": DOC_USB_CABLE,
|
||||||
"vbus_requirements": DOC_USB_BASE,
|
"vbus_requirements": DOC_USB_BASE,
|
||||||
"pull_up": DOC_USB_BASE,
|
"pull_up": DOC_USB_BASE if not hs else DOC_USB_ELEC,
|
||||||
"pull_down": DOC_USB_BASE,
|
"pull_down": DOC_USB_BASE,
|
||||||
"signaling": DOC_USB_BASE,
|
"signaling": DOC_USB_BASE if not hs else DOC_USB_CTS_108,
|
||||||
"data_rate": DOC_USB_BASE,
|
"data_rate": DOC_USB_LSFS if not hs else DOC_USB_CTS_108,
|
||||||
"test_method": DOC_USB_CTS,
|
"test_method": DOC_USB_CTS,
|
||||||
"compliance_test": DOC_USB_CTS,
|
"compliance_test": DOC_USB_CTS,
|
||||||
}
|
}
|
||||||
@@ -690,10 +812,62 @@ def build_m0_catalog() -> dict[str, Any]:
|
|||||||
out = []
|
out = []
|
||||||
for p in USB2_CHECKS:
|
for p in USB2_CHECKS:
|
||||||
mand: MandatoryClass = "RECOMMENDED" if p in rec else "MANDATORY"
|
mand: MandatoryClass = "RECOMMENDED" if p in rec else "MANDATORY"
|
||||||
|
if hs and p == "data_rate":
|
||||||
|
out.append(_num(
|
||||||
|
pid, p, 480.0, "Mb/s",
|
||||||
|
document=DOC_USB_CTS_108, organization=ORG_USBIF,
|
||||||
|
revision=REV_USB_CTS_108, section="3.2 EL_2", page="3",
|
||||||
|
conditions=["HS transmitter", "tolerance ±0.05%"],
|
||||||
|
))
|
||||||
|
continue
|
||||||
|
if hs and p in {"rise_time", "fall_time"}:
|
||||||
|
out.append(_num(
|
||||||
|
pid, p, 300.0, "ps",
|
||||||
|
document=DOC_USB_CTS_108, organization=ORG_USBIF,
|
||||||
|
revision=REV_USB_CTS_108, section="3.2 EL_6", page="3",
|
||||||
|
conditions=[
|
||||||
|
"HS driver 10% to 90% differential",
|
||||||
|
"minimum greater than 300 ps",
|
||||||
|
],
|
||||||
|
))
|
||||||
|
continue
|
||||||
|
if hs and p == "pull_up":
|
||||||
|
out.append(_num(
|
||||||
|
pid, p, 1500.0, "ohm",
|
||||||
|
document=DOC_USB_CTS_108, organization=ORG_USBIF,
|
||||||
|
revision=REV_USB_CTS_108, section="3.5 EL_31", page="4",
|
||||||
|
conditions=["device speed detection 1.5K pull-up"],
|
||||||
|
))
|
||||||
|
continue
|
||||||
|
if hs and p == "dc_resistance":
|
||||||
|
out.append(_num(
|
||||||
|
pid, p, 17.0, "ohm",
|
||||||
|
document=DOC_USB_CTS_108, organization=ORG_USBIF,
|
||||||
|
revision=REV_USB_CTS_108, section="3.9.1", page="7",
|
||||||
|
conditions=[
|
||||||
|
"HS device-only upstream",
|
||||||
|
"D+ and D- individually",
|
||||||
|
"maximum series DC resistance",
|
||||||
|
],
|
||||||
|
))
|
||||||
|
continue
|
||||||
out.append(_c(
|
out.append(_c(
|
||||||
pid, p, "UNKNOWN",
|
pid, p, "UNKNOWN",
|
||||||
mandatory=mand,
|
mandatory=mand,
|
||||||
needed_document=docs.get(p, DOC_USB_BASE),
|
needed_document=docs.get(p, DOC_USB_LSFS if not hs else DOC_USB_BASE),
|
||||||
|
))
|
||||||
|
if hs:
|
||||||
|
out.append(_num(
|
||||||
|
pid, "dc_resistance_captive_cable_device", 23.0, "ohm",
|
||||||
|
document=DOC_USB_CTS_108, organization=ORG_USBIF,
|
||||||
|
revision=REV_USB_CTS_108, section="3.9.1", page="7",
|
||||||
|
conditions=["HS captive-cable device", "D+ and D- individually", "maximum"],
|
||||||
|
))
|
||||||
|
out.append(_num(
|
||||||
|
pid, "dc_resistance_host_hub_downstream", 13.0, "ohm",
|
||||||
|
document=DOC_USB_CTS_108, organization=ORG_USBIF,
|
||||||
|
revision=REV_USB_CTS_108, section="3.9.2", page="7",
|
||||||
|
conditions=["HS host/hub or dual-role device downstream", "D+ and D- individually", "maximum"],
|
||||||
))
|
))
|
||||||
return out
|
return out
|
||||||
|
|
||||||
@@ -704,21 +878,122 @@ def build_m0_catalog() -> dict[str, Any]:
|
|||||||
doc = DOC_USB_CABLE if p in cable else DOC_USB_ELEC
|
doc = DOC_USB_CABLE if p in cable else DOC_USB_ELEC
|
||||||
if p == "usb2_channel_requirements":
|
if p == "usb2_channel_requirements":
|
||||||
doc = DOC_USB_ELEC
|
doc = DOC_USB_ELEC
|
||||||
|
if p in {"vbus_requirements", "voltage"}:
|
||||||
|
doc = DOC_USB_CABLE
|
||||||
out.append(_c(pid, p, "UNKNOWN", needed_document=doc))
|
out.append(_c(pid, p, "UNKNOWN", needed_document=doc))
|
||||||
|
out.append(_num(
|
||||||
|
pid, "gnd_ir_drop_cable", 250.0, "mV",
|
||||||
|
document=DOC_USBC_FTS, organization=ORG_USBIF,
|
||||||
|
revision=REV_USBC_FTS, section="4.4.1#1", page="10",
|
||||||
|
mandatory="OPTIONAL", source_type="CABLE",
|
||||||
|
conditions=["cable IR drop for ground; not a receptacle PCB ohm"],
|
||||||
|
))
|
||||||
|
out.append(_num(
|
||||||
|
pid, "vbus_ir_drop_cable", 500.0, "mV",
|
||||||
|
document=DOC_USBC_FTS, organization=ORG_USBIF,
|
||||||
|
revision=REV_USBC_FTS, section="4.4.1#1", page="10",
|
||||||
|
mandatory="OPTIONAL", source_type="CABLE",
|
||||||
|
conditions=["cable IR drop for VBUS; not a receptacle PCB ohm"],
|
||||||
|
))
|
||||||
return out
|
return out
|
||||||
|
|
||||||
def _eth_cons(pid: str, *, phy: bool = False) -> list[dict[str, Any]]:
|
def _eth_cons(pid: str, lid: str) -> list[dict[str, Any]]:
|
||||||
|
if lid == "10base-t":
|
||||||
|
missing = DOC_IEEE_S1_C14
|
||||||
|
elif lid == "1000base-t":
|
||||||
|
missing = DOC_IEEE_S3_C40
|
||||||
|
elif lid == "1000base-x":
|
||||||
|
missing = DOC_IEEE_S3_C36
|
||||||
|
elif lid == "100base-tx":
|
||||||
|
missing = DOC_IEEE_TP_PMD
|
||||||
|
elif lid == "100base-fx":
|
||||||
|
missing = (
|
||||||
|
"ISO/IEC 9314-3:1990 fiber-PMD (incorporated by IEEE 802.3-2012 Clause 26; "
|
||||||
|
"optical MDI, not copper PCB ohms)"
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
missing = DOC_IEEE_OTHER.get(lid, DOC_IEEE_8023)
|
||||||
out = []
|
out = []
|
||||||
for p in ETH_CHECKS:
|
for p in ETH_CHECKS:
|
||||||
if p in {"phy_requirements", "magnetics_requirements"} or phy:
|
if p in {"phy_requirements", "magnetics_requirements"}:
|
||||||
if p in {"phy_requirements", "magnetics_requirements"}:
|
out.append(_c(
|
||||||
out.append(_c(
|
pid, p, "PHY_DEPENDENT",
|
||||||
pid, p, "PHY_DEPENDENT",
|
source_type="PHY", source_class="VENDOR",
|
||||||
source_type="PHY", source_class="VENDOR",
|
needed_document="PHY vendor datasheet (not IEEE-universal)",
|
||||||
needed_document="PHY vendor datasheet (not IEEE-universal)",
|
))
|
||||||
))
|
continue
|
||||||
continue
|
if lid == "100base-tx" and p == "data_rate":
|
||||||
out.append(_c(pid, p, "UNKNOWN", needed_document=DOC_IEEE_8023))
|
out.append(_num(
|
||||||
|
pid, p, 100.0, "Mb/s",
|
||||||
|
document=DOC_IEEE_2012, organization=ORG_IEEE,
|
||||||
|
revision=REV_IEEE_2012, section="21.1", page="39",
|
||||||
|
conditions=["100BASE-T family including 100BASE-TX"],
|
||||||
|
))
|
||||||
|
continue
|
||||||
|
if lid == "100base-tx" and p == "maximum_channel_length":
|
||||||
|
out.append(_num(
|
||||||
|
pid, p, 100.0, "m",
|
||||||
|
document=DOC_IEEE_2012, organization=ORG_IEEE,
|
||||||
|
revision=REV_IEEE_2012, section="25.4.9.2", page="232",
|
||||||
|
source_type="CABLE",
|
||||||
|
conditions=["Category 5 link segment of up to 100 m"],
|
||||||
|
))
|
||||||
|
continue
|
||||||
|
if lid == "100base-tx" and p == "cable_channel":
|
||||||
|
out.append(_num(
|
||||||
|
pid, p, 100.0, "ohm",
|
||||||
|
document=DOC_IEEE_2012, organization=ORG_IEEE,
|
||||||
|
revision=REV_IEEE_2012, section="25.4.9.2.2", page="232",
|
||||||
|
source_type="CABLE",
|
||||||
|
conditions=[
|
||||||
|
"nominal differential characteristic impedance of the link segment",
|
||||||
|
"1 MHz to 100 MHz including cords and connecting hardware",
|
||||||
|
"not a PCB trace differential impedance",
|
||||||
|
],
|
||||||
|
))
|
||||||
|
continue
|
||||||
|
if lid == "100base-fx" and p == "data_rate":
|
||||||
|
out.append(_num(
|
||||||
|
pid, p, 100.0, "Mb/s",
|
||||||
|
document=DOC_IEEE_2012, organization=ORG_IEEE,
|
||||||
|
revision=REV_IEEE_2012, section="26.1", page="245",
|
||||||
|
conditions=["100BASE-FX"],
|
||||||
|
))
|
||||||
|
continue
|
||||||
|
if lid == "100base-fx" and p == "differential_impedance":
|
||||||
|
out.append(_c(
|
||||||
|
pid, p, "NOT_APPLICABLE",
|
||||||
|
mandatory="INFORMATIONAL", source_type="STANDARD",
|
||||||
|
conditions=["optical fiber MDI"],
|
||||||
|
))
|
||||||
|
continue
|
||||||
|
nd = missing
|
||||||
|
if lid == "100base-tx" and p in {
|
||||||
|
"differential_impedance", "impedance_tolerance", "termination",
|
||||||
|
}:
|
||||||
|
nd = DOC_IEEE_TP_PMD
|
||||||
|
out.append(_c(pid, p, "UNKNOWN", needed_document=nd))
|
||||||
|
if lid == "100base-tx":
|
||||||
|
out.append(_num(
|
||||||
|
pid, "isolation_after_test", 2.0e6, "ohm",
|
||||||
|
document=DOC_IEEE_2012, organization=ORG_IEEE,
|
||||||
|
revision=REV_IEEE_2012, section="25.4.6", page="231",
|
||||||
|
conditions=[
|
||||||
|
"PMD MDI that is not a PI",
|
||||||
|
"resistance after isolation test, measured at 500 V dc",
|
||||||
|
"minimum 2 MΩ",
|
||||||
|
],
|
||||||
|
))
|
||||||
|
out.append(_num(
|
||||||
|
pid, "isolation_rms", 1500.0, "V",
|
||||||
|
document=DOC_IEEE_2012, organization=ORG_IEEE,
|
||||||
|
revision=REV_IEEE_2012, section="25.4.6 a", page="231",
|
||||||
|
mandatory="OPTIONAL",
|
||||||
|
conditions=[
|
||||||
|
"one of three allowed isolation tests",
|
||||||
|
"1500 V rms at 50 Hz to 60 Hz for 60 s",
|
||||||
|
],
|
||||||
|
))
|
||||||
return out
|
return out
|
||||||
|
|
||||||
def _hdmi_cons(pid: str) -> list[dict[str, Any]]:
|
def _hdmi_cons(pid: str) -> list[dict[str, Any]]:
|
||||||
@@ -727,17 +1002,102 @@ def build_m0_catalog() -> dict[str, Any]:
|
|||||||
for p in HDMI_CHECKS
|
for p in HDMI_CHECKS
|
||||||
]
|
]
|
||||||
|
|
||||||
for lid, pid, hints, note in (
|
def _dvi_cons(pid: str) -> list[dict[str, Any]]:
|
||||||
("usb2-ls", "usb2-ls-dpair", ["USB_D+", "USB_LS"], "USB 2.0 Low Speed. No invented Z."),
|
out = []
|
||||||
("usb2-fs", "usb2-fs-dpair", ["USB_D+", "USB_FS"], "USB 2.0 Full Speed. No invented Z."),
|
for p in DVI_CHECKS:
|
||||||
|
if p == "termination":
|
||||||
|
out.append(_num(
|
||||||
|
pid, p, 50.0, "ohm",
|
||||||
|
document=DOC_DVI_10, organization=ORG_DDWG,
|
||||||
|
revision=REV_DVI_10, section="4.2", table="Table 4-2", page="35",
|
||||||
|
conditions=["TMDS termination resistance", "±10%"],
|
||||||
|
))
|
||||||
|
continue
|
||||||
|
if p == "differential_impedance":
|
||||||
|
out.append(_num(
|
||||||
|
pid, p, 100.0, "ohm",
|
||||||
|
document=DOC_DVI_10, organization=ORG_DDWG,
|
||||||
|
revision=REV_DVI_10, section="4.4", table="Table 4-7", page="38",
|
||||||
|
conditions=["receiver at termination", "±10%"],
|
||||||
|
))
|
||||||
|
continue
|
||||||
|
if p == "impedance_tolerance":
|
||||||
|
out.append(_num(
|
||||||
|
pid, p, 10.0, "percent",
|
||||||
|
document=DOC_DVI_10, organization=ORG_DDWG,
|
||||||
|
revision=REV_DVI_10, section="4.4", table="Table 4-7", page="38",
|
||||||
|
conditions=["at termination ±10%"],
|
||||||
|
))
|
||||||
|
continue
|
||||||
|
if p in {"rise_time", "fall_time"}:
|
||||||
|
out.append(_num(
|
||||||
|
pid, p, 75.0, "ps",
|
||||||
|
document=DOC_DVI_10, organization=ORG_DDWG,
|
||||||
|
revision=REV_DVI_10, section="4.3", table="Table 4-4", page="36",
|
||||||
|
conditions=["20%–80%", "minimum 75 ps", "maximum 0.4 Tbit"],
|
||||||
|
))
|
||||||
|
continue
|
||||||
|
if p == "intra_pair_skew":
|
||||||
|
out.append(_num(
|
||||||
|
pid, p, 0.15, "Tbit",
|
||||||
|
document=DOC_DVI_10, organization=ORG_DDWG,
|
||||||
|
revision=REV_DVI_10, section="4.3", table="Table 4-4", page="36",
|
||||||
|
conditions=["transmitter connector maximum"],
|
||||||
|
))
|
||||||
|
continue
|
||||||
|
if p == "inter_lane_skew":
|
||||||
|
out.append(_num(
|
||||||
|
pid, p, 0.20, "Tpixel",
|
||||||
|
document=DOC_DVI_10, organization=ORG_DDWG,
|
||||||
|
revision=REV_DVI_10, section="4.3", table="Table 4-4", page="36",
|
||||||
|
conditions=["transmitter connector maximum"],
|
||||||
|
))
|
||||||
|
continue
|
||||||
|
if p == "electrical_levels":
|
||||||
|
out.append(_num(
|
||||||
|
pid, p, 400.0, "mV",
|
||||||
|
document=DOC_DVI_10, organization=ORG_DDWG,
|
||||||
|
revision=REV_DVI_10, section="4.3", table="Table 4-3", page="35",
|
||||||
|
conditions=["single-ended Vswing minimum 400 mV", "maximum 600 mV"],
|
||||||
|
))
|
||||||
|
continue
|
||||||
|
if p == "voltage":
|
||||||
|
out.append(_num(
|
||||||
|
pid, p, 3.3, "V",
|
||||||
|
document=DOC_DVI_10, organization=ORG_DDWG,
|
||||||
|
revision=REV_DVI_10, section="4.2", table="Table 4-2", page="35",
|
||||||
|
conditions=["AVcc termination supply", "±5%"],
|
||||||
|
))
|
||||||
|
continue
|
||||||
|
out.append(_c(
|
||||||
|
pid, p, "UNKNOWN",
|
||||||
|
needed_document=(
|
||||||
|
"Digital Visual Interface (DVI) Revision 1.0 (recovered; this field is not a "
|
||||||
|
"single PCB number in the cited tables)"
|
||||||
|
),
|
||||||
|
))
|
||||||
|
out.append(_num(
|
||||||
|
pid, "through_connection_impedance", 100.0, "ohm",
|
||||||
|
document=DOC_DVI_10, organization=ORG_DDWG,
|
||||||
|
revision=REV_DVI_10, section="4.4", table="Table 4-7", page="38",
|
||||||
|
source_type="CONNECTOR",
|
||||||
|
conditions=["through a mated connector", "±20%"],
|
||||||
|
))
|
||||||
|
return out
|
||||||
|
|
||||||
|
for lid, pid, hints, note, hs in (
|
||||||
|
("usb2-ls", "usb2-ls-dpair", ["USB_D+", "USB_LS"],
|
||||||
|
"USB 2.0 Low Speed. Electrical CTS v1.08 lists LS tests without numeric criteria.", False),
|
||||||
|
("usb2-fs", "usb2-fs-dpair", ["USB_D+", "USB_FS"],
|
||||||
|
"USB 2.0 Full Speed. Electrical CTS v1.08 lists FS tests without numeric criteria.", False),
|
||||||
("usb2-ls-fs", "usb2-ls-fs-dpair", ["USB_D+", "USB_D-", "USB_DP", "USB_DM", "D+", "D-"],
|
("usb2-ls-fs", "usb2-ls-fs-dpair", ["USB_D+", "USB_D-", "USB_DP", "USB_DM", "D+", "D-"],
|
||||||
"LS/FS umbrella pair. No invented Z."),
|
"LS/FS umbrella pair. No LS/FS ohms in Electrical CTS v1.08.", False),
|
||||||
("usb2-hs", "usb2-hs-dpair", ["USB_D+", "USB_D-", "USB_HS"],
|
("usb2-hs", "usb2-hs-dpair", ["USB_D+", "USB_D-", "USB_HS"],
|
||||||
"USB 2.0 High Speed. USB-IF cite required before NUMERIC Z."),
|
"USB 2.0 High Speed. Zdiff is not stated in Electrical CTS v1.08 (do not invent differential ohms).", True),
|
||||||
):
|
):
|
||||||
physical.append(_iface(
|
physical.append(_iface(
|
||||||
pid, lid, "SERIAL", "SERIAL_DIFFERENTIAL", "YES",
|
pid, lid, "SERIAL", "SERIAL_DIFFERENTIAL", "YES",
|
||||||
USB2_CHECKS, _usb2_cons(pid),
|
USB2_CHECKS, _usb2_cons(pid, hs=hs),
|
||||||
hints=hints, notes=note,
|
hints=hints, notes=note,
|
||||||
))
|
))
|
||||||
physical.append(_iface(
|
physical.append(_iface(
|
||||||
@@ -750,7 +1110,7 @@ def build_m0_catalog() -> dict[str, Any]:
|
|||||||
"No invented Rd/Rp ohms."
|
"No invented Rd/Rp ohms."
|
||||||
),
|
),
|
||||||
))
|
))
|
||||||
usb2_over_c = _usb2_cons("usb-c-usb2-receptacle")
|
usb2_over_c = _usb2_cons("usb-c-usb2-receptacle", hs=True)
|
||||||
seen_p = {c["parameter"] for c in usb2_over_c}
|
seen_p = {c["parameter"] for c in usb2_over_c}
|
||||||
for c in _usbc_cons("usb-c-usb2-receptacle"):
|
for c in _usbc_cons("usb-c-usb2-receptacle"):
|
||||||
if c["parameter"] not in seen_p:
|
if c["parameter"] not in seen_p:
|
||||||
@@ -841,11 +1201,14 @@ def build_m0_catalog() -> dict[str, Any]:
|
|||||||
conn = "none" if lid in {"sgmii", "1000base-x", "100base-fx", "10gbase-r"} else "RJ45"
|
conn = "none" if lid in {"sgmii", "1000base-x", "100base-fx", "10gbase-r"} else "RJ45"
|
||||||
physical.append(_iface(
|
physical.append(_iface(
|
||||||
pid, lid, "SERIAL", "SERIAL_DIFFERENTIAL", "YES",
|
pid, lid, "SERIAL", "SERIAL_DIFFERENTIAL", "YES",
|
||||||
ETH_CHECKS, _eth_cons(pid),
|
ETH_CHECKS, _eth_cons(pid, lid),
|
||||||
connector=conn, hints=hints,
|
connector=conn, hints=hints,
|
||||||
notes=(
|
notes=(
|
||||||
f"Incomplete skeleton: IEEE 802.3 not on file. "
|
"IEEE 802.3-2012 Section Two (Clauses 21–33) on file. "
|
||||||
f"IEEE vs PHY vs PCB vs magnetics are distinct. Not auto from RJ45."
|
"10BASE-T is Clause 14 (Section One, not here). "
|
||||||
|
"1000BASE-T is Clause 40 (Section Three, not here). "
|
||||||
|
"100 Ω in Clause 25 is cabling/link-segment, not PCB Z. "
|
||||||
|
"Not auto from RJ45. IEEE vs PHY vs PCB vs magnetics are distinct."
|
||||||
),
|
),
|
||||||
incomplete=True,
|
incomplete=True,
|
||||||
))
|
))
|
||||||
@@ -875,6 +1238,16 @@ def build_m0_catalog() -> dict[str, Any]:
|
|||||||
notes="HDMI FRL is distinct from TMDS. Do not apply TMDS rules. UNKNOWN until Adopter spec.",
|
notes="HDMI FRL is distinct from TMDS. Do not apply TMDS rules. UNKNOWN until Adopter spec.",
|
||||||
incomplete=True,
|
incomplete=True,
|
||||||
))
|
))
|
||||||
|
physical.append(_iface(
|
||||||
|
"dvi-1.0-tmds", "dvi", "SERIAL", "SERIAL_DIFFERENTIAL", "YES",
|
||||||
|
DVI_CHECKS, _dvi_cons("dvi-1.0-tmds"),
|
||||||
|
connector="DVI",
|
||||||
|
hints=["DVI", "TMDS", "TX0", "TX1", "TX2"],
|
||||||
|
notes=(
|
||||||
|
"DVI 1.0 TMDS. Not HDMI. Table 4-2 termination 50 Ω ±10%; "
|
||||||
|
"Table 4-7 receiver at termination 100 Ω ±10%. Table 4-8 cable skew is informative."
|
||||||
|
),
|
||||||
|
))
|
||||||
|
|
||||||
def _mem_constraints(pid: str, kind: ValueKind, source_type: SourceType) -> list[dict[str, Any]]:
|
def _mem_constraints(pid: str, kind: ValueKind, source_type: SourceType) -> list[dict[str, Any]]:
|
||||||
cls: SourceClass = "VENDOR" if source_type != "STANDARD" else "NORMATIVE"
|
cls: SourceClass = "VENDOR" if source_type != "STANDARD" else "NORMATIVE"
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -67,9 +67,10 @@ _ETH_PHY_RE = re.compile(
|
|||||||
)
|
)
|
||||||
_ETH_MAG_RE = re.compile(r"MAGNETIC|PULSE\s*JACK|ETHERNET\s*XFR|LAN_XFR", re.I)
|
_ETH_MAG_RE = re.compile(r"MAGNETIC|PULSE\s*JACK|ETHERNET\s*XFR|LAN_XFR", re.I)
|
||||||
_HDMI_MINI_RE = re.compile(r"MINI\s*HDMI|HDMI[\s_\-]*C\b|HDMI[\s_\-]*MINI", re.I)
|
_HDMI_MINI_RE = re.compile(r"MINI\s*HDMI|HDMI[\s_\-]*C\b|HDMI[\s_\-]*MINI", re.I)
|
||||||
_HDMI_RE = re.compile(r"\bHDMI\b|TMDS", re.I)
|
_HDMI_RE = re.compile(r"\bHDMI\b", re.I)
|
||||||
_HDMI_FRL_RE = re.compile(r"\bFRL\b|HDMI\s*2\.1", re.I)
|
_HDMI_FRL_RE = re.compile(r"\bFRL\b|HDMI\s*2\.1", re.I)
|
||||||
_HDMI_TMDS_NET = re.compile(r"TMDS|HDMI[_]?TX|HDMI[_]?CLK|HDMI[_]?D\d", re.I)
|
_HDMI_TMDS_NET = re.compile(r"HDMI[_]?TX|HDMI[_]?CLK|HDMI[_]?D\d|TMDS", re.I)
|
||||||
|
_DVI_RE = re.compile(r"\bDVI\b|DVI[\s_\-]*[DAI]", re.I)
|
||||||
_DDR_GEN = [
|
_DDR_GEN = [
|
||||||
("ddr5", re.compile(r"\bDDR5\b", re.I)),
|
("ddr5", re.compile(r"\bDDR5\b", re.I)),
|
||||||
("ddr4", re.compile(r"\bDDR4\b|MT41|K4A|IS43TR", re.I)),
|
("ddr4", re.compile(r"\bDDR4\b|MT41|K4A|IS43TR", re.I)),
|
||||||
@@ -283,6 +284,7 @@ def recognize_physical_buses(
|
|||||||
out.extend(_recognize_declared(graph, ifaces, logical))
|
out.extend(_recognize_declared(graph, ifaces, logical))
|
||||||
out.extend(_recognize_usb(graph, ifaces))
|
out.extend(_recognize_usb(graph, ifaces))
|
||||||
out.extend(_recognize_ethernet(graph, ifaces))
|
out.extend(_recognize_ethernet(graph, ifaces))
|
||||||
|
out.extend(_recognize_dvi(graph, ifaces))
|
||||||
out.extend(_recognize_hdmi(graph, ifaces))
|
out.extend(_recognize_hdmi(graph, ifaces))
|
||||||
out.extend(_recognize_hbm(graph, ifaces))
|
out.extend(_recognize_hbm(graph, ifaces))
|
||||||
out.extend(_recognize_ddr(graph, ifaces))
|
out.extend(_recognize_ddr(graph, ifaces))
|
||||||
@@ -615,6 +617,40 @@ def _recognize_ethernet(graph: DesignGraph, ifaces: dict) -> list[PhysicalBusIns
|
|||||||
)]
|
)]
|
||||||
|
|
||||||
|
|
||||||
|
def _recognize_dvi(graph: DesignGraph, ifaces: dict) -> list[PhysicalBusInstance]:
|
||||||
|
conns = [
|
||||||
|
c for c in graph.components.values()
|
||||||
|
if c.component_type == ComponentType.CONNECTOR and (
|
||||||
|
_DVI_RE.search(_blob(c, graph)) or _DVI_RE.search(c.footprint or "")
|
||||||
|
)
|
||||||
|
]
|
||||||
|
if not conns:
|
||||||
|
return []
|
||||||
|
pid = "dvi-1.0-tmds"
|
||||||
|
iface = ifaces.get(pid)
|
||||||
|
if iface is None:
|
||||||
|
return []
|
||||||
|
host = conns[0].reference
|
||||||
|
tmds = [
|
||||||
|
n for n in graph.nets
|
||||||
|
if _HDMI_TMDS_NET.search(n) or _HDMI_TMDS_NET.search(_leaf(n)) or _DVI_RE.search(n)
|
||||||
|
]
|
||||||
|
return [PhysicalBusInstance(
|
||||||
|
instance_id=f"{pid}:{host}",
|
||||||
|
logical_protocol_id="dvi",
|
||||||
|
physical_interface_id=pid,
|
||||||
|
pcb_relevant=iface.pcb_relevant,
|
||||||
|
confidence=_EVIDENCE_SCORE["part"],
|
||||||
|
evidence_kind="part",
|
||||||
|
recognition_status="REVIEW" if not tmds else "RECOGNIZED",
|
||||||
|
nets=tmds,
|
||||||
|
host_ref=host,
|
||||||
|
notes="DVI 1.0 TMDS. Not HDMI. Connector is not HDMI Type A.",
|
||||||
|
connector="DVI",
|
||||||
|
physical_implementation="DVI 1.0 TMDS",
|
||||||
|
)]
|
||||||
|
|
||||||
|
|
||||||
def _recognize_hdmi(graph: DesignGraph, ifaces: dict) -> list[PhysicalBusInstance]:
|
def _recognize_hdmi(graph: DesignGraph, ifaces: dict) -> list[PhysicalBusInstance]:
|
||||||
conns = [
|
conns = [
|
||||||
c for c in graph.components.values()
|
c for c in graph.components.values()
|
||||||
@@ -625,6 +661,12 @@ def _recognize_hdmi(graph: DesignGraph, ifaces: dict) -> list[PhysicalBusInstanc
|
|||||||
]
|
]
|
||||||
tmds = [n for n in graph.nets if _HDMI_TMDS_NET.search(n) or _HDMI_TMDS_NET.search(_leaf(n))]
|
tmds = [n for n in graph.nets if _HDMI_TMDS_NET.search(n) or _HDMI_TMDS_NET.search(_leaf(n))]
|
||||||
blob = " ".join(_blob(c, graph) for c in graph.components.values())
|
blob = " ".join(_blob(c, graph) for c in graph.components.values())
|
||||||
|
dvi_present = any(
|
||||||
|
_DVI_RE.search(_blob(c, graph)) or _DVI_RE.search(c.footprint or "")
|
||||||
|
for c in graph.components.values()
|
||||||
|
)
|
||||||
|
if dvi_present and not re.search(r"\bHDMI\b", blob, re.I):
|
||||||
|
return []
|
||||||
frl = bool(_HDMI_FRL_RE.search(blob) or any(_HDMI_FRL_RE.search(n) for n in graph.nets))
|
frl = bool(_HDMI_FRL_RE.search(blob) or any(_HDMI_FRL_RE.search(n) for n in graph.nets))
|
||||||
mini = any(
|
mini = any(
|
||||||
_HDMI_MINI_RE.search(_blob(c, graph)) or _HDMI_MINI_RE.search(c.footprint or "")
|
_HDMI_MINI_RE.search(_blob(c, graph)) or _HDMI_MINI_RE.search(c.footprint or "")
|
||||||
|
|||||||
@@ -2,6 +2,13 @@
|
|||||||
|
|
||||||
What's new in Periscope.
|
What's new in Periscope.
|
||||||
|
|
||||||
|
## 2.74.0 — 2026-09-22 — Protocol packs from recovered PDFs (USB CTS, Type-C FTS, DVI 1.0, IEEE 802.3-2012 §2)
|
||||||
|
|
||||||
|
NUMERIC constraints now carry title, revision, section/table, and page from the recovered PDFs. USB 2.0 HS fills data rate / rise-fall / 1.5 kΩ pull-up / DCR from Electrical CTS v1.08; Zdiff stays UNKNOWN (CTS does not state 90 Ω). Type-C Rp/Rd/VBUS volts stay UNKNOWN (Functional Test Spec points at Cable and Connector tables). DVI 1.0 is a separate protocol from HDMI. IEEE 802.3-2012 Section Two fills 100BASE-TX cabling 100 Ω / 100 m / isolation and 100 Mb/s; 10BASE-T Clause 14 and 1000BASE-T Clause 40 are not in Section Two.
|
||||||
|
|
||||||
|
- [Changed] `protocol_catalog.py` + `catalog.json`; DVI recognition.
|
||||||
|
- [New] pytest `tests/pcb/test_protocol_pdf_pack.py`.
|
||||||
|
|
||||||
## 2.73.0 — 2026-09-22 — Protocol certification M6/M7 (USB-C / Ethernet / HDMI packs)
|
## 2.73.0 — 2026-09-22 — Protocol certification M6/M7 (USB-C / Ethernet / HDMI packs)
|
||||||
|
|
||||||
USB 2.0 (LS/FS/HS) is the protocol; USB Type-C is a connector/interface system; USB 2.0 over Type-C is the physical implementation. Type-C does not imply USB3 or USB4. Mini HDMI is a connector, not a protocol. Ethernet variants (10/100/1000/2.5G/5G/10G, SGMII, 1000BASE-X, 100BASE-FX, 10GBASE-R) are incomplete skeletons. All listed numeric fields stay **UNKNOWN** with `needed_document` (USB-IF / IEEE 802.3 / HDMI Adopter). No invented ohms, no typical-as-standard, no OpenEMS.
|
USB 2.0 (LS/FS/HS) is the protocol; USB Type-C is a connector/interface system; USB 2.0 over Type-C is the physical implementation. Type-C does not imply USB3 or USB4. Mini HDMI is a connector, not a protocol. Ethernet variants (10/100/1000/2.5G/5G/10G, SGMII, 1000BASE-X, 100BASE-FX, 10GBASE-R) are incomplete skeletons. All listed numeric fields stay **UNKNOWN** with `needed_document` (USB-IF / IEEE 802.3 / HDMI Adopter). No invented ohms, no typical-as-standard, no OpenEMS.
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "periscope-web",
|
"name": "periscope-web",
|
||||||
"version": "2.73.0",
|
"version": "2.74.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"sync-version": "node scripts/sync-version.mjs",
|
"sync-version": "node scripts/sync-version.mjs",
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ REQUIRED_LOGICAL = {
|
|||||||
"usb2-ls-fs", "usb2-ls", "usb2-fs", "usb2-hs", "usb-c", "usb-c-usb2",
|
"usb2-ls-fs", "usb2-ls", "usb2-fs", "usb2-hs", "usb-c", "usb-c-usb2",
|
||||||
"usb3-x", "usb4", "100base-tx", "10base-t", "1000base-t",
|
"usb3-x", "usb4", "100base-tx", "10base-t", "1000base-t",
|
||||||
"hdmi-1.4", "hdmi-2.0", "hdmi-frl",
|
"hdmi-1.4", "hdmi-2.0", "hdmi-frl",
|
||||||
|
"dvi",
|
||||||
"ddr-family", "ddr4", "lpddr-family", "lpddr4",
|
"ddr-family", "ddr4", "lpddr-family", "lpddr4",
|
||||||
"hbm-family", "hbm3", "hyperbus", "qspi", "octal-spi", "emmc", "ufs",
|
"hbm-family", "hbm3", "hyperbus", "qspi", "octal-spi", "emmc", "ufs",
|
||||||
"axi4", "axi4-lite", "ahb", "apb", "wishbone", "avalon-mm", "avalon-st",
|
"axi4", "axi4-lite", "ahb", "apb", "wishbone", "avalon-mm", "avalon-st",
|
||||||
@@ -98,12 +99,28 @@ def test_hdmi_mini_is_same_logical_different_connector():
|
|||||||
assert mini.connector == "HDMI-C-mini"
|
assert mini.connector == "HDMI-C-mini"
|
||||||
|
|
||||||
|
|
||||||
def test_catalog_has_no_invented_ohm_numbers():
|
def test_catalog_numeric_requires_official_cite_no_invented_usb_90ohm():
|
||||||
cat = load_catalog()
|
cat = load_catalog()
|
||||||
|
usb_z = []
|
||||||
for iface in cat.physical_interfaces:
|
for iface in cat.physical_interfaces:
|
||||||
for c in iface.constraints:
|
for c in iface.constraints:
|
||||||
assert c.value is None
|
if c.value_kind == "NUMERIC":
|
||||||
assert c.value_kind != "NUMERIC"
|
assert c.value is not None
|
||||||
|
assert c.source is not None
|
||||||
|
assert c.source.document and c.source.organization
|
||||||
|
assert c.source.revision
|
||||||
|
assert c.source.page
|
||||||
|
assert c.source.section or c.source.table
|
||||||
|
if (
|
||||||
|
iface.logical_protocol_id.startswith("usb")
|
||||||
|
and c.parameter == "differential_impedance"
|
||||||
|
):
|
||||||
|
usb_z.append(c)
|
||||||
|
assert c.value_kind != "NUMERIC"
|
||||||
|
assert c.value is None
|
||||||
|
assert usb_z
|
||||||
|
blob = json.dumps([c.model_dump() for c in usb_z])
|
||||||
|
assert "90" not in blob
|
||||||
|
|
||||||
|
|
||||||
def test_recommended_is_not_fail_mandatory():
|
def test_recommended_is_not_fail_mandatory():
|
||||||
|
|||||||
@@ -90,9 +90,11 @@ def test_m10_no_invented_ohms_and_no_usbif_fill():
|
|||||||
loaded = load_catalog()
|
loaded = load_catalog()
|
||||||
for iface in loaded.physical_interfaces:
|
for iface in loaded.physical_interfaces:
|
||||||
for c in iface.constraints:
|
for c in iface.constraints:
|
||||||
assert c.value is None
|
if c.value_kind == "NUMERIC":
|
||||||
assert c.value_kind != "NUMERIC" or (c.source is not None)
|
assert c.source is not None
|
||||||
if c.value_kind != "NUMERIC":
|
assert c.source.document
|
||||||
|
else:
|
||||||
|
assert c.value is None
|
||||||
assert c.unit is None
|
assert c.unit is None
|
||||||
blob = json.dumps([
|
blob = json.dumps([
|
||||||
c.model_dump() for p in loaded.physical_interfaces for c in p.constraints
|
c.model_dump() for p in loaded.physical_interfaces for c in p.constraints
|
||||||
|
|||||||
@@ -84,15 +84,21 @@ def test_usb2_and_usb_c_unknown_with_usbif_needed_document_no_90ohm():
|
|||||||
or p.id.startswith("usb-")
|
or p.id.startswith("usb-")
|
||||||
]
|
]
|
||||||
assert usb_ifaces
|
assert usb_ifaces
|
||||||
blob = json.dumps([c.model_dump() for p in usb_ifaces for c in p.constraints])
|
z_blob = json.dumps([
|
||||||
assert "90" not in blob
|
c.model_dump() for p in usb_ifaces for c in p.constraints
|
||||||
|
if c.parameter == "differential_impedance"
|
||||||
|
])
|
||||||
|
assert "90" not in z_blob
|
||||||
for p in usb_ifaces:
|
for p in usb_ifaces:
|
||||||
for c in p.constraints:
|
for c in p.constraints:
|
||||||
assert c.value is None
|
if c.parameter == "differential_impedance":
|
||||||
assert c.value_kind != "NUMERIC"
|
assert c.value is None
|
||||||
|
assert c.value_kind != "NUMERIC"
|
||||||
if c.value_kind in {"UNKNOWN", "MISSING_SOURCE"}:
|
if c.value_kind in {"UNKNOWN", "MISSING_SOURCE"}:
|
||||||
assert c.needed_document
|
assert c.needed_document
|
||||||
assert "USB-IF" in c.needed_document or "specification" in c.needed_document.lower()
|
assert "USB-IF" in c.needed_document or "specification" in c.needed_document.lower() or "Specification" in c.needed_document
|
||||||
|
if p.logical_protocol_id == "usb-c" and c.parameter in {"rp", "rd"}:
|
||||||
|
assert c.value_kind == "UNKNOWN"
|
||||||
over = next(p for p in cat.physical_interfaces if p.id == "usb-c-usb2-receptacle")
|
over = next(p for p in cat.physical_interfaces if p.id == "usb-c-usb2-receptacle")
|
||||||
assert over.logical_protocol_id == "usb2-hs"
|
assert over.logical_protocol_id == "usb2-hs"
|
||||||
assert over.connector == "Type-C"
|
assert over.connector == "Type-C"
|
||||||
@@ -202,8 +208,8 @@ def test_mini_hdmi_is_connector_not_protocol_id():
|
|||||||
def test_ethernet_hdmi_skeletons_unknown_needed_document():
|
def test_ethernet_hdmi_skeletons_unknown_needed_document():
|
||||||
cat = load_catalog()
|
cat = load_catalog()
|
||||||
for lid in (
|
for lid in (
|
||||||
"10base-t", "100base-tx", "1000base-t", "2.5gbase-t", "5gbase-t",
|
"10base-t", "1000base-t", "2.5gbase-t", "5gbase-t",
|
||||||
"10gbase-t", "sgmii", "1000base-x", "100base-fx", "10gbase-r",
|
"10gbase-t", "sgmii", "1000base-x", "10gbase-r",
|
||||||
"hdmi-1.4", "hdmi-2.0", "hdmi-frl",
|
"hdmi-1.4", "hdmi-2.0", "hdmi-frl",
|
||||||
):
|
):
|
||||||
ifaces = [p for p in cat.physical_interfaces if p.logical_protocol_id == lid]
|
ifaces = [p for p in cat.physical_interfaces if p.logical_protocol_id == lid]
|
||||||
@@ -218,7 +224,7 @@ def test_ethernet_hdmi_skeletons_unknown_needed_document():
|
|||||||
if lid.startswith("hdmi"):
|
if lid.startswith("hdmi"):
|
||||||
assert "HDMI" in c.needed_document
|
assert "HDMI" in c.needed_document
|
||||||
else:
|
else:
|
||||||
assert "IEEE" in c.needed_document or "PHY" in (c.needed_document or "")
|
assert "IEEE" in c.needed_document or "PHY" in (c.needed_document or "") or "SGMII" in (c.needed_document or "")
|
||||||
tmds = next(p for p in cat.physical_interfaces if p.id == "hdmi-1.4-tmds-type-a")
|
tmds = next(p for p in cat.physical_interfaces if p.id == "hdmi-1.4-tmds-type-a")
|
||||||
frl = next(p for p in cat.physical_interfaces if p.id == "hdmi-frl-pcb")
|
frl = next(p for p in cat.physical_interfaces if p.id == "hdmi-frl-pcb")
|
||||||
assert tmds.logical_protocol_id != frl.logical_protocol_id
|
assert tmds.logical_protocol_id != frl.logical_protocol_id
|
||||||
|
|||||||
@@ -0,0 +1,148 @@
|
|||||||
|
"""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.0
|
||||||
|
assert by["data_rate"].unit == "Mb/s"
|
||||||
|
assert by["data_rate"].source.document == "USB 2.0 Electrical Compliance Test Specification"
|
||||||
|
assert "1.08" in by["data_rate"].source.revision
|
||||||
|
assert "EL_2" in (by["data_rate"].source.section or "")
|
||||||
|
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",
|
||||||
|
):
|
||||||
|
_cite_ok(by[key])
|
||||||
|
assert by[key].source.organization == "USB-IF"
|
||||||
|
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")
|
||||||
|
assert ls_rate.value_kind == "UNKNOWN"
|
||||||
|
blob = json.dumps(z.model_dump())
|
||||||
|
assert "90" not in blob
|
||||||
|
|
||||||
|
|
||||||
|
def test_type_c_rp_rd_unknown_fts_does_not_state_ohms():
|
||||||
|
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}
|
||||||
|
for p in ("rp", "rd", "ra", "cc"):
|
||||||
|
assert by[p].value_kind == "UNKNOWN"
|
||||||
|
assert "Cable and Connector" in (by[p].needed_document or "")
|
||||||
|
assert by["voltage"].value_kind == "UNKNOWN"
|
||||||
|
_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"
|
||||||
|
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")
|
||||||
|
tdr = next(c for c in ten.constraints if c.parameter == "data_rate")
|
||||||
|
assert tdr.value_kind == "UNKNOWN"
|
||||||
|
assert "Clause 14" in (tdr.needed_document or "")
|
||||||
|
gbe = next(p for p in cat.physical_interfaces if p.id == "1000base-t-mdi")
|
||||||
|
gdr = next(c for c in gbe.constraints if c.parameter == "data_rate")
|
||||||
|
assert gdr.value_kind == "UNKNOWN"
|
||||||
|
assert "Clause 40" in (gdr.needed_document or "")
|
||||||
|
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"
|
||||||
Reference in New Issue
Block a user