imrishabh18/rp2040-motor-controller
A library of PCB component definitions covering MOSFETs, motor drivers, USB-PD control, sensors, current monitors, transistors, diodes, resistors, speakers, connectors, and mirrored bottom-side logos, with pin mappings, footprints, and 3D models.
- Version
- 1.0.55
- License
- unset
- Stars
- 5
scripts/repair-top-routes.py
"""Repair affected signal routes, negotiating around retained signal copper.
Motor-power routes and crystal routes are never displaced by this helper.
Every candidate still requires the normal full checks and physical audits.
"""
import json
import re
import ast
import subprocess
import sys
from pathlib import Path
folder = 'dist/top-assembly'
log_path = Path('reports/changed-route-repair.log')
pending = list(json.loads(Path('reports/repair-queue.json').read_text()))
original_widths = {}
active = None
for line in log_path.read_text().splitlines():
if line.startswith('ROUTING '): active = line.split()[1]
if line.startswith('Net ') and active and active not in original_widths:
widths = re.findall(r"'width': ([0-9.]+)", line)
if widths: original_widths[active] = min(map(float, widths))
if line.startswith('Routed '):
target = line.split()[1]
pending = [t for t in pending if t != target]
if line.startswith('QUEUED '):
pending.extend(t for t in ast.literal_eval(line[7:]) if t not in pending)
if sys.argv[1:]: pending = sys.argv[1:]
plan = json.loads(Path(folder+'/route-plan.json').read_text())
traces = {t['pcb_trace_id']: t for t in plan['traces']}
circuit = json.loads(Path('dist/pd-control/unrouted.json').read_text())
source_names = {e['source_trace_id']: e.get('name') for e in circuit if e['type']=='source_trace'}
protected = [t['pcb_trace_id'] for t in plan['traces'] if max(p.get('width', 0) for p in t['route']) >= .35 or source_names.get(t.get('source_trace_id')) in ['XIN','XOUT_R','XOUT','CXIN','CXOUT']]
with log_path.open('a', buffering=1) as log:
attempts = 0
while pending:
attempts += 1
if attempts > 80: raise SystemExit('Routing negotiation exceeded 80 repairs')
target = pending.pop(0)
width = original_widths.get(target, min(p.get('width', 1) for p in traces[target]['route'] if p['route_type']=='wire'))
args = ['.venv/bin/python','scripts/route-local.py',folder,target,str(width),'--shorten','--via-cost=35','--ripup='+','.join(pending),'--report-dir=reports/top-routing']
print('ROUTING',target,'remaining',len(pending),file=log,flush=True)
result = subprocess.run(args,stdout=log,stderr=subprocess.STDOUT)
if result.returncode:
print('NEGOTIATING',target,file=log,flush=True)
result = subprocess.run(args+['--soft-routing','--soft-penalty=180','--protected='+','.join(protected)],stdout=log,stderr=subprocess.STDOUT)
if result.returncode: raise SystemExit('Failed '+target)
displaced = json.loads(Path('reports/top-routing/local-route-blockers.json').read_text())
assert not set(displaced).intersection(protected), 'Protected power/clock route displaced'
pending.extend(t for t in displaced if t not in pending and t != target)
print('QUEUED',displaced,file=log,flush=True)
print('All queued routing repairs completed',file=log,flush=True)
