master
John Lauer Add live Fusion net routing with verified copper and recorded demo 0418917 1mo ago
"""Author an unrouted EAGLE routing coupon and a matching schematic, offline."""
from pathlib import Path
import copy
import json
import xml.etree.ElementTree as ET


def make(directory):
    directory = Path(directory)
    directory.mkdir(parents=True, exist_ok=True)
    layers = ET.parse(Path(__file__).resolve().parents[2] / 'examples/ADS8588SIPM.fusion.lbr').find('drawing/layers')
    def new(kind):
        root = ET.Element('eagle', version='9.6.2')
        drawing = ET.SubElement(root, 'drawing')
        ET.SubElement(drawing, 'settings')
        ET.SubElement(drawing, 'grid', distance='0.1', unitdist='mm', unit='mm', style='lines', multiple='1', display='no', altdistance='0.01', altunitdist='mm', altunit='mm')
        drawing.append(copy.deepcopy(layers))
        return root, ET.SubElement(drawing, kind)
    lib = ET.Element('library', name='RoutingFixture')
    packages = ET.SubElement(lib, 'packages')
    symbols = ET.SubElement(lib, 'symbols')
    sets = ET.SubElement(lib, 'devicesets')
    for count in (1, 6):
        name = f'TESTPOINTS_{count}'
        pkg = ET.SubElement(packages, 'package', name=name)
        sym = ET.SubElement(symbols, 'symbol', name=name)
        ds = ET.SubElement(sets, 'deviceset', name=name, prefix='J')
        ET.SubElement(ET.SubElement(ds, 'gates'), 'gate', name='G$1', symbol=name, x='0', y='0')
        device = ET.SubElement(ET.SubElement(ds, 'devices'), 'device', name='', package=name)
        connects = ET.SubElement(device, 'connects')
        for i in range(1, count+1):
            ET.SubElement(pkg, 'pad', name=str(i), x='0', y=str((i-1)*5), drill='1', diameter='2', shape='round')
            ET.SubElement(sym, 'pin', name=str(i), x='0', y=str((i-1)*5), length='short', direction='pas')
            ET.SubElement(connects, 'connect', gate='G$1', pin=str(i), pad=str(i))
        ET.SubElement(ET.SubElement(device, 'technologies'), 'technology', name='')
    br, board = new('board')
    plain = ET.SubElement(board, 'plain')
    for a,b in zip([(0,0),(54,0),(54,44),(0,44)],[(54,0),(54,44),(0,44),(0,0)]):
        ET.SubElement(plain,'wire', x1=str(a[0]),y1=str(a[1]),x2=str(b[0]),y2=str(b[1]),width='0',layer='20')
    ET.SubElement(plain,'text',x='13',y='40',size='1.5',layer='21').text='FUSION TRACE ROUTING'
    ET.SubElement(board,'libraries').append(copy.deepcopy(lib))
    ET.SubElement(board,'attributes'); ET.SubElement(board,'variantdefs')
    ET.SubElement(ET.SubElement(board,'classes'),'class',number='0',name='default',width='0.25',drill='0.3')
    rules = ET.SubElement(board,'designrules',name='RoutingFixture')
    for name,value in {'layerSetup':'(1*16)','mdWireWire':'0.2mm','mdWirePad':'0.2mm','mdWireVia':'0.2mm','msWidth':'0.2mm','msDrill':'0.3mm','mdCopperDimension':'0.5mm'}.items():
        ET.SubElement(rules,'param',name=name,value=value)
    elements=ET.SubElement(board,'elements')
    positions={'J1':(7,7,6),'J2':(47,7,6),'J3':(27,38,1)}
    for ref,(x,y,n) in positions.items():
        ET.SubElement(elements,'element',name=ref,library='RoutingFixture',package=f'TESTPOINTS_{n}',value='ROUTING_TEST',x=str(x),y=str(y))
    signals=ET.SubElement(board,'signals'); plan=[]
    for i in range(1,7):
        s=ET.SubElement(signals,'signal',name=f'NET_{i}')
        for ref in ('J1','J2'): ET.SubElement(s,'contactref',element=ref,pad=str(i))
        if i==6: ET.SubElement(s,'contactref',element='J3',pad='1')
        y=7+(i-1)*5
        pts=[{'pad':f'J1.{i}'},[14,y],[40,y],{'pad':f'J2.{i}'}]
        if i==3: pts=[{'pad':'J1.3'},{'x':14,'y':y,'layer':16},{'x':40,'y':y,'layer':1},{'pad':'J2.3'}]
        paths=[pts]
        if i==6: paths.append([[27,y],[27,35],{'pad':'J3.1'}])
        plan.append({'net':f'NET_{i}','layer':1,'width':0.25,'paths':paths})
    sr,sch=new('schematic')
    ET.SubElement(sch,'libraries').append(copy.deepcopy(lib))
    ET.SubElement(sch,'attributes'); ET.SubElement(sch,'variantdefs')
    ET.SubElement(ET.SubElement(sch,'classes'),'class',number='0',name='default',width='0.25',drill='0.3')
    parts=ET.SubElement(sch,'parts')
    sheet=ET.SubElement(ET.SubElement(sch,'sheets'),'sheet'); ET.SubElement(sheet,'plain')
    instances=ET.SubElement(sheet,'instances')
    for ref,(x,y,n) in positions.items():
        ET.SubElement(parts,'part',name=ref,library='RoutingFixture',deviceset=f'TESTPOINTS_{n}',device='',value='ROUTING_TEST')
        ET.SubElement(instances,'instance',part=ref,gate='G$1',x=str(x),y=str(y))
    ET.SubElement(sheet,'busses'); nets=ET.SubElement(sheet,'nets')
    for i in range(1,7):
        net=ET.SubElement(nets,'net',{'name':f'NET_{i}','class':'0'})
        seg=ET.SubElement(net,'segment'); y=7+(i-1)*5
        for ref in ('J1','J2'): ET.SubElement(seg,'pinref',part=ref,gate='G$1',pin=str(i))
        ET.SubElement(seg,'wire',x1='7',y1=str(y),x2='47',y2=str(y),width='0.1524',layer='91')
        if i==6:
            ET.SubElement(seg,'pinref',part='J3',gate='G$1',pin='1')
            ET.SubElement(seg,'wire',x1='27',y1=str(y),x2='27',y2='38',width='0.1524',layer='91')
            ET.SubElement(seg,'junction',x='27',y=str(y))
    for suffix,root in [('brd',br),('sch',sr)]:
        ET.indent(root)
        (directory/f'fusion-routing.{suffix}').write_text('<?xml version="1.0" encoding="utf-8"?>\n<!DOCTYPE eagle SYSTEM "eagle.dtd">\n'+ET.tostring(root,encoding='unicode'))
    (directory/'plan.json').write_text(json.dumps(plan,indent=2)+'\n')
    return directory


if __name__ == '__main__':
    import sys
    print(make(sys.argv[1]))