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):
pad.SetSize(size)
pad.SetShape(PAD_RECT)
pad.SetAttribute(PAD_SMD)
pad.SetLayerSet( pad.StandardMask() )
pad.SetLayerSet( pad.SMDMask() )
pad.SetPos0(pos)
pad.SetPosition(pos)
pad.SetPadName(name)
......
......@@ -15,8 +15,10 @@
#
import pcbnew
import math
import FootprintWizardDrawingAids
class FootprintWizardParameterManager:
"""
Functions for helpfully managing parameters to a KiCAD Footprint
......@@ -50,8 +52,9 @@ class FootprintWizardParameterManager:
uMils = 2
uNatural = 3
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.
......@@ -66,14 +69,16 @@ class FootprintWizardParameterManager:
val = pcbnew.FromMils(default)
elif unit == self.uNatural:
val = default
elif unit == self.uString:
val = str(default)
elif unit == self.uBool:
val = "True" if default else "False" #ugly stringing
val = "True" if default else "False" # ugly stringing
else:
print "Warning: Unknown unit type: %s" % unit
return
if unit in [self.uNatural, self.uBool]:
param = "*%s" % param #star prefix for natural
if unit in [self.uNatural, self.uBool, self.uString]:
param = "*%s" % param # star prefix for natural
if section not in self.parameters:
self.parameters[section] = {}
......@@ -89,7 +94,8 @@ class FootprintWizardParameterManager:
for key, value in section.iteritems():
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"
if "*" in key:
......@@ -101,7 +107,7 @@ class FootprintWizardParameterManager:
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():
......@@ -124,8 +130,8 @@ class FootprintWizardParameterManager:
if not printed_section:
print " %s:" % name
print " %s: %s (have %s)" % (key, value,
self.parameters[name][key])
print " %s: %s (have %s)" % (
key, value, self.parameters[name][key])
def ProcessParameters(self):
"""
......@@ -134,14 +140,15 @@ class FootprintWizardParameterManager:
"""
self.ClearErrors()
self.CheckParameters();
self.CheckParameters()
if self._ParametersHaveErrors():
print "Cannot build footprint: Parameters have errors:"
self._PrintParameterErrors()
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()
return True
......@@ -150,29 +157,37 @@ class FootprintWizardParameterManager:
# PARAMETER CHECKERS
#################################################################
def CheckParamPositiveInt(self, section, param, min_value = 1,
max_value = None, is_multiple_of = 1):
def CheckParamInt(self, section, param, min_value=1,
max_value=None, is_multiple_of=1):
"""
Make sure a parameter can be made into an int, and enforce
limits if required
"""
try:
self.parameters[section][param] = int(self.parameters[section][param])
self.parameters[section][param] = (
int(self.parameters[section][param]))
except ValueError:
self.parameter_errors[section][param] = "Must be a valid integer"
self.parameter_errors[section][param] = (
"Must be a valid integer")
return
if min_value is not None and (self.parameters[section][param] < min_value):
self.parameter_errors[section][param] = "Must be greater than or equal to %d" % (min_value)
if min_value is not None and (
self.parameters[section][param] < min_value):
self.parameter_errors[section][param] = (
"Must be greater than or equal to %d" % (min_value))
return
if max_value is not None and (self.parameters[section][param] > min_value):
self.parameter_errors[section][param] = "Must be less than or equal to %d" % (max_value)
if max_value is not None and (
self.parameters[section][param] > min_value):
self.parameter_errors[section][param] = (
"Must be less than or equal to %d" % (max_value))
return
if is_multiple_of > 1 and (self.parameters[section][param] % is_multiple_of) > 0:
self.parameter_errors[section][param] = "Must be a multiple of %d" % is_multiple_of
if is_multiple_of > 1 and (
self.parameters[section][param] % is_multiple_of) > 0:
self.parameter_errors[section][param] = (
"Must be a multiple of %d" % is_multiple_of)
return
return
......@@ -182,11 +197,13 @@ class FootprintWizardParameterManager:
Make sure a parameter looks like a boolean, convert to native
boolean type if so
"""
if str(self.parameters[section][param]).lower() in ["true", "t", "y", "yes", "on", "1", "1.0"]:
self.parameters[section][param] = True;
if str(self.parameters[section][param]).lower() in [
"true", "t", "y", "yes", "on", "1", "1.0"]:
self.parameters[section][param] = True
return
elif str(self.parameters[section][param]).lower() in ["false", "f", "n", "no", "off", "0", "0.0"]:
self.parameters[section][param] = False;
elif str(self.parameters[section][param]).lower() in [
"false", "f", "n", "no", "off", "0", "0.0"]:
self.parameters[section][param] = False
return
self.parameter_errors[section][param] = "Must be boolean (true/false)"
......@@ -194,7 +211,7 @@ class FootprintWizardParameterManager:
class HelpfulFootprintWizardPlugin(pcbnew.FootprintWizardPlugin,
FootprintWizardParameterManager):
FootprintWizardParameterManager):
"""
A class to simplify many aspects of footprint creation, leaving only
the foot-print specific routines to the wizards themselves
......@@ -216,16 +233,46 @@ class HelpfulFootprintWizardPlugin(pcbnew.FootprintWizardPlugin,
self.decription = self.GetDescription()
self.image = self.GetImage()
def GetReference(self):
def GetValue(self):
raise NotImplementedError
def GetValuePrefix(self):
return "U" # footprints needing wizards of often ICs
def GetReferencePrefix(self):
return "U" # footprints needing wizards of often ICs
def GetImage(self):
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):
"""
Draw the footprint.
This is specific to each footprint class, you need to implment
this to draw what you want
"""
raise NotImplementedError
def BuildFootprint(self):
......@@ -234,17 +281,26 @@ class HelpfulFootprintWizardPlugin(pcbnew.FootprintWizardPlugin,
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():
return
self.module = pcbnew.MODULE(None) # create a new module
self.draw = FootprintWizardDrawingAids.FootprintWizardDrawingAids(
self.module)
self.module.SetValue(self.GetValue())
self.module.SetReference("%s**" % self.GetReferencePrefix())
fpid = pcbnew.FPID(self.module.GetValue()) # the name in library
self.module.SetFPID(fpid)
self.draw = FootprintWizardDrawingAids.FootprintWizardDrawingAids(self.module)
self.BuildThisFootprint() # implementer's build function
self.module.SetReference(self.GetReference())
self.module.SetValue("%s**" % self.GetValuePrefix())
self.SetModule3DModel() # add a 3d module if specified
fpid = pcbnew.FPID(self.module.GetReference()) #the name in library
self.module.SetFPID( fpid )
thick = self.GetTextThickness()
self.BuildThisFootprint() # implementer's build function
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
class PadMaker:
......@@ -9,7 +32,7 @@ class PadMaker:
def __init__(self, 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.SetSize(pcbnew.wxSize(l, w))
......@@ -22,7 +45,23 @@ class PadMaker:
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.SetSize(pcbnew.wxSize(l, w))
......@@ -34,23 +73,65 @@ class PadMaker:
return pad
def SMTRoundPad(self, size):
pad = self.SMDPad(size, size, shape = pcbnew.PAD_CIRCLE)
pad = self.SMDPad(size, size, shape=pcbnew.PAD_CIRCLE)
return pad
class PadArray:
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):
self.firstPad = fpNum
self.firstPadNum = fpNum
def AddPad(self, 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):
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
# pad data, but not actually add it
self.pad = pad
......@@ -58,78 +139,121 @@ class PadGridArray(PadArray):
self.ny = int(ny)
self.px = px
self.py = py
self.pin1Pos = pin1Pos
self.centre = centre
# handy utility function 1 - A, 2 - B, 26 - AA, etc
# aIndex = 0 for 0 - A
# alphabet = set of allowable chars if not A-Z, eg ABCDEFGHJKLMNPRTUVWY for BGA
def AlphaNameFromNumber(self, n, aIndex = 1, alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"):
# alphabet = set of allowable chars if not A-Z,
# eg ABCDEFGHJKLMNPRTUVWY for BGA
def AlphaNameFromNumber(self, n, aIndex=1,
alphabet="ABCDEFGHIJKLMNOPQRSTUVWXYZ"):
div, mod = divmod(n - aIndex, len(alphabet))
alpha = alphabet[mod]
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
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
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 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
pad = self.pad.Duplicate()
for y in range(self.ny):
posY = pin1posY + (self.py * y)
pos = dc.TransformPoint(posX, posY)
pad.SetPos0(pos)
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)
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:
PadGridArray.__init__(self, pad, 1, n, 0, pitch, pin1Pos)
PadGridArray.__init__(self, pad, 1, n, 0, pitch, centre)
else:
PadGridArray.__init__(self, pad, n, 1, pitch, 0, pin1Pos)
class RectPadArray(PadArray):
def __init__(self, nx, ny, pitch, xpitch, ypitch, pin1Pos):
#left row
pin1Pos = pcbnew.wxPoint(-h_pitch / 2, -row_len / 2)
array = PadLineArray(h_pad, pads_per_row, pad_pitch, True, pin1Pos)
array.SetFirstPadInArray(1)
array.AddPadsToModule()
#bottom row
pin1Pos = pcbnew.wxPoint(-row_len / 2, v_pitch / 2)
array = PA.PadLineArray(v_pad, pads_per_row, pad_pitch, False, pin1Pos)
array.SetFirstPadInArray(pads_per_row + 1)
array.AddPadsToModule()
#right row
pin1Pos = pcbnew.wxPoint(h_pitch / 2, row_len / 2)
array = PadLineArray(h_pad, pads_per_row, -pad_pitch, True, pin1Pos)
array.SetFirstPadInArray(2*pads_per_row + 1)
array.AddPadsToModule()
#top row
pin1Pos = pcbnew.wxPoint(row_len / 2, -v_pitch / 2)
array = PadLineArray(v_pad, pads_per_row, -pad_pitch, False, pin1Pos)
array.SetFirstPadInArray(3*pads_per_row + 1)
array.AddPadsToModule()
PadGridArray.__init__(self, pad, n, 1, pitch, 0, centre)
class PadCircleArray(PadArray):
def __init__(self, pad, n, r, angle_offset=0, centre=pcbnew.wxPoint(0, 0),
clockwise=True):
PadArray.__init__(self)
# this pad is more of a "context", we will use it as a source of
# pad data, but not actually add it
self.pad = pad
self.n = int(n)
self.r = r
self.angle_offset = angle_offset
self.centre = centre
self.clockwise = clockwise
# around the circle, CW or CCW according to the flag
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 pin in range(0, self.n):
angle = self.angle_offset + (360 / self.n) * pin
if not self.clockwise:
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
class BGAPadGridArray(PA.PadGridArray):
def NamingFunction(self, x, y):
return "%s%d" % (self.AlphaNameFromNumber(y + 1, alphabet="ABCDEFGHJKLMNPRTUVWY"), x + 1)
def NamingFunction(self, n_x, n_y):
return "%s%d" % (
self.AlphaNameFromNumber(n_y + 1, alphabet="ABCDEFGHJKLMNPRTUVWY"),
n_x + 1)
class BGAWizard(HFPW.HelpfulFootprintWizardPlugin):
......@@ -46,21 +48,19 @@ class BGAWizard(HFPW.HelpfulFootprintWizardPlugin):
def CheckParameters(self):
self.CheckParamPositiveInt("Pads", "*row count")
self.CheckParamPositiveInt("Pads", "*column count")
self.CheckParamInt("Pads", "*row 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
def GetValuePrefix(self):
def GetReferencePrefix(self):
return "U"
def BuildThisFootprint(self):
pads = self.parameters["Pads"]
......@@ -76,23 +76,24 @@ class BGAWizard(HFPW.HelpfulFootprintWizardPlugin):
# add in the pads
pad = PA.PadMaker(self.module).SMTRoundPad(pads["pad size"])
pin1Pos = pcbnew.wxPoint(-((cols - 1) * pad_pitch) / 2,
-((rows - 1) * pad_pitch) / 2)
pin1_pos = pcbnew.wxPoint(-((cols - 1) * pad_pitch) / 2,
-((rows - 1) * pad_pitch) / 2)
array = BGAPadGridArray(pad, cols, rows, pad_pitch, pad_pitch, pin1Pos)
array.AddPadsToModule()
array = BGAPadGridArray(pad, cols, rows, pad_pitch, pad_pitch)
array.AddPadsToModule(self.draw)
#box
ssX = -pin1Pos.x + pads["outline x margin"]
ssY = -pin1Pos.y + pads["outline y margin"]
ssx = -pin1_pos.x + pads["outline x 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
textSize = pcbnew.FromMM(0.8)
text_size = pcbnew.FromMM(1.2) # IPC nominal
self.draw.Value(0, - ssY - textSize, textSize)
self.draw.Reference(0, ssY + textSize, textSize)
self.draw.Value(0, - ssy - text_size, text_size)
self.draw.Reference(0, ssy + text_size, text_size)
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
import pcbnew
import HelpfulFootprintWizardPlugin
import PadArray as PA
class QFPWizard(HelpfulFootprintWizardPlugin.HelpfulFootprintWizardPlugin):
def GetName(self):
......@@ -26,10 +43,10 @@ class QFPWizard(HelpfulFootprintWizardPlugin.HelpfulFootprintWizardPlugin):
def CheckParameters(self):
self.CheckParamPositiveInt("Pads", "*n", is_multiple_of = 4)
self.CheckParamInt("Pads", "*n", is_multiple_of=4)
self.CheckParamBool("Pads", "*oval")
def GetReference(self):
def GetValue(self):
return "QFP %d" % self.parameters["Pads"]["*n"]
def BuildThisFootprint(self):
......@@ -49,44 +66,58 @@ class QFPWizard(HelpfulFootprintWizardPlugin.HelpfulFootprintWizardPlugin):
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)
v_pad = PA.PadMaker(self.module).SMDPad(pad_length, pad_width, shape = pad_shape)
h_pad = PA.PadMaker(self.module).SMDPad(
pad_width, pad_length, shape=pad_shape)
v_pad = PA.PadMaker(self.module).SMDPad(
pad_length, pad_width, shape=pad_shape)
#left row
pin1Pos = pcbnew.wxPoint(-h_pitch / 2, -row_len / 2)
array = PA.PadLineArray(h_pad, pads_per_row, pad_pitch, True, pin1Pos)
pin1Pos = pcbnew.wxPoint(-h_pitch / 2, 0)
array = PA.PadLineArray(h_pad, pads_per_row, pad_pitch, True,
pin1Pos)
array.SetFirstPadInArray(1)
array.AddPadsToModule()
array.AddPadsToModule(self.draw)
#bottom row
pin1Pos = pcbnew.wxPoint(-row_len / 2, v_pitch / 2)
array = PA.PadLineArray(v_pad, pads_per_row, pad_pitch, False, pin1Pos)
pin1Pos = pcbnew.wxPoint(0, v_pitch / 2)
array = PA.PadLineArray(v_pad, pads_per_row, pad_pitch, False,
pin1Pos)
array.SetFirstPadInArray(pads_per_row + 1)
array.AddPadsToModule()
array.AddPadsToModule(self.draw)
#right row
pin1Pos = pcbnew.wxPoint(h_pitch / 2, row_len / 2)
array = PA.PadLineArray(h_pad, pads_per_row, -pad_pitch, True, pin1Pos)
pin1Pos = pcbnew.wxPoint(h_pitch / 2, 0)
array = PA.PadLineArray(h_pad, pads_per_row, -pad_pitch, True,
pin1Pos)
array.SetFirstPadInArray(2*pads_per_row + 1)
array.AddPadsToModule()
array.AddPadsToModule(self.draw)
#top row
pin1Pos = pcbnew.wxPoint(row_len / 2, -v_pitch / 2)
array = PA.PadLineArray(v_pad, pads_per_row, -pad_pitch, False, pin1Pos)
pin1Pos = pcbnew.wxPoint(0, -v_pitch / 2)
array = PA.PadLineArray(v_pad, pads_per_row, -pad_pitch, False,
pin1Pos)
array.SetFirstPadInArray(3*pads_per_row + 1)
array.AddPadsToModule()
array.AddPadsToModule(self.draw)
limX = pads["package width"] / 2
limY = pads["package height"] / 2
lim_x = pads["package width"] / 2
lim_y = pads["package height"] / 2
inner = (row_len / 2) + pad_pitch
#top left - diagonal
self.draw.Line(-limX, -inner, -inner, -limY)
self.draw.Line(-lim_x, -inner, -inner, -lim_y)
# 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
self.draw.Polyline([(-inner, limY), (-limX, limY), (-limX, inner)])
self.draw.Polyline([(-inner, lim_y), (-lim_x, lim_y), (-lim_x, inner)])
# 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()
......@@ -24,10 +24,11 @@ import PadArray as PA
class RowedGridArray(PA.PadGridArray):
def NamingFunction(self, x, y):
if (x % 2) == 0: # even row, count up
return (x * self.ny) + y + 1;
else: # odd row, count down
return (self.ny * (x + 1)) - y;
if (x % 2) == 0: # even row, count up
return (x * self.ny) + y + 1
else: # odd row, count down
return (self.ny * (x + 1)) - y
class RowedFootprint(HFPW.HelpfulFootprintWizardPlugin):
......@@ -39,9 +40,13 @@ class RowedFootprint(HFPW.HelpfulFootprintWizardPlugin):
self.AddParam("Pads", "row count", self.uNatural, 2)
def CheckParameters(self):
self.CheckParamPositiveInt("Pads", "*row count")
self.CheckParamPositiveInt("Pads", "*n", is_multiple_of = self.parameters["Pads"]["*row count"])
self.CheckParamBool("Pads", "*silk screen inside") #can do this internally to parameter manager?
self.CheckParamInt("Pads", "*row count")
self.CheckParamInt(
"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):
......@@ -57,39 +62,40 @@ class RowedFootprint(HFPW.HelpfulFootprintWizardPlugin):
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
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.AddPadsToModule()
array = RowedGridArray(pad, num_rows, pads_per_row, row_pitch,
pad_pitch)
array.AddPadsToModule(self.draw)
# draw the Silk Screen
pad_length = pads["pad length"]
pad_width = pads["pad width"]
ssXOffset = -pad_length / 2 - pads["outline x margin"]
ssYOffset = -pad_width / 2 - pads["outline y margin"]
ssx_offset = -pad_length / 2 - pads["outline x margin"]
ssy_offset = -pad_width / 2 - pads["outline y margin"]
if pads["*silk screen inside"]:
ssXOffset *= -1
ssX = -pin1Pos.x - ssXOffset
ssY = -pin1Pos.y - ssYOffset
ssx_offset *= -1
ssx = -pin1_pos.x - ssx_offset
ssy = -pin1_pos.y - ssy_offset
self.DrawBox(ssX, ssY)
self.DrawBox(ssx, ssy)
#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.Reference(0, ssY + textSize, textSize)
self.draw.Value(0, - ssy - text_size, text_size)
self.draw.Reference(0, ssy + text_size, text_size)
class SDIPWizard(RowedFootprint):
......@@ -111,15 +117,15 @@ class SDIPWizard(RowedFootprint):
self.AddParam("Pads", "outline x margin", self.uMM, 0.5)
self.AddParam("Pads", "outline y margin", self.uMM, 1)
def GetReference(self):
def GetValue(self):
rows = self.parameters["Pads"]["*row count"]
if rows == 1:
if rows == 1:
name = "SIP"
elif rows == 2:
name = "DIP"
else: # triple and up aren't really a thing, but call it something!
else: # triple and up aren't really a thing, but call it something!
name = "xIP"
return "%s %d" % (name, self.parameters["Pads"]["*n"])
......@@ -128,9 +134,10 @@ class SDIPWizard(RowedFootprint):
pad_length = self.parameters["Pads"]["pad length"]
pad_width = self.parameters["Pads"]["pad width"]
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:
......@@ -144,18 +151,19 @@ class SDIPWizard(RowedFootprint):
notchWidth = pcbnew.FromMM(3)
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:
# -----------------
# |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
pad_pitch = self.parameters["Pads"]["pad pitch"];
self.draw.HLine(-ssX, pin1Pos.y + pad_pitch/2, ssX * 2)
pad_pitch = self.parameters["Pads"]["pad pitch"]
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()
......@@ -168,7 +176,7 @@ class SOICWizard(RowedFootprint):
def GetDescription(self):
return "SOIC, MSOP, SSOP, TSSOP, etc, footprint wizard"
def GetReference(self):
def GetValue(self):
return "%s %d" % ("SOIC", self.parameters["Pads"]["*n"])
def GenerateParameterList(self):
......@@ -186,15 +194,16 @@ class SOICWizard(RowedFootprint):
def GetPad(self):
pad_length = self.parameters["Pads"]["pad length"]
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 |
# |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()
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