diff options
Diffstat (limited to 'eeschema/plugins')
18 files changed, 2422 insertions, 0 deletions
diff --git a/eeschema/plugins/CMakeLists.txt b/eeschema/plugins/CMakeLists.txt new file mode 100644 index 0000000..7ad2757 --- /dev/null +++ b/eeschema/plugins/CMakeLists.txt @@ -0,0 +1,30 @@ +# Install the *.xsl file(s), user will need to install 'xsltproc' and setup +# EESCHEMA's netlist plugins +# See chapter 14 of eeschema.pdf + + +set( XSL_SCRIPTS_LIST + xsl_scripts/bom_with_title_block_2_csv.xsl + xsl_scripts/bom2csv.xsl + xsl_scripts/bom2grouped_csv.xsl + xsl_scripts/netlist_form_cadstar-RINF.xsl + xsl_scripts/netlist_form_cadstar.xsl + xsl_scripts/netlist_form_OrcadPcb2.xsl + xsl_scripts/netlist_form_pads-pcb.xsl + ) + +set( PYTHON_SCRIPTS_LIST + python_scripts/README-bom.txt + python_scripts/kicad_netlist_reader.py + python_scripts/bom_csv_grouped_by_value.py + python_scripts/bom_csv_grouped_by_value_with_fp.py + python_scripts/bom_csv_sorted_by_ref.py + python_scripts/bom_html_grouped_by_value.py + python_scripts/bom_html_with_advanced_grouping.py + python_scripts/bom_sorted_by_ref.py + ) + +install( FILES ${XSL_SCRIPTS_LIST} ${PYTHON_SCRIPTS_LIST} + DESTINATION ${KICAD_PLUGINS} + COMPONENT binary + ) diff --git a/eeschema/plugins/python_scripts/README-bom.txt b/eeschema/plugins/python_scripts/README-bom.txt new file mode 100644 index 0000000..7a53d7d --- /dev/null +++ b/eeschema/plugins/python_scripts/README-bom.txt @@ -0,0 +1,38 @@ +bom_?.py are some python scripts which read a generic xml netlist from eeschema, +and create a bom. + +All examples use kicad_netlist_reader.py, which is a python utility to read +and parse this generic xml netlist and create the corresponding data +used to build the bom. + +You can modify them to build the bom you want. + +to use them, you should install python, and run: +python bom_example?.py <netlist name> <bom list netname> + +See Eeschema doc, chapter 14 for info about the generic xml netlist format, +and how to run a script from Eeschema to create a customized netlist or BOM. + +If the python comment +""" + @package + some comments +""" +is added to the begining of the python script, the comment will be displayed +in Eescheam, in the BOM dialog + +For instance: +""" + @package + Generate a HTML BOM list. + Components are sorted and grouped by value + Fields are (if exist) + Ref, Quantity, Value, Part, Datasheet, Description, Vendor +""" + +displays: + Generate a HTML BOM list. + Components are sorted and grouped by value + Fields are (if exist) + Ref, Quantity, Value, Part, Datasheet, Description, Vendor +in BOM dialog diff --git a/eeschema/plugins/python_scripts/bom_csv_grouped_by_value.py b/eeschema/plugins/python_scripts/bom_csv_grouped_by_value.py new file mode 100644 index 0000000..b582d61 --- /dev/null +++ b/eeschema/plugins/python_scripts/bom_csv_grouped_by_value.py @@ -0,0 +1,167 @@ +# +# Example python script to generate a BOM from a KiCad generic netlist +# +# Example: Sorted and Grouped CSV BOM +# +""" + @package + Generate a csv BOM list. + Components are sorted by ref and grouped by value + Fields are (if exist) + Item, Qty, Reference(s), Value, LibPart, Footprint, Datasheet + + Command line: + python "pathToFile/bom_csv_grouped_by_value.py" "%I" "%O.csv" +""" + +from __future__ import print_function + +# Import the KiCad python helper module and the csv formatter +import kicad_netlist_reader +import csv +import sys + +def myEqu(self, other): + """myEqu is a more advanced equivalence function for components which is + used by component grouping. Normal operation is to group components based + on their value and footprint. + + In this example of a custom equivalency operator we compare the + value, the part name and the footprint. + """ + result = True + if self.getValue() != other.getValue(): + result = False + elif self.getPartName() != other.getPartName(): + result = False + elif self.getFootprint() != other.getFootprint(): + result = False + + return result + +# Override the component equivalence operator - it is important to do this +# before loading the netlist, otherwise all components will have the original +# equivalency operator. +kicad_netlist_reader.comp.__eq__ = myEqu + +if len(sys.argv) != 3: + print("Usage ", __file__, "<generic_netlist.xml> <output.csv>", file=sys.stderr) + sys.exit(1) + + +# Generate an instance of a generic netlist, and load the netlist tree from +# the command line option. If the file doesn't exist, execution will stop +net = kicad_netlist_reader.netlist(sys.argv[1]) + +# Open a file to write to, if the file cannot be opened output to stdout +# instead +try: + f = open(sys.argv[2], 'w') +except IOError: + e = "Can't open output file for writing: " + sys.argv[2] + print( __file__, ":", e, sys.stderr ) + f = sys.stdout + +# subset the components to those wanted in the BOM, controlled +# by <configure> block in kicad_netlist_reader.py +components = net.getInterestingComponents() + +compfields = net.gatherComponentFieldUnion(components) +partfields = net.gatherLibPartFieldUnion() + +# remove Reference, Value, Datasheet, and Footprint, they will come from 'columns' below +partfields -= set( ['Reference', 'Value', 'Datasheet', 'Footprint'] ) + +columnset = compfields | partfields # union + +# prepend an initial 'hard coded' list and put the enchillada into list 'columns' +columns = ['Item', 'Qty', 'Reference(s)', 'Value', 'LibPart', 'Footprint', 'Datasheet'] + sorted(list(columnset)) + +# Create a new csv writer object to use as the output formatter +out = csv.writer( f, lineterminator='\n', delimiter=',', quotechar='\"', quoting=csv.QUOTE_ALL ) + +# override csv.writer's writerow() to support encoding conversion (initial encoding is utf8): +def writerow( acsvwriter, columns ): + utf8row = [] + for col in columns: + utf8row.append( str(col) ) # currently, no change + acsvwriter.writerow( utf8row ) + +# Output a set of rows as a header providing general information +writerow( out, ['Source:', net.getSource()] ) +writerow( out, ['Date:', net.getDate()] ) +writerow( out, ['Tool:', net.getTool()] ) +writerow( out, ['Generator:', sys.argv[0]] ) +writerow( out, ['Component Count:', len(components)] ) +writerow( out, [] ) +writerow( out, ['Individual Components:'] ) +writerow( out, [] ) # blank line +writerow( out, columns ) + +# Output all the interesting components individually first: +row = [] +for c in components: + del row[:] + row.append('') # item is blank in individual table + row.append('') # Qty is always 1, why print it + row.append( c.getRef() ) # Reference + row.append( c.getValue() ) # Value + row.append( c.getLibName() + ":" + c.getPartName() ) # LibPart + #row.append( c.getDescription() ) + row.append( c.getFootprint() ) + row.append( c.getDatasheet() ) + + # from column 7 upwards, use the fieldnames to grab the data + for field in columns[7:]: + row.append( c.getField( field ) ); + + writerow( out, row ) + + +writerow( out, [] ) # blank line +writerow( out, [] ) # blank line +writerow( out, [] ) # blank line + +writerow( out, ['Collated Components:'] ) +writerow( out, [] ) # blank line +writerow( out, columns ) # reuse same columns + + + +# Get all of the components in groups of matching parts + values +# (see kicad_netlist_reader.py) +grouped = net.groupComponents(components) + + +# Output component information organized by group, aka as collated: +item = 0 +for group in grouped: + del row[:] + refs = "" + + # Add the reference of every component in the group and keep a reference + # to the component so that the other data can be filled in once per group + for component in group: + if len(refs) > 0: + refs += ", " + refs += component.getRef() + c = component + + # Fill in the component groups common data + # columns = ['Item', 'Qty', 'Reference(s)', 'Value', 'LibPart', 'Footprint', 'Datasheet'] + sorted(list(columnset)) + item += 1 + row.append( item ) + row.append( len(group) ) + row.append( refs ); + row.append( c.getValue() ) + row.append( c.getLibName() + ":" + c.getPartName() ) + row.append( net.getGroupFootprint(group) ) + row.append( net.getGroupDatasheet(group) ) + + # from column 7 upwards, use the fieldnames to grab the data + for field in columns[7:]: + row.append( net.getGroupField(group, field) ); + + writerow( out, row ) + +f.close() diff --git a/eeschema/plugins/python_scripts/bom_csv_grouped_by_value_with_fp.py b/eeschema/plugins/python_scripts/bom_csv_grouped_by_value_with_fp.py new file mode 100644 index 0000000..dd14af0 --- /dev/null +++ b/eeschema/plugins/python_scripts/bom_csv_grouped_by_value_with_fp.py @@ -0,0 +1,65 @@ +# +# Example python script to generate a BOM from a KiCad generic netlist +# +# Example: Sorted and Grouped CSV BOM +# + +""" + @package + Generate a Tab delimited list (csv file type). + Components are sorted by ref and grouped by value with same footprint + Fields are (if exist) + 'Ref', 'Qnty', 'Value', 'Cmp name', 'Footprint', 'Description', 'Vendor' + + Command line: + python "pathToFile/bom_csv_grouped_by_value_with_fp.py" "%I" "%O.csv" +""" + +# Import the KiCad python helper module and the csv formatter +import kicad_netlist_reader +import csv +import sys + +# Generate an instance of a generic netlist, and load the netlist tree from +# the command line option. If the file doesn't exist, execution will stop +net = kicad_netlist_reader.netlist(sys.argv[1]) + +# Open a file to write to, if the file cannot be opened output to stdout +# instead +try: + f = open(sys.argv[2], 'w') +except IOError: + e = "Can't open output file for writing: " + sys.argv[2] + print(__file__, ":", e, sys.stderr) + f = sys.stdout + +# Create a new csv writer object to use as the output formatter +out = csv.writer(f, lineterminator='\n', delimiter=',', quotechar='\"', quoting=csv.QUOTE_ALL) + +# Output a set of rows for a header providing general information +out.writerow(['Source:', net.getSource()]) +out.writerow(['Date:', net.getDate()]) +out.writerow(['Tool:', net.getTool()]) +out.writerow( ['Generator:', sys.argv[0]] ) +out.writerow(['Component Count:', len(net.components)]) +out.writerow(['Ref', 'Qnty', 'Value', 'Cmp name', 'Footprint', 'Description', 'Vendor']) + +# Get all of the components in groups of matching parts + values +# (see ky_generic_netlist_reader.py) +grouped = net.groupComponents() + +# Output all of the component information +for group in grouped: + refs = "" + + # Add the reference of every component in the group and keep a reference + # to the component so that the other data can be filled in once per group + for component in group: + refs += component.getRef() + ", " + c = component + + # Fill in the component groups common data + out.writerow([refs, len(group), c.getValue(), c.getPartName(), c.getFootprint(), + c.getDescription(), c.getField("Vendor")]) + + diff --git a/eeschema/plugins/python_scripts/bom_csv_sorted_by_ref.py b/eeschema/plugins/python_scripts/bom_csv_sorted_by_ref.py new file mode 100644 index 0000000..e66cc13 --- /dev/null +++ b/eeschema/plugins/python_scripts/bom_csv_sorted_by_ref.py @@ -0,0 +1,62 @@ +# +# Example python script to generate a BOM from a KiCad generic netlist +# +# Example: Ungrouped (One component per row) CSV output +# + +""" + @package + Generate a csv list file. + Components are sorted by ref + One component per line + Fields are (if exist) + Ref, value, Part, footprint, Datasheet, Manufacturer, Vendor + + Command line: + python "pathToFile/bom_csv_sorted_by_ref.py" "%I" "%O.csv" +""" + +from __future__ import print_function + +# Import the KiCad python helper module +import kicad_netlist_reader +import csv +import sys + +# Generate an instance of a generic netlist, and load the netlist tree from +# the command line option. If the file doesn't exist, execution will stop +net = kicad_netlist_reader.netlist(sys.argv[1]) + +# Open a file to write to, if the file cannot be opened output to stdout +# instead +try: + f = open(sys.argv[2], 'w') +except IOError: + e = "Can't open output file for writing: " + sys.argv[2] + print( __file__, ":", e, sys.stderr ) + f = sys.stdout + +# Create a new csv writer object to use as the output formatter +out = csv.writer(f, lineterminator='\n', delimiter=',', quotechar="\"", quoting=csv.QUOTE_ALL) + +# override csv.writer's writerow() to support utf8 encoding: +def writerow( acsvwriter, columns ): + utf8row = [] + for col in columns: + utf8row.append( str(col) ) + acsvwriter.writerow( utf8row ) + +components = net.getInterestingComponents() + +# Output a field delimited header line +writerow( out, ['Source:', net.getSource()] ) +writerow( out, ['Date:', net.getDate()] ) +writerow( out, ['Tool:', net.getTool()] ) +writerow( out, ['Component Count:', len(components)] ) +writerow( out, ['Ref', 'Value', 'Footprint', 'Datasheet', 'Manufacturer', 'Vendor'] ) + +# Output all of the component information (One component per row) +for c in components: + writerow( out, [c.getRef(), c.getValue(), c.getFootprint(), c.getDatasheet(), + c.getField("Manufacturer"), c.getField("Vendor")]) + diff --git a/eeschema/plugins/python_scripts/bom_html_grouped_by_value.py b/eeschema/plugins/python_scripts/bom_html_grouped_by_value.py new file mode 100644 index 0000000..80def66 --- /dev/null +++ b/eeschema/plugins/python_scripts/bom_html_grouped_by_value.py @@ -0,0 +1,98 @@ +# +# Example python script to generate a BOM from a KiCad generic netlist +# +# Example: Sorted and Grouped HTML BOM +# +""" + @package + Generate a HTML BOM list. + Components are sorted by ref and grouped by value + Fields are (if exist) + Ref, Quantity, Value, Part, Datasheet, Description, Vendor + + Command line: + python "pathToFile/bom_html_grouped_by_value.py" "%I" "%O.html" +""" + +from __future__ import print_function + +# Import the KiCad python helper module and the csv formatter +import kicad_netlist_reader +import sys + +# Start with a basic html template +html = """ +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" + "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml"> + <head> + <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> + </head> + <body> + <h1><!--SOURCE--></h1> + <p><!--DATE--></p> + <p><!--TOOL--></p> + <p><!--COMPCOUNT--></p> + <table> + <!--TABLEROW--> + </table> + </body> +</html> + """ + +# Generate an instance of a generic netlist, and load the netlist tree from +# the command line option. If the file doesn't exist, execution will stop +net = kicad_netlist_reader.netlist(sys.argv[1]) + +# Open a file to write to, if the file cannot be opened output to stdout +# instead +try: + f = open(sys.argv[2], 'w') +except IOError: + e = "Can't open output file for writing: " + sys.argv[2] + print(__file__, ":", e, file=sys.stderr) + f = sys.stdout + +components = net.getInterestingComponents() + +# Output a set of rows for a header providing general information +html = html.replace('<!--SOURCE-->', net.getSource()) +html = html.replace('<!--DATE-->', net.getDate()) +html = html.replace('<!--TOOL-->', net.getTool()) +html = html.replace('<!--COMPCOUNT-->', "<b>Component Count:</b>" + \ + str(len(components))) + +row = "<tr><th style='width:640px'>Ref</th>" +row += "<th>Qnty</th>" +row += "<th>Value</th>" + "<th>Part</th>" + "<th>Datasheet</th>" +row += "<th>Description</th>" + "<th>Vendor</th></tr>" + +html = html.replace('<!--TABLEROW-->', row + "<!--TABLEROW-->") + +# Get all of the components in groups of matching parts + values +# (see kicad_netlist_reader.py) +grouped = net.groupComponents(components) + +# Output all of the component information +for group in grouped: + refs = "" + + # Add the reference of every component in the group and keep a reference + # to the component so that the other data can be filled in once per group + for component in group: + if len(refs) > 0: + refs += ", " + refs += component.getRef() + c = component + + row = "<tr><td>" + refs +"</td><td>" + str(len(group)) + row += "</td><td>" + c.getValue() + row += "</td><td>" + c.getLibName() + ":" + c.getPartName() + row += "</td><td>" + c.getDatasheet() + row += "</td><td>" + c.getDescription() + row += "</td><td>" + c.getField("Vendor")+ "</td></tr>" + + html = html.replace('<!--TABLEROW-->', row + "<!--TABLEROW-->") + +# Print the formatted html to the file +print(html, file=f) diff --git a/eeschema/plugins/python_scripts/bom_html_with_advanced_grouping.py b/eeschema/plugins/python_scripts/bom_html_with_advanced_grouping.py new file mode 100644 index 0000000..a091351 --- /dev/null +++ b/eeschema/plugins/python_scripts/bom_html_with_advanced_grouping.py @@ -0,0 +1,132 @@ +# +# Example python script to generate a BOM from a KiCad generic netlist +# +# Example: Sorted and Grouped HTML BOM with advanced grouping +# + +""" + @package + Generate a HTML BOM list. + Components are sorted and grouped by value + Fields are (if exist) + Ref, Quantity, Value, Part, Footprint, Description, Vendor + + Command line: + python "pathToFile/bom_with_advanced_grouping.py" "%I" "%O.html" +""" + + +from __future__ import print_function + +# Import the KiCad python helper module and the csv formatter +import kicad_netlist_reader +import sys + +# Start with a basic html template +html = """ +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" + "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml"> + <head> + <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> + <title>KiCad BOM Example 5</title> + </head> + <body> + <h1><!--SOURCE--></h1> + <p><!--DATE--></p> + <p><!--TOOL--></p> + <p><!--COMPCOUNT--></p> + <table> + <!--TABLEROW--> + </table> + </body> +</html> + """ + +def myEqu(self, other): + """myEqu is a more advanced equivalence function for components which is + used by component grouping. Normal operation is to group components based + on their Value and Footprint. + + In this example of a more advanced equivalency operator we also compare the + custom fields Voltage, Tolerance and Manufacturer as well as the assigned + footprint. If these fields are not used in some parts they will simply be + ignored (they will match as both will be empty strings). + + """ + result = True + if self.getValue() != other.getValue(): + result = False + elif self.getPartName() != other.getPartName(): + result = False + elif self.getFootprint() != other.getFootprint(): + result = False + elif self.getField("Tolerance") != other.getField("Tolerance"): + result = False + elif self.getField("Manufacturer") != other.getField("Manufacturer"): + result = False + elif self.getField("Voltage") != other.getField("Voltage"): + result = False + + return result + +# Override the component equivalence operator - it is important to do this +# before loading the netlist, otherwise all components will have the original +# equivalency operator. +kicad_netlist_reader.comp.__eq__ = myEqu + +# Generate an instance of a generic netlist, and load the netlist tree from +# <file>.tmp. If the file doesn't exist, execution will stop +net = kicad_netlist_reader.netlist(sys.argv[1]) + +# Open a file to write too, if the file cannot be opened output to stdout +# instead +try: + f = open(sys.argv[2], 'w') +except IOError: + e = "Can't open output file for writing: " + sys.argv[2] + print(__file__, ":", e, file=sys.stderr) + f = sys.stdout + +# Output a set of rows for a header providing general information +html = html.replace('<!--SOURCE-->', net.getSource()) +html = html.replace('<!--DATE-->', net.getDate()) +html = html.replace('<!--TOOL-->', net.getTool()) +html = html.replace('<!--COMPCOUNT-->', "<b>Component Count:</b>" + \ + str(len(net.components))) + +row = "<tr><th style='width:640px'>Ref</th>" + "<th>Qnty</th>" +row += "<th>Value</th>" + "<th>Part</th>" + "<th>Footprint</th>" +row += "<th>Description</th>" + "<th>Vendor</th></tr>" + +html = html.replace('<!--TABLEROW-->', row + "<!--TABLEROW-->") + +components = net.getInterestingComponents() + +# Get all of the components in groups of matching parts + values +# (see kicad_netlist_reader.py) +grouped = net.groupComponents(components) + +# Output all of the component information +for group in grouped: + refs = "" + + # Add the reference of every component in the group and keep a reference + # to the component so that the other data can be filled in once per group + for component in group: + if len(refs) > 0: + refs += ", " + refs += component.getRef() + c = component + + row = "\n " + row += "<tr><td>" + refs +"</td><td>" + str(len(group)) + row += "</td><td>" + c.getValue() + "</td><td>" + c.getLibName() + ":" + row += c.getPartName() + "</td><td>" + c.getFootprint() + "</td><td>" + row += c.getDescription() + "</td><td>" + c.getField("Vendor") + row += "</td></tr>" + + html = html.replace('<!--TABLEROW-->', row + "<!--TABLEROW-->") + +# Print the formatted html to output file +print(html, file=f) diff --git a/eeschema/plugins/python_scripts/bom_sorted_by_ref.py b/eeschema/plugins/python_scripts/bom_sorted_by_ref.py new file mode 100644 index 0000000..6dd28d5 --- /dev/null +++ b/eeschema/plugins/python_scripts/bom_sorted_by_ref.py @@ -0,0 +1,61 @@ +# +# Example python script to generate a BOM from a KiCad generic netlist +# +""" + @package + Generate a BOM list file (a simple text). + Components are sorted by ref + One component per line + Fields are (if exist) + Ref, Quantity, value, Part, footprint, Description, Vendor + Fields are separated by tabs + + Command line: + python "pathToFile/bom_sorted_by_ref.py" "%I" "%O.txt" +""" + +from __future__ import print_function + +# Import the KiCad python helper module and the csv formatter +import kicad_netlist_reader +import csv +import sys + +# Generate an instance of a generic netlist, and load the netlist tree from +# the command line option. If the file doesn't exist, execution will stop +net = kicad_netlist_reader.netlist(sys.argv[1]) + +# Open a file to write to, if the file cannot be opened output to stdout +# instead +try: + f = open(sys.argv[2], 'w') +except IOError: + e = "Can't open output file for writing: " + sys.argv[2] + print(__file__, ":", e, sys.stderr) + f = sys.stdout + +# Create a new csv writer object to use as the output formatter, although we +# are created a tab delimited list instead! +out = csv.writer(f, lineterminator='\n', delimiter='\t', quoting=csv.QUOTE_NONE) + +# override csv.writer's writerow() to support utf8 encoding: +def writerow( acsvwriter, columns ): + utf8row = [] + for col in columns: + txt=str(col); + utf8row.append( txt ) + acsvwriter.writerow( utf8row ) + +components = net.getInterestingComponents() + +# Output a field delimited header line +writerow( out, ['Source:', net.getSource()] ) +writerow( out, ['Date:', net.getDate()] ) +writerow( out, ['Tool:', net.getTool()] ) +writerow( out, ['Component Count:', len(components)] ) +writerow( out, ['Ref', 'Value', 'Part', 'Footprint', 'Description', 'Vendor'] ) + +# Output all of the component information +for c in components: + writerow( out, [c.getRef(), c.getValue(), c.getLibName() + ":" + c.getPartName(), + c.getFootprint(), c.getDescription(), c.getField("Vendor")]) diff --git a/eeschema/plugins/python_scripts/kicad_netlist_reader.py b/eeschema/plugins/python_scripts/kicad_netlist_reader.py new file mode 100644 index 0000000..407f572 --- /dev/null +++ b/eeschema/plugins/python_scripts/kicad_netlist_reader.py @@ -0,0 +1,764 @@ +# +# KiCad python module for interpreting generic netlists which can be used +# to generate Bills of materials, etc. +# +# Remember these files use UTF8 encoding +# +# No string formatting is used on purpose as the only string formatting that +# is current compatible with python 2.4+ to 3.0+ is the '%' method, and that +# is due to be deprecated in 3.0+ soon +# + +""" + @package + Helper module for interpreting generic netlist and build custom + bom generators or netlists in foreign format +""" + + +from __future__ import print_function +import sys +import xml.sax as sax +import re +import pdb + +#-----<Configure>---------------------------------------------------------------- + +# excluded_fields is a list of regular expressions. If any one matches a field +# from either a component or a libpart, then that will not be included as a +# column in the BOM. Otherwise all columns from all used libparts and components +# will be unionized and will appear. Some fields are impossible to blacklist, such +# as Ref, Value, Footprint, and Datasheet. Additionally Qty and Item are supplied +# unconditionally as columns, and may not be removed. +excluded_fields = [ + #'Price@1000' + ] + + +# You may exlude components from the BOM by either: +# +# 1) adding a custom field named "Installed" to your components and filling it +# with a value of "NU" (Normally Uninstalled). +# See netlist.getInterestingComponents(), or +# +# 2) blacklisting it in any of the three following lists: + + +# regular expressions which match component 'Reference' fields of components that +# are to be excluded from the BOM. +excluded_references = [ + 'TP[0-9]+' # all test points + ] + + +# regular expressions which match component 'Value' fields of components that +# are to be excluded from the BOM. +excluded_values = [ + 'MOUNTHOLE', + 'SCOPETEST', + 'MOUNT_HOLE', + 'SOLDER_BRIDGE.*' + ] + + +# regular expressions which match component 'Footprint' fields of components that +# are to be excluded from the BOM. +excluded_footprints = [ + #'MOUNTHOLE' + ] + +#-----</Configure>--------------------------------------------------------------- + + +class xmlElement(): + """xml element which can represent all nodes of the netlist tree. It can be + used to easily generate various output formats by propogating format + requests to children recursively. + """ + def __init__(self, name, parent=None): + self.name = name + self.attributes = {} + self.parent = parent + self.chars = "" + self.children = [] + + def __str__(self): + """String representation of this netlist element + + """ + return self.name + "[" + self.chars + "]" + " attr_count:" + str(len(self.attributes)) + + def formatXML(self, nestLevel=0, amChild=False): + """Return this element formatted as XML + + Keywords: + nestLevel -- increases by one for each level of nesting. + amChild -- If set to True, the start of document is not returned. + + """ + s = "" + + indent = "" + for i in range(nestLevel): + indent += " " + + if not amChild: + s = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n" + + s += indent + "<" + self.name + for a in self.attributes: + s += " " + a + "=\"" + self.attributes[a] + "\"" + + if (len(self.chars) == 0) and (len(self.children) == 0): + s += "/>" + else: + s += ">" + self.chars + + for c in self.children: + s += "\n" + s += c.formatXML(nestLevel+1, True) + + if (len(self.children) > 0): + s += "\n" + indent + + if (len(self.children) > 0) or (len(self.chars) > 0): + s += "</" + self.name + ">" + + return s + + def formatHTML(self, amChild=False): + """Return this element formatted as HTML + + Keywords: + amChild -- If set to True, the start of document is not returned + + """ + s = "" + + if not amChild: + s = """<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" + "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> + <html xmlns="http://www.w3.org/1999/xhtml"> + <head> + <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> + <title></title> + </head> + <body> + <table> + """ + + s += "<tr><td><b>" + self.name + "</b><br>" + self.chars + "</td><td><ul>" + for a in self.attributes: + s += "<li>" + a + " = " + self.attributes[a] + "</li>" + + s += "</ul></td></tr>\n" + + for c in self.children: + s += c.formatHTML(True) + + if not amChild: + s += """</table> + </body> + </html>""" + + return s + + def addAttribute(self, attr, value): + """Add an attribute to this element""" + if type(value) != str: value = value.encode('utf-8') + self.attributes[attr] = value + + def setAttribute(self, attr, value): + """Set an attributes value - in fact does the same thing as add + attribute + + """ + self.attributes[attr] = value + + def setChars(self, chars): + """Set the characters for this element""" + self.chars = chars + + def addChars(self, chars): + """Add characters (textual value) to this element""" + self.chars += chars + + def addChild(self, child): + """Add a child element to this element""" + self.children.append(child) + return self.children[len(self.children) - 1] + + def getParent(self): + """Get the parent of this element (Could be None)""" + return self.parent + + def getChild(self, name): + """Returns the first child element named 'name' + + Keywords: + name -- The name of the child element to return""" + for child in self.children: + if child.name == name: + return child + return None + + def getChildren(self, name=None): + if name: + # return _all_ children named "name" + ret = [] + for child in self.children: + if child.name == name: + ret.append(child) + return ret + else: + return self.children + + def get(self, elemName, attribute="", attrmatch=""): + """Return the text data for either an attribute or an xmlElement + """ + if (self.name == elemName): + if attribute != "": + try: + if attrmatch != "": + if self.attributes[attribute] == attrmatch: + ret = self.chars + if type(ret) != str: ret = ret.encode('utf-8') + return ret + else: + ret = self.attributes[attribute] + if type(ret) != str: ret = ret.encode('utf-8') + return ret + except AttributeError: + ret = "" + if type(ret) != str: ret = ret.encode('utf-8') + return ret + else: + ret = self.chars + if type(ret) != str: ret = ret.encode('utf-8') + return ret + + for child in self.children: + ret = child.get(elemName, attribute, attrmatch) + if ret != "": + if type(ret) != str: ret = ret.encode('utf-8') + return ret + + ret = "" + if type(ret) != str: ret = ret.encode('utf-8') + return ret + + + +class libpart(): + """Class for a library part, aka 'libpart' in the xml netlist file. + (Components in eeschema are instantiated from library parts.) + This part class is implemented by wrapping an xmlElement with accessors. + This xmlElement instance is held in field 'element'. + """ + def __init__(self, xml_element): + # + self.element = xml_element + + #def __str__(self): + # simply print the xmlElement associated with this part + #return str(self.element) + + def getLibName(self): + return self.element.get("libpart", "lib") + + def getPartName(self): + return self.element.get("libpart", "part") + + def getDescription(self): + return self.element.get("description") + + def getField(self, name): + return self.element.get("field", "name", name) + + def getFieldNames(self): + """Return a list of field names in play for this libpart. + """ + fieldNames = [] + fields = self.element.getChild('fields') + if fields: + for f in fields.getChildren(): + fieldNames.append( f.get('field','name') ) + return fieldNames + + def getDatasheet(self): + return self.getField("Datasheet") + + def getFootprint(self): + return self.getField("Footprint") + + def getAliases(self): + """Return a list of aliases or None""" + aliases = self.element.getChild("aliases") + if aliases: + ret = [] + children = aliases.getChildren() + # grab the text out of each child: + for child in children: + ret.append( child.get("alias") ) + return ret + return None + + +class comp(): + """Class for a component, aka 'comp' in the xml netlist file. + This component class is implemented by wrapping an xmlElement instance + with accessors. The xmlElement is held in field 'element'. + """ + + def __init__(self, xml_element): + self.element = xml_element + self.libpart = None + + # Set to true when this component is included in a component group + self.grouped = False + + def __eq__(self, other): + """ Equivalency operator, remember this can be easily overloaded + 2 components are equivalent ( i.e. can be grouped + if they have same value and same footprint + + Override the component equivalence operator must be done before + loading the netlist, otherwise all components will have the original + equivalency operator. + + You have to define a comparison module (for instance named myEqu) + and add the line; + kicad_netlist_reader.comp.__eq__ = myEqu + in your bom generator script before calling the netliste reader by something like: + net = kicad_netlist_reader.netlist(sys.argv[1]) + """ + result = False + if self.getValue() == other.getValue(): + if self.getFootprint() == other.getFootprint(): + result = True + return result + + def setLibPart(self, part): + self.libpart = part + + def getLibPart(self): + return self.libpart + + def getPartName(self): + return self.element.get("libsource", "part") + + def getLibName(self): + return self.element.get("libsource", "lib") + + def setValue(self, value): + """Set the value of this component""" + v = self.element.getChild("value") + if v: + v.setChars(value) + + def getValue(self): + return self.element.get("value") + + def getField(self, name, libraryToo=True): + """Return the value of a field named name. The component is first + checked for the field, and then the components library part is checked + for the field. If the field doesn't exist in either, an empty string is + returned + + Keywords: + name -- The name of the field to return the value for + libraryToo -- look in the libpart's fields for the same name if not found + in component itself + """ + + field = self.element.get("field", "name", name) + if field == "" and libraryToo: + field = self.libpart.getField(name) + return field + + def getFieldNames(self): + """Return a list of field names in play for this component. Mandatory + fields are not included, and they are: Value, Footprint, Datasheet, Ref. + The netlist format only includes fields with non-empty values. So if a field + is empty, it will not be present in the returned list. + """ + fieldNames = [] + fields = self.element.getChild('fields') + if fields: + for f in fields.getChildren(): + fieldNames.append( f.get('field','name') ) + return fieldNames + + def getRef(self): + return self.element.get("comp", "ref") + + def getFootprint(self, libraryToo=True): + ret = self.element.get("footprint") + if ret =="" and libraryToo: + ret = self.libpart.getFootprint() + return ret + + def getDatasheet(self, libraryToo=True): + ret = self.element.get("datasheet") + if ret == '' and libraryToo: + ret = self.libpart.getDatasheet() + return ret + + def getTimestamp(self): + return self.element.get("tstamp") + + def getDescription(self): + return self.libpart.getDescription() + + +class netlist(): + """ Kicad generic netlist class. Generally loaded from a kicad generic + netlist file. Includes several helper functions to ease BOM creating + scripts + + """ + def __init__(self, fname=""): + """Initialiser for the genericNetlist class + + Keywords: + fname -- The name of the generic netlist file to open (Optional) + + """ + self.design = None + self.components = [] + self.libparts = [] + self.libraries = [] + self.nets = [] + + # The entire tree is loaded into self.tree + self.tree = [] + + self._curr_element = None + + # component blacklist regexs, made from exluded_* above. + self.excluded_references = [] + self.excluded_values = [] + self.excluded_footprints = [] + + if fname != "": + self.load(fname) + + def addChars(self, content): + """Add characters to the current element""" + self._curr_element.addChars(content) + + def addElement(self, name): + """Add a new kicad generic element to the list""" + if self._curr_element == None: + self.tree = xmlElement(name) + self._curr_element = self.tree + else: + self._curr_element = self._curr_element.addChild( + xmlElement(name, self._curr_element)) + + # If this element is a component, add it to the components list + if self._curr_element.name == "comp": + self.components.append(comp(self._curr_element)) + + # Assign the design element + if self._curr_element.name == "design": + self.design = self._curr_element + + # If this element is a library part, add it to the parts list + if self._curr_element.name == "libpart": + self.libparts.append(libpart(self._curr_element)) + + # If this element is a net, add it to the nets list + if self._curr_element.name == "net": + self.nets.append(self._curr_element) + + # If this element is a library, add it to the libraries list + if self._curr_element.name == "library": + self.libraries.append(self._curr_element) + + return self._curr_element + + def endDocument(self): + """Called when the netlist document has been fully parsed""" + # When the document is complete, the library parts must be linked to + # the components as they are seperate in the tree so as not to + # duplicate library part information for every component + for c in self.components: + for p in self.libparts: + if p.getLibName() == c.getLibName(): + if p.getPartName() == c.getPartName(): + c.setLibPart(p) + break + else: + aliases = p.getAliases() + if aliases and self.aliasMatch( c.getPartName(), aliases ): + c.setLibPart(p) + break; + + if not c.getLibPart(): + print( 'missing libpart for ref:', c.getRef(), c.getPartName(), c.getLibName() ) + + + def aliasMatch(self, partName, aliasList): + for alias in aliasList: + if partName == alias: + return True + return False + + def endElement(self): + """End the current element and switch to its parent""" + self._curr_element = self._curr_element.getParent() + + def getDate(self): + """Return the date + time string generated by the tree creation tool""" + return self.design.get("date") + + def getSource(self): + """Return the source string for the design""" + return self.design.get("source") + + def getTool(self): + """Return the tool string which was used to create the netlist tree""" + return self.design.get("tool") + + def gatherComponentFieldUnion(self, components=None): + """Gather the complete 'set' of unique component fields, fields found in any component. + """ + if not components: + components=self.components + + s = set() + for c in components: + s.update( c.getFieldNames() ) + + # omit anything matching any regex in excluded_fields + ret = set() + for field in s: + exclude = False + for rex in excluded_fields: + if re.match( rex, field ): + exclude = True + break + if not exclude: + ret.add(field) + + return ret # this is a python 'set' + + def gatherLibPartFieldUnion(self): + """Gather the complete 'set' of part fields, fields found in any part. + """ + s = set() + for p in self.libparts: + s.update( p.getFieldNames() ) + + # omit anything matching any regex in excluded_fields + ret = set() + for field in s: + exclude = False + for rex in excluded_fields: + if re.match( rex, field ): + exclude = True + break + if not exclude: + ret.add(field) + + return ret # this is a python 'set' + + def getInterestingComponents(self): + """Return a subset of all components, those that should show up in the BOM. + Omit those that should not, by consulting the blacklists: + excluded_values, excluded_refs, and excluded_footprints, which hold one + or more regular expressions. If any of the the regular expressions match + the corresponding field's value in a component, then the component is exluded. + """ + + # pre-compile all the regex expressions: + del self.excluded_references[:] + del self.excluded_values[:] + del self.excluded_footprints[:] + + for rex in excluded_references: + self.excluded_references.append( re.compile( rex ) ) + + for rex in excluded_values: + self.excluded_values.append( re.compile( rex ) ) + + for rex in excluded_footprints: + self.excluded_footprints.append( re.compile( rex ) ) + + # the subset of components to return, considered as "interesting". + ret = [] + + # run each component thru a series of tests, if it passes all, then add it + # to the interesting list 'ret'. + for c in self.components: + exclude = False + if not exclude: + for refs in self.excluded_references: + if refs.match(c.getRef()): + exclude = True + break; + if not exclude: + for vals in self.excluded_values: + if vals.match(c.getValue()): + exclude = True + break; + if not exclude: + for mods in self.excluded_footprints: + if mods.match(c.getFootprint()): + exclude = True + break; + + if not exclude: + # This is a fairly personal way to flag DNS (Do Not Stuff). NU for + # me means Normally Uninstalled. You can 'or in' another expression here. + if c.getField( "Installed" ) == 'NU': + exclude = True + + if not exclude: + ret.append(c) + + # Sort first by ref as this makes for easier to read BOM's + def f(v): + return re.sub(r'([A-z]+)[0-9]+', r'\1', v) + '%08i' % int(re.sub(r'[A-z]+([0-9]+)', r'\1', v)) + ret.sort(key=lambda g: f(g.getRef())) + + return ret + + + def groupComponents(self, components = None): + """Return a list of component lists. Components are grouped together + when the value, library and part identifiers match. + + Keywords: + components -- is a list of components, typically an interesting subset + of all components, or None. If None, then all components are looked at. + """ + if not components: + components = self.components + + groups = [] + + # Make sure to start off will all components ungrouped to begin with + for c in components: + c.grouped = False + + # Group components based on the value, library and part identifiers + for c in components: + if c.grouped == False: + c.grouped = True + newgroup = [] + newgroup.append(c) + + # Check every other ungrouped component against this component + # and add to the group as necessary + for ci in components: + if ci.grouped == False and ci == c: + newgroup.append(ci) + ci.grouped = True + + # Add the new component group to the groups list + groups.append(newgroup) + + # Each group is a list of components, we need to sort each list first + # to get them in order as this makes for easier to read BOM's + def f(v): + return re.sub(r'([A-z]+)[0-9]+', r'\1', v) + '%08i' % int(re.sub(r'[A-z]+([0-9]+)', r'\1', v)) + for g in groups: + g = sorted(g, key=lambda g: f(g.getRef())) + + # Finally, sort the groups to order the references alphabetically + groups = sorted(groups, key=lambda group: f(group[0].getRef())) + + return groups + + def getGroupField(self, group, field): + """Return the whatever is known about the given field by consulting each + component in the group. If any of them know something about the property/field, + then return that first non-blank value. + """ + for c in group: + ret = c.getField(field, False) + if ret != '': + return ret + return group[0].getLibPart().getField(field) + + def getGroupFootprint(self, group): + """Return the whatever is known about the Footprint by consulting each + component in the group. If any of them know something about the Footprint, + then return that first non-blank value. + """ + for c in group: + ret = c.getFootprint() + if ret != "": + return ret + return group[0].getLibPart().getFootprint() + + def getGroupDatasheet(self, group): + """Return the whatever is known about the Datasheet by consulting each + component in the group. If any of them know something about the Datasheet, + then return that first non-blank value. + """ + for c in group: + ret = c.getDatasheet() + if ret != "": + return ret + + if len(group) > 0: + return group[0].getLibPart().getDatasheet() + else: + print("NULL!") + return '' + + def formatXML(self): + """Return the whole netlist formatted in XML""" + return self.tree.formatXML() + + def formatHTML(self): + """Return the whole netlist formatted in HTML""" + return self.tree.formatHTML() + + def load(self, fname): + """Load a kicad generic netlist + + Keywords: + fname -- The name of the generic netlist file to open + + """ + try: + self._reader = sax.make_parser() + self._reader.setContentHandler(_gNetReader(self)) + self._reader.parse(fname) + except IOError as e: + print( __file__, ":", e, file=sys.stderr ) + sys.exit(-1) + + + +class _gNetReader(sax.handler.ContentHandler): + """SAX kicad generic netlist content handler - passes most of the work back + to the 'netlist' class which builds a complete tree in RAM for the design + + """ + def __init__(self, aParent): + self.parent = aParent + + def startElement(self, name, attrs): + """Start of a new XML element event""" + element = self.parent.addElement(name) + + for name in attrs.getNames(): + element.addAttribute(name, attrs.getValue(name)) + + def endElement(self, name): + self.parent.endElement() + + def characters(self, content): + # Ignore erroneous white space - ignoreableWhitespace does not get rid + # of the need for this! + if not content.isspace(): + self.parent.addChars(content) + + def endDocument(self): + """End of the XML document event""" + self.parent.endDocument() diff --git a/eeschema/plugins/python_scripts/round_robin.py b/eeschema/plugins/python_scripts/round_robin.py new file mode 100644 index 0000000..0f15e6f --- /dev/null +++ b/eeschema/plugins/python_scripts/round_robin.py @@ -0,0 +1,28 @@ +# +# Example python script to generate an equivalent XML document from XML input +# +# Example: Round robin, XML to XML conversion +# + +from __future__ import print_function + +# Import the KiCad python helper module and the csv formatter +import kicad_netlist_reader +import sys +import pdb + + +# Generate an instance of a generic netlist, and load the netlist tree from +# the command line option. If the file doesn't exist, execution will stop +net = kicad_netlist_reader.netlist(sys.argv[1]) + +# Open a file to write to, if the file cannot be opened output to stdout +# instead +try: + f = open(sys.argv[2], 'w') +except IOError: + e = "Can't open output file for writing: " + sys.argv[2] + print( __file__, ":", e, sys.stderr) + f = sys.stdout + +print(net.formatXML(), file=f) diff --git a/eeschema/plugins/python_scripts/round_value_robin.py b/eeschema/plugins/python_scripts/round_value_robin.py new file mode 100644 index 0000000..e1bf3ff --- /dev/null +++ b/eeschema/plugins/python_scripts/round_value_robin.py @@ -0,0 +1,74 @@ +# +# Example python script to generate an equivalent XML document from XML input +# +# Example: Round value robin, XML to XML conversion with partial value monging +# + +from __future__ import print_function + +# Import the KiCad python helper module and the csv formatter +import kicad_netlist_reader +import sys + +def checkvalue(self): + """Check values, and replace with preferred/consistent values""" + ref = self.getRef() + r = ref.split("R") + c = ref.split("C") + v = self.getValue() + + # Common to all values - convert decimation if necessary + dec = v.split(",") + if (len(dec) == 2): + newval = dec[0] + "." + dec[1] + self.setValue(newval) + v = self.getValue() + + if len(r) == 2 and r[1].isdigit(): + # This is a resistor - make values consistent + # If the value is a pure value, add R to the end of the value + if v.isdigit(): + i = int(v) + if (i > 1000000): + i = i / 1000000 + v = str(i) + "M" + if (i > 1000): + i = i / 1000 + v = str(i) + "K" + else: + v = str(i) + "R" + + self.setValue(v) + else: + # Get the multiplier character + multiplier = v[len(v) - 1] + v = v.strip(multiplier) + v = v.split(".") + if (len(v) == 2): + newval = v[0] + multiplier + v[1] + self.setValue(newval) + v = self.getValue() + + + +# Give components a new method for checking the values (this could easily be a +# Company Part Number generator method instead) +kicad_netlist_reader.comp.checkvalue = checkvalue + +# Generate an instance of a generic netlist, and load the netlist tree from +# the command line option. If the file doesn't exist, execution will stop +net = kicad_netlist_reader.netlist(sys.argv[1]) + +# Open a file to write to, if the file cannot be opened output to stdout +# instead +try: + f = open(sys.argv[2], 'w') +except IOError: + e = "Can't open output file for writing: " + sys.argv[2] + print(__file__, ":", e, file=sys.stderr) + f = sys.stdout + +for c in net.components: + c.checkvalue() + +print(net.formatXML(), file=f) diff --git a/eeschema/plugins/xsl_scripts/bom2csv.xsl b/eeschema/plugins/xsl_scripts/bom2csv.xsl new file mode 100644 index 0000000..67d588b --- /dev/null +++ b/eeschema/plugins/xsl_scripts/bom2csv.xsl @@ -0,0 +1,99 @@ +<!--XSL style sheet to convert EESCHEMA XML Partlist Format to CSV BOM Format + Copyright (C) 2013, Stefan Helmert. + GPL v2. + + Functionality: + Generation of csv table with table head of all existing field names + and correct assigned cell entries + + How to use this is explained in eeschema.pdf chapter 14. You enter a command line into the + netlist exporter using a new (custom) tab in the netlist export dialog. The command is + similar to + on Windows: + xsltproc -o "%O.csv" "C:\Program Files (x86)\KiCad\bin\plugins\bom2csv.xsl" "%I" + on Linux: + xsltproc -o "%O.csv" /usr/local/lib/kicad/plugins/bom2csv.xsl "%I" + + Instead of "%O.csv" you can alternatively use "%O" if you will supply your own file extension when + prompted in the UI. The double quotes are there to account for the possibility of space(s) + in the filename. +--> + +<!-- + @package + Generate a Tab delimited list (csv file type). + One component per line + Fields are + Ref,Value, Footprint, Datasheet, Field5, Field4, price + + Command line + xsltproc -o "%O.csv" "pathToFile/bom2csv.xsl" "%I" +--> + +<!DOCTYPE xsl:stylesheet [ + <!ENTITY nl "
"> <!--new line CR, LF, or LF, your choice --> +]> + + +<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> + <xsl:output method="text"/> + + <!-- for table head and empty table fields--> + <xsl:key name="headentr" match="field" use="@name"/> + + <!-- main part --> + <xsl:template match="/export"> + <xsl:text>Reference, Value, Footprint, Datasheet</xsl:text> + + <!-- find all existing table head entries and list each one once --> + <xsl:for-each select="components/comp/fields/field[generate-id(.) = generate-id(key('headentr',@name)[1])]"> + <xsl:text>, </xsl:text> + <xsl:value-of select="@name"/> + </xsl:for-each> + <xsl:text>&nl;</xsl:text> + + <!-- all table entries --> + <xsl:apply-templates select="components/comp"/> + </xsl:template> + + <!-- the table entries --> + <xsl:template match="components/comp"> + <xsl:text>"</xsl:text> + <xsl:value-of select="@ref"/><xsl:text>","</xsl:text> + <xsl:value-of select="value"/><xsl:text>","</xsl:text> + <xsl:value-of select="footprint"/><xsl:text>","</xsl:text> + <xsl:value-of select="datasheet"/><xsl:text>"</xsl:text> + <xsl:apply-templates select="fields"/> + <xsl:text>&nl;</xsl:text> + </xsl:template> + + <!-- table entries with dynamic table head --> + <xsl:template match="fields"> + + <!-- remember current fields section --> + <xsl:variable name="fieldvar" select="field"/> + + <!-- for all existing head entries --> + <xsl:for-each select="/export/components/comp/fields/field[generate-id(.) = generate-id(key('headentr',@name)[1])]"> + <xsl:variable name="allnames" select="@name"/> + <xsl:text>,"</xsl:text> + + <!-- for all field entries in the remembered fields section --> + <xsl:for-each select="$fieldvar"> + + <!-- only if this field entry exists in this fields section --> + <xsl:if test="@name=$allnames"> + <!-- content of the field --> + <xsl:value-of select="."/> + </xsl:if> + <!-- + If it does not exist, use an empty cell in output for this row. + Every non-blank entry is assigned to its proper column. + --> + </xsl:for-each> + + <xsl:text>"</xsl:text> + </xsl:for-each> + </xsl:template> + + </xsl:stylesheet> diff --git a/eeschema/plugins/xsl_scripts/bom2grouped_csv.xsl b/eeschema/plugins/xsl_scripts/bom2grouped_csv.xsl new file mode 100644 index 0000000..e9b8446 --- /dev/null +++ b/eeschema/plugins/xsl_scripts/bom2grouped_csv.xsl @@ -0,0 +1,104 @@ +<!--XSL style sheet to convert EESCHEMA XML Partlist Format to grouped CSV BOM Format + Copyright (C) 2014, Wolf Walter. + Copyright (C) 2013, Stefan Helmert. + GPL v2. + + Functionality: + Generation of Digi-Key ordering system compatible BOM + + How to use this is explained in eeschema.pdf chapter 14. You enter a command line into the + netlist exporter using a new (custom) tab in the netlist export dialog. + The command line is + xsltproc -o "%O.csv" "FullPathToFile/bom2groupedCsv.xsl" "%I" +--> +<!-- + @package + Functionality: + * Generate a comma separated value BOM list (csv file type). + * Components are sorted by ref and grouped by same value+footprint + One value per line + Fields are + Reference, Quantity, Value, Footprint, Datasheet + + The command line is + xsltproc -o "%O.csv" "FullPathToFile/bom2groupedCsv.xsl" "%I" +--> + + +<!DOCTYPE xsl:stylesheet [ + <!ENTITY nl "
"> <!--new line CR, LF, or LF, your choice --> +]> + + +<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> + <xsl:output method="text"/> + + <!-- for Muenchian grouping of footprint and value combination --> + <xsl:key name="partTypeByValueAndFootprint" match="comp" use="concat(footprint, '-', value)" /> + + <!-- for table head and empty table fields--> + <xsl:key name="headentr" match="field" use="@name"/> + + <!-- main part --> + <xsl:template match="/export"> + <xsl:text>Reference, Quantity, Value, Footprint, Datasheet</xsl:text> + + <!-- find all existing table head entries and list each one once --> + <xsl:for-each select="components/comp/fields/field[generate-id(.) = generate-id(key('headentr',@name)[1])]"> + <xsl:text>, </xsl:text> + <xsl:value-of select="@name"/> + </xsl:for-each> + + <!-- all table entries --> + <xsl:apply-templates select="components"/> + </xsl:template> + + <xsl:template match="components"> + <!-- for Muenchian grouping of footprint and value combination --> + <xsl:for-each select="comp[count(. | key('partTypeByValueAndFootprint', concat(footprint, '-', value))[1]) = 1]"> + <xsl:sort select="@ref" /> + <xsl:text>&nl;</xsl:text> + <!-- list of all references --> + <xsl:for-each select="key('partTypeByValueAndFootprint', concat(footprint, '-', value))"> + <xsl:sort select="@ref" /> + <xsl:value-of select="@ref"/><xsl:text> </xsl:text> + </xsl:for-each><xsl:text>,</xsl:text> + <!-- quantity of parts with same footprint and value --> + <xsl:value-of select="count(key('partTypeByValueAndFootprint', concat(footprint, '-', value)))"/><xsl:text>,</xsl:text> + <xsl:text>"</xsl:text> + <xsl:value-of select="value"/><xsl:text>","</xsl:text> + <xsl:value-of select="footprint"/><xsl:text>","</xsl:text> + <xsl:value-of select="datasheet"/><xsl:text>"</xsl:text> + <xsl:apply-templates select="fields"/> + </xsl:for-each> + </xsl:template> + + <!-- table entries with dynamic table head --> + <xsl:template match="fields"> + + <!-- remember current fields section --> + <xsl:variable name="fieldvar" select="field"/> + + <!-- for all existing head entries --> + <xsl:for-each select="/export/components/comp/fields/field[generate-id(.) = generate-id(key('headentr',@name)[1])]"> + <xsl:variable name="allnames" select="@name"/> + <xsl:text>,"</xsl:text> + + <!-- for all field entries in the remembered fields section --> + <xsl:for-each select="$fieldvar"> + + <!-- only if this field entry exists in this fields section --> + <xsl:if test="@name=$allnames"> + <!-- content of the field --> + <xsl:value-of select="."/> + <xsl:text>"</xsl:text> + </xsl:if> + <!-- + If it does not exist, use an empty cell in output for this row. + Every non-blank entry is assigned to its proper column. + --> + </xsl:for-each> + </xsl:for-each> + </xsl:template> + + </xsl:stylesheet>
\ No newline at end of file diff --git a/eeschema/plugins/xsl_scripts/bom_with_title_block_2_csv.xsl b/eeschema/plugins/xsl_scripts/bom_with_title_block_2_csv.xsl new file mode 100644 index 0000000..feed1ce --- /dev/null +++ b/eeschema/plugins/xsl_scripts/bom_with_title_block_2_csv.xsl @@ -0,0 +1,167 @@ +<!-- + EESCHEMA BOM plugin. Creates BOM CSV files from the project net file. + Based on Stefan Helmert bom2csv.xsl + + Note: + The project infomation (i.e title, company and revision) is taken from the root sheet. + + Arthur: + Ronald Sousa HashDefineElectronics.com + + Ouput Example: + Source, + Kicad Rev, working director and file source + Generated Date, date this file was generated + + Title, the project's title + Company, the project's company + Rev, the project's revision + Date Source, project's issue date + Comment, This is comment 1 + Comment, This is comment 2 + Comment, This is comment 3 + Comment, This is comment 4 +--> +<!-- + @package + Output format + Reference, Value, Fields[n], Library, Library Ref + U1, PIC32MX, Fields[n], KicadLib, PIC + +Command line: + xsltproc -o "%O.csv" "pathToFile/bom2csv.xsl" "%I" +--> + +<!DOCTYPE xsl:stylesheet [ + <!ENTITY nl "
"> <!--new line CR, LF, or LF, your choice --> +]> + +<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> + <xsl:output method="text"/> + + <!-- for table head and empty table fields--> + <xsl:key name="headentr" match="field" use="@name"/> + + <!-- main part --> + <xsl:template match="/export"> + <xsl:text>Source,</xsl:text><xsl:value-of select="design/source"/><xsl:text>&nl;</xsl:text> + <xsl:text>Kicad Rev,</xsl:text><xsl:value-of select="design/tool"/><xsl:text>&nl;</xsl:text> + <xsl:text>Generated Date,</xsl:text><xsl:value-of select="design/date"/><xsl:text>&nl;</xsl:text> + + <xsl:text>&nl;</xsl:text> + + <!-- Ouput Root sheet project information --> + <xsl:apply-templates select="/export/design/sheet[1]"/> + + <xsl:text>&nl;</xsl:text> + + <!-- Output table header --> + <xsl:text>Reference,Value,</xsl:text> + <xsl:for-each select="components/comp/fields/field[generate-id(.) = generate-id(key('headentr',@name)[1])]"> + <xsl:value-of select="@name"/> + <xsl:text>,</xsl:text> + </xsl:for-each> + <xsl:text>Library,Library Ref</xsl:text> + <xsl:text>&nl;</xsl:text> + + <!-- all table entries --> + <xsl:apply-templates select="components/comp"/> + </xsl:template> + + <!-- generate the Root sheet project information --> + <xsl:template match="/export/design/sheet[1]"> + + <xsl:choose> + <xsl:when test="title_block/title !=''"> + <xsl:text>Title,</xsl:text><xsl:value-of select="title_block/title"/><xsl:text>&nl;</xsl:text> + </xsl:when> + <xsl:otherwise> + <xsl:text>Title,Not Set</xsl:text><xsl:text>&nl;</xsl:text> + </xsl:otherwise> + </xsl:choose> + + + <xsl:choose> + <xsl:when test="title_block/company !=''"> + <xsl:text>Company,</xsl:text><xsl:value-of select="title_block/company"/><xsl:text>&nl;</xsl:text> + </xsl:when> + <xsl:otherwise> + <xsl:text>Company,Not Set</xsl:text><xsl:text>&nl;</xsl:text> + </xsl:otherwise> + </xsl:choose> + + <xsl:choose> + <xsl:when test="title_block/rev !=''"> + <xsl:text>Revision,</xsl:text><xsl:value-of select="title_block/rev"/><xsl:text>&nl;</xsl:text> + </xsl:when> + <xsl:otherwise> + <xsl:text>Revision,Not Set</xsl:text><xsl:text>&nl;</xsl:text> + </xsl:otherwise> + </xsl:choose> + + <xsl:choose> + <xsl:when test="title_block/date !=''"> + <xsl:text>Date Issue,</xsl:text><xsl:value-of select="title_block/date"/><xsl:text>&nl;</xsl:text> + </xsl:when> + <xsl:otherwise> + <xsl:text>Date Issue,Not Set</xsl:text><xsl:text>&nl;</xsl:text> + </xsl:otherwise> + </xsl:choose> + + <xsl:apply-templates select="title_block/comment"/> + + </xsl:template> + + <xsl:template match="title_block/comment"> + <xsl:choose> + <xsl:when test="@value !=''"> + <xsl:text>Comment,</xsl:text><xsl:value-of select="@value"/><xsl:text>&nl;</xsl:text> + </xsl:when> + </xsl:choose> + </xsl:template> + + + + <!-- the table entries --> + <xsl:template match="components/comp"> + <xsl:value-of select="@ref"/><xsl:text>,</xsl:text> + <xsl:value-of select="value"/><xsl:text>,</xsl:text> + <xsl:apply-templates select="fields"/> + <xsl:apply-templates select="libsource"/> + <xsl:text>&nl;</xsl:text> + </xsl:template> + + <!-- the library selection --> + <xsl:template match="libsource"> + <xsl:value-of select="@lib"/><xsl:text>,</xsl:text> + <xsl:value-of select="@part"/> + </xsl:template> + + <!-- table entries with dynamic table head --> + <xsl:template match="fields"> + + <!-- remember current fields section --> + <xsl:variable name="fieldvar" select="field"/> + + <!-- for all existing head entries --> + <xsl:for-each select="/export/components/comp/fields/field[generate-id(.) = generate-id(key('headentr',@name)[1])]"> + <xsl:variable name="allnames" select="@name"/> + + <!-- for all field entries in the remembered fields section --> + <xsl:for-each select="$fieldvar"> + + <!-- only if this field entry exists in this fields section --> + <xsl:if test="@name=$allnames"> + <!-- content of the field --> + <xsl:value-of select="."/> + </xsl:if> + <!-- + If it does not exist, use an empty cell in output for this row. + Every non-blank entry is assigned to its proper column. + --> + </xsl:for-each> + <xsl:text>,</xsl:text> + </xsl:for-each> + </xsl:template> + + </xsl:stylesheet> diff --git a/eeschema/plugins/xsl_scripts/netlist_form_OrcadPcb2.xsl b/eeschema/plugins/xsl_scripts/netlist_form_OrcadPcb2.xsl new file mode 100644 index 0000000..3017711 --- /dev/null +++ b/eeschema/plugins/xsl_scripts/netlist_form_OrcadPcb2.xsl @@ -0,0 +1,210 @@ +<?xml version="1.0" encoding="ISO-8859-1"?> +<!--XSL style sheet to EESCHEMA Generic Netlist Format to CADSTAR netlist format + Copyright (C) 2010, SoftPLC Corporation. + GPL v2. + + How to use: + see eeschema.pdf, chapter 14 +--> + +<!DOCTYPE xsl:stylesheet [ + <!ENTITY nl "
"> <!--new line CR, LF --> +]> + +<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> +<xsl:output method="text" omit-xml-declaration="yes" indent="no"/> + +<!-- + Netlist header + Creates the entire netlist + (can be seen as equivalent to main function in C +--> +<xsl:template match="/export"> + <xsl:text>( { EESchema Netlist Version 1.1 </xsl:text> + <!-- Generate line .TIM <time> --> + <xsl:apply-templates select="design/date"/> + <!-- Generate line eeschema version ... --> + <xsl:apply-templates select="design/tool"/> + <xsl:text>}&nl;</xsl:text> + + <!-- Generate the list of components --> + <xsl:apply-templates select="components/comp"/> <!-- Generate list of components --> + + <!-- end of file --> + <xsl:text>)&nl;*&nl;</xsl:text> +</xsl:template> + +<!-- + Generate id in header like "eeschema (2010-08-17 BZR 2450)-unstable" +--> +<xsl:template match="tool"> + <xsl:apply-templates/> +</xsl:template> + +<!-- + Generate date in header like "20/08/2010 10:45:33" +--> +<xsl:template match="date"> + <xsl:apply-templates/> + <xsl:text>&nl;</xsl:text> +</xsl:template> + +<!-- + This template read each component + (path = /export/components/comp) + creates lines: + ( 3EBF7DBD $noname U1 74LS125 + ... pin list ... + ) + and calls "create_pin_list" template to build the pin list +--> +<xsl:template match="comp"> + <xsl:text> ( </xsl:text> + <xsl:choose> + <xsl:when test = "tstamp != '' "> + <xsl:apply-templates select="tstamp"/> + </xsl:when> + <xsl:otherwise> + <xsl:text>00000000</xsl:text> + </xsl:otherwise> + </xsl:choose> + <xsl:text> </xsl:text> + <xsl:choose> + <xsl:when test = "footprint != '' "> + <xsl:apply-templates select="footprint"/> + </xsl:when> + <xsl:otherwise> + <xsl:text>$noname</xsl:text> + </xsl:otherwise> + </xsl:choose> + <xsl:text> </xsl:text> + <xsl:value-of select="@ref"/> + <xsl:text> </xsl:text> + <xsl:choose> + <xsl:when test = "value != '' "> + <xsl:apply-templates select="value"/> + </xsl:when> + <xsl:otherwise> + <xsl:text>"~"</xsl:text> + </xsl:otherwise> + </xsl:choose> + <xsl:text>&nl;</xsl:text> + <xsl:call-template name="Search_pin_list" > + <xsl:with-param name="cmplib_id" select="libsource/@part"/> + <xsl:with-param name="cmp_ref" select="@ref"/> + </xsl:call-template> + <xsl:text> )&nl;</xsl:text> +</xsl:template> + +<!-- + This template search for a given lib component description in list + lib component descriptions are in /export/libparts, + and each description start at ./libpart + We search here for the list of pins of the given component + This template has 2 parameters: + "cmplib_id" (reference in libparts) + "cmp_ref" (schematic reference of the given component) +--> +<xsl:template name="Search_pin_list" > + <xsl:param name="cmplib_id" select="0" /> + <xsl:param name="cmp_ref" select="0" /> + <xsl:for-each select="/export/libparts/libpart"> + <xsl:if test = "@part = $cmplib_id "> + <xsl:apply-templates name="build_pin_list" select="pins/pin"> + <xsl:with-param name="cmp_ref" select="$cmp_ref"/> + </xsl:apply-templates> + </xsl:if> + </xsl:for-each> +</xsl:template> + + +<!-- + This template writes the pin list of a component + from the pin list of the library description + The pin list from library description is something like + <pins> + <pin num="1" type="passive"/> + <pin num="2" type="passive"/> + </pins> + Output pin list is ( <pin num> <net name> ) + something like + ( 1 VCC ) + ( 2 GND ) +--> +<xsl:template name="build_pin_list" match="pin"> + <xsl:param name="cmp_ref" select="0" /> + + <!-- write pin numner and separator --> + <xsl:text> ( </xsl:text> + <xsl:value-of select="@num"/> + <xsl:text> </xsl:text> + + <!-- search net name in nets section and write it: --> + <xsl:variable name="pinNum" select="@num" /> + <xsl:for-each select="/export/nets/net"> + <!-- net name is output only if there is more than one pin in net + else use "?" as net name, so count items in this net + --> + <xsl:variable name="pinCnt" select="count(node)" /> + <xsl:apply-templates name="Search_pin_netname" select="node"> + <xsl:with-param name="cmp_ref" select="$cmp_ref"/> + <xsl:with-param name="pin_cnt_in_net" select="$pinCnt"/> + <xsl:with-param name="pin_num"> <xsl:value-of select="$pinNum"/> + </xsl:with-param> + </xsl:apply-templates> + </xsl:for-each> + + <!-- close line --> + <xsl:text> )&nl;</xsl:text> +</xsl:template> + +<!-- + This template writes the pin netname of a given pin of a given component + from the nets list + The nets list description is something like + <nets> + <net code="1" name="GND"> + <node ref="J1" pin="20"/> + <node ref="C2" pin="2"/> + </net> + <net code="2" name=""> + <node ref="U2" pin="11"/> + </net> + </nets> + This template has 2 parameters: + "cmp_ref" (schematic reference of the given component) + "pin_num" (pin number) +--> + +<xsl:template name="Search_pin_netname" match="node"> + <xsl:param name="cmp_ref" select="0" /> + <xsl:param name="pin_num" select="0" /> + <xsl:param name="pin_cnt_in_net" select="0" /> + + <xsl:if test = "@ref = $cmp_ref "> + <xsl:if test = "@pin = $pin_num"> + <!-- net name is output only if there is more than one pin in net + else use "?" as net name + --> + <xsl:if test = "$pin_cnt_in_net>1"> + <xsl:choose> + <!-- if a net has a name, use it, + else build a name from its net code + --> + <xsl:when test = "../@name != '' "> + <xsl:value-of select="../@name"/> + </xsl:when> + <xsl:otherwise> + <xsl:text>$N-0</xsl:text><xsl:value-of select="../@code"/> + </xsl:otherwise> + </xsl:choose> + </xsl:if> + <xsl:if test = "$pin_cnt_in_net <2"> + <xsl:text>?</xsl:text> + </xsl:if> + </xsl:if> + </xsl:if> + +</xsl:template> + +</xsl:stylesheet> diff --git a/eeschema/plugins/xsl_scripts/netlist_form_cadstar-RINF.xsl b/eeschema/plugins/xsl_scripts/netlist_form_cadstar-RINF.xsl new file mode 100644 index 0000000..7df4b76 --- /dev/null +++ b/eeschema/plugins/xsl_scripts/netlist_form_cadstar-RINF.xsl @@ -0,0 +1,131 @@ +<?xml version="1.0" encoding="ISO-8859-1"?> +<!--XSL style sheet to EESCHEMA Generic Netlist Format to CADSTAR netlist format + Copyright (C) 2010, SoftPLC Corporation. + GPL v2. + + How to use: + see eeschema.pdf, chapter 14 +--> + +<!DOCTYPE xsl:stylesheet [ + <!ENTITY nl "
"> <!--new line CR, LF --> +]> + +<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> +<xsl:output method="text" omit-xml-declaration="yes" indent="no"/> + +<!-- Netlist header --> +<xsl:template match="/export"> + <xsl:text>.HEA&nl;</xsl:text> + <xsl:apply-templates select="design/date"/> <!-- Generate line .TIM <time> --> + <xsl:apply-templates select="design/tool"/> <!-- Generate line .APP <eeschema version> --> + <xsl:text>&nl;</xsl:text> + <xsl:apply-templates select="components/comp"/> <!-- Generate list of components --> + <xsl:text>&nl;&nl;</xsl:text> + <xsl:apply-templates select="nets/net"/> <!-- Generate list of nets and connections --> + <xsl:text>&nl;.END&nl;</xsl:text> +</xsl:template> + + <!-- Generate line .APP "eeschema (2010-08-17 BZR 2450)-unstable" --> +<xsl:template match="tool"> + <xsl:text>.APP "</xsl:text> + <xsl:apply-templates/> + <xsl:text>"&nl;</xsl:text> +</xsl:template> + + <!-- Generate line .TIM 20/08/2010 10:45:33 --> +<xsl:template match="date"> + <xsl:text>.TIM </xsl:text> + <xsl:apply-templates/> + <xsl:text>&nl;</xsl:text> +</xsl:template> + +<!-- for each component --> +<!-- create lines like + .ADD_COM U3 74LS541 (when no footprint name specified) + .ADD_COM JP1 CONN_8X2 pin_array_8x2 pin_array_8x2 (with a specified footprint name) +--> +<xsl:template match="comp"> + <xsl:text>.ADD_COM </xsl:text> + <xsl:value-of select="@ref"/> + <xsl:text> </xsl:text> + <xsl:choose> + <xsl:when test = "value != '' "> + <xsl:apply-templates select="value"/> + </xsl:when> + <xsl:otherwise> + <xsl:text>?</xsl:text> + </xsl:otherwise> + </xsl:choose> + <xsl:choose> + <xsl:when test = "footprint != '' "> + <xsl:text> </xsl:text> + <xsl:apply-templates select="footprint"/> + </xsl:when> + <xsl:otherwise> + </xsl:otherwise> + </xsl:choose> + <xsl:text>&nl;</xsl:text> +</xsl:template> + +<!-- for each net --> +<!-- create lines like +.ADD_TER U3.9 /PC-RST +.TER U3.8 + BUS1.2 +.ADD_TER BUS1.14 /PC-IOR +.TER U3.7 +--> +<xsl:template match="net"> + <!-- nets are output only if there is more than one pin in net --> + <xsl:if test="count(node)>1"> + <xsl:variable name="netname"> + <xsl:text> </xsl:text> + <xsl:choose> + <xsl:when test = "@name != '' "> + <xsl:value-of select="@name"/> + </xsl:when> + <xsl:otherwise> + <xsl:text>N-</xsl:text> + <xsl:value-of select="@code"/> + </xsl:otherwise> + </xsl:choose> + <xsl:text>&nl;</xsl:text> + </xsl:variable> + <xsl:apply-templates select="node" mode="first"/> + <xsl:value-of select="$netname"/> + <xsl:apply-templates select="node" mode="others"/> + </xsl:if> +</xsl:template> + +<!-- for each node --> +<xsl:template match="node" mode="first"> + <xsl:if test="position()=1"> + <xsl:text>.ADD_TER </xsl:text> + <xsl:value-of select="@ref"/> + <xsl:text>.</xsl:text> + <xsl:value-of select="@pin"/> + <xsl:text> </xsl:text> + </xsl:if> +</xsl:template> + +<xsl:template match="node" mode="others"> + <xsl:choose> + <xsl:when test='position()=1'> + </xsl:when> + <xsl:when test='position()=2'> + <xsl:text>.TER </xsl:text> + </xsl:when> + <xsl:otherwise> + <xsl:text> </xsl:text> + </xsl:otherwise> + </xsl:choose> + <xsl:if test="position()>1"> + <xsl:value-of select="@ref"/> + <xsl:text>.</xsl:text> + <xsl:value-of select="@pin"/> + <xsl:text>&nl;</xsl:text> + </xsl:if> +</xsl:template> + +</xsl:stylesheet> diff --git a/eeschema/plugins/xsl_scripts/netlist_form_cadstar.xsl b/eeschema/plugins/xsl_scripts/netlist_form_cadstar.xsl new file mode 100644 index 0000000..0c72f53 --- /dev/null +++ b/eeschema/plugins/xsl_scripts/netlist_form_cadstar.xsl @@ -0,0 +1,123 @@ +<?xml version="1.0" encoding="ISO-8859-1"?> +<!--XSL style sheet to EESCHEMA Generic Netlist Format to CADSTAR netlist format + Copyright (C) 2010, SoftPLC Corporation. + GPL v2. + + How to use: + see eeschema.pdf, chapter 14 +--> + +<!DOCTYPE xsl:stylesheet [ + <!ENTITY nl "
"> <!--new line CR, LF --> +]> + +<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> +<xsl:output method="text" omit-xml-declaration="yes" indent="no"/> + +<!-- Netlist header --> +<xsl:template match="/export"> + <xsl:text>.HEA&nl;</xsl:text> + <xsl:apply-templates select="design/date"/> <!-- Generate line .TIM <time> --> + <xsl:apply-templates select="design/tool"/> <!-- Generate line .APP <eeschema version> --> + <xsl:text>&nl;</xsl:text> + <xsl:apply-templates select="components/comp"/> <!-- Generate list of components --> + <xsl:text>&nl;&nl;</xsl:text> + <xsl:apply-templates select="nets/net"/> <!-- Generate list of nets and connections --> + <xsl:text>&nl;.END&nl;</xsl:text> +</xsl:template> + + <!-- Generate line .APP "eeschema (2010-08-17 BZR 2450)-unstable" --> +<xsl:template match="tool"> + <xsl:text>.APP "</xsl:text> + <xsl:apply-templates/> + <xsl:text>"&nl;</xsl:text> +</xsl:template> + + <!-- Generate line .TIM 20/08/2010 10:45:33 --> +<xsl:template match="date"> + <xsl:text>.TIM </xsl:text> + <xsl:apply-templates/> + <xsl:text>&nl;</xsl:text> +</xsl:template> + +<!-- for each component --> +<!-- create lines like + .ADD_COM U3 "74LS541" (when no footprint name specified) + .ADD_COM JP1 "CONN_8X2" "pin_array_8x2" "pin_array_8x2" (with a specified footprint name) +--> +<xsl:template match="comp"> + <xsl:text>.ADD_COM </xsl:text> + <xsl:value-of select="@ref"/> + <xsl:text> </xsl:text> + <xsl:choose> + <xsl:when test = "value != '' "> + <xsl:text>"</xsl:text> <xsl:apply-templates select="value"/> <xsl:text>"</xsl:text> + </xsl:when> + <xsl:otherwise> + <xsl:text>""</xsl:text> + </xsl:otherwise> + </xsl:choose> + <xsl:text>&nl;</xsl:text> +</xsl:template> + +<!-- for each net --> +<!-- create lines like +.ADD_TER U3.9 "/PC-RST" +.TER U3.8 + BUS1.2 +.ADD_TER BUS1.14 "/PC-IOR" +.TER U3.7 +--> +<xsl:template match="net"> + <!-- nets are output only if there is more than one pin in net --> + <xsl:if test="count(node)>1"> + <xsl:variable name="netname"> + <xsl:text>"</xsl:text> + <xsl:choose> + <xsl:when test = "@name != '' "> + <xsl:value-of select="@name"/> + </xsl:when> + <xsl:otherwise> + <xsl:text>N-</xsl:text> + <xsl:value-of select="@code"/> + </xsl:otherwise> + </xsl:choose> + <xsl:text>"&nl;</xsl:text> + </xsl:variable> + <xsl:apply-templates select="node" mode="first"/> + <xsl:value-of select="$netname"/> + <xsl:apply-templates select="node" mode="others"/> + </xsl:if> +</xsl:template> + +<!-- for each node --> +<xsl:template match="node" mode="first"> + <xsl:if test="position()=1"> + <xsl:text>.ADD_TER </xsl:text> + <xsl:value-of select="@ref"/> + <xsl:text>.</xsl:text> + <xsl:value-of select="@pin"/> + <xsl:text> </xsl:text> + </xsl:if> +</xsl:template> + +<xsl:template match="node" mode="others"> + <xsl:choose> + <xsl:when test='position()=1'> + </xsl:when> + <xsl:when test='position()=2'> + <xsl:text>.TER </xsl:text> + </xsl:when> + <xsl:otherwise> + <xsl:text> </xsl:text> + </xsl:otherwise> + </xsl:choose> + <xsl:if test="position()>1"> + <xsl:value-of select="@ref"/> + <xsl:text>.</xsl:text> + <xsl:value-of select="@pin"/> + <xsl:text>&nl;</xsl:text> + </xsl:if> +</xsl:template> + +</xsl:stylesheet> diff --git a/eeschema/plugins/xsl_scripts/netlist_form_pads-pcb.xsl b/eeschema/plugins/xsl_scripts/netlist_form_pads-pcb.xsl new file mode 100644 index 0000000..355072c --- /dev/null +++ b/eeschema/plugins/xsl_scripts/netlist_form_pads-pcb.xsl @@ -0,0 +1,69 @@ +<?xml version="1.0" encoding="ISO-8859-1"?> +<!--XSL style sheet to EESCHEMA Generic Netlist Format to PADS netlist format + Copyright (C) 2010, SoftPLC Corporation. + GPL v2. + + How to use: + see eeschema.pdf, chapter 14 +--> + +<!DOCTYPE xsl:stylesheet [ + <!ENTITY nl "
"> <!--new line CR, LF --> +]> + +<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> +<xsl:output method="text" omit-xml-declaration="yes" indent="no"/> + +<xsl:template match="/export"> + <xsl:text>*PADS-PCB*&nl;*PART*&nl;</xsl:text> + <xsl:apply-templates select="components/comp"/> + <xsl:text>&nl;*NET*&nl;</xsl:text> + <xsl:apply-templates select="nets/net"/> + <xsl:text>*END*&nl;</xsl:text> +</xsl:template> + +<!-- for each component --> +<xsl:template match="comp"> + <xsl:text> </xsl:text> + <xsl:value-of select="@ref"/> + <xsl:text> </xsl:text> + <xsl:choose> + <xsl:when test = "footprint != '' "> + <xsl:apply-templates select="footprint"/> + </xsl:when> + <xsl:otherwise> + <xsl:text>unknown</xsl:text> + </xsl:otherwise> + </xsl:choose> + <xsl:text>&nl;</xsl:text> +</xsl:template> + +<!-- for each net --> +<xsl:template match="net"> + <!-- nets are output only if there is more than one pin in net --> + <xsl:if test="count(node)>1"> + <xsl:text>*SIGNAL* </xsl:text> + <xsl:choose> + <xsl:when test = "@name != '' "> + <xsl:value-of select="@name"/> + </xsl:when> + <xsl:otherwise> + <xsl:text>N-</xsl:text> + <xsl:value-of select="@code"/> + </xsl:otherwise> + </xsl:choose> + <xsl:text>&nl;</xsl:text> + <xsl:apply-templates select="node"/> + </xsl:if> +</xsl:template> + +<!-- for each node --> +<xsl:template match="node"> + <xsl:text> </xsl:text> + <xsl:value-of select="@ref"/> + <xsl:text>.</xsl:text> + <xsl:value-of select="@pin"/> + <xsl:text>&nl;</xsl:text> +</xsl:template> + +</xsl:stylesheet> |