Rebrand Pinscope to Periscope across product and codebase.
Rename the core package to periscopex, update UI/docs/Docker/deploy defaults to periscope.michelebigi.it, and keep legacy version/storage key aliases so existing projects keep working. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,112 @@
|
||||
"""Enable pins on the fitted variant: no pull and no driver is ERROR.
|
||||
|
||||
Runs only when the BOM actually marks DNP/fitted. Enable tied to a rail
|
||||
is a driver. DNP resistors are removed from the variant graph.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import re
|
||||
|
||||
from backend.periscopex.models import (
|
||||
ComponentConstraints,
|
||||
ComponentType,
|
||||
DesignGraph,
|
||||
Finding,
|
||||
)
|
||||
from backend.periscopex.passive_rail_check import (
|
||||
_is_ground_net,
|
||||
_is_power_net,
|
||||
_pin_name_tokens,
|
||||
)
|
||||
from backend.periscopex.validate import _match_constraints
|
||||
|
||||
_EN_RE = re.compile(
|
||||
r"(?:^|[_/])(EN|ENA|ENABLE|n?SHDN|nEN|EN_N|CHIP_EN)(?:$|[_/\d])",
|
||||
re.I,
|
||||
)
|
||||
|
||||
|
||||
def _dnp_map(graph: DesignGraph) -> dict[str, bool] | None:
|
||||
"""Return {ref: is_dnp} if any BOM row carries DNP/fitted, else None."""
|
||||
fields = graph.bom_fields or {}
|
||||
if not fields:
|
||||
return None
|
||||
if not any("dnp" in (v or {}) or "fitted" in (v or {}) for v in fields.values()):
|
||||
return None
|
||||
out: dict[str, bool] = {}
|
||||
for ref in graph.components:
|
||||
row = fields.get(ref) or {}
|
||||
if "dnp" in row:
|
||||
out[ref] = bool(row.get("dnp"))
|
||||
elif "fitted" in row:
|
||||
out[ref] = not bool(row.get("fitted"))
|
||||
else:
|
||||
out[ref] = False
|
||||
return out
|
||||
|
||||
|
||||
def _is_fitted(dnp: dict[str, bool], ref: str) -> bool:
|
||||
return not dnp.get(ref, False)
|
||||
|
||||
|
||||
def check_dnp_enables(
|
||||
graph: DesignGraph,
|
||||
constraints_map: dict[str, ComponentConstraints] | None = None,
|
||||
) -> list[Finding]:
|
||||
dnp = _dnp_map(graph)
|
||||
if dnp is None:
|
||||
return []
|
||||
cmap = constraints_map or {}
|
||||
findings: list[Finding] = []
|
||||
for ref, comp in sorted(graph.components.items()):
|
||||
if not _is_fitted(dnp, ref):
|
||||
continue
|
||||
if comp.component_type != ComponentType.IC:
|
||||
continue
|
||||
cons = _match_constraints(comp.mpn or comp.value, cmap)
|
||||
for pin_num, net in sorted(comp.pins.items(), key=lambda x: str(x[0])):
|
||||
tokens = _pin_name_tokens(cons, pin_num)
|
||||
names = tokens or [net or "", pin_num]
|
||||
if not any(_EN_RE.search(t) for t in names):
|
||||
continue
|
||||
if _is_power_net(graph, net) or _is_ground_net(graph, net):
|
||||
continue
|
||||
has_pull = False
|
||||
has_driver = False
|
||||
for r in graph.components_on_net(net):
|
||||
if r == ref or not _is_fitted(dnp, r):
|
||||
continue
|
||||
other = graph.components.get(r)
|
||||
if not other:
|
||||
continue
|
||||
if other.component_type == ComponentType.IC:
|
||||
has_driver = True
|
||||
continue
|
||||
if other.component_type != ComponentType.RESISTOR:
|
||||
continue
|
||||
others = {n for n in other.pins.values() if n != net}
|
||||
if any(_is_power_net(graph, n) or _is_ground_net(graph, n) for n in others):
|
||||
has_pull = True
|
||||
if has_pull or has_driver:
|
||||
continue
|
||||
variant = (graph.bom_fields.get(ref) or {}).get("variant")
|
||||
findings.append(Finding(
|
||||
designator=ref,
|
||||
mpn=comp.mpn or "",
|
||||
aspect="dnp",
|
||||
source="dnp_check",
|
||||
status="ERROR",
|
||||
finding=(
|
||||
f"{ref} enable '{net}' has no fitted pull or driver "
|
||||
f"(DNP parts ignored)."
|
||||
),
|
||||
why="On the fitted variant the enable net is floating.",
|
||||
recommendation="Fit a pull, tie EN to a rail, or drive it from a PG/GPIO.",
|
||||
reference="BOM DNP/fitted",
|
||||
net=net,
|
||||
pins=[f"{ref}.{pin_num}"],
|
||||
rule_id="PE-DNP-001",
|
||||
variant=str(variant) if variant else None,
|
||||
))
|
||||
return findings
|
||||
Reference in New Issue
Block a user