mirror of
https://github.com/skogaby/KFChickenShim.git
synced 2026-09-09 02:55:30 -05:00
641 lines
19 KiB
Python
641 lines
19 KiB
Python
import os
|
|
import sys
|
|
import datetime
|
|
|
|
print "" # print a new line
|
|
print "Running KiCadPadMod.py"
|
|
|
|
def ensure_dir(file_path):
|
|
try:
|
|
os.makedirs(file_path)
|
|
except OSError:
|
|
if not os.path.isdir(file_path):
|
|
raise
|
|
|
|
numArgs = len(sys.argv)
|
|
lastArg = numArgs - 1
|
|
#if numArgs < 3:
|
|
# #Print help
|
|
# print ""
|
|
# print "Not enough arguments!"
|
|
# print "See /Documentation/KiCadPadMod.md for manual."
|
|
# exit()
|
|
|
|
#Iterate through the line and inspect all the elements.
|
|
argPointer = 1
|
|
notEnoughArgs = 0
|
|
justListArgs = 0
|
|
|
|
subArgString = "undef"
|
|
padArgString = "undef"
|
|
nopadArgString = "undef"
|
|
onlypadArgString = "undef"
|
|
addArgString = "undef"
|
|
remArgString = "undef"
|
|
modArgString = "undef"
|
|
modArgValueString = "undef"
|
|
modArgValueMMString = "undef"
|
|
sourcePath = "undef"
|
|
destPath = "undef"
|
|
searchTermString = "undef"
|
|
|
|
#Insert the following to debug parsing
|
|
#print " Result..."
|
|
#print " currentArg =",
|
|
#print sys.argv[argPointer]
|
|
#print " argPointer =",
|
|
#print argPointer
|
|
#print " lastArg =",
|
|
#print lastArg
|
|
|
|
if lastArg < 3: #At min, we need .py path path
|
|
notEnoughArgs = 1
|
|
|
|
#Look for -l
|
|
if sys.argv[argPointer] == "-l" and notEnoughArgs == 0 :
|
|
justListArgs = 1
|
|
# print "-l option in effect, not touching files"
|
|
if argPointer <= lastArg - 2:
|
|
argPointer += 1
|
|
else:
|
|
notEnoughArgs = 1
|
|
|
|
#look for sub
|
|
if sys.argv[argPointer] == "-sub" and notEnoughArgs == 0 :
|
|
# print "we have sub, need 3 additional args"
|
|
if argPointer <= lastArg - 3:
|
|
argPointer += 1
|
|
subArgString = sys.argv[argPointer]
|
|
argPointer += 1
|
|
else:
|
|
notEnoughArgs = 1
|
|
|
|
#look for pad
|
|
if sys.argv[argPointer] == "-pad" and notEnoughArgs == 0 :
|
|
# print "we have pad, need 3 additional args"
|
|
if argPointer <= lastArg - 3:
|
|
argPointer += 1
|
|
padArgString = sys.argv[argPointer]
|
|
argPointer += 1
|
|
else:
|
|
notEnoughArgs = 1
|
|
|
|
#look for nopad
|
|
if sys.argv[argPointer] == "-nopad" and notEnoughArgs == 0 :
|
|
# print "we have nopad, need 3 additional args"
|
|
if argPointer <= lastArg - 3:
|
|
argPointer += 1
|
|
nopadArgString = sys.argv[argPointer]
|
|
argPointer += 1
|
|
else:
|
|
notEnoughArgs = 1
|
|
|
|
#look for onlypad
|
|
if sys.argv[argPointer] == "-onlypad" and notEnoughArgs == 0 :
|
|
# print "we have onlypad, need 3 additional args"
|
|
if argPointer <= lastArg - 3:
|
|
argPointer += 1
|
|
onlypadArgString = sys.argv[argPointer]
|
|
argPointer += 1
|
|
else:
|
|
notEnoughArgs = 1
|
|
|
|
#look for add
|
|
if sys.argv[argPointer] == "-add" and notEnoughArgs == 0 :
|
|
# print "we have add, need 3 additional args"
|
|
if argPointer <= lastArg - 3:
|
|
argPointer += 1
|
|
addArgString = sys.argv[argPointer]
|
|
argPointer += 1
|
|
else:
|
|
notEnoughArgs = 1
|
|
|
|
#look for rem
|
|
if sys.argv[argPointer] == "-rem" and notEnoughArgs == 0 :
|
|
# print "we have rem, need 3 additional args"
|
|
if argPointer <= lastArg - 3:
|
|
argPointer += 1
|
|
remArgString = sys.argv[argPointer]
|
|
argPointer += 1
|
|
else:
|
|
notEnoughArgs = 1
|
|
|
|
#look for mod
|
|
if sys.argv[argPointer] == "-mod" and notEnoughArgs == 0 :
|
|
# print "we have mod, need 4 additional args"
|
|
if argPointer <= lastArg - 4:
|
|
argPointer += 1
|
|
modArgString = sys.argv[argPointer]
|
|
argPointer += 1
|
|
modArgValueString = sys.argv[argPointer]
|
|
modArgValueMMString = "{:6.4f}".format(float(sys.argv[argPointer]) * 25.4)
|
|
argPointer += 1
|
|
else:
|
|
notEnoughArgs = 1
|
|
|
|
#Now there should be two args remaining
|
|
sourcePath = sys.argv[argPointer]
|
|
argPointer += 1
|
|
destPath = sys.argv[argPointer]
|
|
argPointer += 1
|
|
|
|
#If there is another term, it's the search term
|
|
if argPointer <= lastArg:
|
|
searchTermString = sys.argv[argPointer]
|
|
|
|
if justListArgs == 1 or notEnoughArgs == 1:
|
|
print ""
|
|
if justListArgs == 1:
|
|
print "-l option in effect, listing results"
|
|
if notEnoughArgs == 1:
|
|
print " (Notice: parsing failed)"
|
|
else:
|
|
print "-l option not in effect, but parsing failed so listing results anyhow"
|
|
print ""
|
|
print "subArgString:",
|
|
print subArgString
|
|
print "padArgString:",
|
|
print padArgString
|
|
print "nopadArgString:",
|
|
print nopadArgString
|
|
print "onlypadArgString:",
|
|
print onlypadArgString
|
|
print "addArgString:",
|
|
print addArgString
|
|
print "remArgString:",
|
|
print remArgString
|
|
print "modArgString:",
|
|
print modArgString
|
|
print "modArgValueString:",
|
|
print modArgValueString
|
|
print "modArgValueMMString:",
|
|
print modArgValueMMString
|
|
print "sourcePath:",
|
|
print sourcePath
|
|
print "destPath:",
|
|
print destPath
|
|
print "searchTermString:",
|
|
print searchTermString
|
|
|
|
# Now check for valid options
|
|
invalidOptions = 0
|
|
optionsCount = 0
|
|
|
|
print ""
|
|
if subArgString != "undef":
|
|
if subArgString == "0" or subArgString == "1":
|
|
print "Valid sublevel"
|
|
else:
|
|
invalidOptions = 1
|
|
print "[ERROR] Invalid sublevel option"
|
|
else:
|
|
print "No sublevel specified, operation TBD"
|
|
|
|
if padArgString != "undef":
|
|
if padArgString == "SMD" or padArgString == "PTH" or padArgString == "NPTH":
|
|
print "Valid pad value"
|
|
else:
|
|
invalidOptions = 1
|
|
print "[ERROR] Invalid pad option"
|
|
else:
|
|
invalidOptions = 1
|
|
print "no pad option specified!"
|
|
|
|
if nopadArgString != "undef":
|
|
if nopadArgString == "CENTER":
|
|
print "excluding center pad"
|
|
else:
|
|
invalidOptions = 1
|
|
print "[ERROR] Invalid nopad option"
|
|
else:
|
|
print "nopad not used, including center pad."
|
|
|
|
if onlypadArgString != "undef":
|
|
if onlypadArgString == "CENTER":
|
|
print "Only operation on center pad"
|
|
else:
|
|
invalidOptions = 1
|
|
print "[ERROR] Invalid onlypad option"
|
|
else:
|
|
print "onlypad not used, including all pads."
|
|
|
|
if nopadArgString != "undef" and onlypadArgString != "undef":
|
|
invalidOptions = 1
|
|
print "[ERROR] You can't exclude the center pad but only operate on it!"
|
|
|
|
if addArgString != "undef":
|
|
if addArgString == "F.Paste" or addArgString == "B.Paste" or addArgString == "F.Mask" or addArgString == "B.Mask":
|
|
print "Valid add value"
|
|
optionsCount += 1
|
|
else:
|
|
invalidOptions = 1
|
|
print "[ERROR] Invalid add option"
|
|
else:
|
|
print "No add option specified."
|
|
|
|
if remArgString != "undef":
|
|
if remArgString == "F.Paste" or remArgString == "B.Paste" or remArgString == "F.Mask" or remArgString == "B.Mask":
|
|
print "Valid rem value"
|
|
optionsCount += 1
|
|
else:
|
|
invalidOptions = 1
|
|
print "[ERROR] Invalid rem option"
|
|
else:
|
|
print "No rem option specified."
|
|
|
|
if modArgString != "undef":
|
|
if modArgString == "PadClearance" or modArgString == "MaskClearance" or modArgString == "PasteClearance":
|
|
print "Valid mod value"
|
|
optionsCount += 1
|
|
else:
|
|
invalidOptions = 1
|
|
print "[ERROR] Invalid mod option"
|
|
else:
|
|
print "No mod option specified."
|
|
|
|
if optionsCount == 0:
|
|
invalidOptions = 1
|
|
print "[ERROR] No operations specified."
|
|
|
|
if optionsCount > 1:
|
|
invalidOptions = 1
|
|
print "[ERROR] More than one option specified."
|
|
print " (Use batch file to run script multiple times instead.)"
|
|
|
|
# Now check for valid paths
|
|
if sourcePath != "undef":
|
|
print "Source path specified",
|
|
else:
|
|
invalidOptions = 1
|
|
print "[ERROR] Source path not present"
|
|
|
|
if destPath != "undef":
|
|
print "Destination path specified",
|
|
else:
|
|
invalidOptions = 1
|
|
print "[ERROR] Destination path not present"
|
|
|
|
if searchTermString != "undef":
|
|
print "Search terms specified",
|
|
else:
|
|
print "No search terms provided, using *.kicad_mod"
|
|
|
|
if justListArgs == 1 or notEnoughArgs == 1 or invalidOptions == 1:
|
|
print ""
|
|
if notEnoughArgs == 1:
|
|
print "[ERROR] Encountered invalid syntax."
|
|
if invalidOptions == 1:
|
|
print "[ERROR] Encountered invalid options."
|
|
if justListArgs == 1 and notEnoughArgs == 0 and invalidOptions == 0:
|
|
print "Syntax and parsing passed!"
|
|
else:
|
|
exit()
|
|
else:
|
|
print ""
|
|
print "Option parsing passed!"
|
|
|
|
# Now check file paths are actually valid
|
|
pathError = 0
|
|
|
|
print ""
|
|
print "Checking file paths"
|
|
|
|
print "Destination path:",
|
|
print destPath
|
|
if not os.path.isdir(destPath):
|
|
print " Destination path does not exists. Will be created!"
|
|
else:
|
|
print " Destination path exists!"
|
|
|
|
print "Source path:",
|
|
print sourcePath
|
|
if not os.path.isdir(sourcePath):
|
|
pathError = 1
|
|
print " [ERROR] soruce path doesn't exist!"
|
|
else:
|
|
print " Source path exists!"
|
|
|
|
if pathError == 1:
|
|
print ""
|
|
print "Path error, can't continue"
|
|
exit()
|
|
|
|
directoryList = []
|
|
fileList = []
|
|
|
|
#save contents of source into fileList, excluding those without .kicad_mod
|
|
for filename in os.listdir(sourcePath):
|
|
if filename[len(filename) - 10:] == ".kicad_mod":
|
|
fullFilePath = filename
|
|
print "file:",
|
|
print fullFilePath,
|
|
if searchTermString != "undef":
|
|
if filename.find(searchTermString, 0, len(filename)) != -1:
|
|
#found match
|
|
fileList.append(fullFilePath)
|
|
print ""
|
|
else:
|
|
print "[IGNORED]"
|
|
else:
|
|
fileList.append(fullFilePath)
|
|
print ""
|
|
|
|
if subArgString == "1":
|
|
#Save contents of source into directoryList, only choosing files with .pretty
|
|
for filename in os.listdir(sourcePath):
|
|
if filename[len(filename) - 7:] == ".pretty":
|
|
fullFilePath = filename
|
|
directoryList.append(fullFilePath)
|
|
#extend fileList with subdirs
|
|
for directoryname in directoryList:
|
|
print "directory:",
|
|
print directoryname
|
|
for filename in os.listdir(sourcePath + "\\" + directoryname):
|
|
if filename[len(filename) - 10:] == ".kicad_mod":
|
|
fullFilePath = directoryname + "\\" + filename
|
|
print " file:",
|
|
print fullFilePath,
|
|
if searchTermString != "undef":
|
|
if filename.find(searchTermString, 0, len(filename)) != -1:
|
|
#found match
|
|
fileList.append(fullFilePath)
|
|
print ""
|
|
else:
|
|
print "[IGNORED]"
|
|
else:
|
|
fileList.append(fullFilePath)
|
|
print ""
|
|
|
|
|
|
#print fileList
|
|
#print directoryList
|
|
|
|
if justListArgs == 1:
|
|
print ""
|
|
print "Exiting (-l option used)"
|
|
exit()
|
|
else:
|
|
print "Running script..."
|
|
|
|
ensure_dir(destPath)
|
|
for dirname in directoryList:
|
|
ensure_dir(destPath + dirname)
|
|
|
|
for filename in fileList:
|
|
print ""
|
|
print "Opening",
|
|
fullFilePath = sourcePath + filename
|
|
print fullFilePath
|
|
# Open the export mod style file
|
|
if os.path.isfile(fullFilePath) == True:
|
|
statinfo = os.stat(fullFilePath)
|
|
workingFileHandle = open(fullFilePath, "r")
|
|
# Read the footprint to memeory
|
|
workingFileMemory = workingFileHandle.read()
|
|
# ..Now workingFileMemory is a string that is the input file
|
|
|
|
|
|
#First, seek out initial "pad" text
|
|
locVar = workingFileMemory.find("(pad ", 0, len(workingFileMemory))
|
|
if locVar > 0:
|
|
#This file has one or more
|
|
fileVar = 0
|
|
parsingFile = 1
|
|
while parsingFile == 1 and fileVar < len(workingFileMemory):
|
|
locVar = workingFileMemory.find("(pad ", fileVar, len(workingFileMemory))
|
|
if locVar > 0:
|
|
#print "Found pad!"
|
|
fileVar = locVar + 1
|
|
leftParen = locVar
|
|
leftParenCount = 1
|
|
rightParenCount = 0
|
|
countIsNonZero = 1
|
|
nextParen = leftParen
|
|
|
|
while countIsNonZero == 1:
|
|
|
|
#Find next paren
|
|
var2 = workingFileMemory.find("(", nextParen + 1, len(workingFileMemory))
|
|
var1 = workingFileMemory.find(")", nextParen + 1, len(workingFileMemory))
|
|
if var1 != -1 or var2 != 0:
|
|
if var2 < var1 and var2 > 0:
|
|
#set output = var2
|
|
nextParen = var2
|
|
else:
|
|
nextParen = var1
|
|
#Found something
|
|
#modify counts
|
|
if workingFileMemory[nextParen] == '(':
|
|
#print workingFileMemory[nextParen]
|
|
leftParenCount = leftParenCount + 1
|
|
elif workingFileMemory[nextParen] == ')':
|
|
#print workingFileMemory[nextParen]
|
|
rightParenCount = rightParenCount + 1
|
|
else:
|
|
print "No more chars"
|
|
countIsNonZero = 0
|
|
#print leftParenCount,
|
|
#print ",",
|
|
#print rightParenCount
|
|
#if counts are equal, do a thing then bail
|
|
workOnPad = 0
|
|
if leftParenCount == rightParenCount:
|
|
print "Found: ",
|
|
if workingFileMemory.find("(at 0 0)", leftParen, nextParen) > 0:
|
|
#This is a center pad
|
|
print "Center,",
|
|
if nopadArgString != "CENTER":
|
|
print "(will modify)",
|
|
#work on this pad
|
|
workOnPad = 1
|
|
else:
|
|
countIsNonZero = 0 #break
|
|
print "(ignored)"
|
|
if workingFileMemory.find("(at 0 0)", leftParen, nextParen) == -1:
|
|
print "Normal,",
|
|
#This is not a center pad
|
|
if onlypadArgString != "CENTER":
|
|
print "(will modify)",
|
|
#work on this pad
|
|
workOnPad = 1
|
|
else:
|
|
countIsNonZero = 0 #break
|
|
print "(ignored)"
|
|
# Now test for the type of pad, but only after center rules adhered to
|
|
if workOnPad == 1:
|
|
workOnPad = 0
|
|
if workingFileMemory.find(" smd ", leftParen + 4, nextParen) > 0: #adding 4 insures pad named 'smd' doesn't trigger
|
|
#This is a smd pad
|
|
print "Type: SMD",
|
|
if padArgString == "SMD":
|
|
print "(will modify)"
|
|
#work on this pad
|
|
workOnPad = 1
|
|
else:
|
|
countIsNonZero = 0 #break
|
|
print "(ignored)"
|
|
if workingFileMemory.find(" thru_hole ", leftParen + 4, nextParen) > 0: #adding 4 insures pad named 'thru_hole' doesn't trigger
|
|
#This is a thru_hole pad
|
|
print "Type: PTH",
|
|
if padArgString == "PTH":
|
|
print "(will modify)"
|
|
#work on this pad
|
|
workOnPad = 1
|
|
else:
|
|
countIsNonZero = 0 #break
|
|
print "(ignored)"
|
|
if workingFileMemory.find(" np_thru_hole ", leftParen + 4, nextParen) > 0: #adding 4 insures pad named 'np_thru_hole' doesn't trigger
|
|
#This is a np_thru_hole pad
|
|
print "Type: NPTH",
|
|
if padArgString == "NPTH":
|
|
print "(will modify)"
|
|
#work on this pad
|
|
workOnPad = 1
|
|
else:
|
|
countIsNonZero = 0 #break
|
|
print "(ignored)"
|
|
|
|
if workOnPad == 1:
|
|
countIsNonZero = 0
|
|
rightParen = nextParen + 1
|
|
# print "Syntax Correct!"
|
|
# print workingFileMemory[leftParen:rightParen]
|
|
|
|
#This is where the options on what to do take place.
|
|
#If rem is used, remove the pad layer
|
|
if remArgString != "undef":
|
|
#We will be removing a layer
|
|
#Generate string data
|
|
# find .
|
|
var3 = remArgString.find(".", 0, len(remArgString))
|
|
if var3 != -1:
|
|
searchString = " *." + remArgString[var3+1:]
|
|
replaceString = " F." + remArgString[var3+1:] + " B." + remArgString[var3+1:]
|
|
removeString = " " + remArgString
|
|
#Look for the (layers .....) param
|
|
var1 = workingFileMemory.find("(layers ", leftParen, rightParen)
|
|
var2 = workingFileMemory.find(")", var1, rightParen)
|
|
#convert *.thing to F.thing and B.thing
|
|
var3 = workingFileMemory.find(searchString, var1, var2)
|
|
if var3 != -1:
|
|
tempFileMemory = workingFileMemory[:var3] + workingFileMemory[var3 + len(searchString):]
|
|
#Move pointers
|
|
rightParen -= len(searchString)
|
|
var2 -= len(searchString)
|
|
#Now insert new text
|
|
#print tempFileMemory[leftParen:rightParen]
|
|
workingFileMemory = tempFileMemory[:var3] + replaceString + tempFileMemory[var3:]
|
|
rightParen += len(replaceString)
|
|
var2 += len(replaceString)
|
|
#print workingFileMemory[leftParen:rightParen]
|
|
#Search for string to remove
|
|
var4 = workingFileMemory.find(removeString, var1, var2)
|
|
if var4 != -1:
|
|
tempFileMemory = workingFileMemory[:var4] + workingFileMemory[var4 + len(removeString):]
|
|
workingFileMemory = tempFileMemory
|
|
rightParen -= len(removeString)
|
|
var2 -= len(removeString)
|
|
#print workingFileMemory[leftParen:rightParen]
|
|
#If add was used, add the layer if it doesn't already exist
|
|
if addArgString != "undef":
|
|
#We will be adding a layer
|
|
# find .
|
|
var3 = addArgString.find(".", 0, len(addArgString))
|
|
if var3 != -1:
|
|
#Generate string data
|
|
searchString = " *." + addArgString[var3+1:]
|
|
addString = " " + addArgString
|
|
#Look for the (layers .....) param
|
|
var1 = workingFileMemory.find("(layers ", leftParen, rightParen)
|
|
var2 = workingFileMemory.find(")", var1, rightParen)
|
|
#if *.thing is found, we are done!
|
|
var3 = workingFileMemory.find(searchString, var1, var2)
|
|
if var3 != -1:
|
|
# *. was found! the arg is covered.
|
|
var3 = var3
|
|
else:
|
|
# *. not found, but perhaps the single one is there
|
|
var3 = workingFileMemory.find(addString[1:], leftParen, rightParen)
|
|
if var3 != -1:
|
|
#found it, we are done
|
|
var3 = var3
|
|
else:
|
|
#we need to add it.
|
|
tempFileMemory = workingFileMemory[:var2] + addString + workingFileMemory[var2:]
|
|
rightParen += len(addString)
|
|
var2 += len(addString)
|
|
workingFileMemory = tempFileMemory
|
|
#print workingFileMemory[leftParen:rightParen]
|
|
#If mod was used, remove the attrib and reapply it.
|
|
if modArgString != "undef" and modArgValueMMString != "undef":
|
|
#We will be modifying a parameter
|
|
#Generate string data
|
|
searchString = "undef"
|
|
if modArgString == "PadClearance":
|
|
searchString = "(clearance"
|
|
if modArgString == "MaskClearance":
|
|
searchString = "(solder_mask_margin"
|
|
if modArgString == "PasteClearance":
|
|
searchString = "(solder_paste_margin"
|
|
|
|
if searchString != "undef":
|
|
#good to go!
|
|
addString = searchString + " " + modArgValueMMString + ")"
|
|
|
|
#Look for instance of search term
|
|
var3 = workingFileMemory.find(searchString, leftParen, rightParen)
|
|
if var3 != -1:
|
|
#found it -- index it
|
|
var1 = workingFileMemory.find(searchString, leftParen, rightParen)
|
|
var2 = workingFileMemory.find(")", var1, rightParen)
|
|
#Calculate length of this string
|
|
stringLen = var2 - var1 + 1
|
|
#remove it
|
|
tempFileMemory = workingFileMemory[:var1] + workingFileMemory[var1 + stringLen:]
|
|
workingFileMemory = tempFileMemory
|
|
rightParen -= stringLen
|
|
var2 -= stringLen
|
|
#var1 should now equal var2
|
|
|
|
#Now add the new tag
|
|
if workingFileMemory[rightParen - 2] != " ":
|
|
tempString = " " + addString
|
|
addString = tempString
|
|
tempFileMemory = workingFileMemory[:rightParen - 1] + addString + workingFileMemory[rightParen - 1:]
|
|
rightParen += len(addString)
|
|
var2 += len(addString)
|
|
workingFileMemory = tempFileMemory
|
|
#print workingFileMemory[leftParen:rightParen]
|
|
else:
|
|
print "Invalid modArgString"
|
|
else:
|
|
parsingFile = 0
|
|
# print workingFileMemory[locVar-3:locVar+3]
|
|
else:
|
|
#This file has none!
|
|
print "File has no pads!"
|
|
|
|
#print tempFileMemory
|
|
#programPause = raw_input("Press the <ENTER> key to continue...")
|
|
|
|
#Write the output file
|
|
outputFilePath = destPath + filename
|
|
# Write out the workingFileMemory
|
|
if os.path.isfile(outputFilePath) == True:
|
|
statinfo = os.stat(outputFilePath)
|
|
outputFileHandle = open(outputFilePath, "w+")
|
|
# Read the KiCad Library to memeory
|
|
else:
|
|
print "creating",
|
|
print outputFilePath
|
|
outputFileHandle = open(outputFilePath, "w+")
|
|
outputFileHandle.write(workingFileMemory) # Enable this line to write memory to OUTPUT
|
|
outputFileHandle.close()
|
|
|
|
workingFileHandle.close()
|
|
else:
|
|
print "File not opened!"
|
|
|
|
print ""
|
|
|
|
print "Script finished!" |