1# This program is free software; you can redistribute it and/or modify 2# it under the terms of the GNU General Public License as published by 3# the Free Software Foundation; either version 2 of the License, or 4# (at your option) any later version. 5# 6# This program is distributed in the hope that it will be useful, 7# but WITHOUT ANY WARRANTY; without even the implied warranty of 8# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 9# GNU General Public License for more details. 10# 11# You should have received a copy of the GNU General Public License 12# along with this program; if not, write to the Free Software 13# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 14# MA 02110-1301, USA. 15# 16 17from __future__ import division 18import pcbnew 19 20import FootprintWizardBase 21import PadArray as PA 22 23 24class RowedGridArray(PA.PadGridArray): 25 26 def __init__(self, *args, **kwargs): 27 super(RowedGridArray, self).__init__(*args, **kwargs) 28 29 def NamingFunction(self, x, y): 30 pad_cnt = self.nx*self.ny 31 32 if self.ny == 1: 33 return x+1 34 35 if (y % 2) == 0: # upper row, count down 36 return pad_cnt-x 37 else: # lower row, count up 38 return x+1 39 40 41class RowedFootprint(FootprintWizardBase.FootprintWizard): 42 43 pad_count_key = 'pad count' 44 row_count_key = 'row count' 45 row_spacing_key = 'row spacing' 46 pad_length_key = 'pad length' 47 pad_width_key = 'pad width' 48 pad_pitch_key = 'pad pitch' 49 50 silkscreen_inside_key = 'silk screen inside' 51 outline_x_margin_key = 'outline x margin' 52 outline_y_margin_key = 'outline y margin' 53 54 def GenerateParameterList(self): 55 # defaults for a DIP package 56 self.AddParam("Pads", self.pad_count_key, self.uInteger, 24) 57 self.AddParam("Pads", self.row_count_key, self.uInteger, 2, min_value=1, max_value=2) 58 59 self.AddParam("Body", self.silkscreen_inside_key, self.uBool, False) 60 self.AddParam("Body", self.outline_x_margin_key, self.uMM, 0.5) 61 self.AddParam("Body", self.outline_y_margin_key, self.uMM, 0.5) 62 63 def CheckParameters(self): 64 self.CheckParam("Pads", self.pad_count_key, multiple=self.parameters['Pads'][self.row_count_key], info='Pads must be multiple of row count') 65 66 def BuildThisFootprint(self): 67 pads = self.parameters["Pads"] 68 body = self.parameters["Body"] 69 num_pads = pads[self.pad_count_key] 70 pad_length = pads[self.pad_length_key] 71 pad_width = pads[self.pad_width_key] 72 row_pitch = pads[self.row_spacing_key] 73 pad_pitch = pads[self.pad_pitch_key] 74 num_rows = pads[self.row_count_key] 75 76 pads_per_row = num_pads // num_rows 77 78 # add in the pads 79 pad = self.GetPad() 80 81 array = RowedGridArray(pad, pads_per_row, num_rows, pad_pitch, row_pitch) 82 array.AddPadsToModule(self.draw) 83 84 # draw the Silk Screen 85 Hsize = pad_pitch * (num_pads / num_rows - 1) 86 Vsize = row_pitch * (num_rows - 1) 87 pin1_posY = -Vsize / 2 88 pin1_posX = -Hsize / 2 89 90 pad_length = pads[self.pad_length_key] 91 pad_width = pads[self.pad_width_key] 92 93 ssx_offset = -pad_width / 2 - body[self.outline_x_margin_key] 94 ssy_offset = -pad_length / 2 - body[self.outline_y_margin_key] 95 96 if body[self.silkscreen_inside_key]: 97 ssy_offset *= -1 98 99 ssx = -pin1_posX - ssx_offset 100 ssy = -pin1_posY - ssy_offset 101 102 cmargin = self.draw.GetLineThickness() 103 self.draw.SetLineThickness( pcbnew.FromMM( 0.12 ) ) #Default per KLC F5.1 as of 12/2018 104 self.DrawBox(ssx, ssy) 105 106 # Courtyard 107 self.draw.SetLayer(pcbnew.F_CrtYd) 108 cclearance = pcbnew.FromMM(0.25) 109 sizex = (-pin1_posX + cclearance) * 2 + pad_width 110 sizey = (-pin1_posY + cclearance) * 2 + pad_length 111 # round size to nearest 0.02mm, rectangle will thus land on a 0.01mm grid 112 sizex = pcbnew.PutOnGridMM(sizex, 0.02) 113 sizey = pcbnew.PutOnGridMM(sizey, 0.02) 114 # set courtyard line thickness to the one defined in KLC 115 self.draw.SetLineThickness(pcbnew.FromMM(0.05)) 116 self.draw.Box(0, 0, sizex, sizey) 117 # restore line thickness to previous value 118 self.draw.SetLineThickness(pcbnew.FromMM(cmargin)) 119 120 #reference and value 121 text_size = self.GetTextSize() # IPC nominal 122 123 if num_rows == 1: 124 text_py = ssy + text_size 125 self.draw.Value(0, -text_py, text_size) 126 self.draw.Reference(0, text_py, text_size) 127 else: 128 text_px = ssx + text_size 129 # self.draw.Value(text_px, 0, text_size, orientation_degree=90) 130 self.draw.Value(0, 0, text_size) 131 self.draw.Reference(-text_px, 0, text_size, orientation_degree=90) 132 133 # set the attribute 134 if self.GetName() == "S-DIP": 135 self.module.SetAttributes(pcbnew.PAD_ATTRIB_PTH) 136 elif self.GetName() == "SOIC": 137 self.module.SetAttributes(pcbnew.PAD_ATTRIB_SMD) 138 139class SDIPWizard(RowedFootprint): 140 141 def GetName(self): 142 return "S-DIP" 143 144 def GetDescription(self): 145 return "Single/Dual Inline Package Footprint Wizard" 146 147 def GenerateParameterList(self): 148 RowedFootprint.GenerateParameterList(self) 149 150 self.AddParam("Pads", self.pad_pitch_key, self.uMM, 2.54) 151 self.AddParam("Pads", self.pad_width_key, self.uMM, 1.2) 152 self.AddParam("Pads", self.pad_length_key, self.uMM, 2) 153 self.AddParam("Pads", self.row_spacing_key, self.uMM, 7.52) 154 self.AddParam("Pads", "drill size", self.uMM, 0.8) 155 156 def GetValue(self): 157 pads = self.parameters["Pads"] 158 rows = pads[self.row_count_key] 159 pad_count = pads[self.pad_count_key] 160 row_dist_mil = pcbnew.Iu2Mils(int(self.parameters["Pads"][self.row_spacing_key])) #int(self.parameters["Pads"][self.row_spacing_key] / 2.54 * 100) 161 pad_shape = "" 162 163 if pads[self.pad_width_key] != pads[self.pad_length_key]: 164 pad_shape = '_ELL' 165 166 if rows == 1: 167 name = "SIP" 168 return "%s-%d" % (name, pad_count) 169 170 name = "DIP" 171 return "%s-%d_%d%s" % (name, pad_count, row_dist_mil, pad_shape) 172 173 def GetPad(self): 174 pad_length = self.parameters["Pads"][self.pad_length_key] 175 pad_width = self.parameters["Pads"][self.pad_width_key] 176 drill = self.parameters["Pads"]["drill size"] 177 shape = pcbnew.PAD_SHAPE_CIRCLE 178 179 if pad_length != pad_width: 180 shape = pcbnew.PAD_SHAPE_OVAL 181 182 return PA.PadMaker(self.module).THPad( 183 pad_length, pad_width, drill, shape=shape) 184 185 def DrawBox(self, ssx, ssy): 186 187 if self.parameters["Pads"][self.row_count_key] == 2: 188 189 # ---------- 190 # |8 7 6 5 | 191 # > | 192 # |1 2 3 4 | 193 # ---------- 194 195 # draw the notch 196 notchWidth = ssy/1.5 197 notchHeight = self.draw.GetLineThickness()*3 198 199 # NotchedBox draws the notch on top. Rotate the box 90 degrees 200 # to have it on the left 201 self.draw.NotchedBox(0, 0, ssy*2, ssx*2, notchWidth, notchHeight, -90) 202 else: 203 # ----------------- 204 # |1|2 3 4 5 6 7 8| 205 # ----------------- 206 self.draw.Box(0, 0, ssx*2, ssy*2) 207 208 #line between pin1 and pin2 209 pad_pitch = self.parameters["Pads"][self.pad_pitch_key] 210 pad_cnt = self.parameters["Pads"][self.pad_count_key] 211 line_x = ( pad_cnt/2 - 1) * pad_pitch 212 self.draw.VLine(-line_x, -ssy, ssy * 2) 213 214 return ssx, ssy 215 216SDIPWizard().register() 217 218 219class SOICWizard(RowedFootprint): 220 221 def GetName(self): 222 return "SOIC" 223 224 def GetDescription(self): 225 return "SOIC, MSOP, SSOP, TSSOP, etc, footprint wizard" 226 227 def GetValue(self): 228 pad_count = self.parameters["Pads"][self.pad_count_key] 229 return "%s-%d" % ("SOIC", pad_count) 230 231 def GenerateParameterList(self): 232 RowedFootprint.GenerateParameterList(self) 233 234 #and override some of them 235 self.AddParam("Pads", self.pad_pitch_key, self.uMM, 1.27) 236 self.AddParam("Pads", self.pad_width_key, self.uMM, 0.6) 237 self.AddParam("Pads", self.pad_length_key, self.uMM, 2.2) 238 self.AddParam("Pads", self.row_spacing_key, self.uMM, 5.2) 239 240 def GetPad(self): 241 pad_length = self.parameters["Pads"][self.pad_length_key] 242 pad_width = self.parameters["Pads"][self.pad_width_key] 243 return PA.PadMaker(self.module).SMDPad( 244 pad_length, pad_width, shape=pcbnew.PAD_SHAPE_RECT) 245 246 def DrawBox(self, ssx, ssy): 247 248 # ---------- 249 # |8 7 6 5 | 250 # |1 2 3 4 | 251 # \--------- 252 253 setback = pcbnew.FromMM(0.8) 254 255 if setback > ssy: 256 setback = ssy 257 258 self.draw.BoxWithDiagonalAtCorner(0, 0, ssx*2, ssy*2, setback, self.draw.flipY) 259 260SOICWizard().register() 261