WireIt: PCBNEW plugin for adding/cutting/swapping wires in the physical layout


I’ve released WireIt, a PCBNEW plugin that lets you add nets, remove nets, and swap pins on the physical layout. Changes made in the layout can be dumped to a file for backannotation into the schematic. There is a short video demonstrating its use.

I’m using WireIt in conjunction with PadPainter to do I/O pin assignments from an FPGA to surrounding peripherals so that the wiring is as crossover-free as I can make it.

Moving from Python to Lisp/Lua
PCB design without schematic

Just wondering:
How much effort would it be to automatically generate the netlist from existing traces?
For example, this thread is a reverse engineering effort in which a PCB is re-created from the gerber files



Below is a script that exports a pcbnew formatted NETLIST from a design file.

Useful for manual/text originated designs, or designs imported from other CAD flows, where you may not have an Original NETLIST, or may be unsure about its validity.

# PcbNew_Export_PcbNew_NET derived from PcbNew_Export_PADS_NET.py
# eg Usage - in KiCad PcbNew Python Console paste after >>>
# >>> execfile("C:\KiCad_Python\Check_Footprint_Attr\PcbNew_Export_PcbNew_NET.py")  - gone in P3 ?
# Purposes : 
# * for "complete the circle" tests when using KiCad IMPORT design feature 
# * for ECO check, create a NET copy when starting, and confirm matches when completed.
# * for Version control reporting of merged, or non SCH design flows. 

# V1.0  first port from PcbNew_Export_PADS_NET.py
# checked can import original, and the exported netlists fine, and can import-over.
# Notice the NET number jumps around, so original does not match exported, but the netname seems to win, so import is ok.
# That means you should save an exported COPY asap, if you want to keep an audit comparison.
# V1.01  Added report comment at end of net file, KiCad seems to tolerate that
# V1.02  Improved tests and reports
# V1.03  Fixed message Info: Changing component path "X1:/568E18BC" to "", by adding extract of needed (sheetpath (tstamps /)) (tstamp 568E18BC) lines

import string     # used for rsplit
import pcbnew             # ok on fresh start

pcb = pcbnew.GetBoard()   # Works on Loaded Design file

# For now, just dump the ASCII NET info to the Python Console, can add File-name later
# Allows comments as *REMARK*
print '(export (version D)'
print '  (components'
#(export (version D)
#  (components
#    (comp (ref J1)
#      (value TI_BOOSTER_40_J1)
#      (footprint Pin_Headers:Pin_Header_Angled_1x10_Pitch2.54mm))
#    (comp (ref J2)

# ~~~~~~~~~~~~~~ Audit counters ~~~~~~~~~~~~~~~~~
ShtPathCount = 0
PartCount = 0
SkipCount = 0
PinCount  = 0
Warnings  = 0

# def GetPadCount(self, *args): """ GetPadCount(MODULE self, INCLUDE_NPTH_T aIncludeNPTH) -> unsigned int  GetPadCount(MODULE self) -> unsigned int  """ return _pcbnew.MODULE_GetPadCount(self, *args)
# def GetUniquePadCount(self, *args): """ GetUniquePadCount(MODULE self, INCLUDE_NPTH_T aIncludeNPTH) -> unsigned int GetUniquePadCount(MODULE self) -> unsigned int  """ return _pcbnew.MODULE_GetUniquePadCount(self, *args)
#    (comp (ref J1)
#      (value TI_BOOSTER_40_J1)
#      (footprint Pin_Headers:Pin_Header_Angled_1x10_Pitch2.54mm))
#    (comp (ref J2)

# try to export    (path /568E18BC) entry - similar to (attr smd) called Sheet path in help, hover says it is an A unique ID, a timestamp, alternate identifier to the reference.
# part.GetTimeStamp() gives 1448919751 = 0x565CC2C7 
# Last item JP1 has /567C1358 seems quite close to .. 0x567C132C 0x567C1358-1450971948 = 44  WTF ?   1450971948  = 0x567C132C    (tstamp 567C132C)
#   (module hack-footprints:SMD_Jumper (layer B.Cu) (tedit 569F9EC7) (tstamp 567C132C)
#     (path /567C1358)   << want this one, NOT tstamp ??, tho tstamp is close usually quite close ?     aGetPath /567C1358
# P6 gives  0x569F8542-1453287917 = 6997   1453287917  = 0x569F69ED  (tstamp 569F69ED)
# P5 gives 0x569F6050-1453284133  = 1323   1453284133 = 0x569F5B25   (tstamp 569F5B25)

for part in pcb.GetModules():
       ref       = part.Reference().GetText()
       if ref:   # skip empty names - PCAD files seem to have some ?
#         footprint = part.GetFPID().GetFootprintName()  fails v5rc 2018 ?, can't see GetFootprintName in helps ?
         footprint = part.GetFPID().GetLibItemName()    # seems to fix that ?
         val       = part.Value().GetText()
         LibNick = part.GetFPID().GetLibNickname()  # This is UTF8, but how to check if printing nothing ??
         aGetPath = part.GetPath()                  # Gets string from FootprintProperties.SheetPath, can have Number AND prefix like /567C1359
         print '    (comp (ref "%s")'%(ref) 
         print '      (value "%s")'%(val)   
         if aGetPath <> '' :                  # make this optional ? gives error messages if not in netlist
            aPtn = aGetPath.rpartition('/')   # Guess paths always use / ?
            if aPtn[1] <> '' :            
                print '      (sheetpath (tstamps %s%s))'%(aPtn[0],aPtn[1])
            print '      (tstamp %s)'%(aPtn[2])
            ShtPathCount = ShtPathCount + 1

         if not LibNick.empty() :
            print '      (footprint "%s:%s"))'%(LibNick,footprint)
         else:    #empty string in library, so shorter format
            print '      (footprint "%s"))'%(footprint)   
         PartCount = PartCount + 1
         SkipCount = SkipCount + 1
print ')'    # Balance braces 

Nc = pcb.GetNetCount()
Pc = pcb.GetPadCount()
print "  (nets" # Start NETS section 
#    (net (code 6) (name /NTH)
#      (node (ref J1) (pin 9))
#      (node (ref TH1) (pin 2)))
#    (net (code 7) (name "Net-(J1-Pad3)")   << hmm, some use quotes, some do not ??

for sN in range(1,Nc):              # order does not seem to match .kicad_pcb node numbers, but maybe does not matter ?
   Net = pcb.FindNet(sN)            # Scan by node number  -> NETINFO_ITEM
   nName  = Net.GetNetname()
#   if '-' in nName:                 # Do Other chars need "" ? - does it matter if "" are on a std NET? - seems not, so can simplify with "" everywhere.
   print '    (net (code %s) (name "%s")'%(sN,nName)  # Place all netnames in quotes
#   else:  
#     print '    (net (code %s) (name "%s")'%(sN,nName)

#   for pad in Net.Pads():           # WTF fails May 2018 V5 RC ?? 'NETINFO_ITEM' object has no attribute 'Pads' ?
#        print pad.GetPadName()  # MISSING IN v5.X?
   for pad in pcb.GetPads():         # will be MUCH slower, but seems to fix it....
      if (pad.GetNetCode() == sN):   # Net code may be  faster ?
        PinName = pad.GetPadName()
        Module  = pad.GetParent()
        RefDes  = Module.GetReference()
        PinCount = PinCount+1                             
        print '      (node (ref "%s") (pin "%s"))'%(RefDes,PinName)  # try quotes to see if empty pinnum and ref helped 
   print ')'    # Balance braces 
print '))'      # Balance braces 
print '#Comment  KiCad NET export using PcbNew_Export_PcbNew_NET.py v1.03, from Kicad design: %s'%(pcb.GetFileName())
print "#Comment: Parts:%s, Nets:%s, PinsConected:%s, TotalPads:%s, Ref Skipped:%s, SheetPath:%s" %(PartCount,(Nc-1),PinCount,Pc,SkipCount,ShtPathCount)  # Kicad tolerates EOF comment line, so report
# Test Results Good, - when Part-only 

# example:
#Comment  KiCad NET export using PcbNew_Export_PcbNew_NET.py v1.02, from Kicad design: C:/KiCadFiles/HACKmaster/HACK-master-R3/kicad/hack_jg.kicad_pcb
#Comment: Parts:36, Nets:44, PinsConected:164, TotalPads:169, Ref Skipped:0 

# references :
# https://github.com/KiCad/kicad-doc/blob/master/src/pcbnew/pcbnew_python_scripting.adoc
# C:\Program Files\KiCad\lib\python2.7\site-packages\pcbnew.py
# Test operation/reports :
# Import New with new node gives
#  Changing footprint "U1:" pad "G" net name from "" to "GND". 
# import with node removed
#  Clearing component "U1:" pin "G" net name.


I have another (minor?) feature request… :slight_smile:
To work best, this will need a fix made to Select Copper Connection.

Request: can ‘Disconnect airwires from pads’ also act as a split-net command, where someone selects N segments of a NET, but not the whole net.
Usually one split keeps the old net name, and a new net name is assigned to now isolated connection set.
PADS and Vias touched would have that new net name applied.

I think Select Copper Connection selects vias in the sub-group, but does not select touched pads. ie that may need a pass to find/select pads touching a selected trace ?

One use case, is in manual duplicate of a cell array, where that slavish clones all net names where exact clones may not be desired. Being able to split some routed nets, after clone, would be useful.


I can look at doing this. Can you enter it as an issue/enhancement on the Github repo? I can’t say when I’ll get to it: I’m still trying to make a living and I have several other KiCad-related tools that also need attention.


Sure, done that. No hurry, and I also submitted a bug report above on the Select Copper.