import sys import os from pcbnew import * filename = sys.argv[1] pcb = LoadBoard(filename) ToUnits = ToMM FromUnits = FromMM print("") print("List drawings:") # layers = pcb.GetEnabledLayers() top_layer_id = pcb.GetLayerID("F.Cu") new_foots = {} foot_name = "" foot_path = "" for item in pcb.GetDrawings(): if type(item) is PCB_TEXT and "User.Drawings" in item.GetLayerName(): lines = str(item.GetText()).splitlines() # Must have the correct header if "Foot Pinout" not in lines[0]: continue if not lines[1].startswith("Name:"): continue foot_name = lines[1].split(":")[-1].strip() if not lines[2].startswith("Path:"): continue foot_path = lines[2].split(":")[-1].strip() for line in lines[3:]: sp = line.split(':', 1) if len(sp) != 2: continue # Path to substitue footprint ref = sp[0] foot_sp = sp[1].split(',') foot = foot_sp[0].strip() offset = (0,0) # Optional offset tuple if len(foot_sp) == 2: offset = tuple(foot_sp[1]) new_foots[ref] = [foot, offset] # pins = sp[1] # pin_refs = [] # for pin in pins.split(','): # pin_refs.push(int(pin)) break elif type(item) is PCB_TEXT: print("Text: ", item.GetText()) print("Layer: ", item.GetLayerName()) print("") print("New Footprint List: ", new_foots) # Clear tracks pcb.Tracks().clear() # Clear zones pcb.Zones().clear() # Clear Drawings pcb.Drawings().clear() # Keep only required foots saved = [] while len(pcb.Footprints()) > 1: foot = pcb.Footprints().pop() if foot.GetReference() in new_foots.keys(): saved.append(foot) # just in case pcb.DeleteAllFootprints() # Add them back sorted_pads = [] for foot in saved: vals = new_foots[foot.GetReference()] # Change the footprint foot.SetFPIDAsString(vals[0]) # Save the original postion of footprint + pads orig_cent = foot.GetBoundingBox(False,False).Centre() pads = [] for pad in foot.Pads(): pads.append([pad.GetCenter(), pad.GetNet()]) # Flip to other side foot.SetLayerAndFlip(top_layer_id) # Put back in original position with an offset box = foot.GetBoundingBox(False,False) new_cent = foot.GetBoundingBox(False,False).Centre() cent_diff = orig_cent - new_cent foot.SetX(foot.GetX() + cent_diff.x + vals[1][0]) foot.SetY(foot.GetY() + cent_diff.y + vals[1][1]) # Flip the net assignments of the pads for pad in foot.Pads(): sorted_pads.append(pad) # Check position diff from old # to new new_cent = pad.GetCenter() diffs = [] for [old_cent,_] in pads: diffs.append(new_cent - old_cent) min_diff = min(diffs) # If pad is within 0.05mm it's a match if (min_diff.x**2 + min_diff.y**2)**0.5 < 50000: # Set the net to what the old pad was i = diffs.index(min_diff) match_pad = pads[i][1:] pad.SetNet(match_pad[0]) pcb.Add(foot) # Sort by Y sorted_pads.sort(key=lambda p: p.GetY()) box = pcb.GetBoundingBox() brd_width = ToUnits(box.GetWidth()) brd_height = ToUnits(box.GetHeight()) print("Box: ", box) print("W: ", brd_width, "H: ", brd_height) sys.path.append(os.path.join(sys.path[0],"../../../../../dev/kicad-footprint-generator")) from KicadModTree import * from KicadModTree.nodes.specialized.PadArray import PadArray footprint_name = "" # init kicad footprint kicad_mod = Footprint(footprint_name, FootprintType.SMD) kicad_mod.setDescription("A example footprint") kicad_mod.setTags("example") # set general values kicad_mod.append(Text(type='reference', text='REF**', at=[0,-3], layer='F.SilkS')) kicad_mod.append(Text(type='value', text=footprint_name, at=[1.5,3], layer='F.Fab')) # create silscreen kicad_mod.append(RectLine(start=[-brd_width/2,-brd_height/2], end=[brd_width/2,brd_height/2], layer='F.SilkS', width=0.15)) # create courtyard kicad_mod.append(RectLine(start=[-brd_width/2 - 0.1,-brd_height/2 - 0.1], end=[brd_width/2 + 0.1,brd_height/2 + 0.1], layer='F.CrtYd', width=0.05, offset=2)) # create pads for x, pad in enumerate(sorted_pads): cent = ToUnits(pad.GetCenter()) pad_size = ToUnits(pad.GetSize()) drill_size = ToUnits(pad.GetDrillSize()) kicad_mod.append(Pad(number=x, type=Pad.TYPE_THT, shape=Pad.SHAPE_RECT, at=list(cent), size=list(pad_size), drill=list(drill_size), layers=['*.Cu', '*.Mask', 'F.SilkS'])) # kicad_mod.append(Pad(number=22, type=Pad.TYPE_THT, shape=Pad.SHAPE_CIRCLE, at=[3,0], size=[2,2], drill=1.2, layers=['*.Cu', '*.Mask', 'F.SilkS'])) # # kicad_mod.append(Pad(number=12, type=Pad.TYPE_SMT, shape=Pad.SHAPE_RECT, at=[3,0], size=[2,2], drill=1.2, layers=['*.Cu', '*.Mask', 'F.SilkS'])) # add model # kicad_mod.append(Model(filename="example.3dshapes/example_footprint.wrl" # ,at=[0,0,0] # ,scale=[1,1,1] # ,rotate=[0,0,0])) # kicad_mod.append(PadArray(pincount=10,spacing=[1,-1],center=[0,0], initial=5, increment=2, type=Pad.TYPE_SMT, shape=Pad.SHAPE_RECT, size=[1,2], layers=["*.Cu"])) # output kicad model #print(kicad_mod) # print render tree #print(kicad_mod.getRenderTree()) #print(kicad_mod.getCompleteRenderTree()) # write file file_handler = KicadFileHandler(kicad_mod) file_handler.writeFile('example_footprint.kicad_mod') SaveBoard("test/test.kicad_pcb", pcb)