Files
periscope/backend/periscopex/pcb_net_match.py
T
michele 16c606ae3d Add MODE=pcb layout exam job with AI and deterministic checks.
Parallel pcb_status pipeline: parse board, classify domains/groups,
inventory traces, PE-LAY/PLC/SI/DRT checks, per-IC datasheet review.
Findings merge into the report UI. No auto-place or pcbnew write-back.
2026-09-19 22:54:17 +02:00

87 lines
2.8 KiB
Python

"""Pad net on the PCB vs pin net on the schematic graph.
Silent when either side has no name. Power-flag footprints (#PWR) skipped.
"""
from __future__ import annotations
from backend.periscopex.models import DesignGraph, Finding, LayoutGraph
def _ensure_recommendation(f: Finding) -> Finding:
if not (f.recommendation or "").strip():
f.recommendation = (
"Align the PCB pad net with the schematic pin, then re-run PCB review."
)
return f
def check_pcb_net_match(
graph: DesignGraph,
layout: LayoutGraph | None,
) -> list[Finding]:
if layout is None or not layout.footprints:
return []
findings: list[Finding] = []
sch_refs = {
ref for ref in graph.components
if not ref.startswith("#")
}
pcb_refs = {
ref for ref in layout.footprints
if not ref.startswith("#")
}
for ref in sorted(sch_refs - pcb_refs):
comp = graph.components[ref]
findings.append(_ensure_recommendation(Finding(
designator=ref,
mpn=comp.mpn or "",
aspect="pcb_match",
finding=f"{ref} is in the schematic but has no footprint on the PCB.",
why="Layout review cannot check a part that is not placed.",
status="WARNING",
recommendation=f"Place {ref} on the board or remove it from the schematic/BOM.",
source="pcb_net_match",
rule_id="PE-LAY-002",
pins=[],
)))
for ref, fp in sorted(layout.footprints.items()):
if ref.startswith("#"):
continue
comp = graph.components.get(ref)
if comp is None:
continue
for pad in fp.pads:
if not pad.net or not pad.number:
continue
sch_net = graph.pin_net(ref, pad.number)
if not sch_net:
continue
if sch_net == pad.net:
continue
findings.append(_ensure_recommendation(Finding(
designator=ref,
mpn=comp.mpn or "",
aspect="pcb_match",
finding=(
f"{ref}.{pad.number} PCB net '{pad.net}' does not match "
f"schematic net '{sch_net}'."
),
why=(
"Datasheet and SI checks follow schematic net names. "
"A pad on the wrong net is a layout error, not a BOM typo."
),
status="ERROR",
recommendation=(
f"Reconnect pad {ref}.{pad.number} to '{sch_net}' "
f"(or fix the schematic if the PCB is authoritative)."
),
source="pcb_net_match",
rule_id="PE-LAY-001",
net=pad.net,
pins=[pad.number],
)))
return findings