Prefer .kicad_pcb pad nets when building the design graph.
Schematic geometry on KiCad 10 boards was swapping rails and inventing floating pins; board connectivity is authoritative when a PCB is uploaded. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -254,6 +254,7 @@ def build_graph(
|
||||
mpn_col: str = "Manufacturer Part Number",
|
||||
skipped: list[SkippedItem] | None = None,
|
||||
include_subdesigns: set[str] | None = None,
|
||||
pcb_path: str | Path | None = None,
|
||||
) -> DesignGraph:
|
||||
"""Build a DesignGraph deterministically from project files.
|
||||
|
||||
@@ -264,6 +265,9 @@ def build_graph(
|
||||
4. Resolve passive specs from patterns + cached component models
|
||||
5. Assemble components with classified type, linked constraints, and specs
|
||||
6. Assemble nets with inferred type/voltage and enriched pin names
|
||||
|
||||
When ``pcb_path`` points at a ``.kicad_pcb``, pad nets from the board replace
|
||||
schematic-derived connectivity (KiCad board nets are authoritative).
|
||||
"""
|
||||
# Parse BOM first so we can feed known refs into the netlist parser —
|
||||
# PADS-PCB netlists allow multi-word designators (e.g. "CV GND"), which
|
||||
@@ -284,6 +288,17 @@ def build_graph(
|
||||
known_refs=set(bom.keys()),
|
||||
include_subdesigns=include_subdesigns,
|
||||
)
|
||||
if pcb_path is not None:
|
||||
pcb = Path(pcb_path)
|
||||
if pcb.is_file():
|
||||
from backend.pinscopex.parsers_kicad_pcb import nets_from_pcb, parse_kicad_pcb
|
||||
|
||||
layout = parse_kicad_pcb(pcb)
|
||||
pcb_nets = nets_from_pcb(layout)
|
||||
if pcb_nets:
|
||||
raw_nets = pcb_nets
|
||||
for ref, fp in layout.footprints.items():
|
||||
parts.setdefault(ref, fp.footprint or "")
|
||||
if fmt.startswith("kicad"):
|
||||
from backend.pinscopex.parsers_kicad import kicad_part_fields
|
||||
for ref, extra in kicad_part_fields(netlist_path).items():
|
||||
|
||||
@@ -45,16 +45,62 @@ def _prop(node: object, key: str) -> str:
|
||||
|
||||
def _pad_net(pad: object) -> str:
|
||||
n = _kid(pad, "net")
|
||||
if n and len(n) >= 3:
|
||||
if not n or len(n) < 2:
|
||||
return ""
|
||||
# KiCad 9/10 often stores ``(net "GND")`` without a numeric code.
|
||||
if len(n) == 2 and not isinstance(n[1], list):
|
||||
return str(n[1])
|
||||
# Legacy ``(net 3 "GND")``.
|
||||
if len(n) >= 3:
|
||||
return str(n[2])
|
||||
return ""
|
||||
|
||||
|
||||
def _normalize_pcb_net_name(name: str) -> str:
|
||||
"""Strip KiCad root-sheet ``/`` prefixes; keep empty / unconnected as-is."""
|
||||
n = (name or "").strip()
|
||||
if not n:
|
||||
return ""
|
||||
while n.startswith("/"):
|
||||
n = n[1:]
|
||||
return n
|
||||
|
||||
|
||||
def nets_from_pcb(layout: LayoutGraph) -> dict[str, list[tuple[str, str]]]:
|
||||
"""Pad connectivity from a parsed board — authoritative when sch geometry fails."""
|
||||
nets: dict[str, list[tuple[str, str]]] = {}
|
||||
seen: set[tuple[str, str, str]] = set()
|
||||
for ref, fp in layout.footprints.items():
|
||||
for pad in fp.pads:
|
||||
raw = pad.net or ""
|
||||
if not raw:
|
||||
continue
|
||||
name = _normalize_pcb_net_name(raw)
|
||||
if not name:
|
||||
continue
|
||||
key = (name, ref, pad.number)
|
||||
if key in seen:
|
||||
continue
|
||||
seen.add(key)
|
||||
nets.setdefault(name, []).append((ref, pad.number))
|
||||
return nets
|
||||
|
||||
|
||||
def _net_name(node: object, nets: dict[str, int]) -> str:
|
||||
n = _kid(node, "net")
|
||||
if not n or len(n) < 2:
|
||||
named = _val(node, "net_name")
|
||||
return named
|
||||
# ``(net "GND")`` or ``(net 1)`` or ``(net 1 "GND")``
|
||||
if len(n) == 2 and not isinstance(n[1], list):
|
||||
token = n[1]
|
||||
if isinstance(token, str) and not str(token).replace(".", "", 1).isdigit():
|
||||
return str(token)
|
||||
try:
|
||||
code = int(_fnum(token))
|
||||
except (TypeError, ValueError):
|
||||
return str(token)
|
||||
return next((name for name, c in nets.items() if c == code), str(code))
|
||||
if len(n) >= 3:
|
||||
return str(n[2])
|
||||
try:
|
||||
|
||||
Reference in New Issue
Block a user