Commit c1e0a8d0 authored by unknown's avatar unknown Committed by jean-pierre charras

Patch for the Python footprint wizard helpers. This adds a few more drawing...

Patch for the Python footprint wizard helpers. This adds a few more drawing functions, such as for circles, and also uses a matrix-based transform stack with greatly simplifies constructing footprints consisting of regularly spaced elements (e.g. in lines, grids, circles, or some list of points that you specify).
This fixes bug #1366299
parent 1edd8c8a
...@@ -30,7 +30,7 @@ class FPCFootprintWizard(FootprintWizardPlugin): ...@@ -30,7 +30,7 @@ class FPCFootprintWizard(FootprintWizardPlugin):
pad.SetSize(size) pad.SetSize(size)
pad.SetShape(PAD_RECT) pad.SetShape(PAD_RECT)
pad.SetAttribute(PAD_SMD) pad.SetAttribute(PAD_SMD)
pad.SetLayerSet( pad.StandardMask() ) pad.SetLayerSet( pad.SMDMask() )
pad.SetPos0(pos) pad.SetPos0(pos)
pad.SetPosition(pos) pad.SetPosition(pos)
pad.SetPadName(name) pad.SetPadName(name)
......
...@@ -15,8 +15,10 @@ ...@@ -15,8 +15,10 @@
# #
import pcbnew import pcbnew
import math
import FootprintWizardDrawingAids import FootprintWizardDrawingAids
class FootprintWizardParameterManager: class FootprintWizardParameterManager:
""" """
Functions for helpfully managing parameters to a KiCAD Footprint Functions for helpfully managing parameters to a KiCAD Footprint
...@@ -50,8 +52,9 @@ class FootprintWizardParameterManager: ...@@ -50,8 +52,9 @@ class FootprintWizardParameterManager:
uMils = 2 uMils = 2
uNatural = 3 uNatural = 3
uBool = 4 uBool = 4
uString = 5
def AddParam(self, section, param, unit, default, hint = ''): def AddParam(self, section, param, unit, default, hint=''):
""" """
Add a parameter with some properties. Add a parameter with some properties.
...@@ -66,14 +69,16 @@ class FootprintWizardParameterManager: ...@@ -66,14 +69,16 @@ class FootprintWizardParameterManager:
val = pcbnew.FromMils(default) val = pcbnew.FromMils(default)
elif unit == self.uNatural: elif unit == self.uNatural:
val = default val = default
elif unit == self.uString:
val = str(default)
elif unit == self.uBool: elif unit == self.uBool:
val = "True" if default else "False" #ugly stringing val = "True" if default else "False" # ugly stringing
else: else:
print "Warning: Unknown unit type: %s" % unit print "Warning: Unknown unit type: %s" % unit
return return
if unit in [self.uNatural, self.uBool]: if unit in [self.uNatural, self.uBool, self.uString]:
param = "*%s" % param #star prefix for natural param = "*%s" % param # star prefix for natural
if section not in self.parameters: if section not in self.parameters:
self.parameters[section] = {} self.parameters[section] = {}
...@@ -89,7 +94,8 @@ class FootprintWizardParameterManager: ...@@ -89,7 +94,8 @@ class FootprintWizardParameterManager:
for key, value in section.iteritems(): for key, value in section.iteritems():
unit = "" unit = ""
if (type(value) is int or type(value) is float) and not "*" in key: if ((type(value) is int or type(value) is float)
and not "*" in key):
unit = "mm" unit = "mm"
if "*" in key: if "*" in key:
...@@ -101,7 +107,7 @@ class FootprintWizardParameterManager: ...@@ -101,7 +107,7 @@ class FootprintWizardParameterManager:
def _ParametersHaveErrors(self): def _ParametersHaveErrors(self):
""" """
Return true if we discovered errors suring parameter processing Return true if we discovered errors during parameter processing
""" """
for name, section in self.parameter_errors.iteritems(): for name, section in self.parameter_errors.iteritems():
...@@ -124,8 +130,8 @@ class FootprintWizardParameterManager: ...@@ -124,8 +130,8 @@ class FootprintWizardParameterManager:
if not printed_section: if not printed_section:
print " %s:" % name print " %s:" % name
print " %s: %s (have %s)" % (key, value, print " %s: %s (have %s)" % (
self.parameters[name][key]) key, value, self.parameters[name][key])
def ProcessParameters(self): def ProcessParameters(self):
""" """
...@@ -134,14 +140,15 @@ class FootprintWizardParameterManager: ...@@ -134,14 +140,15 @@ class FootprintWizardParameterManager:
""" """
self.ClearErrors() self.ClearErrors()
self.CheckParameters(); self.CheckParameters()
if self._ParametersHaveErrors(): if self._ParametersHaveErrors():
print "Cannot build footprint: Parameters have errors:" print "Cannot build footprint: Parameters have errors:"
self._PrintParameterErrors() self._PrintParameterErrors()
return False return False
print "Building new %s footprint with the following parameters:" % self.name print ("Building new %s footprint with the following parameters:"
% self.name)
self._PrintParameterTable() self._PrintParameterTable()
return True return True
...@@ -150,29 +157,37 @@ class FootprintWizardParameterManager: ...@@ -150,29 +157,37 @@ class FootprintWizardParameterManager:
# PARAMETER CHECKERS # PARAMETER CHECKERS
################################################################# #################################################################
def CheckParamPositiveInt(self, section, param, min_value = 1, def CheckParamInt(self, section, param, min_value=1,
max_value = None, is_multiple_of = 1): max_value=None, is_multiple_of=1):
""" """
Make sure a parameter can be made into an int, and enforce Make sure a parameter can be made into an int, and enforce
limits if required limits if required
""" """
try: try:
self.parameters[section][param] = int(self.parameters[section][param]) self.parameters[section][param] = (
int(self.parameters[section][param]))
except ValueError: except ValueError:
self.parameter_errors[section][param] = "Must be a valid integer" self.parameter_errors[section][param] = (
"Must be a valid integer")
return return
if min_value is not None and (self.parameters[section][param] < min_value): if min_value is not None and (
self.parameter_errors[section][param] = "Must be greater than or equal to %d" % (min_value) self.parameters[section][param] < min_value):
self.parameter_errors[section][param] = (
"Must be greater than or equal to %d" % (min_value))
return return
if max_value is not None and (self.parameters[section][param] > min_value): if max_value is not None and (
self.parameter_errors[section][param] = "Must be less than or equal to %d" % (max_value) self.parameters[section][param] > min_value):
self.parameter_errors[section][param] = (
"Must be less than or equal to %d" % (max_value))
return return
if is_multiple_of > 1 and (self.parameters[section][param] % is_multiple_of) > 0: if is_multiple_of > 1 and (
self.parameter_errors[section][param] = "Must be a multiple of %d" % is_multiple_of self.parameters[section][param] % is_multiple_of) > 0:
self.parameter_errors[section][param] = (
"Must be a multiple of %d" % is_multiple_of)
return return
return return
...@@ -182,11 +197,13 @@ class FootprintWizardParameterManager: ...@@ -182,11 +197,13 @@ class FootprintWizardParameterManager:
Make sure a parameter looks like a boolean, convert to native Make sure a parameter looks like a boolean, convert to native
boolean type if so boolean type if so
""" """
if str(self.parameters[section][param]).lower() in ["true", "t", "y", "yes", "on", "1", "1.0"]: if str(self.parameters[section][param]).lower() in [
self.parameters[section][param] = True; "true", "t", "y", "yes", "on", "1", "1.0"]:
self.parameters[section][param] = True
return return
elif str(self.parameters[section][param]).lower() in ["false", "f", "n", "no", "off", "0", "0.0"]: elif str(self.parameters[section][param]).lower() in [
self.parameters[section][param] = False; "false", "f", "n", "no", "off", "0", "0.0"]:
self.parameters[section][param] = False
return return
self.parameter_errors[section][param] = "Must be boolean (true/false)" self.parameter_errors[section][param] = "Must be boolean (true/false)"
...@@ -216,16 +233,46 @@ class HelpfulFootprintWizardPlugin(pcbnew.FootprintWizardPlugin, ...@@ -216,16 +233,46 @@ class HelpfulFootprintWizardPlugin(pcbnew.FootprintWizardPlugin,
self.decription = self.GetDescription() self.decription = self.GetDescription()
self.image = self.GetImage() self.image = self.GetImage()
def GetReference(self): def GetValue(self):
raise NotImplementedError raise NotImplementedError
def GetValuePrefix(self): def GetReferencePrefix(self):
return "U" # footprints needing wizards of often ICs return "U" # footprints needing wizards of often ICs
def GetImage(self): def GetImage(self):
return "" return ""
def GetTextSize(self):
"""
IPC nominal
"""
return pcbnew.FromMM(1.2)
def GetTextThickness(self):
"""
Thicker than IPC guidelines (10% of text height = 0.12mm)
as 5 wires/mm is a common silk screen limitation
"""
return pcbnew.FromMM(0.2)
def SetModule3DModel(self):
"""
Set a 3D model for the module
Default is to do nothing, you need to implement this if you have
a model to set
FIXME: This doesn't seem to be enabled yet?
"""
pass
def BuildThisFootprint(self): def BuildThisFootprint(self):
"""
Draw the footprint.
This is specific to each footprint class, you need to implment
this to draw what you want
"""
raise NotImplementedError raise NotImplementedError
def BuildFootprint(self): def BuildFootprint(self):
...@@ -234,17 +281,26 @@ class HelpfulFootprintWizardPlugin(pcbnew.FootprintWizardPlugin, ...@@ -234,17 +281,26 @@ class HelpfulFootprintWizardPlugin(pcbnew.FootprintWizardPlugin,
the implmenting class the implmenting class
""" """
self.module = pcbnew.MODULE(None) # create a new module
# do it first, so if we return early, we don't segfault KiCad
if not self.ProcessParameters(): if not self.ProcessParameters():
return return
self.module = pcbnew.MODULE(None) # create a new module self.draw = FootprintWizardDrawingAids.FootprintWizardDrawingAids(
self.module)
self.draw = FootprintWizardDrawingAids.FootprintWizardDrawingAids(self.module)
self.module.SetReference(self.GetReference()) self.module.SetValue(self.GetValue())
self.module.SetValue("%s**" % self.GetValuePrefix()) self.module.SetReference("%s**" % self.GetReferencePrefix())
fpid = pcbnew.FPID(self.module.GetReference()) #the name in library fpid = pcbnew.FPID(self.module.GetValue()) # the name in library
self.module.SetFPID( fpid ) self.module.SetFPID(fpid)
self.BuildThisFootprint() # implementer's build function self.BuildThisFootprint() # implementer's build function
self.SetModule3DModel() # add a 3d module if specified
thick = self.GetTextThickness()
self.module.Reference().SetThickness(thick)
self.module.Value().SetThickness(thick)
# PadArray.py
#
# Copyright 2014 john <john@johndev>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
# MA 02110-1301, USA.
#
#
from __future__ import division
import math
import pcbnew import pcbnew
class PadMaker: class PadMaker:
...@@ -9,7 +32,7 @@ class PadMaker: ...@@ -9,7 +32,7 @@ class PadMaker:
def __init__(self, module): def __init__(self, module):
self.module = module self.module = module
def THPad(self, w, l, drill, shape = pcbnew.PAD_OVAL): def THPad(self, w, l, drill, shape=pcbnew.PAD_OVAL):
pad = pcbnew.D_PAD(self.module) pad = pcbnew.D_PAD(self.module)
pad.SetSize(pcbnew.wxSize(l, w)) pad.SetSize(pcbnew.wxSize(l, w))
...@@ -22,7 +45,23 @@ class PadMaker: ...@@ -22,7 +45,23 @@ class PadMaker:
return pad return pad
def SMDPad(self, w, l, shape = pcbnew.PAD_RECT): def THRoundPad(self, size, drill):
pad = self.THPad(size, size, drill, shape=pcbnew.PAD_CIRCLE)
return pad
def NPTHRoundPad(self, drill):
pad = pcbnew.D_PAD(self.module)
pad.SetSize(pcbnew.wxSize(drill, drill))
pad.SetShape(pcbnew.PAD_CIRCLE)
pad.SetAttribute(pcbnew.PAD_HOLE_NOT_PLATED)
pad.SetLayerSet(pad.UnplatedHoleMask())
pad.SetDrillSize(pcbnew.wxSize(drill, drill))
return pad
def SMDPad(self, w, l, shape=pcbnew.PAD_RECT):
pad = pcbnew.D_PAD(self.module) pad = pcbnew.D_PAD(self.module)
pad.SetSize(pcbnew.wxSize(l, w)) pad.SetSize(pcbnew.wxSize(l, w))
...@@ -34,23 +73,65 @@ class PadMaker: ...@@ -34,23 +73,65 @@ class PadMaker:
return pad return pad
def SMTRoundPad(self, size): def SMTRoundPad(self, size):
pad = self.SMDPad(size, size, shape = pcbnew.PAD_CIRCLE) pad = self.SMDPad(size, size, shape=pcbnew.PAD_CIRCLE)
return pad return pad
class PadArray: class PadArray:
def __init__(self): def __init__(self):
self.firstPad = 1; self.firstPadNum = 1
self.pinNames = None
self.firstPad = None
def SetPinNames(self, pinNames):
"""
Set a name for all the pins
"""
self.pinNames = pinNames
def SetFirstPadType(self, firstPad):
self.firstPad = firstPad
def SetFirstPadInArray(self, fpNum): def SetFirstPadInArray(self, fpNum):
self.firstPad = fpNum self.firstPadNum = fpNum
def AddPad(self, pad): def AddPad(self, pad):
self.pad.GetParent().Add(pad) self.pad.GetParent().Add(pad)
def GetPad(self, is_first_pad, pos):
if (self.firstPad and is_first_pad):
pad = self.firstPad
else:
pad = self.pad
# create a new pad with same characteristics
pad = pad.Duplicate()
pad.SetPos0(pos)
pad.SetPosition(pos)
return pad
def GetName(self, *args, **kwargs):
if self.pinNames is None:
return self.NamingFunction(*args, **kwargs)
return self.pinNames
def NamingFunction(self, *args, **kwargs):
"""
Implement this as needed for each array type
"""
raise NotImplementedError;
class PadGridArray(PadArray): class PadGridArray(PadArray):
def __init__(self, pad, nx, ny, px, py, pin1Pos): def __init__(self, pad, nx, ny, px, py, centre=pcbnew.wxPoint(0, 0)):
PadArray.__init__(self)
# this pad is more of a "context", we will use it as a source of # this pad is more of a "context", we will use it as a source of
# pad data, but not actually add it # pad data, but not actually add it
self.pad = pad self.pad = pad
...@@ -58,78 +139,121 @@ class PadGridArray(PadArray): ...@@ -58,78 +139,121 @@ class PadGridArray(PadArray):
self.ny = int(ny) self.ny = int(ny)
self.px = px self.px = px
self.py = py self.py = py
self.pin1Pos = pin1Pos self.centre = centre
# handy utility function 1 - A, 2 - B, 26 - AA, etc # handy utility function 1 - A, 2 - B, 26 - AA, etc
# aIndex = 0 for 0 - A # aIndex = 0 for 0 - A
# alphabet = set of allowable chars if not A-Z, eg ABCDEFGHJKLMNPRTUVWY for BGA # alphabet = set of allowable chars if not A-Z,
def AlphaNameFromNumber(self, n, aIndex = 1, alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"): # eg ABCDEFGHJKLMNPRTUVWY for BGA
def AlphaNameFromNumber(self, n, aIndex=1,
alphabet="ABCDEFGHIJKLMNOPQRSTUVWXYZ"):
div, mod = divmod(n - aIndex, len(alphabet)) div, mod = divmod(n - aIndex, len(alphabet))
alpha = alphabet[mod] alpha = alphabet[mod]
if div > 0: if div > 0:
return self.AlphaNameFromNumber(div, aIndex, alphabet) + alpha; return self.AlphaNameFromNumber(div, aIndex, alphabet) + alpha
return alpha; return alpha
# right to left, top to bottom # right to left, top to bottom
def NamingFunction(self, x, y): def NamingFunction(self, x, y):
return self.firstPad + (self.nx * y + x) return self.firstPadNum + (self.nx * y + x)
#relocate the pad and add it as many times as we need #relocate the pad and add it as many times as we need
def AddPadsToModule(self): def AddPadsToModule(self, dc):
pin1posX = self.centre.x - self.px * (self.nx - 1) / 2
pin1posY = self.centre.y - self.py * (self.ny - 1) / 2
for x in range(0, self.nx): for x in range(0, self.nx):
for y in range(self.ny):
posX = self.pin1Pos.x + (self.px * x)
posY = self.pin1Pos.y + (self.py * y)
pos = pcbnew.wxPoint(posX, posY) posX = pin1posX + (x * self.px)
# create a new pad with same characteristics for y in range(self.ny):
pad = self.pad.Duplicate() posY = pin1posY + (self.py * y)
pad.SetPos0(pos) pos = dc.TransformPoint(posX, posY)
pad.SetPosition(pos)
pad = self.GetPad(x == 0 and y == 0, pos)
pad.SetPadName(str(self.NamingFunction(x,y))) pad.SetPadName(self.GetName(x,y))
self.AddPad(pad) self.AddPad(pad)
class PadLineArray(PadGridArray): class PadLineArray(PadGridArray):
def __init__(self, pad, n, pitch, isVertical, pin1Pos): def __init__(self, pad, n, pitch, isVertical,
centre=pcbnew.wxPoint(0, 0)):
if isVertical: if isVertical:
PadGridArray.__init__(self, pad, 1, n, 0, pitch, pin1Pos) PadGridArray.__init__(self, pad, 1, n, 0, pitch, centre)
else: else:
PadGridArray.__init__(self, pad, n, 1, pitch, 0, pin1Pos) PadGridArray.__init__(self, pad, n, 1, pitch, 0, centre)
class RectPadArray(PadArray): class PadCircleArray(PadArray):
def __init__(self, nx, ny, pitch, xpitch, ypitch, pin1Pos): def __init__(self, pad, n, r, angle_offset=0, centre=pcbnew.wxPoint(0, 0),
clockwise=True):
#left row PadArray.__init__(self)
pin1Pos = pcbnew.wxPoint(-h_pitch / 2, -row_len / 2) # this pad is more of a "context", we will use it as a source of
array = PadLineArray(h_pad, pads_per_row, pad_pitch, True, pin1Pos) # pad data, but not actually add it
array.SetFirstPadInArray(1) self.pad = pad
array.AddPadsToModule() self.n = int(n)
self.r = r
#bottom row self.angle_offset = angle_offset
pin1Pos = pcbnew.wxPoint(-row_len / 2, v_pitch / 2) self.centre = centre
array = PA.PadLineArray(v_pad, pads_per_row, pad_pitch, False, pin1Pos) self.clockwise = clockwise
array.SetFirstPadInArray(pads_per_row + 1)
array.AddPadsToModule() # around the circle, CW or CCW according to the flag
def NamingFunction(self, n):
#right row return str(self.firstPadNum + n)
pin1Pos = pcbnew.wxPoint(h_pitch / 2, row_len / 2)
array = PadLineArray(h_pad, pads_per_row, -pad_pitch, True, pin1Pos) #relocate the pad and add it as many times as we need
array.SetFirstPadInArray(2*pads_per_row + 1) def AddPadsToModule(self, dc):
array.AddPadsToModule()
for pin in range(0, self.n):
#top row
pin1Pos = pcbnew.wxPoint(row_len / 2, -v_pitch / 2) angle = self.angle_offset + (360 / self.n) * pin
array = PadLineArray(v_pad, pads_per_row, -pad_pitch, False, pin1Pos)
array.SetFirstPadInArray(3*pads_per_row + 1) if not self.clockwise:
array.AddPadsToModule() angle = -angle
pos_x = math.sin(angle * math.pi / 180) * self.r
pos_y = -math.cos(angle * math.pi / 180) * self.r
pos = dc.TransformPoint(pos_x, pos_y)
pad = self.GetPad(pin == 0, pos)
pad.SetPadName(self.GetName(pin))
self.AddPad(pad)
class PadCustomArray(PadArray):
"""
Layout pads according to a custom array of [x,y] data
"""
def __init__(self, pad, array):
PadArray.__init__(self)
self.pad = pad
self.array = array
def NamingFunction(self, n):
return str(self.firstPadNum + n)
#relocate the pad and add it as many times as we need
def AddPadsToModule(self, dc):
for i in range(len(self.array)):
pos = dc.TransformPoint(self.array[i][0], self.array[i][1])
pad = self.GetPad(i == 0, pos)
pad.SetPadName(self.GetName(i))
self.AddPad(pad)
...@@ -23,8 +23,10 @@ import PadArray as PA ...@@ -23,8 +23,10 @@ import PadArray as PA
class BGAPadGridArray(PA.PadGridArray): class BGAPadGridArray(PA.PadGridArray):
def NamingFunction(self, x, y): def NamingFunction(self, n_x, n_y):
return "%s%d" % (self.AlphaNameFromNumber(y + 1, alphabet="ABCDEFGHJKLMNPRTUVWY"), x + 1) return "%s%d" % (
self.AlphaNameFromNumber(n_y + 1, alphabet="ABCDEFGHJKLMNPRTUVWY"),
n_x + 1)
class BGAWizard(HFPW.HelpfulFootprintWizardPlugin): class BGAWizard(HFPW.HelpfulFootprintWizardPlugin):
...@@ -46,21 +48,19 @@ class BGAWizard(HFPW.HelpfulFootprintWizardPlugin): ...@@ -46,21 +48,19 @@ class BGAWizard(HFPW.HelpfulFootprintWizardPlugin):
def CheckParameters(self): def CheckParameters(self):
self.CheckParamPositiveInt("Pads", "*row count") self.CheckParamInt("Pads", "*row count")
self.CheckParamPositiveInt("Pads", "*column count") self.CheckParamInt("Pads", "*column count")
def GetValue(self):
def GetReference(self): pins = (self.parameters["Pads"]["*row count"]
* self.parameters["Pads"]["*column count"])
pins = self.parameters["Pads"]["*row count"] * self.parameters["Pads"]["*column count"]
return "BGA %d" % pins return "BGA %d" % pins
def GetReferencePrefix(self):
def GetValuePrefix(self):
return "U" return "U"
def BuildThisFootprint(self): def BuildThisFootprint(self):
pads = self.parameters["Pads"] pads = self.parameters["Pads"]
...@@ -76,23 +76,24 @@ class BGAWizard(HFPW.HelpfulFootprintWizardPlugin): ...@@ -76,23 +76,24 @@ class BGAWizard(HFPW.HelpfulFootprintWizardPlugin):
# add in the pads # add in the pads
pad = PA.PadMaker(self.module).SMTRoundPad(pads["pad size"]) pad = PA.PadMaker(self.module).SMTRoundPad(pads["pad size"])
pin1Pos = pcbnew.wxPoint(-((cols - 1) * pad_pitch) / 2, pin1_pos = pcbnew.wxPoint(-((cols - 1) * pad_pitch) / 2,
-((rows - 1) * pad_pitch) / 2) -((rows - 1) * pad_pitch) / 2)
array = BGAPadGridArray(pad, cols, rows, pad_pitch, pad_pitch, pin1Pos) array = BGAPadGridArray(pad, cols, rows, pad_pitch, pad_pitch)
array.AddPadsToModule() array.AddPadsToModule(self.draw)
#box #box
ssX = -pin1Pos.x + pads["outline x margin"] ssx = -pin1_pos.x + pads["outline x margin"]
ssY = -pin1Pos.y + pads["outline y margin"] ssy = -pin1_pos.y + pads["outline y margin"]
self.draw.BoxWithDiagonalAtCorner(0, 0, ssX*2, ssY*2, pads["outline x margin"]) self.draw.BoxWithDiagonalAtCorner(0, 0, ssx*2, ssy*2,
pads["outline x margin"])
#reference and value #reference and value
textSize = pcbnew.FromMM(0.8) text_size = pcbnew.FromMM(1.2) # IPC nominal
self.draw.Value(0, - ssY - textSize, textSize) self.draw.Value(0, - ssy - text_size, text_size)
self.draw.Reference(0, ssY + textSize, textSize) self.draw.Reference(0, ssy + text_size, text_size)
BGAWizard().register() BGAWizard().register()
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
# MA 02110-1301, USA.
#
from __future__ import division
import math
import pcbnew
import HelpfulFootprintWizardPlugin as HFPW
import PadArray as PA
class circular_array_wizard(HFPW.HelpfulFootprintWizardPlugin):
def GetName(self):
return "Circular Array"
def GetDescription(self):
return "Circular array of pads"
def GenerateParameterList(self):
self.AddParam("Pads", "n", self.uNatural, 6)
self.AddParam("Pads", "pad width", self.uMM, 1.5)
self.AddParam("Pads", "drill", self.uMM, 1)
self.AddParam("Pads", "circle diameter", self.uMM, 5)
self.AddParam("Pads", "first pad angle", self.uNatural, 0)
self.AddParam("Pads", "number clockwise", self.uBool, True)
self.AddParam("Pads", "first pad number", self.uNatural, 1)
def CheckParameters(self):
self.CheckParamInt("Pads", "*n")
self.CheckParamInt("Pads", "*first pad number")
self.CheckParamBool("Pads", "*number clockwise")
def GetValue(self):
return "A"
def GetReference(self):
return ""
def BuildThisFootprint(self):
prm = self.parameters['Pads']
pad_size = prm['pad width']
pad = PA.PadMaker(self.module).THPad(
prm['pad width'],
prm['pad width'],
prm['drill'])
array = PA.PadCircleArray(
pad, prm['*n'], prm['circle diameter'] / 2,
angle_offset=prm["*first pad angle"],
centre=pcbnew.wxPoint(0, 0),
clockwise=prm["*number clockwise"])
array.SetFirstPadInArray(prm["*first pad number"])
array.AddPadsToModule(self.draw)
circular_array_wizard().register()
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
# MA 02110-1301, USA.
#
from __future__ import division from __future__ import division
import pcbnew import pcbnew
import HelpfulFootprintWizardPlugin import HelpfulFootprintWizardPlugin
import PadArray as PA import PadArray as PA
class QFPWizard(HelpfulFootprintWizardPlugin.HelpfulFootprintWizardPlugin): class QFPWizard(HelpfulFootprintWizardPlugin.HelpfulFootprintWizardPlugin):
def GetName(self): def GetName(self):
...@@ -26,10 +43,10 @@ class QFPWizard(HelpfulFootprintWizardPlugin.HelpfulFootprintWizardPlugin): ...@@ -26,10 +43,10 @@ class QFPWizard(HelpfulFootprintWizardPlugin.HelpfulFootprintWizardPlugin):
def CheckParameters(self): def CheckParameters(self):
self.CheckParamPositiveInt("Pads", "*n", is_multiple_of = 4) self.CheckParamInt("Pads", "*n", is_multiple_of=4)
self.CheckParamBool("Pads", "*oval") self.CheckParamBool("Pads", "*oval")
def GetReference(self): def GetValue(self):
return "QFP %d" % self.parameters["Pads"]["*n"] return "QFP %d" % self.parameters["Pads"]["*n"]
def BuildThisFootprint(self): def BuildThisFootprint(self):
...@@ -49,44 +66,58 @@ class QFPWizard(HelpfulFootprintWizardPlugin.HelpfulFootprintWizardPlugin): ...@@ -49,44 +66,58 @@ class QFPWizard(HelpfulFootprintWizardPlugin.HelpfulFootprintWizardPlugin):
pad_shape = pcbnew.PAD_OVAL if pads["*oval"] else pcbnew.PAD_RECT pad_shape = pcbnew.PAD_OVAL if pads["*oval"] else pcbnew.PAD_RECT
h_pad = PA.PadMaker(self.module).SMDPad(pad_width, pad_length, shape = pad_shape) h_pad = PA.PadMaker(self.module).SMDPad(
v_pad = PA.PadMaker(self.module).SMDPad(pad_length, pad_width, shape = pad_shape) pad_width, pad_length, shape=pad_shape)
v_pad = PA.PadMaker(self.module).SMDPad(
pad_length, pad_width, shape=pad_shape)
#left row #left row
pin1Pos = pcbnew.wxPoint(-h_pitch / 2, -row_len / 2) pin1Pos = pcbnew.wxPoint(-h_pitch / 2, 0)
array = PA.PadLineArray(h_pad, pads_per_row, pad_pitch, True, pin1Pos) array = PA.PadLineArray(h_pad, pads_per_row, pad_pitch, True,
pin1Pos)
array.SetFirstPadInArray(1) array.SetFirstPadInArray(1)
array.AddPadsToModule() array.AddPadsToModule(self.draw)
#bottom row #bottom row
pin1Pos = pcbnew.wxPoint(-row_len / 2, v_pitch / 2) pin1Pos = pcbnew.wxPoint(0, v_pitch / 2)
array = PA.PadLineArray(v_pad, pads_per_row, pad_pitch, False, pin1Pos) array = PA.PadLineArray(v_pad, pads_per_row, pad_pitch, False,
pin1Pos)
array.SetFirstPadInArray(pads_per_row + 1) array.SetFirstPadInArray(pads_per_row + 1)
array.AddPadsToModule() array.AddPadsToModule(self.draw)
#right row #right row
pin1Pos = pcbnew.wxPoint(h_pitch / 2, row_len / 2) pin1Pos = pcbnew.wxPoint(h_pitch / 2, 0)
array = PA.PadLineArray(h_pad, pads_per_row, -pad_pitch, True, pin1Pos) array = PA.PadLineArray(h_pad, pads_per_row, -pad_pitch, True,
pin1Pos)
array.SetFirstPadInArray(2*pads_per_row + 1) array.SetFirstPadInArray(2*pads_per_row + 1)
array.AddPadsToModule() array.AddPadsToModule(self.draw)
#top row #top row
pin1Pos = pcbnew.wxPoint(row_len / 2, -v_pitch / 2) pin1Pos = pcbnew.wxPoint(0, -v_pitch / 2)
array = PA.PadLineArray(v_pad, pads_per_row, -pad_pitch, False, pin1Pos) array = PA.PadLineArray(v_pad, pads_per_row, -pad_pitch, False,
pin1Pos)
array.SetFirstPadInArray(3*pads_per_row + 1) array.SetFirstPadInArray(3*pads_per_row + 1)
array.AddPadsToModule() array.AddPadsToModule(self.draw)
limX = pads["package width"] / 2 lim_x = pads["package width"] / 2
limY = pads["package height"] / 2 lim_y = pads["package height"] / 2
inner = (row_len / 2) + pad_pitch inner = (row_len / 2) + pad_pitch
#top left - diagonal #top left - diagonal
self.draw.Line(-limX, -inner, -inner, -limY) self.draw.Line(-lim_x, -inner, -inner, -lim_y)
# top right # top right
self.draw.Polyline([(inner, -limY), (limX, -limY), (limX, -inner)]) self.draw.Polyline([(inner, -lim_y), (lim_x, -lim_y), (lim_x, -inner)])
# bottom left # bottom left
self.draw.Polyline([(-inner, limY), (-limX, limY), (-limX, inner)]) self.draw.Polyline([(-inner, lim_y), (-lim_x, lim_y), (-lim_x, inner)])
# bottom right # bottom right
self.draw.Polyline([(inner, limY), (limX, limY), (limX, inner)]) self.draw.Polyline([(inner, lim_y), (lim_x, lim_y), (lim_x, inner)])
#reference and value
text_size = pcbnew.FromMM(1.2) # IPC nominal
text_offset = v_pitch / 2 + text_size + pad_length / 2
self.draw.Value(0, -text_offset, text_size)
self.draw.Reference(0, text_offset, text_size)
QFPWizard().register() QFPWizard().register()
...@@ -25,9 +25,10 @@ class RowedGridArray(PA.PadGridArray): ...@@ -25,9 +25,10 @@ class RowedGridArray(PA.PadGridArray):
def NamingFunction(self, x, y): def NamingFunction(self, x, y):
if (x % 2) == 0: # even row, count up if (x % 2) == 0: # even row, count up
return (x * self.ny) + y + 1; return (x * self.ny) + y + 1
else: # odd row, count down else: # odd row, count down
return (self.ny * (x + 1)) - y; return (self.ny * (x + 1)) - y
class RowedFootprint(HFPW.HelpfulFootprintWizardPlugin): class RowedFootprint(HFPW.HelpfulFootprintWizardPlugin):
...@@ -39,9 +40,13 @@ class RowedFootprint(HFPW.HelpfulFootprintWizardPlugin): ...@@ -39,9 +40,13 @@ class RowedFootprint(HFPW.HelpfulFootprintWizardPlugin):
self.AddParam("Pads", "row count", self.uNatural, 2) self.AddParam("Pads", "row count", self.uNatural, 2)
def CheckParameters(self): def CheckParameters(self):
self.CheckParamPositiveInt("Pads", "*row count") self.CheckParamInt("Pads", "*row count")
self.CheckParamPositiveInt("Pads", "*n", is_multiple_of = self.parameters["Pads"]["*row count"]) self.CheckParamInt(
self.CheckParamBool("Pads", "*silk screen inside") #can do this internally to parameter manager? "Pads", "*n",
is_multiple_of=self.parameters["Pads"]["*row count"])
# can do this internally to parameter manager?
self.CheckParamBool("Pads", "*silk screen inside")
def BuildThisFootprint(self): def BuildThisFootprint(self):
...@@ -57,39 +62,40 @@ class RowedFootprint(HFPW.HelpfulFootprintWizardPlugin): ...@@ -57,39 +62,40 @@ class RowedFootprint(HFPW.HelpfulFootprintWizardPlugin):
pads_per_row = num_pads // num_rows pads_per_row = num_pads // num_rows
row_length = pad_pitch * (pads_per_row - 1) #fenceposts row_length = pad_pitch * (pads_per_row - 1) # fenceposts
# add in the pads # add in the pads
pad = self.GetPad() pad = self.GetPad()
pin1Pos = pcbnew.wxPoint(-((num_rows - 1) * row_pitch) / 2, -row_length / 2) pin1_pos = pcbnew.wxPoint(
-((num_rows - 1) * row_pitch) / 2,
-row_length / 2)
array = RowedGridArray(pad, num_rows, pads_per_row, row_pitch, pad_pitch, pin1Pos) array = RowedGridArray(pad, num_rows, pads_per_row, row_pitch,
array.AddPadsToModule() pad_pitch)
array.AddPadsToModule(self.draw)
# draw the Silk Screen # draw the Silk Screen
pad_length = pads["pad length"] pad_length = pads["pad length"]
pad_width = pads["pad width"] pad_width = pads["pad width"]
ssXOffset = -pad_length / 2 - pads["outline x margin"] ssx_offset = -pad_length / 2 - pads["outline x margin"]
ssYOffset = -pad_width / 2 - pads["outline y margin"] ssy_offset = -pad_width / 2 - pads["outline y margin"]
if pads["*silk screen inside"]: if pads["*silk screen inside"]:
ssXOffset *= -1 ssx_offset *= -1
ssX = -pin1Pos.x - ssXOffset
ssY = -pin1Pos.y - ssYOffset
ssx = -pin1_pos.x - ssx_offset
ssy = -pin1_pos.y - ssy_offset
self.DrawBox(ssX, ssY) self.DrawBox(ssx, ssy)
#reference and value #reference and value
textSize = pcbnew.FromMM(0.8) text_size = pcbnew.FromMM(1.2) # IPC nominal
self.draw.Value(0, - ssY - textSize, textSize) self.draw.Value(0, - ssy - text_size, text_size)
self.draw.Reference(0, ssY + textSize, textSize) self.draw.Reference(0, ssy + text_size, text_size)
class SDIPWizard(RowedFootprint): class SDIPWizard(RowedFootprint):
...@@ -111,7 +117,7 @@ class SDIPWizard(RowedFootprint): ...@@ -111,7 +117,7 @@ class SDIPWizard(RowedFootprint):
self.AddParam("Pads", "outline x margin", self.uMM, 0.5) self.AddParam("Pads", "outline x margin", self.uMM, 0.5)
self.AddParam("Pads", "outline y margin", self.uMM, 1) self.AddParam("Pads", "outline y margin", self.uMM, 1)
def GetReference(self): def GetValue(self):
rows = self.parameters["Pads"]["*row count"] rows = self.parameters["Pads"]["*row count"]
...@@ -128,9 +134,10 @@ class SDIPWizard(RowedFootprint): ...@@ -128,9 +134,10 @@ class SDIPWizard(RowedFootprint):
pad_length = self.parameters["Pads"]["pad length"] pad_length = self.parameters["Pads"]["pad length"]
pad_width = self.parameters["Pads"]["pad width"] pad_width = self.parameters["Pads"]["pad width"]
drill = self.parameters["Pads"]["drill size"] drill = self.parameters["Pads"]["drill size"]
return PA.PadMaker(self.module).THPad(pad_width, pad_length, drill, shape = pcbnew.PAD_OVAL) return PA.PadMaker(self.module).THPad(
pad_width, pad_length, drill, shape=pcbnew.PAD_OVAL)
def DrawBox(self, ssX, ssY): def DrawBox(self, ssx, ssy):
if self.parameters["Pads"]["*row count"] == 2: if self.parameters["Pads"]["*row count"] == 2:
...@@ -144,18 +151,19 @@ class SDIPWizard(RowedFootprint): ...@@ -144,18 +151,19 @@ class SDIPWizard(RowedFootprint):
notchWidth = pcbnew.FromMM(3) notchWidth = pcbnew.FromMM(3)
notchHeight = pcbnew.FromMM(1) notchHeight = pcbnew.FromMM(1)
self.draw.NotchedBox(0, 0, ssX*2, ssY*2, notchWidth, notchHeight) self.draw.NotchedBox(0, 0, ssx*2, ssy*2, notchWidth, notchHeight)
else: else:
# ----------------- # -----------------
# |1|2 3 4 5 6 7 8| # |1|2 3 4 5 6 7 8|
# ----------------- # -----------------
self.draw.Box(ssX*2, ssY*2) self.draw.Box(0, 0, ssx*2, ssy*2)
#line between pin1 and pin2 #line between pin1 and pin2
pad_pitch = self.parameters["Pads"]["pad pitch"]; pad_pitch = self.parameters["Pads"]["pad pitch"]
self.draw.HLine(-ssX, pin1Pos.y + pad_pitch/2, ssX * 2) line_y = - (self.parameters["Pads"]["*n"] - 2) * pad_pitch / 2
self.draw.HLine(-ssx, line_y, ssx * 2)
return ssX, ssY return ssx, ssy
SDIPWizard().register() SDIPWizard().register()
...@@ -168,7 +176,7 @@ class SOICWizard(RowedFootprint): ...@@ -168,7 +176,7 @@ class SOICWizard(RowedFootprint):
def GetDescription(self): def GetDescription(self):
return "SOIC, MSOP, SSOP, TSSOP, etc, footprint wizard" return "SOIC, MSOP, SSOP, TSSOP, etc, footprint wizard"
def GetReference(self): def GetValue(self):
return "%s %d" % ("SOIC", self.parameters["Pads"]["*n"]) return "%s %d" % ("SOIC", self.parameters["Pads"]["*n"])
def GenerateParameterList(self): def GenerateParameterList(self):
...@@ -186,15 +194,16 @@ class SOICWizard(RowedFootprint): ...@@ -186,15 +194,16 @@ class SOICWizard(RowedFootprint):
def GetPad(self): def GetPad(self):
pad_length = self.parameters["Pads"]["pad length"] pad_length = self.parameters["Pads"]["pad length"]
pad_width = self.parameters["Pads"]["pad width"] pad_width = self.parameters["Pads"]["pad width"]
return PA.PadMaker(self.module).SMDPad(pad_width, pad_length, shape = pcbnew.PAD_RECT) return PA.PadMaker(self.module).SMDPad(
pad_width, pad_length, shape=pcbnew.PAD_RECT)
def DrawBox(self, ssX, ssY): def DrawBox(self, ssx, ssy):
# ---------- # ----------
# |8 7 6 5 | # |8 7 6 5 |
# |1 2 3 4 | # |1 2 3 4 |
# \--------- # \---------
self.draw.BoxWithDiagonalAtCorner(0, 0, ssX*2, ssY*2, pcbnew.FromMM(1)) self.draw.BoxWithDiagonalAtCorner(0, 0, ssx*2, ssy*2, pcbnew.FromMM(1))
SOICWizard().register() SOICWizard().register()
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment