from pathlib import Path
import xml.etree.ElementTree as E,re,json
import wx
_app=wx.App(False)
import pcbnew as k
p=Path(__file__).resolve().parent;d=p/'board';r=E.parse(p/'source_netlist_A52.xml').getroot();board=k.BOARD();board.SetCopperLayerCount(2)
mm=k.FromMM
pt=lambda x,y:k.VECTOR2I(mm(x),mm(y))
root=re.search(r'\(uuid "([^"]+)"',(d/'led_driver.kicad_sch').read_text()).group(1)
netobjects={};pinmeta={}
for n in r.findall('./nets/net'):
 name=n.get('name');net=k.NETINFO_ITEM(board,name,len(netobjects)+1);board.Add(net);netobjects[name]=net
 for c in n:pinmeta[c.get('ref'),c.get('pin')]=(name,c.get('pinfunction',''),c.get('pintype',''))
positions={'U1':(23,46),'U2':(53,46),'U3':(83,46),'J1':(91,65),'J2':(10,10),'J3':(40,10),'J4':(70,10),
'R1':(17,41.4),'R2':(47,41.4),'R3':(77,41.4),'C1':(29,41.4),'C2':(29,44.2),'C3':(59,41.4),'C4':(59,44.2),'C5':(89,41.4),'C6':(89,44.2),'R4':(48,80),'R5':(54,80),'R6':(42,80),'R7':(36,80)}
fps={}
for c in r.findall('./components/comp'):
 ref=c.get('ref');name=c.findtext('footprint').split(':',1)[1];fp=k.FootprintLoad(str(d/'Lamp_Driver.pretty'),name);assert fp
 if ref in ['R1','R2','R3']:fp.SetOrientationDegrees(180)
 fp.SetReference(ref);fp.SetValue(c.findtext('value'));fp.SetPath(k.KIID_PATH('/'+root+'/'+c.findtext('tstamps')));fp.SetPosition(pt(*positions[ref]));fp.SetFPID(k.LIB_ID('Lamp_Driver',name));fp.SetDNP(any(v.get('name')=='dnp' for v in c.findall('property')))
 fp.Reference().SetPosition(pt(positions[ref][0],positions[ref][1]+(2 if ref in ['C2','C4','C6'] else -7 if ref.startswith('U') else -2)))
 for pad in fp.Pads():
  n=pad.GetNumber()
  if n:
   name,func,typ=pinmeta[ref,n];pad.SetNet(netobjects[name]);pad.SetPinFunction(func);pad.SetPinType(typ)
 board.Add(fp);fps[ref]=fp
for i,(x,y) in enumerate([(4,4),(92,4),(4,88),(92,88)],1):
 fp=k.FootprintLoad(str(d/'Lamp_Driver.pretty'),'MountingHole_3.2mm_M3');fp.SetReference('H'+str(i));fp.SetPosition(pt(x,y));fp.Reference().SetPosition(pt(x if x==4 else 86,y+4 if y==4 else y-4));board.Add(fp)
for a,b in [((0,0),(96,0)),((96,0),(96,92)),((96,92),(0,92)),((0,92),(0,0))]:
 line=k.PCB_SHAPE();line.SetShape(k.SHAPE_T_SEGMENT);line.SetStart(pt(*a));line.SetEnd(pt(*b));line.SetLayer(k.Edge_Cuts);line.SetWidth(mm(.05));board.Add(line)
def via(x,y,net='/GND'):
 v=k.PCB_VIA(board);v.SetPosition(pt(x,y));v.SetWidth(mm(.6));v.SetDrill(mm(.3));v.SetViaType(k.VIATYPE_THROUGH);v.SetLayerPair(k.F_Cu,k.B_Cu);v.SetNet(netobjects[net]);v.SetFrontTentingMode(k.TENTING_MODE_TENTED);v.SetBackTentingMode(k.TENTING_MODE_TENTED);board.Add(v)
def segment(a,b,net,width=.2):
 t=k.PCB_TRACK(board);t.SetStart(pt(*a));t.SetEnd(pt(*b));t.SetWidth(mm(width));t.SetLayer(k.F_Cu);t.SetNet(netobjects[net]);board.Add(t)
for i,x in enumerate([23,53,83]):
 for dx in [-.8,.8]:
  for dy in [-1.6,0,1.6]:via(x+dx,46+dy)
 # Preliminary short front-end wiring; board routing is not complete.
 segment((x-3.05,41.4),(x-5.175,41.4),'/REXT_'+str(i+1))
 via(x-7.5,41.4);segment((x-6.825,41.4),(x-7.5,41.4),'/GND')
 segment((x+3.05,41.4),(x+5.225,41.4),'/VDD_3V3')
 segment((x+4.5,41.4),(x+4.5,44.2),'/VDD_3V3');segment((x+4.5,44.2),(x+5.225,44.2),'/VDD_3V3')
 for y in [41.4,44.2]:
  via(x+7.5,y);segment((x+6.775,y),(x+7.5,y),'/GND')
zone=k.ZONE(board);zone.SetLayer(k.B_Cu);zone.SetNet(netobjects['/GND']);zone.SetLocalClearance(mm(.2));zone.SetThermalReliefGap(mm(.25));zone.SetThermalReliefSpokeWidth(mm(.25));zone.SetPadConnection(k.ZONE_CONNECTION_FULL);z=zone.Outline();z.NewOutline()
for x,y in [(1,1),(95,1),(95,91),(1,91)]:z.Append(mm(x),mm(y))
board.Add(zone)
text=k.PCB_TEXT(board);text.SetText('A53 BENCH CANDIDATE / INCOMPLETE ROUTING / NOT FOR FABRICATION');text.SetPosition(pt(48,86));text.SetLayer(k.F_SilkS);text.SetTextSize(pt(.9,.9));text.SetTextThickness(mm(.15));board.Add(text)
k.SaveBoard(str(d/'led_driver.kicad_pcb'),board)
(p/'placement_candidate.json').write_text(json.dumps({'outline_mm':[96,92],'layout_scope':'bench, not product housing fit','positions':positions,'thermal_vias_per_chip':6,'thermal_via_mm':[.6,.3],'tenting':'front and back, filled/capped process not qualified','routing':'ONLY preliminary REXT and logic decoupling, all other nets open','manufacturing':'HOLD'},indent=2)+'\n')
print('Saved20 circuit footprints +4 holes,18 thermal vias,9 ground vias; incomplete routing')
