Eeschema: add python script netlist_form_OrcadPcb2.py and netlist_form_pads-pcb-asc.py

to replace netlist_form_OrcadPcb2.xsl and netlist_form_pads-pcb.asc.xsl
This commit is contained in:
jean-pierre charras 2021-09-02 16:21:18 +02:00
parent bc8245ca7b
commit 7e2abf545b
4 changed files with 279 additions and 12 deletions

View File

@ -286,6 +286,16 @@ class libpart():
fieldNames.append( f.get('field','name') )
return fieldNames
def getPinList(self):
"""Return a list of pins in play for this libpart.
"""
pinList = []
pins = self.element.getChild('pins')
if pins:
for f in pins.getChildren():
pinList.append( f )
return pinList
def getDatasheet(self):
return self.getField("Datasheet")
@ -361,20 +371,21 @@ class comp():
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
def getField(self, name, aLibraryToo = 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
aLibraryToo -- 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 and self.libpart:
if field == "" and aLibraryToo and self.libpart:
field = self.libpart.getField(name)
return field
@ -394,15 +405,25 @@ class comp():
def getRef(self):
return self.element.get("comp", "ref")
def getFootprint(self, libraryToo=True):
'''
return the footprint name. if empty and aLibraryToo = True, return the
footprint name from libary
'''
def getFootprint(self, aLibraryToo = True):
ret = self.element.get("footprint")
if ret == "" and libraryToo and self.libpart:
if ret == "" and aLibraryToo and self.libpart:
ret = self.libpart.getFootprint()
return ret
def getDatasheet(self, libraryToo=True):
'''
return the datasheet name. if empty and aLibraryToo = True, return the
datasheet name from libary
'''
def getDatasheet(self, aLibraryToo = True):
ret = self.element.get("datasheet")
if ret == "" and libraryToo and self.libpart:
if ret == "" and aLibraryToo and self.libpart:
ret = self.libpart.getDatasheet()
return ret
@ -420,6 +441,41 @@ class comp():
def getDescription(self):
return self.element.get("libsource", "description")
'''
return the netname of the pin aPinNum in netlist aNetlist
if aSkipEmptyNet = True, net having only one pin will return a empty name
'''
def getPinNetname(self, aPinNum, aNetlist, aSkipEmptyNet):
ref = self.getRef()
for net in aNetlist.nets:
net_name = net.get( "net", "name" )
item_cnt = 1
netitems = net.children
for node in netitems:
curr_item_ref = node.get( "node", "ref" )
if curr_item_ref == ref:
curr_pin = node.get( "node", "pin" )
if aPinNum == curr_pin:
if aSkipEmptyNet: #ensure at least 2 pins are in net
pin_count = 0
for curr_node in netitems:
pin_count += 1
if pin_count > 1:
return net_name
return ""
else:
return net_name
return "?"
class netlist():
""" Kicad generic netlist class. Generally loaded from a kicad generic

View File

@ -0,0 +1,110 @@
#
# Example python script to generate a BOM from a KiCad generic netlist
#
"""
@package
Output: old OrcadPcb2 netlist format
Sorted By: Ref
Command line:
python "pathToFile/netlist_form_OrcadPcb2.py" "%I" "%O.net"
"""
from __future__ import print_function
# Import the KiCad python helper module
import kicad_netlist_reader
import sys
# A helper function to convert a UTF8/Unicode/locale string read in netlist
# for python2 or python3 (Windows/unix)
def fromNetlistText( aText ):
if sys.platform.startswith('win32'):
try:
return aText.encode('utf-8').decode('cp1252')
except UnicodeDecodeError:
return aText
else:
return aText
# 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
netlist = 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], 'wb')
except IOError:
e = "Can't open output file for writing: " + sys.argv[2]
print(__file__, ":", e, sys.stderr)
f = sys.stdout
components = netlist.getInterestingComponents()
row =""
''' Netlist header:
( { EESchema Netlist Version 1.1 02/09/2021 11:10:00
Eeschema (5.99.0-12178-ge03257b55f-dirty)}
'''
''' Generate line ( { EESchema Netlist Version 1.1 <time> '''
row += '( { EESchema Netlist Version 1.1 ' + netlist.getDate() + '\n'
''' Generate line Eeschema <eeschema version> '''
row += 'Eeschema ' + netlist.getTool() + ' }\n\n'
'''
This template read each component and creates lines:
( 3EBF7DBD $noname U1 74LS125
... pin list ...
)
and calls "create_pin_list" template to build the pin list
'''
for c in components:
fp_name = c.getFootprint( False )
if fp_name == "":
fp_name = "$noname"
row += "( " + c.getTimestamp() + ' ' + fp_name
row += ' ' + c.getRef()
row += ' ' + c.getValue()
row += '\n'
'''
generate pin list
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 )
for not connected pins:
( 3 ? )
'''
lib = c.getLibPart()
pinlist = lib.getPinList()
for pin in pinlist:
pin_num = pin.get('pin','num')
row += " ( " + pin_num + " "
netname = c.getPinNetname( pin_num, netlist, True )
if netname == "":
netname = "?"
row += netname
row += " )\n"
row += ')\n'
row += '\n)\n'
f.write(row.encode('utf-8'))
f.close()

View File

@ -8,7 +8,7 @@
Sorted By: Ref
Command line:
python "pathToFile/bom_txt_sorted_by_ref.py" "%I" "%O.rinf"
python "pathToFile/netlist_form_cadstar.py" "%I" "%O.frp"
"""
from __future__ import print_function
@ -50,7 +50,8 @@ row += ".HEA" + '\n'
''' Generate line .TIM <time> '''
row += '.TIM ' + netlist.getDate() + '\n'
''' Generate line .APP <eeschema version> '''
row += '.APP ' + netlist.getTool() + '\n\n'
row += '.APP ' + netlist.getTool() + '\n'
row += '.TYP FULL' + '\n\n'
''' Generate list of component
@ -62,8 +63,10 @@ row += '.APP ' + netlist.getTool() + '\n\n'
for c in components:
row += ".ADD_COM " + " " + c.getRef() + " \"" + c.getValue() + "\""
if c.getFootprint() != "":
row += " \"" + c.getFootprint() + "\""
fp_name = c.getFootprint( False )
if fp_name != "":
row += " \"" + fp_name + "\""
row += '\n'

View File

@ -0,0 +1,98 @@
#
# Example python script to generate a BOM from a KiCad generic netlist
#
"""
@package
Output: PADS format netlist
Sorted By: Ref
Command line:
python "pathToFile/netlist_form_pads-pcb-asc.py" "%I" "%O.net"
"""
from __future__ import print_function
# Import the KiCad python helper module
import kicad_netlist_reader
import sys
# A helper function to convert a UTF8/Unicode/locale string read in netlist
# for python2 or python3 (Windows/unix)
def fromNetlistText( aText ):
if sys.platform.startswith('win32'):
try:
return aText.encode('utf-8').decode('cp1252')
except UnicodeDecodeError:
return aText
else:
return aText
# 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
netlist = 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], 'wb')
except IOError:
e = "Can't open output file for writing: " + sys.argv[2]
print(__file__, ":", e, sys.stderr)
f = sys.stdout
components = netlist.getInterestingComponents()
row =""
''' Netlist header '''
row += "!PADS-POWERPCB-V2.0-MILS!" + '\n'
row += '*PART*' + '\n'
''' Generate list of component
for each component create lines like
C1 Capacitor_THT:CP_Axial_L18.0mm_D6.5mm_P25.00mm_Horizontal
C2 Capacitor_THT:CP_Axial_L18.0mm_D6.5mm_P25.00mm_Horizontal
'''
for c in components:
row += " " + c.getRef()
fp_name = c.getFootprint( False )
if fp_name != "":
row += " " + fp_name
row += '\n'
'''
generate for each net create lines like
*SIGNAL* /CLOCK-RB6
P2.27
P3.39
'''
nets = netlist.getNets()
row += '\n*NET*' + '\n'
for net in nets:
# count the number of pads in net. nets with only one pad are skipped
netitems = net.children
pad_count = 0
for node in netitems:
pad_count += 1
netitems = net.children
if pad_count > 1:
row += "*SIGNAL* " + net.get( "net", "name" ) + '\n'
for node in netitems:
row += node.get('node','ref') + '.' + node.get('node','pin') + '\n'
row += '*END*\n'
f.write(row.encode('utf-8'))
f.close()