Working on an interactive Python Extension Script which leverages kicad hashes to identify all components and nets which are coming to layout from the same hierarchical schematic. The envisioned function is you click a footprint in pcb editor, envoke script, and the script causes all nets and components from the same hierarchical script to be highlighted so that they can be manipulated as a group.
So, we have studied the hashtags and the python interface extensively. We have written a python script (following) which through debug we have verified is choosing exactly what we want, all of the items we want highlighted are highlighted, and then the script ends and it drops all chosen items. We seem to be 99.9% there, but are missing something. We realize that:
a) The problem might be because we are using an older version of kicad (caused by our OS distributions having long integration cycles which also tends to make them more stable. However, this may be a bug which is already fixed though upgrading right now would cause our workstations to completely crash. If this is the case though it would make sense that we need to setup a dedicated workstation for this purpose… Just need to know. We are using kicad 5.0.2 by the way)
b) The problem might be we are misreading and/or misunderstanding something about the mechanisms behind the kicad extensions. Here the right person telling us the right tip could literally save us months of the most infuriating guessing.
c) Don’t even know… Guessing. Everybody with my team though is completely puzzled by this action. With this, if this tool were to work, it would absolutely be something of general interest and we are completely open as is the idea with open software to allow others to use the extension.
Without further stuff… here it is… Any thoughts greatly appreciated (including tips for attaching documents instead of just pasting inline…)
# This is an action plugin script for kicad
# Copy it into /usr/share/kicad/scripting/plugins/
# Then start kicad, pcbnew, and go to the Tools->External Plugins menu.
# It should be visible as menu item "panel selector" with a hammer icon.
import pcbnew
def isRouted(pad):
loc=pad.GetPosition()
for i in pad.GetBoard().TracksInNet( pad.GetNetCode() ):
if i.GetStart()==loc or i.GetEnd()==loc : return True
return False
def isAnchor(module):
ref=module.GetReference()
if ref and ord( ref[0] )==0x2693: return True
return False
class PanelSelectPlugin(pcbnew.ActionPlugin):
def defaults(self):
self.name="panel selector"
self.category="panelization"
self.description="""Select panel anchor(s) and sheet contents from a pre-selected modules.
If incompatible anchors are selected, deselect incompatible panels with less modules.
If Panels are already fully selected, deselect everything except anchors.
If only a single anchor is left selected, move the cursor to it.
"""
# layertable={}
# for i in range( pcbnew.PCB_LAYER_ID_COUNT ):
# layertable[board.GetLayerName(i)]=i
#
def Run(self):
# The entry function that is executed on user action
board=pcbnew.GetBoard()
# Find selected items, sort into sheets (panels) they belong to.
# A 'panelID' is path code[:-1].
# An 'anchorID' is the minimumID code[-1] for a given sheetID.
# For every panelID, locate an anchorID and anchorModule.
print("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n")
all_panel={}
for module in board.GetModules():
path=module.GetPath().split('/')
if len(path)==2: continue # Don't catalog root sheet, no point...
panelID='/'.join(path[:-1])
partID=path[-1]
try:
panel=all_panel[panelID]
except:
#panel=[ selected, footprints, anchID, anchM, searchForAnch ]
panel=[0,0,partID,module,True]
all_panel[panelID]=panel
panel[0]+=module.IsSelected()
if module.IsSelected(): print( "Sel=",partID,module.GetReference())
panel[1]+=1 # Count footprints
if panel[4] and (partID<panel[2]): panel[2:5]=( partID,module,True)
if isAnchor(module): panel[2:5]=( partID,module,False )
# All panel instances are tabulated
board.ClearSelected() # Prepare for panel-wide selection.
# If any two panels are compatible, they will have the same anchorID
anchorID, allSelect=False,set()
# Go through all panels, keeping only paths that have the anchor.
for panelID,panel in all_panel.items():
if not panel[0]: continue
if not anchorID: anchorID=panel[2]
if anchorID != panel[2]:
if panel[0]: print("Warn: Deselecting ",panel[3].GetReference())
continue
panel[3].SetSelected() # Anchor is always on if any selection
if panel[0]!=panel[1]: allSelect.add( panelID )
for module in board.GetModules():
path=module.GetPath().split('/')
panelID='/'.join(path[:-1])
if panelID in allSelect:
module.SetSelected()
print("+",module.GetReference() )
return