Merge lp:~john-j-beard/kicad/fpwizards into lp:kicad/product
- fpwizards
- Merge into product
Proposed by
John Beard
Status: | Merged |
---|---|
Merge reported by: | John Beard |
Merged at revision: | not available |
Proposed branch: | lp:~john-j-beard/kicad/fpwizards |
Merge into: | lp:kicad/product |
Diff against target: |
1177 lines (+913/-229) 6 files modified
pcbnew/scripting/plugins/FootprintWizardDrawingAids.py (+134/-0) pcbnew/scripting/plugins/HelpfulFootprintWizardPlugin.py (+250/-0) pcbnew/scripting/plugins/PadArray.py (+148/-0) pcbnew/scripting/plugins/bga_wizard.py (+98/-0) pcbnew/scripting/plugins/qfp_wizard.py (+83/-229) pcbnew/scripting/plugins/sdip_wizard.py (+200/-0) |
To merge this branch: | bzr merge lp:~john-j-beard/kicad/fpwizards |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
KiCad Lead Developers | Pending | ||
Review via email: mp+216560@code.launchpad.net |
Commit message
Description of the change
Add a conveneience layer under the Python foortprint wizard interface, along with some new examples of new wizards (SIP/SIP, SOIC/SSOP/
For now, this is just a wrapper around the pcbnew classes (and you can write wizards without it, or with only bits of it), but there is no reason it (or parts of it) couldn't be moved into the pcbnew module if wanted.
To post a comment you must log in.
Revision history for this message
jean-pierre charras (jp-charras) wrote : | # |
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === added file 'pcbnew/scripting/plugins/FootprintWizardDrawingAids.py' |
2 | --- pcbnew/scripting/plugins/FootprintWizardDrawingAids.py 1970-01-01 00:00:00 +0000 |
3 | +++ pcbnew/scripting/plugins/FootprintWizardDrawingAids.py 2014-04-20 22:23:21 +0000 |
4 | @@ -0,0 +1,134 @@ |
5 | +# This program is free software; you can redistribute it and/or modify |
6 | +# it under the terms of the GNU General Public License as published by |
7 | +# the Free Software Foundation; either version 2 of the License, or |
8 | +# (at your option) any later version. |
9 | +# |
10 | +# This program is distributed in the hope that it will be useful, |
11 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
12 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
13 | +# GNU General Public License for more details. |
14 | +# |
15 | +# You should have received a copy of the GNU General Public License |
16 | +# along with this program; if not, write to the Free Software |
17 | +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, |
18 | +# MA 02110-1301, USA. |
19 | +# |
20 | + |
21 | +import pcbnew |
22 | + |
23 | +class FootprintWizardDrawingAids: |
24 | + """ |
25 | + Collection of handy functions to simplify drawing shapes from within |
26 | + footprint wizards |
27 | + |
28 | + A "drawing context" is provided which can be used to set and retain |
29 | + settings such as line width and layer |
30 | + """ |
31 | + def __init__(self, module): |
32 | + self.module = module |
33 | + #drawing context defaults |
34 | + self.dc = { |
35 | + 'layer': pcbnew.SILKSCREEN_N_FRONT, |
36 | + 'width': pcbnew.FromMM(0.2) |
37 | + } |
38 | + |
39 | + def SetWidth(self, width): |
40 | + self.dc['width'] = width |
41 | + |
42 | + def SetLayer(self, layer): |
43 | + self.dc['layer'] = layer |
44 | + |
45 | + def Line(self, x1, y1, x2, y2): |
46 | + |
47 | + outline = pcbnew.EDGE_MODULE(self.module) |
48 | + outline.SetWidth(self.dc['width']) |
49 | + outline.SetLayer(self.dc['layer']) |
50 | + outline.SetShape(pcbnew.S_SEGMENT) |
51 | + start = pcbnew.wxPoint(x1, y1) |
52 | + end = pcbnew.wxPoint(x2, y2) |
53 | + outline.SetStartEnd(start, end) |
54 | + self.module.Add(outline) |
55 | + |
56 | + # extends from (x1,y1) right |
57 | + def HLine(self, x, y, l): |
58 | + """ |
59 | + Draw a horizontal line from (x,y), rightwards |
60 | + """ |
61 | + self.Line(x, y, x + l, y) |
62 | + |
63 | + def VLine(self, x, y, l): |
64 | + """ |
65 | + Draw a vertical line from (x1,y1), downwards |
66 | + """ |
67 | + self.Line(x, y, x, y + l) |
68 | + |
69 | + def Polyline(self, pts): |
70 | + |
71 | + if len(pts) < 2: |
72 | + return |
73 | + |
74 | + for i in range(0, len(pts) - 1): |
75 | + self.Line(pts[i][0], pts[i][1], pts[i+1][0], pts[i+1][1]) |
76 | + |
77 | + def Reference(self, x, y, size): |
78 | + """ |
79 | + Draw the module's reference as the given point. |
80 | + |
81 | + The actual setting of the reference is not done in this drawing |
82 | + aid - that is up to the wizard |
83 | + """ |
84 | + |
85 | + text_size = pcbnew.wxSize(size, size) |
86 | + |
87 | + self.module.Reference().SetPos0(pcbnew.wxPoint(x, y)) |
88 | + self.module.Reference().SetTextPosition(self.module.Reference().GetPos0()) |
89 | + self.module.Reference().SetSize(text_size) |
90 | + |
91 | + def Value(self, x, y, size): |
92 | + """ |
93 | + As for references, draw the module's value |
94 | + """ |
95 | + text_size = pcbnew.wxSize(size, size) |
96 | + |
97 | + self.module.Value().SetPos0(pcbnew.wxPoint(x, y)) |
98 | + self.module.Value().SetTextPosition(self.module.Value().GetPos0()) |
99 | + self.module.Value().SetSize(text_size) |
100 | + |
101 | + def Box(self, x, y, w, h): |
102 | + """ |
103 | + Draw a rectangular box, centred at (x,y), with given width and |
104 | + height |
105 | + """ |
106 | + self.VLine(x - w/2, y - h/2, h) # left |
107 | + self.VLine(x + w/2, y - h/2, h) # right |
108 | + self.HLine(x - w/2, y + h/2, w) # bottom |
109 | + self.HLine(x - w/2, y - h/2, w) # top |
110 | + |
111 | + def NotchedBox(self, x, y, w, h, notchW, notchH): |
112 | + """ |
113 | + Draw a box with a notch in the top edge |
114 | + """ |
115 | + #limit to half the overall width |
116 | + notchW = min(x + w/2, notchW) |
117 | + |
118 | + # draw notch |
119 | + self.Polyline([ #three sides of box |
120 | + (x - w/2, y - h/2), |
121 | + (x - w/2, y + h/2), |
122 | + (x + w/2, y + h/2), |
123 | + (x + w/2, y - h/2), |
124 | + #the notch |
125 | + (notchW/2, y - h/2), |
126 | + (notchW/2, y - h/2 + notchH), |
127 | + (-notchW/2, y - h/2 + notchH), |
128 | + (-notchW/2, y - h/2), |
129 | + (x - w/2, y - h/2) |
130 | + ]) |
131 | + |
132 | + def BoxWithDiagonalAtCorner(self, x, y, w, h, diagSetback): |
133 | + |
134 | + self.Box(x, y, w, h) |
135 | + |
136 | + #diagonal corner |
137 | + self.Line(x - w/2 + diagSetback, x - h/2, x - w/2, |
138 | + x - h/2 + diagSetback) |
139 | |
140 | === added file 'pcbnew/scripting/plugins/HelpfulFootprintWizardPlugin.py' |
141 | --- pcbnew/scripting/plugins/HelpfulFootprintWizardPlugin.py 1970-01-01 00:00:00 +0000 |
142 | +++ pcbnew/scripting/plugins/HelpfulFootprintWizardPlugin.py 2014-04-20 22:23:21 +0000 |
143 | @@ -0,0 +1,250 @@ |
144 | +# This program is free software; you can redistribute it and/or modify |
145 | +# it under the terms of the GNU General Public License as published by |
146 | +# the Free Software Foundation; either version 2 of the License, or |
147 | +# (at your option) any later version. |
148 | +# |
149 | +# This program is distributed in the hope that it will be useful, |
150 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
151 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
152 | +# GNU General Public License for more details. |
153 | +# |
154 | +# You should have received a copy of the GNU General Public License |
155 | +# along with this program; if not, write to the Free Software |
156 | +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, |
157 | +# MA 02110-1301, USA. |
158 | +# |
159 | + |
160 | +import pcbnew |
161 | +import FootprintWizardDrawingAids |
162 | + |
163 | +class FootprintWizardParameterManager: |
164 | + """ |
165 | + Functions for helpfully managing parameters to a KiCAD Footprint |
166 | + Wizard. |
167 | + |
168 | + Abstracts away from whatever structure is used by pcbnew's footprint |
169 | + wizard class |
170 | + """ |
171 | + |
172 | + def __init__(self): |
173 | + self.parameters = {} |
174 | + self.GenerateParameterList() |
175 | + |
176 | + def GenerateParameterList(self): |
177 | + """ |
178 | + Construct parameters here, or leave out to have no parameters |
179 | + """ |
180 | + pass |
181 | + |
182 | + def CheckParameters(self): |
183 | + """ |
184 | + Implement this to make checks on parameter values, filling |
185 | + parameter_errors (or using the checker routines) |
186 | + |
187 | + Subclasses can implment their own and override the parent |
188 | + defaults and add new ones |
189 | + """ |
190 | + pass |
191 | + |
192 | + uMM = 1 |
193 | + uMils = 2 |
194 | + uNatural = 3 |
195 | + uBool = 4 |
196 | + |
197 | + def AddParam(self, section, param, unit, default, hint = ''): |
198 | + """ |
199 | + Add a parameter with some properties. |
200 | + |
201 | + TODO: Hints are not supported, as there is as yet nowhere to |
202 | + put them in the KiCAD interface |
203 | + """ |
204 | + |
205 | + val = None |
206 | + if unit == self.uMM: |
207 | + val = pcbnew.FromMM(default) |
208 | + elif unit == self.uMils: |
209 | + val = pcbnew.FromMils(default) |
210 | + elif unit == self.uNatural: |
211 | + val = default |
212 | + elif unit == self.uBool: |
213 | + val = "True" if default else "False" #ugly stringing |
214 | + else: |
215 | + print "Warning: Unknown unit type: %s" % unit |
216 | + return |
217 | + |
218 | + if unit in [self.uNatural, self.uBool]: |
219 | + param = "*%s" % param #star prefix for natural |
220 | + |
221 | + if section not in self.parameters: |
222 | + self.parameters[section] = {} |
223 | + |
224 | + self.parameters[section][param] = val |
225 | + |
226 | + def _PrintParameterTable(self): |
227 | + """ |
228 | + Pretty-print the parameters we have |
229 | + """ |
230 | + for name, section in self.parameters.iteritems(): |
231 | + print " %s:" % name |
232 | + |
233 | + for key, value in section.iteritems(): |
234 | + unit = "" |
235 | + if (type(value) is int or type(value) is float) and not "*" in key: |
236 | + unit = "mm" |
237 | + |
238 | + if "*" in key: |
239 | + key = key[1:] |
240 | + else: |
241 | + value = pcbnew.ToMM(value) |
242 | + |
243 | + print " %s: %s%s" % (key, value, unit) |
244 | + |
245 | + def _ParametersHaveErrors(self): |
246 | + """ |
247 | + Return true if we discovered errors suring parameter processing |
248 | + """ |
249 | + |
250 | + for name, section in self.parameter_errors.iteritems(): |
251 | + for k, v in section.iteritems(): |
252 | + if v: |
253 | + return True |
254 | + |
255 | + return False |
256 | + |
257 | + def _PrintParameterErrors(self): |
258 | + """ |
259 | + Pretty-print parameters with errors |
260 | + """ |
261 | + |
262 | + for name, section in self.parameter_errors.iteritems(): |
263 | + printed_section = False |
264 | + |
265 | + for key, value in section.iteritems(): |
266 | + if value: |
267 | + if not printed_section: |
268 | + print " %s:" % name |
269 | + |
270 | + print " %s: %s (have %s)" % (key, value, |
271 | + self.parameters[name][key]) |
272 | + |
273 | + def ProcessParameters(self): |
274 | + """ |
275 | + Make sure the parameters we have meet whatever expectations the |
276 | + footprint wizard has of them |
277 | + """ |
278 | + |
279 | + self.ClearErrors() |
280 | + self.CheckParameters(); |
281 | + |
282 | + if self._ParametersHaveErrors(): |
283 | + print "Cannot build footprint: Parameters have errors:" |
284 | + self._PrintParameterErrors() |
285 | + return False |
286 | + |
287 | + print "Building new %s footprint with the following parameters:" % self.name |
288 | + |
289 | + self._PrintParameterTable() |
290 | + return True |
291 | + |
292 | + ################################################################# |
293 | + # PARAMETER CHECKERS |
294 | + ################################################################# |
295 | + |
296 | + def CheckParamPositiveInt(self, section, param, min_value = 1, |
297 | + max_value = None, is_multiple_of = 1): |
298 | + """ |
299 | + Make sure a parameter can be made into an int, and enforce |
300 | + limits if required |
301 | + """ |
302 | + |
303 | + try: |
304 | + self.parameters[section][param] = int(self.parameters[section][param]) |
305 | + except ValueError: |
306 | + self.parameter_errors[section][param] = "Must be a valid integer" |
307 | + return |
308 | + |
309 | + if min_value is not None and (self.parameters[section][param] < min_value): |
310 | + self.parameter_errors[section][param] = "Must be greater than or equal to %d" % (min_value) |
311 | + return |
312 | + |
313 | + if max_value is not None and (self.parameters[section][param] > min_value): |
314 | + self.parameter_errors[section][param] = "Must be less than or equal to %d" % (max_value) |
315 | + return |
316 | + |
317 | + if is_multiple_of > 1 and (self.parameters[section][param] % is_multiple_of) > 0: |
318 | + self.parameter_errors[section][param] = "Must be a multiple of %d" % is_multiple_of |
319 | + return |
320 | + |
321 | + return |
322 | + |
323 | + def CheckParamBool(self, section, param): |
324 | + """ |
325 | + Make sure a parameter looks like a boolean, convert to native |
326 | + boolean type if so |
327 | + """ |
328 | + if str(self.parameters[section][param]).lower() in ["true", "t", "y", "yes", "on", "1", "1.0"]: |
329 | + self.parameters[section][param] = True; |
330 | + return |
331 | + elif str(self.parameters[section][param]).lower() in ["false", "f", "n", "no", "off", "0", "0.0"]: |
332 | + self.parameters[section][param] = False; |
333 | + return |
334 | + |
335 | + self.parameter_errors[section][param] = "Must be boolean (true/false)" |
336 | + return |
337 | + |
338 | + |
339 | +class HelpfulFootprintWizardPlugin(pcbnew.FootprintWizardPlugin, |
340 | + FootprintWizardParameterManager): |
341 | + """ |
342 | + A class to simplify many aspects of footprint creation, leaving only |
343 | + the foot-print specific routines to the wizards themselves |
344 | + |
345 | + Generally, you need to implement: |
346 | + GetReference() |
347 | + GetValue() |
348 | + GenerateParameterList() |
349 | + CheckParameters() |
350 | + BuildThisFootprint() |
351 | + GetName() |
352 | + GetDescription() |
353 | + """ |
354 | + def __init__(self): |
355 | + pcbnew.FootprintWizardPlugin.__init__(self) |
356 | + FootprintWizardParameterManager.__init__(self) |
357 | + |
358 | + self.name = self.GetName() |
359 | + self.decription = self.GetDescription() |
360 | + self.image = self.GetImage() |
361 | + |
362 | + def GetReference(self): |
363 | + raise NotImplementedError |
364 | + |
365 | + def GetValuePrefix(self): |
366 | + return "U" # footprints needing wizards of often ICs |
367 | + |
368 | + def GetImage(self): |
369 | + return "" |
370 | + |
371 | + def BuildThisFootprint(self): |
372 | + raise NotImplementedError |
373 | + |
374 | + def BuildFootprint(self): |
375 | + """ |
376 | + Actually make the footprint. We defer all but the setup to |
377 | + the implmenting class |
378 | + """ |
379 | + |
380 | + if not self.ProcessParameters(): |
381 | + return |
382 | + |
383 | + self.module = pcbnew.MODULE(None) # create a new module |
384 | + |
385 | + self.draw = FootprintWizardDrawingAids.FootprintWizardDrawingAids(self.module) |
386 | + |
387 | + self.module.SetReference(self.GetReference()) |
388 | + self.module.SetValue("%s**" % self.GetValuePrefix()) |
389 | + |
390 | + fpid = pcbnew.FPID(self.module.GetReference()) #the name in library |
391 | + self.module.SetFPID( fpid ) |
392 | + |
393 | + self.BuildThisFootprint() # implementer's build function |
394 | |
395 | === added file 'pcbnew/scripting/plugins/PadArray.py' |
396 | --- pcbnew/scripting/plugins/PadArray.py 1970-01-01 00:00:00 +0000 |
397 | +++ pcbnew/scripting/plugins/PadArray.py 2014-04-20 22:23:21 +0000 |
398 | @@ -0,0 +1,148 @@ |
399 | + |
400 | +import pcbnew |
401 | + |
402 | +class PadMaker: |
403 | + """ |
404 | + Useful construction functions for common types of pads |
405 | + """ |
406 | + |
407 | + def __init__(self, module): |
408 | + self.module = module |
409 | + |
410 | + def THPad(self, w, l, drill, shape = pcbnew.PAD_OVAL): |
411 | + pad = pcbnew.D_PAD(self.module) |
412 | + |
413 | + pad.SetSize(pcbnew.wxSize(l, w)) |
414 | + |
415 | + pad.SetShape(shape) |
416 | + |
417 | + pad.SetAttribute(pcbnew.PAD_STANDARD) |
418 | + pad.SetLayerMask(pcbnew.PAD_STANDARD_DEFAULT_LAYERS) |
419 | + pad.SetDrillSize(pcbnew.wxSize(drill, drill)) |
420 | + |
421 | + return pad |
422 | + |
423 | + def SMDPad(self, w, l, shape = pcbnew.PAD_RECT): |
424 | + pad = pcbnew.D_PAD(self.module) |
425 | + pad.SetSize(pcbnew.wxSize(l, w)) |
426 | + |
427 | + pad.SetShape(shape) |
428 | + |
429 | + pad.SetAttribute(pcbnew.PAD_SMD) |
430 | + pad.SetLayerMask(pcbnew.PAD_SMD_DEFAULT_LAYERS) |
431 | + |
432 | + return pad |
433 | + |
434 | + def SMTRoundPad(self, size): |
435 | + pad = self.SMDPad(size, size, shape = pcbnew.PAD_CIRCLE) |
436 | + return pad |
437 | + |
438 | +class PadArray: |
439 | + |
440 | + def __init__(self): |
441 | + self.firstPad = 1; |
442 | + |
443 | + def SetFirstPadInArray(self, fpNum): |
444 | + self.firstPad = fpNum |
445 | + |
446 | + # HACK! pad should one day have its own clone method |
447 | + def ClonePad(self): |
448 | + |
449 | + pad = pcbnew.D_PAD(self.pad.GetParent()) |
450 | + |
451 | + pad.SetSize(self.pad.GetSize()) |
452 | + pad.SetShape(self.pad.GetShape()) |
453 | + pad.SetAttribute(self.pad.GetAttribute()) |
454 | + pad.SetLayerMask(self.pad.GetLayerMask()) |
455 | + pad.SetDrillSize(self.pad.GetDrillSize()) |
456 | + |
457 | + return pad |
458 | + |
459 | + def AddPad(self, pad): |
460 | + self.pad.GetParent().Add(pad) |
461 | + |
462 | +class PadGridArray(PadArray): |
463 | + |
464 | + def __init__(self, pad, nx, ny, px, py, pin1Pos): |
465 | + # this pad is more of a "context", we will use it as a source of |
466 | + # pad data, but not actually add it |
467 | + self.pad = pad |
468 | + self.nx = int(nx) |
469 | + self.ny = int(ny) |
470 | + self.px = px |
471 | + self.py = py |
472 | + self.pin1Pos = pin1Pos |
473 | + |
474 | + # handy utility function 1 - A, 2 - B, 26 - AA, etc |
475 | + # aIndex = 0 for 0 - A |
476 | + def AlphaNameFromNumber(self, n, aIndex = 1): |
477 | + |
478 | + div, mod = divmod(n - aIndex, 26) |
479 | + alpha = chr(65 + mod) |
480 | + |
481 | + if div > 0: |
482 | + return self.AlphaNameFromNumber(div) + alpha; |
483 | + |
484 | + return alpha; |
485 | + |
486 | + # right to left, top to bottom |
487 | + def NamingFunction(self, x, y): |
488 | + return self.firstPad + (self.nx * y + x) |
489 | + |
490 | + #relocate the pad and add it as many times as we need |
491 | + def AddPadsToModule(self): |
492 | + |
493 | + for x in range(0, self.nx): |
494 | + for y in range(self.ny): |
495 | + posX = self.pin1Pos.x + (self.px * x) |
496 | + posY = self.pin1Pos.y + (self.py * y) |
497 | + |
498 | + pos = pcbnew.wxPoint(posX, posY) |
499 | + |
500 | + # THIS DOESN'T WORK yet! |
501 | + #pad = self.pad.Clone() |
502 | + pad = self.ClonePad() |
503 | + |
504 | + pad.SetPos0(pos) |
505 | + pad.SetPosition(pos) |
506 | + |
507 | + pad.SetPadName(str(self.NamingFunction(x,y))) |
508 | + |
509 | + self.AddPad(pad) |
510 | + |
511 | +class PadLineArray(PadGridArray): |
512 | + |
513 | + def __init__(self, pad, n, pitch, isVertical, pin1Pos): |
514 | + |
515 | + if isVertical: |
516 | + PadGridArray.__init__(self, pad, 1, n, 0, pitch, pin1Pos) |
517 | + else: |
518 | + PadGridArray.__init__(self, pad, n, 1, pitch, 0, pin1Pos) |
519 | + |
520 | +class RectPadArray(PadArray): |
521 | + |
522 | + def __init__(self, nx, ny, pitch, xpitch, ypitch, pin1Pos): |
523 | + |
524 | + #left row |
525 | + pin1Pos = pcbnew.wxPoint(-h_pitch / 2, -row_len / 2) |
526 | + array = PadLineArray(h_pad, pads_per_row, pad_pitch, True, pin1Pos) |
527 | + array.SetFirstPadInArray(1) |
528 | + array.AddPadsToModule() |
529 | + |
530 | + #bottom row |
531 | + pin1Pos = pcbnew.wxPoint(-row_len / 2, v_pitch / 2) |
532 | + array = PA.PadLineArray(v_pad, pads_per_row, pad_pitch, False, pin1Pos) |
533 | + array.SetFirstPadInArray(pads_per_row + 1) |
534 | + array.AddPadsToModule() |
535 | + |
536 | + #right row |
537 | + pin1Pos = pcbnew.wxPoint(h_pitch / 2, row_len / 2) |
538 | + array = PadLineArray(h_pad, pads_per_row, -pad_pitch, True, pin1Pos) |
539 | + array.SetFirstPadInArray(2*pads_per_row + 1) |
540 | + array.AddPadsToModule() |
541 | + |
542 | + #top row |
543 | + pin1Pos = pcbnew.wxPoint(row_len / 2, -v_pitch / 2) |
544 | + array = PadLineArray(v_pad, pads_per_row, -pad_pitch, False, pin1Pos) |
545 | + array.SetFirstPadInArray(3*pads_per_row + 1) |
546 | + array.AddPadsToModule() |
547 | |
548 | === added file 'pcbnew/scripting/plugins/bga_wizard.py' |
549 | --- pcbnew/scripting/plugins/bga_wizard.py 1970-01-01 00:00:00 +0000 |
550 | +++ pcbnew/scripting/plugins/bga_wizard.py 2014-04-20 22:23:21 +0000 |
551 | @@ -0,0 +1,98 @@ |
552 | +# This program is free software; you can redistribute it and/or modify |
553 | +# it under the terms of the GNU General Public License as published by |
554 | +# the Free Software Foundation; either version 2 of the License, or |
555 | +# (at your option) any later version. |
556 | +# |
557 | +# This program is distributed in the hope that it will be useful, |
558 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
559 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
560 | +# GNU General Public License for more details. |
561 | +# |
562 | +# You should have received a copy of the GNU General Public License |
563 | +# along with this program; if not, write to the Free Software |
564 | +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, |
565 | +# MA 02110-1301, USA. |
566 | +# |
567 | + |
568 | +from __future__ import division |
569 | +import pcbnew |
570 | + |
571 | +import HelpfulFootprintWizardPlugin as HFPW |
572 | +import PadArray as PA |
573 | + |
574 | + |
575 | +class BGAPadGridArray(PA.PadGridArray): |
576 | + |
577 | + def NamingFunction(self, x, y): |
578 | + return "%s%d" % (self.AlphaNameFromNumber(y + 1), x + 1) |
579 | + |
580 | + |
581 | +class BGAWizard(HFPW.HelpfulFootprintWizardPlugin): |
582 | + |
583 | + def GetName(self): |
584 | + return "BGA" |
585 | + |
586 | + def GetDescription(self): |
587 | + return "Ball Grid Array Footprint Wizard" |
588 | + |
589 | + def GenerateParameterList(self): |
590 | + |
591 | + self.AddParam("Pads", "pad pitch", self.uMM, 1) |
592 | + self.AddParam("Pads", "pad size", self.uMM, 0.5) |
593 | + self.AddParam("Pads", "row count", self.uNatural, 5) |
594 | + self.AddParam("Pads", "column count", self.uNatural, 5) |
595 | + self.AddParam("Pads", "outline x margin", self.uMM, 1) |
596 | + self.AddParam("Pads", "outline y margin", self.uMM, 1) |
597 | + |
598 | + def CheckParameters(self): |
599 | + |
600 | + self.CheckParamPositiveInt("Pads", "*row count") |
601 | + self.CheckParamPositiveInt("Pads", "*column count") |
602 | + |
603 | + |
604 | + def GetReference(self): |
605 | + |
606 | + pins = self.parameters["Pads"]["*row count"] * self.parameters["Pads"]["*column count"] |
607 | + |
608 | + return "BGA %d" % pins |
609 | + |
610 | + |
611 | + def GetValuePrefix(self): |
612 | + return "U" |
613 | + |
614 | + |
615 | + def BuildThisFootprint(self): |
616 | + |
617 | + pads = self.parameters["Pads"] |
618 | + |
619 | + rows = pads["*row count"] |
620 | + cols = pads["*column count"] |
621 | + pad_size = pads["pad size"] |
622 | + |
623 | + pad_size = pcbnew.wxSize(pad_size, pad_size) |
624 | + |
625 | + pad_pitch = pads["pad pitch"] |
626 | + |
627 | + # add in the pads |
628 | + pad = PA.PadMaker(self.module).SMTRoundPad(pads["pad size"]) |
629 | + |
630 | + pin1Pos = pcbnew.wxPoint(-((rows - 1) * pad_pitch) / 2, |
631 | + -((cols - 1) * pad_pitch) / 2) |
632 | + |
633 | + array = BGAPadGridArray(pad, rows, cols, pad_pitch, pad_pitch, pin1Pos) |
634 | + array.AddPadsToModule() |
635 | + |
636 | + #box |
637 | + ssX = -pin1Pos.x + pads["outline x margin"] |
638 | + ssY = -pin1Pos.y + pads["outline y margin"] |
639 | + |
640 | + self.draw.BoxWithDiagonalAtCorner(0, 0, ssX*2, ssY*2, pads["outline x margin"]) |
641 | + |
642 | + #reference and value |
643 | + textSize = pcbnew.FromMM(0.8) |
644 | + |
645 | + self.draw.Value(0, - ssY - textSize, textSize) |
646 | + self.draw.Reference(0, ssY + textSize, textSize) |
647 | + |
648 | + |
649 | +BGAWizard().register() |
650 | |
651 | === modified file 'pcbnew/scripting/plugins/qfp_wizard.py' |
652 | --- pcbnew/scripting/plugins/qfp_wizard.py 2014-02-21 10:05:28 +0000 |
653 | +++ pcbnew/scripting/plugins/qfp_wizard.py 2014-04-20 22:23:21 +0000 |
654 | @@ -1,235 +1,89 @@ |
655 | +from __future__ import division |
656 | import pcbnew |
657 | |
658 | -def abs(x): |
659 | - if x < 0: |
660 | - return -x |
661 | - |
662 | - return x |
663 | - |
664 | -class QFPWizard(pcbnew.FootprintWizardPlugin): |
665 | - def __init__(self): |
666 | - pcbnew.FootprintWizardPlugin.__init__(self) |
667 | - self.name = "QFP" |
668 | - self.description = "QFP Footprint Wizard" |
669 | - self.parameters = { |
670 | - "Pads": { |
671 | - "*n": 100, |
672 | - "pitch": pcbnew.FromMM(0.5), |
673 | - "width": pcbnew.FromMM(0.25), |
674 | - "length": pcbnew.FromMM(1.5), |
675 | - "horizontal pitch": pcbnew.FromMM(15), |
676 | - "vertical pitch": pcbnew.FromMM(15), |
677 | - "*oval": "True" |
678 | - }, |
679 | - "Package": { |
680 | - "width": pcbnew.FromMM(14), |
681 | - "height": pcbnew.FromMM(14) |
682 | - } |
683 | - } |
684 | - |
685 | - self.ClearErrors() |
686 | - |
687 | - def smd_rect_pad(self, module, size, pos, name): |
688 | - pad = pcbnew.D_PAD(module) |
689 | - |
690 | - pad.SetSize(size) |
691 | - |
692 | - if self.parameters['Pads'].get('*oval', "true").lower() == "true": |
693 | - pad.SetShape(pcbnew.PAD_OVAL) |
694 | - else: |
695 | - pad.SetShape(pcbnew.PAD_RECT) |
696 | - |
697 | - pad.SetAttribute(pcbnew.PAD_SMD) |
698 | - pad.SetLayerMask(pcbnew.PAD_SMD_DEFAULT_LAYERS) |
699 | - pad.SetPos0(pos) |
700 | - pad.SetPosition(pos) |
701 | - pad.SetPadName(name) |
702 | - |
703 | - return pad |
704 | +import HelpfulFootprintWizardPlugin |
705 | +import PadArray as PA |
706 | + |
707 | +class QFPWizard(HelpfulFootprintWizardPlugin.HelpfulFootprintWizardPlugin): |
708 | + |
709 | + def GetName(self): |
710 | + return "QFP" |
711 | + |
712 | + def GetDescription(self): |
713 | + return "QFP Footprint Wizard" |
714 | + |
715 | + def GenerateParameterList(self): |
716 | + self.AddParam("Pads", "n", self.uNatural, 100) |
717 | + self.AddParam("Pads", "pad pitch", self.uMM, 0.5) |
718 | + self.AddParam("Pads", "pad width", self.uMM, 0.25) |
719 | + self.AddParam("Pads", "pad length", self.uMM, 1.5) |
720 | + self.AddParam("Pads", "vertical pitch", self.uMM, 15) |
721 | + self.AddParam("Pads", "horizontal pitch", self.uMM, 15) |
722 | + self.AddParam("Pads", "oval", self.uBool, True) |
723 | + |
724 | + self.AddParam("Pads", "package width", self.uMM, 14) |
725 | + self.AddParam("Pads", "package height", self.uMM, 14) |
726 | |
727 | def CheckParameters(self): |
728 | - errors = "" |
729 | - pads = self.parameters |
730 | - |
731 | - num_pads = pads["Pads"]["*n"] |
732 | - if (num_pads < 1): |
733 | - self.parameter_errors["Pads"]["*n"] = "Must be positive" |
734 | - errors +="Pads/n has wrong value, " |
735 | - pads["Pads"]["*n"] = int(num_pads) # Reset to int instead of float |
736 | - |
737 | - return errors |
738 | - |
739 | - def BuildFootprint(self): |
740 | - if self.has_errors(): |
741 | - print "Cannot build footprint: Parameters have errors:" |
742 | - print self.parameter_errors |
743 | - return |
744 | - |
745 | - print "Building new QFP footprint with the following parameters:" |
746 | - self.print_parameter_table() |
747 | - |
748 | - self.module = pcbnew.MODULE(None) # create a new module |
749 | - |
750 | - pads = self.parameters |
751 | - num_pads = int(pads["Pads"]["*n"]) |
752 | - pad_width = pads["Pads"]["width"] |
753 | - pad_length = pads["Pads"]["length"] |
754 | - pad_pitch = pads["Pads"]["pitch"] |
755 | - pad_horizontal_pitch = pads["Pads"]["horizontal pitch"] |
756 | - pad_vertical_pitch = pads["Pads"]["vertical pitch"] |
757 | - |
758 | - package_width = pads["Package"]["width"] |
759 | - package_height = pads["Package"]["height"] |
760 | - |
761 | - side_length = pad_pitch * ((num_pads / 4) - 1) |
762 | - |
763 | - offsetX = pad_pitch * ((num_pads / 4) - 1) / 2 |
764 | - text_size = pcbnew.wxSize(pcbnew.FromMM(0.8), pcbnew.FromMM(0.8)) |
765 | - |
766 | - self.module.SetReference("QFP %d" % int(num_pads)) |
767 | - self.module.Reference().SetPos0(pcbnew.wxPoint(0, pcbnew.FromMM(-0.8))) |
768 | - self.module.Reference().SetTextPosition(self.module.Reference().GetPos0()) |
769 | - self.module.Reference().SetSize(text_size) |
770 | - |
771 | - self.module.SetValue("U**") |
772 | - self.module.Value().SetPos0(pcbnew.wxPoint(0, pcbnew.FromMM(+0.8))) |
773 | - self.module.Value().SetTextPosition(self.module.Value().GetPos0()) |
774 | - self.module.Value().SetSize(text_size) |
775 | - |
776 | - fpid = pcbnew.FPID(self.module.GetReference()) #the name in library |
777 | - self.module.SetFPID( fpid ) |
778 | - |
779 | - pad_size_left_right = pcbnew.wxSize(pad_length, pad_width) |
780 | - pad_size_bottom_top = pcbnew.wxSize(pad_width, pad_length) |
781 | - |
782 | - for cur_pad in range(0, num_pads): |
783 | - side = int(cur_pad / (num_pads / 4)) # 0 -> left, 1 -> bottom, 2 -> right, 3 -> top |
784 | - |
785 | - if side == 0 or side == 2: |
786 | - pad_size = pad_size_left_right |
787 | - |
788 | - pad_pos_x = -(pad_horizontal_pitch / 2) |
789 | - pad_pos_y = (cur_pad % (num_pads / 4)) * pad_pitch - (side_length / 2) |
790 | - |
791 | - if side == 2: |
792 | - pad_pos_x = -pad_pos_x |
793 | - pad_pos_y = -pad_pos_y |
794 | - |
795 | - else: |
796 | - pad_size = pad_size_bottom_top |
797 | - |
798 | - pad_pos_x = (cur_pad % (num_pads / 4)) * pad_pitch - (side_length / 2) |
799 | - pad_pos_y = -(pad_vertical_pitch / 2) |
800 | - |
801 | - if side == 1: |
802 | - pad_pos_y = -pad_pos_y |
803 | - else: |
804 | - pad_pos_x = -pad_pos_x |
805 | - |
806 | - pad_pos = pcbnew.wxPoint(pad_pos_x, pad_pos_y) |
807 | - |
808 | - pad = self.smd_rect_pad(self.module, pad_size, pad_pos, str(cur_pad + 1)) |
809 | - |
810 | - self.module.Add(pad) |
811 | - |
812 | - half_package_width = package_width / 2 |
813 | - half_package_height = package_height / 2 |
814 | - |
815 | - package_pad_height_offset = abs(package_height - side_length) / 2 - pad_pitch |
816 | - package_pad_width_offset = abs(package_width - side_length) / 2 - pad_pitch |
817 | - |
818 | - # Bottom Left Edge, vertical line |
819 | - outline = pcbnew.EDGE_MODULE(self.module) |
820 | - outline.SetWidth(pcbnew.FromMM(0.2)) |
821 | - outline.SetLayer(pcbnew.SILKSCREEN_N_FRONT) |
822 | - outline.SetShape(pcbnew.S_SEGMENT) |
823 | - start = pcbnew.wxPoint(-half_package_width, half_package_height - package_pad_height_offset) |
824 | - end = pcbnew.wxPoint(-half_package_width, half_package_height) |
825 | - outline.SetStartEnd(start, end) |
826 | - self.module.Add(outline) |
827 | - |
828 | - # Bottom Left Edge, horizontal line |
829 | - outline = pcbnew.EDGE_MODULE(self.module) |
830 | - outline.SetWidth(pcbnew.FromMM(0.2)) |
831 | - outline.SetLayer(pcbnew.SILKSCREEN_N_FRONT) |
832 | - outline.SetShape(pcbnew.S_SEGMENT) |
833 | - start = pcbnew.wxPoint(-half_package_width, half_package_height) |
834 | - end = pcbnew.wxPoint(-half_package_width + package_pad_width_offset, half_package_height) |
835 | - outline.SetStartEnd(start, end) |
836 | - self.module.Add(outline) |
837 | - |
838 | - # Bottom Right Edge, vertical line |
839 | - outline = pcbnew.EDGE_MODULE(self.module) |
840 | - outline.SetWidth(pcbnew.FromMM(0.2)) |
841 | - outline.SetLayer(pcbnew.SILKSCREEN_N_FRONT) |
842 | - outline.SetShape(pcbnew.S_SEGMENT) |
843 | - start = pcbnew.wxPoint(half_package_width, half_package_height - package_pad_height_offset) |
844 | - end = pcbnew.wxPoint(half_package_width, half_package_height) |
845 | - outline.SetStartEnd(start, end) |
846 | - self.module.Add(outline) |
847 | - |
848 | - # Bottom Right Edge, horizontal line |
849 | - outline = pcbnew.EDGE_MODULE(self.module) |
850 | - outline.SetWidth(pcbnew.FromMM(0.2)) |
851 | - outline.SetLayer(pcbnew.SILKSCREEN_N_FRONT) |
852 | - outline.SetShape(pcbnew.S_SEGMENT) |
853 | - start = pcbnew.wxPoint(half_package_width, half_package_height) |
854 | - end = pcbnew.wxPoint(half_package_width - package_pad_width_offset, half_package_height) |
855 | - outline.SetStartEnd(start, end) |
856 | - self.module.Add(outline) |
857 | - |
858 | - # Top Right Edge, vertical line |
859 | - outline = pcbnew.EDGE_MODULE(self.module) |
860 | - outline.SetWidth(pcbnew.FromMM(0.2)) |
861 | - outline.SetLayer(pcbnew.SILKSCREEN_N_FRONT) |
862 | - outline.SetShape(pcbnew.S_SEGMENT) |
863 | - start = pcbnew.wxPoint(half_package_width, -half_package_height + package_pad_height_offset) |
864 | - end = pcbnew.wxPoint(half_package_width, -half_package_height) |
865 | - outline.SetStartEnd(start, end) |
866 | - self.module.Add(outline) |
867 | - |
868 | - # Top Right Edge, horizontal line |
869 | - outline = pcbnew.EDGE_MODULE(self.module) |
870 | - outline.SetWidth(pcbnew.FromMM(0.2)) |
871 | - outline.SetLayer(pcbnew.SILKSCREEN_N_FRONT) |
872 | - outline.SetShape(pcbnew.S_SEGMENT) |
873 | - start = pcbnew.wxPoint(half_package_width, -half_package_height) |
874 | - end = pcbnew.wxPoint(half_package_width - package_pad_width_offset, -half_package_height) |
875 | - outline.SetStartEnd(start, end) |
876 | - self.module.Add(outline) |
877 | - |
878 | - # Top Left Edge, straight line |
879 | - outline = pcbnew.EDGE_MODULE(self.module) |
880 | - outline.SetWidth(pcbnew.FromMM(0.2)) |
881 | - outline.SetLayer(pcbnew.SILKSCREEN_N_FRONT) |
882 | - outline.SetShape(pcbnew.S_SEGMENT) |
883 | - start = pcbnew.wxPoint(-half_package_width, -half_package_height + package_pad_height_offset) |
884 | - end = pcbnew.wxPoint(-half_package_width + package_pad_width_offset, -half_package_height) |
885 | - outline.SetStartEnd(start, end) |
886 | - self.module.Add(outline) |
887 | - |
888 | - def print_parameter_table(self): |
889 | - for name, section in self.parameters.iteritems(): |
890 | - print " %s:" % name |
891 | - |
892 | - for key, value in section.iteritems(): |
893 | - unit = "" |
894 | - if (type(value) is int or type(value) is float) and not "*" in key: |
895 | - unit = "mm" |
896 | - |
897 | - if "*" in key: |
898 | - key = key[1:] |
899 | - else: |
900 | - value = pcbnew.ToMM(value) |
901 | - |
902 | - print " %s: %s%s" % (key, value, unit) |
903 | - |
904 | - def has_errors(self): |
905 | - for name, section in self.parameter_errors.iteritems(): |
906 | - for k, v in section.iteritems(): |
907 | - if v: |
908 | - return True |
909 | - |
910 | - return False |
911 | + |
912 | + self.CheckParamPositiveInt("Pads", "*n", is_multiple_of = 4) |
913 | + |
914 | + def GetReference(self): |
915 | + return "QFP %d" % self.parameters["Pads"]["*n"] |
916 | + |
917 | + def BuildThisFootprint(self): |
918 | + |
919 | + pads = self.parameters["Pads"] |
920 | + |
921 | + pad_pitch = pads["pad pitch"] |
922 | + pad_length = self.parameters["Pads"]["pad length"] |
923 | + pad_width = self.parameters["Pads"]["pad width"] |
924 | + |
925 | + v_pitch = pads["vertical pitch"] |
926 | + h_pitch = pads["horizontal pitch"] |
927 | + |
928 | + pads_per_row = pads["*n"] // 4 |
929 | + |
930 | + row_len = (pads_per_row - 1) * pad_pitch |
931 | + |
932 | + h_pad = PA.PadMaker(self.module).SMDPad(pad_width, pad_length, shape = pcbnew.PAD_OVAL) |
933 | + v_pad = PA.PadMaker(self.module).SMDPad(pad_length, pad_width, shape = pcbnew.PAD_OVAL) |
934 | + |
935 | + #left row |
936 | + pin1Pos = pcbnew.wxPoint(-h_pitch / 2, -row_len / 2) |
937 | + array = PA.PadLineArray(h_pad, pads_per_row, pad_pitch, True, pin1Pos) |
938 | + array.SetFirstPadInArray(1) |
939 | + array.AddPadsToModule() |
940 | + |
941 | + #bottom row |
942 | + pin1Pos = pcbnew.wxPoint(-row_len / 2, v_pitch / 2) |
943 | + array = PA.PadLineArray(v_pad, pads_per_row, pad_pitch, False, pin1Pos) |
944 | + array.SetFirstPadInArray(pads_per_row + 1) |
945 | + array.AddPadsToModule() |
946 | + |
947 | + #right row |
948 | + pin1Pos = pcbnew.wxPoint(h_pitch / 2, row_len / 2) |
949 | + array = PA.PadLineArray(h_pad, pads_per_row, -pad_pitch, True, pin1Pos) |
950 | + array.SetFirstPadInArray(2*pads_per_row + 1) |
951 | + array.AddPadsToModule() |
952 | + |
953 | + #top row |
954 | + pin1Pos = pcbnew.wxPoint(row_len / 2, -v_pitch / 2) |
955 | + array = PA.PadLineArray(v_pad, pads_per_row, -pad_pitch, False, pin1Pos) |
956 | + array.SetFirstPadInArray(3*pads_per_row + 1) |
957 | + array.AddPadsToModule() |
958 | + |
959 | + limX = pads["package width"] / 2 |
960 | + limY = pads["package height"] / 2 |
961 | + inner = (row_len / 2) + pad_pitch |
962 | + |
963 | + #top left - diagonal |
964 | + self.draw.Line(-limX, -inner, -inner, -limY) |
965 | + # top right |
966 | + self.draw.Polyline([(inner, -limY), (limX, -limY), (limX, -inner)]) |
967 | + # bottom left |
968 | + self.draw.Polyline([(-inner, limY), (-limX, limY), (-limX, inner)]) |
969 | + # bottom right |
970 | + self.draw.Polyline([(inner, limY), (limX, limY), (limX, inner)]) |
971 | |
972 | QFPWizard().register() |
973 | |
974 | === added file 'pcbnew/scripting/plugins/sdip_wizard.py' |
975 | --- pcbnew/scripting/plugins/sdip_wizard.py 1970-01-01 00:00:00 +0000 |
976 | +++ pcbnew/scripting/plugins/sdip_wizard.py 2014-04-20 22:23:21 +0000 |
977 | @@ -0,0 +1,200 @@ |
978 | +# This program is free software; you can redistribute it and/or modify |
979 | +# it under the terms of the GNU General Public License as published by |
980 | +# the Free Software Foundation; either version 2 of the License, or |
981 | +# (at your option) any later version. |
982 | +# |
983 | +# This program is distributed in the hope that it will be useful, |
984 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
985 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
986 | +# GNU General Public License for more details. |
987 | +# |
988 | +# You should have received a copy of the GNU General Public License |
989 | +# along with this program; if not, write to the Free Software |
990 | +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, |
991 | +# MA 02110-1301, USA. |
992 | +# |
993 | + |
994 | +from __future__ import division |
995 | +import pcbnew |
996 | + |
997 | +import HelpfulFootprintWizardPlugin as HFPW |
998 | +import PadArray as PA |
999 | + |
1000 | + |
1001 | +class RowedGridArray(PA.PadGridArray): |
1002 | + |
1003 | + def NamingFunction(self, x, y): |
1004 | + if (x % 2) == 0: # even row, count up |
1005 | + return (x * self.ny) + y + 1; |
1006 | + else: # odd row, count down |
1007 | + return (self.ny * (x + 1)) - y; |
1008 | + |
1009 | +class RowedFootprint(HFPW.HelpfulFootprintWizardPlugin): |
1010 | + |
1011 | + def GenerateParameterList(self): |
1012 | + |
1013 | + # defaults for a DIP package |
1014 | + self.AddParam("Pads", "n", self.uNatural, 24) |
1015 | + self.AddParam("Pads", "silk screen inside", self.uBool, False) |
1016 | + self.AddParam("Pads", "row count", self.uNatural, 2) |
1017 | + |
1018 | + def CheckParameters(self): |
1019 | + self.CheckParamPositiveInt("Pads", "*row count") |
1020 | + self.CheckParamPositiveInt("Pads", "*n", is_multiple_of = self.parameters["Pads"]["*row count"]) |
1021 | + self.CheckParamBool("Pads", "*silk screen inside") #can do this internally to parameter manager? |
1022 | + |
1023 | + def BuildThisFootprint(self): |
1024 | + |
1025 | + pads = self.parameters["Pads"] |
1026 | + |
1027 | + num_pads = pads["*n"] |
1028 | + |
1029 | + pad_length = pads["pad length"] |
1030 | + pad_width = pads["pad width"] |
1031 | + row_pitch = pads["row spacing"] |
1032 | + pad_pitch = pads["pad pitch"] |
1033 | + num_rows = pads["*row count"] |
1034 | + |
1035 | + pads_per_row = num_pads // num_rows |
1036 | + |
1037 | + row_length = pad_pitch * (pads_per_row - 1) #fenceposts |
1038 | + |
1039 | + # add in the pads |
1040 | + pad = self.GetPad() |
1041 | + |
1042 | + pin1Pos = pcbnew.wxPoint(-((num_rows - 1) * row_pitch) / 2, -row_length / 2) |
1043 | + |
1044 | + array = RowedGridArray(pad, num_rows, pads_per_row, row_pitch, pad_pitch, pin1Pos) |
1045 | + array.AddPadsToModule() |
1046 | + |
1047 | + # draw the Silk Screen |
1048 | + |
1049 | + pad_length = pads["pad length"] |
1050 | + pad_width = pads["pad width"] |
1051 | + |
1052 | + ssXOffset = -pad_length / 2 - pads["outline x margin"] |
1053 | + ssYOffset = -pad_width / 2 - pads["outline y margin"] |
1054 | + |
1055 | + |
1056 | + if pads["*silk screen inside"]: |
1057 | + ssXOffset *= -1 |
1058 | + |
1059 | + ssX = -pin1Pos.x - ssXOffset |
1060 | + ssY = -pin1Pos.y - ssYOffset |
1061 | + |
1062 | + |
1063 | + self.DrawBox(ssX, ssY) |
1064 | + |
1065 | + #reference and value |
1066 | + textSize = pcbnew.FromMM(0.8) |
1067 | + |
1068 | + self.draw.Value(0, - ssY - textSize, textSize) |
1069 | + self.draw.Reference(0, ssY + textSize, textSize) |
1070 | + |
1071 | + |
1072 | +class SDIPWizard(RowedFootprint): |
1073 | + |
1074 | + def GetName(self): |
1075 | + return "S/DIP" |
1076 | + |
1077 | + def GetDescription(self): |
1078 | + return "Single/Dual Inline Package Footprint Wizard" |
1079 | + |
1080 | + def GenerateParameterList(self): |
1081 | + RowedFootprint.GenerateParameterList(self) |
1082 | + |
1083 | + self.AddParam("Pads", "pad pitch", self.uMils, 100) |
1084 | + self.AddParam("Pads", "pad width", self.uMils, 60) |
1085 | + self.AddParam("Pads", "pad length", self.uMils, 150) |
1086 | + self.AddParam("Pads", "row spacing", self.uMils, 300) |
1087 | + self.AddParam("Pads", "drill size", self.uMM, 1) |
1088 | + self.AddParam("Pads", "outline x margin", self.uMM, 0.5) |
1089 | + self.AddParam("Pads", "outline y margin", self.uMM, 1) |
1090 | + |
1091 | + def GetReference(self): |
1092 | + |
1093 | + rows = self.parameters["Pads"]["*row count"] |
1094 | + |
1095 | + if rows == 1: |
1096 | + name = "SIP" |
1097 | + elif rows == 2: |
1098 | + name = "DIP" |
1099 | + else: # triple and up aren't really a thing, but call it something! |
1100 | + name = "xIP" |
1101 | + |
1102 | + return "%s %d" % (name, self.parameters["Pads"]["*n"]) |
1103 | + |
1104 | + def GetPad(self): |
1105 | + pad_length = self.parameters["Pads"]["pad length"] |
1106 | + pad_width = self.parameters["Pads"]["pad width"] |
1107 | + drill = self.parameters["Pads"]["drill size"] |
1108 | + return PA.PadMaker(self.module).THPad(pad_width, pad_length, drill, shape = pcbnew.PAD_OVAL) |
1109 | + |
1110 | + def DrawBox(self, ssX, ssY): |
1111 | + |
1112 | + if self.parameters["Pads"]["*row count"] == 2: |
1113 | + |
1114 | + # ---------- |
1115 | + # |8 7 6 5 | |
1116 | + # > | |
1117 | + # |1 2 3 4 | |
1118 | + # ---------- |
1119 | + |
1120 | + # draw the notch |
1121 | + notchWidth = pcbnew.FromMM(3) |
1122 | + notchHeight = pcbnew.FromMM(1) |
1123 | + |
1124 | + self.draw.NotchedBox(0, 0, ssX*2, ssY*2, notchWidth, notchHeight) |
1125 | + else: |
1126 | + # ----------------- |
1127 | + # |1|2 3 4 5 6 7 8| |
1128 | + # ----------------- |
1129 | + self.draw.Box(ssX*2, ssY*2) |
1130 | + |
1131 | + #line between pin1 and pin2 |
1132 | + pad_pitch = self.parameters["Pads"]["pad pitch"]; |
1133 | + self.draw.HLine(-ssX, pin1Pos.y + pad_pitch/2, ssX * 2) |
1134 | + |
1135 | + return ssX, ssY |
1136 | + |
1137 | +SDIPWizard().register() |
1138 | + |
1139 | + |
1140 | +class SOICWizard(RowedFootprint): |
1141 | + |
1142 | + def GetName(self): |
1143 | + return "SOIC" |
1144 | + |
1145 | + def GetDescription(self): |
1146 | + return "SOIC, MSOP, SSOP, TSSOP, etc, footprint wizard" |
1147 | + |
1148 | + def GetReference(self): |
1149 | + return "%s %d" % ("SOIC", self.parameters["Pads"]["*n"]) |
1150 | + |
1151 | + def GenerateParameterList(self): |
1152 | + RowedFootprint.GenerateParameterList(self) |
1153 | + |
1154 | + #and override some of them |
1155 | + self.AddParam("Pads", "pad pitch", self.uMM, 1.27) |
1156 | + self.AddParam("Pads", "pad width", self.uMM, 0.6) |
1157 | + self.AddParam("Pads", "pad length", self.uMM, 2.2) |
1158 | + self.AddParam("Pads", "row spacing", self.uMM, 5.2) |
1159 | + |
1160 | + self.AddParam("Pads", "outline x margin", self.uMM, 0.5) |
1161 | + self.AddParam("Pads", "outline y margin", self.uMM, 0.5) |
1162 | + |
1163 | + def GetPad(self): |
1164 | + pad_length = self.parameters["Pads"]["pad length"] |
1165 | + pad_width = self.parameters["Pads"]["pad width"] |
1166 | + return PA.PadMaker(self.module).SMDPad(pad_width, pad_length, shape = pcbnew.PAD_RECT) |
1167 | + |
1168 | + def DrawBox(self, ssX, ssY): |
1169 | + |
1170 | + # ---------- |
1171 | + # |8 7 6 5 | |
1172 | + # |1 2 3 4 | |
1173 | + # \--------- |
1174 | + |
1175 | + self.draw.BoxWithDiagonalAtCorner(0, 0, ssX*2, ssY*2, pcbnew.FromMM(1)) |
1176 | + |
1177 | +SOICWizard().register() |
Thanks.
I committed your patch.
For this kind of change, I prefer a patch instead of a merge request.