54 行
2.5 KiB
Python
54 行
2.5 KiB
Python
"""Inject violations into a disposable board to check R2 rules actually fire."""
|
|
import json
|
|
import shutil
|
|
|
|
import pcbnew as pcb
|
|
from bootstrap_pcb import xy, rounded_rect
|
|
from optimize_pcb_layout import ROOT, OUT
|
|
from verify_pcb_layout import run, routing
|
|
|
|
|
|
def main():
|
|
folder=OUT/'rule-probe'
|
|
folder.mkdir(exist_ok=True)
|
|
path=folder/'RuleProbe.kicad_pcb'
|
|
b=pcb.BOARD(); b.SetCopperLayerCount(4)
|
|
rounded_rect(b,50,50,220,135,5)
|
|
def net(name):
|
|
item=pcb.NETINFO_ITEM(b,name); b.Add(item); return item
|
|
usb,sw,control=net('USB_DP'),net('Net-(C105-Pad2)'),net('SDA')
|
|
def track(a,z,layer,n,width=.25):
|
|
t=pcb.PCB_TRACK(b); t.SetStart(xy(*a));t.SetEnd(xy(*z));t.SetLayer(layer)
|
|
t.SetWidth(pcb.FromMM(width));t.SetNet(n);b.Add(t)
|
|
track((60,60),(65,60),pcb.F_Cu,usb,.8)
|
|
track((70,70),(80,70),pcb.In1_Cu,control)
|
|
track((90,80),(90,81.5),pcb.F_Cu,control)
|
|
track((90,81.5),(90,83),pcb.F_Cu,control)
|
|
track((100,90),(101.5,90),pcb.B_Cu,control)
|
|
track((101.5,90),(103,90),pcb.B_Cu,control)
|
|
v=pcb.PCB_VIA(b);v.SetPosition(xy(120,100));v.SetWidth(pcb.FromMM(.6))
|
|
v.SetDrill(pcb.FromMM(.3));v.SetLayerPair(pcb.F_Cu,pcb.B_Cu);v.SetNet(sw);b.Add(v)
|
|
pcb.SaveBoard(str(path),b)
|
|
for ext in ('.kicad_pro','.kicad_dru'):
|
|
shutil.copy2(ROOT/'PhoneRail-Board1'/('PhoneRail-Board1'+ext),path.with_suffix(ext))
|
|
drc=folder/'drc.json'
|
|
run(['pcb','drc','--format','json','-o',str(drc),str(path)],drc)
|
|
data=json.loads(drc.read_text(encoding='utf-8'))
|
|
descriptions='\n'.join(v['description'] for v in data['violations'])
|
|
expected=['R2 USB differential target','R2 inner layers reserved','R2 switch copper stays']
|
|
checks={s:s in descriptions for s in expected}
|
|
contract=json.loads((ROOT/'pcb-routing-rules.json').read_text(encoding='utf-8'))
|
|
audit=routing(b,contract,1)
|
|
direction=[v for v in audit['errors'] if v['kind']=='direction']
|
|
checks['Split transverse tracks rejected on both outer layers']=len(direction)==2
|
|
checks['Inner signal track rejected']=any(v['kind']=='inner_signal_track' for v in audit['errors'])
|
|
checks['Explicit nonstandard USB pair skew checked']=any(v['kind']=='usb_skew' for v in audit['errors'])
|
|
result={'checks':checks,'all_passed':all(checks.values()),'routing':audit}
|
|
(folder/'verification.json').write_text(json.dumps(result,indent=2)+'\n',encoding='utf-8')
|
|
print(checks)
|
|
assert result['all_passed'],descriptions
|
|
|
|
|
|
if __name__=='__main__':
|
|
main()
|