def make_bom(): nl = parse_netlist('process-mbaas.net') parts = list(map(process_part, nl.parts)) part_groups = {} for p in parts: ref = ''.join([l for l in p['ref'][0] if l in string.ascii_letters]) k = ref + '-' + p['val'] + '-' + p['fp'] if p['desc'] is not None: k += '-' + p['desc'] if k in part_groups: part_groups[k] += [p] else: part_groups[k] = [p] bom_rows = {} for k in part_groups: pg = part_groups[k] row_key = '-'.join(sorted([refkey(p['ref']) for p in pg])) refs = ', '.join(sorted([p['ref'] for p in pg], key=refkey)) if pg[0]['desc'] is None: name = pg[0]['val'] val = '' else: name = pg[0]['desc'] val = pg[0]['val'] bom_rows[row_key] = dict(refs=refs, name=name, val=val, qty=len(pg), fp=pg[0]['fp']) with open('bom.csv', 'w', newline='') as csvfile: w = csv.writer(csvfile) w.writerow(['References', 'Component', 'Value', 'Qty', 'Footprint']) for k in sorted(bom_rows.keys()): row = bom_rows[k] w.writerow( [row['refs'], row['name'], row['val'], row['qty'], row['fp']])
#documentation https://xesscorp.github.io/kinparse/docs/_build/singlehtml/index.html from kinparse import parse_netlist netlist = parse_netlist( 'kicad-project/test_project_with_uC/test_project_with_uC.net') print(netlist.version) print("netlist date: " + netlist.date) cpu_refs = ['U1'] cpu_values = [] for part in netlist.parts: if part.ref in cpu_refs: cpu_values.append(part.value) print(cpu_values) print(netlist.nets)
def netlist_to_skidl(netlist_src): tab = " " * 4 def legalize(name): """Make a string into a legal python variable name.""" return re.sub("[^a-zA-Z0-9_]", "_", name) def comp_key(comp): """Create an ID key from component's major characteristics.""" chars = [c for c in [comp.lib, comp.name, comp.footprint] if len(c)] return legalize("_".join(chars)) def template_comp_to_skidl(template_comp): """Instantiate a component that will be used as a template.""" ltab = tab # Instantiate component template. name = comp_key(template_comp) # python variable name for template. lib = template_comp.lib part = template_comp.name tmpl = "{ltab}{name} = Part('{lib}', '{part}', dest=TEMPLATE".format(**locals()) footprint = template_comp.footprint if len(footprint): tmpl += ", footprint='{footprint}'".format(**locals()) tmpl += ")\n" # Set attributes of template using the component fields. for fld in template_comp.fields: tmpl += "{ltab}setattr({name}, '{fld.name}', '{fld.value}')\n".format( **locals() ) return tmpl def comp_to_skidl(comp, template_comps): """Instantiate components using the component templates.""" ltab = tab # Use the component key to get the template that matches this component. template_comp_name = comp_key(comp) template_comp = template_comps[template_comp_name] # Get the fields for the template. template_comp_fields = {fld.name: fld.value for fld in template_comp.fields} # Create a legal python variable for storing the instantiated component. ref = comp.ref legal_ref = legalize(ref) # Instantiate the component and its value (if any). inst = "{ltab}{legal_ref} = {template_comp_name}(ref='{ref}'".format(**locals()) if len(comp.value): inst += ", value='{comp.value}'".format(**locals()) inst += ")\n" # Set the fields of the instantiated component if they differ from the values in the template. for fld in comp.fields: if fld.value != template_comp_fields.get(fld.name, ""): inst += "{ltab}setattr({legal_ref}, '{fld.name}', '{fld.value}')\n".format( **locals() ) return inst def net_to_skidl(net): """Instantiate the nets between components.""" # Build a list of component pins attached to the net. pins = [] for pin in net.pins: comp = legalize(pin.ref) # Name of Python variable storing component. pin_num = pin.num # Pin number of component attached to net. pins.append("{comp}['{pin_num}']".format(**locals())) pins = ", ".join(pins) # String the pins into an argument list. ltab = tab # Instantiate the net, connect the pins to it, and return it. return "{ltab}Net('{net.name}').connect({pins})\n".format(**locals()) def _netlist_to_skidl(ntlst): """Convert a netlist into a skidl script.""" # Sequence of operations: # 1. Create a template for each component having a given library, part name and footprint. # 2. Instantiate each component using its matching template. Also, set any attributes # for the component that don't match those in the template. # 3. Instantiate the nets connecting the component pins. # 4. Call the script to instantiate the complete circuit. # 5. Generate the netlist for the circuit. ltab = tab section_div = "#" + "=" * 79 section_comment = ( "\n\n{ltab}{section_div}\n{ltab}# {section_desc}\n{ltab}{section_div}\n\n" ) skidl = "" skidl += "# -*- coding: utf-8 -*-\n\n" skidl += "from skidl import *\n\n\n" circuit_name = legalize(ntlst.source) skidl += "def {circuit_name}():".format(**locals()) section_desc = "Component templates." skidl += section_comment.format(**locals()) comp_templates = {comp_key(comp): comp for comp in ntlst.parts} template_statements = sorted( [template_comp_to_skidl(c) for c in list(comp_templates.values())] ) skidl += "\n".join(template_statements) section_desc = "Component instantiations." skidl += section_comment.format(**locals()) comp_inst_statements = sorted( [comp_to_skidl(c, comp_templates) for c in ntlst.parts] ) skidl += "\n".join(comp_inst_statements) section_desc = "Net interconnections between instantiated components." skidl += section_comment.format(**locals()) net_statements = sorted([net_to_skidl(n) for n in ntlst.nets]) skidl += "\n".join(net_statements) ltab = "" section_desc = "Instantiate the circuit and generate the netlist." skidl += section_comment.format(**locals()) ltab = tab skidl += 'if __name__ == "__main__":\n' skidl += "{ltab}{circuit_name}()\n".format(**locals()) skidl += "{ltab}generate_netlist()\n".format(**locals()) return skidl return _netlist_to_skidl(parse_netlist(netlist_src))
def netlist_to_skidl(netlist_src): tab = ' ' * 4 def legalize(name): """Make a string into a legal python variable name.""" return re.sub('[^a-zA-Z0-9_]', '_', name) def comp_key(comp): """Create an ID key from component's major characteristics.""" lib = comp.libsource.lib.val part = comp.libsource.part.val # Do not include the value in the key otherwise every capacitor or # resistor value will get its own template. try: footprint = comp.footprint.val return legalize('_'.join([lib, part, footprint])) except AttributeError: # Component has no assigned footprint. return legalize('_'.join([lib, part])) def template_comp_to_skidl(template_comp): """Instantiate a component that will be used as a template.""" ltab = tab # Instantiate component template. name = comp_key(template_comp) # python variable name for template. lib = template_comp.libsource.lib.val part = template_comp.libsource.part.val try: footprint = template_comp.footprint.val template_comp_skidl = "{ltab}{name} = Part('{lib}', '{part}', footprint='{footprint}', dest=TEMPLATE)\n".format( **locals()) except AttributeError: template_comp_skidl = "{ltab}{name} = Part('{lib}', '{part}', dest=TEMPLATE)\n".format( **locals()) # Set attributes of template using the component fields. for fld in template_comp.fields: template_comp_skidl += "{ltab}setattr({name}, '{fld.name.val}', '{fld.text}')\n".format( **locals()) return template_comp_skidl def comp_to_skidl(comp, template_comps): """Instantiate components using the component templates.""" ltab = tab # Use the component key to get the template that matches this component. template_comp_name = comp_key(comp) template_comp = template_comps[template_comp_name] # Get the fields for the template. template_comp_fields = { fld.name.val: fld.text for fld in template_comp.fields } # Create a legal python variable for storing the instantiated component. ref = comp.ref.val legal_ref = legalize(ref) # Instantiate the component and its value (if any). try: comp_skidl = "{ltab}{legal_ref} = {template_comp_name}(ref='{ref}', value='{comp.value.val}')\n".format( **locals()) except AttributeError: comp_skidl = "{ltab}{legal_ref} = {template_comp_name}(ref='{ref}')\n".format( **locals()) # Set the fields of the instantiated component if they differ from the values in the template. for fld in comp.fields: if fld.text != template_comp_fields.get(fld.name.val, ''): comp_skidl += "{ltab}setattr({legal_ref}, '{fld.name.val}', '{fld.text}')\n".format( **locals()) return comp_skidl def net_to_skidl(net): """Instantiate the nets between components.""" ltab = tab code = net.code.val # Unique code integer for each net. name = legalize('net__' + code) # Python variable name to storing net. net_name = net.name.val # Original net name from netlist. # Instantiate the net. net_skidl = "{ltab}{name} = Net('{net_name}')\n".format(**locals()) # Connect component pins to the net. net_skidl += "{ltab}{name} += ".format(**locals()) comp_pins = [] for n in net.nodes: comp_var = legalize( n.ref.val) # Python variable storing component. pin_num = n.pin.val # Pin number of component attached to net. comp_pins.append("{comp_var}['{pin_num}']".format(**locals())) net_skidl += ', '.join(comp_pins) + '\n' return net_skidl def _netlist_to_skidl(ntlst): """Convert a netlist into a skidl script.""" # Sequence of operations: # 1. Create a template for each component having a given library, part name and footprint. # 2. Instantiate each component using its matching template. Also, set any attributes # for the component that don't match those in the template. # 3. Instantiate the nets connecting the component pins. # 4. Call the script to instantiate the complete circuit. # 5. Generate the netlist for the circuit. ltab = tab section_div = '#' + '=' * 79 section_comment = "\n\n{ltab}{section_div}\n{ltab}# {section_desc}\n{ltab}{section_div}\n\n" skidl = '' skidl += '# -*- coding: utf-8 -*-\n\n' skidl += 'from skidl import *\n\n\n' circuit_name = legalize(ntlst.design.source.val) skidl += 'def {circuit_name}():'.format(**locals()) section_desc = 'Component templates.' skidl += section_comment.format(**locals()) comp_templates = {comp_key(comp): comp for comp in ntlst.components} template_statements = sorted( [template_comp_to_skidl(c) for c in list(comp_templates.values())]) skidl += '\n'.join(template_statements) section_desc = 'Component instantiations.' skidl += section_comment.format(**locals()) comp_inst_statements = sorted( [comp_to_skidl(c, comp_templates) for c in ntlst.components]) skidl += '\n'.join(comp_inst_statements) section_desc = 'Net interconnections between instantiated components.' skidl += section_comment.format(**locals()) net_statements = sorted([net_to_skidl(n) for n in ntlst.nets]) skidl += '\n'.join(net_statements) ltab = '' section_desc = 'Instantiate the circuit and generate the netlist.' skidl += section_comment.format(**locals()) ltab = tab skidl += 'if __name__ == "__main__":\n' skidl += '{ltab}{circuit_name}()\n'.format(**locals()) skidl += '{ltab}generate_netlist()\n'.format(**locals()) return skidl return _netlist_to_skidl(parse_netlist(netlist_src))
def main(): configure_logging() footprint = "conservify:TQFP-48_7x7mm_Pitch0.5mm" parser = argparse.ArgumentParser(description='') parser.add_argument('args', nargs='*') args = parser.parse_args() working = os.getcwd() processed_args = [] for arg in args.args: if os.path.isfile(arg): processed_args.append(os.path.abspath(arg)) combined = {} combined[footprint] = PinMap() pp = pprint.PrettyPrinter(indent=4, width=1) for child_filename in processed_args: logger.info("Processing: " + child_filename) nl = kinparse.parse_netlist(child_filename) netmap = {} parts = {} for n in nl.nets: name = n.name[0] connected = len(n.nodes) > 1 for node in n.nodes: ref = node.ref[0] pin = node.pin[0] refmap = netmap[ref] = netmap.get(ref, {}) if connected: refmap[pin] = refmap.get(pin, []) + [name] else: refmap[pin] = refmap.get(pin, []) + [name + "*"] for lp in nl.libparts: lp_key = lp.lib[0] + ":" + lp.part[0] parts[lp_key] = lp for c in nl.components: ref = c.ref[0] fp = c.footprint[0] lp_key = c.libsource[0] + ":" + c.libsource[1] if fp == footprint: logger.info("Match: ref=%s %s" % (ref, fp)) part = parts[lp_key] for pin in part.pins: num = pin.num[0] name = pin.name[0] nets = ", ".join(netmap[ref][num]).replace("/", "") combined[footprint].add(child_filename, ref, num, name, nets) if False: logger.info("- %s %s %s" % (num, name, nets)) for fp, pm in combined.iteritems(): print("| " + (" | ".join(["Pin"] + pm.boards() + ["Status"])) + " |") for pin in pm.pins(): print("| " + (" | ".join(pm.pin_row(pin))) + " |")
def kinet2pcb(netlist_origin, brd_filename): """Create a .kicad_pcb from a KiCad netlist file.""" # Get the global and local fp-lib-table file URIs. fp_libs = LibURIs(get_global_fp_lib_table_fn(), os.path.join(".", "fp-lib-table")) # Create a blank KiCad PCB. brd = pcbnew.BOARD() # Get the netlist. if isinstance(netlist_origin, type('')): # Parse the netlist into an object if given a file name string. netlist = kinparse.parse_netlist(netlist_origin) else: # otherwise, the netlist is already an object that can be processed directly. netlist = netlist_origin # Add the components in the netlist to the PCB. for part in netlist.parts: # Get the library and footprint name for the part. fp_lib, fp_name = part.footprint.split(":") # Get the URI of the library directory. lib_uri = fp_libs[fp_lib] # Create a module from the footprint file. fp = pcbnew.FootprintLoad(lib_uri, fp_name) # Set the module parameters based on the part data. #import pdb; pdb.set_trace() fp.SetParent(brd) fp.SetReference(part.ref) fp.SetValue(part.value) # fp.SetTimeStamp(part.sheetpath.tstamps) try: fp.SetPath(part.sheetpath.names) except AttributeError: pass # Add the module to the PCB. brd.Add(fp) # Add the nets in the netlist to the PCB. cnct = brd.GetConnectivity() for net in netlist.nets: # Create a net with the current net name. pcb_net = pcbnew.NETINFO_ITEM(brd, net.name) # Add the net to the PCB. brd.Add(pcb_net) # Connect the part pins on the netlist net to the PCB net. for pin in net.pins: # Find the PCB module pad for the current part pin. module = brd.FindModuleByReference(pin.ref) pad = module.FindPadByName(pin.num) # Connect the pad to the PCB net. cnct.Add(pad) pad.SetNet(pcb_net) # Recalculate the PCB part and net data. brd.BuildListOfNets() cnct.RecalculateRatsnest() pcbnew.Refresh() # Place the board parts into non-overlapping areas that follow the design hierarchy. hierplace.hier_place(brd) # Save the PCB into the KiCad PCB file. pcbnew.SaveBoard(brd_filename, brd)
#!/usr/bin/env python2.7 ''' This file attempts to get a list of the components from the netlist. ''' import sys, os, errno from kinparse import parse_netlist try: # Enter fn when running python file. eg: "python rsch.py [fn]" fn = sys.argv[1] # fn=filename except: # If you don't enter a fn, but an existing file matches the # keyword below, it will find the file. # i.e. "first matching file in ./" import glob fn = glob.glob('./*.net')[0] fn_base = os.path.splitext(fn)[0] # fn without the . extension print("Loading file: %s" % fn) # Load netlist nl = parse_netlist(fn) print('Netlist generated from: {}'.format(nl.design.source.val))